Merge branch 'jc/fix-2.45.1-and-friends-for-2.39' into fixes/2.45.1/2.40

Revert overly aggressive "layered defence" that went into 2.45.1
and friends, which broke "git-lfs", "git-annex", and other use
cases, so that we can rebuild necessary counterparts in the open.

* jc/fix-2.45.1-and-friends-for-2.39:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack
diff --git a/.gitattributes b/.gitattributes
index b0044cf..158c3d4 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,17 +1,17 @@
 * whitespace=!indent,trail,space
 *.[ch] whitespace=indent,trail,space diff=cpp
-*.sh whitespace=indent,trail,space eol=lf
-*.perl eol=lf diff=perl
-*.pl eof=lf diff=perl
-*.pm eol=lf diff=perl
-*.py eol=lf diff=python
-*.bat eol=crlf
+*.sh whitespace=indent,trail,space text eol=lf
+*.perl text eol=lf diff=perl
+*.pl text eof=lf diff=perl
+*.pm text eol=lf diff=perl
+*.py text eol=lf diff=python
+*.bat text eol=crlf
 CODE_OF_CONDUCT.md -whitespace
-/Documentation/**/*.txt eol=lf
-/command-list.txt eol=lf
-/GIT-VERSION-GEN eol=lf
-/mergetools/* eol=lf
-/t/oid-info/* eol=lf
+/Documentation/**/*.txt text eol=lf
+/command-list.txt text eol=lf
+/GIT-VERSION-GEN text eol=lf
+/mergetools/* text eol=lf
+/t/oid-info/* text eol=lf
 /Documentation/git-merge.txt conflict-marker-size=32
 /Documentation/gitk.txt conflict-marker-size=32
 /Documentation/user-manual.txt conflict-marker-size=32
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 76e3f1e..bd390ab 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -288,8 +288,9 @@
     - uses: actions/checkout@v4
     - run: ci/install-dependencies.sh
     - run: ci/run-build-and-tests.sh
-    - run: ci/print-test-failures.sh
+    - name: print test failures
       if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      run: ci/print-test-failures.sh
     - name: Upload failed tests' directories
       if: failure() && env.FAILED_TEST_ARTIFACTS != ''
       uses: actions/upload-artifact@v4
@@ -324,8 +325,9 @@
       if: matrix.vector.jobname == 'linux32'
     - run: ci/install-docker-dependencies.sh
     - run: ci/run-build-and-tests.sh
-    - run: ci/print-test-failures.sh
+    - name: print test failures
       if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      run: ci/print-test-failures.sh
     - name: Upload failed tests' directories
       if: failure() && env.FAILED_TEST_ARTIFACTS != '' && matrix.vector.jobname != 'linux32'
       uses: actions/upload-artifact@v4
diff --git a/.gitignore b/.gitignore
index 0832f1d..e875c59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,14 +14,12 @@
 /bin-wrappers/
 /git
 /git-add
-/git-add--interactive
 /git-am
 /git-annotate
 /git-apply
 /git-archimport
 /git-archive
 /git-bisect
-/git-bisect--helper
 /git-blame
 /git-branch
 /git-bugreport
@@ -60,7 +58,6 @@
 /git-difftool
 /git-difftool--helper
 /git-describe
-/git-env--helper
 /git-fast-export
 /git-fast-import
 /git-fetch
diff --git a/Documentation/RelNotes/2.30.8.txt b/Documentation/RelNotes/2.30.8.txt
index 38c23e0..5ed3efb 100644
--- a/Documentation/RelNotes/2.30.8.txt
+++ b/Documentation/RelNotes/2.30.8.txt
@@ -49,4 +49,3 @@
       t5619: demonstrate clone_local() with ambiguous transport
       clone: delay picking a transport until after get_repo_path()
       dir-iterator: prevent top-level symlinks without FOLLOW_SYMLINKS
-
diff --git a/Documentation/RelNotes/2.40.0.txt b/Documentation/RelNotes/2.40.0.txt
new file mode 100644
index 0000000..3ea445b
--- /dev/null
+++ b/Documentation/RelNotes/2.40.0.txt
@@ -0,0 +1,320 @@
+Git v2.40 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "merge-tree" learns a new `--merge-base` option.
+
+ * "git jump" (in contrib/) learned to present the "quickfix list" to
+   its standard output (instead of letting it consumed by the editor
+   it invokes), and learned to also drive emacs/emacsclient.
+
+ * "git var UNKNOWN_VARIABLE" and "git var VARIABLE" with the variable
+   given an empty value used to behave identically.  Now the latter
+   just gives an empty output, while the former still gives an error
+   message.
+
+ * Introduce a case insensitive mode to the Bash completion helpers.
+
+ * The advice message given by "git status" when it takes long time to
+   enumerate untracked paths has been updated.
+
+ * Just like "git var GIT_EDITOR" abstracts the complex logic to
+   choose which editor gets used behind it, "git var" now give support
+   to GIT_SEQUENCE_EDITOR.
+
+ * "git format-patch" learned to honor format.mboxrd even when sending
+   patches to the standard output stream,
+
+ * 'cat-file' gains mailmap support for its '--batch-check' and '-s'
+   options.
+
+ * Conditionally skip the pre-applypatch and applypatch-msg hooks when
+   applying patches with 'git am'.
+
+ * Introduce an optional configuration to allow the trailing hash that
+   protects the index file from bit flipping.
+
+ * "git check-attr" learned to take an optional tree-ish to read the
+   .gitattributes file from.
+
+ * "scalar" learned to give progress bar.
+
+ * "grep -P" learned to use Unicode Character Property to grok
+   character classes when processing \b and \w etc.
+
+ * "git rebase" often ignored incompatible options instead of
+   complaining, which has been corrected.
+
+ * "scalar" warns but continues when its periodic maintenance
+   feature cannot be enabled.
+
+ * The bundle-URI subsystem adds support for creation-token heuristics
+   to help incremental fetches.
+
+ * Userdiff regexp update for Java language.
+
+ * "git fetch --jobs=0" used to hit a BUG(), which has been corrected
+   to use the available CPUs.
+
+ * An invalid label or ref in the "rebase -i" todo file used to
+   trigger an runtime error. SUch an error is now diagnosed while the
+   todo file is parsed.
+
+ * The "diff" drivers specified by the "diff" attribute attached to
+   paths can now specify which algorithm (e.g. histogram) to use.
+
+ * "git range-diff" learned --abbrev=<num> option.
+
+ * "git archive HEAD^{tree}" records the paths with the current
+   timestamp in the archive, making it harder to obtain a stable
+   output.  The command learned the --mtime option to specify an
+   arbitrary timestamp (e.g. --mtime="@0 +0000" for the epoch).
+
+ * The credential subsystem learned that a password may have an
+   explicit expiration.
+
+ * The format.attach configuration variable lacked a way to override a
+   value defined in a lower-priority configuration file (e.g. the
+   system one) by redefining it in a higher-priority configuration
+   file.  Now, setting format.attach to an empty string means show the
+   patch inline in the e-mail message, without using MIME attachment.
+
+   This is a backward incompatible change.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * `git bisect` becomes a builtin.
+
+ * The pack-bitmap machinery is taught to log the paths of redundant
+   bitmap(s) to trace2 instead of stderr.
+
+ * Use the SHA1DC implementation on macOS, just like other platforms,
+   by default.
+
+ * Even in a repository with promisor remote, it is useless to
+   attempt to lazily attempt fetching an object that is expected to be
+   commit, because no "filter" mode omits commit objects.  Take
+   advantage of this assumption to fail fast on errors.
+
+ * Stop using "git --super-prefix" and narrow the scope of its use to
+   the submodule--helper.
+
+ * Stop running win+VS build by default.
+
+ * CI updates.  We probably want a clean-up to move the long shell
+   script embedded in yaml file into a separate file, but that can
+   come later.
+
+ * Use `git diff --no-index` as a test_cmp on Windows.
+
+   We'd probably need to revisit "do we really want to, and have to,
+   lose CRLF vs LF?" later, at which time we may be able to further
+   clean this up by replacing "git diff --no-index" with "diff -u".
+
+ * Avoid unnecessary builds in CI, with settings configured in
+   ci-config.
+
+ * Plug leaks in sequencer subsystem and its users.
+
+ * In-tree .gitattributes update to match the way we recommend our
+   users to mark a file as text.
+   (merge 1f34e0cd3d po/attributes-text later to maint).
+
+ * Finally retire the scripted "git add -p/-i" implementation and have
+   everybody use the one reimplemented in C.
+
+
+Fixes since v2.39
+-----------------
+
+ * Various leak fixes.
+
+ * Fix a bug where `pack-objects` would not respect multiple `--filter`
+   arguments when invoked directly.
+   (merge d4f7036887 rs/multi-filter-args later to maint).
+
+ * Make fsmonitor more robust to avoid the flakiness seen in t7527.
+   (merge 6692d45477 jh/t7527-unflake-by-forcing-cookie later to maint).
+
+ * Stop using deprecated macOS API in fsmonitor.
+   (merge b0226007f0 jh/fsmonitor-darwin-modernize later to maint).
+
+ * Redefining system functions for a few functions did not follow our
+   usual "implement git_foo() and #define foo(args) git_foo(args)"
+   pattern, which has broken build for some folks.
+
+ * The way the diff machinery prepares the options array for the
+   parse_options API has been refactored to avoid resource leaks.
+   (merge 189e97bc4b rs/diff-parseopts later to maint).
+
+ * Correct pthread API usage.
+   (merge 786e67611d sx/pthread-error-check-fix later to maint).
+
+ * The code to auto-correct a misspelt subcommand unnecessarily called
+   into git_default_config() from the early config codepath, which was
+   a no-no.  This has bee corrected.
+   (merge 0918d08887 sg/help-autocorrect-config-fix later to maint).
+
+ * "git http-fetch" (which is rarely used) forgot to identify itself
+   in the trace2 output.
+   (merge 7abb43cbc8 jt/http-fetch-trace2-report-name later to maint).
+
+ * The output from "git diff --stat" on an unmerged path lost the
+   terminating LF in Git 2.39, which has been corrected.
+   (merge 209d9cb011 pg/diff-stat-unmerged-regression-fix later to maint).
+
+ * "git pull -v --recurse-submodules" attempted to pass "-v" down to
+   underlying "git submodule update", which did not understand the
+   request and barfed, which has been corrected.
+   (merge 6f65f84766 ss/pull-v-recurse-fix later to maint).
+
+ * When given a pattern that matches an empty string at the end of a
+   line, the code to parse the "git diff" line-ranges fell into an
+   infinite loop, which has been corrected.
+
+ * Fix the sequence to fsync $GIT_DIR/packed-refs file that forgot to
+   flush its output to the disk..
+
+ * Fix to a small regression in 2.38 days.
+
+ * "git diff --relative" did not mix well with "git diff --ext-diff",
+   which has been corrected.
+
+ * The logic to see if we are using the "cone" mode by checking the
+   sparsity patterns has been tightened to avoid mistaking a pattern
+   that names a single file as specifying a cone.
+
+ * Deal with a few deprecation warning from cURL library.
+
+ * Doc update for environment variables set when hooks are invoked.
+
+ * Document ORIG_HEAD a bit more.
+
+ * "git ls-tree --format='%(path) %(path)' $tree $path" showed the
+   path three times, which has been corrected.
+
+ * Remove "git env--helper" and demote it to a test-tool subcommand.
+   (merge 4a1baacd46 ab/test-env-helper later to maint).
+
+ * Newer regex library macOS stopped enabling GNU-like enhanced BRE,
+   where '\(A\|B\)' works as alternation, unless explicitly asked with
+   the REG_ENHANCED flag.  "git grep" now can be compiled to do so, to
+   retain the old behaviour.
+
+ * Pthread emulation on Win32 leaked thread handle when a thread is
+   joined.
+   (merge 238a9dfe86 sk/win32-close-handle-upon-pthread-join later to maint).
+
+ * "git send-email -v 3" used to be expanded to "git send-email
+   --validate 3" when the user meant to pass them down to
+   "format-patch", which has been corrected.
+   (merge 8774aa56ad km/send-email-with-v-reroll-count later to maint).
+
+ * Document that "branch -f <branch>" disables only the safety to
+   avoid recreating an existing branch.
+
+ * "git fetch <group>", when "<group>" of remotes lists the same
+   remote twice, unnecessarily failed when parallel fetching was
+   enabled, which has been corrected.
+   (merge 06a668cb90 cw/fetch-remote-group-with-duplication later to maint).
+
+ * Clarify how "checkout -b/-B" and "git branch [-f]" are similar but
+   different in the documentation.
+
+ * "git hash-object" now checks that the resulting object is well
+   formed with the same code as "git fsck".
+   (merge 8e4309038f jk/hash-object-fsck later to maint).
+
+ * Improve the error message given when private key is not loaded in
+   the ssh agent in the codepath to sign with an ssh key.
+   (merge dce7b31126 as/ssh-signing-improve-key-missing-error later to maint).
+
+ * Adjust "git request-pull" to strip embedded signature from signed
+   tags to notice non-PGP signatures.
+   (merge a9cad02538 gm/request-pull-with-non-pgp-signed-tags later to maint).
+
+ * Remove support for MSys, which now lags way behind MSys2.
+   (merge 2987407f3c hj/remove-msys-support later to maint).
+
+ * Fix use of CreateThread() API call made early in the windows
+   start-up code.
+   (merge 592bcab61b sk/winansi-createthread-fix later to maint).
+
+ * "git pack-objects" learned to release delta-island bitmap data when
+   it is done using it, saving peak heap memory usage.
+   (merge 647982bb71 ew/free-island-marks later to maint).
+
+ * In an environment where dynamically generated code is prohibited to
+   run (e.g. SELinux), failure to JIT pcre patterns is expected.  Fall
+   back to interpreted execution in such a case.
+   (merge 50b6ad55b0 cb/grep-fallback-failing-jit later to maint).
+
+ * "git name-rev" heuristics update.
+   (merge b2182a8730 en/name-rev-make-taggerdate-much-less-important later to maint).
+
+ * Remove more remaining uses of macros that relies on the_index
+   singleton instance without explicitly spelling it out.
+
+ * Remove unnecessary explicit sizing of strbuf.
+   (merge 93ea118bed rs/cache-tree-strbuf-growth-fix later to maint).
+
+ * Doc update.
+   (merge d9ec3b0dc0 jk/doc-ls-remote-matching later to maint).
+
+ * Error messages given upon a signature verification failure used to
+   discard the errors from underlying gpg program, which has been
+   corrected.
+   (merge ad6b320756 js/gpg-errors later to maint).
+
+ * Update --date=default documentation.
+   (merge 9deef088ae rd/doc-default-date-format later to maint).
+
+ * A test helper had a single write(2) of 256kB, which was too big for
+   some platforms (e.g. NonStop), which has been corrected by using
+   xwrite() wrapper appropriately.
+   (merge 58eab6ff13 jc/genzeros-avoid-raw-write later to maint).
+
+ * sscanf(3) used in "git symbolic-ref --short" implementation found
+   to be not working reliably on macOS in UTF-8 locales.  Rewrite the
+   code to avoid sscanf() altogether to work it around.
+   (merge 613bef56b8 jk/shorten-unambiguous-ref-wo-sscanf later to maint).
+
+ * Various fix-ups on HTTP tests.
+   (merge 8f2146dbf1 jk/http-test-fixes later to maint).
+
+ * Fixes to code that parses the todo file used in "rebase -i".
+   (merge 666b6e1135 pw/rebase-i-parse-fix later to maint).
+
+ * Test library clean-up.
+   (merge c600a91c94 ar/test-lib-remove-stale-comment later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 4eb1ccecd4 dh/mingw-ownership-check-typofix later to maint).
+   (merge f95526419b ar/typofix-gitattributes-doc later to maint).
+   (merge 27875aeec9 km/doc-branch-start-point later to maint).
+   (merge 35c194dc57 es/t1509-root-fixes later to maint).
+   (merge 7b341645e3 pw/ci-print-failure-name-fix later to maint).
+   (merge bcb71d45bf jx/t1301-updates later to maint).
+   (merge ebdc46c242 jc/doc-diff-patch.txt later to maint).
+   (merge a87a20cbb4 ar/test-cleanup later to maint).
+   (merge f5156f1885 ar/bisect-doc-update later to maint).
+   (merge fca2d86c97 jk/interop-error later to maint).
+   (merge cf4936ed74 tl/ls-tree-code-clean-up later to maint).
+   (merge dcb47e52b0 en/t6426-todo-cleanup later to maint).
+   (merge 5b8db44bdd jc/format-patch-v-unleak later to maint).
+   (merge 590b636737 jk/hash-object-literally-fd-leak later to maint).
+   (merge 5458ba0a4d tb/t0003-invoke-dd-more-portably later to maint).
+   (merge 70661d288b ar/markup-em-dash later to maint).
+   (merge e750951e74 en/ls-files-doc-update later to maint).
+   (merge 4f542975d1 mh/doc-credential-cache-only-in-core later to maint).
+   (merge 3a2ebaebc7 gc/index-format-doc later to maint).
+   (merge b08edf709d jk/httpd-test-updates later to maint).
+   (merge d85e9448dd wl/new-command-doc later to maint).
+   (merge d912a603ed kf/t5000-modernise later to maint).
+   (merge e65b868d07 rs/size-t-fixes later to maint).
+   (merge 3eb1e1ca9a ab/config-h-remove-unused later to maint).
+   (merge d390e08076 cw/doc-pushurl-vs-url later to maint).
+   (merge 567342fc77 rs/ctype-test later to maint).
+   (merge d35d8f2e7a ap/t2015-style-update later to maint).
diff --git a/Documentation/RelNotes/2.40.1.txt b/Documentation/RelNotes/2.40.1.txt
new file mode 100644
index 0000000..e72f6b1
--- /dev/null
+++ b/Documentation/RelNotes/2.40.1.txt
@@ -0,0 +1,8 @@
+Git v2.40.1 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6, v2.37.7, v2.38.5
+and v2.39.3 to address the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007; see the release notes for these
+versions for details.
diff --git a/Documentation/RelNotes/2.40.2.txt b/Documentation/RelNotes/2.40.2.txt
new file mode 100644
index 0000000..646a2cc
--- /dev/null
+++ b/Documentation/RelNotes/2.40.2.txt
@@ -0,0 +1,7 @@
+Git v2.40.2 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4 to address
+the security issues CVE-2024-32002, CVE-2024-32004, CVE-2024-32020,
+CVE-2024-32021 and CVE-2024-32465; see the release notes for that
+version for details.
diff --git a/Documentation/config/add.txt b/Documentation/config/add.txt
index 3e859f3..e0354ce 100644
--- a/Documentation/config/add.txt
+++ b/Documentation/config/add.txt
@@ -7,6 +7,7 @@
 	variables.
 
 add.interactive.useBuiltin::
-	Set to `false` to fall back to the original Perl implementation of
-	the interactive version of linkgit:git-add[1] instead of the built-in
-	version. Is `true` by default.
+	Unused configuration variable. Used in Git versions v2.25.0 to
+	v2.36.0 to enable the built-in version of linkgit:git-add[1]'s
+	interactive mode, which then became the default in Git
+	versions v2.37.0 to v2.39.0.
diff --git a/Documentation/config/bundle.txt b/Documentation/config/bundle.txt
index daa21eb..3faae386 100644
--- a/Documentation/config/bundle.txt
+++ b/Documentation/config/bundle.txt
@@ -15,6 +15,13 @@
 	complete understanding of the bundled information (`all`) or if any one
 	of the listed bundle URIs is sufficient (`any`).
 
+bundle.heuristic::
+	If this string-valued key exists, then the bundle list is designed to
+	work well with incremental `git fetch` commands. The heuristic signals
+	that there are additional keys available for each bundle that help
+	determine which subset of bundles the client should download. The
+	only value currently understood is `creationToken`.
+
 bundle.<id>.*::
 	The `bundle.<id>.*` keys are used to describe a single item in the
 	bundle list, grouped under `<id>` for identification purposes.
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
index 95975e5..e52bc6b 100644
--- a/Documentation/config/feature.txt
+++ b/Documentation/config/feature.txt
@@ -23,6 +23,11 @@
 	working directory. With many files, commands such as `git status` and
 	`git checkout` may be slow and these new defaults improve performance:
 +
+* `index.skipHash=true` speeds up index writes by not computing a trailing
+  checksum. Note that this will cause Git versions earlier than 2.13.0 to
+  refuse to parse the index and Git versions earlier than 2.40.0 will report
+  a corrupted index during `git fsck`.
++
 * `index.version=4` enables path-prefix compression in the index.
 +
 * `core.untrackedCache=true` enables the untracked cache. This setting assumes
diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt
index cd65d23..568f0f7 100644
--- a/Documentation/config/fetch.txt
+++ b/Documentation/config/fetch.txt
@@ -96,3 +96,27 @@
 	merge and the write may take longer. Having an updated commit-graph
 	file helps performance of many Git commands, including `git merge-base`,
 	`git push -f`, and `git log --graph`. Defaults to false.
+
+fetch.bundleURI::
+	This value stores a URI for downloading Git object data from a bundle
+	URI before performing an incremental fetch from the origin Git server.
+	This is similar to how the `--bundle-uri` option behaves in
+	linkgit:git-clone[1]. `git clone --bundle-uri` will set the
+	`fetch.bundleURI` value if the supplied bundle URI contains a bundle
+	list that is organized for incremental fetches.
++
+If you modify this value and your repository has a `fetch.bundleCreationToken`
+value, then remove that `fetch.bundleCreationToken` value before fetching from
+the new bundle URI.
+
+fetch.bundleCreationToken::
+	When using `fetch.bundleURI` to fetch incrementally from a bundle
+	list that uses the "creationToken" heuristic, this config value
+	stores the maximum `creationToken` value of the downloaded bundles.
+	This value is used to prevent downloading bundles in the future
+	if the advertised `creationToken` is not strictly larger than this
+	value.
++
+The creation token values are chosen by the provider serving the specific
+bundle URI. If you modify the URI at `fetch.bundleURI`, then be sure to
+remove the value for the `fetch.bundleCreationToken` value before fetching.
diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index c7303d8..73678d8 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -3,7 +3,8 @@
 	'format-patch'.  The value can also be a double quoted string
 	which will enable attachments as the default and set the
 	value as the boundary.  See the --attach option in
-	linkgit:git-format-patch[1].
+	linkgit:git-format-patch[1].  To countermand an earlier
+	value, set it to an empty string.
 
 format.from::
 	Provides the default value for the `--from` option to format-patch.
@@ -139,3 +140,7 @@
 ------------
 +
 will only show notes from `refs/notes/bar`.
+
+format.mboxrd::
+	A boolean value which enables the robust "mboxrd" format when
+	`--stdout` is in use to escape "^>+From " lines.
diff --git a/Documentation/config/gpg.txt b/Documentation/config/gpg.txt
index 86f6308..37e2831 100644
--- a/Documentation/config/gpg.txt
+++ b/Documentation/config/gpg.txt
@@ -12,6 +12,9 @@
 gpg.format::
 	Specifies which key format to use when signing with `--gpg-sign`.
 	Default is "openpgp". Other possible values are "x509", "ssh".
++
+See linkgit:gitformat-signature[5] for the signature format, which differs
+based on the selected `gpg.format`.
 
 gpg.<format>.program::
 	Use this to customize the program used for the signing format you
diff --git a/Documentation/config/index.txt b/Documentation/config/index.txt
index 75f3a2d..23c7985 100644
--- a/Documentation/config/index.txt
+++ b/Documentation/config/index.txt
@@ -30,3 +30,14 @@
 	Specify the version with which new index files should be
 	initialized.  This does not affect existing repositories.
 	If `feature.manyFiles` is enabled, then the default is 4.
+
+index.skipHash::
+	When enabled, do not compute the trailing hash for the index file.
+	This accelerates Git commands that manipulate the index, such as
+	`git add`, `git commit`, or `git status`. Instead of storing the
+	checksum, write a trailing set of bytes with value zero, indicating
+	that the computation was skipped.
++
+If you enable `index.skipHash`, then Git clients older than 2.13.0 will
+refuse to parse the index and Git clients older than 2.40.0 will report an
+error during `git fsck`.
diff --git a/Documentation/config/transfer.txt b/Documentation/config/transfer.txt
index 264812c..c3ac767 100644
--- a/Documentation/config/transfer.txt
+++ b/Documentation/config/transfer.txt
@@ -115,3 +115,9 @@
 transfer.advertiseSID::
 	Boolean. When true, client and server processes will advertise their
 	unique session IDs to their remote counterpart. Defaults to false.
+
+transfer.bundleURI::
+	When `true`, local `git clone` commands will request bundle
+	information from the remote server (if advertised) and download
+	bundles before continuing the clone through the Git protocol.
+	Defaults to `false`.
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index c78063d..546adf7 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -1,3 +1,4 @@
+[[generate_patch_text_with_p]]
 Generating patch text with -p
 -----------------------------
 
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 3674ac4..7d73e97 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -22,7 +22,13 @@
 -p::
 -u::
 --patch::
-	Generate patch (see section on generating patches).
+	Generate patch (see section titled
+ifdef::git-log[]
+<<generate_patch_text_with_p, "Generating patch text with -p">>).
+endif::git-log[]
+ifndef::git-log[]
+"Generating patch text with -p").
+endif::git-log[]
 ifdef::git-diff[]
 	This is the default.
 endif::git-diff[]
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index a030d33..ed44c1c 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -274,7 +274,7 @@
 ------------
               staged     unstaged path
      1:       binary      nothing foo.png
-     2:     +403/-35        +1/-1 git-add--interactive.perl
+     2:     +403/-35        +1/-1 add-interactive.c
 ------------
 +
 It shows that foo.png has differences from HEAD (but that is
@@ -282,7 +282,7 @@
 difference between indexed copy and the working tree
 version (if the working tree version were also different,
 'binary' would have been shown in place of 'nothing').  The
-other file, git-add{litdd}interactive.perl, has 403 lines added
+other file, add-interactive.c, has 403 lines added
 and 35 lines deleted if you commit what is in the index, but
 working tree file has further modifications (one addition and
 one deletion).
@@ -303,7 +303,7 @@
 ------------
            staged     unstaged path
   1:       binary      nothing foo.png
-* 2:     +403/-35        +1/-1 git-add--interactive.perl
+* 2:     +403/-35        +1/-1 add-interactive.c
 ------------
 +
 To remove selection, prefix the input with `-`
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 326276e..0c1dfb3 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -9,7 +9,7 @@
 SYNOPSIS
 --------
 [verse]
-'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8]
+'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--no-verify]
 	 [--[no-]3way] [--interactive] [--committer-date-is-author-date]
 	 [--ignore-date] [--ignore-space-change | --ignore-whitespace]
 	 [--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
@@ -138,6 +138,12 @@
 --interactive::
 	Run interactively.
 
+-n::
+--no-verify::
+	By default, the pre-applypatch and applypatch-msg hooks are run.
+	When any of `--no-verify` or `-n` is given, these are bypassed.
+	See also linkgit:githooks[5].
+
 --committer-date-is-author-date::
 	By default the command records the date from the e-mail
 	message as the commit author date, and uses the time of
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index 1d478cb..5e16e6d 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -208,7 +208,7 @@
 * `warn` outputs warnings for a few such errors, but applies the
   patch as-is (default).
 * `fix` outputs warnings for a few such errors, and applies the
-  patch after fixing them (`strip` is a synonym --- the tool
+  patch after fixing them (`strip` is a synonym -- the tool
   used to consider only trailing whitespace characters as errors, and the
   fix involved 'stripping' them, but modern Gits do more).
 * `error` outputs warnings for a few such errors, and refuses
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index 60c0409..6bab201 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -86,6 +86,11 @@
 	Look for attributes in .gitattributes files in the working tree
 	as well (see <<ATTRIBUTES>>).
 
+--mtime=<time>::
+	Set modification time of archive entries.  Without this option
+	the committer time is used if `<tree-ish>` is a commit or tag,
+	and the current time if it is a tree.
+
 <extra>::
 	This can be any options that the archiver backend understands.
 	See next section.
diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt
index f3d9566..0bc1657 100644
--- a/Documentation/git-bisect-lk2009.txt
+++ b/Documentation/git-bisect-lk2009.txt
@@ -1347,8 +1347,8 @@
 References
 ----------
 
-- [[[1]]] https://www.nist.gov/sites/default/files/documents/director/planning/report02-3.pdf['The Economic Impacts of Inadequate Infratructure for Software Testing'.  Nist Planning Report 02-3], see Executive Summary and Chapter 8.
-- [[[2]]] http://www.oracle.com/technetwork/java/codeconvtoc-136057.html['Code Conventions for the Java Programming Language'. Sun Microsystems.]
+- [[[1]]] https://web.archive.org/web/20091206032101/http://www.nist.gov/public_affairs/releases/n02-10.htm['Software Errors Cost U.S. Economy $59.5 Billion Annually'. Nist News Release.] See also https://www.nist.gov/system/files/documents/director/planning/report02-3.pdf['The Economic Impacts of Inadequate Infratructure for Software Testing'.  Nist Planning Report 02-3], Executive Summary and Chapter 8.
+- [[[2]]] https://www.oracle.com/java/technologies/javase/codeconventions-introduction.html['Code Conventions for the Java Programming Language: 1. Introduction'. Sun Microsystems.]
 - [[[3]]] https://en.wikipedia.org/wiki/Software_maintenance['Software maintenance'. Wikipedia.]
 - [[[4]]] https://lore.kernel.org/git/7vps5xsbwp.fsf_-_@assigned-by-dhcp.cox.net/[Junio C Hamano. 'Automated bisect success story'.]
 - [[[5]]] https://lwn.net/Articles/317154/[Christian Couder. 'Fully automated bisecting with "git bisect run"'. LWN.net.]
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 2aaf13b..d382ac6 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -116,7 +116,7 @@
 
 -f::
 --force::
-	Reset <branchname> to <startpoint>, even if <branchname> exists
+	Reset <branchname> to <start-point>, even if <branchname> exists
 	already. Without `-f`, 'git branch' refuses to change an existing branch.
 	In combination with `-d` (or `--delete`), allow deleting the
 	branch irrespective of its merged status, or whether it even
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index ec30b5c..411de2e 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -45,7 +45,9 @@
 
 -s::
 	Instead of the content, show the object size identified by
-	`<object>`.
+	`<object>`. If used with `--use-mailmap` option, will show
+	the size of updated object after replacing idents using the
+	mailmap mechanism.
 
 -e::
 	Exit with zero status if `<object>` exists and is a valid
@@ -89,26 +91,54 @@
 --batch::
 --batch=<format>::
 	Print object information and contents for each object provided
-	on stdin.  May not be combined with any other options or arguments
-	except `--textconv` or `--filters`, in which case the input lines
-	also need to specify the path, separated by whitespace.  See the
-	section `BATCH OUTPUT` below for details.
+	on stdin. May not be combined with any other options or arguments
+	except `--textconv`, `--filters`, or `--use-mailmap`.
++
+--
+	* When used with `--textconv` or `--filters`, the input lines
+	  must specify the path, separated by whitespace. See the section
+	  `BATCH OUTPUT` below for details.
+
+	* When used with `--use-mailmap`, for commit and tag objects, the
+	  contents part of the output shows the identities replaced using the
+	  mailmap mechanism, while the information part of the output shows
+	  the size of the object as if it actually recorded the replacement
+	  identities.
+--
 
 --batch-check::
 --batch-check=<format>::
-	Print object information for each object provided on stdin.  May
-	not be combined with any other options or arguments except
-	`--textconv` or `--filters`, in which case the input lines also
-	need to specify the path, separated by whitespace.  See the
-	section `BATCH OUTPUT` below for details.
+	Print object information for each object provided on stdin. May not be
+	combined with any other options or arguments except `--textconv`, `--filters`
+	or `--use-mailmap`.
++
+--
+	* When used with `--textconv` or `--filters`, the input lines must
+	 specify the path, separated by whitespace. See the section
+	 `BATCH OUTPUT` below for details.
+
+	* When used with `--use-mailmap`, for commit and tag objects, the
+	  printed object information shows the size of the object as if the
+	  identities recorded in it were replaced by the mailmap mechanism.
+--
 
 --batch-command::
 --batch-command=<format>::
 	Enter a command mode that reads commands and arguments from stdin. May
-	only be combined with `--buffer`, `--textconv` or `--filters`. In the
-	case of `--textconv` or `--filters`, the input lines also need to specify
-	the path, separated by whitespace. See the section `BATCH OUTPUT` below
-	for details.
+	only be combined with `--buffer`, `--textconv`, `--use-mailmap` or
+	`--filters`.
++
+--
+	* When used with `--textconv` or `--filters`, the input lines must
+	  specify the path, separated by whitespace. See the section
+	  `BATCH OUTPUT` below for details.
+
+	* When used with `--use-mailmap`, for commit and tag objects, the
+	  `contents` command shows the identities replaced using the
+	  mailmap mechanism, while the `info` command shows the size
+	  of the object as if it actually recorded the replacement
+	  identities.
+--
 +
 `--batch-command` recognizes the following commands:
 +
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
index 84f41a8..6e4f3aa 100644
--- a/Documentation/git-check-attr.txt
+++ b/Documentation/git-check-attr.txt
@@ -9,8 +9,8 @@
 SYNOPSIS
 --------
 [verse]
-'git check-attr' [-a | --all | <attr>...] [--] <pathname>...
-'git check-attr' --stdin [-z] [-a | --all | <attr>...]
+'git check-attr' [--source <tree-ish>] [-a | --all | <attr>...] [--] <pathname>...
+'git check-attr' --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]
 
 DESCRIPTION
 -----------
@@ -36,6 +36,11 @@
 	If `--stdin` is also given, input paths are separated
 	with a NUL character instead of a linefeed character.
 
+--source=<tree-ish>::
+	Check attributes against the specified tree-ish. It is common to
+	specify the source tree by naming a commit, branch or tag associated
+	with it.
+
 \--::
 	Interpret all preceding arguments as attributes and all following
 	arguments as path names.
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index dcff441..6bb32ab 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -479,9 +479,9 @@
 any of these will create a reference to it:
 
 ------------
-$ git checkout -b foo   <1>
-$ git branch foo        <2>
-$ git tag foo           <3>
+$ git checkout -b foo  # or "git switch -c foo"  <1>
+$ git branch foo                                 <2>
+$ git tag foo                                    <3>
 ------------
 
 <1> creates a new branch `foo`, which refers to commit `f`, and then
diff --git a/Documentation/git-credential-cache.txt b/Documentation/git-credential-cache.txt
index 432e159..f473994 100644
--- a/Documentation/git-credential-cache.txt
+++ b/Documentation/git-credential-cache.txt
@@ -14,10 +14,13 @@
 DESCRIPTION
 -----------
 
-This command caches credentials in memory for use by future Git
-programs. The stored credentials never touch the disk, and are forgotten
-after a configurable timeout.  The cache is accessible over a Unix
-domain socket, restricted to the current user by filesystem permissions.
+This command caches credentials for use by future Git programs.
+The stored credentials are kept in memory of the cache-daemon
+process (instead of written to a file) and are forgotten after a
+configurable timeout. Credentials are forgotten sooner if the
+cache-daemon dies, for example if the system restarts. The cache
+is accessible over a Unix domain socket, restricted to the current
+user by filesystem permissions.
 
 You probably don't want to invoke this command directly; it is meant to
 be used as a credential helper by other parts of Git. See
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index ac2818b..29d184a 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -144,6 +144,12 @@
 
 	The credential's password, if we are asking it to be stored.
 
+`password_expiry_utc`::
+
+	Generated passwords such as an OAuth access token may have an expiry date.
+	When reading credentials from helpers, `git credential fill` ignores expired
+	passwords. Represented as Unix time UTC, seconds since 1970.
+
 `url`::
 
 	When this special attribute is read by `git credential`, the
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index 63d9569..fba66f1 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -251,10 +251,10 @@
 $ git fetch origin
 ------------------------------------------------
 +
-The above command copies all branches from the remote refs/heads/
-namespace and stores them to the local refs/remotes/origin/ namespace,
-unless the branch.<name>.fetch option is used to specify a non-default
-refspec.
+The above command copies all branches from the remote `refs/heads/`
+namespace and stores them to the local `refs/remotes/origin/` namespace,
+unless the `remote.<repository>.fetch` option is used to specify a
+non-default refspec.
 
 * Using refspecs explicitly:
 +
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
index 77c3a8a..3407f3c 100644
--- a/Documentation/git-hook.txt
+++ b/Documentation/git-hook.txt
@@ -8,7 +8,7 @@
 SYNOPSIS
 --------
 [verse]
-'git hook' run [--ignore-missing] <hook-name> [-- <hook-args>]
+'git hook' run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]
 
 DESCRIPTION
 -----------
@@ -31,6 +31,11 @@
 OPTIONS
 -------
 
+--to-stdin::
+	For "run"; Specify a file which will be streamed into the
+	hook's stdin. The hook will receive the entire file from
+	beginning to EOF.
+
 --ignore-missing::
 	Ignore any missing hook by quietly returning zero. Used for
 	tools that want to do a blind one-shot run of a hook that may
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 440043c..1abdd3c 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -12,6 +12,7 @@
 'git ls-files' [-z] [-t] [-v] [-f]
 		[-c|--cached] [-d|--deleted] [-o|--others] [-i|--ignored]
 		[-s|--stage] [-u|--unmerged] [-k|--killed] [-m|--modified]
+		[--resolve-undo]
 		[--directory [--no-empty-directory]] [--eol]
 		[--deduplicate]
 		[-x <pattern>|--exclude=<pattern>]
@@ -28,21 +29,26 @@
 directory list, and shows different combinations of the two.
 
 One or more of the options below may be used to determine the files
-shown:
+shown, and each file may be printed multiple times if there are
+multiple entries in the index or multiple statuses are applicable for
+the relevant file selection options.
 
 OPTIONS
 -------
 -c::
 --cached::
-	Show cached files in the output (default)
+	Show all files cached in Git's index, i.e. all tracked files.
+	(This is the default if no -c/-s/-d/-o/-u/-k/-m/--resolve-undo
+	options are specified.)
 
 -d::
 --deleted::
-	Show deleted files in the output
+	Show files with an unstaged deletion
 
 -m::
 --modified::
-	Show modified files in the output
+	Show files with an unstaged modification (note that an unstaged
+	deletion also counts as an unstaged modification)
 
 -o::
 --others::
@@ -50,11 +56,14 @@
 
 -i::
 --ignored::
-	Show only ignored files in the output. When showing files in the
-	index, print only those matched by an exclude pattern. When
-	showing "other" files, show only those matched by an exclude
-	pattern. Standard ignore rules are not automatically activated,
-	therefore at least one of the `--exclude*` options is required.
+	Show only ignored files in the output.  Must be used with
+	either an explicit '-c' or '-o'.  When showing files in the
+	index (i.e. when used with '-c'), print only those files
+	matching an exclude pattern.  When showing "other" files
+	(i.e. when used with '-o'), show only those matched by an
+	exclude pattern.  Standard ignore rules are not automatically
+	activated, therefore at least one of the `--exclude*` options
+	is required.
 
 -s::
 --stage::
@@ -63,19 +72,29 @@
 --directory::
 	If a whole directory is classified as "other", show just its
 	name (with a trailing slash) and not its whole contents.
+	Has no effect without -o/--others.
 
 --no-empty-directory::
 	Do not list empty directories. Has no effect without --directory.
 
 -u::
 --unmerged::
-	Show unmerged files in the output (forces --stage)
+	Show information about unmerged files in the output, but do
+	not show any other tracked files (forces --stage, overrides
+	--cached).
 
 -k::
 --killed::
-	Show files on the filesystem that need to be removed due
-	to file/directory conflicts for checkout-index to
-	succeed.
+	Show untracked files on the filesystem that need to be removed
+	due to file/directory conflicts for tracked files to be able to
+	be written to the filesystem.
+
+--resolve-undo::
+	Show files having resolve-undo information in the index
+	together with their resolve-undo information.  (resolve-undo
+	information is what is used to implement "git checkout -m
+	$PATH", i.e. to recreate merge conflicts that were
+	accidentally resolved)
 
 -z::
 	\0 line termination on output and do not quote filenames.
@@ -100,7 +119,8 @@
 
 --exclude-per-directory=<file>::
 	Read additional exclude patterns that apply only to the
-	directory and its subdirectories in <file>.
+	directory and its subdirectories in <file>.  Deprecated; use
+	--exclude-standard instead.
 
 --exclude-standard::
 	Add the standard Git exclusions: .git/info/exclude, .gitignore
@@ -118,24 +138,27 @@
 	with `-s` or `-u` options does not make any sense.
 
 -t::
-	This feature is semi-deprecated. For scripting purpose,
-	linkgit:git-status[1] `--porcelain` and
+	Show status tags together with filenames.  Note that for
+	scripting purposes, linkgit:git-status[1] `--porcelain` and
 	linkgit:git-diff-files[1] `--name-status` are almost always
 	superior alternatives, and users should look at
 	linkgit:git-status[1] `--short` or linkgit:git-diff[1]
 	`--name-status` for more user-friendly alternatives.
 +
 --
-This option identifies the file status with the following tags (followed by
-a space) at the start of each line:
+This option provides a reason for showing each filename, in the form
+of a status tag (which is followed by a space and then the filename).
+The status tags are all single characters from the following list:
 
-	H::	cached
-	S::	skip-worktree
-	M::	unmerged
-	R::	removed/deleted
-	C::	modified/changed
-	K::	to be killed
-	?::	other
+	H::	tracked file that is not either unmerged or skip-worktree
+	S::	tracked file that is skip-worktree
+	M::	tracked file that is unmerged
+	R::	tracked file with unstaged removal/deletion
+	C::	tracked file with unstaged modification/change
+	K::	untracked paths which are part of file/directory conflicts
+		which prevent checking out tracked files
+	?::	untracked file
+	U::     file with resolve-undo information
 --
 
 -v::
@@ -269,7 +292,9 @@
 flags --others or --ignored are specified.  linkgit:gitignore[5]
 specifies the format of exclude patterns.
 
-These exclude patterns come from these places, in order:
+Generally, you should just use --exclude-standard, but for historical
+reasons the exclude patterns can be specified from the following
+places, in order:
 
   1. The command-line flag --exclude=<pattern> specifies a
      single pattern.  Patterns are ordered in the same order
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index 492e573..ff3da54 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -11,7 +11,7 @@
 [verse]
 'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]
 	      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]
-	      [--symref] [<repository> [<refs>...]]
+	      [--symref] [<repository> [<patterns>...]]
 
 DESCRIPTION
 -----------
@@ -85,25 +85,32 @@
 	either a URL or the name of a remote (see the GIT URLS and
 	REMOTES sections of linkgit:git-fetch[1]).
 
-<refs>...::
+<patterns>...::
 	When unspecified, all references, after filtering done
-	with --heads and --tags, are shown.  When <refs>... are
-	specified, only references matching the given patterns
-	are displayed.
+	with --heads and --tags, are shown.  When <patterns>... are
+	specified, only references matching one or more of the given
+	patterns are displayed. Each pattern is interpreted as a glob
+	(see `glob` in linkgit:gitglossary[7]) which is matched against
+	the "tail" of a ref, starting either from the start of the ref
+	(so a full name like `refs/heads/foo` matches) or from a slash
+	separator (so `bar` matches `refs/heads/bar` but not
+	`refs/heads/foobar`).
 
 EXAMPLES
 --------
 
 ----
-$ git ls-remote --tags ./.
+$ git ls-remote --tags .
 d6602ec5194c87b0fc87103ca4d67251c76f233a	refs/tags/v0.99
 f25a265a342aed6041ab0cc484224d9ca54b6f41	refs/tags/v0.99.1
 7ceca275d047c90c0c7d5afb13ab97efdf51bd6e	refs/tags/v0.99.3
 c5db5456ae3b0873fc659c19fafdde22313cc441	refs/tags/v0.99.2
 0918385dbd9656cab0d1d81ba7453d49bbc16250	refs/tags/junio-gpg-pub
+
 $ git ls-remote http://www.kernel.org/pub/scm/git/git.git master seen rc
 5fe978a5381f1fbad26a80e682ddd2a401966740	refs/heads/master
 c781a84b5204fb294c9ccc79f8b3baceeb32c061	refs/heads/seen
+
 $ git remote add korg http://www.kernel.org/pub/scm/git/git.git
 $ git ls-remote --tags korg v\*
 d6602ec5194c87b0fc87103ca4d67251c76f233a	refs/tags/v0.99
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt
index 04bcc41..88ee942 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.txt
@@ -64,6 +64,11 @@
 	share no common history.  This flag can be given to override that
 	check and make the merge proceed anyway.
 
+--merge-base=<commit>::
+	Instead of finding the merge-bases for <branch1> and <branch2>,
+	specify a merge-base for the merge, and specifying multiple bases is
+	currently not supported. This option is incompatible with `--stdin`.
+
 [[OUTPUT]]
 OUTPUT
 ------
@@ -216,6 +221,17 @@
   * any messages that would have been printed to stdout (the
     <<IM,Informational messages>>)
 
+INPUT FORMAT
+------------
+'git merge-tree --stdin' input format is fully text based. Each line
+has this format:
+
+	[<base-commit> -- ]<branch1> <branch2>
+
+If one line is separated by `--`, the string before the separator is
+used for specifying a merge-base for the merge and the string after
+the separator describes the branches to be merged.
+
 MISTAKES TO AVOID
 -----------------
 
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index 7567955..b097074 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -219,7 +219,7 @@
 `git diff-index --cached $M`.  Note that this does not
 necessarily match what `git diff-index --cached $H` would have
 produced before such a two tree merge.  This is because of cases
-18 and 19 --- if you already had the changes in $M (e.g. maybe
+18 and 19 -- if you already had the changes in $M (e.g. maybe
 you picked it up via e-mail in a patch form), `git diff-index
 --cached $H` would have told you about the change before this
 merge, but it would not show in `git diff-index --cached $M`
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index d811c1c..9a295bc 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -208,6 +208,39 @@
 
     git rebase --abort
 
+MODE OPTIONS
+------------
+
+The options in this section cannot be used with any other option,
+including not with each other:
+
+--continue::
+	Restart the rebasing process after having resolved a merge conflict.
+
+--skip::
+	Restart the rebasing process by skipping the current patch.
+
+--abort::
+	Abort the rebase operation and reset HEAD to the original
+	branch. If `<branch>` was provided when the rebase operation was
+	started, then `HEAD` will be reset to `<branch>`. Otherwise `HEAD`
+	will be reset to where it was when the rebase operation was
+	started.
+
+--quit::
+	Abort the rebase operation but `HEAD` is not reset back to the
+	original branch. The index and working tree are also left
+	unchanged as a result. If a temporary stash entry was created
+	using `--autostash`, it will be saved to the stash list.
+
+--edit-todo::
+	Edit the todo list during an interactive rebase.
+
+--show-current-patch::
+	Show the current patch in an interactive rebase or when rebase
+	is stopped because of conflicts. This is the equivalent of
+	`git show REBASE_HEAD`.
+
 OPTIONS
 -------
 --onto <newbase>::
@@ -249,22 +282,6 @@
 <branch>::
 	Working branch; defaults to `HEAD`.
 
---continue::
-	Restart the rebasing process after having resolved a merge conflict.
-
---abort::
-	Abort the rebase operation and reset HEAD to the original
-	branch. If `<branch>` was provided when the rebase operation was
-	started, then `HEAD` will be reset to `<branch>`. Otherwise `HEAD`
-	will be reset to where it was when the rebase operation was
-	started.
-
---quit::
-	Abort the rebase operation but `HEAD` is not reset back to the
-	original branch. The index and working tree are also left
-	unchanged as a result. If a temporary stash entry was created
-	using `--autostash`, it will be saved to the stash list.
-
 --apply::
 	Use applying strategies to rebase (calling `git-am`
 	internally).  This option may become a no-op in the future
@@ -321,7 +338,6 @@
 	upstream changes, the behavior towards them is controlled by
 	the `--empty` flag.)
 +
-
 In the absence of `--keep-base` (or if `--no-reapply-cherry-picks` is
 given), these commits will be automatically dropped.  Because this
 necessitates reading all upstream commits, this can be expensive in
@@ -330,7 +346,6 @@
 dropped commit (unless `--quiet` is given). Advice will also be issued
 unless `advice.skippedCherryPicks` is set to false (see
 linkgit:git-config[1]).
-
 +
 `--reapply-cherry-picks` allows rebase to forgo reading all upstream
 commits, potentially improving performance.
@@ -345,17 +360,6 @@
 +
 See also INCOMPATIBLE OPTIONS below.
 
---skip::
-	Restart the rebasing process by skipping the current patch.
-
---edit-todo::
-	Edit the todo list during an interactive rebase.
-
---show-current-patch::
-	Show the current patch in an interactive rebase or when rebase
-	is stopped because of conflicts. This is the equivalent of
-	`git show REBASE_HEAD`.
-
 -m::
 --merge::
 	Using merging strategies to rebase (default).
@@ -574,10 +578,7 @@
 --root::
 	Rebase all commits reachable from `<branch>`, instead of
 	limiting them with an `<upstream>`.  This allows you to rebase
-	the root commit(s) on a branch.  When used with `--onto`, it
-	will skip changes already contained in `<newbase>` (instead of
-	`<upstream>`) whereas without `--onto` it will operate on every
-	change.
+	the root commit(s) on a branch.
 +
 See also INCOMPATIBLE OPTIONS below.
 
@@ -630,6 +631,8 @@
 +
 If the configuration variable `rebase.updateRefs` is set, then this option
 can be used to override and disable this setting.
++
+See also INCOMPATIBLE OPTIONS below.
 
 INCOMPATIBLE OPTIONS
 --------------------
@@ -645,17 +648,15 @@
  * --merge
  * --strategy
  * --strategy-option
- * --allow-empty-message
- * --[no-]autosquash
+ * --autosquash
  * --rebase-merges
  * --interactive
  * --exec
  * --no-keep-empty
  * --empty=
- * --reapply-cherry-picks
- * --edit-todo
+ * --[no-]reapply-cherry-picks when used without --keep-base
  * --update-refs
- * --root when used in combination with --onto
+ * --root when used without --onto
 
 In addition, the following pairs of options are incompatible:
 
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 5e438a7..a051b1e 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -457,6 +457,66 @@
 them to fail. Scripts running `status` in the background should consider
 using `git --no-optional-locks status` (see linkgit:git[1] for details).
 
+UNTRACKED FILES AND PERFORMANCE
+-------------------------------
+
+`git status` can be very slow in large worktrees if/when it
+needs to search for untracked files and directories. There are
+many configuration options available to speed this up by either
+avoiding the work or making use of cached results from previous
+Git commands. There is no single optimum set of settings right
+for everyone. We'll list a summary of the relevant options to help
+you, but before going into the list, you may want to run `git status`
+again, because your configuration may already be caching `git status`
+results, so it could be faster on subsequent runs.
+
+* The `--untracked-files=no` flag or the
+	`status.showUntrackedfiles=false` config (see above for both):
+	indicate that `git status` should not report untracked
+	files. This is the fastest option. `git status` will not list
+	the untracked files, so you need to be careful to remember if
+	you create any new files and manually `git add` them.
+
+* `advice.statusUoption=false` (see linkgit:git-config[1]):
+	setting this variable to `false` disables the warning message
+	given when enumerating untracked files takes more than 2
+	seconds.  In a large project, it may take longer and the user
+	may have already accepted the trade off (e.g. using "-uno" may
+	not be an acceptable option for the user), in which case, there
+	is no point issuing the warning message, and in such a case,
+	disabling the warning may be the best.
+
+* `core.untrackedCache=true` (see linkgit:git-update-index[1]):
+	enable the untracked cache feature and only search directories
+	that have been modified since the previous `git status` command.
+	Git remembers the set of untracked files within each directory
+	and assumes that if a directory has not been modified, then
+	the set of untracked files within has not changed.  This is much
+	faster than enumerating the contents of every directory, but still
+	not without cost, because Git still has to search for the set of
+	modified directories. The untracked cache is stored in the
+	`.git/index` file. The reduced cost of searching for untracked
+	files is offset slightly by the increased size of the index and
+	the cost of keeping it up-to-date. That reduced search time is
+	usually worth the additional size.
+
+* `core.untrackedCache=true` and `core.fsmonitor=true` or
+	`core.fsmonitor=<hook_command_pathname>` (see
+	linkgit:git-update-index[1]): enable both the untracked cache
+	and FSMonitor features and only search directories that have
+	been modified since the previous `git status` command.  This
+	is faster than using just the untracked cache alone because
+	Git can also avoid searching for modified directories.  Git
+	only has to enumerate the exact set of directories that have
+	changed recently. While the FSMonitor feature can be enabled
+	without the untracked cache, the benefits are greatly reduced
+	in that case.
+
+Note that after you turn on the untracked cache and/or FSMonitor
+features it may take a few `git status` commands for the various
+caches to warm up before you see improved command times.  This is
+normal.
+
 SEE ALSO
 --------
 linkgit:gitignore[5]
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index 6aa521f..f40202b 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -13,7 +13,8 @@
 
 DESCRIPTION
 -----------
-Prints a Git logical variable.
+Prints a Git logical variable. Exits with code 1 if the variable has
+no value.
 
 OPTIONS
 -------
@@ -49,6 +50,14 @@
     The build you are using chose '{git-default-editor}' as the default.
 endif::git-default-editor[]
 
+GIT_SEQUENCE_EDITOR::
+    Text editor used to edit the 'todo' file while running `git rebase
+    -i`. Like `GIT_EDITOR`, the value is meant to be interpreted by
+    the shell when it is used. The order of preference is the
+    `$GIT_SEQUENCE_EDITOR` environment variable, then
+    `sequence.editor` configuration, and then the value of `git var
+    GIT_EDITOR`.
+
 GIT_PAGER::
     Text viewer for use by Git commands (e.g., 'less').  The value
     is meant to be interpreted by the shell.  The order of preference
diff --git a/Documentation/git.txt b/Documentation/git.txt
index d296946..898907b 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -13,8 +13,7 @@
     [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
     [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
     [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
-    [--super-prefix=<path>] [--config-env=<name>=<envvar>]
-    <command> [<args>]
+    [--config-env=<name>=<envvar>] <command> [<args>]
 
 DESCRIPTION
 -----------
@@ -169,11 +168,6 @@
 	details.  Equivalent to setting the `GIT_NAMESPACE` environment
 	variable.
 
---super-prefix=<path>::
-	Currently for internal use only.  Set a prefix which gives a path from
-	above a repository down to its root.  One use is to give submodules
-	context about the superproject that invoked it.
-
 --bare::
 	Treat the repository as a bare repository.  If GIT_DIR
 	environment is not set, it is set to the current working
@@ -619,7 +613,7 @@
 (e.g. `new-file` in "git-diff-files"), `/dev/null` (e.g. `old-file`
 when a new file is added), or a temporary file (e.g. `old-file` in the
 index).  `GIT_EXTERNAL_DIFF` should not worry about unlinking the
-temporary file --- it is removed when `GIT_EXTERNAL_DIFF` exits.
+temporary file -- it is removed when `GIT_EXTERNAL_DIFF` exits.
 +
 For a path that is unmerged, `GIT_EXTERNAL_DIFF` is called with 1
 parameter, <path>.
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 4b36d51..39bfbca 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -758,6 +758,37 @@
 parameters, just like `GIT_EXTERNAL_DIFF` program is called.
 See linkgit:git[1] for details.
 
+Setting the internal diff algorithm
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The diff algorithm can be set through the `diff.algorithm` config key, but
+sometimes it may be helpful to set the diff algorithm per path. For example,
+one may want to use the `minimal` diff algorithm for .json files, and the
+`histogram` for .c files, and so on without having to pass in the algorithm
+through the command line each time.
+
+First, in `.gitattributes`, assign the `diff` attribute for paths.
+
+------------------------
+*.json diff=<name>
+------------------------
+
+Then, define a "diff.<name>.algorithm" configuration to specify the diff
+algorithm, choosing from `myers`, `patience`, `minimal`, or `histogram`.
+
+----------------------------------------------------------------
+[diff "<name>"]
+  algorithm = histogram
+----------------------------------------------------------------
+
+This diff algorithm applies to user facing diff output like git-diff(1),
+git-show(1) and is used for the `--stat` output as well. The merge machinery
+will not use the diff algorithm set through this method.
+
+NOTE: If `diff.<name>.command` is defined for path with the
+`diff=<name>` attribute, it is executed as an external diff driver
+(see above), and adding `diff.<name>.algorithm` has no effect, as the
+algorithm is not passed to the external diff driver.
 
 Defining a custom hunk-header
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1155,7 +1186,7 @@
 
 String::
 
-	Specify a comma separate list of common whitespace problems to
+	Specify a comma separated list of common whitespace problems to
 	notice in the same format as the `core.whitespace` configuration
 	variable.
 
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 4522471..100f045 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -167,7 +167,7 @@
 If there are multiple instances of the `credential.helper` configuration
 variable, each helper will be tried in turn, and may provide a username,
 password, or nothing. Once Git has acquired both a username and a
-password, no more helpers will be tried.
+non-expired password, no more helpers will be tried.
 +
 If `credential.helper` is configured to the empty string, this resets
 the helper list to empty (so you may override a helper set by a
diff --git a/Documentation/gitformat-index.txt b/Documentation/gitformat-index.txt
index 015cb21..0773e5c 100644
--- a/Documentation/gitformat-index.txt
+++ b/Documentation/gitformat-index.txt
@@ -83,11 +83,13 @@
 
   32-bit mode, split into (high to low bits)
 
+    16-bit unused, must be zero
+
     4-bit object type
       valid values in binary are 1000 (regular file), 1010 (symbolic link)
       and 1110 (gitlink)
 
-    3-bit unused
+    3-bit unused, must be zero
 
     9-bit unix permission. Only 0755 and 0644 are valid for regular files.
     Symbolic links and gitlinks have value 0 in this field.
diff --git a/Documentation/gitformat-signature.txt b/Documentation/gitformat-signature.txt
index a249869..d4d3a31 100644
--- a/Documentation/gitformat-signature.txt
+++ b/Documentation/gitformat-signature.txt
@@ -17,12 +17,24 @@
 Git uses cryptographic signatures in various places, currently objects (tags,
 commits, mergetags) and transactions (pushes). In every case, the command which
 is about to create an object or transaction determines a payload from that,
-calls gpg to obtain a detached signature for the payload (`gpg -bsa`) and
-embeds the signature into the object or transaction.
+calls an external program to obtain a detached signature for the payload
+(`gpg -bsa` in the case of PGP signatures), and embeds the signature into the
+object or transaction.
 
-Signatures always begin with `-----BEGIN PGP SIGNATURE-----`
-and end with `-----END PGP SIGNATURE-----`, unless gpg is told to
-produce RFC1991 signatures which use `MESSAGE` instead of `SIGNATURE`.
+Signatures begin with an "ASCII Armor" header line and end with a tail line,
+which differ depending on signature type (as selected by `gpg.format`, see
+linkgit:git-config[1]). These are, for `gpg.format` values:
+
+`gpg` (PGP)::
+	`-----BEGIN PGP SIGNATURE-----` and `-----END PGP SIGNATURE-----`.
+	Or, if gpg is told to produce RFC1991 signatures,
+	`-----BEGIN PGP MESSAGE-----` and `-----END PGP MESSAGE-----`
+
+`ssh` (SSH)::
+	`-----BEGIN SSH SIGNATURE-----` and `-----END SSH SIGNATURE-----`
+
+`x509` (X.509)::
+	`-----BEGIN SIGNED MESSAGE-----` and `-----END SIGNED MESSAGE-----`
 
 Signatures sometimes appear as a part of the normal payload
 (e.g. a signed tag has the signature block appended after the payload
@@ -37,7 +49,7 @@
 This is even true for an originally empty line.  In the following
 examples, the end of line that ends with a whitespace letter is
 highlighted with a `$` sign; if you are trying to recreate these
-example by hand, do not cut and paste them---they are there
+example by hand, do not cut and paste them--they are there
 primarily to highlight extra whitespace at the end of some lines.
 
 The signed payload and the way the signature is embedded depends
diff --git a/Documentation/gitprotocol-v2.txt b/Documentation/gitprotocol-v2.txt
index 59bf41c..acb97ad 100644
--- a/Documentation/gitprotocol-v2.txt
+++ b/Documentation/gitprotocol-v2.txt
@@ -578,6 +578,207 @@
 
 	obj-info = obj-id SP obj-size
 
+bundle-uri
+~~~~~~~~~~
+
+If the 'bundle-uri' capability is advertised, the server supports the
+`bundle-uri' command.
+
+The capability is currently advertised with no value (i.e. not
+"bundle-uri=somevalue"), a value may be added in the future for
+supporting command-wide extensions. Clients MUST ignore any unknown
+capability values and proceed with the 'bundle-uri` dialog they
+support.
+
+The 'bundle-uri' command is intended to be issued before `fetch` to
+get URIs to bundle files (see linkgit:git-bundle[1]) to "seed" and
+inform the subsequent `fetch` command.
+
+The client CAN issue `bundle-uri` before or after any other valid
+command. To be useful to clients it's expected that it'll be issued
+after an `ls-refs` and before `fetch`, but CAN be issued at any time
+in the dialog.
+
+DISCUSSION of bundle-uri
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The intent of the feature is optimize for server resource consumption
+in the common case by changing the common case of fetching a very
+large PACK during linkgit:git-clone[1] into a smaller incremental
+fetch.
+
+It also allows servers to achieve better caching in combination with
+an `uploadpack.packObjectsHook` (see linkgit:git-config[1]).
+
+By having new clones or fetches be a more predictable and common
+negotiation against the tips of recently produces *.bundle file(s).
+Servers might even pre-generate the results of such negotiations for
+the `uploadpack.packObjectsHook` as new pushes come in.
+
+One way that servers could take advantage of these bundles is that the
+server would anticipate that fresh clones will download a known bundle,
+followed by catching up to the current state of the repository using ref
+tips found in that bundle (or bundles).
+
+PROTOCOL for bundle-uri
+^^^^^^^^^^^^^^^^^^^^^^^
+
+A `bundle-uri` request takes no arguments, and as noted above does not
+currently advertise a capability value. Both may be added in the
+future.
+
+When the client issues a `command=bundle-uri` request, the response is a
+list of key-value pairs provided as packet lines with value
+`<key>=<value>`. Each `<key>` should be interpreted as a config key from
+the `bundle.*` namespace to construct a list of bundles. These keys are
+grouped by a `bundle.<id>.` subsection, where each key corresponding to a
+given `<id>` contributes attributes to the bundle defined by that `<id>`.
+See linkgit:git-config[1] for the specific details of these keys and how
+the Git client will interpret their values.
+
+Clients MUST parse the line according to the above format, lines that do
+not conform to the format SHOULD be discarded. The user MAY be warned in
+such a case.
+
+bundle-uri CLIENT AND SERVER EXPECTATIONS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+URI CONTENTS::
+The content at the advertised URIs MUST be one of two types.
++
+The advertised URI may contain a bundle file that `git bundle verify`
+would accept. I.e. they MUST contain one or more reference tips for
+use by the client, MUST indicate prerequisites (in any) with standard
+"-" prefixes, and MUST indicate their "object-format", if
+applicable.
++
+The advertised URI may alternatively contain a plaintext file that `git
+config --list` would accept (with the `--file` option). The key-value
+pairs in this list are in the `bundle.*` namespace (see
+linkgit:git-config[1]).
+
+bundle-uri CLIENT ERROR RECOVERY::
+A client MUST above all gracefully degrade on errors, whether that
+error is because of bad missing/data in the bundle URI(s), because
+that client is too dumb to e.g. understand and fully parse out bundle
+headers and their prerequisite relationships, or something else.
++
+Server operators should feel confident in turning on "bundle-uri" and
+not worry if e.g. their CDN goes down that clones or fetches will run
+into hard failures. Even if the server bundle(s) are
+incomplete, or bad in some way the client should still end up with a
+functioning repository, just as if it had chosen not to use this
+protocol extension.
++
+All subsequent discussion on client and server interaction MUST keep
+this in mind.
+
+bundle-uri SERVER TO CLIENT::
+The ordering of the returned bundle uris is not significant. Clients
+MUST parse their headers to discover their contained OIDS and
+prerequisites. A client MUST consider the content of the bundle(s)
+themselves and their header as the ultimate source of truth.
++
+A server MAY even return bundle(s) that don't have any direct
+relationship to the repository being cloned (either through accident,
+or intentional "clever" configuration), and expect a client to sort
+out what data they'd like from the bundle(s), if any.
+
+bundle-uri CLIENT TO SERVER::
+The client SHOULD provide reference tips found in the bundle header(s)
+as 'have' lines in any subsequent `fetch` request. A client MAY also
+ignore the bundle(s) entirely if doing so is deemed worse for some
+reason, e.g. if the bundles can't be downloaded, it doesn't like the
+tips it finds etc.
+
+WHEN ADVERTISED BUNDLE(S) REQUIRE NO FURTHER NEGOTIATION::
+If after issuing `bundle-uri` and `ls-refs`, and getting the header(s)
+of the bundle(s) the client finds that the ref tips it wants can be
+retrieved entirely from advertised bundle(s), the client MAY disconnect
+from the Git server. The results of such a 'clone' or 'fetch' should be
+indistinguishable from the state attained without using bundle-uri.
+
+EARLY CLIENT DISCONNECTIONS AND ERROR RECOVERY::
+A client MAY perform an early disconnect while still downloading the
+bundle(s) (having streamed and parsed their headers). In such a case
+the client MUST gracefully recover from any errors related to
+finishing the download and validation of the bundle(s).
++
+I.e. a client might need to re-connect and issue a 'fetch' command,
+and possibly fall back to not making use of 'bundle-uri' at all.
++
+This "MAY" behavior is specified as such (and not a "SHOULD") on the
+assumption that a server advertising bundle uris is more likely than
+not to be serving up a relatively large repository, and to be pointing
+to URIs that have a good chance of being in working order. A client
+MAY e.g. look at the payload size of the bundles as a heuristic to see
+if an early disconnect is worth it, should falling back on a full
+"fetch" dialog be necessary.
+
+WHEN ADVERTISED BUNDLE(S) REQUIRE FURTHER NEGOTIATION::
+A client SHOULD commence a negotiation of a PACK from the server via
+the "fetch" command using the OID tips found in advertised bundles,
+even if's still in the process of downloading those bundle(s).
++
+This allows for aggressive early disconnects from any interactive
+server dialog. The client blindly trusts that the advertised OID tips
+are relevant, and issues them as 'have' lines, it then requests any
+tips it would like (usually from the "ls-refs" advertisement) via
+'want' lines. The server will then compute a (hopefully small) PACK
+with the expected difference between the tips from the bundle(s) and
+the data requested.
++
+The only connection the client then needs to keep active is to the
+concurrently downloading static bundle(s), when those and the
+incremental PACK are retrieved they should be inflated and
+validated. Any errors at this point should be gracefully recovered
+from, see above.
+
+bundle-uri PROTOCOL FEATURES
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The client constructs a bundle list from the `<key>=<value>` pairs
+provided by the server. These pairs are part of the `bundle.*` namespace
+as documented in linkgit:git-config[1]. In this section, we discuss some
+of these keys and describe the actions the client will do in response to
+this information.
+
+In particular, the `bundle.version` key specifies an integer value. The
+only accepted value at the moment is `1`, but if the client sees an
+unexpected value here then the client MUST ignore the bundle list.
+
+As long as `bundle.version` is understood, all other unknown keys MAY be
+ignored by the client. The server will guarantee compatibility with older
+clients, though newer clients may be better able to use the extra keys to
+minimize downloads.
+
+Any backwards-incompatible addition of pre-URI key-value will be
+guarded by a new `bundle.version` value or values in 'bundle-uri'
+capability advertisement itself, and/or by new future `bundle-uri`
+request arguments.
+
+Some example key-value pairs that are not currently implemented but could
+be implemented in the future include:
+
+ * Add a "hash=<val>" or "size=<bytes>" advertise the expected hash or
+   size of the bundle file.
+
+ * Advertise that one or more bundle files are the same (to e.g. have
+   clients round-robin or otherwise choose one of N possible files).
+
+ * A "oid=<OID>" shortcut and "prerequisite=<OID>" shortcut. For
+   expressing the common case of a bundle with one tip and no
+   prerequisites, or one tip and one prerequisite.
++
+This would allow for optimizing the common case of servers who'd like
+to provide one "big bundle" containing only their "main" branch,
+and/or incremental updates thereof.
++
+A client receiving such a a response MAY assume that they can skip
+retrieving the header from a bundle at the indicated URI, and thus
+save themselves and the server(s) the request(s) needed to inspect the
+headers of that bundle or bundles.
+
 GIT
 ---
 Part of the linkgit:git[1] suite
diff --git a/Documentation/howto/new-command.txt b/Documentation/howto/new-command.txt
index 15a4c80..880c511 100644
--- a/Documentation/howto/new-command.txt
+++ b/Documentation/howto/new-command.txt
@@ -1,13 +1,13 @@
 From: Eric S. Raymond <esr@thyrsus.com>
 Abstract: This is how-to documentation for people who want to add extension
- commands to Git.  It should be read alongside api-builtin.txt.
+ commands to Git.  It should be read alongside builtin.h.
 Content-type: text/asciidoc
 
 How to integrate new subcommands
 ================================
 
 This is how-to documentation for people who want to add extension
-commands to Git.  It should be read alongside api-builtin.txt.
+commands to Git.  It should be read alongside builtin.h.
 
 Runtime environment
 -------------------
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 0b4c1c8..3b71334 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -146,24 +146,34 @@
 '%m':: left (`<`), right (`>`) or boundary (`-`) mark
 '%w([<w>[,<i1>[,<i2>]]])':: switch line wrapping, like the -w option of
 			    linkgit:git-shortlog[1].
-'%<(<N>[,trunc|ltrunc|mtrunc])':: make the next placeholder take at
-				  least N columns, padding spaces on
+'%<( <N> [,trunc|ltrunc|mtrunc])':: make the next placeholder take at
+				  least N column widths, padding spaces on
 				  the right if necessary.  Optionally
-				  truncate at the beginning (ltrunc),
-				  the middle (mtrunc) or the end
-				  (trunc) if the output is longer than
-				  N columns.  Note that truncating
+				  truncate (with ellipsis '..') at the left (ltrunc) `..ft`,
+				  the middle (mtrunc) `mi..le`, or the end
+				  (trunc) `rig..`, if the output is longer than
+				  N columns.
+				  Note 1: that truncating
 				  only works correctly with N >= 2.
-'%<|(<N>)':: make the next placeholder take at least until Nth
-	     columns, padding spaces on the right if necessary
-'%>(<N>)', '%>|(<N>)':: similar to '%<(<N>)', '%<|(<N>)' respectively,
+				  Note 2: spaces around the N and M (see below)
+				  values are optional.
+				  Note 3: Emojis and other wide characters
+				  will take two display columns, which may
+				  over-run column boundaries.
+				  Note 4: decomposed character combining marks
+				  may be misplaced at padding boundaries.
+'%<|( <M> )':: make the next placeholder take at least until Mth
+	     display column, padding spaces on the right if necessary.
+	     Use negative M values for column positions measured
+	     from the right hand edge of the terminal window.
+'%>( <N> )', '%>|( <M> )':: similar to '%<( <N> )', '%<|( <M> )' respectively,
 			but padding spaces on the left
-'%>>(<N>)', '%>>|(<N>)':: similar to '%>(<N>)', '%>|(<N>)'
+'%>>( <N> )', '%>>|( <M> )':: similar to '%>( <N> )', '%>|( <M> )'
 			  respectively, except that if the next
 			  placeholder takes more spaces than given and
 			  there are spaces on its left, use those
 			  spaces
-'%><(<N>)', '%><|(<N>)':: similar to '%<(<N>)', '%<|(<N>)'
+'%><( <N> )', '%><|( <M> )':: similar to '%<( <N> )', '%<|( <M> )'
 			  respectively, but padding both sides
 			  (i.e. the text is centered)
 
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index ff68e48..0d90d5b 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -1100,12 +1100,12 @@
 format placeholders. When using `-local`, the correct syntax is
 `--date=format-local:...`.
 
-`--date=default` is the default format, and is similar to
-`--date=rfc2822`, with a few exceptions:
+`--date=default` is the default format, and is based on ctime(3)
+output.  It shows a single line with three-letter day of the week,
+three-letter month, day-of-month, hour-minute-seconds in "HH:MM:SS"
+format, followed by 4-digit year, plus timezone information, unless
+the local time zone is used, e.g. `Thu Jan 1 00:00:00 1970 +0000`.
 --
-	- there is no comma after the day-of-week
-
-	- the time zone is omitted when the local time zone is used
 
 ifdef::git-rev-list[]
 --header::
diff --git a/Documentation/technical/bundle-uri.txt b/Documentation/technical/bundle-uri.txt
index b78d01d..91d3a13 100644
--- a/Documentation/technical/bundle-uri.txt
+++ b/Documentation/technical/bundle-uri.txt
@@ -479,14 +479,14 @@
    (This choice is an opt-in via a config option and a command-line
    option.)
 
-4. Allow the client to understand the `bundle.flag=forFetch` configuration
+4. Allow the client to understand the `bundle.heuristic` configuration key
    and the `bundle.<id>.creationToken` heuristic. When `git clone`
-   discovers a bundle URI with `bundle.flag=forFetch`, it configures the
-   client repository to check that bundle URI during later `git fetch <remote>`
+   discovers a bundle URI with `bundle.heuristic`, it configures the client
+   repository to check that bundle URI during later `git fetch <remote>`
    commands.
 
 5. Allow clients to discover bundle URIs during `git fetch` and configure
-   a bundle URI for later fetches if `bundle.flag=forFetch`.
+   a bundle URI for later fetches if `bundle.heuristic` is set.
 
 6. Implement the "inspect headers" heuristic to reduce data downloads when
    the `bundle.<id>.creationToken` heuristic is not available.
diff --git a/Documentation/technical/hash-function-transition.txt b/Documentation/technical/hash-function-transition.txt
index e2ac36d..ed57481 100644
--- a/Documentation/technical/hash-function-transition.txt
+++ b/Documentation/technical/hash-function-transition.txt
@@ -562,7 +562,7 @@
 The design described here allows fetches by SHA-1 clients of a
 personal SHA-256 repository because it's not much more difficult than
 allowing pushes from that repository. This support needs to be guarded
-by a configuration option --- servers like git.kernel.org that serve a
+by a configuration option -- servers like git.kernel.org that serve a
 large number of clients would not be expected to bear that cost.
 
 Meaning of signatures
diff --git a/Documentation/technical/rerere.txt b/Documentation/technical/rerere.txt
index 35d4541..be58f1b 100644
--- a/Documentation/technical/rerere.txt
+++ b/Documentation/technical/rerere.txt
@@ -99,7 +99,7 @@
     compatible with what AB and AC wanted to do.
 
 So the conflict we would see when merging AB into ACAB should be
-resolved the same way---it is the resolution that is in line with that
+resolved the same way--it is the resolution that is in line with that
 declaration.
 
 Imagine that similarly previously a branch XYXZ was forked from XY,
diff --git a/Documentation/urls-remotes.txt b/Documentation/urls-remotes.txt
index 86d0008..e410912 100644
--- a/Documentation/urls-remotes.txt
+++ b/Documentation/urls-remotes.txt
@@ -33,7 +33,9 @@
 ------------
 
 The `<pushurl>` is used for pushes only. It is optional and defaults
-to `<URL>`.
+to `<URL>`. Pushing to a remote affects all defined pushurls or to all
+defined urls if no pushurls are defined. Fetch, however, will only
+fetch from the first defined url if muliple urls are defined.
 
 Named file in `$GIT_DIR/remotes`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index c124ef0..fc9c36a 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.39.4
+DEF_VER=v2.40.2
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index 232314e..6745146 100644
--- a/INSTALL
+++ b/INSTALL
@@ -120,7 +120,7 @@
 	  for everyday use (e.g. "bisect", "request-pull").
 
 	- "Perl" version 5.8 or later is needed to use some of the
-	  features (e.g. preparing a partial commit using "git add -i/-p",
+	  features (e.g. sending patches using "git send-email",
 	  interacting with svn repositories with "git svn").  If you can
 	  live without these, use NO_PERL.  Note that recent releases of
 	  Redhat/Fedora are reported to ship Perl binary package with some
diff --git a/Makefile b/Makefile
index 4b1502b..79ed649 100644
--- a/Makefile
+++ b/Makefile
@@ -515,10 +515,8 @@
 # Define BLK_SHA1 to make use of optimized C SHA-1 routines bundled
 # with git (in the block-sha1/ directory).
 #
-# Define NO_APPLE_COMMON_CRYPTO on OSX to opt-out of using the
-# "APPLE_COMMON_CRYPTO" backend for SHA-1, which is currently the
-# default on that OS. On macOS 01.4 (Tiger) or older,
-# NO_APPLE_COMMON_CRYPTO is defined by default.
+# Define APPLE_COMMON_CRYPTO_SHA1 to use Apple's CommonCrypto for
+# SHA-1.
 #
 # If don't enable any of the *_SHA1 settings in this section, Git will
 # default to its built-in sha1collisiondetection library, which is a
@@ -695,7 +693,6 @@
 # interactive shell sessions without exporting it.
 unexport CDPATH
 
-SCRIPT_SH += git-bisect.sh
 SCRIPT_SH += git-difftool--helper.sh
 SCRIPT_SH += git-filter-branch.sh
 SCRIPT_SH += git-merge-octopus.sh
@@ -711,7 +708,6 @@
 SCRIPT_LIB += git-sh-i18n
 SCRIPT_LIB += git-sh-setup
 
-SCRIPT_PERL += git-add--interactive.perl
 SCRIPT_PERL += git-archimport.perl
 SCRIPT_PERL += git-cvsexportcommit.perl
 SCRIPT_PERL += git-cvsimport.perl
@@ -805,6 +801,7 @@
 TEST_BUILTINS_OBJS += test-dump-fsmonitor.o
 TEST_BUILTINS_OBJS += test-dump-split-index.o
 TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
+TEST_BUILTINS_OBJS += test-env-helper.o
 TEST_BUILTINS_OBJS += test-example-decorate.o
 TEST_BUILTINS_OBJS += test-fast-rebase.o
 TEST_BUILTINS_OBJS += test-fsmonitor-client.o
@@ -1206,7 +1203,7 @@
 BUILTIN_OBJS += builtin/annotate.o
 BUILTIN_OBJS += builtin/apply.o
 BUILTIN_OBJS += builtin/archive.o
-BUILTIN_OBJS += builtin/bisect--helper.o
+BUILTIN_OBJS += builtin/bisect.o
 BUILTIN_OBJS += builtin/blame.o
 BUILTIN_OBJS += builtin/branch.o
 BUILTIN_OBJS += builtin/bugreport.o
@@ -1238,7 +1235,6 @@
 BUILTIN_OBJS += builtin/diff-tree.o
 BUILTIN_OBJS += builtin/diff.o
 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
@@ -1916,7 +1912,7 @@
 	BASIC_CFLAGS += -DNO_POSIX_GOODIES
 endif
 
-ifdef APPLE_COMMON_CRYPTO
+ifdef APPLE_COMMON_CRYPTO_SHA1
 	# Apple CommonCrypto requires chunking
 	SHA1_MAX_BLOCK_SIZE = 1024L*1024L*1024L
 endif
@@ -1933,7 +1929,7 @@
 	LIB_OBJS += block-sha1/sha1.o
 	BASIC_CFLAGS += -DSHA1_BLK
 else
-ifdef APPLE_COMMON_CRYPTO
+ifdef APPLE_COMMON_CRYPTO_SHA1
 	COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
 	BASIC_CFLAGS += -DSHA1_APPLE
 else
diff --git a/RelNotes b/RelNotes
index 34ee294..6d30158 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.39.4.txt
\ No newline at end of file
+Documentation/RelNotes/2.40.2.txt
\ No newline at end of file
diff --git a/apply.c b/apply.c
index b17e833..9762157 100644
--- a/apply.c
+++ b/apply.c
@@ -4105,7 +4105,7 @@ static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid)
 static int build_fake_ancestor(struct apply_state *state, struct patch *list)
 {
 	struct patch *patch;
-	struct index_state result = { NULL };
+	struct index_state result = INDEX_STATE_INIT(state->repo);
 	struct lock_file lock = LOCK_INIT;
 	int res;
 
diff --git a/archive.c b/archive.c
index 941495f..9aeaf2b 100644
--- a/archive.c
+++ b/archive.c
@@ -120,7 +120,7 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate,
 	static struct attr_check *check;
 	if (!check)
 		check = attr_check_initl("export-ignore", "export-subst", NULL);
-	git_check_attr(istate, path, check);
+	git_check_attr(istate, NULL, path, check);
 	return check;
 }
 
@@ -472,6 +472,8 @@ static void parse_treeish_arg(const char **argv,
 		commit_oid = NULL;
 		archive_time = time(NULL);
 	}
+	if (ar_args->mtime_option)
+		archive_time = approxidate(ar_args->mtime_option);
 
 	tree = parse_tree_indirect(&oid);
 	if (!tree)
@@ -586,6 +588,7 @@ static int parse_archive_args(int argc, const char **argv,
 	const char *remote = NULL;
 	const char *exec = NULL;
 	const char *output = NULL;
+	const char *mtime_option = NULL;
 	int compression_level = -1;
 	int verbose = 0;
 	int i;
@@ -607,6 +610,9 @@ static int parse_archive_args(int argc, const char **argv,
 		OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
 			N_("read .gitattributes in working directory")),
 		OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
+		{ OPTION_STRING, 0, "mtime", &mtime_option, N_("time"),
+		  N_("set modification time of archive entries"),
+		  PARSE_OPT_NONEG },
 		OPT_NUMBER_CALLBACK(&compression_level,
 			N_("set compression level"), number_callback),
 		OPT_GROUP(""),
@@ -668,6 +674,7 @@ static int parse_archive_args(int argc, const char **argv,
 	args->base = base;
 	args->baselen = strlen(base);
 	args->worktree_attributes = worktree_attributes;
+	args->mtime_option = mtime_option;
 
 	return argc;
 }
@@ -710,6 +717,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
 
 	string_list_clear_func(&args.extra_files, extra_file_info_clear);
 	free(args.refname);
+	clear_pathspec(&args.pathspec);
 
 	return rc;
 }
diff --git a/archive.h b/archive.h
index 08bed3e..7178e2a 100644
--- a/archive.h
+++ b/archive.h
@@ -16,6 +16,7 @@ struct archiver_args {
 	struct tree *tree;
 	const struct object_id *commit_oid;
 	const struct commit *commit;
+	const char *mtime_option;
 	timestamp_t time;
 	struct pathspec pathspec;
 	unsigned int verbose : 1;
diff --git a/attr.c b/attr.c
index 9922529..1053dfc 100644
--- a/attr.c
+++ b/attr.c
@@ -13,6 +13,8 @@
 #include "dir.h"
 #include "utf8.h"
 #include "quote.h"
+#include "revision.h"
+#include "object-store.h"
 #include "thread-utils.h"
 
 const char git_attr__true[] = "(builtin)true";
@@ -603,8 +605,7 @@ struct attr_check *attr_check_dup(const struct attr_check *check)
 
 	ret->nr = check->nr;
 	ret->alloc = check->alloc;
-	ALLOC_ARRAY(ret->items, ret->nr);
-	COPY_ARRAY(ret->items, check->items, ret->nr);
+	DUP_ARRAY(ret->items, check->items, ret->nr);
 
 	return ret;
 }
@@ -745,13 +746,61 @@ static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
 	return res;
 }
 
-static struct attr_stack *read_attr_from_index(struct index_state *istate,
-					       const char *path,
-					       unsigned flags)
+static struct attr_stack *read_attr_from_buf(char *buf, const char *path,
+					     unsigned flags)
 {
 	struct attr_stack *res;
-	char *buf, *sp;
+	char *sp;
 	int lineno = 0;
+
+	if (!buf)
+		return NULL;
+
+	CALLOC_ARRAY(res, 1);
+	for (sp = buf; *sp;) {
+		char *ep;
+		int more;
+
+		ep = strchrnul(sp, '\n');
+		more = (*ep == '\n');
+		*ep = '\0';
+		handle_attr_line(res, sp, path, ++lineno, flags);
+		sp = ep + more;
+	}
+	free(buf);
+
+	return res;
+}
+
+static struct attr_stack *read_attr_from_blob(struct index_state *istate,
+					      const struct object_id *tree_oid,
+					      const char *path, unsigned flags)
+{
+	struct object_id oid;
+	unsigned long sz;
+	enum object_type type;
+	void *buf;
+	unsigned short mode;
+
+	if (!tree_oid)
+		return NULL;
+
+	if (get_tree_entry(istate->repo, tree_oid, path, &oid, &mode))
+		return NULL;
+
+	buf = repo_read_object_file(istate->repo, &oid, &type, &sz);
+	if (!buf || type != OBJ_BLOB) {
+		free(buf);
+		return NULL;
+	}
+
+	return read_attr_from_buf(buf, path, flags);
+}
+
+static struct attr_stack *read_attr_from_index(struct index_state *istate,
+					       const char *path, unsigned flags)
+{
+	char *buf;
 	unsigned long size;
 
 	if (!istate)
@@ -779,28 +828,19 @@ static struct attr_stack *read_attr_from_index(struct index_state *istate,
 		return NULL;
 	}
 
-	CALLOC_ARRAY(res, 1);
-	for (sp = buf; *sp; ) {
-		char *ep;
-		int more;
-
-		ep = strchrnul(sp, '\n');
-		more = (*ep == '\n');
-		*ep = '\0';
-		handle_attr_line(res, sp, path, ++lineno, flags);
-		sp = ep + more;
-	}
-	free(buf);
-	return res;
+	return read_attr_from_buf(buf, path, flags);
 }
 
 static struct attr_stack *read_attr(struct index_state *istate,
+				    const struct object_id *tree_oid,
 				    const char *path, unsigned flags)
 {
 	struct attr_stack *res = NULL;
 
 	if (direction == GIT_ATTR_INDEX) {
 		res = read_attr_from_index(istate, path, flags);
+	} else if (tree_oid) {
+		res = read_attr_from_blob(istate, tree_oid, path, flags);
 	} else if (!is_bare_repository()) {
 		if (direction == GIT_ATTR_CHECKOUT) {
 			res = read_attr_from_index(istate, path, flags);
@@ -860,6 +900,7 @@ static void push_stack(struct attr_stack **attr_stack_p,
 }
 
 static void bootstrap_attr_stack(struct index_state *istate,
+				 const struct object_id *tree_oid,
 				 struct attr_stack **stack)
 {
 	struct attr_stack *e;
@@ -885,7 +926,7 @@ static void bootstrap_attr_stack(struct index_state *istate,
 	}
 
 	/* root directory */
-	e = read_attr(istate, GITATTRIBUTES_FILE, flags | READ_ATTR_NOFOLLOW);
+	e = read_attr(istate, tree_oid, GITATTRIBUTES_FILE, flags | READ_ATTR_NOFOLLOW);
 	push_stack(stack, e, xstrdup(""), 0);
 
 	/* info frame */
@@ -899,6 +940,7 @@ static void bootstrap_attr_stack(struct index_state *istate,
 }
 
 static void prepare_attr_stack(struct index_state *istate,
+			       const struct object_id *tree_oid,
 			       const char *path, int dirlen,
 			       struct attr_stack **stack)
 {
@@ -920,7 +962,7 @@ static void prepare_attr_stack(struct index_state *istate,
 	 * .gitattributes in deeper directories to shallower ones,
 	 * and finally use the built-in set as the default.
 	 */
-	bootstrap_attr_stack(istate, stack);
+	bootstrap_attr_stack(istate, tree_oid, stack);
 
 	/*
 	 * Pop the "info" one that is always at the top of the stack.
@@ -975,7 +1017,7 @@ static void prepare_attr_stack(struct index_state *istate,
 		strbuf_add(&pathbuf, path + pathbuf.len, (len - pathbuf.len));
 		strbuf_addf(&pathbuf, "/%s", GITATTRIBUTES_FILE);
 
-		next = read_attr(istate, pathbuf.buf, READ_ATTR_NOFOLLOW);
+		next = read_attr(istate, tree_oid, pathbuf.buf, READ_ATTR_NOFOLLOW);
 
 		/* reset the pathbuf to not include "/.gitattributes" */
 		strbuf_setlen(&pathbuf, len);
@@ -1095,8 +1137,8 @@ static void determine_macros(struct all_attrs_item *all_attrs,
  * Otherwise all attributes are collected.
  */
 static void collect_some_attrs(struct index_state *istate,
-			       const char *path,
-			       struct attr_check *check)
+			       const struct object_id *tree_oid,
+			       const char *path, struct attr_check *check)
 {
 	int pathlen, rem, dirlen;
 	const char *cp, *last_slash = NULL;
@@ -1115,7 +1157,7 @@ static void collect_some_attrs(struct index_state *istate,
 		dirlen = 0;
 	}
 
-	prepare_attr_stack(istate, path, dirlen, &check->stack);
+	prepare_attr_stack(istate, tree_oid, path, dirlen, &check->stack);
 	all_attrs_init(&g_attr_hashmap, check);
 	determine_macros(check->all_attrs, check->stack);
 
@@ -1124,12 +1166,12 @@ static void collect_some_attrs(struct index_state *istate,
 }
 
 void git_check_attr(struct index_state *istate,
-		    const char *path,
+		    const struct object_id *tree_oid, const char *path,
 		    struct attr_check *check)
 {
 	int i;
 
-	collect_some_attrs(istate, path, check);
+	collect_some_attrs(istate, tree_oid, path, check);
 
 	for (i = 0; i < check->nr; i++) {
 		unsigned int n = check->items[i].attr->attr_nr;
@@ -1140,13 +1182,13 @@ void git_check_attr(struct index_state *istate,
 	}
 }
 
-void git_all_attrs(struct index_state *istate,
+void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
 		   const char *path, struct attr_check *check)
 {
 	int i;
 
 	attr_check_reset(check);
-	collect_some_attrs(istate, path, check);
+	collect_some_attrs(istate, tree_oid, path, check);
 
 	for (i = 0; i < check->all_attrs_nr; i++) {
 		const char *name = check->all_attrs[i].attr->name;
diff --git a/attr.h b/attr.h
index 2f22dff..9884ea2 100644
--- a/attr.h
+++ b/attr.h
@@ -45,7 +45,7 @@
  * const char *path;
  *
  * setup_check();
- * git_check_attr(path, check);
+ * git_check_attr(&the_index, tree_oid, path, check);
  * ------------
  *
  * - Act on `.value` member of the result, left in `check->items[]`:
@@ -120,6 +120,7 @@
 #define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024)
 
 struct index_state;
+struct object_id;
 
 /**
  * An attribute is an opaque object that is identified by its name. Pass the
@@ -202,13 +203,14 @@ void attr_check_free(struct attr_check *check);
 const char *git_attr_name(const struct git_attr *);
 
 void git_check_attr(struct index_state *istate,
-		    const char *path, struct attr_check *check);
+		    const struct object_id *tree_oid, const char *path,
+		    struct attr_check *check);
 
 /*
  * Retrieve all attributes that apply to the specified path.
  * check holds the attributes and their values.
  */
-void git_all_attrs(struct index_state *istate,
+void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
 		   const char *path, struct attr_check *check);
 
 enum git_attr_direction {
diff --git a/bisect.c b/bisect.c
index ec7487e..ef5ee5a 100644
--- a/bisect.c
+++ b/bisect.c
@@ -472,7 +472,6 @@ 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 strvec *array)
 {
@@ -1188,8 +1187,6 @@ int bisect_clean_state(void)
 	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());
 	/*
 	 * Cleanup BISECT_START last to support the --no-checkout option
 	 * introduced in the commit 4796e823a.
diff --git a/branch.c b/branch.c
index d182756..e5614b5 100644
--- a/branch.c
+++ b/branch.c
@@ -756,7 +756,7 @@ void create_branches_recursively(struct repository *r, const char *name,
 				_("submodule '%s': unable to find submodule"),
 				submodule_entry_list.entries[i].submodule->name);
 			if (advice_enabled(ADVICE_SUBMODULES_NOT_UPDATED))
-				advise(_("You may try updating the submodules using 'git checkout %s && git submodule update --init'"),
+				advise(_("You may try updating the submodules using 'git checkout --no-recurse-submodules %s && git submodule update --init'"),
 				       start_commitish);
 			exit(code);
 		}
diff --git a/builtin.h b/builtin.h
index 8901a34..46cc789 100644
--- a/builtin.h
+++ b/builtin.h
@@ -51,10 +51,6 @@
  *	on bare repositories.
  *	This only makes sense when `RUN_SETUP` is also set.
  *
- * `SUPPORT_SUPER_PREFIX`:
- *
- *	The built-in supports `--super-prefix`.
- *
  * `DELAY_PAGER_CONFIG`:
  *
  *	If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
@@ -116,7 +112,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);
 int cmd_annotate(int argc, const char **argv, const char *prefix);
 int cmd_apply(int argc, const char **argv, const char *prefix);
 int cmd_archive(int argc, const char **argv, const char *prefix);
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
+int cmd_bisect(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);
diff --git a/builtin/add.c b/builtin/add.c
index 190d1a6..61dd386 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -238,58 +238,14 @@ static int refresh(int verbose, const struct pathspec *pathspec)
 	return ret;
 }
 
-int run_add_interactive(const char *revision, const char *patch_mode,
-			const struct pathspec *pathspec)
-{
-	int i;
-	struct child_process cmd = CHILD_PROCESS_INIT;
-	int use_builtin_add_i =
-		git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
-
-	if (use_builtin_add_i < 0 &&
-	    git_config_get_bool("add.interactive.usebuiltin",
-				&use_builtin_add_i))
-		use_builtin_add_i = 1;
-
-	if (use_builtin_add_i != 0) {
-		enum add_p_mode mode;
-
-		if (!patch_mode)
-			return !!run_add_i(the_repository, pathspec);
-
-		if (!strcmp(patch_mode, "--patch"))
-			mode = ADD_P_ADD;
-		else if (!strcmp(patch_mode, "--patch=stash"))
-			mode = ADD_P_STASH;
-		else if (!strcmp(patch_mode, "--patch=reset"))
-			mode = ADD_P_RESET;
-		else if (!strcmp(patch_mode, "--patch=checkout"))
-			mode = ADD_P_CHECKOUT;
-		else if (!strcmp(patch_mode, "--patch=worktree"))
-			mode = ADD_P_WORKTREE;
-		else
-			die("'%s' not supported", patch_mode);
-
-		return !!run_add_p(the_repository, mode, revision, pathspec);
-	}
-
-	strvec_push(&cmd.args, "add--interactive");
-	if (patch_mode)
-		strvec_push(&cmd.args, patch_mode);
-	if (revision)
-		strvec_push(&cmd.args, revision);
-	strvec_push(&cmd.args, "--");
-	for (i = 0; i < pathspec->nr; i++)
-		/* pass original pathspec, to be re-parsed */
-		strvec_push(&cmd.args, pathspec->items[i].original);
-
-	cmd.git_cmd = 1;
-	return run_command(&cmd);
-}
-
 int interactive_add(const char **argv, const char *prefix, int patch)
 {
 	struct pathspec pathspec;
+	int unused;
+
+	if (!git_config_get_bool("add.interactive.usebuiltin", &unused))
+		warning(_("the add.interactive.useBuiltin setting has been removed!\n"
+			  "See its entry in 'git help config' for details."));
 
 	parse_pathspec(&pathspec, 0,
 		       PATHSPEC_PREFER_FULL |
@@ -297,9 +253,10 @@ int interactive_add(const char **argv, const char *prefix, int patch)
 		       PATHSPEC_PREFIX_ORIGIN,
 		       prefix, argv);
 
-	return run_add_interactive(NULL,
-				   patch ? "--patch" : NULL,
-				   &pathspec);
+	if (patch)
+		return !!run_add_p(the_repository, ADD_P_ADD, NULL, &pathspec);
+	else
+		return !!run_add_i(the_repository, &pathspec);
 }
 
 static int edit_patch(int argc, const char **argv, const char *prefix)
@@ -695,6 +652,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 		die(_("Unable to write new index file"));
 
 	dir_clear(&dir);
-	UNLEAK(pathspec);
+	clear_pathspec(&pathspec);
 	return exit_status;
 }
diff --git a/builtin/am.c b/builtin/am.c
index dddf1b9..e0848dd 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -3,7 +3,7 @@
  *
  * Based on git-am.sh by Junio C Hamano.
  */
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
 #include "cache.h"
 #include "config.h"
 #include "builtin.h"
@@ -117,6 +117,7 @@ struct am_state {
 
 	/* various operating modes and command line options */
 	int interactive;
+	int no_verify;
 	int threeway;
 	int quiet;
 	int signoff; /* enum signoff_type */
@@ -472,10 +473,12 @@ static void am_destroy(const struct am_state *state)
  */
 static int run_applypatch_msg_hook(struct am_state *state)
 {
-	int ret;
+	int ret = 0;
 
 	assert(state->msg);
-	ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
+
+	if (!state->no_verify)
+		ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
 
 	if (!ret) {
 		FREE_AND_NULL(state->msg);
@@ -492,24 +495,12 @@ static int run_applypatch_msg_hook(struct am_state *state)
  */
 static int run_post_rewrite_hook(const struct am_state *state)
 {
-	struct child_process cp = CHILD_PROCESS_INIT;
-	const char *hook = find_hook("post-rewrite");
-	int ret;
+	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
 
-	if (!hook)
-		return 0;
+	strvec_push(&opt.args, "rebase");
+	opt.path_to_stdin = am_path(state, "rewritten");
 
-	strvec_push(&cp.args, hook);
-	strvec_push(&cp.args, "rebase");
-
-	cp.in = xopen(am_path(state, "rewritten"), O_RDONLY);
-	cp.stdout_to_stderr = 1;
-	cp.trace2_hook_name = "post-rewrite";
-
-	ret = run_command(&cp);
-
-	close(cp.in);
-	return ret;
+	return run_hooks_opt("post-rewrite", &opt);
 }
 
 /**
@@ -1489,8 +1480,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
 	 * apply_opts.v keeps referencing the allocated strings for
 	 * strvec_clear() to release.
 	 */
-	ALLOC_ARRAY(apply_argv, apply_opts.nr);
-	COPY_ARRAY(apply_argv, apply_opts.v, apply_opts.nr);
+	DUP_ARRAY(apply_argv, apply_opts.v, apply_opts.nr);
 
 	opts_left = apply_parse_options(apply_opts.nr, apply_argv,
 					&apply_state, &force_apply, &options,
@@ -1650,10 +1640,10 @@ static void do_commit(const struct am_state *state)
 	const char *reflog_msg, *author, *committer = NULL;
 	struct strbuf sb = STRBUF_INIT;
 
-	if (run_hooks("pre-applypatch"))
+	if (!state->no_verify && run_hooks("pre-applypatch"))
 		exit(1);
 
-	if (write_cache_as_tree(&tree, 0, NULL))
+	if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL))
 		die(_("git write-tree failed to write a tree"));
 
 	if (!get_oid_commit("HEAD", &parent)) {
@@ -2061,7 +2051,7 @@ static int clean_index(const struct object_id *head, const struct object_id *rem
 	if (fast_forward_to(head_tree, head_tree, 1))
 		return -1;
 
-	if (write_cache_as_tree(&index, 0, NULL))
+	if (write_index_as_tree(&index, &the_index, get_index_file(), 0, NULL))
 		return -1;
 
 	index_tree = parse_tree_indirect(&index);
@@ -2340,6 +2330,8 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 	struct option options[] = {
 		OPT_BOOL('i', "interactive", &state.interactive,
 			N_("run interactively")),
+		OPT_BOOL('n', "no-verify", &state.no_verify,
+			N_("bypass pre-applypatch and applypatch-msg hooks")),
 		OPT_HIDDEN_BOOL('b', "binary", &binary,
 			N_("historical option -- no-op")),
 		OPT_BOOL('3', "3way", &state.threeway,
diff --git a/builtin/bisect--helper.c b/builtin/bisect.c
similarity index 90%
rename from builtin/bisect--helper.c
rename to builtin/bisect.c
index 6e41cbd..7301740 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -15,23 +15,44 @@ 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_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 GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 
-static const char * const git_bisect_helper_usage[] = {
-	N_("git bisect--helper --bisect-reset [<commit>]"),
-	"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
-	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
-					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
-	"git bisect--helper --bisect-next",
-	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
-	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
-	N_("git bisect--helper --bisect-replay <filename>"),
-	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
-	"git bisect--helper --bisect-visualize",
-	N_("git bisect--helper --bisect-run <cmd>..."),
+#define BUILTIN_GIT_BISECT_START_USAGE \
+	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]" \
+	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
+	   "    [<pathspec>...]")
+#define BUILTIN_GIT_BISECT_STATE_USAGE \
+	N_("git bisect (good|bad) [<rev>...]")
+#define BUILTIN_GIT_BISECT_TERMS_USAGE \
+	"git bisect terms [--term-good | --term-bad]"
+#define BUILTIN_GIT_BISECT_SKIP_USAGE \
+	N_("git bisect skip [(<rev>|<range>)...]")
+#define BUILTIN_GIT_BISECT_NEXT_USAGE \
+	"git bisect next"
+#define BUILTIN_GIT_BISECT_RESET_USAGE \
+	N_("git bisect reset [<commit>]")
+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \
+	"git bisect visualize"
+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \
+	N_("git bisect replay <logfile>")
+#define BUILTIN_GIT_BISECT_LOG_USAGE \
+	"git bisect log"
+#define BUILTIN_GIT_BISECT_RUN_USAGE \
+	N_("git bisect run <cmd>...")
+
+static const char * const git_bisect_usage[] = {
+	BUILTIN_GIT_BISECT_START_USAGE,
+	BUILTIN_GIT_BISECT_STATE_USAGE,
+	BUILTIN_GIT_BISECT_TERMS_USAGE,
+	BUILTIN_GIT_BISECT_SKIP_USAGE,
+	BUILTIN_GIT_BISECT_NEXT_USAGE,
+	BUILTIN_GIT_BISECT_RESET_USAGE,
+	BUILTIN_GIT_BISECT_VISUALIZE_USAGE,
+	BUILTIN_GIT_BISECT_REPLAY_USAGE,
+	BUILTIN_GIT_BISECT_LOG_USAGE,
+	BUILTIN_GIT_BISECT_RUN_USAGE,
 	NULL
 };
 
@@ -656,7 +677,8 @@ static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char
 	return bisect_next(terms, prefix);
 }
 
-static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
+				      const char **argv)
 {
 	int no_checkout = 0;
 	int first_parent_only = 0;
@@ -785,13 +807,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 			strbuf_addstr(&start_head, oid_to_hex(&head_oid));
 		} else if (!get_oid(head, &head_oid) &&
 			   skip_prefix(head, "refs/heads/", &head)) {
-			/*
-			 * This error message should only be triggered by
-			 * cogito usage, and cogito users should understand
-			 * it relates to cg-seek.
-			 */
-			if (!is_empty_or_missing_file(git_path_head_name()))
-				return error(_("won't bisect on cg-seek'ed tree"));
 			strbuf_addstr(&start_head, head);
 		} else {
 			return error(_("bad HEAD - strange symbolic ref"));
@@ -886,13 +901,13 @@ static int bisect_autostart(struct bisect_terms *terms)
 	yesno = git_prompt(_("Do you want me to do it for you "
 			     "[Y/n]? "), PROMPT_ECHO);
 	res = tolower(*yesno) == 'n' ?
-		-1 : bisect_start(terms, empty_strvec, 0);
+		-1 : bisect_start(terms, 0, empty_strvec);
 
 	return res;
 }
 
-static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
-				      int argc)
+static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
+				      const char **argv)
 {
 	const char *state;
 	int i, verify_expected = 1;
@@ -1011,7 +1026,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
 		struct strvec argv = STRVEC_INIT;
 		int res;
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_start(terms, argv.v, argv.nr);
+		res = bisect_start(terms, argv.nr, argv.v);
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1061,7 +1076,8 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
 	return bisect_auto_next(terms, NULL);
 }
 
-static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
+				     const char **argv)
 {
 	int i;
 	enum bisect_error res;
@@ -1091,13 +1107,14 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **ar
 			strvec_push(&argv_state, argv[i]);
 		}
 	}
-	res = bisect_state(terms, argv_state.v, argv_state.nr);
+	res = bisect_state(terms, argv_state.nr, argv_state.v);
 
 	strvec_clear(&argv_state);
 	return res;
 }
 
-static int bisect_visualize(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_visualize(struct bisect_terms *terms, int argc,
+			    const char **argv)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
 	struct strbuf sb = STRBUF_INIT;
@@ -1180,7 +1197,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command)
 	return rc;
 }
 
-static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
 {
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
@@ -1191,13 +1208,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	if (bisect_next_check(terms, NULL))
 		return BISECT_FAILED;
 
-	if (argc)
-		sq_quote_argv(&command, argv);
-	else {
+	if (!argc) {
 		error(_("bisect run failed: no command provided."));
 		return BISECT_FAILED;
 	}
 
+	sq_quote_argv(&command, argv);
+	strbuf_ltrim(&command);
 	while (1) {
 		res = do_bisect_run(command.buf);
 
@@ -1211,8 +1228,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		if (is_first_run && (res == 126 || res == 127)) {
 			int rc = verify_good(terms, command.buf);
 			is_first_run = 0;
-			if (rc < 0) {
-				error(_("unable to verify '%s' on good"
+			if (rc < 0 || 128 <= rc) {
+				error(_("unable to verify %s on good"
 					" revision"), command.buf);
 				res = BISECT_FAILED;
 				break;
@@ -1227,7 +1244,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 		if (res < 0 || 128 <= res) {
 			error(_("bisect run failed: exit code %d from"
-				" '%s' is < 0 or >= 128"), res, command.buf);
+				" %s is < 0 or >= 128"), res, command.buf);
 			break;
 		}
 
@@ -1249,7 +1266,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		saved_stdout = dup(1);
 		dup2(temporary_stdout_fd, 1);
 
-		res = bisect_state(terms, &new_state, 1);
+		res = bisect_state(terms, 1, &new_state);
 
 		fflush(stdout);
 		dup2(saved_stdout, 1);
@@ -1261,14 +1278,14 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		if (res == BISECT_ONLY_SKIPPED_LEFT)
 			error(_("bisect run cannot continue any more"));
 		else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
-			printf(_("bisect run success"));
+			puts(_("bisect run success"));
 			res = BISECT_OK;
 		} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
-			printf(_("bisect found first bad commit"));
+			puts(_("bisect found first bad commit"));
 			res = BISECT_OK;
 		} else if (res) {
-			error(_("bisect run failed: 'git bisect--helper --bisect-state"
-			" %s' exited with error code %d"), new_state, res);
+			error(_("bisect run failed: 'git bisect %s'"
+				" exited with error code %d"), new_state, res);
 		} else {
 			continue;
 		}
@@ -1282,7 +1299,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
 {
 	if (argc > 1)
-		return error(_("--bisect-reset requires either no argument or a commit"));
+		return error(_("'%s' requires either no argument or a commit"),
+			     "git bisect reset");
 	return bisect_reset(argc ? argv[0] : NULL);
 }
 
@@ -1292,7 +1310,8 @@ static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNU
 	struct bisect_terms terms = { 0 };
 
 	if (argc > 1)
-		return error(_("--bisect-terms requires 0 or 1 argument"));
+		return error(_("'%s' requires 0 or 1 argument"),
+			     "git bisect terms");
 	res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
 	free_terms(&terms);
 	return res;
@@ -1304,7 +1323,7 @@ static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNU
 	struct bisect_terms terms = { 0 };
 
 	set_terms(&terms, "bad", "good");
-	res = bisect_start(&terms, argv, argc);
+	res = bisect_start(&terms, argc, argv);
 	free_terms(&terms);
 	return res;
 }
@@ -1315,29 +1334,16 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
 	struct bisect_terms terms = { 0 };
 
 	if (argc)
-		return error(_("--bisect-next requires 0 arguments"));
+		return error(_("'%s' requires 0 arguments"),
+			     "git bisect next");
 	get_terms(&terms);
 	res = bisect_next(&terms, prefix);
 	free_terms(&terms);
 	return res;
 }
 
-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
+static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)
 {
-	int res;
-	struct bisect_terms terms = { 0 };
-
-	set_terms(&terms, "bad", "good");
-	get_terms(&terms);
-	res = bisect_state(&terms, argv, argc);
-	free_terms(&terms);
-	return res;
-}
-
-static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
-{
-	if (argc)
-		return error(_("--bisect-log requires 0 arguments"));
 	return bisect_log();
 }
 
@@ -1361,7 +1367,7 @@ static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUS
 
 	set_terms(&terms, "bad", "good");
 	get_terms(&terms);
-	res = bisect_skip(&terms, argv, argc);
+	res = bisect_skip(&terms, argc, argv);
 	free_terms(&terms);
 	return res;
 }
@@ -1372,7 +1378,7 @@ static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix
 	struct bisect_terms terms = { 0 };
 
 	get_terms(&terms);
-	res = bisect_visualize(&terms, argv, argc);
+	res = bisect_visualize(&terms, argc, argv);
 	free_terms(&terms);
 	return res;
 }
@@ -1383,14 +1389,14 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
 	struct bisect_terms terms = { 0 };
 
 	if (!argc)
-		return error(_("bisect run failed: no command provided."));
+		return error(_("'%s' failed: no command provided."), "git bisect run");
 	get_terms(&terms);
-	res = bisect_run(&terms, argv, argc);
+	res = bisect_run(&terms, argc, argv);
 	free_terms(&terms);
 	return res;
 }
 
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc, const char **argv, const char *prefix)
 {
 	int res = 0;
 	parse_opt_subcommand_fn *fn = NULL;
@@ -1399,7 +1405,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		OPT_SUBCOMMAND("terms", &fn, cmd_bisect__terms),
 		OPT_SUBCOMMAND("start", &fn, cmd_bisect__start),
 		OPT_SUBCOMMAND("next", &fn, cmd_bisect__next),
-		OPT_SUBCOMMAND("state", &fn, cmd_bisect__state),
 		OPT_SUBCOMMAND("log", &fn, cmd_bisect__log),
 		OPT_SUBCOMMAND("replay", &fn, cmd_bisect__replay),
 		OPT_SUBCOMMAND("skip", &fn, cmd_bisect__skip),
@@ -1408,22 +1413,27 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
 		OPT_END()
 	};
-	argc = parse_options(argc, argv, prefix, options,
-			     git_bisect_helper_usage, 0);
+	argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
+			     PARSE_OPT_SUBCOMMAND_OPTIONAL);
 
-	if (!fn)
-		usage_with_options(git_bisect_helper_usage, options);
-	argc--;
-	argv++;
+	if (!fn) {
+		struct bisect_terms terms = { 0 };
 
-	res = fn(argc, argv, prefix);
+		if (!argc)
+			usage_msg_opt(_("need a command"), git_bisect_usage, options);
 
-	/*
-	 * Handle early success
-	 * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
-	 */
-	if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
-		res = BISECT_OK;
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		if (check_and_set_terms(&terms, argv[0]))
+			usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
+				       options, argv[0]);
+		res = bisect_state(&terms, argc, argv);
+		free_terms(&terms);
+	} else {
+		argc--;
+		argv++;
+		res = fn(argc, argv, prefix);
+	}
 
-	return -res;
+	return is_bisect_success(res) ? 0 : -res;
 }
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 9605254..5bc254b 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -106,6 +106,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 	const char *user_relative_path = NULL;
 	char *prefixed_filename;
 	size_t output_path_len;
+	int ret;
 
 	const struct option bugreport_options[] = {
 		OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
@@ -182,7 +183,9 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 		user_relative_path);
 
 	free(prefixed_filename);
-	UNLEAK(buffer);
-	UNLEAK(report_path);
-	return !!launch_editor(report_path.buf, NULL, NULL);
+	strbuf_release(&buffer);
+
+	ret = !!launch_editor(report_path.buf, NULL, NULL);
+	strbuf_release(&report_path);
+	return ret;
 }
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index b3be58b..cc17635 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -132,8 +132,21 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 
 	case 's':
 		oi.sizep = &size;
+
+		if (use_mailmap) {
+			oi.typep = &type;
+			oi.contentp = (void**)&buf;
+		}
+
 		if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
 			die("git cat-file: could not get object info");
+
+		if (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {
+			size_t s = size;
+			buf = replace_idents_using_mailmap(buf, &s);
+			size = cast_size_t_to_ulong(s);
+		}
+
 		printf("%"PRIuMAX"\n", (uintmax_t)size);
 		ret = 0;
 		goto cleanup;
@@ -431,6 +444,9 @@ static void batch_object_write(const char *obj_name,
 	if (!data->skip_object_info) {
 		int ret;
 
+		if (use_mailmap)
+			data->info.typep = &data->type;
+
 		if (pack)
 			ret = packed_object_info(the_repository, pack, offset,
 						 &data->info);
@@ -444,6 +460,18 @@ static void batch_object_write(const char *obj_name,
 			fflush(stdout);
 			return;
 		}
+
+		if (use_mailmap && (data->type == OBJ_COMMIT || data->type == OBJ_TAG)) {
+			size_t s = data->size;
+			char *buf = NULL;
+
+			buf = repo_read_object_file(the_repository, &data->oid, &data->type,
+						    &data->size);
+			buf = replace_idents_using_mailmap(buf, &s);
+			data->size = cast_size_t_to_ulong(s);
+
+			free(buf);
+		}
 	}
 
 	strbuf_reset(scratch);
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 0fef10e..d7a40e6 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -9,9 +9,10 @@
 static int all_attrs;
 static int cached_attrs;
 static int stdin_paths;
+static char *source;
 static const char * const check_attr_usage[] = {
-N_("git check-attr [-a | --all | <attr>...] [--] <pathname>..."),
-N_("git check-attr --stdin [-z] [-a | --all | <attr>...]"),
+N_("git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] <pathname>..."),
+N_("git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"),
 NULL
 };
 
@@ -23,6 +24,7 @@ static const struct option check_attr_options[] = {
 	OPT_BOOL(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
 	OPT_BOOL('z', NULL, &nul_term_line,
 		 N_("terminate input and output records by a NUL character")),
+	OPT_STRING(0, "source", &source, N_("<tree-ish>"), N_("which tree-ish to check attributes at")),
 	OPT_END()
 };
 
@@ -55,27 +57,26 @@ static void output_attr(struct attr_check *check, const char *file)
 	}
 }
 
-static void check_attr(const char *prefix,
-		       struct attr_check *check,
-		       int collect_all,
+static void check_attr(const char *prefix, struct attr_check *check,
+		       const struct object_id *tree_oid, int collect_all,
 		       const char *file)
+
 {
 	char *full_path =
 		prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
 
 	if (collect_all) {
-		git_all_attrs(&the_index, full_path, check);
+		git_all_attrs(&the_index, tree_oid, full_path, check);
 	} else {
-		git_check_attr(&the_index, full_path, check);
+		git_check_attr(&the_index, tree_oid, full_path, check);
 	}
 	output_attr(check, file);
 
 	free(full_path);
 }
 
-static void check_attr_stdin_paths(const char *prefix,
-				   struct attr_check *check,
-				   int collect_all)
+static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
+				   const struct object_id *tree_oid, int collect_all)
 {
 	struct strbuf buf = STRBUF_INIT;
 	struct strbuf unquoted = STRBUF_INIT;
@@ -89,7 +90,7 @@ static void check_attr_stdin_paths(const char *prefix,
 				die("line is badly quoted");
 			strbuf_swap(&buf, &unquoted);
 		}
-		check_attr(prefix, check, collect_all, buf.buf);
+		check_attr(prefix, check, tree_oid, collect_all, buf.buf);
 		maybe_flush_or_die(stdout, "attribute to stdout");
 	}
 	strbuf_release(&buf);
@@ -105,6 +106,8 @@ static NORETURN void error_with_usage(const char *msg)
 int cmd_check_attr(int argc, const char **argv, const char *prefix)
 {
 	struct attr_check *check;
+	struct object_id *tree_oid = NULL;
+	struct object_id initialized_oid;
 	int cnt, i, doubledash, filei;
 
 	if (!is_bare_repository())
@@ -176,11 +179,17 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
 		}
 	}
 
+	if (source) {
+		if (repo_get_oid_tree(the_repository, source, &initialized_oid))
+			die("%s: not a valid tree-ish source", source);
+		tree_oid = &initialized_oid;
+	}
+
 	if (stdin_paths)
-		check_attr_stdin_paths(prefix, check, all_attrs);
+		check_attr_stdin_paths(prefix, check, tree_oid, all_attrs);
 	else {
 		for (i = filei; i < argc; i++)
-			check_attr(prefix, check, all_attrs, argv[i]);
+			check_attr(prefix, check, tree_oid, all_attrs, argv[i]);
 		maybe_flush_or_die(stdout, "attribute to stdout");
 	}
 
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 3fa29a0..a5155cf 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -29,6 +29,7 @@
 #include "xdiff-interface.h"
 #include "entry.h"
 #include "parallel-checkout.h"
+#include "add-interactive.h"
 
 static const char * const checkout_usage[] = {
 	N_("git checkout [<options>] <branch>"),
@@ -232,7 +233,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
 		pos++;
 	}
 	if (!overlay_mode) {
-		unlink_entry(ce);
+		unlink_entry(ce, NULL);
 		return 0;
 	}
 	if (stage == 2)
@@ -499,7 +500,7 @@ static int checkout_paths(const struct checkout_opts *opts,
 		    "--merge", "--conflict", "--staged");
 
 	if (opts->patch_mode) {
-		const char *patch_mode;
+		enum add_p_mode patch_mode;
 		const char *rev = new_branch_info->name;
 		char rev_oid[GIT_MAX_HEXSZ + 1];
 
@@ -517,15 +518,16 @@ static int checkout_paths(const struct checkout_opts *opts,
 			rev = oid_to_hex_r(rev_oid, &new_branch_info->commit->object.oid);
 
 		if (opts->checkout_index && opts->checkout_worktree)
-			patch_mode = "--patch=checkout";
+			patch_mode = ADD_P_CHECKOUT;
 		else if (opts->checkout_index && !opts->checkout_worktree)
-			patch_mode = "--patch=reset";
+			patch_mode = ADD_P_RESET;
 		else if (!opts->checkout_index && opts->checkout_worktree)
-			patch_mode = "--patch=worktree";
+			patch_mode = ADD_P_WORKTREE;
 		else
 			BUG("either flag must have been set, worktree=%d, index=%d",
 			    opts->checkout_worktree, opts->checkout_index);
-		return run_add_interactive(rev, patch_mode, &opts->pathspec);
+		return !!run_add_p(the_repository, patch_mode, rev,
+				   &opts->pathspec);
 	}
 
 	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
@@ -1270,7 +1272,7 @@ static int parse_branchname_arg(int argc, const char **argv,
 	 *       between A and B, A...B names that merge base.
 	 *
 	 *   (b) If <something> is _not_ a commit, either "--" is present
-	 *       or <something> is not a path, no -t or -b was given, and
+	 *       or <something> is not a path, no -t or -b was given,
 	 *       and there is a tracking branch whose name is <something>
 	 *       in one and only one remote (or if the branch exists on the
 	 *       remote named in checkout.defaultRemote), then this is a
@@ -1471,6 +1473,8 @@ static void die_if_some_operation_in_progress(void)
 		      "or \"git worktree add\"."));
 	if (state.bisect_in_progress)
 		warning(_("you are switching branch while bisecting"));
+
+	wt_status_state_free_buffers(&state);
 }
 
 static int checkout_branch(struct checkout_opts *opts,
diff --git a/builtin/clean.c b/builtin/clean.c
index b2701a2..10aaa8c 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -560,7 +560,7 @@ static int parse_choice(struct menu_stuff *menu_stuff,
 
 /*
  * Implement a git-add-interactive compatible UI, which is borrowed
- * from git-add--interactive.perl.
+ * from add-interactive.c.
  *
  * Return value:
  *
@@ -1092,5 +1092,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 	strbuf_release(&buf);
 	string_list_clear(&del_list, 0);
 	string_list_clear(&exclude_list, 0);
+	clear_pathspec(&pathspec);
 	return (errors != 0);
 }
diff --git a/builtin/clone.c b/builtin/clone.c
index 9ec500d..399b2d3 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -921,6 +921,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	int is_bundle = 0, is_local;
 	int reject_shallow = 0;
 	const char *repo_name, *repo, *work_tree, *git_dir;
+	char *repo_to_free = NULL;
 	char *path = NULL, *dir, *display_repo = NULL;
 	int dest_exists, real_dest_exists = 0;
 	const struct ref *refs, *remote_head;
@@ -978,7 +979,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	path = get_repo_path(repo_name, &is_bundle);
 	if (path) {
 		FREE_AND_NULL(path);
-		repo = absolute_pathdup(repo_name);
+		repo = repo_to_free = absolute_pathdup(repo_name);
 	} else if (strchr(repo_name, ':')) {
 		repo = repo_name;
 		display_repo = transport_anonymize_url(repo);
@@ -1277,12 +1278,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	 * data from the --bundle-uri option.
 	 */
 	if (bundle_uri) {
+		int has_heuristic = 0;
+
 		/* At this point, we need the_repository to match the cloned repo. */
 		if (repo_init(the_repository, git_dir, work_tree))
 			warning(_("failed to initialize the repo, skipping bundle URI"));
-		else if (fetch_bundle_uri(the_repository, bundle_uri))
+		else if (fetch_bundle_uri(the_repository, bundle_uri, &has_heuristic))
 			warning(_("failed to fetch objects from bundle URI '%s'"),
 				bundle_uri);
+		else if (has_heuristic)
+			git_config_set_gently("fetch.bundleuri", bundle_uri);
 	}
 
 	strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
@@ -1300,6 +1305,27 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	if (refs)
 		mapped_refs = wanted_peer_refs(refs, &remote->fetch);
 
+	if (!bundle_uri) {
+		/*
+		* Populate transport->got_remote_bundle_uri and
+		* transport->bundle_uri. We might get nothing.
+		*/
+		transport_get_remote_bundle_uri(transport);
+
+		if (transport->bundles &&
+		    hashmap_get_size(&transport->bundles->bundles)) {
+			/* At this point, we need the_repository to match the cloned repo. */
+			if (repo_init(the_repository, git_dir, work_tree))
+				warning(_("failed to initialize the repo, skipping bundle URI"));
+			else if (fetch_bundle_list(the_repository,
+						   transport->bundles))
+				warning(_("failed to fetch advertised bundles"));
+		} else {
+			clear_bundle_list(transport->bundles);
+			FREE_AND_NULL(transport->bundles);
+		}
+	}
+
 	if (mapped_refs) {
 		int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
 
@@ -1421,6 +1447,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	free(unborn_head);
 	free(dir);
 	free(path);
+	free(repo_to_free);
 	UNLEAK(repo);
 	junk_mode = JUNK_LEAVE_ALL;
 
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index e8f77f5..93704f9 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -67,6 +67,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
 	int fd;
 	struct stat st;
 	int flags = 0;
+	int ret;
 
 	static struct option builtin_commit_graph_verify_options[] = {
 		OPT_BOOL(0, "shallow", &opts.shallow,
@@ -111,8 +112,9 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
 	if (!graph)
 		return !!open_ok;
 
-	UNLEAK(graph);
-	return verify_commit_graph(the_repository, graph, flags);
+	ret = verify_commit_graph(the_repository, graph, flags);
+	free_commit_graph(graph);
+	return ret;
 }
 
 extern int read_replace_refs;
@@ -267,8 +269,8 @@ static int graph_write(int argc, const char **argv, const char *prefix)
 
 	if (opts.reachable) {
 		if (write_commit_graph_reachable(odb, flags, &write_opts))
-			return 1;
-		return 0;
+			result = 1;
+		goto cleanup;
 	}
 
 	if (opts.stdin_packs) {
diff --git a/builtin/commit.c b/builtin/commit.c
index 06b1330..985a044 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -5,7 +5,7 @@
  * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
  */
 
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
 #include "cache.h"
 #include "config.h"
 #include "lockfile.h"
@@ -414,7 +414,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
 		discard_index(&the_index);
 		read_index_from(&the_index, get_lock_file_path(&index_lock),
 				get_git_dir());
-		if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
+		if (cache_tree_update(&the_index, WRITE_TREE_SILENT) == 0) {
 			if (reopen_lock_file(&index_lock) < 0)
 				die(_("unable to write index file"));
 			if (write_locked_index(&the_index, &index_lock, 0))
@@ -444,7 +444,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
 				       LOCK_DIE_ON_ERROR);
 		add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
 		refresh_cache_or_die(refresh_flags);
-		update_main_cache_tree(WRITE_TREE_SILENT);
+		cache_tree_update(&the_index, WRITE_TREE_SILENT);
 		if (write_locked_index(&the_index, &index_lock, 0))
 			die(_("unable to write new_index file"));
 		commit_style = COMMIT_NORMAL;
@@ -467,7 +467,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
 		refresh_cache_or_die(refresh_flags);
 		if (the_index.cache_changed
 		    || !cache_tree_fully_valid(the_index.cache_tree))
-			update_main_cache_tree(WRITE_TREE_SILENT);
+			cache_tree_update(&the_index, WRITE_TREE_SILENT);
 		if (write_locked_index(&the_index, &index_lock,
 				       COMMIT_LOCK | SKIP_IF_UNCHANGED))
 			die(_("unable to write new_index file"));
@@ -516,7 +516,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
 	repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR);
 	add_remove_files(&partial);
 	refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
-	update_main_cache_tree(WRITE_TREE_SILENT);
+	cache_tree_update(&the_index, WRITE_TREE_SILENT);
 	if (write_locked_index(&the_index, &index_lock, 0))
 		die(_("unable to write new_index file"));
 
@@ -991,8 +991,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		struct object_id oid;
 		const char *parent = "HEAD";
 
-		if (!active_nr && read_cache() < 0)
-			die(_("Cannot read index"));
+		if (!the_index.cache_nr) {
+			discard_index(&the_index);
+			if (repo_read_index(the_repository) < 0)
+				die(_("Cannot read index"));
+		}
 
 		if (amend)
 			parent = "HEAD^1";
@@ -1076,7 +1079,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	}
 	read_index_from(&the_index, index_file, get_git_dir());
 
-	if (update_main_cache_tree(0)) {
+	if (cache_tree_update(&the_index, 0)) {
 		error(_("Error building trees"));
 		return 0;
 	}
@@ -1875,8 +1878,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 	apply_autostash(git_path_merge_autostash(the_repository));
 
 cleanup:
-	UNLEAK(author_ident);
-	UNLEAK(err);
-	UNLEAK(sb);
+	strbuf_release(&author_ident);
+	strbuf_release(&err);
+	strbuf_release(&sb);
 	return ret;
 }
diff --git a/builtin/config.c b/builtin/config.c
index 753e5fa..060cf9f 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -639,8 +639,9 @@ static char *default_user_config(void)
 int cmd_config(int argc, const char **argv, const char *prefix)
 {
 	int nongit = !startup_info->have_repository;
-	char *value;
+	char *value = NULL;
 	int flags = 0;
+	int ret = 0;
 
 	given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
 
@@ -856,44 +857,38 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		free(config_file);
 	}
 	else if (actions == ACTION_SET) {
-		int ret;
 		check_write();
 		check_argc(argc, 2, 2);
 		value = normalize_value(argv[0], argv[1]);
-		UNLEAK(value);
 		ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
 		if (ret == CONFIG_NOTHING_SET)
 			error(_("cannot overwrite multiple values with a single value\n"
 			"       Use a regexp, --add or --replace-all to change %s."), argv[0]);
-		return ret;
 	}
 	else if (actions == ACTION_SET_ALL) {
 		check_write();
 		check_argc(argc, 2, 3);
 		value = normalize_value(argv[0], argv[1]);
-		UNLEAK(value);
-		return git_config_set_multivar_in_file_gently(given_config_source.file,
-							      argv[0], value, argv[2],
-							      flags);
+		ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+							     argv[0], value, argv[2],
+							     flags);
 	}
 	else if (actions == ACTION_ADD) {
 		check_write();
 		check_argc(argc, 2, 2);
 		value = normalize_value(argv[0], argv[1]);
-		UNLEAK(value);
-		return git_config_set_multivar_in_file_gently(given_config_source.file,
-							      argv[0], value,
-							      CONFIG_REGEX_NONE,
-							      flags);
+		ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+							     argv[0], value,
+							     CONFIG_REGEX_NONE,
+							     flags);
 	}
 	else if (actions == ACTION_REPLACE_ALL) {
 		check_write();
 		check_argc(argc, 2, 3);
 		value = normalize_value(argv[0], argv[1]);
-		UNLEAK(value);
-		return git_config_set_multivar_in_file_gently(given_config_source.file,
-							      argv[0], value, argv[2],
-							      flags | CONFIG_FLAGS_MULTI_REPLACE);
+		ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+							     argv[0], value, argv[2],
+							     flags | CONFIG_FLAGS_MULTI_REPLACE);
 	}
 	else if (actions == ACTION_GET) {
 		check_argc(argc, 1, 2);
@@ -934,26 +929,28 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 							      flags | CONFIG_FLAGS_MULTI_REPLACE);
 	}
 	else if (actions == ACTION_RENAME_SECTION) {
-		int ret;
 		check_write();
 		check_argc(argc, 2, 2);
 		ret = git_config_rename_section_in_file(given_config_source.file,
 							argv[0], argv[1]);
 		if (ret < 0)
 			return ret;
-		if (ret == 0)
+		else if (!ret)
 			die(_("no such section: %s"), argv[0]);
+		else
+			ret = 0;
 	}
 	else if (actions == ACTION_REMOVE_SECTION) {
-		int ret;
 		check_write();
 		check_argc(argc, 1, 1);
 		ret = git_config_rename_section_in_file(given_config_source.file,
 							argv[0], NULL);
 		if (ret < 0)
 			return ret;
-		if (ret == 0)
+		else if (!ret)
 			die(_("no such section: %s"), argv[0]);
+		else
+			ret = 0;
 	}
 	else if (actions == ACTION_GET_COLOR) {
 		check_argc(argc, 1, 2);
@@ -966,5 +963,6 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		return get_colorbool(argv[0], argc == 2);
 	}
 
-	return 0;
+	free(value);
+	return ret;
 }
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index f3c8983..338058b 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -127,6 +127,9 @@ static void serve_one_client(FILE *in, FILE *out)
 		if (e) {
 			fprintf(out, "username=%s\n", e->item.username);
 			fprintf(out, "password=%s\n", e->item.password);
+			if (e->item.password_expiry_utc != TIME_MAX)
+				fprintf(out, "password_expiry_utc=%"PRItime"\n",
+					e->item.password_expiry_utc);
 		}
 	}
 	else if (!strcmp(action.buf, "exit")) {
diff --git a/builtin/diff.c b/builtin/diff.c
index 163f2c6..26f1e53 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -612,7 +612,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 	if (1 < rev.diffopt.skip_stat_unmatch)
 		refresh_index_quietly();
 	release_revisions(&rev);
-	UNLEAK(ent);
+	object_array_clear(&ent);
 	UNLEAK(blob);
 	return result;
 }
diff --git a/builtin/difftool.c b/builtin/difftool.c
index d9b7622..dbbfb19 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -361,7 +361,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	struct hashmap symlinks2 = HASHMAP_INIT(pair_cmp, NULL);
 	struct hashmap_iter iter;
 	struct pair_entry *entry;
-	struct index_state wtindex;
+	struct index_state wtindex = INDEX_STATE_INIT(the_repository);
 	struct checkout lstate, rstate;
 	int err = 0;
 	struct child_process cmd = CHILD_PROCESS_INIT;
@@ -387,8 +387,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	mkdir(ldir.buf, 0700);
 	mkdir(rdir.buf, 0700);
 
-	memset(&wtindex, 0, sizeof(wtindex));
-
 	memset(&lstate, 0, sizeof(lstate));
 	lstate.base_dir = lbase_dir = xstrdup(ldir.buf);
 	lstate.base_dir_len = ldir.len;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7378caf..a09606b 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -29,6 +29,7 @@
 #include "commit-graph.h"
 #include "shallow.h"
 #include "worktree.h"
+#include "bundle-uri.h"
 
 #define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
 
@@ -2109,6 +2110,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
 int cmd_fetch(int argc, const char **argv, const char *prefix)
 {
 	int i;
+	const char *bundle_uri;
 	struct string_list list = STRING_LIST_INIT_DUP;
 	struct remote *remote = NULL;
 	int result = 0;
@@ -2194,6 +2196,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 	if (dry_run)
 		write_fetch_head = 0;
 
+	if (!max_jobs)
+		max_jobs = online_cpus();
+
+	if (!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri) &&
+	    fetch_bundle_uri(the_repository, bundle_uri, NULL))
+		warning(_("failed to fetch bundles from '%s'"), bundle_uri);
+
 	if (all) {
 		if (argc == 1)
 			die(_("fetch --all does not take a repository argument"));
@@ -2228,6 +2237,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 			argv++;
 		}
 	}
+	string_list_remove_duplicates(&list, 0);
 
 	if (negotiate_only) {
 		struct oidset acked_commits = OIDSET_INIT;
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 6f30a4f..0feef8c 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -710,6 +710,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 				  "fsmonitor: unsupported V1 protocol '%s'"),
 				 command);
 		do_trivial = 1;
+		do_cookie = 1;
 
 	} else {
 		/* We have "builtin:*" */
@@ -719,6 +720,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 					 "fsmonitor: invalid V2 protocol token '%s'",
 					 command);
 			do_trivial = 1;
+			do_cookie = 1;
 
 		} else {
 			/*
@@ -1209,7 +1211,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
 	 * events.
 	 */
 	if (pthread_create(&state->listener_thread, NULL,
-			   fsm_listen__thread_proc, state) < 0) {
+			   fsm_listen__thread_proc, state)) {
 		ipc_server_stop_async(state->ipc_server_data);
 		err = error(_("could not start fsmonitor listener thread"));
 		goto cleanup;
@@ -1220,7 +1222,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
 	 * Start the health thread to watch over our process.
 	 */
 	if (pthread_create(&state->health_thread, NULL,
-			   fsm_health__thread_proc, state) < 0) {
+			   fsm_health__thread_proc, state)) {
 		ipc_server_stop_async(state->ipc_server_data);
 		err = error(_("could not start fsmonitor health thread"));
 		goto cleanup;
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index b506381..44db83f 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -27,6 +27,7 @@ static int hash_literally(struct object_id *oid, int fd, const char *type, unsig
 	else
 		ret = write_object_file_literally(buf.buf, buf.len, type, oid,
 						 flags);
+	close(fd);
 	strbuf_release(&buf);
 	return ret;
 }
diff --git a/builtin/hook.c b/builtin/hook.c
index b6530d1..f95b796 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -7,7 +7,7 @@
 #include "strvec.h"
 
 #define BUILTIN_HOOK_RUN_USAGE \
-	N_("git hook run [--ignore-missing] <hook-name> [-- <hook-args>]")
+	N_("git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]")
 
 static const char * const builtin_hook_usage[] = {
 	BUILTIN_HOOK_RUN_USAGE,
@@ -28,6 +28,8 @@ static int run(int argc, const char **argv, const char *prefix)
 	struct option run_options[] = {
 		OPT_BOOL(0, "ignore-missing", &ignore_missing,
 			 N_("silently ignore missing requested <hook-name>")),
+		OPT_STRING(0, "to-stdin", &opt.path_to_stdin, N_("path"),
+			   N_("file to read into hooks' stdin")),
 		OPT_END(),
 	};
 	int ret;
diff --git a/builtin/log.c b/builtin/log.c
index 89447a5..a70fba1 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -52,6 +52,7 @@ static int decoration_style;
 static int decoration_given;
 static int use_mailmap_config = 1;
 static unsigned int force_in_body_from;
+static int stdout_mboxrd;
 static const char *fmt_patch_subject_prefix = "PATCH";
 static int fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
 static const char *fmt_pretty;
@@ -1006,6 +1007,8 @@ static int git_format_config(const char *var, const char *value, void *cb)
 	if (!strcmp(var, "format.attach")) {
 		if (value && *value)
 			default_attach = xstrdup(value);
+		else if (value && !*value)
+			FREE_AND_NULL(default_attach);
 		else
 			default_attach = xstrdup(git_version_string);
 		return 0;
@@ -1077,6 +1080,10 @@ static int git_format_config(const char *var, const char *value, void *cb)
 		cover_from_description_mode = parse_cover_from_description(value);
 		return 0;
 	}
+	if (!strcmp(var, "format.mboxrd")) {
+		stdout_mboxrd = git_config_bool(var, value);
+		return 0;
+	}
 
 	return git_log_config(var, value, cb);
 }
@@ -1870,6 +1877,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	struct strbuf rdiff1 = STRBUF_INIT;
 	struct strbuf rdiff2 = STRBUF_INIT;
 	struct strbuf rdiff_title = STRBUF_INIT;
+	struct strbuf sprefix = STRBUF_INIT;
 	int creation_factor = -1;
 
 	const struct option builtin_format_patch_options[] = {
@@ -2010,12 +2018,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 		cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
 
 	if (reroll_count) {
-		struct strbuf sprefix = STRBUF_INIT;
-
 		strbuf_addf(&sprefix, "%s v%s",
 			    rev.subject_prefix, reroll_count);
 		rev.reroll_count = reroll_count;
-		rev.subject_prefix = strbuf_detach(&sprefix, NULL);
+		rev.subject_prefix = sprefix.buf;
 	}
 
 	for (i = 0; i < extra_hdr.nr; i++) {
@@ -2105,6 +2111,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 				  rev.diffopt.close_file, "--output",
 				  !!output_directory, "--output-directory");
 
+	if (use_stdout && stdout_mboxrd)
+		rev.commit_format = CMIT_FMT_MBOXRD;
+
 	if (use_stdout) {
 		setup_pager();
 	} else if (!rev.diffopt.close_file) {
@@ -2376,6 +2385,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	strbuf_release(&rdiff1);
 	strbuf_release(&rdiff2);
 	strbuf_release(&rdiff_title);
+	strbuf_release(&sprefix);
 	free(to_free);
 	if (rev.ref_message_ids)
 		string_list_clear(rev.ref_message_ids, 0);
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 4cf8a23..a03b559 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -613,6 +613,7 @@ void overlay_tree_on_index(struct index_state *istate,
 	if (!fn)
 		fn = read_one_entry_quick;
 	err = read_tree(the_repository, tree, &pathspec, fn, istate);
+	clear_pathspec(&pathspec);
 	if (err)
 		die("unable to read tree entries %s", tree_name);
 
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 5d5ac03..6516177 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -8,7 +8,7 @@
 static const char * const ls_remote_usage[] = {
 	N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 	   "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-	   "              [--symref] [<repository> [<refs>...]]"),
+	   "              [--symref] [<repository> [<patterns>...]]"),
 	NULL
 };
 
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index b1f69fb..8cc8c99 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -14,37 +14,11 @@
 #include "parse-options.h"
 #include "pathspec.h"
 
-static int line_termination = '\n';
-#define LS_RECURSIVE 1
-#define LS_TREE_ONLY (1 << 1)
-#define LS_SHOW_TREES (1 << 2)
-static int abbrev;
-static int ls_options;
-static struct pathspec pathspec;
-static int chomp_prefix;
-static const char *ls_tree_prefix;
-static const char *format;
-struct show_tree_data {
-	unsigned mode;
-	enum object_type type;
-	const struct object_id *oid;
-	const char *pathname;
-	struct strbuf *base;
-};
-
-static const  char * const ls_tree_usage[] = {
+static const char * const ls_tree_usage[] = {
 	N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
 	NULL
 };
 
-static enum ls_tree_cmdmode {
-	MODE_DEFAULT = 0,
-	MODE_LONG,
-	MODE_NAME_ONLY,
-	MODE_NAME_STATUS,
-	MODE_OBJECT_ONLY,
-} cmdmode;
-
 static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
 			      const enum object_type type, unsigned int padded)
 {
@@ -64,10 +38,34 @@ static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
 	}
 }
 
+struct ls_tree_options {
+	unsigned null_termination:1;
+	int abbrev;
+	enum ls_tree_path_options {
+		LS_RECURSIVE = 1 << 0,
+		LS_TREE_ONLY = 1 << 1,
+		LS_SHOW_TREES = 1 << 2,
+	} ls_options;
+	struct pathspec pathspec;
+	int chomp_prefix;
+	const char *ls_tree_prefix;
+	const char *format;
+};
+
+struct show_tree_data {
+	struct ls_tree_options *options;
+	unsigned mode;
+	enum object_type type;
+	const struct object_id *oid;
+	const char *pathname;
+	struct strbuf *base;
+};
+
 static size_t expand_show_tree(struct strbuf *sb, const char *start,
 			       void *context)
 {
 	struct show_tree_data *data = context;
+	struct ls_tree_options *options = data->options;
 	const char *end;
 	const char *p;
 	unsigned int errlen;
@@ -92,10 +90,10 @@ static size_t expand_show_tree(struct strbuf *sb, const char *start,
 	} else if (skip_prefix(start, "(objectsize)", &p)) {
 		expand_objectsize(sb, data->oid, data->type, 0);
 	} else if (skip_prefix(start, "(objectname)", &p)) {
-		strbuf_add_unique_abbrev(sb, data->oid, abbrev);
+		strbuf_add_unique_abbrev(sb, data->oid, options->abbrev);
 	} else if (skip_prefix(start, "(path)", &p)) {
-		const char *name;
-		const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
+		const char *name = data->base->buf;
+		const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
 		struct strbuf sbuf = STRBUF_INIT;
 		size_t baselen = data->base->len;
 
@@ -111,18 +109,19 @@ static size_t expand_show_tree(struct strbuf *sb, const char *start,
 	return len;
 }
 
-static int show_recursive(const char *base, size_t baselen, const char *pathname)
+static int show_recursive(struct ls_tree_options *options, const char *base,
+			  size_t baselen, const char *pathname)
 {
 	int i;
 
-	if (ls_options & LS_RECURSIVE)
+	if (options->ls_options & LS_RECURSIVE)
 		return 1;
 
-	if (!pathspec.nr)
+	if (!options->pathspec.nr)
 		return 0;
 
-	for (i = 0; i < pathspec.nr; i++) {
-		const char *spec = pathspec.items[i].match;
+	for (i = 0; i < options->pathspec.nr; i++) {
+		const char *spec = options->pathspec.items[i].match;
 		size_t len, speclen;
 
 		if (strncmp(base, spec, baselen))
@@ -142,13 +141,14 @@ static int show_recursive(const char *base, size_t baselen, const char *pathname
 }
 
 static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
-			 const char *pathname, unsigned mode, void *context UNUSED)
+			 const char *pathname, unsigned mode, void *context)
 {
+	struct ls_tree_options *options = context;
 	int recurse = 0;
 	struct strbuf sb = STRBUF_INIT;
 	enum object_type type = object_type(mode);
-
-	struct show_tree_data data = {
+	struct show_tree_data cb_data = {
+		.options = options,
 		.mode = mode,
 		.type = type,
 		.oid = oid,
@@ -156,92 +156,100 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
 		.base = base,
 	};
 
-	if (type == OBJ_TREE && show_recursive(base->buf, base->len, pathname))
+	if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
 		recurse = READ_TREE_RECURSIVE;
-	if (type == OBJ_TREE && recurse && !(ls_options & LS_SHOW_TREES))
+	if (type == OBJ_TREE && recurse && !(options->ls_options & LS_SHOW_TREES))
 		return recurse;
-	if (type == OBJ_BLOB && (ls_options & LS_TREE_ONLY))
+	if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
 		return 0;
 
-	strbuf_expand(&sb, format, expand_show_tree, &data);
-	strbuf_addch(&sb, line_termination);
+	strbuf_expand(&sb, options->format, expand_show_tree, &cb_data);
+	strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
 	fwrite(sb.buf, sb.len, 1, stdout);
 	strbuf_release(&sb);
 	return recurse;
 }
 
-static int show_tree_common(struct show_tree_data *data, int *recurse,
-			    const struct object_id *oid, struct strbuf *base,
-			    const char *pathname, unsigned mode)
+static int show_tree_common(struct ls_tree_options *options, int *recurse,
+			    struct strbuf *base, const char *pathname,
+			    enum object_type type)
 {
-	enum object_type type = object_type(mode);
 	int ret = -1;
-
 	*recurse = 0;
-	data->mode = mode;
-	data->type = type;
-	data->oid = oid;
-	data->pathname = pathname;
-	data->base = base;
 
 	if (type == OBJ_BLOB) {
-		if (ls_options & LS_TREE_ONLY)
+		if (options->ls_options & LS_TREE_ONLY)
 			ret = 0;
 	} else if (type == OBJ_TREE &&
-		   show_recursive(base->buf, base->len, pathname)) {
+		   show_recursive(options, base->buf, base->len, pathname)) {
 		*recurse = READ_TREE_RECURSIVE;
-		if (!(ls_options & LS_SHOW_TREES))
+		if (!(options->ls_options & LS_SHOW_TREES))
 			ret = *recurse;
 	}
 
 	return ret;
 }
 
-static void show_tree_common_default_long(struct strbuf *base,
+static void show_tree_common_default_long(struct ls_tree_options *options,
+					  struct strbuf *base,
 					  const char *pathname,
 					  const size_t baselen)
 {
+	const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
+
 	strbuf_addstr(base, pathname);
-	write_name_quoted_relative(base->buf,
-				   chomp_prefix ? ls_tree_prefix : NULL, stdout,
-				   line_termination);
+
+	if (options->null_termination) {
+		struct strbuf sb = STRBUF_INIT;
+		const char *name = relative_path(base->buf, prefix, &sb);
+
+		fputs(name, stdout);
+		fputc('\0', stdout);
+
+		strbuf_release(&sb);
+	} else {
+		write_name_quoted_relative(base->buf, prefix, stdout, '\n');
+	}
+
 	strbuf_setlen(base, baselen);
 }
 
 static int show_tree_default(const struct object_id *oid, struct strbuf *base,
 			     const char *pathname, unsigned mode,
-			     void *context UNUSED)
+			     void *context)
 {
+	struct ls_tree_options *options = context;
 	int early;
 	int recurse;
-	struct show_tree_data data = { 0 };
+	enum object_type type = object_type(mode);
 
-	early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+	early = show_tree_common(options, &recurse, base, pathname, type);
 	if (early >= 0)
 		return early;
 
-	printf("%06o %s %s\t", data.mode, type_name(data.type),
-	       find_unique_abbrev(data.oid, abbrev));
-	show_tree_common_default_long(base, pathname, data.base->len);
+	printf("%06o %s %s\t", mode, type_name(object_type(mode)),
+	       find_unique_abbrev(oid, options->abbrev));
+	show_tree_common_default_long(options, base, pathname, base->len);
 	return recurse;
 }
 
 static int show_tree_long(const struct object_id *oid, struct strbuf *base,
 			  const char *pathname, unsigned mode,
-			  void *context UNUSED)
+			  void *context)
 {
+	struct ls_tree_options *options = context;
 	int early;
 	int recurse;
-	struct show_tree_data data = { 0 };
 	char size_text[24];
+	enum object_type type = object_type(mode);
 
-	early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+	early = show_tree_common(options, &recurse, base, pathname, type);
 	if (early >= 0)
 		return early;
 
-	if (data.type == OBJ_BLOB) {
+	if (type == OBJ_BLOB) {
 		unsigned long size;
-		if (oid_object_info(the_repository, data.oid, &size) == OBJ_BAD)
+		if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
 			xsnprintf(size_text, sizeof(size_text), "BAD");
 		else
 			xsnprintf(size_text, sizeof(size_text),
@@ -250,49 +258,76 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
 		xsnprintf(size_text, sizeof(size_text), "-");
 	}
 
-	printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
-	       find_unique_abbrev(data.oid, abbrev), size_text);
-	show_tree_common_default_long(base, pathname, data.base->len);
+	printf("%06o %s %s %7s\t", mode, type_name(type),
+	       find_unique_abbrev(oid, options->abbrev), size_text);
+	show_tree_common_default_long(options, base, pathname, base->len);
 	return recurse;
 }
 
 static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
 			       const char *pathname, unsigned mode,
-			       void *context UNUSED)
+			       void *context)
 {
+	struct ls_tree_options *options = context;
 	int early;
 	int recurse;
 	const size_t baselen = base->len;
-	struct show_tree_data data = { 0 };
+	enum object_type type = object_type(mode);
+	const char *prefix;
 
-	early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+	early = show_tree_common(options, &recurse, base, pathname, type);
 	if (early >= 0)
 		return early;
 
+	prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
 	strbuf_addstr(base, pathname);
-	write_name_quoted_relative(base->buf,
-				   chomp_prefix ? ls_tree_prefix : NULL,
-				   stdout, line_termination);
+	if (options->null_termination) {
+		struct strbuf sb = STRBUF_INIT;
+		const char *name = relative_path(base->buf, prefix, &sb);
+
+		fputs(name, stdout);
+		fputc('\0', stdout);
+
+		strbuf_release(&sb);
+	} else {
+		write_name_quoted_relative(base->buf, prefix, stdout, '\n');
+	}
 	strbuf_setlen(base, baselen);
 	return recurse;
 }
 
 static int show_tree_object(const struct object_id *oid, struct strbuf *base,
 			    const char *pathname, unsigned mode,
-			    void *context UNUSED)
+			    void *context)
 {
+	struct ls_tree_options *options = context;
 	int early;
 	int recurse;
-	struct show_tree_data data = { 0 };
+	enum object_type type = object_type(mode);
+	const char *str;
 
-	early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+	early = show_tree_common(options, &recurse, base, pathname, type);
 	if (early >= 0)
 		return early;
 
-	printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
+	str = find_unique_abbrev(oid, options->abbrev);
+	if (options->null_termination) {
+		fputs(str, stdout);
+		fputc('\0', stdout);
+	} else  {
+		puts(str);
+	}
 	return recurse;
 }
 
+enum ls_tree_cmdmode {
+	MODE_DEFAULT = 0,
+	MODE_LONG,
+	MODE_NAME_ONLY,
+	MODE_NAME_STATUS,
+	MODE_OBJECT_ONLY,
+};
+
 struct ls_tree_cmdmode_to_fmt {
 	enum ls_tree_cmdmode mode;
 	const char *const fmt;
@@ -332,15 +367,18 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	struct tree *tree;
 	int i, full_tree = 0;
 	read_tree_fn_t fn = NULL;
+	enum ls_tree_cmdmode cmdmode = MODE_DEFAULT;
+	int null_termination = 0;
+	struct ls_tree_options options = { 0 };
 	const struct option ls_tree_options[] = {
-		OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
+		OPT_BIT('d', NULL, &options.ls_options, N_("only show trees"),
 			LS_TREE_ONLY),
-		OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"),
+		OPT_BIT('r', NULL, &options.ls_options, N_("recurse into subtrees"),
 			LS_RECURSIVE),
-		OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"),
+		OPT_BIT('t', NULL, &options.ls_options, N_("show trees when recursing"),
 			LS_SHOW_TREES),
-		OPT_SET_INT('z', NULL, &line_termination,
-			    N_("terminate entries with NUL byte"), 0),
+		OPT_BOOL('z', NULL, &null_termination,
+			 N_("terminate entries with NUL byte")),
 		OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
 			    MODE_LONG),
 		OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
@@ -349,29 +387,32 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 			    MODE_NAME_STATUS),
 		OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
 			    MODE_OBJECT_ONLY),
-		OPT_SET_INT(0, "full-name", &chomp_prefix,
+		OPT_SET_INT(0, "full-name", &options.chomp_prefix,
 			    N_("use full path names"), 0),
 		OPT_BOOL(0, "full-tree", &full_tree,
 			 N_("list entire tree; not just current directory "
 			    "(implies --full-name)")),
-		OPT_STRING_F(0, "format", &format, N_("format"),
+		OPT_STRING_F(0, "format", &options.format, N_("format"),
 					 N_("format to use for the output"),
 					 PARSE_OPT_NONEG),
-		OPT__ABBREV(&abbrev),
+		OPT__ABBREV(&options.abbrev),
 		OPT_END()
 	};
 	struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
+	int ret;
 
 	git_config(git_default_config, NULL);
-	ls_tree_prefix = prefix;
+	options.ls_tree_prefix = prefix;
 	if (prefix)
-		chomp_prefix = strlen(prefix);
+		options.chomp_prefix = strlen(prefix);
 
 	argc = parse_options(argc, argv, prefix, ls_tree_options,
 			     ls_tree_usage, 0);
+	options.null_termination = null_termination;
+
 	if (full_tree) {
-		ls_tree_prefix = prefix = NULL;
-		chomp_prefix = 0;
+		options.ls_tree_prefix = prefix = NULL;
+		options.chomp_prefix = 0;
 	}
 	/*
 	 * We wanted to detect conflicts between --name-only and
@@ -383,10 +424,10 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 
 	/* -d -r should imply -t, but -d by itself should not have to. */
 	if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
-	    ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
-		ls_options |= LS_SHOW_TREES;
+	    ((LS_TREE_ONLY|LS_RECURSIVE) & options.ls_options))
+		options.ls_options |= LS_SHOW_TREES;
 
-	if (format && cmdmode)
+	if (options.format && cmdmode)
 		usage_msg_opt(
 			_("--format can't be combined with other format-altering options"),
 			ls_tree_usage, ls_tree_options);
@@ -401,13 +442,13 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	 * cannot be lifted until it is converted to use
 	 * match_pathspec() or tree_entry_interesting()
 	 */
-	parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &
-				  ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
+	parse_pathspec(&options.pathspec, PATHSPEC_ALL_MAGIC &
+		       ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
 		       PATHSPEC_PREFER_CWD,
 		       prefix, argv + 1);
-	for (i = 0; i < pathspec.nr; i++)
-		pathspec.items[i].nowildcard_len = pathspec.items[i].len;
-	pathspec.has_wildcard = 0;
+	for (i = 0; i < options.pathspec.nr; i++)
+		options.pathspec.items[i].nowildcard_len = options.pathspec.items[i].len;
+	options.pathspec.has_wildcard = 0;
 	tree = parse_tree_indirect(&oid);
 	if (!tree)
 		die("not a tree object");
@@ -417,11 +458,11 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	 */
 	while (m2f) {
 		if (!m2f->fmt) {
-			fn = format ? show_tree_fmt : show_tree_default;
-		} else if (format && !strcmp(format, m2f->fmt)) {
+			fn = options.format ? show_tree_fmt : show_tree_default;
+		} else if (options.format && !strcmp(options.format, m2f->fmt)) {
 			cmdmode = m2f->mode;
 			fn = m2f->fn;
-		} else if (!format && cmdmode == m2f->mode) {
+		} else if (!options.format && cmdmode == m2f->mode) {
 			fn = m2f->fn;
 		} else {
 			m2f++;
@@ -430,5 +471,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 		break;
 	}
 
-	return !!read_tree(the_repository, tree, &pathspec, fn, NULL);
+	ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options);
+	clear_pathspec(&options.pathspec);
+	return ret;
 }
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index ae2c011..828dc81 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -3,6 +3,7 @@
 #include "tree-walk.h"
 #include "xdiff-interface.h"
 #include "help.h"
+#include "commit.h"
 #include "commit-reach.h"
 #include "merge-ort.h"
 #include "object-store.h"
@@ -406,6 +407,7 @@ struct merge_tree_options {
 };
 
 static int real_merge(struct merge_tree_options *o,
+		      const char *merge_base,
 		      const char *branch1, const char *branch2,
 		      const char *prefix)
 {
@@ -432,16 +434,31 @@ static int real_merge(struct merge_tree_options *o,
 	opt.branch1 = branch1;
 	opt.branch2 = branch2;
 
-	/*
-	 * Get the merge bases, in reverse order; see comment above
-	 * merge_incore_recursive in merge-ort.h
-	 */
-	merge_bases = get_merge_bases(parent1, parent2);
-	if (!merge_bases && !o->allow_unrelated_histories)
-		die(_("refusing to merge unrelated histories"));
-	merge_bases = reverse_commit_list(merge_bases);
+	if (merge_base) {
+		struct commit *base_commit;
+		struct tree *base_tree, *parent1_tree, *parent2_tree;
 
-	merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
+		base_commit = lookup_commit_reference_by_name(merge_base);
+		if (!base_commit)
+			die(_("could not lookup commit %s"), merge_base);
+
+		opt.ancestor = merge_base;
+		base_tree = get_commit_tree(base_commit);
+		parent1_tree = get_commit_tree(parent1);
+		parent2_tree = get_commit_tree(parent2);
+		merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
+	} else {
+		/*
+		 * Get the merge bases, in reverse order; see comment above
+		 * merge_incore_recursive in merge-ort.h
+		 */
+		merge_bases = get_merge_bases(parent1, parent2);
+		if (!merge_bases && !o->allow_unrelated_histories)
+			die(_("refusing to merge unrelated histories"));
+		merge_bases = reverse_commit_list(merge_bases);
+		merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
+	}
+
 	if (result.clean < 0)
 		die(_("failure to merge"));
 
@@ -487,6 +504,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
 	struct merge_tree_options o = { .show_messages = -1 };
 	int expected_remaining_argc;
 	int original_argc;
+	const char *merge_base = NULL;
 
 	const char * const merge_tree_usage[] = {
 		N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
@@ -515,6 +533,10 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
 			   &o.use_stdin,
 			   N_("perform multiple merges, one per line of input"),
 			   PARSE_OPT_NONEG),
+		OPT_STRING(0, "merge-base",
+			   &merge_base,
+			   N_("commit"),
+			   N_("specify a merge-base for the merge")),
 		OPT_END()
 	};
 
@@ -529,16 +551,35 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
 
 		if (o.mode == MODE_TRIVIAL)
 			die(_("--trivial-merge is incompatible with all other options"));
+		if (merge_base)
+			die(_("--merge-base is incompatible with --stdin"));
 		line_termination = '\0';
 		while (strbuf_getline_lf(&buf, stdin) != EOF) {
 			struct strbuf **split;
 			int result;
+			const char *input_merge_base = NULL;
 
 			split = strbuf_split(&buf, ' ');
-			if (!split[0] || !split[1] || split[2])
+			if (!split[0] || !split[1])
 				die(_("malformed input line: '%s'."), buf.buf);
 			strbuf_rtrim(split[0]);
-			result = real_merge(&o, split[0]->buf, split[1]->buf, prefix);
+			strbuf_rtrim(split[1]);
+
+			/* parse the merge-base */
+			if (!strcmp(split[1]->buf, "--")) {
+				input_merge_base = split[0]->buf;
+			}
+
+			if (input_merge_base && split[2] && split[3] && !split[4]) {
+				strbuf_rtrim(split[2]);
+				strbuf_rtrim(split[3]);
+				result = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);
+			} else if (!input_merge_base && !split[2]) {
+				result = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);
+			} else {
+				die(_("malformed input line: '%s'."), buf.buf);
+			}
+
 			if (result < 0)
 				die(_("merging cannot continue; got unclean result of %d"), result);
 			strbuf_list_free(split);
@@ -581,7 +622,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
 
 	/* Do the relevant type of merge */
 	if (o.mode == MODE_REAL)
-		return real_merge(&o, argv[0], argv[1], prefix);
+		return real_merge(&o, merge_base, argv[0], argv[1], prefix);
 	else
 		return trivial_merge(argv[0], argv[1], argv[2]);
 }
diff --git a/builtin/merge.c b/builtin/merge.c
index 17b41fb..0a3c10a 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -6,7 +6,7 @@
  * Based on git-merge.sh by Junio C Hamano.
  */
 
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
 #include "cache.h"
 #include "config.h"
 #include "parse-options.h"
@@ -188,7 +188,7 @@ static struct strategy *get_strategy(const char *name)
 		for (i = 0; i < main_cmds.cnt; i++) {
 			int j, found = 0;
 			struct cmdname *ent = main_cmds.names[i];
-			for (j = 0; j < ARRAY_SIZE(all_strategy); j++)
+			for (j = 0; !found && j < ARRAY_SIZE(all_strategy); j++)
 				if (!strncmp(ent->name, all_strategy[j].name, ent->len)
 						&& !all_strategy[j].name[ent->len])
 					found = 1;
@@ -390,8 +390,8 @@ static void restore_state(const struct object_id *head,
 	run_command(&cmd);
 
 refresh_cache:
-	discard_cache();
-	if (read_cache() < 0)
+	discard_index(&the_index);
+	if (repo_read_index(the_repository) < 0)
 		die(_("could not read index"));
 }
 
@@ -706,7 +706,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
 
 static void write_tree_trivial(struct object_id *oid)
 {
-	if (write_cache_as_tree(oid, 0, NULL))
+	if (write_index_as_tree(oid, &the_index, get_index_file(), 0, NULL))
 		die(_("git write-tree failed to write a tree"));
 }
 
@@ -1560,7 +1560,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			!common->next &&
 			oideq(&common->item->object.oid, &head_commit->object.oid)) {
 		/* Again the most common case of merging one remote. */
-		struct strbuf msg = STRBUF_INIT;
+		const char *msg = have_message ?
+			"Fast-forward (no commit created; -m option ignored)" :
+			"Fast-forward";
 		struct commit *commit;
 
 		if (verbosity >= 0) {
@@ -1570,10 +1572,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			       find_unique_abbrev(&remoteheads->item->object.oid,
 						  DEFAULT_ABBREV));
 		}
-		strbuf_addstr(&msg, "Fast-forward");
-		if (have_message)
-			strbuf_addstr(&msg,
-				" (no commit created; -m option ignored)");
 		commit = remoteheads->item;
 		if (!commit) {
 			ret = 1;
@@ -1592,9 +1590,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			goto done;
 		}
 
-		finish(head_commit, remoteheads, &commit->object.oid, msg.buf);
+		finish(head_commit, remoteheads, &commit->object.oid, msg);
 		remove_merge_branch_state(the_repository);
-		strbuf_release(&msg);
 		goto done;
 	} else if (!remoteheads->next && common->next)
 		;
@@ -1621,7 +1618,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 				error(_("Your local changes to the following files would be overwritten by merge:\n  %s"),
 				      sb.buf);
 				strbuf_release(&sb);
-				return 2;
+				ret = 2;
+				goto done;
 			}
 
 			/* See if it is really trivial. */
@@ -1789,5 +1787,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	}
 	strbuf_release(&buf);
 	free(branch_to_free);
+	discard_index(&the_index);
 	return ret;
 }
diff --git a/builtin/mv.c b/builtin/mv.c
index 19790ce..edd7b93 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2006 Johannes Schindelin
  */
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "pathspec.h"
@@ -489,7 +489,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 			if ((mode & SPARSE) &&
 			    path_in_sparse_checkout(dst, &the_index)) {
 				/* from out-of-cone to in-cone */
-				int dst_pos = cache_name_pos(dst, strlen(dst));
+				int dst_pos = index_name_pos(&the_index, dst,
+							     strlen(dst));
 				struct cache_entry *dst_ce = the_index.cache[dst_pos];
 
 				dst_ce->ce_flags &= ~CE_SKIP_WORKTREE;
@@ -500,7 +501,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 				   !(mode & SPARSE) &&
 				   !path_in_sparse_checkout(dst, &the_index)) {
 				/* from in-cone to out-of-cone */
-				int dst_pos = cache_name_pos(dst, strlen(dst));
+				int dst_pos = index_name_pos(&the_index, dst,
+							     strlen(dst));
 				struct cache_entry *dst_ce = the_index.cache[dst_pos];
 
 				/*
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 15535e9..97959bf 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -108,19 +108,11 @@ static int is_better_name(struct rev_name *name,
 	int name_distance = effective_distance(name->distance, name->generation);
 	int new_distance = effective_distance(distance, generation);
 
-	/*
-	 * When comparing names based on tags, prefer names
-	 * based on the older tag, even if it is farther away.
-	 */
+	/* If both are tags, we prefer the nearer one. */
 	if (from_tag && name->from_tag)
-		return (name->taggerdate > taggerdate ||
-			(name->taggerdate == taggerdate &&
-			 name_distance > new_distance));
+		return name_distance > new_distance;
 
-	/*
-	 * We know that at least one of them is a non-tag at this point.
-	 * favor a tag over a non-tag.
-	 */
+	/* Favor a tag over a non-tag. */
 	if (name->from_tag != from_tag)
 		return from_tag;
 
@@ -273,17 +265,6 @@ static int subpath_matches(const char *path, const char *filter)
 	return -1;
 }
 
-static const char *name_ref_abbrev(const char *refname, int shorten_unambiguous)
-{
-	if (shorten_unambiguous)
-		refname = shorten_unambiguous_ref(refname, 0);
-	else if (skip_prefix(refname, "refs/heads/", &refname))
-		; /* refname already advanced */
-	else
-		skip_prefix(refname, "refs/", &refname);
-	return refname;
-}
-
 struct name_ref_data {
 	int tags_only;
 	int name_only;
@@ -309,11 +290,19 @@ static void add_to_tip_table(const struct object_id *oid, const char *refname,
 			     int shorten_unambiguous, struct commit *commit,
 			     timestamp_t taggerdate, int from_tag, int deref)
 {
-	refname = name_ref_abbrev(refname, shorten_unambiguous);
+	char *short_refname = NULL;
+
+	if (shorten_unambiguous)
+		short_refname = shorten_unambiguous_ref(refname, 0);
+	else if (skip_prefix(refname, "refs/heads/", &refname))
+		; /* refname already advanced */
+	else
+		skip_prefix(refname, "refs/", &refname);
 
 	ALLOC_GROW(tip_table.table, tip_table.nr + 1, tip_table.alloc);
 	oidcpy(&tip_table.table[tip_table.nr].oid, oid);
-	tip_table.table[tip_table.nr].refname = xstrdup(refname);
+	tip_table.table[tip_table.nr].refname = short_refname ?
+		short_refname : xstrdup(refname);
 	tip_table.table[tip_table.nr].commit = commit;
 	tip_table.table[tip_table.nr].taggerdate = taggerdate;
 	tip_table.table[tip_table.nr].from_tag = from_tag;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 573d0b2..74a167a 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -929,8 +929,10 @@ static struct object_entry **compute_write_order(void)
 	 */
 	for_each_tag_ref(mark_tagged, NULL);
 
-	if (use_delta_islands)
+	if (use_delta_islands) {
 		max_layers = compute_pack_layers(&to_pack);
+		free_island_marks();
+	}
 
 	ALLOC_ARRAY(wo, to_pack.nr_objects);
 	wo_end = 0;
@@ -1318,7 +1320,7 @@ static int no_try_delta(const char *path)
 
 	if (!check)
 		check = attr_check_initl("delta", NULL);
-	git_check_attr(the_repository->index, path, check);
+	git_check_attr(the_repository->index, NULL, path, check);
 	if (ATTR_FALSE(check->items[0].value))
 		return 1;
 	return 0;
@@ -1708,17 +1710,14 @@ static void pbase_tree_put(struct pbase_tree_cache *cache)
 	free(cache);
 }
 
-static int name_cmp_len(const char *name)
+static size_t name_cmp_len(const char *name)
 {
-	int i;
-	for (i = 0; name[i] && name[i] != '\n' && name[i] != '/'; i++)
-		;
-	return i;
+	return strcspn(name, "\n/");
 }
 
 static void add_pbase_object(struct tree_desc *tree,
 			     const char *name,
-			     int cmplen,
+			     size_t cmplen,
 			     const char *fullname)
 {
 	struct name_entry entry;
@@ -1743,7 +1742,7 @@ static void add_pbase_object(struct tree_desc *tree,
 			struct tree_desc sub;
 			struct pbase_tree_cache *tree;
 			const char *down = name+cmplen+1;
-			int downlen = name_cmp_len(down);
+			size_t downlen = name_cmp_len(down);
 
 			tree = pbase_tree_get(&entry.oid);
 			if (!tree)
@@ -1795,7 +1794,7 @@ static int check_pbase_path(unsigned hash)
 static void add_preferred_base_object(const char *name)
 {
 	struct pbase_tree *it;
-	int cmplen;
+	size_t cmplen;
 	unsigned hash = pack_name_hash(name);
 
 	if (!num_preferred_base || check_pbase_path(hash))
@@ -4149,21 +4148,6 @@ static int option_parse_cruft_expiration(const struct option *opt,
 	return 0;
 }
 
-struct po_filter_data {
-	unsigned have_revs:1;
-	struct rev_info revs;
-};
-
-static struct list_objects_filter_options *po_filter_revs_init(void *value)
-{
-	struct po_filter_data *data = value;
-
-	repo_init_revisions(the_repository, &data->revs, NULL);
-	data->have_revs = 1;
-
-	return &data->revs.filter;
-}
-
 int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 {
 	int use_internal_rev_list = 0;
@@ -4174,7 +4158,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 	int rev_list_index = 0;
 	int stdin_packs = 0;
 	struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
-	struct po_filter_data pfd = { .have_revs = 0 };
+	struct list_objects_filter_options filter_options =
+		LIST_OBJECTS_FILTER_INIT;
 
 	struct option pack_objects_options[] = {
 		OPT_SET_INT('q', "quiet", &progress,
@@ -4265,7 +4250,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 			      &write_bitmap_index,
 			      N_("write a bitmap index if possible"),
 			      WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),
-		OPT_PARSE_LIST_OBJECTS_FILTER_INIT(&pfd, po_filter_revs_init),
+		OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
 		OPT_CALLBACK_F(0, "missing", NULL, N_("action"),
 		  N_("handling for missing objects"), PARSE_OPT_NONEG,
 		  option_parse_missing_action),
@@ -4385,7 +4370,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 	if (!rev_list_all || !rev_list_reflog || !rev_list_index)
 		unpack_unreachable_expiration = 0;
 
-	if (pfd.have_revs && pfd.revs.filter.choice) {
+	if (filter_options.choice) {
 		if (!pack_to_stdout)
 			die(_("cannot use --filter without --stdout"));
 		if (stdin_packs)
@@ -4472,13 +4457,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 		read_cruft_objects();
 	} else if (!use_internal_rev_list) {
 		read_object_list_from_stdin();
-	} else if (pfd.have_revs) {
-		get_object_list(&pfd.revs, rp.nr, rp.v);
-		release_revisions(&pfd.revs);
 	} else {
 		struct rev_info revs;
 
 		repo_init_revisions(the_repository, &revs, NULL);
+		list_objects_filter_copy(&revs.filter, &filter_options);
 		get_object_list(&revs, rp.nr, rp.v);
 		release_revisions(&revs);
 	}
@@ -4513,6 +4496,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 			   reuse_packfile_objects);
 
 cleanup:
+	list_objects_filter_release(&filter_options);
 	strvec_clear(&rp);
 
 	return 0;
diff --git a/builtin/push.c b/builtin/push.c
index 60ac801..8f7d326 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -63,16 +63,9 @@ static struct refspec rs = REFSPEC_INIT_PUSH;
 static struct string_list push_options_config = STRING_LIST_INIT_DUP;
 
 static void refspec_append_mapped(struct refspec *refspec, const char *ref,
-				  struct remote *remote, struct ref *local_refs)
+				  struct remote *remote, struct ref *matched)
 {
 	const char *branch_name;
-	struct ref *matched = NULL;
-
-	/* Does "ref" uniquely name our ref? */
-	if (count_refspec_match(ref, local_refs, &matched) != 1) {
-		refspec_append(refspec, ref);
-		return;
-	}
 
 	if (remote->push.nr) {
 		struct refspec_item query;
@@ -120,15 +113,28 @@ static void set_refspecs(const char **refs, int nr, const char *repo)
 				die(_("--delete only accepts plain target ref names"));
 			refspec_appendf(&rs, ":%s", ref);
 		} else if (!strchr(ref, ':')) {
-			if (!remote) {
-				/* lazily grab remote and local_refs */
-				remote = remote_get(repo);
+			struct ref *matched = NULL;
+
+			/* lazily grab local_refs */
+			if (!local_refs)
 				local_refs = get_local_heads();
+
+			/* Does "ref" uniquely name our ref? */
+			if (count_refspec_match(ref, local_refs, &matched) != 1) {
+				refspec_append(&rs, ref);
+			} else {
+				/* lazily grab remote */
+				if (!remote)
+					remote = remote_get(repo);
+				if (!remote)
+					BUG("must get a remote for repo '%s'", repo);
+
+				refspec_append_mapped(&rs, ref, remote, matched);
 			}
-			refspec_append_mapped(&rs, ref, remote, local_refs);
 		} else
 			refspec_append(&rs, ref);
 	}
+	free_refs(local_refs);
 }
 
 static int push_url_of_remote(struct remote *remote, const char ***url_p)
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index e2a74ef..aecfae1 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -47,7 +47,7 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
 
 	repo_diff_setup(the_repository, &diffopt);
 
-	options = parse_options_concat(range_diff_options, diffopt.parseopts);
+	options = add_diff_options(range_diff_options, &diffopt);
 	argc = parse_options(argc, argv, prefix, options,
 			     builtin_range_diff_usage, PARSE_OPT_KEEP_DASHDASH);
 
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index f702f9d..3ce7541 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
 	int prefix_set = 0;
 	struct lock_file lock_file = LOCK_INIT;
 	const struct option read_tree_options[] = {
+		OPT__SUPER_PREFIX(&opts.super_prefix),
 		OPT_CALLBACK_F(0, "index-output", NULL, N_("file"),
 		  N_("write resulting index to <file>"),
 		  PARSE_OPT_NONEG, index_output_cb),
diff --git a/builtin/rebase.c b/builtin/rebase.c
index b22768c..6635f10 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -113,7 +113,7 @@ struct rebase_options {
 	int autostash;
 	int committer_date_is_author_date;
 	int ignore_date;
-	char *cmd;
+	struct string_list exec;
 	int allow_empty_message;
 	int rebase_merges, rebase_cousins;
 	char *strategy, *strategy_opts;
@@ -122,6 +122,8 @@ struct rebase_options {
 	int reapply_cherry_picks;
 	int fork_point;
 	int update_refs;
+	int config_autosquash;
+	int config_update_refs;
 };
 
 #define REBASE_OPTIONS_INIT {			  	\
@@ -131,8 +133,15 @@ struct rebase_options {
 		.default_backend = "merge",	  	\
 		.flags = REBASE_NO_QUIET, 		\
 		.git_am_opts = STRVEC_INIT,		\
+		.exec = STRING_LIST_INIT_NODUP,		\
 		.git_format_patch_opt = STRBUF_INIT,	\
 		.fork_point = -1,			\
+		.reapply_cherry_picks = -1,             \
+		.allow_empty_message = 1,               \
+		.autosquash = -1,                       \
+		.config_autosquash = -1,                \
+		.update_refs = -1,                      \
+		.config_update_refs = -1,               \
 	}
 
 static struct replay_opts get_replay_opts(const struct rebase_options *opts)
@@ -243,38 +252,22 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,
 	return write_basic_state(opts, head_name, onto, orig_head);
 }
 
-static void split_exec_commands(const char *cmd, struct string_list *commands)
-{
-	if (cmd && *cmd) {
-		string_list_split(commands, cmd, '\n', -1);
-
-		/* rebase.c adds a new line to cmd after every command,
-		 * so here the last command is always empty */
-		string_list_remove_empty_items(commands, 0);
-	}
-}
-
 static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
 {
-	int ret;
+	int ret = -1;
 	char *revisions = NULL, *shortrevisions = NULL;
 	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;
 
 	if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head->object.oid,
 				&revisions, &shortrevisions))
-		return -1;
+		goto cleanup;
 
 	if (init_basic_state(&replay,
 			     opts->head_name ? opts->head_name : "detached HEAD",
-			     opts->onto, &opts->orig_head->object.oid)) {
-		free(revisions);
-		free(shortrevisions);
-
-		return -1;
-	}
+			     opts->onto, &opts->orig_head->object.oid))
+		goto cleanup;
 
 	if (!opts->upstream && opts->squash_onto)
 		write_file(path_squash_onto(), "%s\n",
@@ -297,14 +290,14 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
 						&todo_list))
 			BUG("unusable todo list");
 
-		split_exec_commands(opts->cmd, &commands);
 		ret = complete_action(the_repository, &replay, flags,
 			shortrevisions, opts->onto_name, opts->onto,
-			&opts->orig_head->object.oid, &commands,
+			&opts->orig_head->object.oid, &opts->exec,
 			opts->autosquash, opts->update_refs, &todo_list);
 	}
 
-	string_list_clear(&commands, 0);
+cleanup:
+	replay_opts_release(&replay);
 	free(revisions);
 	free(shortrevisions);
 	todo_list_release(&todo_list);
@@ -346,6 +339,7 @@ static int run_sequencer_rebase(struct rebase_options *opts)
 		struct replay_opts replay_opts = get_replay_opts(opts);
 
 		ret = sequencer_continue(the_repository, &replay_opts);
+		replay_opts_release(&replay_opts);
 		break;
 	}
 	case ACTION_EDIT_TODO:
@@ -561,6 +555,7 @@ static int finish_rebase(struct rebase_options *opts)
 
 		replay.action = REPLAY_INTERACTIVE_REBASE;
 		ret = sequencer_remove_state(&replay);
+		replay_opts_release(&replay);
 	} else {
 		strbuf_addstr(&dir, opts->state_dir);
 		if (remove_dir_recursively(&dir, 0))
@@ -789,7 +784,7 @@ static int rebase_config(const char *var, const char *value, void *data)
 	}
 
 	if (!strcmp(var, "rebase.autosquash")) {
-		opts->autosquash = git_config_bool(var, value);
+		opts->config_autosquash = git_config_bool(var, value);
 		return 0;
 	}
 
@@ -806,7 +801,7 @@ static int rebase_config(const char *var, const char *value, void *data)
 	}
 
 	if (!strcmp(var, "rebase.updaterefs")) {
-		opts->update_refs = git_config_bool(var, value);
+		opts->config_update_refs = git_config_bool(var, value);
 		return 0;
 	}
 
@@ -920,6 +915,9 @@ static int parse_opt_am(const struct option *opt, const char *arg, int unset)
 	BUG_ON_OPT_NEG(unset);
 	BUG_ON_OPT_ARG(arg);
 
+	if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_APPLY)
+	    die(_("apply options and merge options cannot be used together"));
+
 	opts->type = REBASE_APPLY;
 
 	return 0;
@@ -933,8 +931,10 @@ static int parse_opt_merge(const struct option *opt, const char *arg, int unset)
 	BUG_ON_OPT_NEG(unset);
 	BUG_ON_OPT_ARG(arg);
 
-	if (!is_merge(opts))
-		opts->type = REBASE_MERGE;
+	if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_MERGE)
+	    die(_("apply options and merge options cannot be used together"));
+
+	opts->type = REBASE_MERGE;
 
 	return 0;
 }
@@ -948,6 +948,9 @@ static int parse_opt_interactive(const struct option *opt, const char *arg,
 	BUG_ON_OPT_NEG(unset);
 	BUG_ON_OPT_ARG(arg);
 
+	if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_MERGE)
+	    die(_("apply options and merge options cannot be used together"));
+
 	opts->type = REBASE_MERGE;
 	opts->flags |= REBASE_INTERACTIVE_EXPLICIT;
 
@@ -1032,11 +1035,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	struct object_id branch_base;
 	int ignore_whitespace = 0;
 	const char *gpg_sign = NULL;
-	struct string_list exec = STRING_LIST_INIT_NODUP;
 	const char *rebase_merges = NULL;
 	struct string_list strategy_options = STRING_LIST_INIT_NODUP;
 	struct object_id squash_onto;
 	char *squash_onto_name = NULL;
+	char *keep_base_onto_name = NULL;
 	int reschedule_failed_exec = -1;
 	int allow_preemptive_ff = 1;
 	int preserve_merges_selected = 0;
@@ -1127,7 +1130,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			N_("GPG-sign commits"),
 			PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
 		OPT_AUTOSTASH(&options.autostash),
-		OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
+		OPT_STRING_LIST('x', "exec", &options.exec, N_("exec"),
 				N_("add exec lines after each commit of the "
 				   "editable list")),
 		OPT_BOOL_F(0, "allow-empty-message",
@@ -1164,8 +1167,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	prepare_repo_settings(the_repository);
 	the_repository->settings.command_requires_full_index = 0;
 
-	options.reapply_cherry_picks = -1;
-	options.allow_empty_message = 1;
 	git_config(rebase_config, &options);
 	/* options.gpg_sign_opt will be either "-S" or NULL */
 	gpg_sign = options.gpg_sign_opt ? "" : NULL;
@@ -1230,13 +1231,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		if (options.fork_point < 0)
 			options.fork_point = 0;
 	}
-	/*
-	 * --keep-base defaults to --reapply-cherry-picks to avoid losing
-	 * commits when using this option.
-	 */
-	if (options.reapply_cherry_picks < 0)
-		options.reapply_cherry_picks = keep_base;
-
 	if (options.root && options.fork_point > 0)
 		die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point");
 
@@ -1250,7 +1244,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (trace2_is_enabled()) {
 		if (is_merge(&options))
 			trace2_cmd_mode("interactive");
-		else if (exec.nr)
+		else if (options.exec.nr)
 			trace2_cmd_mode("interactive-exec");
 		else
 			trace2_cmd_mode(action_names[options.action]);
@@ -1322,6 +1316,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		if (reset_head(the_repository, &ropts) < 0)
 			die(_("could not move back to %s"),
 			    oid_to_hex(&options.orig_head->object.oid));
+		strbuf_release(&head_msg);
 		remove_branch_state(the_repository, 0);
 		ret = finish_rebase(&options);
 		goto cleanup;
@@ -1333,6 +1328,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 			replay.action = REPLAY_INTERACTIVE_REBASE;
 			ret = sequencer_remove_state(&replay);
+			replay_opts_release(&replay);
 		} else {
 			strbuf_reset(&buf);
 			strbuf_addstr(&buf, options.state_dir);
@@ -1377,8 +1373,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 	if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||
 	    (options.action != ACTION_NONE) ||
-	    (exec.nr > 0) ||
-	    options.autosquash) {
+	    (options.exec.nr > 0) ||
+	    (options.autosquash == -1 && options.config_autosquash == 1) ||
+	    options.autosquash == 1) {
 		allow_preemptive_ff = 0;
 	}
 	if (options.committer_date_is_author_date || options.ignore_date)
@@ -1401,8 +1398,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		}
 	}
 
-	for (i = 0; i < exec.nr; i++)
-		if (check_exec_cmd(exec.items[i].string))
+	for (i = 0; i < options.exec.nr; i++)
+		if (check_exec_cmd(options.exec.items[i].string))
 			exit(1);
 
 	if (!(options.flags & REBASE_NO_QUIET))
@@ -1411,27 +1408,34 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (options.empty != EMPTY_UNSPECIFIED)
 		imply_merge(&options, "--empty");
 
-	/*
-	 * --keep-base implements --reapply-cherry-picks by altering upstream so
-	 * it works with both backends.
-	 */
-	if (options.reapply_cherry_picks && !keep_base)
-		imply_merge(&options, "--reapply-cherry-picks");
+	if (options.reapply_cherry_picks < 0)
+		/*
+		 * We default to --no-reapply-cherry-picks unless
+		 * --keep-base is given; when --keep-base is given, we want
+		 * to default to --reapply-cherry-picks.
+		 */
+		options.reapply_cherry_picks = keep_base;
+	else if (!keep_base)
+		/*
+		 * The apply backend always searches for and drops cherry
+		 * picks.  This is often not wanted with --keep-base, so
+		 * --keep-base allows --reapply-cherry-picks to be
+		 * simulated by altering the upstream such that
+		 * cherry-picks cannot be detected and thus all commits are
+		 * reapplied.  Thus, --[no-]reapply-cherry-picks is
+		 * supported when --keep-base is specified, but not when
+		 * --keep-base is left out.
+		 */
+		imply_merge(&options, options.reapply_cherry_picks ?
+					  "--reapply-cherry-picks" :
+					  "--no-reapply-cherry-picks");
 
 	if (gpg_sign)
 		options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
 
-	if (exec.nr) {
-		int i;
-
+	if (options.exec.nr)
 		imply_merge(&options, "--exec");
 
-		strbuf_reset(&buf);
-		for (i = 0; i < exec.nr; i++)
-			strbuf_addf(&buf, "exec %s\n", exec.items[i].string);
-		options.cmd = xstrdup(buf.buf);
-	}
-
 	if (rebase_merges) {
 		if (!*rebase_merges)
 			; /* default mode; do nothing */
@@ -1504,15 +1508,29 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			if (strcmp(options.git_am_opts.v[i], "-q"))
 				break;
 
-		if (i >= 0) {
+		if (i >= 0 || options.type == REBASE_APPLY) {
 			if (is_merge(&options))
 				die(_("apply options and merge options "
 					  "cannot be used together"));
+			else if (options.autosquash == -1 && options.config_autosquash == 1)
+				die(_("apply options are incompatible with rebase.autosquash.  Consider adding --no-autosquash"));
+			else if (options.update_refs == -1 && options.config_update_refs == 1)
+				die(_("apply options are incompatible with rebase.updateRefs.  Consider adding --no-update-refs"));
 			else
 				options.type = REBASE_APPLY;
 		}
 	}
 
+	if (options.update_refs == 1)
+		imply_merge(&options, "--update-refs");
+	options.update_refs = (options.update_refs >= 0) ? options.update_refs :
+			     ((options.config_update_refs >= 0) ? options.config_update_refs : 0);
+
+	if (options.autosquash == 1)
+		imply_merge(&options, "--autosquash");
+	options.autosquash = (options.autosquash >= 0) ? options.autosquash :
+			     ((options.config_autosquash >= 0) ? options.config_autosquash : 0);
+
 	if (options.type == REBASE_UNSPECIFIED) {
 		if (!strcmp(options.default_backend, "merge"))
 			imply_merge(&options, "--merge");
@@ -1542,7 +1560,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (options.empty == EMPTY_UNSPECIFIED) {
 		if (options.flags & REBASE_INTERACTIVE_EXPLICIT)
 			options.empty = EMPTY_ASK;
-		else if (exec.nr > 0)
+		else if (options.exec.nr > 0)
 			options.empty = EMPTY_KEEP;
 		else
 			options.empty = EMPTY_DROP;
@@ -1658,7 +1676,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		strbuf_addstr(&buf, options.upstream_name);
 		strbuf_addstr(&buf, "...");
 		strbuf_addstr(&buf, branch_name);
-		options.onto_name = xstrdup(buf.buf);
+		options.onto_name = keep_base_onto_name = xstrdup(buf.buf);
 	} else if (!options.onto_name)
 		options.onto_name = options.upstream_name;
 	if (strstr(options.onto_name, "...")) {
@@ -1828,10 +1846,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	strbuf_release(&revisions);
 	free(options.reflog_action);
 	free(options.head_name);
+	strvec_clear(&options.git_am_opts);
 	free(options.gpg_sign_opt);
-	free(options.cmd);
+	string_list_clear(&options.exec, 0);
 	free(options.strategy);
+	free(options.strategy_opts);
 	strbuf_release(&options.git_format_patch_opt);
 	free(squash_onto_name);
+	free(keep_base_onto_name);
+	string_list_clear(&strategy_options, 0);
 	return !!ret;
 }
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index a90af30..cd5c7a2 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -2032,6 +2032,16 @@ static struct command **queue_command(struct command **tail,
 	return &cmd->next;
 }
 
+static void free_commands(struct command *commands)
+{
+	while (commands) {
+		struct command *next = commands->next;
+
+		free(commands);
+		commands = next;
+	}
+}
+
 static void queue_commands_from_cert(struct command **tail,
 				     struct strbuf *push_cert)
 {
@@ -2569,6 +2579,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
 		run_receive_hook(commands, "post-receive", 1,
 				 &push_options);
 		run_update_post_hook(commands);
+		free_commands(commands);
 		string_list_clear(&push_options, 0);
 		if (auto_gc) {
 			struct child_process proc = CHILD_PROCESS_INIT;
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index fd3538d..ee338bf 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -169,6 +169,8 @@ static int command_loop(const char *child)
 
 	while (1) {
 		size_t i;
+		const char *arg;
+
 		if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
 			if (ferror(stdin))
 				die("Command input error");
@@ -182,10 +184,10 @@ static int command_loop(const char *child)
 		if (!strcmp(buffer, "capabilities")) {
 			printf("*connect\n\n");
 			fflush(stdout);
-		} else if (!strncmp(buffer, "connect ", 8)) {
+		} else if (skip_prefix(buffer, "connect ", &arg)) {
 			printf("\n");
 			fflush(stdout);
-			return run_child(child, buffer + 8);
+			return run_child(child, arg);
 		} else {
 			fprintf(stderr, "Bad command");
 			return 1;
diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c
index 91dfe07..b2a3980 100644
--- a/builtin/remote-fd.c
+++ b/builtin/remote-fd.c
@@ -40,7 +40,7 @@ static void command_loop(int input_fd, int output_fd)
 		if (!strcmp(buffer, "capabilities")) {
 			printf("*connect\n\n");
 			fflush(stdout);
-		} else if (!strncmp(buffer, "connect ", 8)) {
+		} else if (starts_with(buffer, "connect ")) {
 			printf("\n");
 			fflush(stdout);
 			if (bidirectional_transfer_loop(input_fd,
diff --git a/builtin/repack.c b/builtin/repack.c
index 65eb1b8..f649379 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -948,7 +948,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 
 	ret = start_command(&cmd);
 	if (ret)
-		return ret;
+		goto cleanup;
 
 	if (geometry) {
 		FILE *in = xfdopen(cmd.in, "w");
@@ -973,10 +973,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 		item = string_list_append(&names, line.buf);
 		item->util = populate_pack_exts(item->string);
 	}
+	strbuf_release(&line);
 	fclose(out);
 	ret = finish_command(&cmd);
 	if (ret)
-		return ret;
+		goto cleanup;
 
 	if (!names.nr && !po_args.quiet)
 		printf_ln(_("Nothing new to pack."));
@@ -1006,7 +1007,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 				       &existing_nonkept_packs,
 				       &existing_kept_packs);
 		if (ret)
-			return ret;
+			goto cleanup;
 
 		if (delete_redundant && expire_to) {
 			/*
@@ -1038,7 +1039,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 					       &existing_nonkept_packs,
 					       &existing_kept_packs);
 			if (ret)
-				return ret;
+				goto cleanup;
 		}
 	}
 
@@ -1114,7 +1115,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 		string_list_clear(&include, 0);
 
 		if (ret)
-			return ret;
+			goto cleanup;
 	}
 
 	reprepare_packed_git(the_repository);
@@ -1171,11 +1172,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 		write_midx_file(get_object_directory(), NULL, NULL, flags);
 	}
 
+cleanup:
 	string_list_clear(&names, 1);
 	string_list_clear(&existing_nonkept_packs, 0);
 	string_list_clear(&existing_kept_packs, 0);
 	clear_pack_geometry(geometry);
-	strbuf_release(&line);
 
-	return 0;
+	return ret;
 }
diff --git a/builtin/reset.c b/builtin/reset.c
index d2e0185..0697fa8 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -26,6 +26,7 @@
 #include "submodule.h"
 #include "submodule-config.h"
 #include "dir.h"
+#include "add-interactive.h"
 
 #define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
 
@@ -390,7 +391,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 		if (reset_type != NONE)
 			die(_("options '%s' and '%s' cannot be used together"), "--patch", "--{hard,mixed,soft}");
 		trace2_cmd_mode("patch-interactive");
-		return run_add_interactive(rev, "--patch=reset", &pathspec);
+		update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, rev,
+				   &pathspec);
+		goto cleanup;
 	}
 
 	/* git reset tree [--] paths... can be used to
@@ -439,8 +442,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 				       LOCK_DIE_ON_ERROR);
 		if (reset_type == MIXED) {
 			int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
-			if (read_from_tree(&pathspec, &oid, intent_to_add))
-				return 1;
+			if (read_from_tree(&pathspec, &oid, intent_to_add)) {
+				update_ref_status = 1;
+				goto cleanup;
+			}
 			the_index.updated_skipworktree = 1;
 			if (!no_refresh && get_git_work_tree()) {
 				uint64_t t_begin, t_delta_in_ms;
@@ -486,5 +491,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 	if (!pathspec.nr)
 		remove_branch_state(the_repository, 0);
 
+	discard_index(&the_index);
+
+cleanup:
+	clear_pathspec(&pathspec);
 	return update_ref_status;
 }
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 1c344d7..e67999e 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -530,6 +530,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
 	strbuf_addstr(&parsed, " --");
 	sq_quote_argv(&parsed, argv);
 	puts(parsed.buf);
+	strbuf_release(&parsed);
 	return 0;
 }
 
diff --git a/builtin/revert.c b/builtin/revert.c
index 6a9b550..77d2035 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -221,6 +221,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 	opts->strategy = xstrdup_or_null(opts->strategy);
 	if (!opts->strategy && getenv("GIT_TEST_MERGE_ALGORITHM"))
 		opts->strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM"));
+	free(options);
 
 	if (cmd == 'q') {
 		int ret = sequencer_remove_state(opts);
@@ -247,9 +248,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
 	res = run_sequencer(argc, argv, &opts);
 	if (res < 0)
 		die(_("revert failed"));
-	if (opts.revs)
-		release_revisions(opts.revs);
-	free(opts.revs);
+	replay_opts_release(&opts);
 	return res;
 }
 
@@ -263,5 +262,6 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
 	res = run_sequencer(argc, argv, &opts);
 	if (res < 0)
 		die(_("cherry-pick failed"));
+	replay_opts_release(&opts);
 	return res;
 }
diff --git a/builtin/rm.c b/builtin/rm.c
index d4989d4..8844f90 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Linus Torvalds 2006
  */
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
 #include "advice.h"
 #include "config.h"
@@ -86,7 +86,7 @@ static void submodules_absorb_gitdir_if_needed(void)
 			continue;
 
 		if (!submodule_uses_gitfile(name))
-			absorb_git_dir_into_superproject(name);
+			absorb_git_dir_into_superproject(name, NULL);
 	}
 }
 
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index c013aba..358ac3e 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -956,5 +956,6 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 		if (shown_merge_point && --extra < 0)
 			break;
 	}
+	free(head);
 	return 0;
 }
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 58a2250..c373815 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -217,6 +217,7 @@ static int update_working_directory(struct pattern_list *pl)
 	o.head_idx = -1;
 	o.src_index = r->index;
 	o.dst_index = r->index;
+	index_state_init(&o.result, r);
 	o.skip_sparse_checkout = 0;
 	o.pl = pl;
 
diff --git a/builtin/stash.c b/builtin/stash.c
index 62e3671..3a4f9fd 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1,4 +1,4 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "parse-options.h"
@@ -18,6 +18,7 @@
 #include "diffcore.h"
 #include "exec-cmd.h"
 #include "reflog.h"
+#include "add-interactive.h"
 
 #define INCLUDE_ALL_FILES 2
 
@@ -528,7 +529,8 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
 					 NULL, NULL, NULL))
 		return -1;
 
-	if (write_cache_as_tree(&c_tree, 0, NULL))
+	if (write_index_as_tree(&c_tree, &the_index, get_index_file(), 0,
+				NULL))
 		return error(_("cannot apply a stash in the middle of a merge"));
 
 	if (index) {
@@ -552,7 +554,8 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
 
 			discard_index(&the_index);
 			repo_read_index(the_repository);
-			if (write_cache_as_tree(&index_tree, 0, NULL))
+			if (write_index_as_tree(&index_tree, &the_index,
+						get_index_file(), 0, NULL))
 				return error(_("could not save index tree"));
 
 			reset_head();
@@ -1137,7 +1140,7 @@ static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
 	int ret = 0;
 	struct strbuf untracked_msg = STRBUF_INIT;
 	struct child_process cp_upd_index = CHILD_PROCESS_INIT;
-	struct index_state istate = { NULL };
+	struct index_state istate = INDEX_STATE_INIT(the_repository);
 
 	cp_upd_index.git_cmd = 1;
 	strvec_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
@@ -1165,7 +1168,7 @@ static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
 	}
 
 done:
-	discard_index(&istate);
+	release_index(&istate);
 	strbuf_release(&untracked_msg);
 	remove_path(stash_index_path.buf);
 	return ret;
@@ -1176,7 +1179,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
 {
 	int ret = 0;
 	struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
-	struct index_state istate = { NULL };
+	struct index_state istate = INDEX_STATE_INIT(the_repository);
 
 	if (write_index_as_tree(&info->w_tree, &istate, the_repository->index_file,
 				0, NULL)) {
@@ -1199,7 +1202,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
 	}
 
 done:
-	discard_index(&istate);
+	release_index(&istate);
 	return ret;
 }
 
@@ -1209,7 +1212,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
 	int ret = 0;
 	struct child_process cp_read_tree = CHILD_PROCESS_INIT;
 	struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
-	struct index_state istate = { NULL };
+	struct index_state istate = INDEX_STATE_INIT(the_repository);
 	char *old_index_env = NULL, *old_repo_index_file;
 
 	remove_path(stash_index_path.buf);
@@ -1229,7 +1232,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
 	old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
 	setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
 
-	ret = run_add_interactive(NULL, "--patch=stash", ps);
+	ret = !!run_add_p(the_repository, ADD_P_STASH, NULL, ps);
 
 	the_repository->index_file = old_repo_index_file;
 	if (old_index_env && *old_index_env)
@@ -1260,7 +1263,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
 	}
 
 done:
-	discard_index(&istate);
+	release_index(&istate);
 	remove_path(stash_index_path.buf);
 	return ret;
 }
@@ -1271,7 +1274,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
 	struct rev_info rev;
 	struct child_process cp_upd_index = CHILD_PROCESS_INIT;
 	struct strbuf diff_output = STRBUF_INIT;
-	struct index_state istate = { NULL };
+	struct index_state istate = INDEX_STATE_INIT(the_repository);
 
 	init_revisions(&rev, NULL);
 	copy_pathspec(&rev.prune_data, ps);
@@ -1319,7 +1322,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
 	}
 
 done:
-	discard_index(&istate);
+	release_index(&istate);
 	release_revisions(&rev);
 	strbuf_release(&diff_output);
 	remove_path(stash_index_path.buf);
@@ -1377,7 +1380,8 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
 
 	strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf);
 	commit_list_insert(head_commit, &parents);
-	if (write_cache_as_tree(&info->i_tree, 0, NULL) ||
+	if (write_index_as_tree(&info->i_tree, &the_index, get_index_file(), 0,
+				NULL) ||
 	    commit_tree(commit_tree_label.buf, commit_tree_label.len,
 			&info->i_tree, parents, &info->i_commit, NULL, NULL)) {
 		if (!quiet)
@@ -1689,8 +1693,10 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
 	}
 
 done:
+	strbuf_release(&patch);
 	free_stash_info(&info);
 	strbuf_release(&stash_msg_buf);
+	strbuf_release(&untracked_files);
 	return ret;
 }
 
@@ -1725,6 +1731,7 @@ static int push_stash(int argc, const char **argv, const char *prefix,
 		OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
 		OPT_END()
 	};
+	int ret;
 
 	if (argc) {
 		force_assume = !strcmp(argv[0], "-p");
@@ -1764,8 +1771,10 @@ static int push_stash(int argc, const char **argv, const char *prefix,
 		die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
 	}
 
-	return do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
-			     include_untracked, only_staged);
+	ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
+			    include_untracked, only_staged);
+	clear_pathspec(&ps);
+	return ret;
 }
 
 static int push_stash_unassumed(int argc, const char **argv, const char *prefix)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 941afe1..74a2375 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
 }
 
 /* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *get_submodule_displaypath(const char *path, const char *prefix,
+				       const char *super_prefix)
 {
-	const char *super_prefix = get_super_prefix();
-
 	if (prefix && super_prefix) {
 		BUG("cannot have prefix '%s' and superprefix '%s'",
 		    prefix, super_prefix);
@@ -279,6 +278,7 @@ struct foreach_cb {
 	int argc;
 	const char **argv;
 	const char *prefix;
+	const char *super_prefix;
 	int quiet;
 	int recursive;
 };
@@ -297,7 +297,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 	if (validate_submodule_path(path) < 0)
 		exit(128);
 
-	displaypath = get_submodule_displaypath(path, info->prefix);
+	displaypath = get_submodule_displaypath(path, info->prefix,
+						info->super_prefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -367,10 +368,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_pushl(&cpr.args, "--super-prefix", NULL);
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
 			     NULL);
+		strvec_pushl(&cpr.args, "--super-prefix", NULL);
+		strvec_pushf(&cpr.args, "%s/", displaypath);
 
 		if (info->quiet)
 			strvec_push(&cpr.args, "--quiet");
@@ -394,6 +395,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
 	struct option module_foreach_options[] = {
+		OPT__SUPER_PREFIX(&info.super_prefix),
 		OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
 		OPT_BOOL(0, "recursive", &info.recursive,
 			 N_("recurse into nested submodules")),
@@ -438,11 +440,13 @@ static int starts_with_dot_dot_slash(const char *const path)
 
 struct init_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define INIT_CB_INIT { 0 }
 
 static void init_submodule(const char *path, const char *prefix,
+			   const char *super_prefix,
 			   unsigned int flags)
 {
 	const struct submodule *sub;
@@ -450,7 +454,7 @@ static void init_submodule(const char *path, const char *prefix,
 	const char *upd;
 	char *url = NULL, *displaypath;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -526,7 +530,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data
 {
 	struct init_cb *info = cb_data;
 
-	init_submodule(list_item->name, info->prefix, info->flags);
+	init_submodule(list_item->name, info->prefix, info->super_prefix,
+		       info->flags);
 }
 
 static int module_init(int argc, const char **argv, const char *prefix)
@@ -573,6 +578,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
 
 struct status_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define STATUS_CB_INIT { 0 }
@@ -611,7 +617,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,
 
 static void status_submodule(const char *path, const struct object_id *ce_oid,
 			     unsigned int ce_flags, const char *prefix,
-			     unsigned int flags)
+			     const char *super_prefix, unsigned int flags)
 {
 	char *displaypath;
 	struct strvec diff_files_args = STRVEC_INIT;
@@ -630,7 +636,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		die(_("no submodule mapping found in .gitmodules for path '%s'"),
 		      path);
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
 
 	if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
 		print_status(flags, 'U', path, null_oid(), displaypath);
@@ -688,10 +694,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_push(&cpr.args, "--super-prefix");
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "status",
 			     "--recursive", NULL);
+		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushf(&cpr.args, "%s/", displaypath);
 
 		if (flags & OPT_CACHED)
 			strvec_push(&cpr.args, "--cached");
@@ -715,7 +721,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,
 	struct status_cb *info = cb_data;
 
 	status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
-			 info->prefix, info->flags);
+			 info->prefix, info->super_prefix, info->flags);
 }
 
 static int module_status(int argc, const char **argv, const char *prefix)
@@ -725,6 +731,7 @@ static int module_status(int argc, const char **argv, const char *prefix)
 	struct module_list list = MODULE_LIST_INIT;
 	int quiet = 0;
 	struct option module_status_options[] = {
+		OPT__SUPER_PREFIX(&info.super_prefix),
 		OPT__QUIET(&quiet, N_("suppress submodule status output")),
 		OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
 		OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
@@ -793,6 +800,7 @@ struct summary_cb {
 	int argc;
 	const char **argv;
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int cached: 1;
 	unsigned int for_status: 1;
 	unsigned int files: 1;
@@ -954,7 +962,8 @@ static void generate_submodule_summary(struct summary_cb *info,
 		dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
 	}
 
-	displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
+	displaypath = get_submodule_displaypath(p->sm_path, info->prefix,
+						info->super_prefix);
 
 	if (!missing_src && !missing_dst) {
 		struct child_process cp_rev_list = CHILD_PROCESS_INIT;
@@ -1209,12 +1218,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)
 
 struct sync_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define SYNC_CB_INIT { 0 }
 
 static void sync_submodule(const char *path, const char *prefix,
-			   unsigned int flags)
+			   const char *super_prefix, unsigned int flags)
 {
 	const struct submodule *sub;
 	char *remote_key = NULL;
@@ -1248,7 +1258,7 @@ static void sync_submodule(const char *path, const char *prefix,
 		super_config_url = xstrdup("");
 	}
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
 
 	if (!(flags & OPT_QUIET))
 		printf(_("Synchronizing submodule url for '%s'\n"),
@@ -1285,10 +1295,11 @@ static void sync_submodule(const char *path, const char *prefix,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_push(&cpr.args, "--super-prefix");
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "sync",
 			     "--recursive", NULL);
+		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushf(&cpr.args, "%s/", displaypath);
+
 
 		if (flags & OPT_QUIET)
 			strvec_push(&cpr.args, "--quiet");
@@ -1311,7 +1322,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data
 {
 	struct sync_cb *info = cb_data;
 
-	sync_submodule(list_item->name, info->prefix, info->flags);
+	sync_submodule(list_item->name, info->prefix, info->super_prefix,
+		       info->flags);
 }
 
 static int module_sync(int argc, const char **argv, const char *prefix)
@@ -1322,6 +1334,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)
 	int quiet = 0;
 	int recursive = 0;
 	struct option module_sync_options[] = {
+		OPT__SUPER_PREFIX(&info.super_prefix),
 		OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
 		OPT_BOOL(0, "recursive", &recursive,
 			N_("recurse into nested submodules")),
@@ -1377,7 +1390,7 @@ static void deinit_submodule(const char *path, const char *prefix,
 	if (!sub || !sub->name)
 		goto cleanup;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath(path, prefix, NULL);
 
 	/* remove the submodule work tree (unless the user already did it) */
 	if (is_directory(path)) {
@@ -1391,7 +1404,7 @@ static void deinit_submodule(const char *path, const char *prefix,
 					  ".git file by using absorbgitdirs."),
 					displaypath);
 
-			absorb_git_dir_into_superproject(path);
+			absorb_git_dir_into_superproject(path, NULL);
 
 		}
 
@@ -1950,6 +1963,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)
 
 struct update_data {
 	const char *prefix;
+	const char *super_prefix;
 	char *displaypath;
 	enum submodule_update_type update_default;
 	struct object_id suboid;
@@ -2025,7 +2039,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
 	enum submodule_update_type update_type;
 	char *key;
 	const struct update_data *ud = suc->update_data;
-	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix);
+	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix,
+						      ud->super_prefix);
 	struct strbuf sb = STRBUF_INIT;
 	int needs_cloning = 0;
 	int need_free_url = 0;
@@ -2505,11 +2520,11 @@ static void update_data_to_args(const struct update_data *update_data,
 {
 	enum submodule_update_type update_type = update_data->update_default;
 
+	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
 	if (update_data->displaypath) {
 		strvec_push(args, "--super-prefix");
 		strvec_pushf(args, "%s/", update_data->displaypath);
 	}
-	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
 	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
 	if (update_data->quiet)
 		strvec_push(args, "--quiet");
@@ -2687,7 +2702,8 @@ static int update_submodules(struct update_data *update_data)
 			goto fail;
 
 		update_data->displaypath = get_submodule_displaypath(
-			update_data->sm_path, update_data->prefix);
+			update_data->sm_path, update_data->prefix,
+			update_data->super_prefix);
 		code = update_submodule(update_data);
 		FREE_AND_NULL(update_data->displaypath);
 fail:
@@ -2713,6 +2729,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 		LIST_OBJECTS_FILTER_INIT;
 	int ret;
 	struct option module_update_options[] = {
+		OPT__SUPER_PREFIX(&opt.super_prefix),
 		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
 		OPT_BOOL(0, "init", &opt.init,
 			 N_("initialize uninitialized submodules before update")),
@@ -2809,6 +2826,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 			module_list_active(&list);
 
 		info.prefix = opt.prefix;
+		info.super_prefix = opt.super_prefix;
 		if (opt.quiet)
 			info.flags |= OPT_QUIET;
 
@@ -2907,7 +2925,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 	int i;
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
+	const char *super_prefix = NULL;
 	struct option embed_gitdir_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT_END()
 	};
 	const char *const git_submodule_helper_usage[] = {
@@ -2923,7 +2943,8 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 
 	for (i = 0; i < list.nr; i++)
-		absorb_git_dir_into_superproject(list.entries[i]->name);
+		absorb_git_dir_into_superproject(list.entries[i]->name,
+						 super_prefix);
 
 	ret = 0;
 cleanup:
@@ -2955,7 +2976,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
 	config_name = xstrfmt("submodule.%s.url", path);
 
 	config_set_in_gitmodules_file_gently(config_name, newurl);
-	sync_submodule(path, prefix, quiet ? OPT_QUIET : 0);
+	sync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);
 
 	free(config_name);
 
@@ -3277,9 +3298,8 @@ static void die_on_index_match(const char *path, int force)
 		ensure_full_index(&the_index);
 
 		/*
-		 * Since there is only one pathspec, we just need
-		 * need to check ps_matched[0] to know if a cache
-		 * entry matched.
+		 * Since there is only one pathspec, we just need to
+		 * check ps_matched[0] to know if a cache entry matched.
 		 */
 		for (i = 0; i < the_index.cache_nr; i++) {
 			ce_path_match(&the_index, the_index.cache[i], &ps,
@@ -3435,8 +3455,6 @@ static int module_add(int argc, const char **argv, const char *prefix)
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 {
-	const char *cmd = argv[0];
-	const char *subcmd;
 	parse_opt_subcommand_fn *fn = NULL;
 	const char *const usage[] = {
 		N_("git submodule--helper <command>"),
@@ -3460,18 +3478,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 	argc = parse_options(argc, argv, prefix, options, usage, 0);
-	subcmd = argv[0];
-
-	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
-	    strcmp(subcmd, "sync") && strcmp(subcmd, "absorbgitdirs") &&
-	    get_super_prefix())
-		/*
-		 * xstrfmt() rather than "%s %s" to keep the translated
-		 * string identical to git.c's.
-		 */
-		die(_("%s doesn't support --super-prefix"),
-		    xstrfmt("'%s %s'", cmd, subcmd));
 
 	return fn(argc, argv, prefix);
 }
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 9e8119d..88de32b 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -19,6 +19,7 @@ static char *create_temp_file(struct object_id *oid)
 	if (write_in_full(fd, buf, size) < 0)
 		die_errno("unable to write temp-file");
 	close(fd);
+	free(buf);
 	return path;
 }
 
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 82d5902..bf38885 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
 #include "cache.h"
 #include "bulk-checkin.h"
 #include "config.h"
@@ -381,7 +381,7 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
 	if (has_symlink_leading_path(path, len))
 		return error("'%s' is beyond a symbolic link", path);
 
-	pos = cache_name_pos(path, len);
+	pos = index_name_pos(&the_index, path, len);
 	ce = pos < 0 ? NULL : the_index.cache[pos];
 	if (ce && ce_skip_worktree(ce)) {
 		/*
diff --git a/builtin/var.c b/builtin/var.c
index 491db27..a80c1df 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -11,12 +11,12 @@ static const char var_usage[] = "git var (-l | <variable>)";
 
 static const char *editor(int flag)
 {
-	const char *pgm = git_editor();
+	return git_editor();
+}
 
-	if (!pgm && flag & IDENT_STRICT)
-		die("Terminal is dumb, but EDITOR unset");
-
-	return pgm;
+static const char *sequence_editor(int flag)
+{
+	return git_sequence_editor();
 }
 
 static const char *pager(int flag)
@@ -41,6 +41,7 @@ static struct git_var git_vars[] = {
 	{ "GIT_COMMITTER_IDENT", git_committer_info },
 	{ "GIT_AUTHOR_IDENT",   git_author_info },
 	{ "GIT_EDITOR", editor },
+	{ "GIT_SEQUENCE_EDITOR", sequence_editor },
 	{ "GIT_PAGER", pager },
 	{ "GIT_DEFAULT_BRANCH", default_branch },
 	{ "", NULL },
@@ -56,18 +57,15 @@ static void list_vars(void)
 			printf("%s=%s\n", ptr->name, val);
 }
 
-static const char *read_var(const char *var)
+static const struct git_var *get_git_var(const char *var)
 {
 	struct git_var *ptr;
-	const char *val;
-	val = NULL;
 	for (ptr = git_vars; ptr->read; ptr++) {
 		if (strcmp(var, ptr->name) == 0) {
-			val = ptr->read(IDENT_STRICT);
-			break;
+			return ptr;
 		}
 	}
-	return val;
+	return NULL;
 }
 
 static int show_config(const char *var, const char *value, void *cb)
@@ -81,7 +79,9 @@ static int show_config(const char *var, const char *value, void *cb)
 
 int cmd_var(int argc, const char **argv, const char *prefix)
 {
-	const char *val = NULL;
+	const struct git_var *git_var;
+	const char *val;
+
 	if (argc != 2)
 		usage(var_usage);
 
@@ -91,10 +91,15 @@ int cmd_var(int argc, const char **argv, const char *prefix)
 		return 0;
 	}
 	git_config(git_default_config, NULL);
-	val = read_var(argv[1]);
-	if (!val)
+
+	git_var = get_git_var(argv[1]);
+	if (!git_var)
 		usage(var_usage);
 
+	val = git_var->read(IDENT_STRICT);
+	if (!val)
+		return 1;
+
 	printf("%s\n", val);
 
 	return 0;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 4a24d53..254283a 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -173,7 +173,7 @@ static void prune_worktrees(void)
 {
 	struct strbuf reason = STRBUF_INIT;
 	struct strbuf main_path = STRBUF_INIT;
-	struct string_list kept = STRING_LIST_INIT_NODUP;
+	struct string_list kept = STRING_LIST_INIT_DUP;
 	DIR *dir = opendir(git_path("worktrees"));
 	struct dirent *d;
 	if (!dir)
@@ -184,14 +184,14 @@ static void prune_worktrees(void)
 		if (should_prune_worktree(d->d_name, &reason, &path, expire))
 			prune_worktree(d->d_name, reason.buf);
 		else if (path)
-			string_list_append(&kept, path)->util = xstrdup(d->d_name);
+			string_list_append_nodup(&kept, path)->util = xstrdup(d->d_name);
 	}
 	closedir(dir);
 
 	strbuf_add_absolute_path(&main_path, get_git_common_dir());
 	/* massage main worktree absolute path to match 'gitdir' content */
 	strbuf_strip_suffix(&main_path, "/.");
-	string_list_append(&kept, strbuf_detach(&main_path, NULL));
+	string_list_append_nodup(&kept, strbuf_detach(&main_path, NULL));
 	prune_dups(&kept);
 	string_list_clear(&kept, 1);
 
@@ -629,6 +629,7 @@ static int add(int ac, const char **av, const char *prefix)
 			 N_("try to match the new branch name with a remote-tracking branch")),
 		OPT_END()
 	};
+	int ret;
 
 	memset(&opts, 0, sizeof(opts));
 	opts.checkout = 1;
@@ -705,9 +706,9 @@ static int add(int ac, const char **av, const char *prefix)
 		die(_("--[no-]track can only be used if a new branch is created"));
 	}
 
-	UNLEAK(path);
-	UNLEAK(opts);
-	return add_worktree(path, branch, &opts);
+	ret = add_worktree(path, branch, &opts);
+	free(path);
+	return ret;
 }
 
 static void show_worktree_porcelain(struct worktree *wt, int line_terminator)
@@ -922,7 +923,7 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
 
 static void validate_no_submodules(const struct worktree *wt)
 {
-	struct index_state istate = { NULL };
+	struct index_state istate = INDEX_STATE_INIT(the_repository);
 	struct strbuf path = STRBUF_INIT;
 	int i, found_submodules = 0;
 
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index 45d6170..0780103 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
 #include "cache.h"
 #include "config.h"
@@ -38,7 +38,8 @@ int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix)
 	argc = parse_options(argc, argv, cmd_prefix, write_tree_options,
 			     write_tree_usage, 0);
 
-	ret = write_cache_as_tree(&oid, flags, tree_prefix);
+	ret = write_index_as_tree(&oid, &the_index, get_index_file(), flags,
+				  tree_prefix);
 	switch (ret) {
 	case 0:
 		printf("%s\n", oid_to_hex(&oid));
diff --git a/bundle-uri.c b/bundle-uri.c
index 79a914f..8a3c39c 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -7,6 +7,15 @@
 #include "hashmap.h"
 #include "pkt-line.h"
 #include "config.h"
+#include "remote.h"
+
+static struct {
+	enum bundle_list_heuristic heuristic;
+	const char *name;
+} heuristics[BUNDLE_HEURISTIC__COUNT] = {
+	{ BUNDLE_HEURISTIC_NONE, ""},
+	{ BUNDLE_HEURISTIC_CREATIONTOKEN, "creationToken" },
+};
 
 static int compare_bundles(const void *hashmap_cmp_fn_data,
 			   const struct hashmap_entry *he1,
@@ -49,6 +58,7 @@ void clear_bundle_list(struct bundle_list *list)
 
 	for_all_bundles_in_list(list, clear_remote_bundle_info, NULL);
 	hashmap_clear_and_free(&list->bundles, struct remote_bundle_info, ent);
+	free(list->baseURI);
 }
 
 int for_all_bundles_in_list(struct bundle_list *list,
@@ -73,6 +83,9 @@ static int summarize_bundle(struct remote_bundle_info *info, void *data)
 	FILE *fp = data;
 	fprintf(fp, "[bundle \"%s\"]\n", info->id);
 	fprintf(fp, "\turi = %s\n", info->uri);
+
+	if (info->creationToken)
+		fprintf(fp, "\tcreationToken = %"PRIu64"\n", info->creationToken);
 	return 0;
 }
 
@@ -98,6 +111,17 @@ void print_bundle_list(FILE *fp, struct bundle_list *list)
 	fprintf(fp, "\tversion = %d\n", list->version);
 	fprintf(fp, "\tmode = %s\n", mode);
 
+	if (list->heuristic) {
+		int i;
+		for (i = 0; i < BUNDLE_HEURISTIC__COUNT; i++) {
+			if (heuristics[i].heuristic == list->heuristic) {
+				printf("\theuristic = %s\n",
+				       heuristics[list->heuristic].name);
+				break;
+			}
+		}
+	}
+
 	for_all_bundles_in_list(list, summarize_bundle, fp);
 }
 
@@ -140,6 +164,21 @@ static int bundle_list_update(const char *key, const char *value,
 			return 0;
 		}
 
+		if (!strcmp(subkey, "heuristic")) {
+			int i;
+			for (i = 0; i < BUNDLE_HEURISTIC__COUNT; i++) {
+				if (heuristics[i].heuristic &&
+				    heuristics[i].name &&
+				    !strcmp(value, heuristics[i].name)) {
+					list->heuristic = heuristics[i].heuristic;
+					return 0;
+				}
+			}
+
+			/* Ignore unknown heuristics. */
+			return 0;
+		}
+
 		/* Ignore other unknown global keys. */
 		return 0;
 	}
@@ -163,7 +202,14 @@ static int bundle_list_update(const char *key, const char *value,
 	if (!strcmp(subkey, "uri")) {
 		if (bundle->uri)
 			return -1;
-		bundle->uri = xstrdup(value);
+		bundle->uri = relative_url(list->baseURI, value, NULL);
+		return 0;
+	}
+
+	if (!strcmp(subkey, "creationtoken")) {
+		if (sscanf(value, "%"PRIu64, &bundle->creationToken) != 1)
+			warning(_("could not parse bundle list key %s with value '%s'"),
+				"creationToken", value);
 		return 0;
 	}
 
@@ -190,6 +236,18 @@ int bundle_uri_parse_config_format(const char *uri,
 		.error_action = CONFIG_ERROR_ERROR,
 	};
 
+	if (!list->baseURI) {
+		struct strbuf baseURI = STRBUF_INIT;
+		strbuf_addstr(&baseURI, uri);
+
+		/*
+		 * If the URI does not end with a trailing slash, then
+		 * remove the filename portion of the path. This is
+		 * important for relative URIs.
+		 */
+		strbuf_strip_file_from_path(&baseURI);
+		list->baseURI = strbuf_detach(&baseURI, NULL);
+	}
 	result = git_config_from_file_with_options(config_to_bundle_list,
 						   filename, list,
 						   &opts);
@@ -389,6 +447,183 @@ static int download_bundle_to_file(struct remote_bundle_info *bundle, void *data
 	return 0;
 }
 
+struct bundles_for_sorting {
+	struct remote_bundle_info **items;
+	size_t alloc;
+	size_t nr;
+};
+
+static int append_bundle(struct remote_bundle_info *bundle, void *data)
+{
+	struct bundles_for_sorting *list = data;
+	list->items[list->nr++] = bundle;
+	return 0;
+}
+
+/**
+ * For use in QSORT() to get a list sorted by creationToken
+ * in decreasing order.
+ */
+static int compare_creation_token_decreasing(const void *va, const void *vb)
+{
+	const struct remote_bundle_info * const *a = va;
+	const struct remote_bundle_info * const *b = vb;
+
+	if ((*a)->creationToken > (*b)->creationToken)
+		return -1;
+	if ((*a)->creationToken < (*b)->creationToken)
+		return 1;
+	return 0;
+}
+
+static int fetch_bundles_by_token(struct repository *r,
+				  struct bundle_list *list)
+{
+	int cur;
+	int move_direction = 0;
+	const char *creationTokenStr;
+	uint64_t maxCreationToken = 0, newMaxCreationToken = 0;
+	struct bundle_list_context ctx = {
+		.r = r,
+		.list = list,
+		.mode = list->mode,
+	};
+	struct bundles_for_sorting bundles = {
+		.alloc = hashmap_get_size(&list->bundles),
+	};
+
+	ALLOC_ARRAY(bundles.items, bundles.alloc);
+
+	for_all_bundles_in_list(list, append_bundle, &bundles);
+
+	if (!bundles.nr) {
+		free(bundles.items);
+		return 0;
+	}
+
+	QSORT(bundles.items, bundles.nr, compare_creation_token_decreasing);
+
+	/*
+	 * If fetch.bundleCreationToken exists, parses to a uint64t, and
+	 * is not strictly smaller than the maximum creation token in the
+	 * bundle list, then do not download any bundles.
+	 */
+	if (!repo_config_get_value(r,
+				   "fetch.bundlecreationtoken",
+				   &creationTokenStr) &&
+	    sscanf(creationTokenStr, "%"PRIu64, &maxCreationToken) == 1 &&
+	    bundles.items[0]->creationToken <= maxCreationToken) {
+		free(bundles.items);
+		return 0;
+	}
+
+	/*
+	 * Attempt to download and unbundle the minimum number of bundles by
+	 * creationToken in decreasing order. If we fail to unbundle (after
+	 * a successful download) then move to the next non-downloaded bundle
+	 * and attempt downloading. Once we succeed in applying a bundle,
+	 * move to the previous unapplied bundle and attempt to unbundle it
+	 * again.
+	 *
+	 * In the case of a fresh clone, we will likely download all of the
+	 * bundles before successfully unbundling the oldest one, then the
+	 * rest of the bundles unbundle successfully in increasing order
+	 * of creationToken.
+	 *
+	 * If there are existing objects, then this process may terminate
+	 * early when all required commits from "new" bundles exist in the
+	 * repo's object store.
+	 */
+	cur = 0;
+	while (cur >= 0 && cur < bundles.nr) {
+		struct remote_bundle_info *bundle = bundles.items[cur];
+
+		/*
+		 * If we need to dig into bundles below the previous
+		 * creation token value, then likely we are in an erroneous
+		 * state due to missing or invalid bundles. Halt the process
+		 * instead of continuing to download extra data.
+		 */
+		if (bundle->creationToken <= maxCreationToken)
+			break;
+
+		if (!bundle->file) {
+			/*
+			 * Not downloaded yet. Try downloading.
+			 *
+			 * Note that bundle->file is non-NULL if a download
+			 * was attempted, even if it failed to download.
+			 */
+			if (fetch_bundle_uri_internal(ctx.r, bundle, ctx.depth + 1, ctx.list)) {
+				/* Mark as unbundled so we do not retry. */
+				bundle->unbundled = 1;
+
+				/* Try looking deeper in the list. */
+				move_direction = 1;
+				goto move;
+			}
+
+			/* We expect bundles when using creationTokens. */
+			if (!is_bundle(bundle->file, 1)) {
+				warning(_("file downloaded from '%s' is not a bundle"),
+					bundle->uri);
+				break;
+			}
+		}
+
+		if (bundle->file && !bundle->unbundled) {
+			/*
+			 * This was downloaded, but not successfully
+			 * unbundled. Try unbundling again.
+			 */
+			if (unbundle_from_file(ctx.r, bundle->file)) {
+				/* Try looking deeper in the list. */
+				move_direction = 1;
+			} else {
+				/*
+				 * Succeeded in unbundle. Retry bundles
+				 * that previously failed to unbundle.
+				 */
+				move_direction = -1;
+				bundle->unbundled = 1;
+
+				if (bundle->creationToken > newMaxCreationToken)
+					newMaxCreationToken = bundle->creationToken;
+			}
+		}
+
+		/*
+		 * Else case: downloaded and unbundled successfully.
+		 * Skip this by moving in the same direction as the
+		 * previous step.
+		 */
+
+move:
+		/* Move in the specified direction and repeat. */
+		cur += move_direction;
+	}
+
+	/*
+	 * We succeed if the loop terminates because 'cur' drops below
+	 * zero. The other case is that we terminate because 'cur'
+	 * reaches the end of the list, so we have a failure no matter
+	 * which bundles we apply from the list.
+	 */
+	if (cur < 0) {
+		struct strbuf value = STRBUF_INIT;
+		strbuf_addf(&value, "%"PRIu64"", newMaxCreationToken);
+		if (repo_config_set_multivar_gently(ctx.r,
+						    "fetch.bundleCreationToken",
+						    value.buf, NULL, 0))
+			warning(_("failed to store maximum creation token"));
+
+		strbuf_release(&value);
+	}
+
+	free(bundles.items);
+	return cur >= 0;
+}
+
 static int download_bundle_list(struct repository *r,
 				struct bundle_list *local_list,
 				struct bundle_list *global_list,
@@ -426,7 +661,15 @@ static int fetch_bundle_list_in_config_format(struct repository *r,
 		goto cleanup;
 	}
 
-	if ((result = download_bundle_list(r, &list_from_bundle,
+	/*
+	 * If this list uses the creationToken heuristic, then the URIs
+	 * it advertises are expected to be bundles, not nested lists.
+	 * We can drop 'global_list' and 'depth'.
+	 */
+	if (list_from_bundle.heuristic == BUNDLE_HEURISTIC_CREATIONTOKEN) {
+		result = fetch_bundles_by_token(r, &list_from_bundle);
+		global_list->heuristic = BUNDLE_HEURISTIC_CREATIONTOKEN;
+	} else if ((result = download_bundle_list(r, &list_from_bundle,
 					   global_list, depth)))
 		goto cleanup;
 
@@ -537,7 +780,8 @@ static int unlink_bundle(struct remote_bundle_info *info, void *data)
 	return 0;
 }
 
-int fetch_bundle_uri(struct repository *r, const char *uri)
+int fetch_bundle_uri(struct repository *r, const char *uri,
+		     int *has_heuristic)
 {
 	int result;
 	struct bundle_list list;
@@ -557,12 +801,96 @@ int fetch_bundle_uri(struct repository *r, const char *uri)
 	result = unbundle_all_bundles(r, &list);
 
 cleanup:
+	if (has_heuristic)
+		*has_heuristic = (list.heuristic != BUNDLE_HEURISTIC_NONE);
 	for_all_bundles_in_list(&list, unlink_bundle, NULL);
 	clear_bundle_list(&list);
 	clear_remote_bundle_info(&bundle, NULL);
 	return result;
 }
 
+int fetch_bundle_list(struct repository *r, struct bundle_list *list)
+{
+	int result;
+	struct bundle_list global_list;
+
+	/*
+	 * If the creationToken heuristic is used, then the URIs
+	 * advertised by 'list' are not nested lists and instead
+	 * direct bundles. We do not need to use global_list.
+	 */
+	if (list->heuristic == BUNDLE_HEURISTIC_CREATIONTOKEN)
+		return fetch_bundles_by_token(r, list);
+
+	init_bundle_list(&global_list);
+
+	/* If a bundle is added to this global list, then it is required. */
+	global_list.mode = BUNDLE_MODE_ALL;
+
+	if ((result = download_bundle_list(r, list, &global_list, 0)))
+		goto cleanup;
+
+	if (list->heuristic == BUNDLE_HEURISTIC_CREATIONTOKEN)
+		result = fetch_bundles_by_token(r, list);
+	else
+		result = unbundle_all_bundles(r, &global_list);
+
+cleanup:
+	for_all_bundles_in_list(&global_list, unlink_bundle, NULL);
+	clear_bundle_list(&global_list);
+	return result;
+}
+
+/**
+ * API for serve.c.
+ */
+
+int bundle_uri_advertise(struct repository *r, struct strbuf *value UNUSED)
+{
+	static int advertise_bundle_uri = -1;
+
+	if (advertise_bundle_uri != -1)
+		goto cached;
+
+	advertise_bundle_uri = 0;
+	repo_config_get_maybe_bool(r, "uploadpack.advertisebundleuris", &advertise_bundle_uri);
+
+cached:
+	return advertise_bundle_uri;
+}
+
+static int config_to_packet_line(const char *key, const char *value, void *data)
+{
+	struct packet_reader *writer = data;
+
+	if (starts_with(key, "bundle."))
+		packet_write_fmt(writer->fd, "%s=%s", key, value);
+
+	return 0;
+}
+
+int bundle_uri_command(struct repository *r,
+		       struct packet_reader *request)
+{
+	struct packet_writer writer;
+	packet_writer_init(&writer, 1);
+
+	while (packet_reader_read(request) == PACKET_READ_NORMAL)
+		die(_("bundle-uri: unexpected argument: '%s'"), request->line);
+	if (request->status != PACKET_READ_FLUSH)
+		die(_("bundle-uri: expected flush after arguments"));
+
+	/*
+	 * Read all "bundle.*" config lines to the client as key=value
+	 * packet lines.
+	 */
+	git_config(config_to_packet_line, &writer);
+
+	packet_writer_flush(&writer);
+
+	return 0;
+}
+
 /**
  * General API for {transport,connect}.c etc.
  */
diff --git a/bundle-uri.h b/bundle-uri.h
index 4dbc269..6dbc780 100644
--- a/bundle-uri.h
+++ b/bundle-uri.h
@@ -4,6 +4,7 @@
 #include "hashmap.h"
 #include "strbuf.h"
 
+struct packet_reader;
 struct repository;
 struct string_list;
 
@@ -41,6 +42,12 @@ struct remote_bundle_info {
 	 * this boolean is true.
 	 */
 	unsigned unbundled:1;
+
+	/**
+	 * If the bundle is part of a list with the creationToken
+	 * heuristic, then we use this member for sorting the bundles.
+	 */
+	uint64_t creationToken;
 };
 
 #define REMOTE_BUNDLE_INFO_INIT { 0 }
@@ -51,6 +58,14 @@ enum bundle_list_mode {
 	BUNDLE_MODE_ANY
 };
 
+enum bundle_list_heuristic {
+	BUNDLE_HEURISTIC_NONE = 0,
+	BUNDLE_HEURISTIC_CREATIONTOKEN,
+
+	/* Must be last. */
+	BUNDLE_HEURISTIC__COUNT
+};
+
 /**
  * A bundle_list contains an unordered set of remote_bundle_info structs,
  * as well as information about the bundle listing, such as version and
@@ -60,6 +75,26 @@ struct bundle_list {
 	int version;
 	enum bundle_list_mode mode;
 	struct hashmap bundles;
+
+	/**
+	 * The baseURI of a bundle_list is the URI that provided the list.
+	 *
+	 * In the case of the 'bundle-uri' protocol v2 command, the base
+	 * URI is the URI of the Git remote.
+	 *
+	 * Otherwise, the bundle list was downloaded over HTTP from some
+	 * known URI. 'baseURI' is set to that value.
+	 *
+	 * The baseURI is used as the base for any relative URIs
+	 * advertised by the bundle list at that location.
+	 */
+	char *baseURI;
+
+	/**
+	 * A list can have a heuristic, which helps reduce the number of
+	 * downloaded bundles.
+	 */
+	enum bundle_list_heuristic heuristic;
 };
 
 void init_bundle_list(struct bundle_list *list);
@@ -89,8 +124,34 @@ int bundle_uri_parse_config_format(const char *uri,
  * based on that information.
  *
  * Returns non-zero if no bundle information is found at the given 'uri'.
+ *
+ * If the pointer 'has_heuristic' is non-NULL, then the value it points to
+ * will be set to be non-zero if and only if the fetched list has a
+ * heuristic value. Such a value indicates that the list was designed for
+ * incremental fetches.
  */
-int fetch_bundle_uri(struct repository *r, const char *uri);
+int fetch_bundle_uri(struct repository *r, const char *uri,
+		     int *has_heuristic);
+
+/**
+ * Given a bundle list that was already advertised (likely by the
+ * bundle-uri protocol v2 verb) at the given uri, fetch and unbundle the
+ * bundles according to the bundle strategy of that list.
+ *
+ * It is expected that the given 'list' is initialized, including its
+ * 'baseURI' value.
+ *
+ * Returns non-zero if there was an error trying to download the list
+ * or any of its advertised bundles.
+ */
+int fetch_bundle_list(struct repository *r,
+		      struct bundle_list *list);
+
+/**
+ * API for serve.c.
+ */
+int bundle_uri_advertise(struct repository *r, struct strbuf *value);
+int bundle_uri_command(struct repository *r, struct packet_reader *request);
 
 /**
  * General API for {transport,connect}.c etc.
diff --git a/bundle.c b/bundle.c
index 4ef7256..6ab6cd7 100644
--- a/bundle.c
+++ b/bundle.c
@@ -12,6 +12,7 @@
 #include "refs.h"
 #include "strvec.h"
 #include "list-objects-filter-options.h"
+#include "connected.h"
 
 static const char v2_bundle_signature[] = "# v2 git bundle\n";
 static const char v3_bundle_signature[] = "# v3 git bundle\n";
@@ -187,6 +188,21 @@ static int list_refs(struct string_list *r, int argc, const char **argv)
 /* Remember to update object flag allocation in object.h */
 #define PREREQ_MARK (1u<<16)
 
+struct string_list_iterator {
+	struct string_list *list;
+	size_t cur;
+};
+
+static const struct object_id *iterate_ref_map(void *cb_data)
+{
+	struct string_list_iterator *iter = cb_data;
+
+	if (iter->cur >= iter->list->nr)
+		return NULL;
+
+	return iter->list->items[iter->cur++].util;
+}
+
 int verify_bundle(struct repository *r,
 		  struct bundle_header *header,
 		  enum verify_bundle_flags flags)
@@ -196,26 +212,25 @@ int verify_bundle(struct repository *r,
 	 * to be verbose about the errors
 	 */
 	struct string_list *p = &header->prerequisites;
-	struct rev_info revs = REV_INFO_INIT;
-	const char *argv[] = {NULL, "--all", NULL};
-	struct commit *commit;
-	int i, ret = 0, req_nr;
+	int i, ret = 0;
 	const char *message = _("Repository lacks these prerequisite commits:");
+	struct string_list_iterator iter = {
+		.list = p,
+	};
+	struct check_connected_options opts = {
+		.quiet = 1,
+	};
 
 	if (!r || !r->objects || !r->objects->odb)
 		return error(_("need a repository to verify a bundle"));
 
-	repo_init_revisions(r, &revs, NULL);
 	for (i = 0; i < p->nr; i++) {
 		struct string_list_item *e = p->items + i;
 		const char *name = e->string;
 		struct object_id *oid = e->util;
 		struct object *o = parse_object(r, oid);
-		if (o) {
-			o->flags |= PREREQ_MARK;
-			add_pending_object(&revs, o, name);
+		if (o)
 			continue;
-		}
 		ret++;
 		if (flags & VERIFY_BUNDLE_QUIET)
 			continue;
@@ -223,37 +238,14 @@ int verify_bundle(struct repository *r,
 			error("%s", message);
 		error("%s %s", oid_to_hex(oid), name);
 	}
-	if (revs.pending.nr != p->nr)
+	if (ret)
 		goto cleanup;
-	req_nr = revs.pending.nr;
-	setup_revisions(2, argv, &revs, NULL);
 
-	list_objects_filter_copy(&revs.filter, &header->filter);
+	if ((ret = check_connected(iterate_ref_map, &iter, &opts)))
+		error(_("some prerequisite commits exist in the object store, "
+			"but are not connected to the repository's history"));
 
-	if (prepare_revision_walk(&revs))
-		die(_("revision walk setup failed"));
-
-	i = req_nr;
-	while (i && (commit = get_revision(&revs)))
-		if (commit->object.flags & PREREQ_MARK)
-			i--;
-
-	for (i = 0; i < p->nr; i++) {
-		struct string_list_item *e = p->items + i;
-		const char *name = e->string;
-		const struct object_id *oid = e->util;
-		struct object *o = parse_object(r, oid);
-		assert(o); /* otherwise we'd have returned early */
-		if (o->flags & SHOWN)
-			continue;
-		ret++;
-		if (flags & VERIFY_BUNDLE_QUIET)
-			continue;
-		if (ret == 1)
-			error("%s", message);
-		error("%s %s", oid_to_hex(oid), name);
-	}
-
+	/* TODO: preserve this verbose language. */
 	if (flags & VERIFY_BUNDLE_VERBOSE) {
 		struct string_list *r;
 
@@ -282,15 +274,6 @@ int verify_bundle(struct repository *r,
 				  list_objects_filter_spec(&header->filter));
 	}
 cleanup:
-	/* Clean up objects used, as they will be reused. */
-	for (i = 0; i < p->nr; i++) {
-		struct string_list_item *e = p->items + i;
-		struct object_id *oid = e->util;
-		commit = lookup_commit_reference_gently(r, oid, 1);
-		if (commit)
-			clear_commit_marks(commit, ALL_REV_FLAGS | PREREQ_MARK);
-	}
-	release_revisions(&revs);
 	return ret;
 }
 
@@ -627,6 +610,10 @@ int unbundle(struct repository *r, struct bundle_header *header,
 	     enum verify_bundle_flags flags)
 {
 	struct child_process ip = CHILD_PROCESS_INIT;
+
+	if (verify_bundle(r, header, flags))
+		return -1;
+
 	strvec_pushl(&ip.args, "index-pack", "--fix-thin", "--stdin", NULL);
 
 	/* If there is a filter, then we need to create the promisor pack. */
@@ -638,8 +625,6 @@ int unbundle(struct repository *r, struct bundle_header *header,
 		strvec_clear(extra_index_pack_args);
 	}
 
-	if (verify_bundle(r, header, flags))
-		return -1;
 	ip.in = bundle_fd;
 	ip.no_stdout = 1;
 	ip.git_cmd = 1;
diff --git a/cache-tree.c b/cache-tree.c
index c97111c..88c2c04 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -405,7 +405,7 @@ static int update_one(struct cache_tree *it,
 		}
 
 		/*
-		 * CE_INTENT_TO_ADD entries exist on on-disk index but
+		 * CE_INTENT_TO_ADD entries exist in on-disk index but
 		 * they are not part of generated trees. Invalidate up
 		 * to root to force cache-tree users to read elsewhere.
 		 */
@@ -760,7 +760,7 @@ static void prime_cache_tree_rec(struct repository *r,
 	struct tree_desc desc;
 	struct name_entry entry;
 	int cnt;
-	int base_path_len = tree_path->len;
+	size_t base_path_len = tree_path->len;
 
 	oidcpy(&it->oid, &tree->object.oid);
 
@@ -785,7 +785,6 @@ static void prime_cache_tree_rec(struct repository *r,
 			 */
 			if (r->index->sparse_index) {
 				strbuf_setlen(tree_path, base_path_len);
-				strbuf_grow(tree_path, base_path_len + entry.pathlen + 1);
 				strbuf_add(tree_path, entry.path, entry.pathlen);
 				strbuf_addch(tree_path, '/');
 			}
diff --git a/cache-tree.h b/cache-tree.h
index 8efecce..bd97caa 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -53,19 +53,4 @@ int write_index_as_tree(struct object_id *oid, struct index_state *index_state,
 void prime_cache_tree(struct repository *, struct index_state *, struct tree *);
 
 int cache_tree_matches_traversal(struct cache_tree *, struct name_entry *ent, struct traverse_info *info);
-
-#ifdef USE_THE_INDEX_COMPATIBILITY_MACROS
-static inline int write_cache_as_tree(struct object_id *oid, int flags, const char *prefix)
-{
-	return write_index_as_tree(oid, &the_index, get_index_file(), flags, prefix);
-}
-
-static inline int update_main_cache_tree(int flags)
-{
-	if (!the_index.cache_tree)
-		the_index.cache_tree = cache_tree();
-	return cache_tree_update(&the_index, flags);
-}
-#endif
-
 #endif
diff --git a/cache.h b/cache.h
index 8c5fb1e..587a969 100644
--- a/cache.h
+++ b/cache.h
@@ -360,6 +360,22 @@ struct index_state {
 	struct pattern_list *sparse_checkout_patterns;
 };
 
+/**
+ * A "struct index_state istate" must be initialized with
+ * INDEX_STATE_INIT or the corresponding index_state_init().
+ *
+ * If the variable won't be used again, use release_index() to free()
+ * its resources. If it needs to be used again use discard_index(),
+ * which does the same thing, but will use use index_state_init() at
+ * the end. The discard_index() will use its own "istate->repo" as the
+ * "r" argument to index_state_init() in that case.
+ */
+#define INDEX_STATE_INIT(r) { \
+	.repo = (r), \
+}
+void index_state_init(struct index_state *istate, struct repository *r);
+void release_index(struct index_state *istate);
+
 /* Name hashing */
 int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);
 void add_name_hash(struct index_state *istate, struct cache_entry *ce);
@@ -433,18 +449,8 @@ typedef int (*must_prefetch_predicate)(const struct cache_entry *);
 void prefetch_cache_entries(const struct index_state *istate,
 			    must_prefetch_predicate must_prefetch);
 
-#if defined(USE_THE_INDEX_COMPATIBILITY_MACROS) || defined(USE_THE_INDEX_VARIABLE)
+#ifdef USE_THE_INDEX_VARIABLE
 extern struct index_state the_index;
-
-#ifndef USE_THE_INDEX_VARIABLE
-#ifdef USE_THE_INDEX_COMPATIBILITY_MACROS
-#define active_nr (the_index.cache_nr)
-
-#define read_cache() repo_read_index(the_repository)
-#define discard_cache() discard_index(&the_index)
-#define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))
-#endif
-#endif
 #endif
 
 #define TYPE_BITS 3
@@ -480,7 +486,6 @@ static inline enum object_type object_type(unsigned int mode)
 #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
 #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
 #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
-#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -566,7 +571,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
 int get_common_dir(struct strbuf *sb, const char *gitdir);
 const char *get_git_namespace(void);
 const char *strip_namespace(const char *namespaced_ref);
-const char *get_super_prefix(void);
 const char *get_git_work_tree(void);
 
 /*
@@ -1622,8 +1626,10 @@ int repo_interpret_branch_name(struct repository *r,
 
 int validate_headref(const char *ref);
 
-int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
-int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
+int base_name_compare(const char *name1, size_t len1, int mode1,
+		      const char *name2, size_t len2, int mode2);
+int df_name_compare(const char *name1, size_t len1, int mode1,
+		    const char *name2, size_t len2, int mode2);
 int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
 int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
 
diff --git a/ci/lib.sh b/ci/lib.sh
index b6bbb02..e467784 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -256,8 +256,7 @@
 	MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)"
 	if [ "$jobname" != osx-gcc ]
 	then
-		MAKEFLAGS="$MAKEFLAGS NO_APPLE_COMMON_CRYPTO=NoThanks"
-		MAKEFLAGS="$MAKEFLAGS NO_OPENSSL=NoThanks"
+		MAKEFLAGS="$MAKEFLAGS APPLE_COMMON_CRYPTO_SHA1=Yes"
 	fi
 	;;
 esac
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
index 8ebff42..b098e10 100755
--- a/ci/run-build-and-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -26,7 +26,6 @@
 	export GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=1
 	export GIT_TEST_MULTI_PACK_INDEX=1
 	export GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=1
-	export GIT_TEST_ADD_I_USE_BUILTIN=0
 	export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
 	export GIT_TEST_WRITE_REV_INDEX=1
 	export GIT_TEST_CHECKOUT_WORKERS=2
diff --git a/commit-graph.c b/commit-graph.c
index a7d8755..c11b59f 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1594,8 +1594,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)
 			_("Computing commit changed paths Bloom filters"),
 			ctx->commits.nr);
 
-	ALLOC_ARRAY(sorted_commits, ctx->commits.nr);
-	COPY_ARRAY(sorted_commits, ctx->commits.list, ctx->commits.nr);
+	DUP_ARRAY(sorted_commits, ctx->commits.list, ctx->commits.nr);
 
 	if (ctx->order_by_pack)
 		QSORT(sorted_commits, ctx->commits.nr, commit_pos_cmp);
diff --git a/commit-reach.c b/commit-reach.c
index c226ee3..2e33c59 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -245,8 +245,7 @@ static int remove_redundant_with_gen(struct repository *r,
 	 * min_gen_pos points to the current position within 'array'
 	 * that is not yet known to be STALE.
 	 */
-	ALLOC_ARRAY(sorted, cnt);
-	COPY_ARRAY(sorted, array, cnt);
+	DUP_ARRAY(sorted, array, cnt);
 	QSORT(sorted, cnt, compare_commits_by_gen);
 	min_generation = commit_graph_generation(sorted[0]);
 
diff --git a/commit.c b/commit.c
index d00780b..e433c33 100644
--- a/commit.c
+++ b/commit.c
@@ -508,6 +508,17 @@ int repo_parse_commit_internal(struct repository *r,
 	enum object_type type;
 	void *buffer;
 	unsigned long size;
+	struct object_info oi = {
+		.typep = &type,
+		.sizep = &size,
+		.contentp = &buffer,
+	};
+	/*
+	 * Git does not support partial clones that exclude commits, so set
+	 * OBJECT_INFO_SKIP_FETCH_OBJECT to fail fast when an object is missing.
+	 */
+	int flags = OBJECT_INFO_LOOKUP_REPLACE | OBJECT_INFO_SKIP_FETCH_OBJECT |
+		OBJECT_INFO_DIE_IF_CORRUPT;
 	int ret;
 
 	if (!item)
@@ -516,8 +527,8 @@ int repo_parse_commit_internal(struct repository *r,
 		return 0;
 	if (use_commit_graph && parse_commit_in_graph(r, item))
 		return 0;
-	buffer = repo_read_object_file(r, &item->object.oid, &type, &size);
-	if (!buffer)
+
+	if (oid_object_info_extended(r, &item->object.oid, &oi, flags) < 0)
 		return quiet_on_missing ? -1 :
 			error("Could not read %s",
 			     oid_to_hex(&item->object.oid));
@@ -1022,6 +1033,7 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
 	ret = bases->item;
 
 cleanup_return:
+	free(revs.commit);
 	free_commit_list(bases);
 	free(full_refname);
 	return ret;
diff --git a/commit.h b/commit.h
index fa39202..cc2c5da 100644
--- a/commit.h
+++ b/commit.h
@@ -274,8 +274,6 @@ struct ref;
 int for_each_commit_graft(each_commit_graft_fn, void *);
 
 int interactive_add(const char **argv, const char *prefix, int patch);
-int run_add_interactive(const char *revision, const char *patch_mode,
-			const struct pathspec *pathspec);
 
 struct commit_extra_header {
 	struct commit_extra_header *next;
diff --git a/compat/mingw.c b/compat/mingw.c
index d614f15..e433740 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1396,8 +1396,7 @@ static wchar_t *make_environment_block(char **deltaenv)
 			p += s;
 		}
 
-		ALLOC_ARRAY(result, size);
-		COPY_ARRAY(result, wenv, size);
+		DUP_ARRAY(result, wenv, size);
 		FreeEnvironmentStringsW(wenv);
 		return result;
 	}
@@ -1839,16 +1838,13 @@ static int try_shell_exec(const char *cmd, char *const *argv)
 	if (prog) {
 		int exec_id;
 		int argc = 0;
-#ifndef _MSC_VER
-		const
-#endif
 		char **argv2;
 		while (argv[argc]) argc++;
 		ALLOC_ARRAY(argv2, argc + 1);
 		argv2[0] = (char *)cmd;	/* full path to the script file */
 		COPY_ARRAY(&argv2[1], &argv[1], argc);
-		exec_id = trace2_exec(prog, argv2);
-		pid = mingw_spawnv(prog, argv2, 1);
+		exec_id = trace2_exec(prog, (const char **)argv2);
+		pid = mingw_spawnv(prog, (const char **)argv2, 1);
 		if (pid >= 0) {
 			int status;
 			if (waitpid(pid, &status, 0) < 0)
@@ -2752,7 +2748,7 @@ int is_path_owned_by_current_sid(const char *path, struct strbuf *report)
 			/*
 			 * On FAT32 volumes, ownership is not actually recorded.
 			 */
-			strbuf_addf(report, "'%s' is on a file system that does"
+			strbuf_addf(report, "'%s' is on a file system that does "
 				    "not record ownership\n", path);
 		} else if (report) {
 			LPSTR str1, str2, to_free1 = NULL, to_free2 = NULL;
diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c
index 2e7eead..85f8f79 100644
--- a/compat/win32/pthread.c
+++ b/compat/win32/pthread.c
@@ -22,12 +22,12 @@ static unsigned __stdcall win32_start_routine(void *arg)
 }
 
 int pthread_create(pthread_t *thread, const void *unused,
-		   void *(*start_routine)(void*), void *arg)
+		   void *(*start_routine)(void *), void *arg)
 {
 	thread->arg = arg;
 	thread->start_routine = start_routine;
-	thread->handle = (HANDLE)
-		_beginthreadex(NULL, 0, win32_start_routine, thread, 0, NULL);
+	thread->handle = (HANDLE)_beginthreadex(NULL, 0, win32_start_routine,
+						thread, 0, NULL);
 
 	if (!thread->handle)
 		return errno;
@@ -39,14 +39,17 @@ int win32_pthread_join(pthread_t *thread, void **value_ptr)
 {
 	DWORD result = WaitForSingleObject(thread->handle, INFINITE);
 	switch (result) {
-		case WAIT_OBJECT_0:
-			if (value_ptr)
-				*value_ptr = thread->arg;
-			return 0;
-		case WAIT_ABANDONED:
-			return EINVAL;
-		default:
-			return err_win_to_posix(GetLastError());
+	case WAIT_OBJECT_0:
+		if (value_ptr)
+			*value_ptr = thread->arg;
+		CloseHandle(thread->handle);
+		return 0;
+	case WAIT_ABANDONED:
+		CloseHandle(thread->handle);
+		return EINVAL;
+	default:
+		/* the wait failed, so do not detach */
+		return err_win_to_posix(GetLastError());
 	}
 }
 
diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h
index 737983d..cc3221c 100644
--- a/compat/win32/pthread.h
+++ b/compat/win32/pthread.h
@@ -66,7 +66,7 @@ pthread_t pthread_self(void);
 
 static inline void NORETURN pthread_exit(void *ret)
 {
-	ExitThread((DWORD)(intptr_t)ret);
+	_endthreadex((unsigned)(uintptr_t)ret);
 }
 
 typedef DWORD pthread_key_t;
diff --git a/compat/winansi.c b/compat/winansi.c
index 3abe8dd..f83610f 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -644,7 +644,7 @@ void winansi_init(void)
 
 	/* start console spool thread on the pipe's read end */
 	hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
-	if (hthread == INVALID_HANDLE_VALUE)
+	if (!hthread)
 		die_lasterr("CreateThread(console_thread) failed");
 
 	/* schedule cleanup routine */
diff --git a/config.c b/config.c
index 8c1c407..aa2888d 100644
--- a/config.c
+++ b/config.c
@@ -3154,7 +3154,7 @@ int git_config_set_gently(const char *key, const char *value)
 int repo_config_set_worktree_gently(struct repository *r,
 				    const char *key, const char *value)
 {
-	/* Only use worktree-specific config if it is is already enabled. */
+	/* Only use worktree-specific config if it is already enabled. */
 	if (repository_format_worktree_config) {
 		char *file = repo_git_path(r, "config.worktree");
 		int ret = git_config_set_multivar_in_file_gently(
diff --git a/config.h b/config.h
index ef9eade..7606246 100644
--- a/config.h
+++ b/config.h
@@ -448,15 +448,6 @@ void git_configset_init(struct config_set *cs);
 int git_configset_add_file(struct config_set *cs, const char *filename);
 
 /**
- * Parses command line options and environment variables, and adds the
- * variable-value pairs to the `config_set`. Returns 0 on success, or -1
- * if there is an error in parsing. The caller decides whether to free
- * the incomplete configset or continue using it when the function
- * returns -1.
- */
-int git_configset_add_parameters(struct config_set *cs);
-
-/**
  * Finds and returns the value list, sorted in order of increasing priority
  * for the configuration variable `key` and config set `cs`. When the
  * configuration variable `key` is not found, returns NULL. The caller
diff --git a/config.mak.uname b/config.mak.uname
index 7d25995..64c44db 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -624,6 +624,9 @@
 	SHELL_PATH = /usr/coreutils/bin/bash
 endif
 ifeq ($(uname_S),MINGW)
+	ifeq ($(shell expr "$(uname_R)" : '1\.'),2)
+		$(error "Building with MSys is no longer supported")
+	endif
 	pathsep = ;
 	HAVE_ALLOCA_H = YesPlease
 	NO_PREAD = YesPlease
@@ -653,7 +656,6 @@
 	USE_WIN32_IPC = YesPlease
 	USE_WIN32_MMAP = YesPlease
 	MMAP_PREVENTS_DELETE = UnfortunatelyYes
-	USE_NED_ALLOCATOR = YesPlease
 	UNRELIABLE_FSTAT = UnfortunatelyYes
 	OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
 	NO_REGEX = YesPlease
@@ -678,61 +680,43 @@
 	RC = windres -O coff
 	NATIVE_CRLF = YesPlease
 	X = .exe
-ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
-	htmldir = doc/git/html/
-	prefix =
+	# MSys2
+	prefix = /usr/
+	# Enable DEP
+	BASIC_LDFLAGS += -Wl,--nxcompat
+	# Enable ASLR (unless debugging)
+	ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS))))
+		BASIC_LDFLAGS += -Wl,--dynamicbase
+	endif
+	ifeq (MINGW32,$(MSYSTEM))
+		prefix = /mingw32
+		HOST_CPU = i686
+		BASIC_LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup
+	endif
+	ifeq (MINGW64,$(MSYSTEM))
+		prefix = /mingw64
+		HOST_CPU = x86_64
+		BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup
+	else
+		COMPAT_CFLAGS += -D_USE_32BIT_TIME_T
+		BASIC_LDFLAGS += -Wl,--large-address-aware
+	endif
+	CC = gcc
+	COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
+		-fstack-protector-strong
+	EXTLIBS += -lntdll
 	INSTALL = /bin/install
-	EXTLIBS += /mingw/lib/libz.a
 	INTERNAL_QSORT = YesPlease
 	HAVE_LIBCHARSET_H = YesPlease
-	NO_GETTEXT = YesPlease
-	NO_PYTHON = YesPlease
-	COMPAT_CFLAGS += -D__USE_MINGW_ACCESS
-else
-	ifneq ($(shell expr "$(uname_R)" : '1\.'),2)
-		# MSys2
-		prefix = /usr/
-		# Enable DEP
-		BASIC_LDFLAGS += -Wl,--nxcompat
-		# Enable ASLR (unless debugging)
-		ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS))))
-			BASIC_LDFLAGS += -Wl,--dynamicbase
-		endif
-		ifeq (MINGW32,$(MSYSTEM))
-			prefix = /mingw32
-			HOST_CPU = i686
-			BASIC_LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup
-		endif
-		ifeq (MINGW64,$(MSYSTEM))
-			prefix = /mingw64
-			HOST_CPU = x86_64
-			BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup
-		else
-			COMPAT_CFLAGS += -D_USE_32BIT_TIME_T
-			BASIC_LDFLAGS += -Wl,--large-address-aware
-		endif
-		CC = gcc
-		COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
-			-fstack-protector-strong
-		EXTLIBS += -lntdll
-		INSTALL = /bin/install
-		INTERNAL_QSORT = YesPlease
-		HAVE_LIBCHARSET_H = YesPlease
-		USE_GETTEXT_SCHEME = fallthrough
-		USE_LIBPCRE = YesPlease
-		USE_NED_ALLOCATOR = YesPlease
-		ifeq (/mingw64,$(subst 32,64,$(prefix)))
-			# Move system config into top-level /etc/
-			ETC_GITCONFIG = ../etc/gitconfig
-			ETC_GITATTRIBUTES = ../etc/gitattributes
-		endif
-	else
-		COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO
-		NO_CURL = YesPlease
-		NO_PYTHON = YesPlease
+	USE_GETTEXT_SCHEME = fallthrough
+	USE_LIBPCRE = YesPlease
+	USE_NED_ALLOCATOR = YesPlease
+	ifeq (/mingw64,$(subst 32,64,$(prefix)))
+		# Move system config into top-level /etc/
+		ETC_GITCONFIG = ../etc/gitconfig
+		ETC_GITATTRIBUTES = ../etc/gitattributes
 	endif
 endif
-endif
 ifeq ($(uname_S),QNX)
 	COMPAT_CFLAGS += -DSA_RESTART=0
 	EXPAT_NEEDS_XMLPARSE_H = YesPlease
diff --git a/connect.c b/connect.c
index eef752f..63e5964 100644
--- a/connect.c
+++ b/connect.c
@@ -15,6 +15,7 @@
 #include "version.h"
 #include "protocol.h"
 #include "alias.h"
+#include "bundle-uri.h"
 
 static char *server_capabilities_v1;
 static struct strvec server_capabilities_v2 = STRVEC_INIT;
@@ -493,6 +494,49 @@ static void send_capabilities(int fd_out, struct packet_reader *reader)
 	}
 }
 
+int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
+			  struct bundle_list *bundles, int stateless_rpc)
+{
+	int line_nr = 1;
+
+	/* Assert bundle-uri support */
+	ensure_server_supports_v2("bundle-uri");
+
+	/* (Re-)send capabilities */
+	send_capabilities(fd_out, reader);
+
+	/* Send command */
+	packet_write_fmt(fd_out, "command=bundle-uri\n");
+	packet_delim(fd_out);
+
+	packet_flush(fd_out);
+
+	/* Process response from server */
+	while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
+		const char *line = reader->line;
+		line_nr++;
+
+		if (!bundle_uri_parse_line(bundles, line))
+			continue;
+
+		return error(_("error on bundle-uri response line %d: %s"),
+			     line_nr, line);
+	}
+
+	if (reader->status != PACKET_READ_FLUSH)
+		return error(_("expected flush after bundle-uri listing"));
+
+	/*
+	 * Might die(), but obscure enough that that's OK, e.g. in
+	 * serve.c we'll call BUG() on its equivalent (the
+	 * PACKET_READ_RESPONSE_END check).
+	 */
+	check_stateless_delimiter(stateless_rpc, reader,
+				  _("expected response end packet after ref listing"));
+
+	return 0;
+}
+
 struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
 			     struct ref **list, int for_push,
 			     struct transport_ls_refs_options *transport_options,
diff --git a/connected.c b/connected.c
index 4f6388e..b90fd61 100644
--- a/connected.c
+++ b/connected.c
@@ -85,6 +85,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
 promisor_pack_found:
 			;
 		} while ((oid = fn(cb_data)) != NULL);
+		free(new_pack);
 		return 0;
 	}
 
@@ -121,8 +122,10 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
 	else
 		rev_list.no_stderr = opt->quiet;
 
-	if (start_command(&rev_list))
+	if (start_command(&rev_list)) {
+		free(new_pack);
 		return error(_("Could not run 'git rev-list'"));
+	}
 
 	sigchain_push(SIGPIPE, SIG_IGN);
 
@@ -154,5 +157,6 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
 		err = error_errno(_("failed to close rev-list's stdin"));
 
 	sigchain_pop(SIGPIPE);
+	free(new_pack);
 	return finish_command(&rev_list) || err;
 }
diff --git a/contrib/coccinelle/array.cocci b/contrib/coccinelle/array.cocci
index aa75937..27a3b47 100644
--- a/contrib/coccinelle/array.cocci
+++ b/contrib/coccinelle/array.cocci
@@ -94,3 +94,10 @@
 @@
 - ptr = xcalloc(n, \( sizeof(*ptr) \| sizeof(T) \) )
 + CALLOC_ARRAY(ptr, n)
+
+@@
+expression dst, src, n;
+@@
+-ALLOC_ARRAY(dst, n);
+-COPY_ARRAY(dst, src, n);
++DUP_ARRAY(dst, src, n);
diff --git a/contrib/coccinelle/index-compatibility.cocci b/contrib/coccinelle/index-compatibility.cocci
index 8520f03..31e36cf 100644
--- a/contrib/coccinelle/index-compatibility.cocci
+++ b/contrib/coccinelle/index-compatibility.cocci
@@ -1,6 +1,7 @@
 // the_index.* variables
 @@
 identifier AC = active_cache;
+identifier AN = active_nr;
 identifier ACC = active_cache_changed;
 identifier ACT = active_cache_tree;
 @@
@@ -8,6 +9,9 @@
 - AC
 + the_index.cache
 |
+- AN
++ the_index.cache_nr
+|
 - ACC
 + the_index.cache_changed
 |
@@ -15,19 +19,13 @@
 + the_index.cache_tree
 )
 
-@@
-identifier AN = active_nr;
-identifier f != prepare_to_commit;
-@@
-  f(...) {<...
-- AN
-+ the_index.cache_nr
-  ...>}
-
 // "the_repository" simple cases
 @@
 @@
 (
+- read_cache
++ repo_read_index
+|
 - read_cache_unmerged
 + repo_read_index_unmerged
 |
@@ -96,6 +94,15 @@
 |
 - resolve_undo_clear
 + resolve_undo_clear_index
+|
+- cache_name_pos
++ index_name_pos
+|
+- update_main_cache_tree
++ cache_tree_update
+|
+- discard_cache
++ discard_index
 )
   (
 + &the_index,
@@ -137,3 +144,14 @@
   ...
 + , NULL, NULL, NULL
   )
+
+@@
+expression O;
+@@
+- write_cache_as_tree
++ write_index_as_tree
+  (
+- O,
++ O, &the_index, get_index_file(),
+  ...
+  )
diff --git a/contrib/coccinelle/index-compatibility.pending.cocci b/contrib/coccinelle/index-compatibility.pending.cocci
deleted file mode 100644
index 01f875d0..0000000
--- a/contrib/coccinelle/index-compatibility.pending.cocci
+++ /dev/null
@@ -1,24 +0,0 @@
-// "the_repository" simple cases
-@@
-@@
-(
-- read_cache
-+ repo_read_index
-)
-  (
-+ the_repository,
-  ...)
-
-// "the_index" simple cases
-@@
-@@
-(
-- discard_cache
-+ discard_index
-|
-- cache_name_pos
-+ index_name_pos
-)
-  (
-+ &the_index,
-  ...)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index ba5c395..dc95c34 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -58,6 +58,12 @@
 #
 #     When set to "1" suggest all options, including options which are
 #     typically hidden (e.g. '--allow-empty' for 'git commit').
+#
+#   GIT_COMPLETION_IGNORE_CASE
+#
+#     When set, uses for-each-ref '--ignore-case' to find refs that match
+#     case insensitively, even on systems with case sensitive file systems
+#     (e.g., completing tag name "FOO" on "git checkout f<TAB>").
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -646,6 +652,7 @@
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 			"refs/heads/$cur_*" "refs/heads/$cur_*/**"
 }
 
@@ -659,6 +666,7 @@
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 			"refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
 }
 
@@ -669,6 +677,7 @@
 	local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 
 	__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 			"refs/tags/$cur_*" "refs/tags/$cur_*/**"
 }
 
@@ -688,6 +697,7 @@
 	# but only output if the branch name is unique
 	__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
 		--sort="refname:strip=3" \
+		${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 		"refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
 	uniq -u
 }
@@ -712,6 +722,7 @@
 	local format refs
 	local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
 	local match="${4-}"
+	local umatch="${4-}"
 	local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
 
 	__git_find_repo_path
@@ -735,12 +746,19 @@
 		fi
 	fi
 
+	if test "${GIT_COMPLETION_IGNORE_CASE:+1}" = "1"
+	then
+		# uppercase with tr instead of ${match,^^} for bash 3.2 compatibility
+		umatch=$(echo "$match" | tr a-z A-Z 2>/dev/null || echo "$match")
+	fi
+
 	if [ "$list_refs_from" = path ]; then
 		if [[ "$cur_" == ^* ]]; then
 			pfx="$pfx^"
 			fer_pfx="$fer_pfx^"
 			cur_=${cur_#^}
 			match=${match#^}
+			umatch=${umatch#^}
 		fi
 		case "$cur_" in
 		refs|refs/*)
@@ -751,7 +769,7 @@
 		*)
 			for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
 				case "$i" in
-				$match*)
+				$match*|$umatch*)
 					if [ -e "$dir/$i" ]; then
 						echo "$pfx$i$sfx"
 					fi
@@ -765,6 +783,7 @@
 			;;
 		esac
 		__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
+			${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 			"${refs[@]}"
 		if [ -n "$track" ]; then
 			__git_dwim_remote_heads "$pfx" "$match" "$sfx"
@@ -784,15 +803,16 @@
 	*)
 		if [ "$list_refs_from" = remote ]; then
 			case "HEAD" in
-			$match*)	echo "${pfx}HEAD$sfx" ;;
+			$match*|$umatch*)	echo "${pfx}HEAD$sfx" ;;
 			esac
 			__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
+				${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
 				"refs/remotes/$remote/$match*" \
 				"refs/remotes/$remote/$match*/**"
 		else
 			local query_symref
 			case "HEAD" in
-			$match*)	query_symref="HEAD" ;;
+			$match*|$umatch*)	query_symref="HEAD" ;;
 			esac
 			__git ls-remote "$remote" $query_symref \
 				"refs/tags/$match*" "refs/heads/$match*" \
diff --git a/contrib/git-jump/README b/contrib/git-jump/README
index 8bcace2..3211841 100644
--- a/contrib/git-jump/README
+++ b/contrib/git-jump/README
@@ -79,6 +79,14 @@
 git config jump.grepCmd "ag --column"
 --------------------------------------------------
 
+You can use the optional argument '--stdout' to print the listing to
+standard output instead of feeding it to the editor. You can use the
+argument with M-x grep on Emacs:
+
+--------------------------------------------------
+# In Emacs, M-x grep and invoke "git jump --stdout <mode>"
+M-x grep<RET>git jump --stdout diff<RET>
+--------------------------------------------------
 
 Related Programs
 ----------------
@@ -100,7 +108,7 @@
 -----------
 
 This script was written and tested with vim. Given that the quickfix
-format is the same as what gcc produces, I expect emacs users have a
+format is the same as what gcc produces, I expect other tools have a
 similar feature for iterating through the list, but I know nothing about
 how to activate it.
 
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
index 92dbd4c..40c4b0d 100755
--- a/contrib/git-jump/git-jump
+++ b/contrib/git-jump/git-jump
@@ -2,7 +2,7 @@
 
 usage() {
 	cat <<\EOF
-usage: git jump <mode> [<args>]
+usage: git jump [--stdout] <mode> [<args>]
 
 Jump to interesting elements in an editor.
 The <mode> parameter is one of:
@@ -15,12 +15,30 @@
       configured, to the command in `jump.grepCmd`.
 
 ws: elements are whitespace errors. Arguments are given to diff --check.
+
+If the optional argument `--stdout` is given, print the quickfix
+lines to standard output instead of feeding it to the editor.
 EOF
 }
 
 open_editor() {
 	editor=`git var GIT_EDITOR`
-	eval "$editor -q \$1"
+	case "$editor" in
+	*emacs*)
+		# Supported editor values are:
+		# - emacs
+		# - emacsclient
+		# - emacsclient -t
+		#
+		# Wait for completion of the asynchronously executed process
+		# to avoid race conditions in case of "emacsclient".
+		eval "$editor --eval \"(let ((buf (grep \\\"cat \$1\\\"))) (pop-to-buffer buf) (select-frame-set-input-focus (selected-frame)) (while (get-buffer-process buf) (sleep-for 0.1)))\""
+		;;
+	*)
+		# assume anything else is vi-compatible
+		eval "$editor -q \$1"
+		;;
+	esac
 }
 
 mode_diff() {
@@ -64,15 +82,36 @@
 	git diff --check "$@"
 }
 
+use_stdout=
+while test $# -gt 0; do
+	case "$1" in
+	--stdout)
+		use_stdout=t
+		;;
+	--*)
+		usage >&2
+		exit 1
+		;;
+	*)
+		break
+		;;
+	esac
+	shift
+done
 if test $# -lt 1; then
 	usage >&2
 	exit 1
 fi
 mode=$1; shift
+type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
+
+if test "$use_stdout" = "t"; then
+	"mode_$mode" "$@"
+	exit 0
+fi
 
 trap 'rm -f "$tmp"' 0 1 2 3 15
 tmp=`mktemp -t git-jump.XXXXXX` || exit 1
-type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
 "mode_$mode" "$@" >"$tmp"
 test -s "$tmp" || exit 0
 open_editor "$tmp"
diff --git a/convert.c b/convert.c
index 9b67649..a54d169 100644
--- a/convert.c
+++ b/convert.c
@@ -1308,7 +1308,7 @@ void convert_attrs(struct index_state *istate,
 		git_config(read_convert_config, NULL);
 	}
 
-	git_check_attr(istate, path, check);
+	git_check_attr(istate, NULL, path, check);
 	ccheck = check->items;
 	ca->crlf_action = git_path_check_crlf(ccheck + 4);
 	if (ca->crlf_action == CRLF_UNDEFINED)
diff --git a/credential.c b/credential.c
index f6389a5..f320113 100644
--- a/credential.c
+++ b/credential.c
@@ -7,6 +7,7 @@
 #include "prompt.h"
 #include "sigchain.h"
 #include "urlmatch.h"
+#include "git-compat-util.h"
 
 void credential_init(struct credential *c)
 {
@@ -234,6 +235,11 @@ int credential_read(struct credential *c, FILE *fp)
 		} else if (!strcmp(key, "path")) {
 			free(c->path);
 			c->path = xstrdup(value);
+		} else if (!strcmp(key, "password_expiry_utc")) {
+			errno = 0;
+			c->password_expiry_utc = parse_timestamp(value, NULL, 10);
+			if (c->password_expiry_utc == 0 || errno == ERANGE)
+				c->password_expiry_utc = TIME_MAX;
 		} else if (!strcmp(key, "url")) {
 			credential_from_url(c, value);
 		} else if (!strcmp(key, "quit")) {
@@ -269,6 +275,11 @@ void credential_write(const struct credential *c, FILE *fp)
 	credential_write_item(fp, "path", c->path, 0);
 	credential_write_item(fp, "username", c->username, 0);
 	credential_write_item(fp, "password", c->password, 0);
+	if (c->password_expiry_utc != TIME_MAX) {
+		char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
+		credential_write_item(fp, "password_expiry_utc", s, 0);
+		free(s);
+	}
 }
 
 static int run_credential_helper(struct credential *c,
@@ -342,6 +353,12 @@ void credential_fill(struct credential *c)
 
 	for (i = 0; i < c->helpers.nr; i++) {
 		credential_do(c, c->helpers.items[i].string, "get");
+		if (c->password_expiry_utc < time(NULL)) {
+			/* Discard expired password */
+			FREE_AND_NULL(c->password);
+			/* Reset expiry to maintain consistency */
+			c->password_expiry_utc = TIME_MAX;
+		}
 		if (c->username && c->password)
 			return;
 		if (c->quit)
@@ -360,7 +377,7 @@ void credential_approve(struct credential *c)
 
 	if (c->approved)
 		return;
-	if (!c->username || !c->password)
+	if (!c->username || !c->password || c->password_expiry_utc < time(NULL))
 		return;
 
 	credential_apply_config(c);
@@ -381,6 +398,7 @@ void credential_reject(struct credential *c)
 
 	FREE_AND_NULL(c->username);
 	FREE_AND_NULL(c->password);
+	c->password_expiry_utc = TIME_MAX;
 	c->approved = 0;
 }
 
diff --git a/credential.h b/credential.h
index f430e77..935b28a 100644
--- a/credential.h
+++ b/credential.h
@@ -126,10 +126,12 @@ struct credential {
 	char *protocol;
 	char *host;
 	char *path;
+	timestamp_t password_expiry_utc;
 };
 
 #define CREDENTIAL_INIT { \
 	.helpers = STRING_LIST_INIT_DUP, \
+	.password_expiry_utc = TIME_MAX, \
 }
 
 /* Initialize a credential structure, setting all fields to empty. */
diff --git a/csum-file.c b/csum-file.c
index 59ef339..cce13c0 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -45,7 +45,8 @@ void hashflush(struct hashfile *f)
 	unsigned offset = f->offset;
 
 	if (offset) {
-		the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
+		if (!f->skip_hash)
+			the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
 		flush(f, f->buffer, offset);
 		f->offset = 0;
 	}
@@ -64,7 +65,12 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result,
 	int fd;
 
 	hashflush(f);
-	the_hash_algo->final_fn(f->buffer, &f->ctx);
+
+	if (f->skip_hash)
+		hashclr(f->buffer);
+	else
+		the_hash_algo->final_fn(f->buffer, &f->ctx);
+
 	if (result)
 		hashcpy(result, f->buffer);
 	if (flags & CSUM_HASH_IN_STREAM)
@@ -108,7 +114,8 @@ void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
 			 * the hashfile's buffer. In this block,
 			 * f->offset is necessarily zero.
 			 */
-			the_hash_algo->update_fn(&f->ctx, buf, nr);
+			if (!f->skip_hash)
+				the_hash_algo->update_fn(&f->ctx, buf, nr);
 			flush(f, buf, nr);
 		} else {
 			/*
@@ -153,6 +160,7 @@ static struct hashfile *hashfd_internal(int fd, const char *name,
 	f->tp = tp;
 	f->name = name;
 	f->do_crc = 0;
+	f->skip_hash = 0;
 	the_hash_algo->init_fn(&f->ctx);
 
 	f->buffer_len = buffer_len;
diff --git a/csum-file.h b/csum-file.h
index 0d29f52..793a59d 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -20,6 +20,13 @@ struct hashfile {
 	size_t buffer_len;
 	unsigned char *buffer;
 	unsigned char *check_buffer;
+
+	/**
+	 * If non-zero, skip_hash indicates that we should
+	 * not actually compute the hash for this hashfile and
+	 * instead only use it as a buffered write.
+	 */
+	int skip_hash;
 };
 
 /* Checkpoint */
diff --git a/date.c b/date.c
index 53bd6a7..6f45eeb 100644
--- a/date.c
+++ b/date.c
@@ -493,6 +493,12 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
 		return 2;
 	}
 
+	/* ISO-8601 allows yyyymmDD'T'HHMMSS, with less precision */
+	if (*date == 'T' && isdigit(date[1]) && tm->tm_hour == -1) {
+		tm->tm_min = tm->tm_sec = 0;
+		return 1;
+	}
+
 	/* BAD CRAP */
 	return skip_alpha(date);
 }
@@ -639,6 +645,18 @@ static inline int nodate(struct tm *tm)
 }
 
 /*
+ * Have we seen an ISO-8601-alike date, i.e. 20220101T0,
+ * In which, hour is still unset,
+ * and minutes and second has been set to 0.
+ */
+static inline int maybeiso8601(struct tm *tm)
+{
+	return tm->tm_hour == -1 &&
+		tm->tm_min == 0 &&
+		tm->tm_sec == 0;
+}
+
+/*
  * We've seen a digit. Time? Year? Date?
  */
 static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt)
@@ -701,6 +719,25 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
 		return end - date;
 	}
 
+	/* reduced precision of ISO-8601's time: HHMM or HH */
+	if (maybeiso8601(tm)) {
+		unsigned int num1 = num;
+		unsigned int num2 = 0;
+		if (n == 4) {
+			num1 = num / 100;
+			num2 = num % 100;
+		}
+		if ((n == 4 || n == 2) && !nodate(tm) &&
+		    set_time(num1, num2, 0, tm) == 0)
+			return n;
+		/*
+		 * We thought this is an ISO-8601 time string,
+		 * we set minutes and seconds to 0,
+		 * turn out it isn't, rollback the change.
+		 */
+		tm->tm_min = tm->tm_sec = -1;
+	}
+
 	/* Four-digit year or a timezone? */
 	if (n == 4) {
 		if (num <= 1400 && *offset == -1) {
diff --git a/delta-islands.c b/delta-islands.c
index 90c0d69..afdec0a 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -513,6 +513,22 @@ void propagate_island_marks(struct commit *commit)
 	}
 }
 
+void free_island_marks(void)
+{
+	struct island_bitmap *bitmap;
+
+	if (island_marks) {
+		kh_foreach_value(island_marks, bitmap, {
+			if (!--bitmap->refcount)
+				free(bitmap);
+		});
+		kh_destroy_oid_map(island_marks);
+	}
+
+	/* detect use-after-free with a an address which is never valid: */
+	island_marks = (void *)-1;
+}
+
 int compute_pack_layers(struct packing_data *to_pack)
 {
 	uint32_t i;
diff --git a/delta-islands.h b/delta-islands.h
index eb0f952..8d1591a 100644
--- a/delta-islands.h
+++ b/delta-islands.h
@@ -14,5 +14,6 @@ void resolve_tree_islands(struct repository *r,
 void load_delta_islands(struct repository *r, int progress);
 void propagate_island_marks(struct commit *commit);
 int compute_pack_layers(struct packing_data *to_pack);
+void free_island_marks(void);
 
 #endif /* DELTA_ISLANDS_H */
diff --git a/diff-no-index.c b/diff-no-index.c
index 18edbdf..05fafd0 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -255,8 +255,7 @@ int diff_no_index(struct rev_info *revs,
 	};
 	struct option *options;
 
-	options = parse_options_concat(no_index_options,
-				       revs->diffopt.parseopts);
+	options = add_diff_options(no_index_options, &revs->diffopt);
 	argc = parse_options(argc, argv, revs->prefix, options,
 			     diff_no_index_usage, 0);
 	if (argc != 2) {
diff --git a/diff.c b/diff.c
index 6a5ed21..469e18a 100644
--- a/diff.c
+++ b/diff.c
@@ -2800,7 +2800,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 		else if (file->is_unmerged) {
 			strbuf_addf(&out, " %s%s%*s | %*s",
 				    prefix, name, padding, "",
-				    number_width, "Unmerged");
+				    number_width, "Unmerged\n");
 			emit_diff_symbol(options, DIFF_SYMBOL_STATS_LINE,
 					 out.buf, out.len, 0);
 			strbuf_reset(&out);
@@ -3437,6 +3437,22 @@ static int diff_filepair_is_phoney(struct diff_filespec *one,
 	return !DIFF_FILE_VALID(one) && !DIFF_FILE_VALID(two);
 }
 
+static int set_diff_algorithm(struct diff_options *opts,
+			      const char *alg)
+{
+	long value = parse_algorithm_value(alg);
+
+	if (value < 0)
+		return -1;
+
+	/* clear out previous settings */
+	DIFF_XDL_CLR(opts, NEED_MINIMAL);
+	opts->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
+	opts->xdl_opts |= value;
+
+	return 0;
+}
+
 static void builtin_diff(const char *name_a,
 			 const char *name_b,
 			 struct diff_filespec *one,
@@ -4440,15 +4456,13 @@ static void run_diff_cmd(const char *pgm,
 	const char *xfrm_msg = NULL;
 	int complete_rewrite = (p->status == DIFF_STATUS_MODIFIED) && p->score;
 	int must_show_header = 0;
+	struct userdiff_driver *drv = NULL;
 
-
-	if (o->flags.allow_external) {
-		struct userdiff_driver *drv;
-
+	if (o->flags.allow_external || !o->ignore_driver_algorithm)
 		drv = userdiff_find_by_path(o->repo->index, attr_path);
-		if (drv && drv->external)
-			pgm = drv->external;
-	}
+
+	if (o->flags.allow_external && drv && drv->external)
+		pgm = drv->external;
 
 	if (msg) {
 		/*
@@ -4465,12 +4479,16 @@ static void run_diff_cmd(const char *pgm,
 		run_external_diff(pgm, name, other, one, two, xfrm_msg, o);
 		return;
 	}
-	if (one && two)
+	if (one && two) {
+		if (!o->ignore_driver_algorithm && drv && drv->algorithm)
+			set_diff_algorithm(o, drv->algorithm);
+
 		builtin_diff(name, other ? other : name,
 			     one, two, xfrm_msg, must_show_header,
 			     o, complete_rewrite);
-	else
+	} else {
 		fprintf(o->file, "* Unmerged path %s\n", name);
+	}
 }
 
 static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *istate)
@@ -4567,6 +4585,14 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
 	const char *name;
 	const char *other;
 
+	if (!o->ignore_driver_algorithm) {
+		struct userdiff_driver *drv = userdiff_find_by_path(o->repo->index,
+								    p->one->path);
+
+		if (drv && drv->algorithm)
+			set_diff_algorithm(o, drv->algorithm);
+	}
+
 	if (DIFF_PAIR_UNMERGED(p)) {
 		/* unmerged */
 		builtin_diffstat(p->one->path, NULL, NULL, NULL,
@@ -4611,8 +4637,6 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
 	builtin_checkdiff(name, other, attr_path, p->one, p->two, o);
 }
 
-static void prep_parse_options(struct diff_options *options);
-
 void repo_diff_setup(struct repository *r, struct diff_options *options)
 {
 	memcpy(options, &default_diff_options, sizeof(*options));
@@ -4658,8 +4682,6 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
 
 	options->color_moved = diff_color_moved_default;
 	options->color_moved_ws_handling = diff_color_moved_ws_default;
-
-	prep_parse_options(options);
 }
 
 static const char diff_status_letters[] = {
@@ -4817,8 +4839,6 @@ void diff_setup_done(struct diff_options *options)
 			options->filter = ~filter_bit[DIFF_STATUS_FILTER_AON];
 		options->filter &= ~options->filter_not;
 	}
-
-	FREE_AND_NULL(options->parseopts);
 }
 
 int parse_long_opt(const char *opt, const char **argv,
@@ -5113,17 +5133,32 @@ static int diff_opt_diff_algorithm(const struct option *opt,
 				   const char *arg, int unset)
 {
 	struct diff_options *options = opt->value;
-	long value = parse_algorithm_value(arg);
 
 	BUG_ON_OPT_NEG(unset);
-	if (value < 0)
+
+	if (set_diff_algorithm(options, arg))
 		return error(_("option diff-algorithm accepts \"myers\", "
 			       "\"minimal\", \"patience\" and \"histogram\""));
 
-	/* clear out previous settings */
-	DIFF_XDL_CLR(options, NEED_MINIMAL);
-	options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
-	options->xdl_opts |= value;
+	options->ignore_driver_algorithm = 1;
+
+	return 0;
+}
+
+static int diff_opt_diff_algorithm_no_arg(const struct option *opt,
+				   const char *arg, int unset)
+{
+	struct diff_options *options = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	if (set_diff_algorithm(options, opt->long_name))
+		BUG("available diff algorithms include \"myers\", "
+			       "\"minimal\", \"patience\" and \"histogram\"");
+
+	options->ignore_driver_algorithm = 1;
+
 	return 0;
 }
 
@@ -5256,7 +5291,6 @@ static int diff_opt_patience(const struct option *opt,
 
 	BUG_ON_OPT_NEG(unset);
 	BUG_ON_OPT_ARG(arg);
-	options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
 	/*
 	 * Both --patience and --anchored use PATIENCE_DIFF
 	 * internally, so remove any anchors previously
@@ -5265,7 +5299,9 @@ static int diff_opt_patience(const struct option *opt,
 	for (i = 0; i < options->anchors_nr; i++)
 		free(options->anchors[i]);
 	options->anchors_nr = 0;
-	return 0;
+	options->ignore_driver_algorithm = 1;
+
+	return set_diff_algorithm(options, "patience");
 }
 
 static int diff_opt_ignore_regex(const struct option *opt,
@@ -5415,7 +5451,8 @@ static int diff_opt_rotate_to(const struct option *opt, const char *arg, int uns
 	return 0;
 }
 
-static void prep_parse_options(struct diff_options *options)
+struct option *add_diff_options(const struct option *opts,
+				struct diff_options *options)
 {
 	struct option parseopts[] = {
 		OPT_GROUP(N_("Diff output format options")),
@@ -5567,9 +5604,10 @@ static void prep_parse_options(struct diff_options *options)
 			    N_("prevent rename/copy detection if the number of rename/copy targets exceeds given limit")),
 
 		OPT_GROUP(N_("Diff algorithm options")),
-		OPT_BIT(0, "minimal", &options->xdl_opts,
-			N_("produce the smallest possible diff"),
-			XDF_NEED_MINIMAL),
+		OPT_CALLBACK_F(0, "minimal", options, NULL,
+			       N_("produce the smallest possible diff"),
+			       PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+			       diff_opt_diff_algorithm_no_arg),
 		OPT_BIT_F('w', "ignore-all-space", &options->xdl_opts,
 			  N_("ignore whitespace when comparing lines"),
 			  XDF_IGNORE_WHITESPACE, PARSE_OPT_NONEG),
@@ -5595,9 +5633,10 @@ static void prep_parse_options(struct diff_options *options)
 			       N_("generate diff using the \"patience diff\" algorithm"),
 			       PARSE_OPT_NONEG | PARSE_OPT_NOARG,
 			       diff_opt_patience),
-		OPT_BITOP(0, "histogram", &options->xdl_opts,
-			  N_("generate diff using the \"histogram diff\" algorithm"),
-			  XDF_HISTOGRAM_DIFF, XDF_DIFF_ALGORITHM_MASK),
+		OPT_CALLBACK_F(0, "histogram", options, NULL,
+			       N_("generate diff using the \"histogram diff\" algorithm"),
+			       PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+			       diff_opt_diff_algorithm_no_arg),
 		OPT_CALLBACK_F(0, "diff-algorithm", options, N_("<algorithm>"),
 			       N_("choose a diff algorithm"),
 			       PARSE_OPT_NONEG, diff_opt_diff_algorithm),
@@ -5685,22 +5724,25 @@ static void prep_parse_options(struct diff_options *options)
 		OPT_END()
 	};
 
-	ALLOC_ARRAY(options->parseopts, ARRAY_SIZE(parseopts));
-	memcpy(options->parseopts, parseopts, sizeof(parseopts));
+	return parse_options_concat(opts, parseopts);
 }
 
 int diff_opt_parse(struct diff_options *options,
 		   const char **av, int ac, const char *prefix)
 {
+	struct option no_options[] = { OPT_END() };
+	struct option *parseopts = add_diff_options(no_options, options);
+
 	if (!prefix)
 		prefix = "";
 
-	ac = parse_options(ac, av, prefix, options->parseopts, NULL,
+	ac = parse_options(ac, av, prefix, parseopts, NULL,
 			   PARSE_OPT_KEEP_DASHDASH |
 			   PARSE_OPT_KEEP_UNKNOWN_OPT |
 			   PARSE_OPT_NO_INTERNAL_HELP |
 			   PARSE_OPT_ONE_SHOT |
 			   PARSE_OPT_STOP_AT_NON_OPTION);
+	free(parseopts);
 
 	return ac;
 }
@@ -6509,7 +6551,6 @@ void diff_free(struct diff_options *options)
 	diff_free_file(options);
 	diff_free_ignore_regex(options);
 	clear_pathspec(&options->pathspec);
-	FREE_AND_NULL(options->parseopts);
 }
 
 void diff_flush(struct diff_options *options)
diff --git a/diff.h b/diff.h
index fd33cae..8d770b1 100644
--- a/diff.h
+++ b/diff.h
@@ -333,6 +333,7 @@ struct diff_options {
 	int prefix_length;
 	const char *stat_sep;
 	int xdl_opts;
+	int ignore_driver_algorithm;
 
 	/* see Documentation/diff-options.txt */
 	char **anchors;
@@ -394,7 +395,6 @@ struct diff_options {
 	unsigned color_moved_ws_handling;
 
 	struct repository *repo;
-	struct option *parseopts;
 	struct strmap *additional_path_headers;
 
 	int no_free;
@@ -539,6 +539,7 @@ int git_diff_ui_config(const char *var, const char *value, void *cb);
 #define diff_setup(diffopts) repo_diff_setup(the_repository, diffopts)
 #endif
 void repo_diff_setup(struct repository *, struct diff_options *);
+struct option *add_diff_options(const struct option *, struct diff_options *);
 int diff_opt_parse(struct diff_options *, const char **, int, const char *);
 void diff_setup_done(struct diff_options *);
 int git_config_rename(const char *var, const char *value);
diff --git a/dir-iterator.c b/dir-iterator.c
index 3764dd8..cedd304 100644
--- a/dir-iterator.c
+++ b/dir-iterator.c
@@ -112,10 +112,7 @@ static int prepare_next_entry_data(struct dir_iterator_int *iter,
 	iter->base.basename = iter->base.path.buf +
 			      iter->levels[iter->levels_nr - 1].prefix_len;
 
-	if (iter->flags & DIR_ITERATOR_FOLLOW_SYMLINKS)
-		err = stat(iter->base.path.buf, &iter->base.st);
-	else
-		err = lstat(iter->base.path.buf, &iter->base.st);
+	err = lstat(iter->base.path.buf, &iter->base.st);
 
 	saved_errno = errno;
 	if (err && errno != ENOENT)
@@ -213,13 +210,10 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags)
 	iter->flags = flags;
 
 	/*
-	 * Note: stat/lstat already checks for NULL or empty strings and
+	 * Note: lstat already checks for NULL or empty strings and
 	 * nonexistent paths.
 	 */
-	if (iter->flags & DIR_ITERATOR_FOLLOW_SYMLINKS)
-		err = stat(iter->base.path.buf, &iter->base.st);
-	else
-		err = lstat(iter->base.path.buf, &iter->base.st);
+	err = lstat(iter->base.path.buf, &iter->base.st);
 
 	if (err < 0) {
 		saved_errno = errno;
diff --git a/dir-iterator.h b/dir-iterator.h
index e3b6ff2..479e1ec 100644
--- a/dir-iterator.h
+++ b/dir-iterator.h
@@ -54,24 +54,8 @@
  *   and ITER_ERROR is returned immediately. In both cases, a meaningful
  *   warning is emitted. Note: ENOENT errors are always ignored so that
  *   the API users may remove files during iteration.
- *
- * - DIR_ITERATOR_FOLLOW_SYMLINKS: make dir-iterator follow symlinks.
- *   i.e., linked directories' contents will be iterated over and
- *   iter->base.st will contain information on the referred files,
- *   not the symlinks themselves, which is the default behavior. Broken
- *   symlinks are ignored.
- *
- *   Note: setting DIR_ITERATOR_FOLLOW_SYMLINKS affects resolving the
- *   starting path as well (e.g., attempting to iterate starting at a
- *   symbolic link pointing to a directory without FOLLOW_SYMLINKS will
- *   result in an error).
- *
- * Warning: circular symlinks are also followed when
- * DIR_ITERATOR_FOLLOW_SYMLINKS is set. The iteration may end up with
- * an ELOOP if they happen and DIR_ITERATOR_PEDANTIC is set.
  */
 #define DIR_ITERATOR_PEDANTIC (1 << 0)
-#define DIR_ITERATOR_FOLLOW_SYMLINKS (1 << 1)
 
 struct dir_iterator {
 	/* The current path: */
@@ -88,9 +72,7 @@ struct dir_iterator {
 	const char *basename;
 
 	/*
-	 * The result of calling lstat() on path; or stat(), if the
-	 * DIR_ITERATOR_FOLLOW_SYMLINKS flag was set at
-	 * dir_iterator's initialization.
+	 * The result of calling lstat() on path.
 	 */
 	struct stat st;
 };
diff --git a/dir.c b/dir.c
index fd689bb..9036337 100644
--- a/dir.c
+++ b/dir.c
@@ -3600,8 +3600,12 @@ static void free_untracked(struct untracked_cache_dir *ucd)
 
 void free_untracked_cache(struct untracked_cache *uc)
 {
-	if (uc)
-		free_untracked(uc->root);
+	if (!uc)
+		return;
+
+	free(uc->exclude_per_dir_to_free);
+	strbuf_release(&uc->ident);
+	free_untracked(uc->root);
 	free(uc);
 }
 
@@ -3758,7 +3762,7 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
 		      next + offset + hashsz);
 	uc->dir_flags = get_be32(next + ouc_offset(dir_flags));
 	exclude_per_dir = (const char *)next + exclude_per_dir_offset;
-	uc->exclude_per_dir = xstrdup(exclude_per_dir);
+	uc->exclude_per_dir = uc->exclude_per_dir_to_free = xstrdup(exclude_per_dir);
 	/* NUL after exclude_per_dir is covered by sizeof(*ouc) */
 	next += exclude_per_dir_offset + strlen(exclude_per_dir) + 1;
 	if (next >= end)
diff --git a/dir.h b/dir.h
index 62e89a0..264a6e0 100644
--- a/dir.h
+++ b/dir.h
@@ -188,6 +188,7 @@ struct untracked_cache {
 	struct oid_stat ss_info_exclude;
 	struct oid_stat ss_excludes_file;
 	const char *exclude_per_dir;
+	char *exclude_per_dir_to_free;
 	struct strbuf ident;
 	/*
 	 * dir_struct#flags must match dir_flags or the untracked
diff --git a/entry.c b/entry.c
index 1d78e54..9e7dbe3 100644
--- a/entry.c
+++ b/entry.c
@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
 			return error("cannot create submodule directory %s", path);
 		sub = submodule_from_ce(ce);
 		if (sub)
-			return submodule_move_head(ce->name,
+			return submodule_move_head(ce->name, state->super_prefix,
 				NULL, oid_to_hex(&ce->oid),
 				state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
 		break;
@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 			 * no pathname to return.
 			 */
 			BUG("Can't remove entry to a path");
-		unlink_entry(ce);
+		unlink_entry(ce, state->super_prefix);
 		return 0;
 	}
 
@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 				if (!(st.st_mode & S_IFDIR))
 					unlink_or_warn(ce->name);
 
-				return submodule_move_head(ce->name,
+				return submodule_move_head(ce->name, state->super_prefix,
 					NULL, oid_to_hex(&ce->oid), 0);
 			} else
-				return submodule_move_head(ce->name,
+				return submodule_move_head(ce->name, state->super_prefix,
 					"HEAD", oid_to_hex(&ce->oid),
 					state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
 		}
@@ -574,12 +574,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 	return write_entry(ce, path.buf, ca, state, 0, nr_checkouts);
 }
 
-void unlink_entry(const struct cache_entry *ce)
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)
 {
 	const struct submodule *sub = submodule_from_ce(ce);
 	if (sub) {
 		/* state.force is set at the caller. */
-		submodule_move_head(ce->name, "HEAD", NULL,
+		submodule_move_head(ce->name, super_prefix, "HEAD", NULL,
 				    SUBMODULE_MOVE_HEAD_FORCE);
 	}
 	if (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)
diff --git a/entry.h b/entry.h
index 9be4659..2d4fbb8 100644
--- a/entry.h
+++ b/entry.h
@@ -8,6 +8,7 @@ struct checkout {
 	struct index_state *istate;
 	const char *base_dir;
 	int base_dir_len;
+	const char *super_prefix;
 	struct delayed_checkout *delayed_checkout;
 	struct checkout_metadata meta;
 	unsigned force:1,
@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);
 /*
  * Unlink the last component and schedule the leading directories for
  * removal, such that empty directories get removed.
+ *
+ * The "super_prefix" is either NULL, or the "--super-prefix" passed
+ * down from "read-tree" et al.
  */
-void unlink_entry(const struct cache_entry *ce);
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);
 
 void *read_blob_entry(const struct cache_entry *ce, size_t *size);
 int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);
diff --git a/environment.c b/environment.c
index 18d042b..1ee3686 100644
--- a/environment.c
+++ b/environment.c
@@ -102,8 +102,6 @@ char *git_work_tree_cfg;
 
 static char *git_namespace;
 
-static char *super_prefix;
-
 /*
  * Repository-local GIT_* environment variables; see cache.h for details.
  */
@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {
 	NO_REPLACE_OBJECTS_ENVIRONMENT,
 	GIT_REPLACE_REF_BASE_ENVIRONMENT,
 	GIT_PREFIX_ENVIRONMENT,
-	GIT_SUPER_PREFIX_ENVIRONMENT,
 	GIT_SHALLOW_FILE_ENVIRONMENT,
 	GIT_COMMON_DIR_ENVIRONMENT,
 	NULL
@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)
 	return NULL;
 }
 
-const char *get_super_prefix(void)
-{
-	static int initialized;
-	if (!initialized) {
-		super_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));
-		initialized = 1;
-	}
-	return super_prefix;
-}
-
 static int git_work_tree_initialized;
 
 /*
diff --git a/fsck.c b/fsck.c
index 47eaeed..2b18717 100644
--- a/fsck.c
+++ b/fsck.c
@@ -748,6 +748,23 @@ static int fsck_tree(const struct object_id *tree_oid,
 	return retval;
 }
 
+/*
+ * Confirm that the headers of a commit or tag object end in a reasonable way,
+ * either with the usual "\n\n" separator, or at least with a trailing newline
+ * on the final header line.
+ *
+ * This property is important for the memory safety of our callers. It allows
+ * them to scan the buffer linewise without constantly checking the remaining
+ * size as long as:
+ *
+ *   - they check that there are bytes left in the buffer at the start of any
+ *     line (i.e., that the last newline they saw was not the final one we
+ *     found here)
+ *
+ *   - any intra-line scanning they do will stop at a newline, which will worst
+ *     case hit the newline we found here as the end-of-header. This makes it
+ *     OK for them to use helpers like parse_oid_hex(), or even skip_prefix().
+ */
 static int verify_headers(const void *data, unsigned long size,
 			  const struct object_id *oid, enum object_type type,
 			  struct fsck_options *options)
@@ -808,6 +825,20 @@ static int fsck_ident(const char **ident,
 	if (*p != ' ')
 		return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
 	p++;
+	/*
+	 * Our timestamp parser is based on the C strto*() functions, which
+	 * will happily eat whitespace, including the newline that is supposed
+	 * to prevent us walking past the end of the buffer. So do our own
+	 * scan, skipping linear whitespace but not newlines, and then
+	 * confirming we found a digit. We _could_ be even more strict here,
+	 * as we really expect only a single space, but since we have
+	 * traditionally allowed extra whitespace, we'll continue to do so.
+	 */
+	while (*p == ' ' || *p == '\t')
+		p++;
+	if (!isdigit(*p))
+		return report(options, oid, type, FSCK_MSG_BAD_DATE,
+			      "invalid author/committer line - bad date");
 	if (*p == '0' && p[1] != ' ')
 		return report(options, oid, type, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
 	if (date_overflows(parse_timestamp(p, &end, 10)))
@@ -834,12 +865,18 @@ static int fsck_commit(const struct object_id *oid,
 	unsigned author_count;
 	int err;
 	const char *buffer_begin = buffer;
+	const char *buffer_end = buffer + size;
 	const char *p;
 
+	/*
+	 * We _must_ stop parsing immediately if this reports failure, as the
+	 * memory safety of the rest of the function depends on it. See the
+	 * comment above the definition of verify_headers() for more details.
+	 */
 	if (verify_headers(buffer, size, oid, OBJ_COMMIT, options))
 		return -1;
 
-	if (!skip_prefix(buffer, "tree ", &buffer))
+	if (buffer >= buffer_end || !skip_prefix(buffer, "tree ", &buffer))
 		return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
 	if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') {
 		err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
@@ -847,7 +884,7 @@ static int fsck_commit(const struct object_id *oid,
 			return err;
 	}
 	buffer = p + 1;
-	while (skip_prefix(buffer, "parent ", &buffer)) {
+	while (buffer < buffer_end && skip_prefix(buffer, "parent ", &buffer)) {
 		if (parse_oid_hex(buffer, &parent_oid, &p) || *p != '\n') {
 			err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
 			if (err)
@@ -856,7 +893,7 @@ static int fsck_commit(const struct object_id *oid,
 		buffer = p + 1;
 	}
 	author_count = 0;
-	while (skip_prefix(buffer, "author ", &buffer)) {
+	while (buffer < buffer_end && skip_prefix(buffer, "author ", &buffer)) {
 		author_count++;
 		err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
 		if (err)
@@ -868,7 +905,7 @@ static int fsck_commit(const struct object_id *oid,
 		err = report(options, oid, OBJ_COMMIT, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
 	if (err)
 		return err;
-	if (!skip_prefix(buffer, "committer ", &buffer))
+	if (buffer >= buffer_end || !skip_prefix(buffer, "committer ", &buffer))
 		return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
 	err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
 	if (err)
@@ -899,13 +936,19 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
 	int ret = 0;
 	char *eol;
 	struct strbuf sb = STRBUF_INIT;
+	const char *buffer_end = buffer + size;
 	const char *p;
 
+	/*
+	 * We _must_ stop parsing immediately if this reports failure, as the
+	 * memory safety of the rest of the function depends on it. See the
+	 * comment above the definition of verify_headers() for more details.
+	 */
 	ret = verify_headers(buffer, size, oid, OBJ_TAG, options);
 	if (ret)
 		goto done;
 
-	if (!skip_prefix(buffer, "object ", &buffer)) {
+	if (buffer >= buffer_end || !skip_prefix(buffer, "object ", &buffer)) {
 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
 		goto done;
 	}
@@ -916,11 +959,11 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
 	}
 	buffer = p + 1;
 
-	if (!skip_prefix(buffer, "type ", &buffer)) {
+	if (buffer >= buffer_end || !skip_prefix(buffer, "type ", &buffer)) {
 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
 		goto done;
 	}
-	eol = strchr(buffer, '\n');
+	eol = memchr(buffer, '\n', buffer_end - buffer);
 	if (!eol) {
 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
 		goto done;
@@ -932,11 +975,11 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
 		goto done;
 	buffer = eol + 1;
 
-	if (!skip_prefix(buffer, "tag ", &buffer)) {
+	if (buffer >= buffer_end || !skip_prefix(buffer, "tag ", &buffer)) {
 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
 		goto done;
 	}
-	eol = strchr(buffer, '\n');
+	eol = memchr(buffer, '\n', buffer_end - buffer);
 	if (!eol) {
 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line");
 		goto done;
@@ -952,7 +995,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
 	}
 	buffer = eol + 1;
 
-	if (!skip_prefix(buffer, "tagger ", &buffer)) {
+	if (buffer >= buffer_end || !skip_prefix(buffer, "tagger ", &buffer)) {
 		/* early tags do not contain 'tagger' lines; warn only */
 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
 		if (ret)
@@ -960,10 +1003,8 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
 	}
 	else
 		ret = fsck_ident(&buffer, oid, OBJ_TAG, options);
-	if (!*buffer)
-		goto done;
 
-	if (!starts_with(buffer, "\n")) {
+	if (buffer < buffer_end && !starts_with(buffer, "\n")) {
 		/*
 		 * The verify_headers() check will allow
 		 * e.g. "[...]tagger <tagger>\nsome
@@ -1237,19 +1278,26 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
 	if (!obj)
 		return report(options, NULL, OBJ_NONE, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
 
-	if (obj->type == OBJ_BLOB)
-		return fsck_blob(&obj->oid, data, size, options);
-	if (obj->type == OBJ_TREE)
-		return fsck_tree(&obj->oid, data, size, options);
-	if (obj->type == OBJ_COMMIT)
-		return fsck_commit(&obj->oid, data, size, options);
-	if (obj->type == OBJ_TAG)
-		return fsck_tag(&obj->oid, data, size, options);
+	return fsck_buffer(&obj->oid, obj->type, data, size, options);
+}
 
-	return report(options, &obj->oid, obj->type,
+int fsck_buffer(const struct object_id *oid, enum object_type type,
+		void *data, unsigned long size,
+		struct fsck_options *options)
+{
+	if (type == OBJ_BLOB)
+		return fsck_blob(oid, data, size, options);
+	if (type == OBJ_TREE)
+		return fsck_tree(oid, data, size, options);
+	if (type == OBJ_COMMIT)
+		return fsck_commit(oid, data, size, options);
+	if (type == OBJ_TAG)
+		return fsck_tag(oid, data, size, options);
+
+	return report(options, oid, type,
 		      FSCK_MSG_UNKNOWN_TYPE,
 		      "unknown type '%d' (internal fsck error)",
-		      obj->type);
+		      type);
 }
 
 int fsck_error_function(struct fsck_options *o,
diff --git a/fsck.h b/fsck.h
index fcecf41..6683308 100644
--- a/fsck.h
+++ b/fsck.h
@@ -184,6 +184,14 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
 	struct fsck_options *options);
 
 /*
+ * Same as fsck_object(), but for when the caller doesn't have an object
+ * struct.
+ */
+int fsck_buffer(const struct object_id *oid, enum object_type,
+		void *data, unsigned long size,
+		struct fsck_options *options);
+
+/*
  * fsck a tag, and pass info about it back to the caller. This is
  * exposed fsck_object() internals for git-mktag(1).
  */
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index ee63a97..899bfe9 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -143,8 +143,6 @@ static void lookup_fsmonitor_settings(struct repository *r)
 
 enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
 {
-	if (!r)
-		r = the_repository;
 	if (!r->settings.fsmonitor)
 		lookup_fsmonitor_settings(r);
 
@@ -153,8 +151,6 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
 
 const char *fsm_settings__get_hook_path(struct repository *r)
 {
-	if (!r)
-		r = the_repository;
 	if (!r->settings.fsmonitor)
 		lookup_fsmonitor_settings(r);
 
@@ -174,8 +170,6 @@ void fsm_settings__set_ipc(struct repository *r)
 	 * Caller requested IPC explicitly, so avoid (possibly
 	 * recursive) config lookup.
 	 */
-	if (!r)
-		r = the_repository;
 	if (!r->settings.fsmonitor)
 		r->settings.fsmonitor = alloc_settings();
 
@@ -197,8 +191,6 @@ void fsm_settings__set_hook(struct repository *r, const char *path)
 	 * Caller requested hook explicitly, so avoid (possibly
 	 * recursive) config lookup.
 	 */
-	if (!r)
-		r = the_repository;
 	if (!r->settings.fsmonitor)
 		r->settings.fsmonitor = alloc_settings();
 
@@ -210,8 +202,6 @@ void fsm_settings__set_hook(struct repository *r, const char *path)
 
 void fsm_settings__set_disabled(struct repository *r)
 {
-	if (!r)
-		r = the_repository;
 	if (!r->settings.fsmonitor)
 		r->settings.fsmonitor = alloc_settings();
 
@@ -223,8 +213,6 @@ void fsm_settings__set_disabled(struct repository *r)
 void fsm_settings__set_incompatible(struct repository *r,
 				    enum fsmonitor_reason reason)
 {
-	if (!r)
-		r = the_repository;
 	if (!r->settings.fsmonitor)
 		r->settings.fsmonitor = alloc_settings();
 
@@ -235,8 +223,6 @@ void fsm_settings__set_incompatible(struct repository *r,
 
 enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
 {
-	if (!r)
-		r = the_repository;
 	if (!r->settings.fsmonitor)
 		lookup_fsmonitor_settings(r);
 
diff --git a/fsmonitor.c b/fsmonitor.c
index 08af00c..a5b9e75 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -304,7 +304,7 @@ void refresh_fsmonitor(struct index_state *istate)
 	char *buf;
 	unsigned int i;
 	int is_trivial = 0;
-	struct repository *r = istate->repo ? istate->repo : the_repository;
+	struct repository *r = istate->repo;
 	enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
 	enum fsmonitor_reason reason = fsm_settings__get_reason(r);
 
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
deleted file mode 100755
index 95887fd..0000000
--- a/git-add--interactive.perl
+++ /dev/null
@@ -1,1920 +0,0 @@
-#!/usr/bin/perl
-
-use 5.008;
-use strict;
-use warnings;
-use Git qw(unquote_path);
-use Git::I18N;
-
-binmode(STDOUT, ":raw");
-
-my $repo = Git->repository();
-
-my $menu_use_color = $repo->get_colorbool('color.interactive');
-my ($prompt_color, $header_color, $help_color) =
-	$menu_use_color ? (
-		$repo->get_color('color.interactive.prompt', 'bold blue'),
-		$repo->get_color('color.interactive.header', 'bold'),
-		$repo->get_color('color.interactive.help', 'red bold'),
-	) : ();
-my $error_color = ();
-if ($menu_use_color) {
-	my $help_color_spec = ($repo->config('color.interactive.help') or
-				'red bold');
-	$error_color = $repo->get_color('color.interactive.error',
-					$help_color_spec);
-}
-
-my $diff_use_color = $repo->get_colorbool('color.diff');
-my ($fraginfo_color) =
-	$diff_use_color ? (
-		$repo->get_color('color.diff.frag', 'cyan'),
-	) : ();
-my ($diff_context_color) =
-	$diff_use_color ? (
-		$repo->get_color($repo->config('color.diff.context') ? 'color.diff.context' : 'color.diff.plain', ''),
-	) : ();
-my ($diff_old_color) =
-	$diff_use_color ? (
-		$repo->get_color('color.diff.old', 'red'),
-	) : ();
-my ($diff_new_color) =
-	$diff_use_color ? (
-		$repo->get_color('color.diff.new', 'green'),
-	) : ();
-
-my $normal_color = $repo->get_color("", "reset");
-
-my $diff_algorithm = $repo->config('diff.algorithm');
-my $diff_filter = $repo->config('interactive.difffilter');
-
-my $use_readkey = 0;
-my $use_termcap = 0;
-my %term_escapes;
-
-sub ReadMode;
-sub ReadKey;
-if ($repo->config_bool("interactive.singlekey")) {
-	eval {
-		require Term::ReadKey;
-		Term::ReadKey->import;
-		$use_readkey = 1;
-	};
-	if (!$use_readkey) {
-		print STDERR "missing Term::ReadKey, disabling interactive.singlekey\n";
-	}
-	eval {
-		require Term::Cap;
-		my $termcap = Term::Cap->Tgetent;
-		foreach (values %$termcap) {
-			$term_escapes{$_} = 1 if /^\e/;
-		}
-		$use_termcap = 1;
-	};
-}
-
-sub colored {
-	my $color = shift;
-	my $string = join("", @_);
-
-	if (defined $color) {
-		# Put a color code at the beginning of each line, a reset at the end
-		# color after newlines that are not at the end of the string
-		$string =~ s/(\n+)(.)/$1$color$2/g;
-		# reset before newlines
-		$string =~ s/(\n+)/$normal_color$1/g;
-		# codes at beginning and end (if necessary):
-		$string =~ s/^/$color/;
-		$string =~ s/$/$normal_color/ unless $string =~ /\n$/;
-	}
-	return $string;
-}
-
-# command line options
-my $patch_mode_only;
-my $patch_mode;
-my $patch_mode_revision;
-
-sub apply_patch;
-sub apply_patch_for_checkout_commit;
-sub apply_patch_for_stash;
-
-my %patch_modes = (
-	'stage' => {
-		DIFF => 'diff-files -p',
-		APPLY => sub { apply_patch 'apply --cached', @_; },
-		APPLY_CHECK => 'apply --cached',
-		FILTER => 'file-only',
-		IS_REVERSE => 0,
-	},
-	'stash' => {
-		DIFF => 'diff-index -p HEAD',
-		APPLY => sub { apply_patch 'apply --cached', @_; },
-		APPLY_CHECK => 'apply --cached',
-		FILTER => undef,
-		IS_REVERSE => 0,
-	},
-	'reset_head' => {
-		DIFF => 'diff-index -p --cached',
-		APPLY => sub { apply_patch 'apply -R --cached', @_; },
-		APPLY_CHECK => 'apply -R --cached',
-		FILTER => 'index-only',
-		IS_REVERSE => 1,
-	},
-	'reset_nothead' => {
-		DIFF => 'diff-index -R -p --cached',
-		APPLY => sub { apply_patch 'apply --cached', @_; },
-		APPLY_CHECK => 'apply --cached',
-		FILTER => 'index-only',
-		IS_REVERSE => 0,
-	},
-	'checkout_index' => {
-		DIFF => 'diff-files -p',
-		APPLY => sub { apply_patch 'apply -R', @_; },
-		APPLY_CHECK => 'apply -R',
-		FILTER => 'file-only',
-		IS_REVERSE => 1,
-	},
-	'checkout_head' => {
-		DIFF => 'diff-index -p',
-		APPLY => sub { apply_patch_for_checkout_commit '-R', @_ },
-		APPLY_CHECK => 'apply -R',
-		FILTER => undef,
-		IS_REVERSE => 1,
-	},
-	'checkout_nothead' => {
-		DIFF => 'diff-index -R -p',
-		APPLY => sub { apply_patch_for_checkout_commit '', @_ },
-		APPLY_CHECK => 'apply',
-		FILTER => undef,
-		IS_REVERSE => 0,
-	},
-	'worktree_head' => {
-		DIFF => 'diff-index -p',
-		APPLY => sub { apply_patch 'apply -R', @_ },
-		APPLY_CHECK => 'apply -R',
-		FILTER => undef,
-		IS_REVERSE => 1,
-	},
-	'worktree_nothead' => {
-		DIFF => 'diff-index -R -p',
-		APPLY => sub { apply_patch 'apply', @_ },
-		APPLY_CHECK => 'apply',
-		FILTER => undef,
-		IS_REVERSE => 0,
-	},
-);
-
-$patch_mode = 'stage';
-my %patch_mode_flavour = %{$patch_modes{$patch_mode}};
-
-sub run_cmd_pipe {
-	if ($^O eq 'MSWin32') {
-		my @invalid = grep {m/[":*]/} @_;
-		die "$^O does not support: @invalid\n" if @invalid;
-		my @args = map { m/ /o ? "\"$_\"": $_ } @_;
-		return qx{@args};
-	} else {
-		my $fh = undef;
-		open($fh, '-|', @_) or die;
-		my @out = <$fh>;
-		close $fh || die "Cannot close @_ ($!)";
-		return @out;
-	}
-}
-
-my ($GIT_DIR) = run_cmd_pipe(qw(git rev-parse --git-dir));
-
-if (!defined $GIT_DIR) {
-	exit(1); # rev-parse would have already said "not a git repo"
-}
-chomp($GIT_DIR);
-
-sub refresh {
-	my $fh;
-	open $fh, 'git update-index --refresh |'
-	    or die;
-	while (<$fh>) {
-		;# ignore 'needs update'
-	}
-	close $fh;
-}
-
-sub list_untracked {
-	map {
-		chomp $_;
-		unquote_path($_);
-	}
-	run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @ARGV);
-}
-
-# TRANSLATORS: you can adjust this to align "git add -i" status menu
-my $status_fmt = __('%12s %12s %s');
-my $status_head = sprintf($status_fmt, __('staged'), __('unstaged'), __('path'));
-
-{
-	my $initial;
-	sub is_initial_commit {
-		$initial = system('git rev-parse HEAD -- >/dev/null 2>&1') != 0
-			unless defined $initial;
-		return $initial;
-	}
-}
-
-{
-	my $empty_tree;
-	sub get_empty_tree {
-		return $empty_tree if defined $empty_tree;
-
-		($empty_tree) = run_cmd_pipe(qw(git hash-object -t tree /dev/null));
-		chomp $empty_tree;
-		return $empty_tree;
-	}
-}
-
-sub get_diff_reference {
-	my $ref = shift;
-	if (defined $ref and $ref ne 'HEAD') {
-		return $ref;
-	} elsif (is_initial_commit()) {
-		return get_empty_tree();
-	} else {
-		return 'HEAD';
-	}
-}
-
-# Returns list of hashes, contents of each of which are:
-# VALUE:	pathname
-# BINARY:	is a binary path
-# INDEX:	is index different from HEAD?
-# FILE:		is file different from index?
-# INDEX_ADDDEL:	is it add/delete between HEAD and index?
-# FILE_ADDDEL:	is it add/delete between index and file?
-# UNMERGED:	is the path unmerged
-
-sub list_modified {
-	my ($only) = @_;
-	my (%data, @return);
-	my ($add, $del, $adddel, $file);
-
-	my $reference = get_diff_reference($patch_mode_revision);
-	for (run_cmd_pipe(qw(git diff-index --cached
-			     --numstat --summary), $reference,
-			     '--', @ARGV)) {
-		if (($add, $del, $file) =
-		    /^([-\d]+)	([-\d]+)	(.*)/) {
-			my ($change, $bin);
-			$file = unquote_path($file);
-			if ($add eq '-' && $del eq '-') {
-				$change = __('binary');
-				$bin = 1;
-			}
-			else {
-				$change = "+$add/-$del";
-			}
-			$data{$file} = {
-				INDEX => $change,
-				BINARY => $bin,
-				FILE => __('nothing'),
-			}
-		}
-		elsif (($adddel, $file) =
-		       /^ (create|delete) mode [0-7]+ (.*)$/) {
-			$file = unquote_path($file);
-			$data{$file}{INDEX_ADDDEL} = $adddel;
-		}
-	}
-
-	for (run_cmd_pipe(qw(git diff-files --ignore-submodules=dirty --numstat --summary --raw --), @ARGV)) {
-		if (($add, $del, $file) =
-		    /^([-\d]+)	([-\d]+)	(.*)/) {
-			$file = unquote_path($file);
-			my ($change, $bin);
-			if ($add eq '-' && $del eq '-') {
-				$change = __('binary');
-				$bin = 1;
-			}
-			else {
-				$change = "+$add/-$del";
-			}
-			$data{$file}{FILE} = $change;
-			if ($bin) {
-				$data{$file}{BINARY} = 1;
-			}
-		}
-		elsif (($adddel, $file) =
-		       /^ (create|delete) mode [0-7]+ (.*)$/) {
-			$file = unquote_path($file);
-			$data{$file}{FILE_ADDDEL} = $adddel;
-		}
-		elsif (/^:[0-7]+ [0-7]+ [0-9a-f]+ [0-9a-f]+ (.)	(.*)$/) {
-			$file = unquote_path($2);
-			if (!exists $data{$file}) {
-				$data{$file} = +{
-					INDEX => __('unchanged'),
-					BINARY => 0,
-				};
-			}
-			if ($1 eq 'U') {
-				$data{$file}{UNMERGED} = 1;
-			}
-		}
-	}
-
-	for (sort keys %data) {
-		my $it = $data{$_};
-
-		if ($only) {
-			if ($only eq 'index-only') {
-				next if ($it->{INDEX} eq __('unchanged'));
-			}
-			if ($only eq 'file-only') {
-				next if ($it->{FILE} eq __('nothing'));
-			}
-		}
-		push @return, +{
-			VALUE => $_,
-			%$it,
-		};
-	}
-	return @return;
-}
-
-sub find_unique {
-	my ($string, @stuff) = @_;
-	my $found = undef;
-	for (my $i = 0; $i < @stuff; $i++) {
-		my $it = $stuff[$i];
-		my $hit = undef;
-		if (ref $it) {
-			if ((ref $it) eq 'ARRAY') {
-				$it = $it->[0];
-			}
-			else {
-				$it = $it->{VALUE};
-			}
-		}
-		eval {
-			if ($it =~ /^$string/) {
-				$hit = 1;
-			};
-		};
-		if (defined $hit && defined $found) {
-			return undef;
-		}
-		if ($hit) {
-			$found = $i + 1;
-		}
-	}
-	return $found;
-}
-
-# inserts string into trie and updates count for each character
-sub update_trie {
-	my ($trie, $string) = @_;
-	foreach (split //, $string) {
-		$trie = $trie->{$_} ||= {COUNT => 0};
-		$trie->{COUNT}++;
-	}
-}
-
-# returns an array of tuples (prefix, remainder)
-sub find_unique_prefixes {
-	my @stuff = @_;
-	my @return = ();
-
-	# any single prefix exceeding the soft limit is omitted
-	# if any prefix exceeds the hard limit all are omitted
-	# 0 indicates no limit
-	my $soft_limit = 0;
-	my $hard_limit = 3;
-
-	# build a trie modelling all possible options
-	my %trie;
-	foreach my $print (@stuff) {
-		if ((ref $print) eq 'ARRAY') {
-			$print = $print->[0];
-		}
-		elsif ((ref $print) eq 'HASH') {
-			$print = $print->{VALUE};
-		}
-		update_trie(\%trie, $print);
-		push @return, $print;
-	}
-
-	# use the trie to find the unique prefixes
-	for (my $i = 0; $i < @return; $i++) {
-		my $ret = $return[$i];
-		my @letters = split //, $ret;
-		my %search = %trie;
-		my ($prefix, $remainder);
-		my $j;
-		for ($j = 0; $j < @letters; $j++) {
-			my $letter = $letters[$j];
-			if ($search{$letter}{COUNT} == 1) {
-				$prefix = substr $ret, 0, $j + 1;
-				$remainder = substr $ret, $j + 1;
-				last;
-			}
-			else {
-				my $prefix = substr $ret, 0, $j;
-				return ()
-				    if ($hard_limit && $j + 1 > $hard_limit);
-			}
-			%search = %{$search{$letter}};
-		}
-		if (ord($letters[0]) > 127 ||
-		    ($soft_limit && $j + 1 > $soft_limit)) {
-			$prefix = undef;
-			$remainder = $ret;
-		}
-		$return[$i] = [$prefix, $remainder];
-	}
-	return @return;
-}
-
-# filters out prefixes which have special meaning to list_and_choose()
-sub is_valid_prefix {
-	my $prefix = shift;
-	return (defined $prefix) &&
-	    !($prefix =~ /[\s,]/) && # separators
-	    !($prefix =~ /^-/) &&    # deselection
-	    !($prefix =~ /^\d+/) &&  # selection
-	    ($prefix ne '*') &&      # "all" wildcard
-	    ($prefix ne '?');        # prompt help
-}
-
-# given a prefix/remainder tuple return a string with the prefix highlighted
-# for now use square brackets; later might use ANSI colors (underline, bold)
-sub highlight_prefix {
-	my $prefix = shift;
-	my $remainder = shift;
-
-	if (!defined $prefix) {
-		return $remainder;
-	}
-
-	if (!is_valid_prefix($prefix)) {
-		return "$prefix$remainder";
-	}
-
-	if (!$menu_use_color) {
-		return "[$prefix]$remainder";
-	}
-
-	return "$prompt_color$prefix$normal_color$remainder";
-}
-
-sub error_msg {
-	print STDERR colored $error_color, @_;
-}
-
-sub list_and_choose {
-	my ($opts, @stuff) = @_;
-	my (@chosen, @return);
-	if (!@stuff) {
-	    return @return;
-	}
-	my $i;
-	my @prefixes = find_unique_prefixes(@stuff) unless $opts->{LIST_ONLY};
-
-      TOPLOOP:
-	while (1) {
-		my $last_lf = 0;
-
-		if ($opts->{HEADER}) {
-			my $indent = $opts->{LIST_FLAT} ? "" : "     ";
-			print colored $header_color, "$indent$opts->{HEADER}\n";
-		}
-		for ($i = 0; $i < @stuff; $i++) {
-			my $chosen = $chosen[$i] ? '*' : ' ';
-			my $print = $stuff[$i];
-			my $ref = ref $print;
-			my $highlighted = highlight_prefix(@{$prefixes[$i]})
-			    if @prefixes;
-			if ($ref eq 'ARRAY') {
-				$print = $highlighted || $print->[0];
-			}
-			elsif ($ref eq 'HASH') {
-				my $value = $highlighted || $print->{VALUE};
-				$print = sprintf($status_fmt,
-				    $print->{INDEX},
-				    $print->{FILE},
-				    $value);
-			}
-			else {
-				$print = $highlighted || $print;
-			}
-			printf("%s%2d: %s", $chosen, $i+1, $print);
-			if (($opts->{LIST_FLAT}) &&
-			    (($i + 1) % ($opts->{LIST_FLAT}))) {
-				print "\t";
-				$last_lf = 0;
-			}
-			else {
-				print "\n";
-				$last_lf = 1;
-			}
-		}
-		if (!$last_lf) {
-			print "\n";
-		}
-
-		return if ($opts->{LIST_ONLY});
-
-		print colored $prompt_color, $opts->{PROMPT};
-		if ($opts->{SINGLETON}) {
-			print "> ";
-		}
-		else {
-			print ">> ";
-		}
-		my $line = <STDIN>;
-		if (!$line) {
-			print "\n";
-			$opts->{ON_EOF}->() if $opts->{ON_EOF};
-			last;
-		}
-		chomp $line;
-		last if $line eq '';
-		if ($line eq '?') {
-			$opts->{SINGLETON} ?
-			    singleton_prompt_help_cmd() :
-			    prompt_help_cmd();
-			next TOPLOOP;
-		}
-		for my $choice (split(/[\s,]+/, $line)) {
-			my $choose = 1;
-			my ($bottom, $top);
-
-			# Input that begins with '-'; unchoose
-			if ($choice =~ s/^-//) {
-				$choose = 0;
-			}
-			# A range can be specified like 5-7 or 5-.
-			if ($choice =~ /^(\d+)-(\d*)$/) {
-				($bottom, $top) = ($1, length($2) ? $2 : 1 + @stuff);
-			}
-			elsif ($choice =~ /^\d+$/) {
-				$bottom = $top = $choice;
-			}
-			elsif ($choice eq '*') {
-				$bottom = 1;
-				$top = 1 + @stuff;
-			}
-			else {
-				$bottom = $top = find_unique($choice, @stuff);
-				if (!defined $bottom) {
-					error_msg sprintf(__("Huh (%s)?\n"), $choice);
-					next TOPLOOP;
-				}
-			}
-			if ($opts->{SINGLETON} && $bottom != $top) {
-				error_msg sprintf(__("Huh (%s)?\n"), $choice);
-				next TOPLOOP;
-			}
-			for ($i = $bottom-1; $i <= $top-1; $i++) {
-				next if (@stuff <= $i || $i < 0);
-				$chosen[$i] = $choose;
-			}
-		}
-		last if ($opts->{IMMEDIATE} || $line eq '*');
-	}
-	for ($i = 0; $i < @stuff; $i++) {
-		if ($chosen[$i]) {
-			push @return, $stuff[$i];
-		}
-	}
-	return @return;
-}
-
-sub singleton_prompt_help_cmd {
-	print colored $help_color, __ <<'EOF' ;
-Prompt help:
-1          - select a numbered item
-foo        - select item based on unique prefix
-           - (empty) select nothing
-EOF
-}
-
-sub prompt_help_cmd {
-	print colored $help_color, __ <<'EOF' ;
-Prompt help:
-1          - select a single item
-3-5        - select a range of items
-2-3,6-9    - select multiple ranges
-foo        - select item based on unique prefix
--...       - unselect specified items
-*          - choose all items
-           - (empty) finish selecting
-EOF
-}
-
-sub status_cmd {
-	list_and_choose({ LIST_ONLY => 1, HEADER => $status_head },
-			list_modified());
-	print "\n";
-}
-
-sub say_n_paths {
-	my $did = shift @_;
-	my $cnt = scalar @_;
-	if ($did eq 'added') {
-		printf(__n("added %d path\n", "added %d paths\n",
-			   $cnt), $cnt);
-	} elsif ($did eq 'updated') {
-		printf(__n("updated %d path\n", "updated %d paths\n",
-			   $cnt), $cnt);
-	} elsif ($did eq 'reverted') {
-		printf(__n("reverted %d path\n", "reverted %d paths\n",
-			   $cnt), $cnt);
-	} else {
-		printf(__n("touched %d path\n", "touched %d paths\n",
-			   $cnt), $cnt);
-	}
-}
-
-sub update_cmd {
-	my @mods = list_modified('file-only');
-	return if (!@mods);
-
-	my @update = list_and_choose({ PROMPT => __('Update'),
-				       HEADER => $status_head, },
-				     @mods);
-	if (@update) {
-		system(qw(git update-index --add --remove --),
-		       map { $_->{VALUE} } @update);
-		say_n_paths('updated', @update);
-	}
-	print "\n";
-}
-
-sub revert_cmd {
-	my @update = list_and_choose({ PROMPT => __('Revert'),
-				       HEADER => $status_head, },
-				     list_modified());
-	if (@update) {
-		if (is_initial_commit()) {
-			system(qw(git rm --cached),
-				map { $_->{VALUE} } @update);
-		}
-		else {
-			my @lines = run_cmd_pipe(qw(git ls-tree HEAD --),
-						 map { $_->{VALUE} } @update);
-			my $fh;
-			open $fh, '| git update-index --index-info'
-			    or die;
-			for (@lines) {
-				print $fh $_;
-			}
-			close($fh);
-			for (@update) {
-				if ($_->{INDEX_ADDDEL} &&
-				    $_->{INDEX_ADDDEL} eq 'create') {
-					system(qw(git update-index --force-remove --),
-					       $_->{VALUE});
-					printf(__("note: %s is untracked now.\n"), $_->{VALUE});
-				}
-			}
-		}
-		refresh();
-		say_n_paths('reverted', @update);
-	}
-	print "\n";
-}
-
-sub add_untracked_cmd {
-	my @add = list_and_choose({ PROMPT => __('Add untracked') },
-				  list_untracked());
-	if (@add) {
-		system(qw(git update-index --add --), @add);
-		say_n_paths('added', @add);
-	} else {
-		print __("No untracked files.\n");
-	}
-	print "\n";
-}
-
-sub run_git_apply {
-	my $cmd = shift;
-	my $fh;
-	open $fh, '| git ' . $cmd . " --allow-overlap";
-	print $fh @_;
-	return close $fh;
-}
-
-sub parse_diff {
-	my ($path) = @_;
-	my @diff_cmd = split(" ", $patch_mode_flavour{DIFF});
-	if (defined $diff_algorithm) {
-		splice @diff_cmd, 1, 0, "--diff-algorithm=${diff_algorithm}";
-	}
-	if (defined $patch_mode_revision) {
-		push @diff_cmd, get_diff_reference($patch_mode_revision);
-	}
-	my @diff = run_cmd_pipe("git", @diff_cmd, qw(--no-color --), $path);
-	my @colored = ();
-	if ($diff_use_color) {
-		my @display_cmd = ("git", @diff_cmd, qw(--color --), $path);
-		if (defined $diff_filter) {
-			# quotemeta is overkill, but sufficient for shell-quoting
-			my $diff = join(' ', map { quotemeta } @display_cmd);
-			@display_cmd = ("$diff | $diff_filter");
-		}
-
-		@colored = run_cmd_pipe(@display_cmd);
-	}
-	my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };
-
-	if (@colored && @colored != @diff) {
-		print STDERR
-		  "fatal: mismatched output from interactive.diffFilter\n",
-		  "hint: Your filter must maintain a one-to-one correspondence\n",
-		  "hint: between its input and output lines.\n";
-		exit 1;
-	}
-
-	for (my $i = 0; $i < @diff; $i++) {
-		if ($diff[$i] =~ /^@@ /) {
-			push @hunk, { TEXT => [], DISPLAY => [],
-				TYPE => 'hunk' };
-		}
-		push @{$hunk[-1]{TEXT}}, $diff[$i];
-		push @{$hunk[-1]{DISPLAY}},
-			(@colored ? $colored[$i] : $diff[$i]);
-	}
-	return @hunk;
-}
-
-sub parse_diff_header {
-	my $src = shift;
-
-	my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' };
-	my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' };
-	my $deletion = { TEXT => [], DISPLAY => [], TYPE => 'deletion' };
-	my $addition;
-
-	for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
-		if ($src->{TEXT}->[$i] =~ /^new file/) {
-			$addition = 1;
-			$head->{TYPE} = 'addition';
-		}
-		my $dest =
-		   $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ? $mode :
-		   $src->{TEXT}->[$i] =~ /^deleted file/ ? $deletion :
-		   $head;
-		push @{$dest->{TEXT}}, $src->{TEXT}->[$i];
-		push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i];
-	}
-	return ($head, $mode, $deletion, $addition);
-}
-
-sub hunk_splittable {
-	my ($text) = @_;
-
-	my @s = split_hunk($text);
-	return (1 < @s);
-}
-
-sub parse_hunk_header {
-	my ($line) = @_;
-	my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
-	    $line =~ /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
-	$o_cnt = 1 unless defined $o_cnt;
-	$n_cnt = 1 unless defined $n_cnt;
-	return ($o_ofs, $o_cnt, $n_ofs, $n_cnt);
-}
-
-sub format_hunk_header {
-	my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) = @_;
-	return ("@@ -$o_ofs" .
-		(($o_cnt != 1) ? ",$o_cnt" : '') .
-		" +$n_ofs" .
-		(($n_cnt != 1) ? ",$n_cnt" : '') .
-		" @@\n");
-}
-
-sub split_hunk {
-	my ($text, $display) = @_;
-	my @split = ();
-	if (!defined $display) {
-		$display = $text;
-	}
-	# If there are context lines in the middle of a hunk,
-	# it can be split, but we would need to take care of
-	# overlaps later.
-
-	my ($o_ofs, undef, $n_ofs) = parse_hunk_header($text->[0]);
-	my $hunk_start = 1;
-
-      OUTER:
-	while (1) {
-		my $next_hunk_start = undef;
-		my $i = $hunk_start - 1;
-		my $this = +{
-			TEXT => [],
-			DISPLAY => [],
-			TYPE => 'hunk',
-			OLD => $o_ofs,
-			NEW => $n_ofs,
-			OCNT => 0,
-			NCNT => 0,
-			ADDDEL => 0,
-			POSTCTX => 0,
-			USE => undef,
-		};
-
-		while (++$i < @$text) {
-			my $line = $text->[$i];
-			my $display = $display->[$i];
-			if ($line =~ /^\\/) {
-				push @{$this->{TEXT}}, $line;
-				push @{$this->{DISPLAY}}, $display;
-				next;
-			}
-			if ($line =~ /^ /) {
-				if ($this->{ADDDEL} &&
-				    !defined $next_hunk_start) {
-					# We have seen leading context and
-					# adds/dels and then here is another
-					# context, which is trailing for this
-					# split hunk and leading for the next
-					# one.
-					$next_hunk_start = $i;
-				}
-				push @{$this->{TEXT}}, $line;
-				push @{$this->{DISPLAY}}, $display;
-				$this->{OCNT}++;
-				$this->{NCNT}++;
-				if (defined $next_hunk_start) {
-					$this->{POSTCTX}++;
-				}
-				next;
-			}
-
-			# add/del
-			if (defined $next_hunk_start) {
-				# We are done with the current hunk and
-				# this is the first real change for the
-				# next split one.
-				$hunk_start = $next_hunk_start;
-				$o_ofs = $this->{OLD} + $this->{OCNT};
-				$n_ofs = $this->{NEW} + $this->{NCNT};
-				$o_ofs -= $this->{POSTCTX};
-				$n_ofs -= $this->{POSTCTX};
-				push @split, $this;
-				redo OUTER;
-			}
-			push @{$this->{TEXT}}, $line;
-			push @{$this->{DISPLAY}}, $display;
-			$this->{ADDDEL}++;
-			if ($line =~ /^-/) {
-				$this->{OCNT}++;
-			}
-			else {
-				$this->{NCNT}++;
-			}
-		}
-
-		push @split, $this;
-		last;
-	}
-
-	for my $hunk (@split) {
-		$o_ofs = $hunk->{OLD};
-		$n_ofs = $hunk->{NEW};
-		my $o_cnt = $hunk->{OCNT};
-		my $n_cnt = $hunk->{NCNT};
-
-		my $head = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
-		my $display_head = $head;
-		unshift @{$hunk->{TEXT}}, $head;
-		if ($diff_use_color) {
-			$display_head = colored($fraginfo_color, $head);
-		}
-		unshift @{$hunk->{DISPLAY}}, $display_head;
-	}
-	return @split;
-}
-
-sub find_last_o_ctx {
-	my ($it) = @_;
-	my $text = $it->{TEXT};
-	my ($o_ofs, $o_cnt) = parse_hunk_header($text->[0]);
-	my $i = @{$text};
-	my $last_o_ctx = $o_ofs + $o_cnt;
-	while (0 < --$i) {
-		my $line = $text->[$i];
-		if ($line =~ /^ /) {
-			$last_o_ctx--;
-			next;
-		}
-		last;
-	}
-	return $last_o_ctx;
-}
-
-sub merge_hunk {
-	my ($prev, $this) = @_;
-	my ($o0_ofs, $o0_cnt, $n0_ofs, $n0_cnt) =
-	    parse_hunk_header($prev->{TEXT}[0]);
-	my ($o1_ofs, $o1_cnt, $n1_ofs, $n1_cnt) =
-	    parse_hunk_header($this->{TEXT}[0]);
-
-	my (@line, $i, $ofs, $o_cnt, $n_cnt);
-	$ofs = $o0_ofs;
-	$o_cnt = $n_cnt = 0;
-	for ($i = 1; $i < @{$prev->{TEXT}}; $i++) {
-		my $line = $prev->{TEXT}[$i];
-		if ($line =~ /^\+/) {
-			$n_cnt++;
-			push @line, $line;
-			next;
-		} elsif ($line =~ /^\\/) {
-			push @line, $line;
-			next;
-		}
-
-		last if ($o1_ofs <= $ofs);
-
-		$o_cnt++;
-		$ofs++;
-		if ($line =~ /^ /) {
-			$n_cnt++;
-		}
-		push @line, $line;
-	}
-
-	for ($i = 1; $i < @{$this->{TEXT}}; $i++) {
-		my $line = $this->{TEXT}[$i];
-		if ($line =~ /^\+/) {
-			$n_cnt++;
-			push @line, $line;
-			next;
-		} elsif ($line =~ /^\\/) {
-			push @line, $line;
-			next;
-		}
-		$ofs++;
-		$o_cnt++;
-		if ($line =~ /^ /) {
-			$n_cnt++;
-		}
-		push @line, $line;
-	}
-	my $head = format_hunk_header($o0_ofs, $o_cnt, $n0_ofs, $n_cnt);
-	@{$prev->{TEXT}} = ($head, @line);
-}
-
-sub coalesce_overlapping_hunks {
-	my (@in) = @_;
-	my @out = ();
-
-	my ($last_o_ctx, $last_was_dirty);
-	my $ofs_delta = 0;
-
-	for (@in) {
-		if ($_->{TYPE} ne 'hunk') {
-			push @out, $_;
-			next;
-		}
-		my $text = $_->{TEXT};
-		my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
-						parse_hunk_header($text->[0]);
-		unless ($_->{USE}) {
-			$ofs_delta += $o_cnt - $n_cnt;
-			# If this hunk has been edited then subtract
-			# the delta that is due to the edit.
-			if ($_->{OFS_DELTA}) {
-				$ofs_delta -= $_->{OFS_DELTA};
-			}
-			next;
-		}
-		if ($ofs_delta) {
-			if ($patch_mode_flavour{IS_REVERSE}) {
-				$o_ofs -= $ofs_delta;
-			} else {
-				$n_ofs += $ofs_delta;
-			}
-			$_->{TEXT}->[0] = format_hunk_header($o_ofs, $o_cnt,
-							     $n_ofs, $n_cnt);
-		}
-		# If this hunk was edited then adjust the offset delta
-		# to reflect the edit.
-		if ($_->{OFS_DELTA}) {
-			$ofs_delta += $_->{OFS_DELTA};
-		}
-		if (defined $last_o_ctx &&
-		    $o_ofs <= $last_o_ctx &&
-		    !$_->{DIRTY} &&
-		    !$last_was_dirty) {
-			merge_hunk($out[-1], $_);
-		}
-		else {
-			push @out, $_;
-		}
-		$last_o_ctx = find_last_o_ctx($out[-1]);
-		$last_was_dirty = $_->{DIRTY};
-	}
-	return @out;
-}
-
-sub reassemble_patch {
-	my $head = shift;
-	my @patch;
-
-	# Include everything in the header except the beginning of the diff.
-	push @patch, (grep { !/^[-+]{3}/ } @$head);
-
-	# Then include any headers from the hunk lines, which must
-	# come before any actual hunk.
-	while (@_ && $_[0] !~ /^@/) {
-		push @patch, shift;
-	}
-
-	# Then begin the diff.
-	push @patch, grep { /^[-+]{3}/ } @$head;
-
-	# And then the actual hunks.
-	push @patch, @_;
-
-	return @patch;
-}
-
-sub color_diff {
-	return map {
-		colored((/^@/  ? $fraginfo_color :
-			 /^\+/ ? $diff_new_color :
-			 /^-/  ? $diff_old_color :
-			 $diff_context_color),
-			$_);
-	} @_;
-}
-
-my %edit_hunk_manually_modes = (
-	stage => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for staging."),
-	stash => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for stashing."),
-	reset_head => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for unstaging."),
-	reset_nothead => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for applying."),
-	checkout_index => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for discarding."),
-	checkout_head => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for discarding."),
-	checkout_nothead => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for applying."),
-	worktree_head => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for discarding."),
-	worktree_nothead => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for applying."),
-);
-
-sub recount_edited_hunk {
-	local $_;
-	my ($oldtext, $newtext) = @_;
-	my ($o_cnt, $n_cnt) = (0, 0);
-	for (@{$newtext}[1..$#{$newtext}]) {
-		my $mode = substr($_, 0, 1);
-		if ($mode eq '-') {
-			$o_cnt++;
-		} elsif ($mode eq '+') {
-			$n_cnt++;
-		} elsif ($mode eq ' ' or $mode eq "\n") {
-			$o_cnt++;
-			$n_cnt++;
-		}
-	}
-	my ($o_ofs, undef, $n_ofs, undef) =
-					parse_hunk_header($newtext->[0]);
-	$newtext->[0] = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
-	my (undef, $orig_o_cnt, undef, $orig_n_cnt) =
-					parse_hunk_header($oldtext->[0]);
-	# Return the change in the number of lines inserted by this hunk
-	return $orig_o_cnt - $orig_n_cnt - $o_cnt + $n_cnt;
-}
-
-sub edit_hunk_manually {
-	my ($oldtext) = @_;
-
-	my $hunkfile = $repo->repo_path . "/addp-hunk-edit.diff";
-	my $fh;
-	open $fh, '>', $hunkfile
-		or die sprintf(__("failed to open hunk edit file for writing: %s"), $!);
-	print $fh Git::comment_lines __("Manual hunk edit mode -- see bottom for a quick guide.\n");
-	print $fh @$oldtext;
-	my $is_reverse = $patch_mode_flavour{IS_REVERSE};
-	my ($remove_plus, $remove_minus) = $is_reverse ? ('-', '+') : ('+', '-');
-	my $comment_line_char = Git::get_comment_line_char;
-	print $fh Git::comment_lines sprintf(__ <<EOF, $remove_minus, $remove_plus, $comment_line_char),
----
-To remove '%s' lines, make them ' ' lines (context).
-To remove '%s' lines, delete them.
-Lines starting with %s will be removed.
-EOF
-__($edit_hunk_manually_modes{$patch_mode}),
-# TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
-__ <<EOF2 ;
-If it does not apply cleanly, you will be given an opportunity to
-edit again.  If all lines of the hunk are removed, then the edit is
-aborted and the hunk is left unchanged.
-EOF2
-	close $fh;
-
-	chomp(my ($editor) = run_cmd_pipe(qw(git var GIT_EDITOR)));
-	system('sh', '-c', $editor.' "$@"', $editor, $hunkfile);
-
-	if ($? != 0) {
-		return undef;
-	}
-
-	open $fh, '<', $hunkfile
-		or die sprintf(__("failed to open hunk edit file for reading: %s"), $!);
-	my @newtext = grep { !/^\Q$comment_line_char\E/ } <$fh>;
-	close $fh;
-	unlink $hunkfile;
-
-	# Abort if nothing remains
-	if (!grep { /\S/ } @newtext) {
-		return undef;
-	}
-
-	# Reinsert the first hunk header if the user accidentally deleted it
-	if ($newtext[0] !~ /^@/) {
-		unshift @newtext, $oldtext->[0];
-	}
-	return \@newtext;
-}
-
-sub diff_applies {
-	return run_git_apply($patch_mode_flavour{APPLY_CHECK} . ' --check',
-			     map { @{$_->{TEXT}} } @_);
-}
-
-sub _restore_terminal_and_die {
-	ReadMode 'restore';
-	print "\n";
-	exit 1;
-}
-
-sub prompt_single_character {
-	if ($use_readkey) {
-		local $SIG{TERM} = \&_restore_terminal_and_die;
-		local $SIG{INT} = \&_restore_terminal_and_die;
-		ReadMode 'cbreak';
-		my $key = ReadKey 0;
-		ReadMode 'restore';
-		if (defined $key) {
-			if ($use_termcap and $key eq "\e") {
-				while (!defined $term_escapes{$key}) {
-					my $next = ReadKey 0.5;
-					last if (!defined $next);
-					$key .= $next;
-				}
-				$key =~ s/\e/^[/;
-			}
-			print "$key";
-		}
-		print "\n";
-		return $key;
-	} else {
-		return <STDIN>;
-	}
-}
-
-sub prompt_yesno {
-	my ($prompt) = @_;
-	while (1) {
-		print colored $prompt_color, $prompt;
-		my $line = prompt_single_character;
-		return undef unless defined $line;
-		return 0 if $line =~ /^n/i;
-		return 1 if $line =~ /^y/i;
-	}
-}
-
-sub edit_hunk_loop {
-	my ($head, $hunks, $ix) = @_;
-	my $hunk = $hunks->[$ix];
-	my $text = $hunk->{TEXT};
-
-	while (1) {
-		my $newtext = edit_hunk_manually($text);
-		if (!defined $newtext) {
-			return undef;
-		}
-		my $newhunk = {
-			TEXT => $newtext,
-			TYPE => $hunk->{TYPE},
-			USE => 1,
-			DIRTY => 1,
-		};
-		$newhunk->{OFS_DELTA} = recount_edited_hunk($text, $newtext);
-		# If this hunk has already been edited then add the
-		# offset delta of the previous edit to get the real
-		# delta from the original unedited hunk.
-		$hunk->{OFS_DELTA} and
-				$newhunk->{OFS_DELTA} += $hunk->{OFS_DELTA};
-		if (diff_applies($head,
-				 @{$hunks}[0..$ix-1],
-				 $newhunk,
-				 @{$hunks}[$ix+1..$#{$hunks}])) {
-			$newhunk->{DISPLAY} = [color_diff(@{$newtext})];
-			return $newhunk;
-		}
-		else {
-			prompt_yesno(
-				# TRANSLATORS: do not translate [y/n]
-				# The program will only accept that input
-				# at this point.
-				# Consider translating (saying "no" discards!) as
-				# (saying "n" for "no" discards!) if the translation
-				# of the word "no" does not start with n.
-				__('Your edited hunk does not apply. Edit again '
-				   . '(saying "no" discards!) [y/n]? ')
-				) or return undef;
-		}
-	}
-}
-
-my %help_patch_modes = (
-	stage => N__(
-"y - stage this hunk
-n - do not stage this hunk
-q - quit; do not stage this hunk or any of the remaining ones
-a - stage this hunk and all later hunks in the file
-d - do not stage this hunk or any of the later hunks in the file"),
-	stash => N__(
-"y - stash this hunk
-n - do not stash this hunk
-q - quit; do not stash this hunk or any of the remaining ones
-a - stash this hunk and all later hunks in the file
-d - do not stash this hunk or any of the later hunks in the file"),
-	reset_head => N__(
-"y - unstage this hunk
-n - do not unstage this hunk
-q - quit; do not unstage this hunk or any of the remaining ones
-a - unstage this hunk and all later hunks in the file
-d - do not unstage this hunk or any of the later hunks in the file"),
-	reset_nothead => N__(
-"y - apply this hunk to index
-n - do not apply this hunk to index
-q - quit; do not apply this hunk or any of the remaining ones
-a - apply this hunk and all later hunks in the file
-d - do not apply this hunk or any of the later hunks in the file"),
-	checkout_index => N__(
-"y - discard this hunk from worktree
-n - do not discard this hunk from worktree
-q - quit; do not discard this hunk or any of the remaining ones
-a - discard this hunk and all later hunks in the file
-d - do not discard this hunk or any of the later hunks in the file"),
-	checkout_head => N__(
-"y - discard this hunk from index and worktree
-n - do not discard this hunk from index and worktree
-q - quit; do not discard this hunk or any of the remaining ones
-a - discard this hunk and all later hunks in the file
-d - do not discard this hunk or any of the later hunks in the file"),
-	checkout_nothead => N__(
-"y - apply this hunk to index and worktree
-n - do not apply this hunk to index and worktree
-q - quit; do not apply this hunk or any of the remaining ones
-a - apply this hunk and all later hunks in the file
-d - do not apply this hunk or any of the later hunks in the file"),
-	worktree_head => N__(
-"y - discard this hunk from worktree
-n - do not discard this hunk from worktree
-q - quit; do not discard this hunk or any of the remaining ones
-a - discard this hunk and all later hunks in the file
-d - do not discard this hunk or any of the later hunks in the file"),
-	worktree_nothead => N__(
-"y - apply this hunk to worktree
-n - do not apply this hunk to worktree
-q - quit; do not apply this hunk or any of the remaining ones
-a - apply this hunk and all later hunks in the file
-d - do not apply this hunk or any of the later hunks in the file"),
-);
-
-sub help_patch_cmd {
-	local $_;
-	my $other = $_[0] . ",?";
-	print colored $help_color, __($help_patch_modes{$patch_mode}), "\n",
-		map { "$_\n" } grep {
-			my $c = quotemeta(substr($_, 0, 1));
-			$other =~ /,$c/
-		} split "\n", __ <<EOF ;
-g - select a hunk to go to
-/ - search for a hunk matching the given regex
-j - leave this hunk undecided, see next undecided hunk
-J - leave this hunk undecided, see next hunk
-k - leave this hunk undecided, see previous undecided hunk
-K - leave this hunk undecided, see previous hunk
-s - split the current hunk into smaller hunks
-e - manually edit the current hunk
-? - print help
-EOF
-}
-
-sub apply_patch {
-	my $cmd = shift;
-	my $ret = run_git_apply $cmd, @_;
-	if (!$ret) {
-		print STDERR @_;
-	}
-	return $ret;
-}
-
-sub apply_patch_for_checkout_commit {
-	my $reverse = shift;
-	my $applies_index = run_git_apply 'apply '.$reverse.' --cached --check', @_;
-	my $applies_worktree = run_git_apply 'apply '.$reverse.' --check', @_;
-
-	if ($applies_worktree && $applies_index) {
-		run_git_apply 'apply '.$reverse.' --cached', @_;
-		run_git_apply 'apply '.$reverse, @_;
-		return 1;
-	} elsif (!$applies_index) {
-		print colored $error_color, __("The selected hunks do not apply to the index!\n");
-		if (prompt_yesno __("Apply them to the worktree anyway? ")) {
-			return run_git_apply 'apply '.$reverse, @_;
-		} else {
-			print colored $error_color, __("Nothing was applied.\n");
-			return 0;
-		}
-	} else {
-		print STDERR @_;
-		return 0;
-	}
-}
-
-sub patch_update_cmd {
-	my @all_mods = list_modified($patch_mode_flavour{FILTER});
-	error_msg sprintf(__("ignoring unmerged: %s\n"), $_->{VALUE})
-		for grep { $_->{UNMERGED} } @all_mods;
-	@all_mods = grep { !$_->{UNMERGED} } @all_mods;
-
-	my @mods = grep { !($_->{BINARY}) } @all_mods;
-	my @them;
-
-	if (!@mods) {
-		if (@all_mods) {
-			print STDERR __("Only binary files changed.\n");
-		} else {
-			print STDERR __("No changes.\n");
-		}
-		return 0;
-	}
-	if ($patch_mode_only) {
-		@them = @mods;
-	}
-	else {
-		@them = list_and_choose({ PROMPT => __('Patch update'),
-					  HEADER => $status_head, },
-					@mods);
-	}
-	for (@them) {
-		return 0 if patch_update_file($_->{VALUE});
-	}
-}
-
-# Generate a one line summary of a hunk.
-sub summarize_hunk {
-	my $rhunk = shift;
-	my $summary = $rhunk->{TEXT}[0];
-
-	# Keep the line numbers, discard extra context.
-	$summary =~ s/@@(.*?)@@.*/$1 /s;
-	$summary .= " " x (20 - length $summary);
-
-	# Add some user context.
-	for my $line (@{$rhunk->{TEXT}}) {
-		if ($line =~ m/^[+-].*\w/) {
-			$summary .= $line;
-			last;
-		}
-	}
-
-	chomp $summary;
-	return substr($summary, 0, 80) . "\n";
-}
-
-
-# Print a one-line summary of each hunk in the array ref in
-# the first argument, starting with the index in the 2nd.
-sub display_hunks {
-	my ($hunks, $i) = @_;
-	my $ctr = 0;
-	$i ||= 0;
-	for (; $i < @$hunks && $ctr < 20; $i++, $ctr++) {
-		my $status = " ";
-		if (defined $hunks->[$i]{USE}) {
-			$status = $hunks->[$i]{USE} ? "+" : "-";
-		}
-		printf "%s%2d: %s",
-			$status,
-			$i + 1,
-			summarize_hunk($hunks->[$i]);
-	}
-	return $i;
-}
-
-my %patch_update_prompt_modes = (
-	stage => {
-		mode => N__("Stage mode change [y,n,q,a,d%s,?]? "),
-		deletion => N__("Stage deletion [y,n,q,a,d%s,?]? "),
-		addition => N__("Stage addition [y,n,q,a,d%s,?]? "),
-		hunk => N__("Stage this hunk [y,n,q,a,d%s,?]? "),
-	},
-	stash => {
-		mode => N__("Stash mode change [y,n,q,a,d%s,?]? "),
-		deletion => N__("Stash deletion [y,n,q,a,d%s,?]? "),
-		addition => N__("Stash addition [y,n,q,a,d%s,?]? "),
-		hunk => N__("Stash this hunk [y,n,q,a,d%s,?]? "),
-	},
-	reset_head => {
-		mode => N__("Unstage mode change [y,n,q,a,d%s,?]? "),
-		deletion => N__("Unstage deletion [y,n,q,a,d%s,?]? "),
-		addition => N__("Unstage addition [y,n,q,a,d%s,?]? "),
-		hunk => N__("Unstage this hunk [y,n,q,a,d%s,?]? "),
-	},
-	reset_nothead => {
-		mode => N__("Apply mode change to index [y,n,q,a,d%s,?]? "),
-		deletion => N__("Apply deletion to index [y,n,q,a,d%s,?]? "),
-		addition => N__("Apply addition to index [y,n,q,a,d%s,?]? "),
-		hunk => N__("Apply this hunk to index [y,n,q,a,d%s,?]? "),
-	},
-	checkout_index => {
-		mode => N__("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
-		deletion => N__("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
-		addition => N__("Discard addition from worktree [y,n,q,a,d%s,?]? "),
-		hunk => N__("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
-	},
-	checkout_head => {
-		mode => N__("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
-		deletion => N__("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
-		addition => N__("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
-		hunk => N__("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
-	},
-	checkout_nothead => {
-		mode => N__("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
-		deletion => N__("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
-		addition => N__("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
-		hunk => N__("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
-	},
-	worktree_head => {
-		mode => N__("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
-		deletion => N__("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
-		addition => N__("Discard addition from worktree [y,n,q,a,d%s,?]? "),
-		hunk => N__("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
-	},
-	worktree_nothead => {
-		mode => N__("Apply mode change to worktree [y,n,q,a,d%s,?]? "),
-		deletion => N__("Apply deletion to worktree [y,n,q,a,d%s,?]? "),
-		addition => N__("Apply addition to worktree [y,n,q,a,d%s,?]? "),
-		hunk => N__("Apply this hunk to worktree [y,n,q,a,d%s,?]? "),
-	},
-);
-
-sub patch_update_file {
-	my $quit = 0;
-	my ($ix, $num);
-	my $path = shift;
-	my ($head, @hunk) = parse_diff($path);
-	($head, my $mode, my $deletion, my $addition) = parse_diff_header($head);
-	for (@{$head->{DISPLAY}}) {
-		print;
-	}
-
-	if (@{$mode->{TEXT}}) {
-		unshift @hunk, $mode;
-	}
-	if (@{$deletion->{TEXT}}) {
-		foreach my $hunk (@hunk) {
-			push @{$deletion->{TEXT}}, @{$hunk->{TEXT}};
-			push @{$deletion->{DISPLAY}}, @{$hunk->{DISPLAY}};
-		}
-		@hunk = ($deletion);
-	}
-
-	$num = scalar @hunk;
-	$ix = 0;
-
-	while (1) {
-		my ($prev, $next, $other, $undecided, $i);
-		$other = '';
-
-		last if ($ix and !$num);
-		if ($num <= $ix) {
-			$ix = 0;
-		}
-		for ($i = 0; $i < $ix; $i++) {
-			if (!defined $hunk[$i]{USE}) {
-				$prev = 1;
-				$other .= ',k';
-				last;
-			}
-		}
-		if ($ix) {
-			$other .= ',K';
-		}
-		for ($i = $ix + 1; $i < $num; $i++) {
-			if (!defined $hunk[$i]{USE}) {
-				$next = 1;
-				$other .= ',j';
-				last;
-			}
-		}
-		if ($ix < $num - 1) {
-			$other .= ',J';
-		}
-		if ($num > 1) {
-			$other .= ',g,/';
-		}
-		for ($i = 0; $i < $num; $i++) {
-			if (!defined $hunk[$i]{USE}) {
-				$undecided = 1;
-				last;
-			}
-		}
-		last if (!$undecided && ($num || !$addition));
-
-		if ($num) {
-			if ($hunk[$ix]{TYPE} eq 'hunk' &&
-			    hunk_splittable($hunk[$ix]{TEXT})) {
-				$other .= ',s';
-			}
-			if ($hunk[$ix]{TYPE} eq 'hunk') {
-				$other .= ',e';
-			}
-			for (@{$hunk[$ix]{DISPLAY}}) {
-				print;
-			}
-		}
-		my $type = $num ? $hunk[$ix]{TYPE} : $head->{TYPE};
-		print colored $prompt_color, "(", ($ix+1), "/", ($num ? $num : 1), ") ",
-			sprintf(__($patch_update_prompt_modes{$patch_mode}{$type}), $other);
-
-		my $line = prompt_single_character;
-		last unless defined $line;
-		if ($line) {
-			if ($line =~ /^y/i) {
-				if ($num) {
-					$hunk[$ix]{USE} = 1;
-				} else {
-					$head->{USE} = 1;
-				}
-			}
-			elsif ($line =~ /^n/i) {
-				if ($num) {
-					$hunk[$ix]{USE} = 0;
-				} else {
-					$head->{USE} = 0;
-				}
-			}
-			elsif ($line =~ /^a/i) {
-				if ($num) {
-					while ($ix < $num) {
-						if (!defined $hunk[$ix]{USE}) {
-							$hunk[$ix]{USE} = 1;
-						}
-						$ix++;
-					}
-				} else {
-					$head->{USE} = 1;
-					$ix++;
-				}
-				next;
-			}
-			elsif ($line =~ /^g(.*)/) {
-				my $response = $1;
-				unless ($other =~ /g/) {
-					error_msg __("No other hunks to goto\n");
-					next;
-				}
-				my $no = $ix > 10 ? $ix - 10 : 0;
-				while ($response eq '') {
-					$no = display_hunks(\@hunk, $no);
-					if ($no < $num) {
-						print __("go to which hunk (<ret> to see more)? ");
-					} else {
-						print __("go to which hunk? ");
-					}
-					$response = <STDIN>;
-					if (!defined $response) {
-						$response = '';
-					}
-					chomp $response;
-				}
-				if ($response !~ /^\s*\d+\s*$/) {
-					error_msg sprintf(__("Invalid number: '%s'\n"),
-							     $response);
-				} elsif (0 < $response && $response <= $num) {
-					$ix = $response - 1;
-				} else {
-					error_msg sprintf(__n("Sorry, only %d hunk available.\n",
-							      "Sorry, only %d hunks available.\n", $num), $num);
-				}
-				next;
-			}
-			elsif ($line =~ /^d/i) {
-				if ($num) {
-					while ($ix < $num) {
-						if (!defined $hunk[$ix]{USE}) {
-							$hunk[$ix]{USE} = 0;
-						}
-						$ix++;
-					}
-				} else {
-					$head->{USE} = 0;
-					$ix++;
-				}
-				next;
-			}
-			elsif ($line =~ /^q/i) {
-				if ($num) {
-					for ($i = 0; $i < $num; $i++) {
-						if (!defined $hunk[$i]{USE}) {
-							$hunk[$i]{USE} = 0;
-						}
-					}
-				} elsif (!defined $head->{USE}) {
-					$head->{USE} = 0;
-				}
-				$quit = 1;
-				last;
-			}
-			elsif ($line =~ m|^/(.*)|) {
-				my $regex = $1;
-				unless ($other =~ m|/|) {
-					error_msg __("No other hunks to search\n");
-					next;
-				}
-				if ($regex eq "") {
-					print colored $prompt_color, __("search for regex? ");
-					$regex = <STDIN>;
-					if (defined $regex) {
-						chomp $regex;
-					}
-				}
-				my $search_string;
-				eval {
-					$search_string = qr{$regex}m;
-				};
-				if ($@) {
-					my ($err,$exp) = ($@, $1);
-					$err =~ s/ at .*git-add--interactive line \d+, <STDIN> line \d+.*$//;
-					error_msg sprintf(__("Malformed search regexp %s: %s\n"), $exp, $err);
-					next;
-				}
-				my $iy = $ix;
-				while (1) {
-					my $text = join ("", @{$hunk[$iy]{TEXT}});
-					last if ($text =~ $search_string);
-					$iy++;
-					$iy = 0 if ($iy >= $num);
-					if ($ix == $iy) {
-						error_msg __("No hunk matches the given pattern\n");
-						last;
-					}
-				}
-				$ix = $iy;
-				next;
-			}
-			elsif ($line =~ /^K/) {
-				if ($other =~ /K/) {
-					$ix--;
-				}
-				else {
-					error_msg __("No previous hunk\n");
-				}
-				next;
-			}
-			elsif ($line =~ /^J/) {
-				if ($other =~ /J/) {
-					$ix++;
-				}
-				else {
-					error_msg __("No next hunk\n");
-				}
-				next;
-			}
-			elsif ($line =~ /^k/) {
-				if ($other =~ /k/) {
-					while (1) {
-						$ix--;
-						last if (!$ix ||
-							 !defined $hunk[$ix]{USE});
-					}
-				}
-				else {
-					error_msg __("No previous hunk\n");
-				}
-				next;
-			}
-			elsif ($line =~ /^j/) {
-				if ($other !~ /j/) {
-					error_msg __("No next hunk\n");
-					next;
-				}
-			}
-			elsif ($line =~ /^s/) {
-				unless ($other =~ /s/) {
-					error_msg __("Sorry, cannot split this hunk\n");
-					next;
-				}
-				my @split = split_hunk($hunk[$ix]{TEXT}, $hunk[$ix]{DISPLAY});
-				if (1 < @split) {
-					print colored $header_color, sprintf(
-						__n("Split into %d hunk.\n",
-						    "Split into %d hunks.\n",
-						    scalar(@split)), scalar(@split));
-				}
-				splice (@hunk, $ix, 1, @split);
-				$num = scalar @hunk;
-				next;
-			}
-			elsif ($line =~ /^e/) {
-				unless ($other =~ /e/) {
-					error_msg __("Sorry, cannot edit this hunk\n");
-					next;
-				}
-				my $newhunk = edit_hunk_loop($head, \@hunk, $ix);
-				if (defined $newhunk) {
-					splice @hunk, $ix, 1, $newhunk;
-				}
-			}
-			else {
-				help_patch_cmd($other);
-				next;
-			}
-			# soft increment
-			while (1) {
-				$ix++;
-				last if ($ix >= $num ||
-					 !defined $hunk[$ix]{USE});
-			}
-		}
-	}
-
-	@hunk = coalesce_overlapping_hunks(@hunk) if ($num);
-
-	my $n_lofs = 0;
-	my @result = ();
-	for (@hunk) {
-		if ($_->{USE}) {
-			push @result, @{$_->{TEXT}};
-		}
-	}
-
-	if (@result or $head->{USE}) {
-		my @patch = reassemble_patch($head->{TEXT}, @result);
-		my $apply_routine = $patch_mode_flavour{APPLY};
-		&$apply_routine(@patch);
-		refresh();
-	}
-
-	print "\n";
-	return $quit;
-}
-
-sub diff_cmd {
-	my @mods = list_modified('index-only');
-	@mods = grep { !($_->{BINARY}) } @mods;
-	return if (!@mods);
-	my (@them) = list_and_choose({ PROMPT => __('Review diff'),
-				     IMMEDIATE => 1,
-				     HEADER => $status_head, },
-				   @mods);
-	return if (!@them);
-	my $reference = (is_initial_commit()) ? get_empty_tree() : 'HEAD';
-	system(qw(git diff -p --cached), $reference, '--',
-		map { $_->{VALUE} } @them);
-}
-
-sub quit_cmd {
-	print __("Bye.\n");
-	exit(0);
-}
-
-sub help_cmd {
-# TRANSLATORS: please do not translate the command names
-# 'status', 'update', 'revert', etc.
-	print colored $help_color, __ <<'EOF' ;
-status        - show paths with changes
-update        - add working tree state to the staged set of changes
-revert        - revert staged set of changes back to the HEAD version
-patch         - pick hunks and update selectively
-diff          - view diff between HEAD and index
-add untracked - add contents of untracked files to the staged set of changes
-EOF
-}
-
-sub process_args {
-	return unless @ARGV;
-	my $arg = shift @ARGV;
-	if ($arg =~ /--patch(?:=(.*))?/) {
-		if (defined $1) {
-			if ($1 eq 'reset') {
-				$patch_mode = 'reset_head';
-				$patch_mode_revision = 'HEAD';
-				$arg = shift @ARGV or die __("missing --");
-				if ($arg ne '--') {
-					$patch_mode_revision = $arg;
-
-					# NEEDSWORK: Instead of comparing to the literal "HEAD",
-					# compare the commit objects instead so that other ways of
-					# saying the same thing (such as "@") are also handled
-					# appropriately.
-					#
-					# This applies to the cases below too.
-					$patch_mode = ($arg eq 'HEAD' ?
-						       'reset_head' : 'reset_nothead');
-					$arg = shift @ARGV or die __("missing --");
-				}
-			} elsif ($1 eq 'checkout') {
-				$arg = shift @ARGV or die __("missing --");
-				if ($arg eq '--') {
-					$patch_mode = 'checkout_index';
-				} else {
-					$patch_mode_revision = $arg;
-					$patch_mode = ($arg eq 'HEAD' ?
-						       'checkout_head' : 'checkout_nothead');
-					$arg = shift @ARGV or die __("missing --");
-				}
-			} elsif ($1 eq 'worktree') {
-				$arg = shift @ARGV or die __("missing --");
-				if ($arg eq '--') {
-					$patch_mode = 'checkout_index';
-				} else {
-					$patch_mode_revision = $arg;
-					$patch_mode = ($arg eq 'HEAD' ?
-						       'worktree_head' : 'worktree_nothead');
-					$arg = shift @ARGV or die __("missing --");
-				}
-			} elsif ($1 eq 'stage' or $1 eq 'stash') {
-				$patch_mode = $1;
-				$arg = shift @ARGV or die __("missing --");
-			} else {
-				die sprintf(__("unknown --patch mode: %s"), $1);
-			}
-		} else {
-			$patch_mode = 'stage';
-			$arg = shift @ARGV or die __("missing --");
-		}
-		die sprintf(__("invalid argument %s, expecting --"),
-			       $arg) unless $arg eq "--";
-		%patch_mode_flavour = %{$patch_modes{$patch_mode}};
-		$patch_mode_only = 1;
-	}
-	elsif ($arg ne "--") {
-		die sprintf(__("invalid argument %s, expecting --"), $arg);
-	}
-}
-
-sub main_loop {
-	my @cmd = ([ 'status', \&status_cmd, ],
-		   [ 'update', \&update_cmd, ],
-		   [ 'revert', \&revert_cmd, ],
-		   [ 'add untracked', \&add_untracked_cmd, ],
-		   [ 'patch', \&patch_update_cmd, ],
-		   [ 'diff', \&diff_cmd, ],
-		   [ 'quit', \&quit_cmd, ],
-		   [ 'help', \&help_cmd, ],
-	);
-	while (1) {
-		my ($it) = list_and_choose({ PROMPT => __('What now'),
-					     SINGLETON => 1,
-					     LIST_FLAT => 4,
-					     HEADER => __('*** Commands ***'),
-					     ON_EOF => \&quit_cmd,
-					     IMMEDIATE => 1 }, @cmd);
-		if ($it) {
-			eval {
-				$it->[1]->();
-			};
-			if ($@) {
-				print "$@";
-			}
-		}
-	}
-}
-
-process_args();
-refresh();
-if ($patch_mode_only) {
-	patch_update_cmd();
-}
-else {
-	status_cmd();
-	main_loop();
-}
diff --git a/git-bisect.sh b/git-bisect.sh
deleted file mode 100755
index dfce4b4..0000000
--- a/git-bisect.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-
-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-{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/
-		a revision after change in a given property.
-git bisect (good|old) [<rev>...]
-	mark <rev>... known-good revisions/
-		revisions before change in a given property.
-git bisect terms [--term-good | --term-bad]
-	show the terms used for old and new commits (default: bad, good)
-git bisect skip [(<rev>|<range>)...]
-	mark <rev>... untestable revisions.
-git bisect next
-	find next bisection to test and check it out.
-git bisect reset [<commit>]
-	finish bisection search and go back to commit.
-git bisect (visualize|view)
-	show bisect status in gitk.
-git bisect replay <logfile>
-	replay bisection log.
-git bisect log
-	show bisect log.
-git bisect run <cmd>...
-	use <cmd>... to automatically bisect.
-
-Please use "git help bisect" to get the full man page.'
-
-OPTIONS_SPEC=
-. git-sh-setup
-
-TERM_BAD=bad
-TERM_GOOD=good
-
-get_terms () {
-	if test -s "$GIT_DIR/BISECT_TERMS"
-	then
-		{
-		read TERM_BAD
-		read TERM_GOOD
-		} <"$GIT_DIR/BISECT_TERMS"
-	fi
-}
-
-case "$#" in
-0)
-	usage ;;
-*)
-	cmd="$1"
-	get_terms
-	shift
-	case "$cmd" in
-	help)
-		git bisect -h ;;
-	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper state "$cmd" "$@" ;;
-	log)
-		git bisect--helper log || exit ;;
-	*)
-		git bisect--helper "$cmd" "$@" ;;
-	esac
-esac
diff --git a/git-compat-util.h b/git-compat-util.h
index de57f43..4f0028c 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -97,8 +97,14 @@ struct strbuf;
 # define BARF_UNLESS_AN_ARRAY(arr)						\
 	BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(__typeof__(arr), \
 							   __typeof__(&(arr)[0])))
+# define BARF_UNLESS_COPYABLE(dst, src) \
+	BUILD_ASSERT_OR_ZERO(__builtin_types_compatible_p(__typeof__(*(dst)), \
+							  __typeof__(*(src))))
 #else
 # define BARF_UNLESS_AN_ARRAY(arr) 0
+# define BARF_UNLESS_COPYABLE(dst, src) \
+	BUILD_ASSERT_OR_ZERO(0 ? ((*(dst) = *(src)), 0) : \
+				 sizeof(*(dst)) == sizeof(*(src)))
 #endif
 /*
  * ARRAY_SIZE - get the number of elements in a visible array
@@ -1102,7 +1108,7 @@ int xstrncmpz(const char *s, const char *t, size_t len);
 #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))
 
 #define COPY_ARRAY(dst, src, n) copy_array((dst), (src), (n), sizeof(*(dst)) + \
-	BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
+	BARF_UNLESS_COPYABLE((dst), (src)))
 static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
 {
 	if (n)
@@ -1110,13 +1116,18 @@ static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
 }
 
 #define MOVE_ARRAY(dst, src, n) move_array((dst), (src), (n), sizeof(*(dst)) + \
-	BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
+	BARF_UNLESS_COPYABLE((dst), (src)))
 static inline void move_array(void *dst, const void *src, size_t n, size_t size)
 {
 	if (n)
 		memmove(dst, src, st_mult(size, n));
 }
 
+#define DUP_ARRAY(dst, src, n) do { \
+	size_t dup_array_n_ = (n); \
+	COPY_ARRAY(ALLOC_ARRAY((dst), dup_array_n_), (src), dup_array_n_); \
+} while (0)
+
 /*
  * These functions help you allocate structs with flex arrays, and copy
  * the data directly into the array. For example, if you had:
diff --git a/git-request-pull.sh b/git-request-pull.sh
index 2d0e446..01640a0 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -153,7 +153,7 @@
 if test $(git cat-file -t "$head") = tag
 then
 	git cat-file tag "$head" |
-	sed -n -e '1,/^$/d' -e '/^-----BEGIN PGP /q' -e p
+	sed -n -e '1,/^$/d' -e '/^-----BEGIN \(PGP\|SSH\|SIGNED\) /q' -e p
 	echo
 	echo "----------------------------------------------------------------"
 fi &&
diff --git a/git-send-email.perl b/git-send-email.perl
index ad51508..c761801 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -208,6 +208,10 @@
 my $force = 0;
 my $dump_aliases = 0;
 
+# Variables to prevent short format-patch options from being captured
+# as abbreviated send-email options
+my $reroll_count;
+
 # Handle interactive edition of files.
 my $multiedit;
 my $editor;
@@ -530,6 +534,7 @@
 		    "batch-size=i" => \$batch_size,
 		    "relogin-delay=i" => \$relogin_delay,
 		    "git-completion-helper" => \$git_completion_helper,
+		    "v=s" => \$reroll_count,
 );
 $rc = GetOptions(%options);
 
@@ -770,7 +775,9 @@
 	die __("Cannot run git format-patch from outside a repository\n")
 		unless $repo;
 	require File::Temp;
-	push @files, $repo->command('format-patch', '-o', File::Temp::tempdir(CLEANUP => 1), @rev_list_opts);
+	push @files, $repo->command('format-patch', '-o', File::Temp::tempdir(CLEANUP => 1),
+				    defined $reroll_count ? ('-v', $reroll_count) : (),
+				    @rev_list_opts);
 }
 
 @files = handle_backup_files(@files);
diff --git a/git-submodule.sh b/git-submodule.sh
index 9a50f2e..7f9582d 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -244,6 +244,9 @@
 		-q|--quiet)
 			quiet=1
 			;;
+		-v|--verbose)
+			quiet=0
+			;;
 		--progress)
 			progress=1
 			;;
diff --git a/git.c b/git.c
index 10202a7..6171fd6 100644
--- a/git.c
+++ b/git.c
@@ -14,9 +14,8 @@
  * RUN_SETUP for reading from the configuration file.
  */
 #define NEED_WORK_TREE		(1<<3)
-#define SUPPORT_SUPER_PREFIX	(1<<4)
-#define DELAY_PAGER_CONFIG	(1<<5)
-#define NO_PARSEOPT		(1<<6) /* parse-options is not used */
+#define DELAY_PAGER_CONFIG	(1<<4)
+#define NO_PARSEOPT		(1<<5) /* parse-options is not used */
 
 struct cmd_struct {
 	const char *cmd;
@@ -29,8 +28,7 @@ const char git_usage_string[] =
 	   "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 	   "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
 	   "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-	   "           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-	   "           <command> [<args>]");
+	   "           [--config-env=<name>=<envvar>] <command> [<args>]");
 
 const char git_more_info_string[] =
 	N_("'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 			setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
 			if (envchanged)
 				*envchanged = 1;
-		} else if (!strcmp(cmd, "--super-prefix")) {
-			if (*argc < 2) {
-				fprintf(stderr, _("no prefix given for --super-prefix\n" ));
-				usage(git_usage_string);
-			}
-			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
-			if (envchanged)
-				*envchanged = 1;
-			(*argv)++;
-			(*argc)--;
-		} else if (skip_prefix(cmd, "--super-prefix=", &cmd)) {
-			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);
-			if (envchanged)
-				*envchanged = 1;
 		} else if (!strcmp(cmd, "--bare")) {
 			char *cwd = xgetcwd();
 			is_bare_repository_cfg = 1;
@@ -446,14 +430,9 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 		use_pager = 1;
 	if (run_setup && startup_info->have_repository)
 		/* get_git_dir() may set up repo, avoid that */
-		trace_repo_setup(prefix);
+		trace_repo_setup();
 	commit_pager_choice();
 
-	if (!help && get_super_prefix()) {
-		if (!(p->option & SUPPORT_SUPER_PREFIX))
-			die(_("%s doesn't support --super-prefix"), p->cmd);
-	}
-
 	if (!help && p->option & NEED_WORK_TREE)
 		setup_work_tree();
 
@@ -492,7 +471,7 @@ static struct cmd_struct commands[] = {
 	{ "annotate", cmd_annotate, RUN_SETUP },
 	{ "apply", cmd_apply, RUN_SETUP_GENTLY },
 	{ "archive", cmd_archive, RUN_SETUP_GENTLY },
-	{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
+	{ "bisect", cmd_bisect, RUN_SETUP },
 	{ "blame", cmd_blame, RUN_SETUP },
 	{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
 	{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {
 	{ "check-ref-format", cmd_check_ref_format, NO_PARSEOPT  },
 	{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout--worker", cmd_checkout__worker,
-		RUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },
+		RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout-index", cmd_checkout_index,
 		RUN_SETUP | NEED_WORK_TREE},
 	{ "cherry", cmd_cherry, RUN_SETUP },
@@ -528,7 +507,6 @@ static struct cmd_struct commands[] = {
 	{ "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },
 	{ "diff-tree", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT },
 	{ "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 },
@@ -539,7 +517,7 @@ static struct cmd_struct commands[] = {
 	{ "format-patch", cmd_format_patch, RUN_SETUP },
 	{ "fsck", cmd_fsck, RUN_SETUP },
 	{ "fsck-objects", cmd_fsck, RUN_SETUP },
-	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },
+	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, RUN_SETUP },
 	{ "gc", cmd_gc, RUN_SETUP },
 	{ "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT },
 	{ "grep", cmd_grep, RUN_SETUP_GENTLY },
@@ -583,7 +561,7 @@ static struct cmd_struct commands[] = {
 	{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
 	{ "push", cmd_push, RUN_SETUP },
 	{ "range-diff", cmd_range_diff, RUN_SETUP | USE_PAGER },
-	{ "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
+	{ "read-tree", cmd_read_tree, RUN_SETUP },
 	{ "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
 	{ "receive-pack", cmd_receive_pack },
 	{ "reflog", cmd_reflog, RUN_SETUP },
@@ -610,7 +588,7 @@ static struct cmd_struct commands[] = {
 	{ "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
 	{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
 	{ "stripspace", cmd_stripspace },
-	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },
+	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP },
 	{ "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
 	{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 	{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
@@ -727,9 +705,6 @@ static void execv_dashed_external(const char **argv)
 	struct child_process cmd = CHILD_PROCESS_INIT;
 	int status;
 
-	if (get_super_prefix())
-		die(_("%s doesn't support --super-prefix"), argv[0]);
-
 	if (use_pager == -1 && !is_builtin(argv[0]))
 		use_pager = check_pager_config(argv[0]);
 	commit_pager_choice();
@@ -799,9 +774,6 @@ static int run_argv(int *argcp, const char ***argv)
 			 */
 			trace2_cmd_name("_run_git_alias_");
 
-			if (get_super_prefix())
-				die("%s doesn't support --super-prefix", **argv);
-
 			commit_pager_choice();
 
 			strvec_push(&cmd.args, "git");
diff --git a/gpg-interface.c b/gpg-interface.c
index f877a1e..5cd66d3 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -977,9 +977,13 @@ static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
 			break; /* found */
 	}
 	ret |= !cp;
+	if (ret) {
+		error(_("gpg failed to sign the data:\n%s"),
+		      gpg_status.len ? gpg_status.buf : "(no gpg output)");
+		strbuf_release(&gpg_status);
+		return -1;
+	}
 	strbuf_release(&gpg_status);
-	if (ret)
-		return error(_("gpg failed to sign the data"));
 
 	/* Strip CR from the line endings, in case we are on Windows. */
 	remove_cr_after(signature, bottom);
@@ -998,6 +1002,7 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
 	char *ssh_signing_key_file = NULL;
 	struct strbuf ssh_signature_filename = STRBUF_INIT;
 	const char *literal_key = NULL;
+	int literal_ssh_key = 0;
 
 	if (!signing_key || signing_key[0] == '\0')
 		return error(
@@ -1005,6 +1010,7 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
 
 	if (is_literal_ssh_key(signing_key, &literal_key)) {
 		/* A literal ssh key */
+		literal_ssh_key = 1;
 		key_file = mks_tempfile_t(".git_signing_key_tmpXXXXXX");
 		if (!key_file)
 			return error_errno(
@@ -1039,8 +1045,10 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
 		     "-Y", "sign",
 		     "-n", "git",
 		     "-f", ssh_signing_key_file,
-		     buffer_file->filename.buf,
 		     NULL);
+	if (literal_ssh_key)
+		strvec_push(&signer.args, "-U");
+	strvec_push(&signer.args, buffer_file->filename.buf);
 
 	sigchain_push(SIGPIPE, SIG_IGN);
 	ret = pipe_command(&signer, NULL, 0, NULL, 0, &signer_stderr, 0);
diff --git a/grep.c b/grep.c
index 06eed69..cee44a7 100644
--- a/grep.c
+++ b/grep.c
@@ -262,6 +262,31 @@ static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
 	free(pointer);
 }
 
+static int pcre2_jit_functional(void)
+{
+	static int jit_working = -1;
+	pcre2_code *code;
+	size_t off;
+	int err;
+
+	if (jit_working != -1)
+		return jit_working;
+
+	/*
+	 * Try to JIT compile a simple pattern to probe if the JIT is
+	 * working in general. It might fail for systems where creating
+	 * memory mappings for runtime code generation is restricted.
+	 */
+	code = pcre2_compile((PCRE2_SPTR)".", 1, 0, &err, &off, NULL);
+	if (!code)
+		return 0;
+
+	jit_working = pcre2_jit_compile(code, PCRE2_JIT_COMPLETE) == 0;
+	pcre2_code_free(code);
+
+	return jit_working;
+}
+
 static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
 {
 	int error;
@@ -293,7 +318,7 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
 		options |= PCRE2_CASELESS;
 	}
 	if (!opt->ignore_locale && is_utf8_locale() && !literal)
-		options |= (PCRE2_UTF | PCRE2_MATCH_INVALID_UTF);
+		options |= (PCRE2_UTF | PCRE2_UCP | PCRE2_MATCH_INVALID_UTF);
 
 #ifndef GIT_PCRE2_VERSION_10_36_OR_HIGHER
 	/* Work around https://bugs.exim.org/show_bug.cgi?id=2642 fixed in 10.36 */
@@ -317,8 +342,29 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
 	pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on);
 	if (p->pcre2_jit_on) {
 		jitret = pcre2_jit_compile(p->pcre2_pattern, PCRE2_JIT_COMPLETE);
-		if (jitret)
-			die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", p->pattern, jitret);
+		if (jitret == PCRE2_ERROR_NOMEMORY && !pcre2_jit_functional()) {
+			/*
+			 * Even though pcre2_config(PCRE2_CONFIG_JIT, ...)
+			 * indicated JIT support, the library might still
+			 * fail to generate JIT code for various reasons,
+			 * e.g. when SELinux's 'deny_execmem' or PaX's
+			 * MPROTECT prevent creating W|X memory mappings.
+			 *
+			 * Instead of faling hard, fall back to interpreter
+			 * mode, just as if the pattern was prefixed with
+			 * '(*NO_JIT)'.
+			 */
+			p->pcre2_jit_on = 0;
+			return;
+		} else if (jitret) {
+			int need_clip = p->patternlen > 64;
+			int clip_len = need_clip ? 64 : p->patternlen;
+			die("Couldn't JIT the PCRE2 pattern '%.*s'%s, got '%d'%s",
+			    clip_len, p->pattern, need_clip ? "..." : "", jitret,
+			    pcre2_jit_functional()
+			    ? "\nPerhaps prefix (*NO_JIT) to your pattern?"
+			    : "");
+		}
 
 		/*
 		 * The pcre2_config(PCRE2_CONFIG_JIT, ...) call just
@@ -769,11 +815,11 @@ static void free_pattern_expr(struct grep_expr *x)
 	free(x);
 }
 
-void free_grep_patterns(struct grep_opt *opt)
+static void free_grep_pat(struct grep_pat *pattern)
 {
 	struct grep_pat *p, *n;
 
-	for (p = opt->pattern_list; p; p = n) {
+	for (p = pattern; p; p = n) {
 		n = p->next;
 		switch (p->token) {
 		case GREP_PATTERN: /* atom */
@@ -790,10 +836,15 @@ void free_grep_patterns(struct grep_opt *opt)
 		}
 		free(p);
 	}
+}
 
-	if (!opt->pattern_expression)
-		return;
-	free_pattern_expr(opt->pattern_expression);
+void free_grep_patterns(struct grep_opt *opt)
+{
+	free_grep_pat(opt->pattern_list);
+	free_grep_pat(opt->header_list);
+
+	if (opt->pattern_expression)
+		free_pattern_expr(opt->pattern_expression);
 }
 
 static const char *end_of_line(const char *cp, unsigned long *left)
diff --git a/help.c b/help.c
index f1e090a..812af4c 100644
--- a/help.c
+++ b/help.c
@@ -563,7 +563,7 @@ static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
 	if (skip_prefix(var, "alias.", &p))
 		add_cmdname(&aliases, p, strlen(p));
 
-	return git_default_config(var, value, cb);
+	return 0;
 }
 
 static int levenshtein_compare(const void *p1, const void *p2)
diff --git a/hook.c b/hook.c
index 22b274b..7981e08 100644
--- a/hook.c
+++ b/hook.c
@@ -59,6 +59,11 @@ static int pick_next_hook(struct child_process *cp,
 
 	cp->no_stdin = 1;
 	strvec_pushv(&cp->env, hook_cb->options->env.v);
+	/* reopen the file for stdin; run_command closes it. */
+	if (hook_cb->options->path_to_stdin) {
+		cp->no_stdin = 0;
+		cp->in = xopen(hook_cb->options->path_to_stdin, O_RDONLY);
+	}
 	cp->stdout_to_stderr = 1;
 	cp->trace2_hook_name = hook_cb->hook_name;
 	cp->dir = hook_cb->options->dir;
diff --git a/hook.h b/hook.h
index 4258b13..19ab9a5 100644
--- a/hook.h
+++ b/hook.h
@@ -30,6 +30,11 @@ struct run_hooks_opt
 	 * was invoked.
 	 */
 	int *invoked_hook;
+
+	/**
+	 * Path to file which should be piped to stdin for each hook.
+	 */
+	const char *path_to_stdin;
 };
 
 #define RUN_HOOKS_OPT_INIT { \
diff --git a/http-backend.c b/http-backend.c
index 6eb3b2f..8ab58e5 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -759,10 +759,14 @@ int cmd_main(int argc, const char **argv)
 		struct service_cmd *c = &services[i];
 		regex_t re;
 		regmatch_t out[1];
+		int ret;
 
 		if (regcomp(&re, c->pattern, REG_EXTENDED))
 			die("Bogus regex in service table: %s", c->pattern);
-		if (!regexec(&re, dir, 1, out, 0)) {
+		ret = regexec(&re, dir, 1, out, 0);
+		regfree(&re);
+
+		if (!ret) {
 			size_t n;
 
 			if (strcmp(method, c->method))
@@ -774,7 +778,6 @@ int cmd_main(int argc, const char **argv)
 			dir[out[0].rm_so] = 0;
 			break;
 		}
-		regfree(&re);
 	}
 
 	if (!cmd)
@@ -786,6 +789,7 @@ int cmd_main(int argc, const char **argv)
 	if (!getenv("GIT_HTTP_EXPORT_ALL") &&
 	    access("git-daemon-export-ok", F_OK) )
 		not_found(&hdr, "Repository not exported: '%s'", dir);
+	free(dir);
 
 	http_config();
 	max_request_buffer = git_env_ulong("GIT_HTTP_MAX_REQUEST_BUFFER",
@@ -795,5 +799,6 @@ int cmd_main(int argc, const char **argv)
 		setenv(GIT_PROTOCOL_ENVIRONMENT, proto_header, 0);
 
 	cmd->imp(&hdr, cmd_arg);
+	free(cmd_arg);
 	return 0;
 }
diff --git a/http-fetch.c b/http-fetch.c
index 31bc5c7..258fec2 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -5,6 +5,7 @@
 #include "walker.h"
 #include "strvec.h"
 #include "urlmatch.h"
+#include "trace2.h"
 
 static const char http_fetch_usage[] = "git http-fetch "
 "[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin | --packfile=hash | commit-id] url";
@@ -137,6 +138,8 @@ int cmd_main(int argc, const char **argv)
 	if (nongit)
 		die(_("not a git repository"));
 
+	trace2_cmd_name("http-fetch");
+
 	git_config(git_default_config, NULL);
 
 	if (packfile) {
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index 5339660..ee01bcd 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -290,10 +290,6 @@ int opt_parse_list_objects_filter(const struct option *opt,
 				  const char *arg, int unset)
 {
 	struct list_objects_filter_options *filter_options = opt->value;
-	opt_lof_init init = (opt_lof_init)opt->defval;
-
-	if (init)
-		filter_options = init(opt->value);
 
 	if (unset || !arg)
 		list_objects_filter_set_no_filter(filter_options);
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
index 7eeadab..1fe393f 100644
--- a/list-objects-filter-options.h
+++ b/list-objects-filter-options.h
@@ -111,27 +111,13 @@ void parse_list_objects_filter(
  * The opt->value to opt_parse_list_objects_filter() is either a
  * "struct list_objects_filter_option *" when using
  * OPT_PARSE_LIST_OBJECTS_FILTER().
- *
- * Or, if using no "struct option" field is used by the callback,
- * except the "defval" which is expected to be an "opt_lof_init"
- * function, which is called with the "opt->value" and must return a
- * pointer to the ""struct list_objects_filter_option *" to be used.
- *
- * The OPT_PARSE_LIST_OBJECTS_FILTER_INIT() can be used e.g. the
- * "struct list_objects_filter_option" is embedded in a "struct
- * rev_info", which the "defval" could be tasked with lazily
- * initializing. See cmd_pack_objects() for an example.
  */
 int opt_parse_list_objects_filter(const struct option *opt,
 				  const char *arg, int unset);
-typedef struct list_objects_filter_options *(*opt_lof_init)(void *);
-#define OPT_PARSE_LIST_OBJECTS_FILTER_INIT(fo, init) \
-	{ OPTION_CALLBACK, 0, "filter", (fo), N_("args"), \
-	  N_("object filtering"), 0, opt_parse_list_objects_filter, \
-	  (intptr_t)(init) }
 
 #define OPT_PARSE_LIST_OBJECTS_FILTER(fo) \
-	OPT_PARSE_LIST_OBJECTS_FILTER_INIT((fo), NULL)
+	OPT_CALLBACK(0, "filter", (fo), N_("args"), \
+		     N_("object filtering"), opt_parse_list_objects_filter)
 
 /*
  * Translates abbreviated numbers in the filter's filter_spec into their
diff --git a/ll-merge.c b/ll-merge.c
index 22a603e..130d265 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -391,7 +391,7 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
 		normalize_file(theirs, path, istate);
 	}
 
-	git_check_attr(istate, path, check);
+	git_check_attr(istate, NULL, path, check);
 	ll_driver_name = check->items[0].value;
 	if (check->items[1].value) {
 		marker_size = atoi(check->items[1].value);
@@ -419,7 +419,7 @@ int ll_merge_marker_size(struct index_state *istate, const char *path)
 
 	if (!check)
 		check = attr_check_initl("conflict-marker-size", NULL);
-	git_check_attr(istate, path, check);
+	git_check_attr(istate, NULL, path, check);
 	if (check->items[0].value) {
 		marker_size = atoi(check->items[0].value);
 		if (marker_size <= 0)
diff --git a/merge-recursive.c b/merge-recursive.c
index 2fd0aa9..ae469f8 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -412,7 +412,7 @@ static int unpack_trees_start(struct merge_options *opt,
 {
 	int rc;
 	struct tree_desc t[3];
-	struct index_state tmp_index = { NULL };
+	struct index_state tmp_index = INDEX_STATE_INIT(opt->repo);
 
 	memset(&opt->priv->unpack_opts, 0, sizeof(opt->priv->unpack_opts));
 	if (opt->priv->call_depth)
diff --git a/object-file.c b/object-file.c
index c1b71c2..939865c 100644
--- a/object-file.c
+++ b/object-file.c
@@ -33,6 +33,7 @@
 #include "object-store.h"
 #include "promisor-remote.h"
 #include "submodule.h"
+#include "fsck.h"
 
 /* The maximum size for an object header. */
 #define MAX_HEADER_LEN 32
@@ -1211,35 +1212,25 @@ static int quick_has_loose(struct repository *r,
 }
 
 /*
- * Map the loose object at "path" if it is not NULL, or the path found by
- * searching for a loose object named "oid".
+ * Map and close the given loose object fd. The path argument is used for
+ * error reporting.
  */
-static void *map_loose_object_1(struct repository *r, const char *path,
-			     const struct object_id *oid, unsigned long *size)
+static void *map_fd(int fd, const char *path, unsigned long *size)
 {
-	void *map;
-	int fd;
+	void *map = NULL;
+	struct stat st;
 
-	if (path)
-		fd = git_open(path);
-	else
-		fd = open_loose_object(r, oid, &path);
-	map = NULL;
-	if (fd >= 0) {
-		struct stat st;
-
-		if (!fstat(fd, &st)) {
-			*size = xsize_t(st.st_size);
-			if (!*size) {
-				/* mmap() is forbidden on empty files */
-				error(_("object file %s is empty"), path);
-				close(fd);
-				return NULL;
-			}
-			map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (!fstat(fd, &st)) {
+		*size = xsize_t(st.st_size);
+		if (!*size) {
+			/* mmap() is forbidden on empty files */
+			error(_("object file %s is empty"), path);
+			close(fd);
+			return NULL;
 		}
-		close(fd);
+		map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
 	}
+	close(fd);
 	return map;
 }
 
@@ -1247,7 +1238,12 @@ void *map_loose_object(struct repository *r,
 		       const struct object_id *oid,
 		       unsigned long *size)
 {
-	return map_loose_object_1(r, NULL, oid, size);
+	const char *p;
+	int fd = open_loose_object(r, oid, &p);
+
+	if (fd < 0)
+		return NULL;
+	return map_fd(fd, p, size);
 }
 
 enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
@@ -1427,7 +1423,9 @@ static int loose_object_info(struct repository *r,
 			     struct object_info *oi, int flags)
 {
 	int status = 0;
+	int fd;
 	unsigned long mapsize;
+	const char *path;
 	void *map;
 	git_zstream stream;
 	char hdr[MAX_HEADER_LEN];
@@ -1448,7 +1446,6 @@ static int loose_object_info(struct repository *r,
 	 * object even exists.
 	 */
 	if (!oi->typep && !oi->type_name && !oi->sizep && !oi->contentp) {
-		const char *path;
 		struct stat st;
 		if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
 			return quick_has_loose(r, oid) ? 0 : -1;
@@ -1459,7 +1456,13 @@ static int loose_object_info(struct repository *r,
 		return 0;
 	}
 
-	map = map_loose_object(r, oid, &mapsize);
+	fd = open_loose_object(r, oid, &path);
+	if (fd < 0) {
+		if (errno != ENOENT)
+			error_errno(_("unable to open loose object %s"), oid_to_hex(oid));
+		return -1;
+	}
+	map = map_fd(fd, path, &mapsize);
 	if (!map)
 		return -1;
 
@@ -1497,6 +1500,10 @@ static int loose_object_info(struct repository *r,
 		break;
 	}
 
+	if (status && (flags & OBJECT_INFO_DIE_IF_CORRUPT))
+		die(_("loose object %s (stored in %s) is corrupt"),
+		    oid_to_hex(oid), path);
+
 	git_inflate_end(&stream);
 cleanup:
 	munmap(map, mapsize);
@@ -1575,9 +1582,6 @@ static int do_oid_object_info_extended(struct repository *r,
 		if (find_pack_entry(r, real, &e))
 			break;
 
-		if (flags & OBJECT_INFO_IGNORE_LOOSE)
-			return -1;
-
 		/* Most likely it's a loose object. */
 		if (!loose_object_info(r, real, oi, flags))
 			return 0;
@@ -1609,6 +1613,15 @@ static int do_oid_object_info_extended(struct repository *r,
 			continue;
 		}
 
+		if (flags & OBJECT_INFO_DIE_IF_CORRUPT) {
+			const struct packed_git *p;
+			if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid))
+				die(_("replacement %s not found for %s"),
+				    oid_to_hex(real), oid_to_hex(oid));
+			if ((p = has_packed_and_bad(r, real)))
+				die(_("packed object %s (stored in %s) is corrupt"),
+				    oid_to_hex(real), p->pack_name);
+		}
 		return -1;
 	}
 
@@ -1659,21 +1672,6 @@ int oid_object_info(struct repository *r,
 	return type;
 }
 
-static void *read_object(struct repository *r,
-			 const struct object_id *oid, enum object_type *type,
-			 unsigned long *size)
-{
-	struct object_info oi = OBJECT_INFO_INIT;
-	void *content;
-	oi.typep = type;
-	oi.sizep = size;
-	oi.contentp = &content;
-
-	if (oid_object_info_extended(r, oid, &oi, 0) < 0)
-		return NULL;
-	return content;
-}
-
 int pretend_object_file(void *buf, unsigned long len, enum object_type type,
 			struct object_id *oid)
 {
@@ -1695,46 +1693,25 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
 
 /*
  * This function dies on corrupt objects; the callers who want to
- * deal with them should arrange to call read_object() and give error
- * messages themselves.
+ * deal with them should arrange to call oid_object_info_extended() and give
+ * error messages themselves.
  */
-void *read_object_file_extended(struct repository *r,
-				const struct object_id *oid,
-				enum object_type *type,
-				unsigned long *size,
-				int lookup_replace)
+void *repo_read_object_file(struct repository *r,
+			    const struct object_id *oid,
+			    enum object_type *type,
+			    unsigned long *size)
 {
+	struct object_info oi = OBJECT_INFO_INIT;
+	unsigned flags = OBJECT_INFO_DIE_IF_CORRUPT | OBJECT_INFO_LOOKUP_REPLACE;
 	void *data;
-	const struct packed_git *p;
-	const char *path;
-	struct stat st;
-	const struct object_id *repl = lookup_replace ?
-		lookup_replace_object(r, oid) : oid;
 
-	errno = 0;
-	data = read_object(r, repl, type, size);
-	if (data)
-		return data;
+	oi.typep = type;
+	oi.sizep = size;
+	oi.contentp = &data;
+	if (oid_object_info_extended(r, oid, &oi, flags))
+		return NULL;
 
-	obj_read_lock();
-	if (errno && errno != ENOENT)
-		die_errno(_("failed to read object %s"), oid_to_hex(oid));
-
-	/* die if we replaced an object with one that does not exist */
-	if (repl != oid)
-		die(_("replacement %s not found for %s"),
-		    oid_to_hex(repl), oid_to_hex(oid));
-
-	if (!stat_loose_object(r, repl, &st, &path))
-		die(_("loose object %s (stored in %s) is corrupt"),
-		    oid_to_hex(repl), path);
-
-	if ((p = has_packed_and_bad(r, repl)))
-		die(_("packed object %s (stored in %s) is corrupt"),
-		    oid_to_hex(repl), p->pack_name);
-	obj_read_unlock();
-
-	return NULL;
+	return data;
 }
 
 void *read_object_with_reference(struct repository *r,
@@ -2262,6 +2239,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
 {
 	void *buf;
 	unsigned long len;
+	struct object_info oi = OBJECT_INFO_INIT;
 	enum object_type type;
 	char hdr[MAX_HEADER_LEN];
 	int hdrlen;
@@ -2269,8 +2247,10 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
 
 	if (has_loose_object(oid))
 		return 0;
-	buf = read_object(the_repository, oid, &type, &len);
-	if (!buf)
+	oi.typep = &type;
+	oi.sizep = &len;
+	oi.contentp = &buf;
+	if (oid_object_info_extended(the_repository, oid, &oi, 0))
 		return error(_("cannot read object for %s"), oid_to_hex(oid));
 	hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
 	ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
@@ -2305,32 +2285,21 @@ int repo_has_object_file(struct repository *r,
 	return repo_has_object_file_with_flags(r, oid, 0);
 }
 
-static void check_tree(const void *buf, size_t size)
+/*
+ * We can't use the normal fsck_error_function() for index_mem(),
+ * because we don't yet have a valid oid for it to report. Instead,
+ * report the minimal fsck error here, and rely on the caller to
+ * give more context.
+ */
+static int hash_format_check_report(struct fsck_options *opts,
+				     const struct object_id *oid,
+				     enum object_type object_type,
+				     enum fsck_msg_type msg_type,
+				     enum fsck_msg_id msg_id,
+				     const char *message)
 {
-	struct tree_desc desc;
-	struct name_entry entry;
-
-	init_tree_desc(&desc, buf, size);
-	while (tree_entry(&desc, &entry))
-		/* do nothing
-		 * tree_entry() will die() on malformed entries */
-		;
-}
-
-static void check_commit(const void *buf, size_t size)
-{
-	struct commit c;
-	memset(&c, 0, sizeof(c));
-	if (parse_commit_buffer(the_repository, &c, buf, size, 0))
-		die(_("corrupt commit"));
-}
-
-static void check_tag(const void *buf, size_t size)
-{
-	struct tag t;
-	memset(&t, 0, sizeof(t));
-	if (parse_tag_buffer(the_repository, &t, buf, size))
-		die(_("corrupt tag"));
+	error(_("object fails fsck: %s"), message);
+	return 1;
 }
 
 static int index_mem(struct index_state *istate,
@@ -2357,12 +2326,13 @@ static int index_mem(struct index_state *istate,
 		}
 	}
 	if (flags & HASH_FORMAT_CHECK) {
-		if (type == OBJ_TREE)
-			check_tree(buf, size);
-		if (type == OBJ_COMMIT)
-			check_commit(buf, size);
-		if (type == OBJ_TAG)
-			check_tag(buf, size);
+		struct fsck_options opts = FSCK_OPTIONS_DEFAULT;
+
+		opts.strict = 1;
+		opts.error_func = hash_format_check_report;
+		if (fsck_buffer(null_oid(), type, buf, size, &opts))
+			die(_("refusing to create malformed object"));
+		fsck_finish(&opts);
 	}
 
 	if (write_object)
@@ -2785,13 +2755,16 @@ int read_loose_object(const char *path,
 		      struct object_info *oi)
 {
 	int ret = -1;
+	int fd;
 	void *map = NULL;
 	unsigned long mapsize;
 	git_zstream stream;
 	char hdr[MAX_HEADER_LEN];
 	unsigned long *size = oi->sizep;
 
-	map = map_loose_object_1(the_repository, path, NULL, &mapsize);
+	fd = git_open(path);
+	if (fd >= 0)
+		map = map_fd(fd, path, &mapsize);
 	if (!map) {
 		error_errno(_("unable to mmap %s"), path);
 		goto out;
diff --git a/object-store.h b/object-store.h
index 1be57ab..1a713d8 100644
--- a/object-store.h
+++ b/object-store.h
@@ -241,17 +241,10 @@ const char *loose_object_path(struct repository *r, struct strbuf *buf,
 void *map_loose_object(struct repository *r, const struct object_id *oid,
 		       unsigned long *size);
 
-void *read_object_file_extended(struct repository *r,
-				const struct object_id *oid,
-				enum object_type *type,
-				unsigned long *size, int lookup_replace);
-static inline void *repo_read_object_file(struct repository *r,
-					  const struct object_id *oid,
-					  enum object_type *type,
-					  unsigned long *size)
-{
-	return read_object_file_extended(r, oid, type, size, 1);
-}
+void *repo_read_object_file(struct repository *r,
+			    const struct object_id *oid,
+			    enum object_type *type,
+			    unsigned long *size);
 #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
 #define read_object_file(oid, type, size) repo_read_object_file(the_repository, oid, type, size)
 #endif
@@ -358,8 +351,7 @@ void assert_oid_type(const struct object_id *oid, enum object_type expect);
 /*
  * Enabling the object read lock allows multiple threads to safely call the
  * following functions in parallel: repo_read_object_file(), read_object_file(),
- * read_object_file_extended(), read_object_with_reference(), read_object(),
- * oid_object_info() and oid_object_info_extended().
+ * read_object_with_reference(), oid_object_info() and oid_object_info_extended().
  *
  * obj_read_lock() and obj_read_unlock() may also be used to protect other
  * section which cannot execute in parallel with object reading. Since the used
@@ -434,19 +426,20 @@ struct object_info {
 #define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
 /* Do not retry packed storage after checking packed and loose storage */
 #define OBJECT_INFO_QUICK 8
-/* Do not check loose object */
-#define OBJECT_INFO_IGNORE_LOOSE 16
 /*
  * Do not attempt to fetch the object if missing (even if fetch_is_missing is
  * nonzero).
  */
-#define OBJECT_INFO_SKIP_FETCH_OBJECT 32
+#define OBJECT_INFO_SKIP_FETCH_OBJECT 16
 /*
  * This is meant for bulk prefetching of missing blobs in a partial
  * clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK
  */
 #define OBJECT_INFO_FOR_PREFETCH (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)
 
+/* Die if object corruption (not just an object being missing) was detected. */
+#define OBJECT_INFO_DIE_IF_CORRUPT 32
+
 int oid_object_info_extended(struct repository *r,
 			     const struct object_id *,
 			     struct object_info *, unsigned flags);
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 440407f..d2a42ab 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -354,8 +354,8 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
 	if (bitmap_git->pack || bitmap_git->midx) {
 		struct strbuf buf = STRBUF_INIT;
 		get_midx_filename(&buf, midx->object_dir);
-		/* ignore extra bitmap file; we can only handle one */
-		warning(_("ignoring extra bitmap file: '%s'"), buf.buf);
+		trace2_data_string("bitmap", the_repository,
+				   "ignoring extra midx bitmap file", buf.buf);
 		close(fd);
 		strbuf_release(&buf);
 		return -1;
@@ -411,9 +411,6 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
 	struct stat st;
 	char *bitmap_name;
 
-	if (open_pack_index(packfile))
-		return -1;
-
 	bitmap_name = pack_bitmap_filename(packfile);
 	fd = git_open(bitmap_name);
 
@@ -432,8 +429,8 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
 	}
 
 	if (bitmap_git->pack || bitmap_git->midx) {
-		/* ignore extra bitmap file; we can only handle one */
-		warning(_("ignoring extra bitmap file: '%s'"), packfile->pack_name);
+		trace2_data_string("bitmap", the_repository,
+				   "ignoring extra bitmap file", packfile->pack_name);
 		close(fd);
 		return -1;
 	}
@@ -458,6 +455,8 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
 		return -1;
 	}
 
+	trace2_data_string("bitmap", the_repository, "opened bitmap file",
+			   packfile->pack_name);
 	return 0;
 }
 
@@ -525,11 +524,16 @@ static int open_pack_bitmap(struct repository *r,
 	struct packed_git *p;
 	int ret = -1;
 
-	assert(!bitmap_git->map);
-
 	for (p = get_all_packs(r); p; p = p->next) {
-		if (open_pack_bitmap_1(bitmap_git, p) == 0)
+		if (open_pack_bitmap_1(bitmap_git, p) == 0) {
 			ret = 0;
+			/*
+			 * The only reason to keep looking is to report
+			 * duplicates.
+			 */
+			if (!trace2_is_enabled())
+				break;
+		}
 	}
 
 	return ret;
@@ -553,11 +557,20 @@ static int open_midx_bitmap(struct repository *r,
 static int open_bitmap(struct repository *r,
 		       struct bitmap_index *bitmap_git)
 {
+	int found;
+
 	assert(!bitmap_git->map);
 
-	if (!open_midx_bitmap(r, bitmap_git))
-		return 0;
-	return open_pack_bitmap(r, bitmap_git);
+	found = !open_midx_bitmap(r, bitmap_git);
+
+	/*
+	 * these will all be skipped if we opened a midx bitmap; but run it
+	 * anyway if tracing is enabled to report the duplicates
+	 */
+	if (!found || trace2_is_enabled())
+		found |= !open_pack_bitmap(r, bitmap_git);
+
+	return found ? 0 : -1;
 }
 
 struct bitmap_index *prepare_bitmap_git(struct repository *r)
diff --git a/packfile.c b/packfile.c
index c0d7dd9..79e21ab 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1650,22 +1650,6 @@ struct unpack_entry_stack_ent {
 	unsigned long size;
 };
 
-static void *read_object(struct repository *r,
-			 const struct object_id *oid,
-			 enum object_type *type,
-			 unsigned long *size)
-{
-	struct object_info oi = OBJECT_INFO_INIT;
-	void *content;
-	oi.typep = type;
-	oi.sizep = size;
-	oi.contentp = &content;
-
-	if (oid_object_info_extended(r, oid, &oi, 0) < 0)
-		return NULL;
-	return content;
-}
-
 void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
 		   enum object_type *final_type, unsigned long *final_size)
 {
@@ -1798,6 +1782,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
 			uint32_t pos;
 			struct object_id base_oid;
 			if (!(offset_to_pack_pos(p, obj_offset, &pos))) {
+				struct object_info oi = OBJECT_INFO_INIT;
+
 				nth_packed_object_id(&base_oid, p,
 						     pack_pos_to_index(p, pos));
 				error("failed to read delta base object %s"
@@ -1805,7 +1791,13 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
 				      oid_to_hex(&base_oid), (uintmax_t)obj_offset,
 				      p->pack_name);
 				mark_bad_packed_object(p, &base_oid);
-				base = read_object(r, &base_oid, &type, &base_size);
+
+				oi.typep = &type;
+				oi.sizep = &base_size;
+				oi.contentp = &base;
+				if (oid_object_info_extended(r, &base_oid, &oi, 0) < 0)
+					base = NULL;
+
 				external_base = base;
 			}
 		}
diff --git a/parse-options.c b/parse-options.c
index a1ec932..fd47432 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -702,8 +702,7 @@ static struct option *preprocess_options(struct parse_opt_ctx_t *ctx,
 	if (!nr_aliases)
 		return NULL;
 
-	ALLOC_ARRAY(newopt, nr + 1);
-	COPY_ARRAY(newopt, options, nr + 1);
+	DUP_ARRAY(newopt, options, nr + 1);
 
 	/* each alias has two string pointers and NULL */
 	CALLOC_ARRAY(ctx->alias_groups, 3 * (nr_aliases + 1));
diff --git a/parse-options.h b/parse-options.h
index b6ef86e..50d852f 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
 	{ OPTION_CALLBACK, 0, "abbrev", (var), N_("n"),	\
 	  N_("use <n> digits to display object names"),	\
 	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
+#define OPT__SUPER_PREFIX(var) \
+	OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
+		N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
+
 #define OPT__COLOR(var, h) \
 	OPT_COLOR_FLAG(0, "color", (var), (h))
 #define OPT_COLUMN(s, l, v, h) \
diff --git a/pathspec.c b/pathspec.c
index 46e77a8..ab70fcb 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -545,7 +545,7 @@ static void NORETURN unsupported_magic(const char *pattern,
 	}
 	/*
 	 * We may want to substitute "this command" with a command
-	 * name. E.g. when add--interactive dies when running
+	 * name. E.g. when "git add -p" or "git add -i" dies when running
 	 * "checkout -p"
 	 */
 	die(_("%s: pathspec magic not supported by this command: %s"),
@@ -681,8 +681,7 @@ void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
 	int i, j;
 
 	*dst = *src;
-	ALLOC_ARRAY(dst->items, dst->nr);
-	COPY_ARRAY(dst->items, src->items, dst->nr);
+	DUP_ARRAY(dst->items, src->items, dst->nr);
 
 	for (i = 0; i < dst->nr; i++) {
 		struct pathspec_item *d = &dst->items[i];
@@ -691,8 +690,7 @@ void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
 		d->match = xstrdup(s->match);
 		d->original = xstrdup(s->original);
 
-		ALLOC_ARRAY(d->attr_match, d->attr_match_nr);
-		COPY_ARRAY(d->attr_match, s->attr_match, d->attr_match_nr);
+		DUP_ARRAY(d->attr_match, s->attr_match, d->attr_match_nr);
 		for (j = 0; j < d->attr_match_nr; j++) {
 			const char *value = s->attr_match[j].value;
 			d->attr_match[j].value = xstrdup_or_null(value);
@@ -732,7 +730,7 @@ int match_pathspec_attrs(struct index_state *istate,
 	if (name[namelen])
 		name = to_free = xmemdupz(name, namelen);
 
-	git_check_attr(istate, name, item->attr_check);
+	git_check_attr(istate, NULL, name, item->attr_check);
 
 	free(to_free);
 
diff --git a/po/bg.po b/po/bg.po
index a2cd8a0..daec132 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -1,7 +1,7 @@
 # Bulgarian translation of git po-file.
-# Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Alexander Shopov <ash@kambanaria.org>.
+# Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Alexander Shopov <ash@kambanaria.org>.
 # This file is distributed under the same license as the git package.
-# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022.
+# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023.
 # ========================
 # DICTIONARY TO MERGE IN GIT GUI
 # ------------------------
@@ -196,6 +196,10 @@
 # scalar repo скаларно хранилище
 # unclean завършвам работа/задача с грешка
 # cache tree кеш за обекти-дървета
+# gitattributes file файл с атрибути на git
+# advertised обявен за наличен
+# superproject свръхпроект
+#
 # ------------------------
 # „$var“ - може да не сработва за shell има gettext и eval_gettext - проверка - намират се лесно по „$
 # ------------------------
@@ -212,10 +216,10 @@
 # for i in `sort -u FILES`; do cnt=`grep $i FILES | wc -l`; echo $cnt $i ;done | sort -n
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.39\n"
+"Project-Id-Version: git 2.40\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-12-06 15:52+0100\n"
-"PO-Revision-Date: 2022-12-06 16:55+0200\n"
+"POT-Creation-Date: 2023-03-01 01:20+0000\n"
+"PO-Revision-Date: 2023-03-02 08:54+0200\n"
 "Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
 "Language-Team: Bulgarian <dict@fsa-bg.org>\n"
 "Language: bg\n"
@@ -250,13 +254,13 @@
 msgid "could not write index"
 msgstr "индексът не може да бъде записан"
 
-#, c-format, perl-format
+#, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "%d файл обновен\n"
 msgstr[1] "%d файла обновени\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "БЕЛЕЖКА: „%s“ вече не се следи.\n"
 
@@ -270,7 +274,7 @@
 msgid "Could not parse HEAD^{tree}"
 msgstr "Указателят „HEAD^{tree}“ не може да бъде анализиран"
 
-#, c-format, perl-format
+#, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "%d файл с отменени промѐни\n"
@@ -283,7 +287,7 @@
 msgid "Add untracked"
 msgstr "Добавяне на неследени"
 
-#, c-format, perl-format
+#, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "%d файл добавен\n"
@@ -377,19 +381,19 @@
 msgid "Bye.\n"
 msgstr "Изход.\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "Добавяне на промяната на права̀та за достъп [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "Добавяне на изтриването [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "Добавяне на добавянето [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Добавяне на това парче [y,n,q,a,d%s,?]? "
 
@@ -413,19 +417,19 @@
 "a — добавяне на това и всички следващи парчета от файла в индекса\n"
 "d — без добавяне на това и всички следващи парчета от файла в индекса\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "Скатаване на промяната на права̀та за достъп [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "Скатаване на изтриването [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "Скатаване на добавянето [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "Скатаване на това парче [y,n,q,a,d%s,?]? "
 
@@ -449,19 +453,19 @@
 "a — скатаване на това и всички следващи парчета от файла\n"
 "d — без скатаване на това и всички следващи парчета от файла\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "Изваждане на промяната на права̀та за достъп [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "Изваждане на изтриването [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "Изваждане на добавянето [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Изваждане на това парче [y,n,q,a,d%s,?]? "
 
@@ -485,20 +489,20 @@
 "a — изваждане на това и всички следващи парчета от файла от индекса\n"
 "d — без изваждане на това и всички следващи парчета от файла от индекса\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr ""
 "Прилагане на промяната на права̀та за достъп към индекса [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "Прилагане на изтриването към индекса [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "Прилагане на добавянето към индекса [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "Прилагане на това парче към индекса [y,n,q,a,d%s,?]? "
 
@@ -522,21 +526,21 @@
 "a — прилагане на това и всички следващи парчета от файла към индекса\n"
 "d — без прилагане на това и всички следващи парчета от файла към индекса\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Премахване на промяната в права̀та за достъп от работното дърво [y,n,q,a,"
 "d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "Премахване на изтриването от работното дърво [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "Премахване на добавянето от работното дърво [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
 msgstr "Премахване на парчето от работното дърво [y,n,q,a,d%s,?]? "
 
@@ -563,23 +567,23 @@
 "d — без премахване на това и всички следващи парчета от файла от работното "
 "дърво\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Премахване на промяната в права̀та за достъп от индекса и работното дърво [y,"
 "n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Премахване на изтриването от индекса и работното дърво [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Премахване на добавянето от индекса и работното дърво [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Премахване на парчето от индекса и работното дърво [y,n,q,a,d%s,?]? "
 
@@ -599,22 +603,22 @@
 "d — без премахване на това и всички следващи парчета от файла от индекса и "
 "работното дърво\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Прилагане на промяната в права̀та за достъп от индекса и работното дърво [y,n,"
 "q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Прилагане на изтриването от индекса и работното дърво [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Прилагане на добавянето от индекса и работното дърво [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Прилагане на парчето от индекса и работното дърво [y,n,q,a,d%s,?]? "
 
@@ -634,21 +638,21 @@
 "d — без прилагане на това и всички следващи парчета от файла от индекса и "
 "работното дърво\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Прилагане на промяната в права̀та за достъп към работното дърво [y,n,q,a,"
 "d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
 msgstr "Прилагане на изтриването към работното дърво [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
 msgstr "Прилагане на добавянето към работното дърво [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
 msgstr "Прилагане на парчето към работното дърво [y,n,q,a,d%s,?]? "
 
@@ -725,8 +729,6 @@
 "За да пропуснете редовете, започващи с „%c“: изтрийте ги.\n"
 "Редовете, които започват с „%c“ ще бъдат пропуснати.\n"
 
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
 "edit again.  If all lines of the hunk are removed, then the edit is\n"
@@ -742,20 +744,12 @@
 msgid "'git apply --cached' failed"
 msgstr "неуспешно изпълнение на „git apply --cached“"
 
-#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr ""
@@ -1621,6 +1615,12 @@
 msgid "report archived files on stderr"
 msgstr "извеждане на архивираните файлове на стандартната грешка"
 
+msgid "time"
+msgstr "ВРЕМЕ"
+
+msgid "set modification time of archive entries"
+msgstr "задаване на ВРЕМЕ на промяна на елементите в архива"
+
 msgid "set compression level"
 msgstr "задаване на нивото на компресиране"
 
@@ -1661,6 +1661,13 @@
 msgid "%.*s is not a valid attribute name"
 msgstr "„%.*s“ е неправилно име за атрибут"
 
+msgid "unable to add additional attribute"
+msgstr "не може да се добави нов атрибут"
+
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "прескачане на прекалено дълъг ред за атрибути: %d"
+
 #, c-format
 msgid "%s not allowed: %s:%d"
 msgstr "%s: командата не е позволена: „%s:%d“"
@@ -1673,6 +1680,18 @@
 "Ако ви трябва начална удивителна, ползвайте „\\!“."
 
 #, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "неуспешно изпълнение на „fstat“ върху файла за атрибути на git „%s“"
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "прескачане на прекалено големия файл за атрибути на git: „%s“"
+
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "прескачане на прекалено големия обект-BLOB за атрибути на git: „%s“"
+
+#, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Неправилно цитирано съдържание във файла „%s“: %s"
 
@@ -1951,12 +1970,12 @@
 
 #, c-format
 msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
 msgstr ""
 "Може да обновите подмодулите с командата:\n"
 "\n"
-"    git checkout %s && git submodule update --init"
+"    git checkout --no-recurse-submodules %s && git submodule update --init"
 
 #, c-format
 msgid "submodule '%s': cannot create branch '%s'"
@@ -1991,6 +2010,13 @@
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Промѐни, които и след обновяването на индекса не са добавени към него:"
 
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"Настройката „add.interactive.useBuiltin“ е премахната!\n"
+"За подробности я потърсете в изхода от „git help config“."
+
 msgid "Could not read the index"
 msgstr "Индексът не може да бъде прочетен"
 
@@ -2399,6 +2425,11 @@
 msgid "run interactively"
 msgstr "интерактивна работа"
 
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr ""
+"без изпълнение на куките преди прилагане на кръпка и съобщение преди "
+"прилагане на кръпка"
+
 msgid "historical option -- no-op"
 msgstr "изоставена опция, съществува по исторически причини, нищо не прави"
 
@@ -2548,31 +2579,28 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: очакваше се изчистване на буферите чрез „flush“"
 
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [ПОДАВАНЕ]"
-
 msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=ЛОШО --term-{old,good}"
-"=ДОБРО] [--no-checkout] [--first-parent] [ЛОШО [ДОБРО…]] [--] [ПЪТ…]"
+"git bisect start [--term-{new,bad}=УПРАВЛЯВАЩА_ДУМА --term-{old,good}"
+"=УПРАВЛЯВАЩА_ДУМА] [--no-checkout] [--first-parent] [ЛОШО [ДОБРО…]] [--] "
+"[ПЪТ…]"
 
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (ЛОШО) [ВЕРСИЯ]"
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [ВЕРСИЯ…]"
 
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (ДОБРО) [ВЕРСИЯ…]"
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(ВЕРСИЯ|ДИАПАЗОН)…]"
 
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay ИМЕ_НА_ФАЙЛ"
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [ПОДАВАНЕ]"
 
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(ВЕРСИЯ|ДИАПАЗОН)…]"
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay ИМЕ_НА_ФАЙЛ"
 
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run КОМАНДА…"
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run КОМАНДА…"
 
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
@@ -2721,11 +2749,6 @@
 "Неуспешно преминаване към „%s“.  Изпълнете командата „git bisect start "
 "СЪЩЕСТВУВАЩ_КЛОН“."
 
-msgid "won't bisect on cg-seek'ed tree"
-msgstr ""
-"не може да се търси двоично, когато е изпълнена командата „cg-seek“ от "
-"„cogito“"
-
 msgid "bad HEAD - strange symbolic ref"
 msgstr "Неправилен указател „HEAD“ — необичаен символен указател"
 
@@ -2781,7 +2804,7 @@
 msgstr "неуспешно двоично търсене, не е зададена команда."
 
 #, c-format
-msgid "unable to verify '%s' on good revision"
+msgid "unable to verify %s on good revision"
 msgstr "„%s“ не може да провери с добра версия"
 
 #, c-format
@@ -2789,7 +2812,7 @@
 msgstr "неправилен изходен код %d за добро подаване"
 
 #, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
 msgstr ""
 "неуспешно двоично търсене: изходният код от командата „%2$s“ е %1$d — това е "
 "извън интервала [0, 128)"
@@ -2801,37 +2824,42 @@
 msgid "bisect run cannot continue any more"
 msgstr "двоичното търсене не може да продължи"
 
-#, c-format
 msgid "bisect run success"
 msgstr "успешно двоично търсене"
 
-#, c-format
 msgid "bisect found first bad commit"
 msgstr "двоичното търсене откри първото лошо подаване"
 
 #, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
-msgstr ""
-"неуспешно двоично търсене: „git bisect--helper --bisect-state %s“ завърши с "
-"код за грешка: %d"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
+msgstr "неуспешно двоично търсене: „git bisect %s“ завърши с код за грешка: %d"
 
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "опцията „--bisect-reset“ изисква или 0 аргументи, или 1 — подаване"
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "„%s“ изисква или 0 аргументи, или едно подаване"
 
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "опцията „--bisect-terms“ изисква 0 или 1 аргумента"
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "„%s“ изисква 0 или 1 аргумент"
 
-msgid "--bisect-next requires 0 arguments"
-msgstr "опцията „--bisect-next“ не приема аргументи"
-
-msgid "--bisect-log requires 0 arguments"
-msgstr "опцията „--bisect-log“ не приема аргументи"
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "„%s“ изисква 0 аргументи"
 
 msgid "no logfile given"
 msgstr "не е зададен журнален файл"
 
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "неуспешно изпълнение на „%s“: не е зададена команда."
+
+msgid "need a command"
+msgstr "необходима е команда"
+
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "непозната команда: „%s“"
+
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 msgstr "git blame [ОПЦИЯ…] [ОПЦИЯ_ЗА_ВЕРСИЯТА…] [ВЕРСИЯ] [--] ФАЙЛ"
 
@@ -3425,6 +3453,9 @@
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
 msgstr "git bundle unbundle [--progress] ФАЙЛ [ИМЕ_НА_УКАЗАТЕЛ…]"
 
+msgid "need a <file> argument"
+msgstr "необходим е аргумент ФАЙЛ"
+
 msgid "do not show progress meter"
 msgstr "без извеждане на напредъка"
 
@@ -3479,10 +3510,6 @@
 msgid "%s takes no arguments"
 msgstr "командата „%s“ не приема аргументи"
 
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "непозната команда: „%s“"
-
 msgid "only one batch option may be specified"
 msgstr "може да укажете само една пакетна опция"
 
@@ -3625,11 +3652,18 @@
 msgid "only two arguments allowed in <type> <object> mode, not %d"
 msgstr "в режим с посочен ВИД ОБЕКТ се изискват точно два аргумента, а не %d"
 
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | АТРИБУТ…] [--] ПЪТ…"
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [--source УКАЗАТЕЛ_КЪМ_ДЪРВО] [-a | --all | АТРИБУТ…] [--] "
+"ПЪТ…"
 
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | АТРИБУТ…]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source УКАЗАТЕЛ_КЪМ_ДЪРВО] [-a | --all | "
+"АТРИБУТ…]"
 
 msgid "report all attributes set on file"
 msgstr "извеждане на всички атрибути, зададени върху файл"
@@ -3643,6 +3677,12 @@
 msgid "terminate input and output records by a NUL character"
 msgstr "разделяне на входните и изходните записи с нулевия знак „NUL“"
 
+msgid "<tree-ish>"
+msgstr "УКАЗАТЕЛ_КЪМ_ДЪРВО"
+
+msgid "which tree-ish to check attributes at"
+msgstr "към кой УКАЗАТЕЛ_КЪМ_ДЪРВО да се премине"
+
 msgid "suppress progress reporting"
 msgstr "без показване на напредъка"
 
@@ -4231,7 +4271,7 @@
 "*          — избиране на всички обекти\n"
 "           — (празно) завършване на избирането\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Huh (%s)?\n"
 msgstr "Неправилен избор (%s).\n"
 
@@ -4382,9 +4422,6 @@
 msgid "create a shallow clone of that depth"
 msgstr "плитко клониране до тази ДЪЛБОЧИНА"
 
-msgid "time"
-msgstr "ВРЕМЕ"
-
 msgid "create a shallow clone since a specific time"
 msgstr "плитко клониране до момент във времето"
 
@@ -4635,6 +4672,9 @@
 msgid "failed to fetch objects from bundle URI '%s'"
 msgstr "неуспешно доставяне на обекти от пратка на адрес „%s“"
 
+msgid "failed to fetch advertised bundles"
+msgstr "неуспешно доставяне на обявените за налични пратки"
+
 msgid "remote transport reported error"
 msgstr "отдалеченият транспорт върна грешка"
 
@@ -5918,29 +5958,6 @@
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "не е зададена команда за „--extcmd=КОМАНДА“"
 
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] ОПЦИИ ПРОМЕНЛИВИ"
-
-msgid "default for git_env_*(...) to fall back on"
-msgstr "стандартна, резервна стойност за „git_env_*(…)“"
-
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr ""
-"без извеждане на информация — стойността на „git_env_*()“ да е изходен код"
-
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr ""
-"опцията „--default“ изисква булева стойност при „--type=bool“, а не „%s“"
-
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not "
-"`%s`"
-msgstr ""
-"опцията „--default“ изисква целочислена стойност без знак при „--"
-"type=ulong“, а не „%s“"
-
 msgid "git fast-export [<rev-list-opts>]"
 msgstr "git fast-export [ОПЦИЯ_ЗА_СПИСЪКА_С_ВЕРСИИ…]"
 
@@ -6349,6 +6366,10 @@
 msgid "--unshallow on a complete repository does not make sense"
 msgstr "не може да използвате опцията „--unshallow“ върху пълно хранилище"
 
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "неуспешно доставяне на пратки от „%s“"
+
 msgid "fetch --all does not take a repository argument"
 msgstr "към „git fetch --all“ не може да добавите аргумент-хранилище"
 
@@ -7393,12 +7414,18 @@
 msgid "'git help config' for more information"
 msgstr "За повече информация изпълнете „git help config“"
 
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] КУКА [-- АРГУМЕНТ_ЗА_КУКА…]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=ПЪТ] КУКА [-- АРГУМЕНТ_ЗА_КУКА…]"
 
 msgid "silently ignore missing requested <hook-name>"
 msgstr "прескачане на заявена КУКА, която липсва"
 
+msgid "file to read into hooks' stdin"
+msgstr "файл за изчитане от стандартния вход на куката"
+
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "неправилен вид на обекта „%s“"
@@ -8251,11 +8278,11 @@
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=КОМАНДА]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=КЛЮЧ]\n"
-"              [--symref] [ХРАНИЛИЩЕ [УКАЗАТЕЛ…]]"
+"              [--symref] [ХРАНИЛИЩЕ [ШАБЛОН]]"
 
 msgid "do not print remote URL"
 msgstr "без извеждане на адресите на отдалечените хранилища"
@@ -8507,9 +8534,15 @@
 msgid "perform multiple merges, one per line of input"
 msgstr "извършване на множество сливания, по едно на ред"
 
+msgid "specify a merge-base for the merge"
+msgstr "база за сливането"
+
 msgid "--trivial-merge is incompatible with all other options"
 msgstr "„--trivial-merge“ е несъвместима с другите опции"
 
+msgid "--merge-base is incompatible with --stdin"
+msgstr "опциите „--merge-base“ и „--stdin“ са несъвместими"
+
 #, c-format
 msgid "malformed input line: '%s'."
 msgstr "входен ред с неправилен формат: „%s“."
@@ -10455,6 +10488,9 @@
 msgid "could not switch to %s"
 msgstr "не може да се премине към „%s“"
 
+msgid "apply options and merge options cannot be used together"
+msgstr "опциите за прилагане и сливане са несъвместими"
+
 #, c-format
 msgid ""
 "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
@@ -10700,8 +10736,19 @@
 msgstr ""
 "опцията „--strategy“ изисква някоя от опциите „--merge“ или „--interactive“"
 
-msgid "apply options and merge options cannot be used together"
-msgstr "опциите за прилагане и сливане са несъвместими"
+msgid ""
+"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"autosquash"
+msgstr ""
+"опциите за прилагане са несъвместими с „rebase.autosquash“.  Пробвайте да "
+"добавите опцията „--no-autosquash“"
+
+msgid ""
+"apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
+"update-refs"
+msgstr ""
+"опциите за прилагане са несъвместими с „rebase.updateRefs“.  Пробвайте да "
+"добавите опцията „--no-update-refs“"
 
 #, c-format
 msgid "Unknown rebase backend: %s"
@@ -12221,7 +12268,7 @@
 msgstr "извеждане на недостижимите указатели"
 
 msgid "show commits in topological order"
-msgstr "извеждане на подаванията в топологическа подредба"
+msgstr "извеждане на подаванията в топологична подредба"
 
 msgid "show only commits not on the first branch"
 msgstr "извеждане само на подаванията, които не са от първия клон"
@@ -12231,7 +12278,7 @@
 
 msgid "topologically sort, maintaining date order where possible"
 msgstr ""
-"топологическа подредба, при запазване на подредбата по дата, доколкото е\n"
+"топологична подредба, при запазване на подредбата по дата, доколкото е\n"
 "възможно"
 
 msgid "<n>[,<base>]"
@@ -13247,10 +13294,6 @@
 msgid "git submodule--helper <command>"
 msgstr "git submodule--helper КОМАНДА"
 
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "„%s“ не поддържа опцията „--super-prefix“"
-
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
 msgstr "git symbolic-ref [-m ПРИЧИНА] ИМЕ УКАЗАТЕЛ"
 
@@ -14013,6 +14056,11 @@
 msgstr "„core.fsyncMethod = batch“ не се поддържа на тази платформа"
 
 #, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr ""
+"ключът за списък с пратки „%s“ не може да се анализира със стойност „%s“"
+
+#, c-format
 msgid "bundle list at '%s' has no mode"
 msgstr "липсва режим в списъка от пратки „%s“"
 
@@ -14023,6 +14071,13 @@
 msgstr "недостатъчно възможности"
 
 #, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "изтегленият от адрес „%s“ файл не е пратка"
+
+msgid "failed to store maximum creation token"
+msgstr "неуспешно запазване на данните за последно създаденото"
+
+#, c-format
 msgid "unrecognized bundle mode from URI '%s'"
 msgstr "непознат режим на пратки от адрес „%s“"
 
@@ -14039,6 +14094,13 @@
 msgid "file at URI '%s' is not a bundle or bundle list"
 msgstr "файлът на адрес „%s“ не е нито пратка, нито списък с пратки"
 
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: непознат аргумент: %s"
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: след аргументите се очаква изчистване на буферите"
+
 msgid "bundle-uri: got an empty line"
 msgstr "bundle-uri: получен е празен ред"
 
@@ -14070,6 +14132,13 @@
 msgid "need a repository to verify a bundle"
 msgstr "за проверката на пратка е необходимо хранилище"
 
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+"в хранилището на обекти съществуват необходими подавания, които не са "
+"свързани с историята на хранилището"
+
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -15526,15 +15595,23 @@
 msgstr "сървърът указа непознат формат на обект: „%s“"
 
 #, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "грешка на ред %d в отговора на командата „bundle-uri“: %s"
+
+msgid "expected flush after bundle-uri listing"
+msgstr ""
+"след изброяването на адресите на пратките се очаква изчистване на буферите"
+
+msgid "expected response end packet after ref listing"
+msgstr "след изброяването на указателите се очаква пакет за край"
+
+#, c-format
 msgid "invalid ls-refs response: %s"
 msgstr "неправилен отговор на „ls-refs“: „%s“"
 
 msgid "expected flush after ref listing"
 msgstr "след изброяването на указателите се очаква изчистване на буферите"
 
-msgid "expected response end packet after ref listing"
-msgstr "след изброяването на указателите се очаква пакет за край"
-
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr "протокол „%s“ не се поддържа"
@@ -16673,7 +16750,7 @@
 
 #, c-format
 msgid "Server does not allow request for unadvertised object %s"
-msgstr "Сървърът не позволява заявка за необявен обект „%s“"
+msgstr "Сървърът не позволява заявка за необявен за наличен обект „%s“"
 
 #, c-format
 msgid "fsmonitor_ipc__send_query: invalid path '%s'"
@@ -16720,16 +16797,20 @@
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-"           <command> [<args>]"
+"           [--config-env=<name>=<envvar>] <command> [<args>]"
 msgstr ""
+"git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
+"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
+"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
+"bare]\n"
+"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
+"           [--config-env=<name>=<envvar>] <command> [<args>]\n"
 "git [-v | --version] [-h | --help] [-C ПЪТ] [-c ИМЕ=СТОЙНОСТ]\n"
 "           [--exec-path[=ПЪТ]] [--html-path] [--man-path] [--info-path]\n"
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=ПЪТ] [--work-tree=ПЪТ] [--namespace=ИМЕ]\n"
-"           [--super-prefix=ПЪТ] [--config-env=ИМЕ=ПРОМЕНЛИВА_НА_СРЕДАТА]\n"
-"           КОМАНДА [АРГ…]"
+"           [--config-env=ИМЕ=ПРОМЕНЛИВА_НА_СРЕДАТА] КОМАНДА [АРГ…]"
 
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -16757,10 +16838,6 @@
 msgstr "опцията „--namespace“ изисква име\n"
 
 #, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "опцията „--super-prefix“ изисква префикс\n"
-
-#, c-format
 msgid "-c expects a configuration string\n"
 msgstr "опцията „-c“ изисква низ за настройка\n"
 
@@ -16880,8 +16957,13 @@
 msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
 msgstr "неуспешно изпълнение на „gpg.ssh.defaultKeyCommand“: %s %s"
 
-msgid "gpg failed to sign the data"
-msgstr "Програмата „gpg“ не подписа данните"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"Програмата „gpg“ не подписа данните:\n"
+"%s"
 
 msgid "user.signingKey needs to be set for ssh signing"
 msgstr ""
@@ -17473,7 +17555,7 @@
 "   or update to an existing commit which has merged those changes\n"
 msgstr ""
 " ⁃ преминаване към подмодула (%s), след които или де се слее подаването\n"
-"   „%s“, или да се обновяви към съществуващо подаване, в които\n"
+"   „%s“, или да се обнови към съществуващо подаване, в които\n"
 "   тези промени са слети\n"
 
 #, c-format
@@ -18070,6 +18152,10 @@
 msgstr "грешни данни в края на непакетирания обект „%s“"
 
 #, c-format
+msgid "unable to open loose object %s"
+msgstr "непакетираният обект „%s“ не може да се отвори"
+
+#, c-format
 msgid "unable to parse %s header"
 msgstr "заглавната част на „%s“ не може да бъде анализирана"
 
@@ -18085,18 +18171,14 @@
 msgstr "заглавната част на „%s“ е прекалено дълга — надхвърля %d байта"
 
 #, c-format
-msgid "failed to read object %s"
-msgstr "обектът „%s“ не може да бъде прочетен"
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "непакетираният обект „%s“ (в „%s“) е повреден"
 
 #, c-format
 msgid "replacement %s not found for %s"
 msgstr "заместителят „%s“ на „%s“ не може да бъде открит"
 
 #, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "непакетираният обект „%s“ (в „%s“) е повреден"
-
-#, c-format
 msgid "packed object %s (stored in %s) is corrupt"
 msgstr "пакетираният обект „%s“ (в „%s“) е повреден"
 
@@ -18108,9 +18190,6 @@
 msgid "unable to set permission to '%s'"
 msgstr "права̀та за достъп до „%s“ не може да бъдат зададени"
 
-msgid "file write error"
-msgstr "грешка при запис на файл"
-
 msgid "error when closing loose object file"
 msgstr "грешка при затварянето на файла с непакетиран обект"
 
@@ -18157,11 +18236,12 @@
 msgid "cannot read object for %s"
 msgstr "обектът за „%s“ не може да се прочете"
 
-msgid "corrupt commit"
-msgstr "повредено подаване"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "„fsck“ откри грешка в обект: „%s“"
 
-msgid "corrupt tag"
-msgstr "повреден етикет"
+msgid "refusing to create malformed object"
+msgstr "не може да се създаде сгрешен обект"
 
 #, c-format
 msgid "read error while indexing %s"
@@ -18432,10 +18512,6 @@
 msgid "cannot fstat bitmap file"
 msgstr "не може да се получи информация за файла с битови маски с „fstat“"
 
-#, c-format
-msgid "ignoring extra bitmap file: '%s'"
-msgstr "игнориране на излишния файл с битови маски: „%s“"
-
 msgid "checksum doesn't match in MIDX and bitmap"
 msgstr ""
 "сумата за проверка се различава във файла с индекса за множество пакети и "
@@ -18721,6 +18797,9 @@
 msgid "use <n> digits to display object names"
 msgstr "да се показват такъв БРОЙ цифри от имената на обектите"
 
+msgid "prefixed path to initial superproject"
+msgstr "път с префикс към първоначалния свръхпроект"
+
 msgid "how to strip spaces and #comments from message"
 msgstr "кои празни знаци и #коментари да се махат от съобщенията"
 
@@ -19240,6 +19319,14 @@
 msgstr "напред с %d, назад с %d"
 
 #, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) не приема аргументи"
+
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "непознат аргумент за „%%(%.*s)“: %s"
+
+#, c-format
 msgid "expected format: %%(color:<color>)"
 msgstr "очакван формат: %%(color:ЦВЯТ)"
 
@@ -19256,22 +19343,6 @@
 msgstr "очаква се цяло число за „refname:rstrip=%s“"
 
 #, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "непознат аргумент за „%%(%s)“: %s"
-
-#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) не приема аргументи"
-
-#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) не приема аргументи"
-
-#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) не приема аргументи"
-
-#, c-format
 msgid "expected %%(trailers:key=<value>)"
 msgstr "очаква се %%(trailers:key=ЕПИЛОГ)"
 
@@ -19288,10 +19359,6 @@
 msgstr "очаква се положителна стойност за „%s“ в %%(%s)"
 
 #, c-format
-msgid "unrecognized email option: %s"
-msgstr "непозната опция за е-поща: %s"
-
-#, c-format
 msgid "expected format: %%(align:<width>,<position>)"
 msgstr "очакван формат: %%(align:ШИРОЧИНА,ПОЗИЦИЯ)"
 
@@ -19304,12 +19371,12 @@
 msgstr "непозната широчина: %s"
 
 #, c-format
-msgid "positive width expected with the %%(align) atom"
-msgstr "очаква се положителна широчина с лексемата „%%(align)“"
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "непознат аргумент за „%%(%s)“: %s"
 
 #, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) не приема аргументи"
+msgid "positive width expected with the %%(align) atom"
+msgstr "очаква се положителна широчина с лексемата „%%(align)“"
 
 #, c-format
 msgid "malformed field name: %.*s"
@@ -20601,6 +20668,23 @@
 msgstr "git %s: неуспешно обновяване на индекса"
 
 #, c-format
+msgid "'%s' is not a valid label"
+msgstr "„%s“ е неправилен етикет"
+
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "„%s“ е неправилно име на указател"
+
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr ""
+"командата „update-ref“ изисква пълно име на указател, напр. „refs/heads/%s“"
+
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "неправилна команда „%.*s“"
+
+#, c-format
 msgid "%s does not accept arguments: '%s'"
 msgstr "„%s“ не приема аргументи: „%s“"
 
@@ -21426,6 +21510,16 @@
 msgid "failed to lstat '%s'"
 msgstr "не може да бъде получена информация чрез „lstat“ за „%s“"
 
+msgid "no remote configured to get bundle URIs from"
+msgstr "не е настроено отдалечено хранилище за списъците с адреси на пратки"
+
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "не е зададен никакъв адрес за отдалеченото хранилище„%s“"
+
+msgid "could not get the bundle-uri list"
+msgstr "списъкът с адреси на пратки не може да се получи"
+
 msgid "test-tool cache-tree <options> (control|prime|update)"
 msgstr "test-tool cache-tree ОПЦИЯ… (control|prime|update)"
 
@@ -21785,6 +21879,14 @@
 msgid "failed to push all needed submodules"
 msgstr "неуспешно изтласкване на всички необходими подмодули"
 
+msgid "bundle-uri operation not supported by protocol"
+msgstr "операцията „bundle-uri“ (адреси на пратки) не се поддържа от протокола"
+
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr ""
+"спъсъкът с адреси на пратки обявени за налични от сървъра не може да се "
+"получи "
+
 msgid "too-short tree object"
 msgstr "прекалено кратък обект-дърво"
 
@@ -22533,14 +22635,18 @@
 
 #, c-format
 msgid ""
-"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-"may speed it up, but you have to be careful not to forget to add\n"
-"new files yourself (see 'git help status')."
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
 msgstr ""
-"Бяха необходими %.2f секунди за изброяването на неследените файлове.\n"
-"Добавянето на опцията „-uno“ към командата „git status“ ще ускори\n"
-"изпълнението, но ще трябва да добавяте новите файлове ръчно.\n"
-"За повече подробности погледнете „git status help“."
+"Изброяването на неследените файлове отне %.2f секунди, но\n"
+"резултатите са запомнени и може да забързат последващиге изброявания."
+
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr "Изброяването на неследените файлове отне %.2f секунди."
+
+msgid "See 'git help status' for information on how to improve this."
+msgstr "Вижте в „git help status“ за начините да подобрите това."
 
 #, c-format
 msgid "Untracked files not listed%s"
@@ -22689,294 +22795,6 @@
 msgid "Unable to determine absolute path of git directory"
 msgstr "Абсолютният път на работното дърво не може да се определи"
 
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#, perl-format
-msgid "%12s %12s %s"
-msgstr "%14s %14s %s"
-
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] "%d файл засегнат\n"
-msgstr[1] "%d файла засегнати\n"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr ""
-"Ако кръпката може да се приложи чисто, редактираното парче ще бъде "
-"незабавно\n"
-"добавено към индекса"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr ""
-"Ако кръпката може да се приложи чисто, редактираното парче ще бъде "
-"незабавно\n"
-"скътано"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr ""
-"Ако кръпката може да се приложи чисто, редактираното парче ще бъде "
-"незабавно\n"
-"извадено от индекса."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr ""
-"Ако кръпката може да се приложи чисто, редактираното парче ще бъде "
-"незабавно\n"
-"набелязано за прилагане."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr ""
-"Ако кръпката може да се приложи чисто, редактираното парче ще бъде "
-"незабавно\n"
-"набелязано за зануляване."
-
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr "файлът за редактиране на парчето код не може да бъде отворен: „%s“"
-
-#, perl-format
-msgid ""
-"---\n"
-"To remove '%s' lines, make them ' ' lines (context).\n"
-"To remove '%s' lines, delete them.\n"
-"Lines starting with %s will be removed.\n"
-msgstr ""
-"———\n"
-"За да пропуснете редовете започващи с „%s“ — заменете знака със „ “ (стават "
-"контекст)\n"
-"За да пропуснете редовете започващи с „%s“ — изтрийте ги.\n"
-"Редовете, които започват с „%s“ ще бъдат пропуснати.\n"
-
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr ""
-"файлът за редактиране на парчето код не може да бъде отворен за четене: „%s“"
-
-msgid ""
-"y - stage this hunk\n"
-"n - do not stage this hunk\n"
-"q - quit; do not stage this hunk or any of the remaining ones\n"
-"a - stage this hunk and all later hunks in the file\n"
-"d - do not stage this hunk or any of the later hunks in the file"
-msgstr ""
-"y — добавяне на парчето в индекса\n"
-"n — без добавяне на парчето в индекса\n"
-"q — изход, без добавяне на това и всички оставащи парчета от файла\n"
-"a — добавяне на това и всички следващи парчета от файла в индекса\n"
-"d — без добавяне на това и всички следващи парчета от файла в индекса"
-
-msgid ""
-"y - stash this hunk\n"
-"n - do not stash this hunk\n"
-"q - quit; do not stash this hunk or any of the remaining ones\n"
-"a - stash this hunk and all later hunks in the file\n"
-"d - do not stash this hunk or any of the later hunks in the file"
-msgstr ""
-"y — скатаване на парчето\n"
-"n — без скатаване на парчето\n"
-"q — изход, без скатаване на това и всички оставащи парчета\n"
-"a — скатаване на това и всички следващи парчета от файла\n"
-"d — без скатаване на това и всички следващи парчета от файла"
-
-msgid ""
-"y - unstage this hunk\n"
-"n - do not unstage this hunk\n"
-"q - quit; do not unstage this hunk or any of the remaining ones\n"
-"a - unstage this hunk and all later hunks in the file\n"
-"d - do not unstage this hunk or any of the later hunks in the file"
-msgstr ""
-"y — изваждане на парчето от индекса\n"
-"n — без изваждане на парчето от индекса\n"
-"q — изход, без изваждане на това и всички оставащи парчета от индекса\n"
-"a — изваждане на това и всички следващи парчета от файла от индекса\n"
-"d — без изваждане на това и всички следващи парчета от файла от индекса"
-
-msgid ""
-"y - apply this hunk to index\n"
-"n - do not apply this hunk to index\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y — прилагане на парчето към индекса\n"
-"n — без прилагане на парчето към индекса\n"
-"q — изход, без прилагане на това и всички оставащи парчета към индекса\n"
-"a — прилагане на това и всички следващи парчета от файла към индекса\n"
-"d — без прилагане на това и всички следващи парчета от файла към индекса"
-
-msgid ""
-"y - discard this hunk from worktree\n"
-"n - do not discard this hunk from worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y — премахване на парчето от работното дърво\n"
-"n — без премахване на парчето от работното дърво\n"
-"q — изход, без премахване на това и всички оставащи парчета от работното "
-"дърво\n"
-"a — премахване на това и всички следващи парчета от файла от работното "
-"дърво\n"
-"d — без премахване на това и всички следващи парчета от файла от работното "
-"дърво"
-
-msgid ""
-"y - discard this hunk from index and worktree\n"
-"n - do not discard this hunk from index and worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y — премахване на парчето от индекса и работното дърво\n"
-"n — без премахване на парчето от индекса и работното дърво\n"
-"q — изход, без премахване на това и всички оставащи парчета от индекса и "
-"работното дърво\n"
-"a — премахване на това и всички следващи парчета от файла от индекса и "
-"работното дърво\n"
-"d — без премахване на това и всички следващи парчета от файла от индекса и "
-"работното дърво"
-
-msgid ""
-"y - apply this hunk to index and worktree\n"
-"n - do not apply this hunk to index and worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y — прилагане на парчето от индекса и работното дърво\n"
-"n — без прилагане на парчето от индекса и работното дърво\n"
-"q — изход, без прилагане на това и всички оставащи парчета от индекса и "
-"работното дърво\n"
-"a — прилагане на това и всички следващи парчета от файла от индекса и "
-"работното дърво\n"
-"d — без прилагане на това и всички следващи парчета от файла от индекса и "
-"работното дърво"
-
-msgid ""
-"y - apply this hunk to worktree\n"
-"n - do not apply this hunk to worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y — прилагане на парчето към работното дърво\n"
-"n — без прилагане на парчето към работното дърво\n"
-"q — изход, без прилагане на това и всички оставащи парчета\n"
-"a — прилагане на това и всички следващи парчета от файла\n"
-"d — без прилагане на това и всички следващи парчета от файла"
-
-msgid ""
-"g - select a hunk to go to\n"
-"/ - search for a hunk matching the given regex\n"
-"j - leave this hunk undecided, see next undecided hunk\n"
-"J - leave this hunk undecided, see next hunk\n"
-"k - leave this hunk undecided, see previous undecided hunk\n"
-"K - leave this hunk undecided, see previous hunk\n"
-"s - split the current hunk into smaller hunks\n"
-"e - manually edit the current hunk\n"
-"? - print help\n"
-msgstr ""
-"g — избор към кое парче да се премине\n"
-"/ — търсене на парче, напасващо към даден регулярен израз\n"
-"j — без решение за парчето, към следващото парче без решение\n"
-"J — без решение за парчето, към следващото парче\n"
-"k — без решение за парчето, към предишното парче без решение\n"
-"K — без решение за парчето, към предишното парче\n"
-"s — разделяне на текущото парче на по-малки\n"
-"e — ръчно редактиране на текущото парче\n"
-"? — извеждане не помощта\n"
-
-msgid "The selected hunks do not apply to the index!\n"
-msgstr "Избраните парчета не може да се добавят в индекса!\n"
-
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "пренебрегване на неслятото: „%s“\n"
-
-msgid "No other hunks to goto\n"
-msgstr "Няма други парчета\n"
-
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "Неправилен номер: „%s“\n"
-
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "Има само %d парче.\n"
-msgstr[1] "Има само %d парчета.\n"
-
-msgid "No other hunks to search\n"
-msgstr "Няма други парчета за търсене\n"
-
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "Сгрешен регулярен израз „%s“: %s\n"
-
-msgid "No hunk matches the given pattern\n"
-msgstr "Никое парче не напасва на регулярния израз\n"
-
-msgid "No previous hunk\n"
-msgstr "Няма друго парче преди това\n"
-
-msgid "No next hunk\n"
-msgstr "Няма друго парче след това\n"
-
-msgid "Sorry, cannot split this hunk\n"
-msgstr "Това парче не може да бъде разделено\n"
-
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "Разделяне на %d парче.\n"
-msgstr[1] "Разделяне на %d парчета.\n"
-
-msgid "Sorry, cannot edit this hunk\n"
-msgstr "Това парче не може да бъде редактирано\n"
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-msgid ""
-"status        - show paths with changes\n"
-"update        - add working tree state to the staged set of changes\n"
-"revert        - revert staged set of changes back to the HEAD version\n"
-"patch         - pick hunks and update selectively\n"
-"diff          - view diff between HEAD and index\n"
-"add untracked - add contents of untracked files to the staged set of "
-"changes\n"
-msgstr ""
-"status        — извеждане на пътищата с промѐните\n"
-"update        — добавяне на състоянието на работното дърво към промѐните в\n"
-"                индекса\n"
-"revert        — отмяна на промѐните в индекса към състоянието сочено от "
-"„HEAD“\n"
-"patch         — избиране на парчета код и обновяване поединично\n"
-"diff          — извеждане на разликата между състоянието на соченото от "
-"„HEAD“\n"
-"                и индекса\n"
-"add untracked — добавяне на неследените файлове към промѐните в индекса\n"
-
-msgid "missing --"
-msgstr "„--“ липсва"
-
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "неизвестна стратегия за прилагане на кръпка към „--patch“: „%s“"
-
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "указан е неправилен аргумент „%s“, а се очаква „--“."
-
 msgid "local zone differs from GMT by a non-minute interval\n"
 msgstr ""
 "разликата между местния часови пояс и GMT съдържа дробна част от минута\n"
diff --git a/po/ca.po b/po/ca.po
index 9141148..c6d2dd6 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -1,7 +1,7 @@
 # Catalan translations for Git.
 # This file is distributed under the same license as the Git package.
 # Alex Henrie <alexhenrie24@gmail.com>, 2014-2016.
-# Jordi Mas i Hernàndez <jmas@softcatala.org>, 2016-2022
+# Jordi Mas i Hernàndez <jmas@softcatala.org>, 2016-2023
 #
 # Terminologia i criteris utilitzats
 #
@@ -68,8 +68,8 @@
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-12-07 07:33+0100\n"
-"PO-Revision-Date: 2022-12-07 19:00-0600\n"
+"POT-Creation-Date: 2023-03-01 01:20+0000\n"
+"PO-Revision-Date: 2023-03-01 19:00-0600\n"
 "Last-Translator: Jordi Mas i Hernàndez <jmas@softcatala.org>\n"
 "Language-Team: Catalan\n"
 "Language: ca\n"
@@ -105,13 +105,13 @@
 msgid "could not write index"
 msgstr "no s'ha pogut escriure l'índex"
 
-#, c-format, perl-format
+#, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "actualitzat %d camí\n"
 msgstr[1] "actualitzats %d camins\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "nota: %s està ara sense seguiment.\n"
 
@@ -125,7 +125,7 @@
 msgid "Could not parse HEAD^{tree}"
 msgstr "No s'ha pogut analitzar HEAD^{tree}"
 
-#, c-format, perl-format
+#, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "revertit %d camí\n"
@@ -138,7 +138,7 @@
 msgid "Add untracked"
 msgstr "Afegeix sense seguiment"
 
-#, c-format, perl-format
+#, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "afegit %d camí\n"
@@ -232,19 +232,19 @@
 msgid "Bye.\n"
 msgstr "Adeu.\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "Canvia el mode de «stage» [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "Suprimeix «stage» [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "Afegeix a «stage» [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Fer un «stage» d'aquest tros [y,n,q,a,d%s,?]? "
 
@@ -268,19 +268,19 @@
 "a - fes «stage» d'aquest tros i de tota la resta de trossos del fitxer\n"
 "d - no facis «stage» d'aquest tros ni de cap altre restant del fitxer\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "Canvia el mode de «stash» [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "Suprimeix «stash» [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "Afegeix a «stash» [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "Fer un «stash» d'aquest tros [y,n,q,a,d%s,?]? "
 
@@ -304,19 +304,19 @@
 "a - fes «stash» d'aquest tros i de tota la resta de trossos del fitxer\n"
 "d - no facis «stash» d'aquest tros ni de cap altre restant del fitxer\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "Canvia el mode de «unstage» [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "Suprimeix «Unstage» [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "Afegeix a «unstage» [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Fer un «unstage» d'aquest tros [y,n,q,a,d%s,?]? "
 
@@ -340,19 +340,19 @@
 "a - fes «unstage» d'aquest tros i de tota la resta de trossos del fitxer\n"
 "d - no facis «unstage» d'aquest tros ni de cap altre restant del fitxer\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr "Aplica el canvi de mode a l'índex [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "Aplica la supressió a l'índex [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "Aplica l'addició a l'índex [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "Aplica aquest tros a l'índex [y,n,q,a,d%s,?]? "
 
@@ -376,19 +376,19 @@
 "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr "Descarta el canvi de mode de l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "Descarta suprimir de l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "Descarta l'addició de l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
 msgstr "Descarta aquest tros de l'arbre de treball [y,n,q,a,d%s,?]? "
 
@@ -412,22 +412,22 @@
 "a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Descarta el canvi de mode de l'índex i de l'arbre de treball [y,n,q,a,"
 "d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Descarta suprimir de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Descarta l'addició de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Descarta aquest tros de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
@@ -445,20 +445,20 @@
 "a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Aplica el canvi de mode a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica la supressió a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica l'addició a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica aquest tros a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
 
@@ -475,19 +475,19 @@
 "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica el canvi de mode a l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica la supressió a l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica l'addició a l'arbre de treball [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica aquest tros a l'arbre de treball [y,n,q,a,d%s,?]? "
 
@@ -564,8 +564,6 @@
 "Per a eliminar les línies «%c», suprimiu-les.\n"
 "Les línies que comencin per %c s'eliminaran.\n"
 
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
 "edit again.  If all lines of the hunk are removed, then the edit is\n"
@@ -581,20 +579,12 @@
 msgid "'git apply --cached' failed"
 msgstr "«git apply --cached» ha fallat"
 
-#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr ""
@@ -1443,6 +1433,12 @@
 msgid "report archived files on stderr"
 msgstr "informa de fitxers arxivats en stderr"
 
+msgid "time"
+msgstr "data"
+
+msgid "set modification time of archive entries"
+msgstr "estableix l'hora de modificació de les entrades de l'arxiu"
+
 msgid "set compression level"
 msgstr "estableix el nivell de compressió"
 
@@ -1483,6 +1479,13 @@
 msgid "%.*s is not a valid attribute name"
 msgstr "%.*s no és un nom d'atribut vàlid"
 
+msgid "unable to add additional attribute"
+msgstr "no s'ha pogut afegir l'atribut addicional"
+
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "s'ignorarà la línia d'atributs massa llarga %d"
+
 #, c-format
 msgid "%s not allowed: %s:%d"
 msgstr "%s no està permès: %s:%d"
@@ -1495,6 +1498,18 @@
 "Useu «\\!» per exclamació capdavantera literal."
 
 #, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "no es pot fer fstat gitattributes al fitxer «%s»"
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "s'ignorarà el fitxer «%s» gitattributes per massa gran"
+
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "s'ignorarà la blob «%s» gitattributes per massa gran"
+
+#, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Comentari amb cometes errònies en el fitxer «%s»: %s"
 
@@ -1773,11 +1788,11 @@
 
 #, c-format
 msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
 msgstr ""
-"Podeu provar d'actualitzar els submòduls utilitzant «git checkout %s && git "
-"submodule update --init»"
+"Podeu provar d'actualitzar els submòduls utilitzant «git checkout --no-"
+"recurse-submodules %s && git submodule update --init»"
 
 #, c-format
 msgid "submodule '%s': cannot create branch '%s'"
@@ -1812,6 +1827,13 @@
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Canvis «unstaged» després d'actualitzar l'índex:"
 
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"s'ha eliminat la configuració add.interactive.useBuiltin\n"
+"Per a més detalls, vegeu la seva entrada a «git help config»."
+
 msgid "Could not read the index"
 msgstr "No s'ha pogut llegir l'índex"
 
@@ -2201,6 +2223,9 @@
 msgid "run interactively"
 msgstr "executa interactivament"
 
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "evita els lligams pre-applypatch i applypatch-msg"
+
 msgid "historical option -- no-op"
 msgstr "opció històrica -- no-op"
 
@@ -2344,32 +2369,27 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: s'esperava una neteja"
 
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [<comissió>]"
-
 msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (bad|new) [<rev>]"
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<rev>...]"
 
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (good|old) [<rev>...]"
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<rev>|<range>)...]"
 
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay <filename>"
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<comissió>]"
 
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <logfile>"
 
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run <ordre>..."
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run <ordre>..."
 
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
@@ -2519,9 +2539,6 @@
 msgstr ""
 "l'agafament de «%s» ha fallat. Proveu «git bisect start <branca-vàlida>»."
 
-msgid "won't bisect on cg-seek'ed tree"
-msgstr "no es bisecarà en un arbre en el qual s'ha fet cg-seek"
-
 msgid "bad HEAD - strange symbolic ref"
 msgstr "HEAD incorrecte - referència simbòlica estranya"
 
@@ -2573,7 +2590,7 @@
 msgstr "ha fallat l'execució de bisect: no s'ha proporcionat cap ordre."
 
 #, c-format
-msgid "unable to verify '%s' on good revision"
+msgid "unable to verify %s on good revision"
 msgstr "no s'ha pogut verificar «%s» en una bona revisió"
 
 #, c-format
@@ -2581,10 +2598,10 @@
 msgstr "codi d'error de sortida %d per a una bona revisió"
 
 #, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
 msgstr ""
-"l'execució de la de bisecció ha fallat: codi de sortida %d de «%s» és < 0 o "
-">= 128"
+"l'execució de la de bisecció ha fallat: codi de sortida %d de %s és < 0 o >= "
+"128"
 
 #, c-format
 msgid "cannot open file '%s' for writing"
@@ -2593,37 +2610,44 @@
 msgid "bisect run cannot continue any more"
 msgstr "l'execució de la bisecció no pot continuar més"
 
-#, c-format
 msgid "bisect run success"
 msgstr "execució de bisecció amb èxit"
 
-#, c-format
 msgid "bisect found first bad commit"
 msgstr "la bisecció ha trobat una primera comissió errònia"
 
 #, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
 msgstr ""
-"l'execució de la bisecció ha fallat: «git bisect--helper --bisect-state %s» "
-"ha sortit amb el codi d'error %d"
+"ha fallat l'execució del bisect: «git bisect %s» ha sortit amb el codi "
+"d'error %d"
 
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "--bisect-reset no requereix cap argument ni comissió"
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "«%s» no requereix cap argument ni comissió"
 
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "--bisect-terms requereix 0 o 1 argument"
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "%s requereix 0 o 1 arguments"
 
-msgid "--bisect-next requires 0 arguments"
-msgstr "--bisect-next no requereix cap argument"
-
-msgid "--bisect-log requires 0 arguments"
-msgstr "--bisect-log no requereix cap argument"
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "«%s» requereix 0 arguments"
 
 msgid "no logfile given"
 msgstr "no s'ha donat cap fitxer de registre"
 
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "«%s» ha fallat: no s'ha proporcionat cap ordre."
+
+msgid "need a command"
+msgstr "cal una subordre"
+
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "ordre desconeguda: «%s»"
+
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 msgstr "git blame [<opcions>] [<opcions-de-revisió>] [<revisió>] [--] fitxer"
 
@@ -3203,6 +3227,9 @@
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
 msgstr "git bundle unbundle [--progress] <fitxer> [<refname>...]"
 
+msgid "need a <file> argument"
+msgstr "necessita un argument <fitxer>"
+
 msgid "do not show progress meter"
 msgstr "no mostris l'indicador de progrés"
 
@@ -3256,10 +3283,6 @@
 msgid "%s takes no arguments"
 msgstr "%s no accepta cap valor"
 
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "ordre desconeguda: «%s»"
-
 msgid "only one batch option may be specified"
 msgstr "només es pot especificar una opció per lots"
 
@@ -3395,11 +3418,17 @@
 msgid "only two arguments allowed in <type> <object> mode, not %d"
 msgstr "només es permeten dos arguments en el mode <tipus> <objecte>, no %d"
 
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | <atribut>...] [--] <nom-de-camí>..."
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
 
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | <atribut>...]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
 
 msgid "report all attributes set on file"
 msgstr "informa de tots els atributs establerts en el fitxer"
@@ -3413,6 +3442,12 @@
 msgid "terminate input and output records by a NUL character"
 msgstr "acaba els registres d'entrada i de sortida amb un caràcter NUL"
 
+msgid "<tree-ish>"
+msgstr "<tree-ish>"
+
+msgid "which tree-ish to check attributes at"
+msgstr "a quin tree-ish s'han de comprovar els atributs"
+
 msgid "suppress progress reporting"
 msgstr "omet els informes de progrés"
 
@@ -3993,7 +4028,7 @@
 "*          - tria tots els ítems\n"
 "           - (buit) finalitza la selecció\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Huh (%s)?\n"
 msgstr "Perdó (%s)?\n"
 
@@ -4142,9 +4177,6 @@
 msgid "create a shallow clone of that depth"
 msgstr "crea un clon superficial d'aquesta profunditat"
 
-msgid "time"
-msgstr "data"
-
 msgid "create a shallow clone since a specific time"
 msgstr "crea un clon superficial des d'una data específica"
 
@@ -4377,6 +4409,9 @@
 msgid "failed to fetch objects from bundle URI '%s'"
 msgstr "no s'han pogut obtenir els objectes de l'URI del paquet «%s»"
 
+msgid "failed to fetch advertised bundles"
+msgstr "no s'han pogut obtenir els paquets anunciats"
+
 msgid "remote transport reported error"
 msgstr "el transport remot ha informat d'un error"
 
@@ -5625,27 +5660,6 @@
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "no s'ha proporcionat l'<ordre> per a --extcmd=<ordre>"
 
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] <opcions> <env-var>"
-
-msgid "default for git_env_*(...) to fall back on"
-msgstr "valor per defecte per a git_env_*(...) en cas d'absència"
-
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr "silenciós només utilitza el valor git_env_*() com a codi de sortida"
-
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr "l'opció «--default» espera un valor booleà amb «--type=bool», no «%s»"
-
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not "
-"`%s`"
-msgstr ""
-"l'opció «--default» espera un valor llarg sense signe amb «--type=ulong», no "
-"«%s»"
-
 msgid "git fast-export [<rev-list-opts>]"
 msgstr "git fast-export [<rev-list-opts>]"
 
@@ -6055,6 +6069,10 @@
 msgid "--unshallow on a complete repository does not make sense"
 msgstr "--unshallow en un repositori complet no té sentit"
 
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "no s'han pogut obtenir els paquets de «%s»"
+
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all no accepta un argument de repositori"
 
@@ -7087,12 +7105,19 @@
 msgid "'git help config' for more information"
 msgstr "«git help config» per a més informació"
 
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=<camí>] <hook-name> [-- <hook-"
+"args>]"
 
 msgid "silently ignore missing requested <hook-name>"
 msgstr "ignora silenciosament la sol·licitud <hook-name> perduda"
 
+msgid "file to read into hooks' stdin"
+msgstr "fitxer per a llegir a l'entrada estàndard dels lligams"
+
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "hi ha una discordança de tipus d'objecte a %s"
@@ -7929,11 +7954,11 @@
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 
 msgid "do not print remote URL"
 msgstr "no imprimeixis l'URL remot"
@@ -8179,9 +8204,15 @@
 msgid "perform multiple merges, one per line of input"
 msgstr "realitza múltiples fusions, una per línia d'entrada"
 
+msgid "specify a merge-base for the merge"
+msgstr "cal especificar una referència base per a la fusió"
+
 msgid "--trivial-merge is incompatible with all other options"
 msgstr "--trivial-merge és incompatible amb totes les altres opcions"
 
+msgid "--merge-base is incompatible with --stdin"
+msgstr "--merge-base és incompatible amb --stdin"
+
 #, c-format
 msgid "malformed input line: '%s'."
 msgstr "línia d'entrada mal formada: «%s»."
@@ -10102,6 +10133,9 @@
 msgid "could not switch to %s"
 msgstr "no s'ha pogut commutar a %s"
 
+msgid "apply options and merge options cannot be used together"
+msgstr "les opcions apply i merge no es poden usar juntes"
+
 #, c-format
 msgid ""
 "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
@@ -10312,7 +10346,7 @@
 "and run me again.  I am stopping in case you still have something\n"
 "valuable there.\n"
 msgstr ""
-"Sembla que ja exigeix un directori %s, i em pregunto\n"
+"Sembla que ja existeix un directori %s, i em pregunto\n"
 "si esteu enmig d'un altre «rebase». Si aquest és el cas, proveu\n"
 "\t%s\n"
 "Si no és cas, feu:\n"
@@ -10330,8 +10364,19 @@
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy requereix --merge o --interactive"
 
-msgid "apply options and merge options cannot be used together"
-msgstr "les opcions apply i merge no es poden usar juntes"
+msgid ""
+"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"autosquash"
+msgstr ""
+"les opcions «apply» són incompatibles amb rebase.autosquash. Considereu "
+"afegir-hi --no-autosquash"
+
+msgid ""
+"apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
+"update-refs"
+msgstr ""
+"les opcions «apply» són incompatibles amb rebase.updateRefs. Considereu "
+"afegir-hi --no-update-refs"
 
 #, c-format
 msgid "Unknown rebase backend: %s"
@@ -12846,10 +12891,6 @@
 msgid "git submodule--helper <command>"
 msgstr "git submodule--helper <command>"
 
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s no admet --super-prefix"
-
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
 msgstr "git symbolic-ref [-m <reason>] <name> <ref>"
 
@@ -13597,6 +13638,11 @@
 msgstr "core.fsyncMethod = batch no és compatible amb aquesta plataforma"
 
 #, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr ""
+"no s'ha pogut analitzar la clau de llista de paquets %s amb el valor «%s»"
+
+#, c-format
 msgid "bundle list at '%s' has no mode"
 msgstr "la llista de farcells a «%s» no té mode"
 
@@ -13607,6 +13653,13 @@
 msgstr "capacitats insuficients"
 
 #, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "el fitxer baixat de «%s» no és un paquet"
+
+msgid "failed to store maximum creation token"
+msgstr "no s'ha pogut emmagatzemar el testimoni de creació màxim"
+
+#, c-format
 msgid "unrecognized bundle mode from URI '%s'"
 msgstr "no s'ha reconegut el model del farcell de l'URI «%s»"
 
@@ -13622,6 +13675,13 @@
 msgid "file at URI '%s' is not a bundle or bundle list"
 msgstr "el fitxer a l'URI «%s» no és farcell o una llista de farcells"
 
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: argument inesperat: «%s»"
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: s'esperava una neteja després dels arguments"
+
 msgid "bundle-uri: got an empty line"
 msgstr "bundle-uri: té una línia buida"
 
@@ -13653,6 +13713,13 @@
 msgid "need a repository to verify a bundle"
 msgstr "cal un repositori per a verificar un farcell"
 
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+"hi ha algunes comissions requerides al magatzem d'objectes, però no estan "
+"connectades a l'historial del repositori"
+
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -15096,16 +15163,23 @@
 msgstr "format d'objecte «%s» especificat pel servidor desconegut"
 
 #, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "error a la línia de resposta de bundle-uri %d: %s"
+
+msgid "expected flush after bundle-uri listing"
+msgstr "s'esperava un buidatge després del llistat de bundle-uri"
+
+msgid "expected response end packet after ref listing"
+msgstr ""
+"s'esperava un paquet de final de resposta després del llistat de referències"
+
+#, c-format
 msgid "invalid ls-refs response: %s"
 msgstr "resposta de ls-refs no vàlida: %s"
 
 msgid "expected flush after ref listing"
 msgstr "s'esperava una neteja després del llistat de referències"
 
-msgid "expected response end packet after ref listing"
-msgstr ""
-"s'esperava un paquet de final de resposta després del llistat de referències"
-
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr "el protocol «%s» no és compatible"
@@ -15479,7 +15553,7 @@
 "unknown color-moved-ws mode '%s', possible values are 'ignore-space-change', "
 "'ignore-space-at-eol', 'ignore-all-space', 'allow-indentation-change'"
 msgstr ""
-"el mode «%s» de «color-moved-ws» és desconegut, els valor possibles són "
+"el mode «%s» de «color-moved-ws» és desconegut, els valors possibles són "
 "«ignore-space-change», «ignore-space-at-eol», «ignore-all-space», «allow-"
 "indentation-change»"
 
@@ -16284,16 +16358,14 @@
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-"           <command> [<args>]"
+"           [--config-env=<name>=<envvar>] <command> [<args>]"
 msgstr ""
-"git [-v | --version] [-h | --help] [-C <camí>] [-c <name>=<value>]\n"
-"           [--exec-path[=<camí>]] [--html-path] [--man-path] [--info-path]\n"
+"git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
+"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
-"           [--git-dir=<camí>] [--work-tree=<camí>] [--namespace=<name>]\n"
-"           [--super-prefix=<camí>] [--config-env=<name>=<envvar>]\n"
-"           <command> [<args>]"
+"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
+"           [--config-env=<name>=<envvar>] <command> [<args>]"
 
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -16319,10 +16391,6 @@
 msgstr "no s'ha especificat un nom d'espai per --namespace\n"
 
 #, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "no s'ha especificat cap prefix per a --super-prefix\n"
-
-#, c-format
 msgid "-c expects a configuration string\n"
 msgstr "-c espera una cadena de configuració\n"
 
@@ -16434,8 +16502,13 @@
 msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
 msgstr "gpg.ssh.defaultKeyCommand ha fallat: %s %s"
 
-msgid "gpg failed to sign the data"
-msgstr "gpg ha fallat en signar les dades"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg ha fallat en signar les dades:\n"
+"%s"
 
 msgid "user.signingKey needs to be set for ssh signing"
 msgstr "user.signingKey s'ha d'establir per a signar amb ssh"
@@ -17605,6 +17678,10 @@
 msgstr "brossa al final de l'objecte solt «%s»"
 
 #, c-format
+msgid "unable to open loose object %s"
+msgstr "no s'ha pogut obrir l'objecte solt %s"
+
+#, c-format
 msgid "unable to parse %s header"
 msgstr "no s'ha pogut analitzar la capçalera %s"
 
@@ -17620,18 +17697,14 @@
 msgstr "la capçalera per a %s és massa llarga, supera els %d bytes"
 
 #, c-format
-msgid "failed to read object %s"
-msgstr "s'ha produït un error en llegir l'objecte %s"
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "l'objecte solt %s (emmagatzemat a %s) és corrupte"
 
 #, c-format
 msgid "replacement %s not found for %s"
 msgstr "no s'ha trobat el reemplaçament %s per a %s"
 
 #, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "l'objecte solt %s (emmagatzemat a %s) és corrupte"
-
-#, c-format
 msgid "packed object %s (stored in %s) is corrupt"
 msgstr "l'objecte empaquetat %s (emmagatzemat a %s) és corrupte"
 
@@ -17643,9 +17716,6 @@
 msgid "unable to set permission to '%s'"
 msgstr "no s'ha pogut establir el permís a «%s»"
 
-msgid "file write error"
-msgstr "s'ha produït un error en escriure al fitxer"
-
 msgid "error when closing loose object file"
 msgstr "error en tancar el fitxer d'objecte solt"
 
@@ -17693,11 +17763,12 @@
 msgid "cannot read object for %s"
 msgstr "no es pot llegir l'objecte per a %s"
 
-msgid "corrupt commit"
-msgstr "comissió corrupta"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "l'objecte ha fallat fsck: %s"
 
-msgid "corrupt tag"
-msgstr "etiqueta corrupta"
+msgid "refusing to create malformed object"
+msgstr "es nega a crear un objecte mal format"
 
 #, c-format
 msgid "read error while indexing %s"
@@ -17966,10 +18037,6 @@
 msgid "cannot fstat bitmap file"
 msgstr "no es pot fer fstat en el fitxer de mapa de bits"
 
-#, c-format
-msgid "ignoring extra bitmap file: '%s'"
-msgstr "s'ignorarà el fitxer extra de mapa de bits: «%s»"
-
 msgid "checksum doesn't match in MIDX and bitmap"
 msgstr "la suma de verificació no coincideix amb el MIDX i el mapa de bits"
 
@@ -18240,6 +18307,9 @@
 msgid "use <n> digits to display object names"
 msgstr "usa <n> xifres per a mostrar els noms d'objecte"
 
+msgid "prefixed path to initial superproject"
+msgstr "camí prefixat al superprojecte inicial"
+
 msgid "how to strip spaces and #comments from message"
 msgstr "com suprimir els espais i #comentaris del missatge"
 
@@ -18749,6 +18819,14 @@
 msgstr "davant per %d, darrere per %d"
 
 #, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) no accepta arguments"
+
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "argument %%(%.*s) desconegut: %s"
+
+#, c-format
 msgid "expected format: %%(color:<color>)"
 msgstr "format esperat: %%(color:<color>)"
 
@@ -18765,22 +18843,6 @@
 msgstr "Valor enter esperat pel nom de referència:rstrip=%s"
 
 #, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "argument %%(%s) desconegut: %s"
-
-#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) no accepta arguments"
-
-#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) no accepta arguments"
-
-#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) no accepta arguments"
-
-#, c-format
 msgid "expected %%(trailers:key=<value>)"
 msgstr "s'esperava %%(trailers:key=<value>)"
 
@@ -18797,10 +18859,6 @@
 msgstr "valor positiu esperat «%s» a %%(%s)"
 
 #, c-format
-msgid "unrecognized email option: %s"
-msgstr "opció del correu electrònic no reconeguda: «%s»"
-
-#, c-format
 msgid "expected format: %%(align:<width>,<position>)"
 msgstr "format esperat: %%(align:<amplada>,<posició>)"
 
@@ -18813,12 +18871,12 @@
 msgstr "amplada no reconeguda:%s"
 
 #, c-format
-msgid "positive width expected with the %%(align) atom"
-msgstr "amplada positiva esperada amb l'àtom %%(align)"
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "argument %%(%s) desconegut: %s"
 
 #, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) no accepta arguments"
+msgid "positive width expected with the %%(align) atom"
+msgstr "amplada positiva esperada amb l'àtom %%(align)"
 
 #, c-format
 msgid "malformed field name: %.*s"
@@ -20077,6 +20135,23 @@
 msgstr "git %s: s'ha produït un error en actualitzar l'índex"
 
 #, c-format
+msgid "'%s' is not a valid label"
+msgstr "«%s» no és una etiqueta vàlida"
+
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "«%s» no és un nom de referència vàlid"
+
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr ""
+"«update-ref» requereix un refname plenament qualificat, p. ex. refs/heads/%s"
+
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "ordre no vàlida «%.*s»"
+
+#, c-format
 msgid "%s does not accept arguments: '%s'"
 msgstr "%s no accepta arguments: «%s»"
 
@@ -20882,6 +20957,16 @@
 msgid "failed to lstat '%s'"
 msgstr "s'ha produït un error en fer lstat a «%s»"
 
+msgid "no remote configured to get bundle URIs from"
+msgstr "no hi ha cap remot configurat per a obtenir els URI del paquet"
+
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "el remot «%s» no té cap URL configurat"
+
+msgid "could not get the bundle-uri list"
+msgstr "no s'ha pogut obtenir la llista bundle-uri"
+
 msgid "test-tool cache-tree <options> (control|prime|update)"
 msgstr "test-tool cache-tree <opcions> (control|prime|update)"
 
@@ -21234,6 +21319,13 @@
 msgid "failed to push all needed submodules"
 msgstr "no s'han pogut pujar tots els submòduls necessaris"
 
+msgid "bundle-uri operation not supported by protocol"
+msgstr "L'operació bundle-uri no és compatible amb el protocol"
+
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr ""
+"no s'ha pogut recuperar la llista de paquets d'URI anunciats pel servidor"
+
 msgid "too-short tree object"
 msgstr "objecte d'arbre massa curt"
 
@@ -21981,14 +22073,20 @@
 
 #, c-format
 msgid ""
-"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-"may speed it up, but you have to be careful not to forget to add\n"
-"new files yourself (see 'git help status')."
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
 msgstr ""
-"S'ha trigat %.2f segons enumerar els fitxers no seguits.\n"
-"«status -uno» pot accelerar-ho, però heu d'anar amb compte de no\n"
-"oblidar-vos d'afegir fitxers nous vosaltres mateixos (vegeu\n"
-"«git help status»)."
+"S'han trigat %.2f segons a enumerar els fitxers sense seguiment,\n"
+"però els resultats es van emmagatzemar a la memòria cau, i les\n"
+"execucions posteriors podrien ser més ràpides."
+
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr "S'han trigat %.2f segons a enumerar els fitxers sense seguiment."
+
+msgid "See 'git help status' for information on how to improve this."
+msgstr ""
+"Vegeu «git help status» per a obtenir informació sobre com millorar-ho."
 
 #, c-format
 msgid "Untracked files not listed%s"
@@ -22134,276 +22232,6 @@
 msgid "Unable to determine absolute path of git directory"
 msgstr "No s'ha pogut determinar el camí absolut del directori de git"
 
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#, perl-format
-msgid "%12s %12s %s"
-msgstr "%12s %12s %s"
-
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] "modificat %d camí\n"
-msgstr[1] "modificat %d camins\n"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr ""
-"Si el pedaç s'aplica correctament, el tros editat es marcarà immediatament\n"
-"per «staging»."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr ""
-"Si el pedaç s'aplica correctament, el tros editat es marcarà immediatament\n"
-"per «stashing»."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr ""
-"Si el pedaç s'aplica correctament, el tros editat es marcarà immediatament\n"
-"per «unstaging»."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr ""
-"Si el pedaç s'aplica correctament, el tros editat es marcarà immediatament\n"
-"per a aplicar-se."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr ""
-"Si el pedaç s'aplica correctament, el tros editat es marcarà immediatament\n"
-"per a descartar-se."
-
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr "s'ha produït un error en escriure al fitxer d'edició del tros: %s"
-
-#, perl-format
-msgid ""
-"---\n"
-"To remove '%s' lines, make them ' ' lines (context).\n"
-"To remove '%s' lines, delete them.\n"
-"Lines starting with %s will be removed.\n"
-msgstr ""
-"---\n"
-"Per a eliminar les línies «%s», convertiu-les en línies ' ' (context).\n"
-"Per a eliminar les línies «%s», suprimiu-les.\n"
-"Les línies que comencin per %s s'eliminaran.\n"
-
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr "s'ha produït un error en llegir al fitxer d'edició del tros: %s"
-
-msgid ""
-"y - stage this hunk\n"
-"n - do not stage this hunk\n"
-"q - quit; do not stage this hunk or any of the remaining ones\n"
-"a - stage this hunk and all later hunks in the file\n"
-"d - do not stage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - fes «stage» d'aquest tros\n"
-"n - no facis «stage» d'aquest tros\n"
-"q - surt; no facis «stage» d'aquest tros o de cap altre restant\n"
-"a - fes «stage» d'aquest tros i tota la resta de trossos del fitxer\n"
-"d - no facis «stage» d'aquest tros o de cap altre restant del fitxer"
-
-msgid ""
-"y - stash this hunk\n"
-"n - do not stash this hunk\n"
-"q - quit; do not stash this hunk or any of the remaining ones\n"
-"a - stash this hunk and all later hunks in the file\n"
-"d - do not stash this hunk or any of the later hunks in the file"
-msgstr ""
-"y - fes «stash» d'aquest tros\n"
-"n - no facis «stash» d'aquest tros\n"
-"q - surt; no facis «stash» d'aquest tros o de cap altre restant\n"
-"a - fes «stash» d'aquest tros i tota la resta de trossos del fitxer\n"
-"d - no facis «stash» d'aquest tros o de cap altre restant del fitxer"
-
-msgid ""
-"y - unstage this hunk\n"
-"n - do not unstage this hunk\n"
-"q - quit; do not unstage this hunk or any of the remaining ones\n"
-"a - unstage this hunk and all later hunks in the file\n"
-"d - do not unstage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - fes «unstage» d'aquest tros\n"
-"n - no facis «unstage» d'aquest tros\n"
-"q - surt; no facis «unstage» d'aquest tros o de cap altre restant\n"
-"a - fes «unstage» d'aquest tros i tota la resta de trossos del fitxer\n"
-"d - no facis «unstage» d'aquest tros o de cap altre restant del fitxer"
-
-msgid ""
-"y - apply this hunk to index\n"
-"n - do not apply this hunk to index\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - aplica aquest tros a l'índex\n"
-"n - no apliquis aquest tros a l'índex\n"
-"q - surt; no apliquis aquest tros ni cap dels pendents\n"
-"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
-"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer"
-
-msgid ""
-"y - discard this hunk from worktree\n"
-"n - do not discard this hunk from worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - descarta aquest tros de l'arbre de treball\n"
-"n - no descartis aquest tros des de l'arbre de treball\n"
-"q - surt; no descartis aquest tros ni cap dels pendents\n"
-"a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
-"d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer"
-
-msgid ""
-"y - discard this hunk from index and worktree\n"
-"n - do not discard this hunk from index and worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - descarta aquest tros de l'índex i de l'arbre de treball\n"
-"n - no descartis aquest tros des de l'índex i de l'arbre de treball\n"
-"q - surt; no descartis aquest tros ni cap dels pendents\n"
-"a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
-"d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer"
-
-msgid ""
-"y - apply this hunk to index and worktree\n"
-"n - do not apply this hunk to index and worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - aplica aquest tros a l'índex i l'arbre de treball\n"
-"n - no apliquis aquest tros des de l'índex i de l'arbre de treball\n"
-"q - surt; no apliquis aquest tros ni cap dels pendents\n"
-"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
-"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer"
-
-msgid ""
-"y - apply this hunk to worktree\n"
-"n - do not apply this hunk to worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - aplica aquest tros a l'arbre de treball\n"
-"n - no apliquis aquest tros a l'arbre de treball\n"
-"q - surt; no apliquis aquest tros ni cap dels pendents\n"
-"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
-"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer"
-
-msgid ""
-"g - select a hunk to go to\n"
-"/ - search for a hunk matching the given regex\n"
-"j - leave this hunk undecided, see next undecided hunk\n"
-"J - leave this hunk undecided, see next hunk\n"
-"k - leave this hunk undecided, see previous undecided hunk\n"
-"K - leave this hunk undecided, see previous hunk\n"
-"s - split the current hunk into smaller hunks\n"
-"e - manually edit the current hunk\n"
-"? - print help\n"
-msgstr ""
-"g - selecciona el tros on voleu anar\n"
-"/ - cerca un tros que coincideixi amb l'expressió regular donada\n"
-"j - deixa aquest tros sense decidir, veure el tros sense decidir següent\n"
-"J - deixa aquest tros sense decidir, veure el tros següent\n"
-"k - deixa aquest tros sense decidir, veure el tros sense decidir anterior\n"
-"K - deixa aquest tros sense decidir, veure el tros anterior\n"
-"s - divideix el tros actual en trossos més petits\n"
-"e - edita manualment el tros actual\n"
-"? - mostra l'ajuda\n"
-
-msgid "The selected hunks do not apply to the index!\n"
-msgstr "Els trossos seleccionats no apliquen a l'índex\n"
-
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "s'està ignorant %s no fusionat\n"
-
-msgid "No other hunks to goto\n"
-msgstr "No hi ha altres trossos on anar-hi\n"
-
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "Número no vàlid: «%s»\n"
-
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "Només %d tros disponible.\n"
-msgstr[1] "Només %d trossos disponibles.\n"
-
-msgid "No other hunks to search\n"
-msgstr "No hi ha cap altre tros a cercar\n"
-
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "Expressió regular de cerca mal formada %s: %s\n"
-
-msgid "No hunk matches the given pattern\n"
-msgstr "No hi ha trossos que coincideixin amb el patró donat\n"
-
-msgid "No previous hunk\n"
-msgstr "Sense tros previ\n"
-
-msgid "No next hunk\n"
-msgstr "No hi ha tros següent\n"
-
-msgid "Sorry, cannot split this hunk\n"
-msgstr "No es pot dividir aquest tros\n"
-
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "Divideix en %d tros.\n"
-msgstr[1] "Divideix en %d trossos.\n"
-
-msgid "Sorry, cannot edit this hunk\n"
-msgstr "No es pot editar aquest tros\n"
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-msgid ""
-"status        - show paths with changes\n"
-"update        - add working tree state to the staged set of changes\n"
-"revert        - revert staged set of changes back to the HEAD version\n"
-"patch         - pick hunks and update selectively\n"
-"diff          - view diff between HEAD and index\n"
-"add untracked - add contents of untracked files to the staged set of "
-"changes\n"
-msgstr ""
-"status        - mostra els camins amb canvis\n"
-"update        - afegeix l'estat de l'arbre de treball al conjunt de canvis "
-"«staged»\n"
-"revert        - reverteix el conjunt de canvis de «staged» a la versió HEAD\n"
-"patch         - selecciona trossos i actualitza'ls selectivament\n"
-"diff          - mostra la diferència entre HEAD i l'índex\n"
-"add untracked - afegeix el contingut dels fitxers no seguits al conjunt de "
-"canvis «staged»\n"
-
-msgid "missing --"
-msgstr "manca --"
-
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "desconegut --patch mode: %s"
-
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "argument %s no vàlid, s'esperava --"
-
 msgid "local zone differs from GMT by a non-minute interval\n"
 msgstr "la zona local difereix de GMT per un interval que no és de minuts\n"
 
@@ -22728,6 +22556,366 @@
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Esteu segur que voleu enviar %s? [y|N]: "
 
+#~ msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
+#~ msgstr "git bisect--helper --bisect-state (bad|new) [<rev>]"
+
+#~ msgid "won't bisect on cg-seek'ed tree"
+#~ msgstr "no es bisecarà en un arbre en el qual s'ha fet cg-seek"
+
+#~ msgid "--bisect-terms requires 0 or 1 argument"
+#~ msgstr "--bisect-terms requereix 0 o 1 argument"
+
+#~ msgid "--bisect-next requires 0 arguments"
+#~ msgstr "--bisect-next no requereix cap argument"
+
+#~ msgid "--bisect-log requires 0 arguments"
+#~ msgstr "--bisect-log no requereix cap argument"
+
+#~ msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
+#~ msgstr "git env--helper --type=[bool|ulong] <opcions> <env-var>"
+
+#~ msgid "default for git_env_*(...) to fall back on"
+#~ msgstr "valor per defecte per a git_env_*(...) en cas d'absència"
+
+#~ msgid "be quiet only use git_env_*() value as exit code"
+#~ msgstr "silenciós només utilitza el valor git_env_*() com a codi de sortida"
+
+#, c-format
+#~ msgid ""
+#~ "option `--default' expects a boolean value with `--type=bool`, not `%s`"
+#~ msgstr ""
+#~ "l'opció «--default» espera un valor booleà amb «--type=bool», no «%s»"
+
+#, c-format
+#~ msgid ""
+#~ "option `--default' expects an unsigned long value with `--type=ulong`, "
+#~ "not `%s`"
+#~ msgstr ""
+#~ "l'opció «--default» espera un valor llarg sense signe amb «--type=ulong», "
+#~ "no «%s»"
+
+#, c-format
+#~ msgid "%s doesn't support --super-prefix"
+#~ msgstr "%s no admet --super-prefix"
+
+#, c-format
+#~ msgid "no prefix given for --super-prefix\n"
+#~ msgstr "no s'ha especificat cap prefix per a --super-prefix\n"
+
+#, c-format
+#~ msgid "failed to read object %s"
+#~ msgstr "s'ha produït un error en llegir l'objecte %s"
+
+#~ msgid "file write error"
+#~ msgstr "s'ha produït un error en escriure al fitxer"
+
+#~ msgid "corrupt commit"
+#~ msgstr "comissió corrupta"
+
+#~ msgid "corrupt tag"
+#~ msgstr "etiqueta corrupta"
+
+#, c-format
+#~ msgid "%%(objecttype) does not take arguments"
+#~ msgstr "%%(objecttype) no accepta arguments"
+
+#, c-format
+#~ msgid "%%(deltabase) does not take arguments"
+#~ msgstr "%%(deltabase) no accepta arguments"
+
+#, c-format
+#~ msgid "%%(body) does not take arguments"
+#~ msgstr "%%(body) no accepta arguments"
+
+#, c-format
+#~ msgid "unrecognized email option: %s"
+#~ msgstr "opció del correu electrònic no reconeguda: «%s»"
+
+#, c-format
+#~ msgid ""
+#~ "It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
+#~ "may speed it up, but you have to be careful not to forget to add\n"
+#~ "new files yourself (see 'git help status')."
+#~ msgstr ""
+#~ "S'ha trigat %.2f segons enumerar els fitxers no seguits.\n"
+#~ "«status -uno» pot accelerar-ho, però heu d'anar amb compte de no\n"
+#~ "oblidar-vos d'afegir fitxers nous vosaltres mateixos (vegeu\n"
+#~ "«git help status»)."
+
+#, perl-format
+#~ msgid "%12s %12s %s"
+#~ msgstr "%12s %12s %s"
+
+#, perl-format
+#~ msgid "touched %d path\n"
+#~ msgid_plural "touched %d paths\n"
+#~ msgstr[0] "modificat %d camí\n"
+#~ msgstr[1] "modificat %d camins\n"
+
+#~ msgid ""
+#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
+#~ "marked for staging."
+#~ msgstr ""
+#~ "Si el pedaç s'aplica correctament, el tros editat es marcarà "
+#~ "immediatament\n"
+#~ "per «staging»."
+
+#~ msgid ""
+#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
+#~ "marked for stashing."
+#~ msgstr ""
+#~ "Si el pedaç s'aplica correctament, el tros editat es marcarà "
+#~ "immediatament\n"
+#~ "per «stashing»."
+
+#~ msgid ""
+#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
+#~ "marked for unstaging."
+#~ msgstr ""
+#~ "Si el pedaç s'aplica correctament, el tros editat es marcarà "
+#~ "immediatament\n"
+#~ "per «unstaging»."
+
+#~ msgid ""
+#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
+#~ "marked for applying."
+#~ msgstr ""
+#~ "Si el pedaç s'aplica correctament, el tros editat es marcarà "
+#~ "immediatament\n"
+#~ "per a aplicar-se."
+
+#~ msgid ""
+#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
+#~ "marked for discarding."
+#~ msgstr ""
+#~ "Si el pedaç s'aplica correctament, el tros editat es marcarà "
+#~ "immediatament\n"
+#~ "per a descartar-se."
+
+#, perl-format
+#~ msgid "failed to open hunk edit file for writing: %s"
+#~ msgstr "s'ha produït un error en escriure al fitxer d'edició del tros: %s"
+
+#, perl-format
+#~ msgid ""
+#~ "---\n"
+#~ "To remove '%s' lines, make them ' ' lines (context).\n"
+#~ "To remove '%s' lines, delete them.\n"
+#~ "Lines starting with %s will be removed.\n"
+#~ msgstr ""
+#~ "---\n"
+#~ "Per a eliminar les línies «%s», convertiu-les en línies ' ' (context).\n"
+#~ "Per a eliminar les línies «%s», suprimiu-les.\n"
+#~ "Les línies que comencin per %s s'eliminaran.\n"
+
+#, perl-format
+#~ msgid "failed to open hunk edit file for reading: %s"
+#~ msgstr "s'ha produït un error en llegir al fitxer d'edició del tros: %s"
+
+#~ msgid ""
+#~ "y - stage this hunk\n"
+#~ "n - do not stage this hunk\n"
+#~ "q - quit; do not stage this hunk or any of the remaining ones\n"
+#~ "a - stage this hunk and all later hunks in the file\n"
+#~ "d - do not stage this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - fes «stage» d'aquest tros\n"
+#~ "n - no facis «stage» d'aquest tros\n"
+#~ "q - surt; no facis «stage» d'aquest tros o de cap altre restant\n"
+#~ "a - fes «stage» d'aquest tros i tota la resta de trossos del fitxer\n"
+#~ "d - no facis «stage» d'aquest tros o de cap altre restant del fitxer"
+
+#~ msgid ""
+#~ "y - stash this hunk\n"
+#~ "n - do not stash this hunk\n"
+#~ "q - quit; do not stash this hunk or any of the remaining ones\n"
+#~ "a - stash this hunk and all later hunks in the file\n"
+#~ "d - do not stash this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - fes «stash» d'aquest tros\n"
+#~ "n - no facis «stash» d'aquest tros\n"
+#~ "q - surt; no facis «stash» d'aquest tros o de cap altre restant\n"
+#~ "a - fes «stash» d'aquest tros i tota la resta de trossos del fitxer\n"
+#~ "d - no facis «stash» d'aquest tros o de cap altre restant del fitxer"
+
+#~ msgid ""
+#~ "y - unstage this hunk\n"
+#~ "n - do not unstage this hunk\n"
+#~ "q - quit; do not unstage this hunk or any of the remaining ones\n"
+#~ "a - unstage this hunk and all later hunks in the file\n"
+#~ "d - do not unstage this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - fes «unstage» d'aquest tros\n"
+#~ "n - no facis «unstage» d'aquest tros\n"
+#~ "q - surt; no facis «unstage» d'aquest tros o de cap altre restant\n"
+#~ "a - fes «unstage» d'aquest tros i tota la resta de trossos del fitxer\n"
+#~ "d - no facis «unstage» d'aquest tros o de cap altre restant del fitxer"
+
+#~ msgid ""
+#~ "y - apply this hunk to index\n"
+#~ "n - do not apply this hunk to index\n"
+#~ "q - quit; do not apply this hunk or any of the remaining ones\n"
+#~ "a - apply this hunk and all later hunks in the file\n"
+#~ "d - do not apply this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - aplica aquest tros a l'índex\n"
+#~ "n - no apliquis aquest tros a l'índex\n"
+#~ "q - surt; no apliquis aquest tros ni cap dels pendents\n"
+#~ "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
+#~ "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer"
+
+#~ msgid ""
+#~ "y - discard this hunk from worktree\n"
+#~ "n - do not discard this hunk from worktree\n"
+#~ "q - quit; do not discard this hunk or any of the remaining ones\n"
+#~ "a - discard this hunk and all later hunks in the file\n"
+#~ "d - do not discard this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - descarta aquest tros de l'arbre de treball\n"
+#~ "n - no descartis aquest tros des de l'arbre de treball\n"
+#~ "q - surt; no descartis aquest tros ni cap dels pendents\n"
+#~ "a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
+#~ "d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer"
+
+#~ msgid ""
+#~ "y - discard this hunk from index and worktree\n"
+#~ "n - do not discard this hunk from index and worktree\n"
+#~ "q - quit; do not discard this hunk or any of the remaining ones\n"
+#~ "a - discard this hunk and all later hunks in the file\n"
+#~ "d - do not discard this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - descarta aquest tros de l'índex i de l'arbre de treball\n"
+#~ "n - no descartis aquest tros des de l'índex i de l'arbre de treball\n"
+#~ "q - surt; no descartis aquest tros ni cap dels pendents\n"
+#~ "a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
+#~ "d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer"
+
+#~ msgid ""
+#~ "y - apply this hunk to index and worktree\n"
+#~ "n - do not apply this hunk to index and worktree\n"
+#~ "q - quit; do not apply this hunk or any of the remaining ones\n"
+#~ "a - apply this hunk and all later hunks in the file\n"
+#~ "d - do not apply this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - aplica aquest tros a l'índex i l'arbre de treball\n"
+#~ "n - no apliquis aquest tros des de l'índex i de l'arbre de treball\n"
+#~ "q - surt; no apliquis aquest tros ni cap dels pendents\n"
+#~ "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
+#~ "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer"
+
+#~ msgid ""
+#~ "y - apply this hunk to worktree\n"
+#~ "n - do not apply this hunk to worktree\n"
+#~ "q - quit; do not apply this hunk or any of the remaining ones\n"
+#~ "a - apply this hunk and all later hunks in the file\n"
+#~ "d - do not apply this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - aplica aquest tros a l'arbre de treball\n"
+#~ "n - no apliquis aquest tros a l'arbre de treball\n"
+#~ "q - surt; no apliquis aquest tros ni cap dels pendents\n"
+#~ "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
+#~ "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer"
+
+#~ msgid ""
+#~ "g - select a hunk to go to\n"
+#~ "/ - search for a hunk matching the given regex\n"
+#~ "j - leave this hunk undecided, see next undecided hunk\n"
+#~ "J - leave this hunk undecided, see next hunk\n"
+#~ "k - leave this hunk undecided, see previous undecided hunk\n"
+#~ "K - leave this hunk undecided, see previous hunk\n"
+#~ "s - split the current hunk into smaller hunks\n"
+#~ "e - manually edit the current hunk\n"
+#~ "? - print help\n"
+#~ msgstr ""
+#~ "g - selecciona el tros on voleu anar\n"
+#~ "/ - cerca un tros que coincideixi amb l'expressió regular donada\n"
+#~ "j - deixa aquest tros sense decidir, veure el tros sense decidir següent\n"
+#~ "J - deixa aquest tros sense decidir, veure el tros següent\n"
+#~ "k - deixa aquest tros sense decidir, veure el tros sense decidir "
+#~ "anterior\n"
+#~ "K - deixa aquest tros sense decidir, veure el tros anterior\n"
+#~ "s - divideix el tros actual en trossos més petits\n"
+#~ "e - edita manualment el tros actual\n"
+#~ "? - mostra l'ajuda\n"
+
+#~ msgid "The selected hunks do not apply to the index!\n"
+#~ msgstr "Els trossos seleccionats no apliquen a l'índex\n"
+
+#, perl-format
+#~ msgid "ignoring unmerged: %s\n"
+#~ msgstr "s'està ignorant %s no fusionat\n"
+
+#~ msgid "No other hunks to goto\n"
+#~ msgstr "No hi ha altres trossos on anar-hi\n"
+
+#, perl-format
+#~ msgid "Invalid number: '%s'\n"
+#~ msgstr "Número no vàlid: «%s»\n"
+
+#, perl-format
+#~ msgid "Sorry, only %d hunk available.\n"
+#~ msgid_plural "Sorry, only %d hunks available.\n"
+#~ msgstr[0] "Només %d tros disponible.\n"
+#~ msgstr[1] "Només %d trossos disponibles.\n"
+
+#~ msgid "No other hunks to search\n"
+#~ msgstr "No hi ha cap altre tros a cercar\n"
+
+#, perl-format
+#~ msgid "Malformed search regexp %s: %s\n"
+#~ msgstr "Expressió regular de cerca mal formada %s: %s\n"
+
+#~ msgid "No hunk matches the given pattern\n"
+#~ msgstr "No hi ha trossos que coincideixin amb el patró donat\n"
+
+#~ msgid "No previous hunk\n"
+#~ msgstr "Sense tros previ\n"
+
+#~ msgid "No next hunk\n"
+#~ msgstr "No hi ha tros següent\n"
+
+#~ msgid "Sorry, cannot split this hunk\n"
+#~ msgstr "No es pot dividir aquest tros\n"
+
+#, perl-format
+#~ msgid "Split into %d hunk.\n"
+#~ msgid_plural "Split into %d hunks.\n"
+#~ msgstr[0] "Divideix en %d tros.\n"
+#~ msgstr[1] "Divideix en %d trossos.\n"
+
+#~ msgid "Sorry, cannot edit this hunk\n"
+#~ msgstr "No es pot editar aquest tros\n"
+
+#~ msgid ""
+#~ "status        - show paths with changes\n"
+#~ "update        - add working tree state to the staged set of changes\n"
+#~ "revert        - revert staged set of changes back to the HEAD version\n"
+#~ "patch         - pick hunks and update selectively\n"
+#~ "diff          - view diff between HEAD and index\n"
+#~ "add untracked - add contents of untracked files to the staged set of "
+#~ "changes\n"
+#~ msgstr ""
+#~ "status        - mostra els camins amb canvis\n"
+#~ "update        - afegeix l'estat de l'arbre de treball al conjunt de "
+#~ "canvis «staged»\n"
+#~ "revert        - reverteix el conjunt de canvis de «staged» a la versió "
+#~ "HEAD\n"
+#~ "patch         - selecciona trossos i actualitza'ls selectivament\n"
+#~ "diff          - mostra la diferència entre HEAD i l'índex\n"
+#~ "add untracked - afegeix el contingut dels fitxers no seguits al conjunt "
+#~ "de canvis «staged»\n"
+
+#~ msgid "missing --"
+#~ msgstr "manca --"
+
+#, perl-format
+#~ msgid "unknown --patch mode: %s"
+#~ msgstr "desconegut --patch mode: %s"
+
+#, perl-format
+#~ msgid "invalid argument %s, expecting --"
+#~ msgstr "argument %s no vàlid, s'esperava --"
+
 #, c-format
 #~ msgid "unable to normalize object directory: %s"
 #~ msgstr "no s'ha pogut normalitzar el directori de l'objecte: %s"
diff --git a/po/de.po b/po/de.po
index 45c7a41..7559a8c 100644
--- a/po/de.po
+++ b/po/de.po
@@ -8,8 +8,8 @@
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-12-02 17:16+0100\n"
-"PO-Revision-Date: 2022-12-02 17:19+0100\n"
+"POT-Creation-Date: 2023-03-03 17:13+0100\n"
+"PO-Revision-Date: 2023-03-03 13:46+0100\n"
 "Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
 "Language-Team: German\n"
 "Language: de\n"
@@ -17,7 +17,7 @@
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n!=1);\n"
-"X-Generator: Poedit 3.2\n"
+"X-Generator: Poedit 3.2.2\n"
 
 #, c-format
 msgid "Huh (%s)?"
@@ -45,13 +45,13 @@
 msgid "could not write index"
 msgstr "konnte Index nicht schreiben"
 
-#, c-format, perl-format
+#, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "%d Pfad aktualisiert\n"
 msgstr[1] "%d Pfade aktualisiert\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "Hinweis: %s ist nun unversioniert.\n"
 
@@ -65,7 +65,7 @@
 msgid "Could not parse HEAD^{tree}"
 msgstr "Konnte HEAD^{tree} nicht parsen."
 
-#, c-format, perl-format
+#, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "%d Pfad wiederhergestellt\n"
@@ -78,7 +78,7 @@
 msgid "Add untracked"
 msgstr "Unversionierte Dateien hinzufügen"
 
-#, c-format, perl-format
+#, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "%d Pfad hinzugefügt\n"
@@ -172,19 +172,19 @@
 msgid "Bye.\n"
 msgstr "Tschüss.\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "Modusänderung der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "Löschung der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "Ergänzung der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Diesen Patch-Block der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
 
@@ -210,19 +210,19 @@
 "d - diesen oder alle weiteren Patch-Blöcke in dieser Datei nicht zum Commit "
 "vormerken\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "Modusänderung stashen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "Löschung stashen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "Ergänzung stashen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "Diesen Patch-Block stashen [y,n,q,a,d%s,?]? "
 
@@ -246,19 +246,19 @@
 "a - diesen und alle weiteren Patch-Blöcke dieser Datei stashen\n"
 "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht stashen\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "Modusänderung aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "Löschung aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "Ergänzung aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Diesen Patch-Block aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
 
@@ -285,19 +285,19 @@
 "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht aus Staging-"
 "Area entfernen\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr "Modusänderung auf Index anwenden [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "Löschung auf Index anwenden [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "Ergänzung auf Index anwenden [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "Diesen Patch-Block auf Index anwenden [y,n,q,a,d%s,?]? "
 
@@ -324,19 +324,19 @@
 "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht auf den Index "
 "anwenden\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr "Modusänderung im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "Löschung im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "Ergänzung im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
 msgstr "Diesen Patch-Block im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
@@ -363,20 +363,20 @@
 "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht im "
 "Arbeitsverzeichnis verwerfen\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Modusänderung vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Löschung vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Ergänzung im Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Diesen Patch-Block vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,"
@@ -395,20 +395,20 @@
 "a - diesen und alle weiteren Patch-Blöcke in der Datei verwerfen\n"
 "d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht verwerfen\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Modusänderung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Löschung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Ergänzung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Diesen Patch-Block auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,"
@@ -428,19 +428,19 @@
 "a - diesen und alle weiteren Patch-Blöcke in der Datei anwenden\n"
 "d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht anwenden\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
 msgstr "Modusänderung auf Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
 msgstr "Löschung auf Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
 msgstr "Ergänzung auf Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Diesen Patch-Block auf das Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
@@ -519,7 +519,6 @@
 "Um '%c' Zeilen zu entfernen, löschen Sie diese.\n"
 "Zeilen, die mit %c beginnen, werden entfernt.\n"
 
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
 "edit again.  If all lines of the hunk are removed, then the edit is\n"
@@ -542,12 +541,6 @@
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr ""
@@ -1416,6 +1409,12 @@
 msgid "report archived files on stderr"
 msgstr "archivierte Dateien in der Standard-Fehlerausgabe ausgeben"
 
+msgid "time"
+msgstr "Zeit"
+
+msgid "set modification time of archive entries"
+msgstr "Änderungszeitpunkt von Archiveinträgen festlegen"
+
 msgid "set compression level"
 msgstr "Komprimierungsgrad setzen"
 
@@ -1456,6 +1455,13 @@
 msgid "%.*s is not a valid attribute name"
 msgstr "%.*s ist kein gültiger Attributname"
 
+msgid "unable to add additional attribute"
+msgstr "konnte kein zusätzliches Attribut hinzufügen"
+
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "ignoriere übermäßig lange Attribut-Zeile %d"
+
 #, c-format
 msgid "%s not allowed: %s:%d"
 msgstr "%s nicht erlaubt: %s:%d"
@@ -1468,6 +1474,18 @@
 "Benutzen Sie '\\!' für führende Ausrufezeichen."
 
 #, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "Kann gitattributes-Datei '%s' nicht lesen"
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "ignoriere übermäßig große gitattributes-Datei '%s'"
+
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "ignoriere übermäßig großen gitattribute-Blob '%s'"
+
+#, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Ungültiger Inhalt bzgl. Anführungszeichen in Datei '%s': %s"
 
@@ -1651,10 +1669,12 @@
 msgid "not tracking: ambiguous information for ref '%s'"
 msgstr "kein Tracking: mehrdeutige Informationen für Referenz '%s'"
 
+#. #-#-#-#-#  branch.c.po  #-#-#-#-#
 #. TRANSLATORS: This is a line listing a remote with duplicate
 #. refspecs in the advice message below. For RTL languages you'll
 #. probably want to swap the "%s" and leading "  " space around.
 #.
+#. #-#-#-#-#  object-name.c.po  #-#-#-#-#
 #. TRANSLATORS: This is line item of ambiguous object output
 #. from describe_ambiguous_object() above. For RTL languages
 #. you'll probably want to swap the "%s" and leading " " space
@@ -1748,11 +1768,11 @@
 
 #, c-format
 msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
 msgstr ""
-"Sie können versuchen die Submodule mit 'git checkout %s && git submodule "
-"update --init' zu aktualisieren"
+"Sie können versuchen, die Submodule mit \"git checkout --no-recurse-"
+"submodules %s && git submodule update --init\" zu aktualisieren."
 
 #, c-format
 msgid "submodule '%s': cannot create branch '%s'"
@@ -1788,6 +1808,13 @@
 msgstr ""
 "Nicht zum Commit vorgemerkte Änderungen nach Aktualisierung der Staging-Area:"
 
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"Die Einstellung add.interactive.useBuiltin wurde entfernt!\n"
+"Siehe den Eintrag in 'git help config' für Details."
+
 msgid "Could not read the index"
 msgstr "Konnte den Index nicht lesen"
 
@@ -2194,6 +2221,9 @@
 msgid "run interactively"
 msgstr "interaktiv ausführen"
 
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "Hooks pre-applypatch und applypatch-msg umgehen"
+
 msgid "historical option -- no-op"
 msgstr "historische Option -- kein Effekt"
 
@@ -2335,32 +2365,28 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: erwartete eine Spülung (flush)"
 
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [<Commit>]"
-
 msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<Begriff> --term-{old,"
-"good}=<Begriff>] [--no-checkout] [--first-parent] [<schlecht> [<gut>...]] "
-"[--] [<Pfade>...]"
+"git bisect start [--term-{new,bad}=<Begriff> --term-{old,good}=<Begriff>] [--"
+"no-checkout] [--first-parent] [<schlecht> [<gut>...]] [--] "
+"[<Pfadspezifikation>...]"
 
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (bad|new) [<Commit>]"
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<Commit>...]"
 
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (good|old) [<Commit>...]"
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<Commit>|<Bereich>)...]"
 
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay <Dateiname>"
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<Commit>]"
 
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(<Commit>|<Bereich>)...]"
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <Logdatei>"
 
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run <Programm>..."
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run <Programm>..."
 
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
@@ -2507,10 +2533,6 @@
 "Auschecken von '%s' fehlgeschlagen. Versuchen Sie 'git bisect start "
 "<gültiger-Branch>'."
 
-msgid "won't bisect on cg-seek'ed tree"
-msgstr ""
-"binäre Suche auf einem durch 'cg-seek' geändertem Verzeichnis nicht möglich"
-
 msgid "bad HEAD - strange symbolic ref"
 msgstr "ungültiger HEAD - merkwürdige symbolische Referenz"
 
@@ -2562,16 +2584,16 @@
 msgstr "'bisect run' fehlgeschlagen: kein Befehl angegeben."
 
 #, c-format
-msgid "unable to verify '%s' on good revision"
-msgstr "konnte '%s' nicht für guten Commit überprüfen"
+msgid "unable to verify %s on good revision"
+msgstr "kann %s bei gutem Commit nicht verifizieren"
 
 #, c-format
 msgid "bogus exit code %d for good revision"
 msgstr "fehlerhafter Exit-Code %d für guten Commit"
 
 #, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
-msgstr "'bisect run' fehlgeschlagen: Exit-Code %d von '%s' ist < 0 oder >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
+msgstr "bisect-Lauf fehlgeschlagen: Exit-Code %d von %s ist < 0 oder >= 128"
 
 #, c-format
 msgid "cannot open file '%s' for writing"
@@ -2580,37 +2602,43 @@
 msgid "bisect run cannot continue any more"
 msgstr "'bisect run' kann nicht mehr fortgesetzt werden"
 
-#, c-format
 msgid "bisect run success"
 msgstr "'bisect run' erfolgreich ausgeführt"
 
-#, c-format
 msgid "bisect found first bad commit"
 msgstr "binäre Suche fand ersten schlechten Commit"
 
 #, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
 msgstr ""
-"'bisect run' fehlgeschlagen: 'git bisect--helper --bisect-state %s' mit "
-"Fehlercode %d beendet"
+"bisect-Lauf fehlgeschlagen: 'git bisect %s' wurde mit Fehlercode %d beendet"
 
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "--bisect-reset benötigt entweder kein Argument oder ein Commit"
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "'%s' erfordert entweder kein Argument oder einen Commit"
 
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "--bisect-terms benötigt 0 oder 1 Argument"
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "'%s' erfordert 0 oder 1 Argument"
 
-msgid "--bisect-next requires 0 arguments"
-msgstr "--bisect-next benötigt 0 Argumente"
-
-msgid "--bisect-log requires 0 arguments"
-msgstr "--bisect-log benötigt 0 Argumente"
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "'%s' erfordert 0 Argumente"
 
 msgid "no logfile given"
 msgstr "keine Log-Datei angegeben"
 
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "'%s' ist fehlgeschlagen: kein Befehl angegeben."
+
+msgid "need a command"
+msgstr "Befehl benötigt"
+
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "unbekannter Befehl: '%s'"
+
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 msgstr "git blame [<Optionen>] [<rev-opts>] [<Commit>] [--] <Datei>"
 
@@ -3201,6 +3229,9 @@
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
 msgstr "git bundle unbundle [--progress] <Datei> [<Referenzname>...]"
 
+msgid "need a <file> argument"
+msgstr "<Datei> Argument benötigt"
+
 msgid "do not show progress meter"
 msgstr "keine Fortschrittsanzeige anzeigen"
 
@@ -3254,10 +3285,6 @@
 msgid "%s takes no arguments"
 msgstr "%s braucht kein Argument"
 
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "unbekannter Befehl: '%s'"
-
 msgid "only one batch option may be specified"
 msgstr "Nur eine Batch-Option erlaubt."
 
@@ -3396,11 +3423,18 @@
 msgid "only two arguments allowed in <type> <object> mode, not %d"
 msgstr "nur zwei Argumente im <Typ> <Objekt> Modus erlaubt, nicht %d"
 
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | <Attribut>...] [--] <Pfadname>..."
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [--source <Commit-Referenz>] [-a | --all | <Attribut>...] "
+"[--] <Pfadname>..."
 
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | <Attribut>...]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source <Commit-Referenz>] [-a | --all | "
+"<Attribut>...]"
 
 msgid "report all attributes set on file"
 msgstr "alle Attribute einer Datei ausgeben"
@@ -3414,6 +3448,12 @@
 msgid "terminate input and output records by a NUL character"
 msgstr "Einträge von Ein- und Ausgabe mit NUL-Zeichen abschließen"
 
+msgid "<tree-ish>"
+msgstr "<Commit-Referenz>"
+
+msgid "which tree-ish to check attributes at"
+msgstr "in welchem Commit die Attribute zu prüfen sind"
+
 msgid "suppress progress reporting"
 msgstr "Fortschrittsanzeige unterdrücken"
 
@@ -4006,7 +4046,7 @@
 "*          - alle Elemente auswählen\n"
 "           - (leer) Auswahl beenden\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Huh (%s)?\n"
 msgstr "Wie bitte (%s)?\n"
 
@@ -4156,9 +4196,6 @@
 msgstr ""
 "einen Klon mit unvollständiger Historie (shallow) in dieser Tiefe erstellen"
 
-msgid "time"
-msgstr "Zeit"
-
 msgid "create a shallow clone since a specific time"
 msgstr ""
 "einen Klon mit unvollständiger Historie (shallow) seit einer bestimmten "
@@ -4410,6 +4447,9 @@
 msgid "failed to fetch objects from bundle URI '%s'"
 msgstr "Objekte aus Bundle-URI '%s' konnten nicht abgerufen werden"
 
+msgid "failed to fetch advertised bundles"
+msgstr "angekündigte Bundles konnten nicht abgerufen werden"
+
 msgid "remote transport reported error"
 msgstr "Remoteübertragung meldete Fehler"
 
@@ -5675,29 +5715,6 @@
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "kein <Programm> für --extcmd=<Programm> angegeben"
 
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] <Optionen> <Umgebungsvariable>"
-
-msgid "default for git_env_*(...) to fall back on"
-msgstr "Standard für git_env_*(...), um darauf zurückzugreifen"
-
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr "Ausgaben unterdrücken; nur git_env_*() Werte als Exit-Code verwenden"
-
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr ""
-"Option `--default' erwartet einen booleschen Wert bei `--type=bool`, nicht "
-"`%s`"
-
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not "
-"`%s`"
-msgstr ""
-"Option `--default' erwartet einen vorzeichenlosen Long-Wert bei `--"
-"type=ulong`, nicht `%s`"
-
 msgid "git fast-export [<rev-list-opts>]"
 msgstr "git fast-export [<rev-list-opts>]"
 
@@ -6111,6 +6128,10 @@
 "--unshallow kann nicht in einem Repository mit vollständiger Historie "
 "verwendet werden"
 
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "Bundles aus '%s' konnten nicht abgerufen werden"
+
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all akzeptiert kein Repository als Argument"
 
@@ -6812,6 +6833,7 @@
 msgid "invalid number of threads specified (%d) for %s"
 msgstr "ungültige Anzahl von Threads (%d) für %s angegeben"
 
+#. #-#-#-#-#  grep.c.po  #-#-#-#-#
 #. TRANSLATORS: %s is the configuration
 #. variable for tweaking threads, currently
 #. grep.threads
@@ -7156,12 +7178,19 @@
 msgid "'git help config' for more information"
 msgstr "'git help config' für weitere Informationen"
 
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] <Hook-Name> [-- <Hook-Argumente>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=<Pfad>] <Hook-Name> [-- <Hook-"
+"Argumente>]"
 
 msgid "silently ignore missing requested <hook-name>"
 msgstr "fehlende Anforderung <Hook-Name> stillschweigend ignorieren"
 
+msgid "file to read into hooks' stdin"
+msgstr "Datei zum Einlesen in das Hook-stdin"
+
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "Objekt-Typen passen bei %s nicht zusammen"
@@ -7999,11 +8028,11 @@
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<Programm>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<Schlüssel>]\n"
-"              [--symref] [<Repository> [<Referenzen>...]]"
+"              [--symref] [<Repository> [<Muster>...]]"
 
 msgid "do not print remote URL"
 msgstr "URL des Remote-Repositories nicht ausgeben"
@@ -8253,9 +8282,15 @@
 msgid "perform multiple merges, one per line of input"
 msgstr "mehrere Merges durchführen, eine pro Eingabezeile"
 
+msgid "specify a merge-base for the merge"
+msgstr "Merge-Basis für den Merge angeben"
+
 msgid "--trivial-merge is incompatible with all other options"
 msgstr "--trivial-merge ist mit allen anderen Optionen inkompatibel"
 
+msgid "--merge-base is incompatible with --stdin"
+msgstr "--merge-base ist inkompatibel mit --stdin"
+
 #, c-format
 msgid "malformed input line: '%s'."
 msgstr "Fehlerhafte Eingabezeile: '%s'."
@@ -10210,6 +10245,11 @@
 msgid "could not switch to %s"
 msgstr "Konnte nicht zu %s wechseln."
 
+msgid "apply options and merge options cannot be used together"
+msgstr ""
+"Optionen für \"am\" und Optionen für \"merge\" können nicht gemeinsam "
+"verwendet werden"
+
 #, c-format
 msgid ""
 "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
@@ -10450,10 +10490,19 @@
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy erfordert --merge oder --interactive"
 
-msgid "apply options and merge options cannot be used together"
+msgid ""
+"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"autosquash"
 msgstr ""
-"Optionen für \"am\" und Optionen für \"merge\" können nicht gemeinsam "
-"verwendet werden"
+"apply-Optionen sind mit rebase.autosquash nicht kompatibel. Erwägen Sie das "
+"Hinzufügen von --no-autosquash"
+
+msgid ""
+"apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
+"update-refs"
+msgstr ""
+"apply-Optionen sind nicht kompatibel mit rebase.updateRefs. Erwägen Sie das "
+"Hinzufügen von --no-update-refs"
 
 #, c-format
 msgid "Unknown rebase backend: %s"
@@ -13004,10 +13053,6 @@
 msgid "git submodule--helper <command>"
 msgstr "git submodule--helper <Befehl>"
 
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s unterstützt kein --super-prefix"
-
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
 msgstr "git symbolic-ref [-m <Grund>] <Name> <Referenz>"
 
@@ -13779,6 +13824,10 @@
 msgstr "core.fsyncMethod = batch wird auf dieser Plattform nicht unterstützt"
 
 #, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr "Konnte Bundle-Listenschlüssel %s mit Wert '%s' nicht parsen."
+
+#, c-format
 msgid "bundle list at '%s' has no mode"
 msgstr "Paketliste bei '%s' hat keinen Modus"
 
@@ -13789,6 +13838,13 @@
 msgstr "unzureichende Fähigkeiten"
 
 #, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "die von '%s' heruntergeladene Datei ist kein Bundle"
+
+msgid "failed to store maximum creation token"
+msgstr "das maximale Erstellungs-Token konnte nicht gespeichert werden"
+
+#, c-format
 msgid "unrecognized bundle mode from URI '%s'"
 msgstr "nicht erkannter Bundle-Modus von URI '%s'"
 
@@ -13804,6 +13860,13 @@
 msgid "file at URI '%s' is not a bundle or bundle list"
 msgstr "Datei unter URI '%s' ist kein Paket oder keine Paketliste"
 
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: unerwartetes Argument: '%s'"
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: erwarteter Flush nach Argumenten"
+
 msgid "bundle-uri: got an empty line"
 msgstr "bundle-uri: erhielt eine leere Zeile"
 
@@ -13835,6 +13898,13 @@
 msgid "need a repository to verify a bundle"
 msgstr "um ein Paket zu überprüfen wird ein Repository benötigt"
 
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+"einige vorausgesetzte Commits sind im Objektspeicher vorhanden, aber sind "
+"nicht mit der Repository-Historie verbunden"
+
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -15287,15 +15357,22 @@
 msgstr "unbekanntes Objekt-Format '%s' vom Server angegeben"
 
 #, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "Fehler in der bundle-uri-Antwortzeile %d: %s"
+
+msgid "expected flush after bundle-uri listing"
+msgstr "erwartete Flush nach Bundle-uri-Auflistung"
+
+msgid "expected response end packet after ref listing"
+msgstr "Antwort-Endpaket nach Auflistung der Referenzen erwartet"
+
+#, c-format
 msgid "invalid ls-refs response: %s"
 msgstr "ungültige ls-refs Antwort: %s"
 
 msgid "expected flush after ref listing"
 msgstr "Flush nach Auflistung der Referenzen erwartet"
 
-msgid "expected response end packet after ref listing"
-msgstr "Antwort-Endpaket nach Auflistung der Referenzen erwartet"
-
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr "Protokoll '%s' wird nicht unterstützt"
@@ -16472,16 +16549,14 @@
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-"           <command> [<args>]"
+"           [--config-env=<name>=<envvar>] <command> [<args>]"
 msgstr ""
 "git [-v | --version] [-h | --help] [-C <Pfad>] [-c <Name>=<Wert>]\n"
 "           [--exec-path[=<Pfad>]] [--html-path] [--man-path] [--info-path]\n"
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<Pfad>] [--work-tree=<Pfad>] [--namespace=<Name>]\n"
-"           [--super-prefix=<Pfad>] [--config-env=<Name>=<Variable>]\n"
-"           <Befehl> [<Argumente>]"
+"           [--config-env=<Name>=<Umgebungsvariable>] <Befehl> [<Argumente>]"
 
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -16508,10 +16583,6 @@
 msgstr "Kein Namespace für --namespace angegeben.\n"
 
 #, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "Kein Präfix für --super-prefix angegeben.\n"
-
-#, c-format
 msgid "-c expects a configuration string\n"
 msgstr "-c erwartet einen Konfigurationsstring.\n"
 
@@ -16625,8 +16696,13 @@
 msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
 msgstr "gpg.ssh.defaultKeyCommand fehlgeschlagen: %s %s"
 
-msgid "gpg failed to sign the data"
-msgstr "gpg beim Signieren der Daten fehlgeschlagen"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg konnte die Daten nicht signieren:\n"
+"%s"
 
 msgid "user.signingKey needs to be set for ssh signing"
 msgstr "user.signingKey muss für die SSH-Signatur gesetzt sein"
@@ -17206,7 +17282,7 @@
 #. conflict in a submodule. The first argument is the submodule
 #. name, and the second argument is the abbreviated id of the
 #. commit that needs to be merged.  For example:
-#. - go to submodule (mysubmodule), and either merge commit abc1234"
+#.  - go to submodule (mysubmodule), and either merge commit abc1234"
 #.
 #, c-format
 msgid ""
@@ -17800,6 +17876,10 @@
 msgstr "Nutzlose Daten am Ende von losem Objekt '%s'."
 
 #, c-format
+msgid "unable to open loose object %s"
+msgstr "loses Objekt %s kann nicht geöffnet werden"
+
+#, c-format
 msgid "unable to parse %s header"
 msgstr "Konnte %s Kopfbereich nicht parsen."
 
@@ -17815,18 +17895,14 @@
 msgstr "Header für %s zu lang, überschreitet %d Bytes"
 
 #, c-format
-msgid "failed to read object %s"
-msgstr "Konnte Objekt %s nicht lesen."
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "Loses Objekt %s (gespeichert in %s) ist beschädigt."
 
 #, c-format
 msgid "replacement %s not found for %s"
 msgstr "Ersetzung %s für %s nicht gefunden."
 
 #, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "Loses Objekt %s (gespeichert in %s) ist beschädigt."
-
-#, c-format
 msgid "packed object %s (stored in %s) is corrupt"
 msgstr "Gepacktes Objekt %s (gespeichert in %s) ist beschädigt."
 
@@ -17838,9 +17914,6 @@
 msgid "unable to set permission to '%s'"
 msgstr "Konnte Zugriffsberechtigung auf '%s' nicht setzen."
 
-msgid "file write error"
-msgstr "Fehler beim Schreiben einer Datei."
-
 msgid "error when closing loose object file"
 msgstr "Fehler beim Schließen der Datei für lose Objekte."
 
@@ -17888,11 +17961,12 @@
 msgid "cannot read object for %s"
 msgstr "Kann Objekt für %s nicht lesen."
 
-msgid "corrupt commit"
-msgstr "fehlerhafter Commit"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "fsck schlägt bei Objekt fehl: %s"
 
-msgid "corrupt tag"
-msgstr "fehlerhaftes Tag"
+msgid "refusing to create malformed object"
+msgstr "verweigere Erstellung eines ungültigen Objekts"
 
 #, c-format
 msgid "read error while indexing %s"
@@ -17949,7 +18023,7 @@
 #. TRANSLATORS: This is a line of ambiguous commit
 #. object output. E.g.:
 #. *
-#. "deadbeef commit 2021-01-01 - Some Commit Message"
+#.    "deadbeef commit 2021-01-01 - Some Commit Message"
 #.
 #, c-format
 msgid "%s commit %s - %s"
@@ -17958,7 +18032,7 @@
 #. TRANSLATORS: This is a line of ambiguous
 #. tag object output. E.g.:
 #. *
-#. "deadbeef tag 2022-01-01 - Some Tag Message"
+#.    "deadbeef tag 2022-01-01 - Some Tag Message"
 #. *
 #. The second argument is the YYYY-MM-DD found
 #. in the tag.
@@ -17974,7 +18048,7 @@
 #. tag object output where we couldn't parse
 #. the tag itself. E.g.:
 #. *
-#. "deadbeef [bad tag, could not parse it]"
+#.    "deadbeef [bad tag, could not parse it]"
 #.
 #, c-format
 msgid "%s [bad tag, could not parse it]"
@@ -18160,10 +18234,6 @@
 msgid "cannot fstat bitmap file"
 msgstr "kann Bitmap-Datei nicht lesen"
 
-#, c-format
-msgid "ignoring extra bitmap file: '%s'"
-msgstr "ignoriere zusätzliche Bitmap-Datei: '%s'"
-
 msgid "checksum doesn't match in MIDX and bitmap"
 msgstr "Prüfsumme stimmt in MIDX und Bitmap nicht überein"
 
@@ -18432,6 +18502,9 @@
 msgid "use <n> digits to display object names"
 msgstr "benutze <Anzahl> Ziffern zur Anzeige von Objektnamen"
 
+msgid "prefixed path to initial superproject"
+msgstr "vorangestellter Pfad zum ursprünglichen Superprojekt"
+
 msgid "how to strip spaces and #comments from message"
 msgstr ""
 "wie Leerzeichen und #Kommentare von der Beschreibung getrennt werden sollen"
@@ -18939,6 +19012,14 @@
 msgstr "%d voraus, %d hinterher"
 
 #, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) nimmt keine Argumente entgegen"
+
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "nicht erkanntes %%(%.*s) Argument: %s"
+
+#, c-format
 msgid "expected format: %%(color:<color>)"
 msgstr "Erwartetes Format: %%(color:<Farbe>)"
 
@@ -18955,22 +19036,6 @@
 msgstr "Positiver Wert erwartet refname:rstrip=%s"
 
 #, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "nicht erkanntes %%(%s) Argument: %s"
-
-#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) akzeptiert keine Argumente"
-
-#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) akzeptiert keine Argumente"
-
-#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) akzeptiert keine Argumente"
-
-#, c-format
 msgid "expected %%(trailers:key=<value>)"
 msgstr "%%(trailers:key=<Wert>) erwartet"
 
@@ -18987,10 +19052,6 @@
 msgstr "positiver Wert erwartet '%s' in %%(%s)"
 
 #, c-format
-msgid "unrecognized email option: %s"
-msgstr "nicht erkannte E-Mail Option: %s"
-
-#, c-format
 msgid "expected format: %%(align:<width>,<position>)"
 msgstr "erwartetes Format: %%(align:<Breite>,<Position>)"
 
@@ -19003,12 +19064,12 @@
 msgstr "nicht erkannte Breite:%s"
 
 #, c-format
-msgid "positive width expected with the %%(align) atom"
-msgstr "Positive Breitenangabe für %%(align) erwartet"
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "nicht erkanntes %%(%s) Argument: %s"
 
 #, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) akzeptiert keine Argumente"
+msgid "positive width expected with the %%(align) atom"
+msgstr "Positive Breitenangabe für %%(align) erwartet"
 
 #, c-format
 msgid "malformed field name: %.*s"
@@ -20275,6 +20336,24 @@
 msgstr "git %s: Fehler beim Aktualisieren des Index"
 
 #, c-format
+msgid "'%s' is not a valid label"
+msgstr "'%s' ist keine gültige Beschriftung"
+
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "'%s' ist kein gültiger Referenzname"
+
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr ""
+"update-ref erfordert einen vollständig qualifizierten Referenznamen, z. B. "
+"refs/heads/%s"
+
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "ungültiger Befehl '%.*s'"
+
+#, c-format
 msgid "%s does not accept arguments: '%s'"
 msgstr "%s akzeptiert keine Argumente: '%s'"
 
@@ -21087,6 +21166,16 @@
 msgid "failed to lstat '%s'"
 msgstr "'lstat' für '%s' fehlgeschlagen"
 
+msgid "no remote configured to get bundle URIs from"
+msgstr "kein Remote-Repository zum Erhalten von Bundle-URIs konfiguriert"
+
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "Remote-Repository '%s' hat keine konfigurierte URL"
+
+msgid "could not get the bundle-uri list"
+msgstr "konnte die Bundle-uri-Liste nicht erhalten"
+
 msgid "test-tool cache-tree <options> (control|prime|update)"
 msgstr "test-tool cache-tree <Optionen> (control|prime|update)"
 
@@ -21442,6 +21531,12 @@
 msgid "failed to push all needed submodules"
 msgstr "Fehler beim Versand aller erforderlichen Submodule."
 
+msgid "bundle-uri operation not supported by protocol"
+msgstr "bundle-uri Operation wird vom Protokoll nicht unterstützt"
+
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr "konnte die vom Server angekündigte bundle-uri-Liste nicht abrufen"
+
 msgid "too-short tree object"
 msgstr "zu kurzes Tree-Objekt"
 
@@ -22229,13 +22324,22 @@
 
 #, c-format
 msgid ""
-"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-"may speed it up, but you have to be careful not to forget to add\n"
-"new files yourself (see 'git help status')."
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
 msgstr ""
-"Es dauerte %.2f Sekunden die unversionierten Dateien zu bestimmen.\n"
-"'status -uno' könnte das beschleunigen, aber Sie müssen darauf achten,\n"
-"neue Dateien selbstständig hinzuzufügen (siehe 'git help status')."
+"Es dauerte %.2f Sekunden, um die unversionierten Dateien aufzuzählen,\n"
+"aber die Ergebnisse wurden zwischengespeichert, sodass spätere Durchläufe "
+"schneller sein können."
+
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr ""
+"Es hat %.2f Sekunden gedauert, um die unversionierten Dateien aufzuzählen."
+
+msgid "See 'git help status' for information on how to improve this."
+msgstr ""
+"Siehe 'git help status' für Informationen darüber, wie man dies verbessern "
+"kann."
 
 #, c-format
 msgid "Untracked files not listed%s"
@@ -22395,289 +22499,6 @@
 msgid "Unable to determine absolute path of git directory"
 msgstr "Konnte absoluten Pfad des Git-Verzeichnisses nicht bestimmen"
 
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#, perl-format
-msgid "%12s %12s %s"
-msgstr "%28s %25s %s"
-
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] "%d Pfad angefasst\n"
-msgstr[1] "%d Pfade angefasst\n"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr ""
-"Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
-"Patch-Block direkt zum Hinzufügen zur Staging-Area markiert."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr ""
-"Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
-"Patch-Block direkt zum Hinzufügen zum Stash markiert."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr ""
-"Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
-"Patch-Block direkt zum Entfernen aus der Staging-Area markiert."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr ""
-"Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
-"Patch-Block direkt zum Anwenden markiert."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr ""
-"Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
-"Patch-Block direkt zum Verwerfen markiert."
-
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr ""
-"Fehler beim Öffnen von Editier-Datei eines Patch-Blocks zum Schreiben: %s"
-
-#, perl-format
-msgid ""
-"---\n"
-"To remove '%s' lines, make them ' ' lines (context).\n"
-"To remove '%s' lines, delete them.\n"
-"Lines starting with %s will be removed.\n"
-msgstr ""
-"---\n"
-"Um '%s' Zeilen zu entfernen, machen Sie aus diesen ' ' Zeilen (Kontext).\n"
-"Um '%s' Zeilen zu entfernen, löschen Sie diese.\n"
-"Zeilen, die mit %s beginnen, werden entfernt.\n"
-
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr "Fehler beim Öffnen von Editier-Datei eines Patch-Blocks zum Lesen: %s"
-
-msgid ""
-"y - stage this hunk\n"
-"n - do not stage this hunk\n"
-"q - quit; do not stage this hunk or any of the remaining ones\n"
-"a - stage this hunk and all later hunks in the file\n"
-"d - do not stage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - diesen Patch-Block zum Commit vormerken\n"
-"n - diesen Patch-Block nicht zum Commit vormerken\n"
-"q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht zum Commit "
-"vormerken\n"
-"a - diesen und alle weiteren Patch-Blöcke dieser Datei zum Commit vormerken\n"
-"d - diesen oder alle weiteren Patch-Blöcke in dieser Datei nicht zum Commit "
-"vormerken"
-
-msgid ""
-"y - stash this hunk\n"
-"n - do not stash this hunk\n"
-"q - quit; do not stash this hunk or any of the remaining ones\n"
-"a - stash this hunk and all later hunks in the file\n"
-"d - do not stash this hunk or any of the later hunks in the file"
-msgstr ""
-"y - diesen Patch-Block stashen\n"
-"n - diesen Patch-Block nicht stashen\n"
-"q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht stashen\n"
-"a - diesen und alle weiteren Patch-Blöcke dieser Datei stashen\n"
-"d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht stashen"
-
-msgid ""
-"y - unstage this hunk\n"
-"n - do not unstage this hunk\n"
-"q - quit; do not unstage this hunk or any of the remaining ones\n"
-"a - unstage this hunk and all later hunks in the file\n"
-"d - do not unstage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - diesen Patch-Block unstashen\n"
-"n - diesen Patch-Block nicht unstashen\n"
-"q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht unstashen\n"
-"a - diesen und alle weiteren Patch-Blöcke dieser Datei unstashen\n"
-"d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht unstashen"
-
-msgid ""
-"y - apply this hunk to index\n"
-"n - do not apply this hunk to index\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - diesen Patch-Block auf den Index anwenden\n"
-"n - diesen Patch-Block nicht auf den Index anwenden\n"
-"q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht auf den Index "
-"anwenden\n"
-"a - diesen und alle weiteren Patch-Blöcke dieser Datei auf den Index "
-"anwenden\n"
-"d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht auf den Index "
-"anwenden"
-
-msgid ""
-"y - discard this hunk from worktree\n"
-"n - do not discard this hunk from worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - diesen Patch-Block im Arbeitsverzeichnis verwerfen\n"
-"n - diesen Patch-Block im Arbeitsverzeichnis nicht verwerfen\n"
-"q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht im "
-"Arbeitsverzeichnis verwerfen\n"
-"a - diesen und alle weiteren Patch-Blöcke dieser Datei im Arbeitsverzeichnis "
-"verwerfen\n"
-"d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht im "
-"Arbeitsverzeichnis verwerfen"
-
-msgid ""
-"y - discard this hunk from index and worktree\n"
-"n - do not discard this hunk from index and worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - diesen Patch-Block im Index und Arbeitsverzeichnis verwerfen\n"
-"n - diesen Patch-Block nicht im Index und Arbeitsverzeichnis verwerfen\n"
-"q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht im Index und "
-"Arbeitsverzeichnis verwerfen\n"
-"a - diesen und alle weiteren Patch-Blöcke in der Datei verwerfen\n"
-"d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht verwerfen"
-
-msgid ""
-"y - apply this hunk to index and worktree\n"
-"n - do not apply this hunk to index and worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - diesen Patch-Block im Index und auf Arbeitsverzeichnis anwenden\n"
-"n - diesen Patch-Block nicht im Index und auf Arbeitsverzeichnis anwenden\n"
-"q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht anwenden\n"
-"a - diesen und alle weiteren Patch-Blöcke in der Datei anwenden\n"
-"d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht anwenden"
-
-msgid ""
-"y - apply this hunk to worktree\n"
-"n - do not apply this hunk to worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - diesen Patch-Block auf das Arbeitsverzeichnis anwenden\n"
-"n - diesen Patch-Block nicht auf das Arbeitsverzeichnis anwenden\n"
-"q - Beenden; diesen und alle verbleibenden Patch-Blöcke nicht anwenden\n"
-"a - diesen und alle weiteren Patch-Blöcke in der Datei anwenden\n"
-"d - diesen und alle weiteren Patch-Blöcke in der Datei nicht anwenden"
-
-msgid ""
-"g - select a hunk to go to\n"
-"/ - search for a hunk matching the given regex\n"
-"j - leave this hunk undecided, see next undecided hunk\n"
-"J - leave this hunk undecided, see next hunk\n"
-"k - leave this hunk undecided, see previous undecided hunk\n"
-"K - leave this hunk undecided, see previous hunk\n"
-"s - split the current hunk into smaller hunks\n"
-"e - manually edit the current hunk\n"
-"? - print help\n"
-msgstr ""
-"g - Patch-Block zum Hinspringen auswählen\n"
-"/ - nach Patch-Block suchen, der gegebenem regulärem Ausdruck entspricht\n"
-"j - diesen Patch-Block unbestimmt lassen, nächsten unbestimmten Patch-Block "
-"anzeigen\n"
-"J - diesen Patch-Block unbestimmt lassen, nächsten Patch-Block anzeigen\n"
-"k - diesen Patch-Block unbestimmt lassen, vorherigen unbestimmten Patch-"
-"Block anzeigen\n"
-"K - diesen Patch-Block unbestimmt lassen, vorherigen Patch-Block anzeigen\n"
-"s - aktuellen Patch-Block in kleinere Patch-Blöcke aufteilen\n"
-"e - aktuellen Patch-Block manuell editieren\n"
-"? - Hilfe anzeigen\n"
-
-msgid "The selected hunks do not apply to the index!\n"
-msgstr ""
-"Die ausgewählten Patch-Blöcke können nicht auf den Index angewendet werden!\n"
-
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "ignoriere nicht zusammengeführte Datei: %s\n"
-
-msgid "No other hunks to goto\n"
-msgstr "Keine anderen Patch-Blöcke verbleibend\n"
-
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "Ungültige Nummer: '%s'\n"
-
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "Entschuldigung, nur %d Patch-Block verfügbar.\n"
-msgstr[1] "Entschuldigung, nur %d Patch-Blöcke verfügbar.\n"
-
-msgid "No other hunks to search\n"
-msgstr "Keine anderen Patch-Blöcke zum Durchsuchen\n"
-
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "Fehlerhafter regulärer Ausdruck für Suche %s: %s\n"
-
-msgid "No hunk matches the given pattern\n"
-msgstr "Kein Patch-Block entspricht dem angegebenen Muster\n"
-
-msgid "No previous hunk\n"
-msgstr "Kein vorheriger Patch-Block\n"
-
-msgid "No next hunk\n"
-msgstr "Kein folgender Patch-Block\n"
-
-msgid "Sorry, cannot split this hunk\n"
-msgstr "Entschuldigung, kann diesen Patch-Block nicht aufteilen.\n"
-
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "In %d Patch-Block aufgeteilt.\n"
-msgstr[1] "In %d Patch-Blöcke aufgeteilt.\n"
-
-msgid "Sorry, cannot edit this hunk\n"
-msgstr "Entschuldigung, kann diesen Patch-Block nicht bearbeiten.\n"
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-msgid ""
-"status        - show paths with changes\n"
-"update        - add working tree state to the staged set of changes\n"
-"revert        - revert staged set of changes back to the HEAD version\n"
-"patch         - pick hunks and update selectively\n"
-"diff          - view diff between HEAD and index\n"
-"add untracked - add contents of untracked files to the staged set of "
-"changes\n"
-msgstr ""
-"status        - Pfade mit Änderungen anzeigen\n"
-"update        - Zustand des Arbeitsverzeichnisses den zum Commit "
-"vorgemerkten Änderungen hinzufügen\n"
-"revert        - zum Commit vorgemerkte Änderungen auf HEAD Version "
-"zurücksetzen\n"
-"patch         - Patch-Blöcke auswählen und selektiv aktualisieren\n"
-"diff          - Unterschiede zwischen HEAD und Index anzeigen\n"
-"add untracked - Inhalte von unversionierten Dateien zum Commit vormerken\n"
-
-msgid "missing --"
-msgstr "-- fehlt"
-
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "Unbekannter --patch Modus: %s"
-
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "ungültiges Argument %s, erwarte --"
-
 msgid "local zone differs from GMT by a non-minute interval\n"
 msgstr ""
 "lokale Zeitzone unterscheidet sich von GMT nicht um ein Minutenintervall\n"
@@ -23016,3 +22837,377 @@
 #, perl-format
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Wollen Sie %s wirklich versenden? [y|N]: "
+
+#~ msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
+#~ msgstr "git bisect--helper --bisect-state (bad|new) [<Commit>]"
+
+#~ msgid "won't bisect on cg-seek'ed tree"
+#~ msgstr ""
+#~ "binäre Suche auf einem durch 'cg-seek' geändertem Verzeichnis nicht "
+#~ "möglich"
+
+#~ msgid "--bisect-terms requires 0 or 1 argument"
+#~ msgstr "--bisect-terms benötigt 0 oder 1 Argument"
+
+#~ msgid "--bisect-next requires 0 arguments"
+#~ msgstr "--bisect-next benötigt 0 Argumente"
+
+#~ msgid "--bisect-log requires 0 arguments"
+#~ msgstr "--bisect-log benötigt 0 Argumente"
+
+#~ msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
+#~ msgstr "git env--helper --type=[bool|ulong] <Optionen> <Umgebungsvariable>"
+
+#~ msgid "default for git_env_*(...) to fall back on"
+#~ msgstr "Standard für git_env_*(...), um darauf zurückzugreifen"
+
+#~ msgid "be quiet only use git_env_*() value as exit code"
+#~ msgstr ""
+#~ "Ausgaben unterdrücken; nur git_env_*() Werte als Exit-Code verwenden"
+
+#, c-format
+#~ msgid ""
+#~ "option `--default' expects a boolean value with `--type=bool`, not `%s`"
+#~ msgstr ""
+#~ "Option `--default' erwartet einen booleschen Wert bei `--type=bool`, "
+#~ "nicht `%s`"
+
+#, c-format
+#~ msgid ""
+#~ "option `--default' expects an unsigned long value with `--type=ulong`, "
+#~ "not `%s`"
+#~ msgstr ""
+#~ "Option `--default' erwartet einen vorzeichenlosen Long-Wert bei `--"
+#~ "type=ulong`, nicht `%s`"
+
+#, c-format
+#~ msgid "%s doesn't support --super-prefix"
+#~ msgstr "%s unterstützt kein --super-prefix"
+
+#, c-format
+#~ msgid "no prefix given for --super-prefix\n"
+#~ msgstr "Kein Präfix für --super-prefix angegeben.\n"
+
+#, c-format
+#~ msgid "failed to read object %s"
+#~ msgstr "Konnte Objekt %s nicht lesen."
+
+#~ msgid "file write error"
+#~ msgstr "Fehler beim Schreiben einer Datei."
+
+#~ msgid "corrupt commit"
+#~ msgstr "fehlerhafter Commit"
+
+#~ msgid "corrupt tag"
+#~ msgstr "fehlerhaftes Tag"
+
+#, c-format
+#~ msgid "%%(objecttype) does not take arguments"
+#~ msgstr "%%(objecttype) akzeptiert keine Argumente"
+
+#, c-format
+#~ msgid "%%(deltabase) does not take arguments"
+#~ msgstr "%%(deltabase) akzeptiert keine Argumente"
+
+#, c-format
+#~ msgid "%%(body) does not take arguments"
+#~ msgstr "%%(body) akzeptiert keine Argumente"
+
+#, c-format
+#~ msgid "unrecognized email option: %s"
+#~ msgstr "nicht erkannte E-Mail Option: %s"
+
+#, c-format
+#~ msgid ""
+#~ "It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
+#~ "may speed it up, but you have to be careful not to forget to add\n"
+#~ "new files yourself (see 'git help status')."
+#~ msgstr ""
+#~ "Es dauerte %.2f Sekunden die unversionierten Dateien zu bestimmen.\n"
+#~ "'status -uno' könnte das beschleunigen, aber Sie müssen darauf achten,\n"
+#~ "neue Dateien selbstständig hinzuzufügen (siehe 'git help status')."
+
+#, perl-format
+#~ msgid "%12s %12s %s"
+#~ msgstr "%28s %25s %s"
+
+#, perl-format
+#~ msgid "touched %d path\n"
+#~ msgid_plural "touched %d paths\n"
+#~ msgstr[0] "%d Pfad angefasst\n"
+#~ msgstr[1] "%d Pfade angefasst\n"
+
+#~ msgid ""
+#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
+#~ "marked for staging."
+#~ msgstr ""
+#~ "Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
+#~ "Patch-Block direkt zum Hinzufügen zur Staging-Area markiert."
+
+#~ msgid ""
+#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
+#~ "marked for stashing."
+#~ msgstr ""
+#~ "Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
+#~ "Patch-Block direkt zum Hinzufügen zum Stash markiert."
+
+#~ msgid ""
+#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
+#~ "marked for unstaging."
+#~ msgstr ""
+#~ "Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
+#~ "Patch-Block direkt zum Entfernen aus der Staging-Area markiert."
+
+#~ msgid ""
+#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
+#~ "marked for applying."
+#~ msgstr ""
+#~ "Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
+#~ "Patch-Block direkt zum Anwenden markiert."
+
+#~ msgid ""
+#~ "If the patch applies cleanly, the edited hunk will immediately be\n"
+#~ "marked for discarding."
+#~ msgstr ""
+#~ "Wenn der Patch sauber angewendet werden kann, wird der bearbeitete\n"
+#~ "Patch-Block direkt zum Verwerfen markiert."
+
+#, perl-format
+#~ msgid "failed to open hunk edit file for writing: %s"
+#~ msgstr ""
+#~ "Fehler beim Öffnen von Editier-Datei eines Patch-Blocks zum Schreiben: %s"
+
+#, perl-format
+#~ msgid ""
+#~ "---\n"
+#~ "To remove '%s' lines, make them ' ' lines (context).\n"
+#~ "To remove '%s' lines, delete them.\n"
+#~ "Lines starting with %s will be removed.\n"
+#~ msgstr ""
+#~ "---\n"
+#~ "Um '%s' Zeilen zu entfernen, machen Sie aus diesen ' ' Zeilen (Kontext).\n"
+#~ "Um '%s' Zeilen zu entfernen, löschen Sie diese.\n"
+#~ "Zeilen, die mit %s beginnen, werden entfernt.\n"
+
+#, perl-format
+#~ msgid "failed to open hunk edit file for reading: %s"
+#~ msgstr ""
+#~ "Fehler beim Öffnen von Editier-Datei eines Patch-Blocks zum Lesen: %s"
+
+#~ msgid ""
+#~ "y - stage this hunk\n"
+#~ "n - do not stage this hunk\n"
+#~ "q - quit; do not stage this hunk or any of the remaining ones\n"
+#~ "a - stage this hunk and all later hunks in the file\n"
+#~ "d - do not stage this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - diesen Patch-Block zum Commit vormerken\n"
+#~ "n - diesen Patch-Block nicht zum Commit vormerken\n"
+#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht zum Commit "
+#~ "vormerken\n"
+#~ "a - diesen und alle weiteren Patch-Blöcke dieser Datei zum Commit "
+#~ "vormerken\n"
+#~ "d - diesen oder alle weiteren Patch-Blöcke in dieser Datei nicht zum "
+#~ "Commit vormerken"
+
+#~ msgid ""
+#~ "y - stash this hunk\n"
+#~ "n - do not stash this hunk\n"
+#~ "q - quit; do not stash this hunk or any of the remaining ones\n"
+#~ "a - stash this hunk and all later hunks in the file\n"
+#~ "d - do not stash this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - diesen Patch-Block stashen\n"
+#~ "n - diesen Patch-Block nicht stashen\n"
+#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht stashen\n"
+#~ "a - diesen und alle weiteren Patch-Blöcke dieser Datei stashen\n"
+#~ "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht stashen"
+
+#~ msgid ""
+#~ "y - unstage this hunk\n"
+#~ "n - do not unstage this hunk\n"
+#~ "q - quit; do not unstage this hunk or any of the remaining ones\n"
+#~ "a - unstage this hunk and all later hunks in the file\n"
+#~ "d - do not unstage this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - diesen Patch-Block unstashen\n"
+#~ "n - diesen Patch-Block nicht unstashen\n"
+#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht unstashen\n"
+#~ "a - diesen und alle weiteren Patch-Blöcke dieser Datei unstashen\n"
+#~ "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht unstashen"
+
+#~ msgid ""
+#~ "y - apply this hunk to index\n"
+#~ "n - do not apply this hunk to index\n"
+#~ "q - quit; do not apply this hunk or any of the remaining ones\n"
+#~ "a - apply this hunk and all later hunks in the file\n"
+#~ "d - do not apply this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - diesen Patch-Block auf den Index anwenden\n"
+#~ "n - diesen Patch-Block nicht auf den Index anwenden\n"
+#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht auf den "
+#~ "Index anwenden\n"
+#~ "a - diesen und alle weiteren Patch-Blöcke dieser Datei auf den Index "
+#~ "anwenden\n"
+#~ "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht auf den "
+#~ "Index anwenden"
+
+#~ msgid ""
+#~ "y - discard this hunk from worktree\n"
+#~ "n - do not discard this hunk from worktree\n"
+#~ "q - quit; do not discard this hunk or any of the remaining ones\n"
+#~ "a - discard this hunk and all later hunks in the file\n"
+#~ "d - do not discard this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - diesen Patch-Block im Arbeitsverzeichnis verwerfen\n"
+#~ "n - diesen Patch-Block im Arbeitsverzeichnis nicht verwerfen\n"
+#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht im "
+#~ "Arbeitsverzeichnis verwerfen\n"
+#~ "a - diesen und alle weiteren Patch-Blöcke dieser Datei im "
+#~ "Arbeitsverzeichnis verwerfen\n"
+#~ "d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht im "
+#~ "Arbeitsverzeichnis verwerfen"
+
+#~ msgid ""
+#~ "y - discard this hunk from index and worktree\n"
+#~ "n - do not discard this hunk from index and worktree\n"
+#~ "q - quit; do not discard this hunk or any of the remaining ones\n"
+#~ "a - discard this hunk and all later hunks in the file\n"
+#~ "d - do not discard this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - diesen Patch-Block im Index und Arbeitsverzeichnis verwerfen\n"
+#~ "n - diesen Patch-Block nicht im Index und Arbeitsverzeichnis verwerfen\n"
+#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht im Index "
+#~ "und Arbeitsverzeichnis verwerfen\n"
+#~ "a - diesen und alle weiteren Patch-Blöcke in der Datei verwerfen\n"
+#~ "d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht verwerfen"
+
+#~ msgid ""
+#~ "y - apply this hunk to index and worktree\n"
+#~ "n - do not apply this hunk to index and worktree\n"
+#~ "q - quit; do not apply this hunk or any of the remaining ones\n"
+#~ "a - apply this hunk and all later hunks in the file\n"
+#~ "d - do not apply this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - diesen Patch-Block im Index und auf Arbeitsverzeichnis anwenden\n"
+#~ "n - diesen Patch-Block nicht im Index und auf Arbeitsverzeichnis "
+#~ "anwenden\n"
+#~ "q - Beenden; diesen oder alle verbleibenden Patch-Blöcke nicht anwenden\n"
+#~ "a - diesen und alle weiteren Patch-Blöcke in der Datei anwenden\n"
+#~ "d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht anwenden"
+
+#~ msgid ""
+#~ "y - apply this hunk to worktree\n"
+#~ "n - do not apply this hunk to worktree\n"
+#~ "q - quit; do not apply this hunk or any of the remaining ones\n"
+#~ "a - apply this hunk and all later hunks in the file\n"
+#~ "d - do not apply this hunk or any of the later hunks in the file"
+#~ msgstr ""
+#~ "y - diesen Patch-Block auf das Arbeitsverzeichnis anwenden\n"
+#~ "n - diesen Patch-Block nicht auf das Arbeitsverzeichnis anwenden\n"
+#~ "q - Beenden; diesen und alle verbleibenden Patch-Blöcke nicht anwenden\n"
+#~ "a - diesen und alle weiteren Patch-Blöcke in der Datei anwenden\n"
+#~ "d - diesen und alle weiteren Patch-Blöcke in der Datei nicht anwenden"
+
+#~ msgid ""
+#~ "g - select a hunk to go to\n"
+#~ "/ - search for a hunk matching the given regex\n"
+#~ "j - leave this hunk undecided, see next undecided hunk\n"
+#~ "J - leave this hunk undecided, see next hunk\n"
+#~ "k - leave this hunk undecided, see previous undecided hunk\n"
+#~ "K - leave this hunk undecided, see previous hunk\n"
+#~ "s - split the current hunk into smaller hunks\n"
+#~ "e - manually edit the current hunk\n"
+#~ "? - print help\n"
+#~ msgstr ""
+#~ "g - Patch-Block zum Hinspringen auswählen\n"
+#~ "/ - nach Patch-Block suchen, der gegebenem regulärem Ausdruck entspricht\n"
+#~ "j - diesen Patch-Block unbestimmt lassen, nächsten unbestimmten Patch-"
+#~ "Block anzeigen\n"
+#~ "J - diesen Patch-Block unbestimmt lassen, nächsten Patch-Block anzeigen\n"
+#~ "k - diesen Patch-Block unbestimmt lassen, vorherigen unbestimmten Patch-"
+#~ "Block anzeigen\n"
+#~ "K - diesen Patch-Block unbestimmt lassen, vorherigen Patch-Block "
+#~ "anzeigen\n"
+#~ "s - aktuellen Patch-Block in kleinere Patch-Blöcke aufteilen\n"
+#~ "e - aktuellen Patch-Block manuell editieren\n"
+#~ "? - Hilfe anzeigen\n"
+
+#~ msgid "The selected hunks do not apply to the index!\n"
+#~ msgstr ""
+#~ "Die ausgewählten Patch-Blöcke können nicht auf den Index angewendet "
+#~ "werden!\n"
+
+#, perl-format
+#~ msgid "ignoring unmerged: %s\n"
+#~ msgstr "ignoriere nicht zusammengeführte Datei: %s\n"
+
+#~ msgid "No other hunks to goto\n"
+#~ msgstr "Keine anderen Patch-Blöcke verbleibend\n"
+
+#, perl-format
+#~ msgid "Invalid number: '%s'\n"
+#~ msgstr "Ungültige Nummer: '%s'\n"
+
+#, perl-format
+#~ msgid "Sorry, only %d hunk available.\n"
+#~ msgid_plural "Sorry, only %d hunks available.\n"
+#~ msgstr[0] "Entschuldigung, nur %d Patch-Block verfügbar.\n"
+#~ msgstr[1] "Entschuldigung, nur %d Patch-Blöcke verfügbar.\n"
+
+#~ msgid "No other hunks to search\n"
+#~ msgstr "Keine anderen Patch-Blöcke zum Durchsuchen\n"
+
+#, perl-format
+#~ msgid "Malformed search regexp %s: %s\n"
+#~ msgstr "Fehlerhafter regulärer Ausdruck für Suche %s: %s\n"
+
+#~ msgid "No hunk matches the given pattern\n"
+#~ msgstr "Kein Patch-Block entspricht dem angegebenen Muster\n"
+
+#~ msgid "No previous hunk\n"
+#~ msgstr "Kein vorheriger Patch-Block\n"
+
+#~ msgid "No next hunk\n"
+#~ msgstr "Kein folgender Patch-Block\n"
+
+#~ msgid "Sorry, cannot split this hunk\n"
+#~ msgstr "Entschuldigung, kann diesen Patch-Block nicht aufteilen.\n"
+
+#, perl-format
+#~ msgid "Split into %d hunk.\n"
+#~ msgid_plural "Split into %d hunks.\n"
+#~ msgstr[0] "In %d Patch-Block aufgeteilt.\n"
+#~ msgstr[1] "In %d Patch-Blöcke aufgeteilt.\n"
+
+#~ msgid "Sorry, cannot edit this hunk\n"
+#~ msgstr "Entschuldigung, kann diesen Patch-Block nicht bearbeiten.\n"
+
+#~ msgid ""
+#~ "status        - show paths with changes\n"
+#~ "update        - add working tree state to the staged set of changes\n"
+#~ "revert        - revert staged set of changes back to the HEAD version\n"
+#~ "patch         - pick hunks and update selectively\n"
+#~ "diff          - view diff between HEAD and index\n"
+#~ "add untracked - add contents of untracked files to the staged set of "
+#~ "changes\n"
+#~ msgstr ""
+#~ "status        - Pfade mit Änderungen anzeigen\n"
+#~ "update        - Zustand des Arbeitsverzeichnisses den zum Commit "
+#~ "vorgemerkten Änderungen hinzufügen\n"
+#~ "revert        - zum Commit vorgemerkte Änderungen auf HEAD Version "
+#~ "zurücksetzen\n"
+#~ "patch         - Patch-Blöcke auswählen und selektiv aktualisieren\n"
+#~ "diff          - Unterschiede zwischen HEAD und Index anzeigen\n"
+#~ "add untracked - Inhalte von unversionierten Dateien zum Commit vormerken\n"
+
+#~ msgid "missing --"
+#~ msgstr "-- fehlt"
+
+#, perl-format
+#~ msgid "unknown --patch mode: %s"
+#~ msgstr "Unbekannter --patch Modus: %s"
+
+#, perl-format
+#~ msgid "invalid argument %s, expecting --"
+#~ msgstr "ungültiges Argument %s, erwarte --"
diff --git a/po/fr.po b/po/fr.po
index 67eab9f..f032441 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -1,5 +1,5 @@
 # French translations for Git.
-# Copyright (C) 2019 Jean-Noël Avila <jn.avila@free.fr>
+# Copyright (C) 2023 Jean-Noël Avila <jn.avila@free.fr>
 # This file is distributed under the same license as the Git package.
 # Jean-Noël Avila <jn.avila@free.fr>, 2013-2019.
 # Sébastien Helleu <flashcode@flashtux.org>, 2013.
@@ -78,8 +78,8 @@
 msgstr ""
 "Project-Id-Version: git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-11-30 19:40+0100\n"
-"PO-Revision-Date: 2022-11-30 19:42+0100\n"
+"POT-Creation-Date: 2023-03-01 01:20+0000\n"
+"PO-Revision-Date: 2023-03-02 18:44+0100\n"
 "Last-Translator: Cédric Malard <c.malard-git@valdun.net>\n"
 "Language-Team: Jean-Noël Avila <jn.avila@free.fr>\n"
 "Language: fr\n"
@@ -115,13 +115,13 @@
 msgid "could not write index"
 msgstr "impossible d'écrire l'index"
 
-#, c-format, perl-format
+#, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "%d chemin mis à jour\n"
 msgstr[1] "%d chemins mis à jour\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "note : %s n'est plus suivi à présent.\n"
 
@@ -135,7 +135,7 @@
 msgid "Could not parse HEAD^{tree}"
 msgstr "Impossible d'analyser HEAD^{tree}"
 
-#, c-format, perl-format
+#, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "%d chemin inversé\n"
@@ -148,7 +148,7 @@
 msgid "Add untracked"
 msgstr "Ajouter un fichier non-suivi"
 
-#, c-format, perl-format
+#, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "%d chemin ajouté\n"
@@ -245,19 +245,19 @@
 msgid "Bye.\n"
 msgstr "Au revoir.\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "Indexer le changement de mode [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "Indexer la suppression [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "Indexer l'ajout [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Indexer cette section [y,n,q,a,d%s,?] ? "
 
@@ -281,19 +281,19 @@
 "a - indexer cette section et toutes les suivantes de ce fichier\n"
 "d - ne pas indexer cette section ni les suivantes de ce fichier\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "Remiser le changement de mode [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "Remiser la suppression [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "Remiser l'ajout [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "Remiser cette section [y,n,q,a,d%s,?] ? "
 
@@ -317,19 +317,19 @@
 "a - remiser cette section et toutes les suivantes de ce fichier\n"
 "d - ne pas remiser cette section ni les suivantes de ce fichier\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "Désindexer le changement de mode [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "Désindexer la suppression [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "Désindexer l'ajout [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Désindexer cette section [y,n,q,a,d%s,?] ? "
 
@@ -353,19 +353,19 @@
 "a - désindexer cette section et toutes les suivantes de ce fichier\n"
 "d - ne pas désindexer cette section ni les suivantes de ce fichier\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr "Appliquer le changement de mode à l'index [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "Appliquer la suppression à l'index [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "Appliquer l'ajout à l'index [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "Appliquer cette section à l'index [y,n,q,a,d%s,?] ? "
 
@@ -389,19 +389,19 @@
 "a - appliquer cette section et toutes les suivantes de ce fichier\n"
 "d - ne pas appliquer cette section ni les suivantes de ce fichier\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr "Abandonner le changement de mode dans l'arbre [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "Abandonner la suppression dans l'arbre [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "Abandonner l'ajout dans l'arbre [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
 msgstr "Abandonner cette section dans l'arbre [y,n,q,a,d%s,?] ? "
 
@@ -425,20 +425,20 @@
 "a - supprimer cette section et toutes les suivantes de ce fichier\n"
 "d - ne pas supprimer cette section ni les suivantes de ce fichier\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Abandonner le changement de mode dans l'index et l'arbre [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Abandonner la suppression de l'index et de l'arbre [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Abandonner l'ajout de l'index et de l'arbre [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Supprimer la section dans l'index et l'arbre de travail [y,n,q,a,d%s,?] ? "
@@ -456,24 +456,24 @@
 "a - éliminer cette section et toutes les suivantes de ce fichier\n"
 "d - ne pas éliminer cette section ni les suivantes de ce fichier\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Appliquer le changement de mode dans l'index et l'arbre de travail [y,n,q,a,"
 "d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Appliquer la suppression dans l'index et l'arbre de travail [y,n,q,a,"
 "d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Appliquer l'ajout dans l'index et l'arbre de travail [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Appliquer la section à l'index et l'arbre de travail [y,n,q,a,d%s,?] ? "
@@ -491,20 +491,20 @@
 "a - appliquer cette section et toutes les suivantes de ce fichier\n"
 "d - ne pas appliquer cette section ni les suivantes de ce fichier\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Appliquer le changement de mode dans l'arbre de travail [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
 msgstr "Appliquer la suppression dans l'arbre de travail [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
 msgstr "Appliquer l'ajout dans l'arbre de travail [y,n,q,a,d%s,?] ? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
 msgstr "Appliquer la section à l'arbre de travail [y,n,q,a,d%s,?] ? "
 
@@ -581,8 +581,6 @@
 "Pour éliminer les lignes '%c', effacez-les.\n"
 "Les lignes commençant par %c seront éliminées.\n"
 
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
 "edit again.  If all lines of the hunk are removed, then the edit is\n"
@@ -598,24 +596,16 @@
 msgid "'git apply --cached' failed"
 msgstr "'git apply --cached' a échoué"
 
-#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr ""
-"Votre section éditée ne s'applique pas. L'éditer à nouveau (\"no\" "
+"Votre section éditée ne s'applique pas. L'éditer à nouveau (\"n\" "
 "l'élimine !) [y|n] ? "
 
 msgid "The selected hunks do not apply to the index!"
@@ -1469,6 +1459,12 @@
 msgid "report archived files on stderr"
 msgstr "afficher les fichiers archivés sur stderr"
 
+msgid "time"
+msgstr "heure"
+
+msgid "set modification time of archive entries"
+msgstr "régler la date de modification des entrées de l'archive"
+
 msgid "set compression level"
 msgstr "régler le niveau de compression"
 
@@ -1509,6 +1505,13 @@
 msgid "%.*s is not a valid attribute name"
 msgstr "%.*s n'est pas un nom valide d'attribut"
 
+msgid "unable to add additional attribute"
+msgstr "Impossible d'ajouter l'attribut additionnel"
+
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "ligne d'attribute trop longue ignorée %d"
+
 #, c-format
 msgid "%s not allowed: %s:%d"
 msgstr "%s non permis : %s : %d"
@@ -1521,6 +1524,18 @@
 "Utilisez '\\!' pour un point d'exclamation littéral."
 
 #, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "impossible de fstat le fichier gitattributes '%s'"
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "fichier gitattributes trop gros ignoré '%s'"
+
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "blob gitattributes trop gros ignoré '%s'"
+
+#, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Contenu mal cité dans le fichier '%s' : %s"
 
@@ -1798,11 +1813,11 @@
 
 #, c-format
 msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
 msgstr ""
 "Vous pouvez essayer de mettre à jour les sous-modules en utilisant 'git "
-"checkout %s && git submodule update --init'"
+"checkout --no-recurse-submodules %s && git submodule update --init'"
 
 #, c-format
 msgid "submodule '%s': cannot create branch '%s'"
@@ -1837,6 +1852,13 @@
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Modifications non indexées après rafraîchissement de l'index :"
 
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"le réglage add.interactive.useBuiltin a été supprimé !\n"
+"Référez-vous à cette entrée dans 'git help config' pour plus de détails."
+
 msgid "Could not read the index"
 msgstr "Impossible de lire l'index"
 
@@ -2232,6 +2254,9 @@
 msgid "run interactively"
 msgstr "exécution interactive"
 
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "court-circuiter les crochets pre-applypatch and applypatch-msg"
+
 msgid "historical option -- no-op"
 msgstr "option historique -- no-op"
 
@@ -2376,32 +2401,28 @@
 msgid "git archive: expected a flush"
 msgstr "git archive : vidage attendu"
 
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [<commit>]"
-
 msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<terme> --term-{old,good}"
-"=<terme>][--no-checkout] [--first-parent] [<mauvais> [<bon>...]] [--] "
-"[<chemins>...]"
+"git bisect start [--term-{new,bad}=<terme> --term-{old,good}=<terme>]    [--"
+"no-checkout] [--first-parent] [<mauvais> [<bon>...]] [--]    [<spéc-de-"
+"chemin>...]"
 
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (bad|new) [<rév>]"
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<rév>...]"
 
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (good|old) [<rév>...]"
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<rév>|<plage>)...]"
 
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay <nom-de-fichier>"
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<commit>]"
 
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(<rév>|<plage>)...]"
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <fichier-journal>"
 
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run <cmd>..."
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run <cmd>..."
 
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
@@ -2548,9 +2569,6 @@
 msgstr ""
 "l'extraction de '%s' a échoué. Essayez 'git bisect start <branche-valide>'."
 
-msgid "won't bisect on cg-seek'ed tree"
-msgstr "refus de bissecter sur un arbre 'cg-seeked'"
-
 msgid "bad HEAD - strange symbolic ref"
 msgstr "mauvaise HEAD - référence symbolique douteuse"
 
@@ -2602,16 +2620,16 @@
 msgstr "la bissection a échoué : aucune commande fournie."
 
 #, c-format
-msgid "unable to verify '%s' on good revision"
-msgstr "impossible de vérifier '%s' sur une bonne révision"
+msgid "unable to verify %s on good revision"
+msgstr "impossible de vérifier %s sur une bonne révision"
 
 #, c-format
 msgid "bogus exit code %d for good revision"
 msgstr "code de sortie %d erroné pour une bonne révision"
 
 #, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
-msgstr "la bissection a échoué : le code retour %d de '%s' est < 0 ou >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
+msgstr "la bissection a échoué : le code retour %d de %s est < 0 ou >= 128"
 
 #, c-format
 msgid "cannot open file '%s' for writing"
@@ -2620,37 +2638,42 @@
 msgid "bisect run cannot continue any more"
 msgstr "la bissection ne peut plus continuer"
 
-#, c-format
 msgid "bisect run success"
 msgstr "succès de la bissection"
 
-#, c-format
 msgid "bisect found first bad commit"
 msgstr "la bissection a trouvé le premier mauvais commit"
 
 #, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
-msgstr ""
-"la bissection a échoué : 'git bisect--helper --bisect-state %s' a retourné "
-"le code erreur %d"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
+msgstr "la bissection a échoué : 'git bisect %s' a retourné le code erreur %d"
 
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "--bisect-reset supporte soit aucun argument, soit un commit"
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "%s supporte soit aucun argument, soit un commit"
 
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "--bisect-terms exige 0 ou 1 argument"
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "'%s' nécessite 0 ou 1 argument"
 
-msgid "--bisect-next requires 0 arguments"
-msgstr "--bisect-next exige 0 argument"
-
-msgid "--bisect-log requires 0 arguments"
-msgstr "--bisect-log exige 0 argument"
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "'%s' n'accepte aucun argument"
 
 msgid "no logfile given"
 msgstr "pas de fichier de log donné"
 
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "'%s' a échoué : aucune commande fournie."
+
+msgid "need a command"
+msgstr "commande requise"
+
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "commande inconnue : '%s'"
+
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 msgstr "git blame [<options>] [<rev-opts>] [<rev>] [--] <fichier>"
 
@@ -3241,6 +3264,9 @@
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
 msgstr "git bundle unbundle [--progress] <fichier> [<nom-de-ref>...]"
 
+msgid "need a <file> argument"
+msgstr "requiert un argument <fichier>"
+
 msgid "do not show progress meter"
 msgstr "ne pas afficher la barre de progression"
 
@@ -3294,10 +3320,6 @@
 msgid "%s takes no arguments"
 msgstr "%s n'accepte aucune argument"
 
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "commande inconnue : %s"
-
 msgid "only one batch option may be specified"
 msgstr "une seule option de traitement ne peut être spécifiée à la fois"
 
@@ -3434,11 +3456,17 @@
 msgid "only two arguments allowed in <type> <object> mode, not %d"
 msgstr "deux arguments seulement permis dans le mode <type> <objet>, pas %d"
 
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | <attr>...] [--] <chemin>..."
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [--source <arbre-esque>] [-a | --all | <attr>...] [--] "
+"<chemin>..."
 
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | <attr>...]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source <arbre-esque>] [-a | --all | <attr>...]"
 
 msgid "report all attributes set on file"
 msgstr "afficher tous les attributs associés au fichier"
@@ -3453,6 +3481,12 @@
 msgstr ""
 "terminer les enregistrements en entrée et en sortie par un caractère NUL"
 
+msgid "<tree-ish>"
+msgstr "<arbre-esque>"
+
+msgid "which tree-ish to check attributes at"
+msgstr "à quel <arbre-esque> vérifier les attributs"
+
 msgid "suppress progress reporting"
 msgstr "supprimer l'état d'avancement"
 
@@ -4040,7 +4074,7 @@
 "*          - choisir tous les éléments\n"
 "           - (vide) terminer la sélection\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Huh (%s)?\n"
 msgstr "Hein (%s) ?\n"
 
@@ -4189,9 +4223,6 @@
 msgid "create a shallow clone of that depth"
 msgstr "créer un clone superficiel de cette profondeur"
 
-msgid "time"
-msgstr "heure"
-
 msgid "create a shallow clone since a specific time"
 msgstr "créer un clone superficiel depuis une date spécifique"
 
@@ -4434,6 +4465,9 @@
 msgid "failed to fetch objects from bundle URI '%s'"
 msgstr "impossible de récupérer les objets depuis l'URI de paquet '%s'"
 
+msgid "failed to fetch advertised bundles"
+msgstr "échec de récupération des colis annoncés"
+
 msgid "remote transport reported error"
 msgstr "le transport distant a retourné une erreur"
 
@@ -5689,30 +5723,6 @@
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "pas de <commande> spécifié pour --extcmd=<commande>"
 
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] <options> <var d'env>"
-
-msgid "default for git_env_*(...) to fall back on"
-msgstr "valeur par défaut pour git_env_*(...) en cas d'absence"
-
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr ""
-"mode silencieux n'utilisant la valeur de git_env_*() que pour le code de "
-"sortie"
-
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr ""
-"l'option `--default` attend une valeur booléenne avec `--type=bool`, pas `%s`"
-
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not "
-"`%s`"
-msgstr ""
-"l'option `--default` attend une valeur entier long non signé avec `--"
-"type=ulong`, pas `%s`"
-
 msgid "git fast-export [<rev-list-opts>]"
 msgstr "git fast-export [<options-de-liste-de-révisions>]"
 
@@ -6122,6 +6132,10 @@
 msgid "--unshallow on a complete repository does not make sense"
 msgstr "--unshallow sur un dépôt complet n'a pas de sens"
 
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "échec de récupération des colis depuis '%s'"
+
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all n'accepte pas d'argument de dépôt"
 
@@ -7160,13 +7174,19 @@
 msgid "'git help config' for more information"
 msgstr "'git help config' pour plus d'information"
 
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
 msgstr ""
-"git hook run [--ignore-missing] <nom-de-crochet> [-- <arguments-de-crochet>]"
+"git hook run [--ignore-missing] [--to-stdin=<chemin>] <nom-de-crochet> [-- "
+"<arguments-de-crochet>]"
 
 msgid "silently ignore missing requested <hook-name>"
 msgstr "ignorer silencieusement le <nom-de-crochet> requis manquant"
 
+msgid "file to read into hooks' stdin"
+msgstr "fichier à la lire dans l'entrée standard du crochet"
+
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "type d'objet non correspondant à %s"
@@ -7985,7 +8005,7 @@
 msgstr "si un <fichier> n'est pas dans l'index, traiter cela comme une erreur"
 
 msgid "tree-ish"
-msgstr "arbre ou apparenté"
+msgstr "arbre-esque"
 
 msgid "pretend that paths removed since <tree-ish> are still present"
 msgstr ""
@@ -8011,11 +8031,11 @@
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<clé>]\n"
-"              [--symref] [<dépôt> [<réf>...]]"
+"              [--symref] [<dépôt> [<motif>...]]"
 
 msgid "do not print remote URL"
 msgstr "ne pas afficher les URL distantes"
@@ -8265,9 +8285,15 @@
 msgid "perform multiple merges, one per line of input"
 msgstr "réaliser des fusions multiples, une par ligne d'entrée"
 
+msgid "specify a merge-base for the merge"
+msgstr "spécifier une base de fusion pour la fusion"
+
 msgid "--trivial-merge is incompatible with all other options"
 msgstr "--trivial-merge est incompatible avec d'autres options"
 
+msgid "--merge-base is incompatible with --stdin"
+msgstr "--merge-base est incompatible avec --stdin"
+
 #, c-format
 msgid "malformed input line: '%s'."
 msgstr "ligne en entrée malformée : '%s'."
@@ -10202,6 +10228,10 @@
 msgid "could not switch to %s"
 msgstr "impossible de basculer vers %s"
 
+msgid "apply options and merge options cannot be used together"
+msgstr ""
+"Les options d'apply et celles de merge ne peuvent pas être utilisées ensemble"
+
 #, c-format
 msgid ""
 "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
@@ -10437,9 +10467,19 @@
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy requiert --merge ou --interactive"
 
-msgid "apply options and merge options cannot be used together"
+msgid ""
+"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"autosquash"
 msgstr ""
-"Les options d'apply et celles de merge ne peuvent pas être utilisées ensemble"
+"les options d'application sont incompatibles avec rebase.autosquash. "
+"Considérez l'ajout de --no-autosquash"
+
+msgid ""
+"apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
+"update-refs"
+msgstr ""
+"les options d'application sont incompatibles avec rebase.updateRefs. "
+"Considérez l'ajout de --no-update-refs"
 
 #, c-format
 msgid "Unknown rebase backend: %s"
@@ -12980,10 +13020,6 @@
 msgid "git submodule--helper <command>"
 msgstr "git submodule--helper <commande>"
 
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s ne gère pas --super-prefix"
-
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
 msgstr "git symbolic-ref [-m <raison>] <nom> <réf>"
 
@@ -13744,6 +13780,10 @@
 msgstr "core.fsyncMethod = batch non géré sur cette plateforme"
 
 #, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr "impossible d'analyser la clé de liste de colis %s avec la valeur '%s'"
+
+#, c-format
 msgid "bundle list at '%s' has no mode"
 msgstr "la liste de colis n'a pas de mode à '%s'"
 
@@ -13754,6 +13794,13 @@
 msgstr "capacités insuffisantes"
 
 #, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "le fichier téléchargé depuis '%s' n'est pas un colis"
+
+msgid "failed to store maximum creation token"
+msgstr "échec de stockage du jeton de création maximum"
+
+#, c-format
 msgid "unrecognized bundle mode from URI '%s'"
 msgstr "mode de colisage non reconnu depuis l'URI '%s'"
 
@@ -13769,6 +13816,13 @@
 msgid "file at URI '%s' is not a bundle or bundle list"
 msgstr "le fichier à l'URI '%s' n'est pas un colis ou une liste de colis"
 
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri :argument inattendu : '%s'"
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri : vidage attendu après les arguments"
+
 msgid "bundle-uri: got an empty line"
 msgstr "bundle-uri : ligne vide rencontrée"
 
@@ -13800,6 +13854,13 @@
 msgid "need a repository to verify a bundle"
 msgstr "la vérification d'un colis requiert un dépôt"
 
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+"des commits prérequis existent dans le stock d'objets, mais ne sont pas "
+"connectés à l'historique du dépôt"
+
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -15255,15 +15316,22 @@
 msgstr "format d'objet spécifié par le serveur inconnu '%s'"
 
 #, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "erreur sur la ligne %d de réponse bundle-uri : %s"
+
+msgid "expected flush after bundle-uri listing"
+msgstr "vidage attendu après le listage des bundle-uri"
+
+msgid "expected response end packet after ref listing"
+msgstr "paquet de fin de réponse attendu après le listage de références"
+
+#, c-format
 msgid "invalid ls-refs response: %s"
 msgstr "réponse à ls-ref invalide : %s"
 
 msgid "expected flush after ref listing"
 msgstr "vidage attendu après le listage de références"
 
-msgid "expected response end packet after ref listing"
-msgstr "paquet de fin de réponse attendu après le listage de références"
-
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr "le protocole '%s' n'est pas supporté"
@@ -16427,11 +16495,11 @@
 
 #, c-format
 msgid "could not send '%s' command to fsmonitor--daemon"
-msgstr "impossible de lancer la commmand '%s' à fsmonitor--daemon"
+msgstr "impossible de lancer la commande '%s' à fsmonitor--daemon"
 
 #, c-format
 msgid "bare repository '%s' is incompatible with fsmonitor"
-msgstr "le dépôit nu '%s' est incompatible avec fsmonitor"
+msgstr "le dépôt nu '%s' est incompatible avec fsmonitor"
 
 #, c-format
 msgid "repository '%s' is incompatible with fsmonitor due to errors"
@@ -16459,18 +16527,16 @@
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-"           <command> [<args>]"
+"           [--config-env=<name>=<envvar>] <command> [<args>]"
 msgstr ""
-"git [--version] [-h | --help] [-C <chemin>] [-c <nom>=<valeur>]\n"
+"git [-v | --version] [-h | --help] [-C <chemin>] [-c <nom>=<valeur>]\n"
 "           [--exec-path[=<chemin>]] [--html-path] [--man-path] [--info-"
 "path]\n"
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<chemin>] [--work-tree=<chemin>] [--namespace=<nom>]\n"
-"           [--super-prefix=<chemin>] [--config-env=<nom>=<variable-d-"
-"environnement>]\n"
-"           <commande> [<args>]"
+"           [--config-env=<nom>=<variable-d-environnement>] <commande> "
+"[<args>]"
 
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -16496,10 +16562,6 @@
 msgstr "aucun espace de nom fournit pour --namespace\n"
 
 #, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "aucun préfixe fourni pour --super-prefix\n"
-
-#, c-format
 msgid "-c expects a configuration string\n"
 msgstr "-c requiert une chaîne de configuration\n"
 
@@ -16611,8 +16673,13 @@
 msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
 msgstr "gpg.ssh.defaultKeyCommand a échoué : %s %s"
 
-msgid "gpg failed to sign the data"
-msgstr "gpg n'a pas pu signer les données"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg n'a pas pu signer les données :\n"
+"%s"
 
 msgid "user.signingKey needs to be set for ssh signing"
 msgstr "user.signingKey doit être configuré pour signer avec ssh"
@@ -17771,6 +17838,10 @@
 msgstr "données incorrectes à la fin de l'objet libre '%s'"
 
 #, c-format
+msgid "unable to open loose object %s"
+msgstr "impossible d'ouvrir l'objet libre %s"
+
+#, c-format
 msgid "unable to parse %s header"
 msgstr "impossible d'analyser l'entête %s"
 
@@ -17786,18 +17857,14 @@
 msgstr "entête de %s trop long, attendu %d octets"
 
 #, c-format
-msgid "failed to read object %s"
-msgstr "impossible de lire l'objet %s"
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "l'objet libre %s (stocké dans %s) est corrompu"
 
 #, c-format
 msgid "replacement %s not found for %s"
 msgstr "remplacement %s non trouvé pour %s"
 
 #, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "l'objet libre %s (stocké dans %s) est corrompu"
-
-#, c-format
 msgid "packed object %s (stored in %s) is corrupt"
 msgstr "l'objet empaqueté %s (stocké dans %s) est corrompu"
 
@@ -17809,9 +17876,6 @@
 msgid "unable to set permission to '%s'"
 msgstr "impossible de régler les droits de '%s'"
 
-msgid "file write error"
-msgstr "erreur d'écriture d'un fichier"
-
 msgid "error when closing loose object file"
 msgstr "erreur en fermeture du fichier d'objet esseulé"
 
@@ -17858,11 +17922,12 @@
 msgid "cannot read object for %s"
 msgstr "impossible de lire l'objet pour %s"
 
-msgid "corrupt commit"
-msgstr "commit corrompu"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "l'objet est en échec de fsck : %s"
 
-msgid "corrupt tag"
-msgstr "étiquette corrompue"
+msgid "refusing to create malformed object"
+msgstr "Refus de créer un objet malformé"
 
 #, c-format
 msgid "read error while indexing %s"
@@ -18131,10 +18196,6 @@
 msgid "cannot fstat bitmap file"
 msgstr "impossible d'obtenir le statut (fstat) du fichier de bitmap"
 
-#, c-format
-msgid "ignoring extra bitmap file: '%s'"
-msgstr "fichier bitmap extra ignoré : '%s'"
-
 msgid "checksum doesn't match in MIDX and bitmap"
 msgstr "la somme de contrôle ne correspond pas entre MIDX et bitmap"
 
@@ -18400,6 +18461,9 @@
 msgid "use <n> digits to display object names"
 msgstr "utiliser <n> chiffres pour afficher les noms des objets"
 
+msgid "prefixed path to initial superproject"
+msgstr "chemin préfixé vers le superprojet initial"
+
 msgid "how to strip spaces and #comments from message"
 msgstr "comment éliminer les espaces et les commentaires # du message"
 
@@ -18914,6 +18978,14 @@
 msgstr "en avance de %d, en retard de %d"
 
 #, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) n'accepte pas d'argument"
+
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "argument %%(%.*s) non reconnu : %s"
+
+#, c-format
 msgid "expected format: %%(color:<color>)"
 msgstr "format attendu : %%(color:<couleur>)"
 
@@ -18930,22 +19002,6 @@
 msgstr "Valeur entière attendue refname:rstrip=%s"
 
 #, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "argument %%(%s) non reconnu : %s"
-
-#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) n'accepte pas d'argument"
-
-#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) n'accepte pas d'argument"
-
-#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) n'accepte pas d'argument"
-
-#, c-format
 msgid "expected %%(trailers:key=<value>)"
 msgstr "%%(trailers:key=<value>) attendu"
 
@@ -18962,10 +19018,6 @@
 msgstr "valeur positive attendue '%s' dans %%(%s)"
 
 #, c-format
-msgid "unrecognized email option: %s"
-msgstr "option de courriel non reconnue : %s"
-
-#, c-format
 msgid "expected format: %%(align:<width>,<position>)"
 msgstr "format attendu : %%(align:<largeur>,<position>)"
 
@@ -18978,12 +19030,12 @@
 msgstr "largeur non reconnue : %s"
 
 #, c-format
-msgid "positive width expected with the %%(align) atom"
-msgstr "valeur positive attendue avec l'atome %%(align)"
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "argument %%(%s) non reconnu : %s"
 
 #, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) n'accepte pas d'argument"
+msgid "positive width expected with the %%(align) atom"
+msgstr "valeur positive attendue avec l'atome %%(align)"
 
 #, c-format
 msgid "malformed field name: %.*s"
@@ -20243,6 +20295,24 @@
 msgstr "git %s : échec du rafraîchissement de l'index"
 
 #, c-format
+msgid "'%s' is not a valid label"
+msgstr "'%s' n'est pas un label valide"
+
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "'%s' n'est pas un nom valide de référence"
+
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr ""
+"update-ref requiert un nom de référence totalement qualifié par ex. refs/"
+"heads/%s"
+
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "commande '%.*s' invalide"
+
+#, c-format
 msgid "%s does not accept arguments: '%s'"
 msgstr "%s n'accepte pas d'argument : '%s'"
 
@@ -21053,6 +21123,16 @@
 msgid "failed to lstat '%s'"
 msgstr "échec du lstat de '%s'"
 
+msgid "no remote configured to get bundle URIs from"
+msgstr "aucun distant configuré depuis lequel récupérer des URIs de colis"
+
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "le distant '%s' n'a pas d'URL configuré"
+
+msgid "could not get the bundle-uri list"
+msgstr "impossible d'avoir la liste de bundle-uris"
+
 msgid "test-tool cache-tree <options> (control|prime|update)"
 msgstr "test-tool cache-tree <options> (control|prime|update)"
 
@@ -21412,6 +21492,13 @@
 msgid "failed to push all needed submodules"
 msgstr "échec de la poussée de tous les sous-modules nécessaires"
 
+msgid "bundle-uri operation not supported by protocol"
+msgstr "opération bundle-uri non supportée par le protocole"
+
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr ""
+"impossible de récupérer la liste de bundle-uris annoncée par le serveur"
+
 msgid "too-short tree object"
 msgstr "objet arbre trop court"
 
@@ -22165,14 +22252,19 @@
 
 #, c-format
 msgid ""
-"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-"may speed it up, but you have to be careful not to forget to add\n"
-"new files yourself (see 'git help status')."
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
 msgstr ""
-"L'énumération des fichiers non suivis a duré %.2f secondes. 'status -uno'\n"
-"peut l'accélérer, mais vous devez alors faire attention à ne pas\n"
-"oublier d'ajouter les nouveaux fichiers par vous-même (voir 'git help "
-"status')."
+"L'énumération des fichiers non-suivis a pris %.2f secondes,\n"
+"mais les resultats ont été mis en cache, et les lancements suivants seront "
+"plus rapides."
+
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr "L'énumération des fichiers non-suivis a pris %.2f secondes."
+
+msgid "See 'git help status' for information on how to improve this."
+msgstr "Voir 'git help status' pour tout information pour améliorer ceci."
 
 #, c-format
 msgid "Untracked files not listed%s"
@@ -22323,275 +22415,6 @@
 msgid "Unable to determine absolute path of git directory"
 msgstr "Impossible de déterminer le chemin absolu du répertoire git"
 
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#, perl-format
-msgid "%12s %12s %s"
-msgstr "%12s %s12s %s"
-
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] "%d chemin touché\n"
-msgstr[1] "%d chemins touchés\n"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr ""
-"Si le patch s'applique proprement, la section éditée sera\n"
-"immédiatement marquée comme indexée."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr ""
-"Si le patch s'applique proprement, la section éditée sera\n"
-"immédiatement marquée comme remisée."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr ""
-"Si le patch s'applique proprement, la section éditée sera\n"
-"immédiatement marquée comme desindexée."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr ""
-"Si le patch s'applique proprement, la section éditée sera\n"
-"immédiatement marquée comme appliquée."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr ""
-"Si le patch s'applique proprement, la section éditée sera\n"
-"immédiatement marquée comme éliminée."
-
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr "impossible d'ouvrir le fichier d'édition de section en écriture : %s"
-
-#, perl-format
-msgid ""
-"---\n"
-"To remove '%s' lines, make them ' ' lines (context).\n"
-"To remove '%s' lines, delete them.\n"
-"Lines starting with %s will be removed.\n"
-msgstr ""
-"---\n"
-"Pour éliminer les lignes '%s', rendez-les ' ' (contexte).\n"
-"Pour éliminer les lignes '%s', effacez-les.\n"
-"Les lignes commençant par %s seront éliminées.\n"
-
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr "échec de l'ouverture du fichier d'édition de section en lecture : %s"
-
-msgid ""
-"y - stage this hunk\n"
-"n - do not stage this hunk\n"
-"q - quit; do not stage this hunk or any of the remaining ones\n"
-"a - stage this hunk and all later hunks in the file\n"
-"d - do not stage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - indexer cette section\n"
-"n - ne pas indexer cette section\n"
-"q - quitter ; ne pas indexer cette section ni les autres restantes\n"
-"a - indexer cette section et toutes les suivantes de ce fichier\n"
-"d - ne pas indexer cette section ni les suivantes de ce fichier"
-
-msgid ""
-"y - stash this hunk\n"
-"n - do not stash this hunk\n"
-"q - quit; do not stash this hunk or any of the remaining ones\n"
-"a - stash this hunk and all later hunks in the file\n"
-"d - do not stash this hunk or any of the later hunks in the file"
-msgstr ""
-"y - remiser cette section\n"
-"n - ne pas remiser cette section\n"
-"q - quitter ; ne pas remiser cette section ni les autres restantes\n"
-"a - remiser cette section et toutes les suivantes de ce fichier\n"
-"d - ne pas remiser cette section ni les suivantes de ce fichier"
-
-msgid ""
-"y - unstage this hunk\n"
-"n - do not unstage this hunk\n"
-"q - quit; do not unstage this hunk or any of the remaining ones\n"
-"a - unstage this hunk and all later hunks in the file\n"
-"d - do not unstage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - désindexer cette section\n"
-"n - ne pas désindexer cette section\n"
-"q - quitter ; ne pas désindexer cette section ni les autres restantes\n"
-"a - désindexer cette section et toutes les suivantes de ce fichier\n"
-"d - ne pas désindexer cette section ni les suivantes de ce fichier"
-
-msgid ""
-"y - apply this hunk to index\n"
-"n - do not apply this hunk to index\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - appliquer cette section\n"
-"n - ne pas appliquer cette section\n"
-"q - quitter ; ne pas appliquer cette section ni les autres restantes\n"
-"a - appliquer cette section et toutes les suivantes de ce fichier\n"
-"d - ne pas appliquer cette section ni les suivantes de ce fichier"
-
-msgid ""
-"y - discard this hunk from worktree\n"
-"n - do not discard this hunk from worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - supprimer cette section\n"
-"n - ne pas supprimer cette section\n"
-"q - quitter ; ne pas supprimer cette section ni les autres restantes\n"
-"a - supprimer cette section et toutes les suivantes de ce fichier\n"
-"d - ne pas supprimer cette section ni les suivantes de ce fichier"
-
-msgid ""
-"y - discard this hunk from index and worktree\n"
-"n - do not discard this hunk from index and worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - éliminer cette section de l'index et de l'arbre de travail\n"
-"n - ne pas éliminer cette section\n"
-"q - quitter ; ne pas éliminer cette section ni les autres restantes\n"
-"a - éliminer cette section et toutes les suivantes de ce fichier\n"
-"d - ne pas éliminer cette section ni les suivantes de ce fichier"
-
-msgid ""
-"y - apply this hunk to index and worktree\n"
-"n - do not apply this hunk to index and worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - appliquer cette section à l'index et à l'arbre de travail\n"
-"n - ne pas appliquer cette section\n"
-"q - quitter ; ne pas appliquer cette section ni les autres restantes\n"
-"a - appliquer cette section et toutes les suivantes de ce fichier\n"
-"d - ne pas appliquer cette section ni les suivantes de ce fichier"
-
-msgid ""
-"y - apply this hunk to worktree\n"
-"n - do not apply this hunk to worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - appliquer cette section à l'arbre de travail\n"
-"n - ne pas appliquer cette section\n"
-"q - quitter ; ne pas appliquer cette section ni les autres restantes\n"
-"a - appliquer cette section et toutes les suivantes de ce fichier\n"
-"d - ne pas appliquer cette section ni les suivantes de ce fichier"
-
-msgid ""
-"g - select a hunk to go to\n"
-"/ - search for a hunk matching the given regex\n"
-"j - leave this hunk undecided, see next undecided hunk\n"
-"J - leave this hunk undecided, see next hunk\n"
-"k - leave this hunk undecided, see previous undecided hunk\n"
-"K - leave this hunk undecided, see previous hunk\n"
-"s - split the current hunk into smaller hunks\n"
-"e - manually edit the current hunk\n"
-"? - print help\n"
-msgstr ""
-"g - selectionner une section et s'y rendre\n"
-"/ - rechercher une section correspondant à une regex donnée\n"
-"j - laisser cette section non décidée et aller à la suivante non-décidée\n"
-"J - laisser cette section non décidée et aller à la suivante\n"
-"k - laisser cette section non décidée et aller à la précédente non-décidée\n"
-"K - laisser cette section non décidée et aller à la précédente\n"
-"s - découper la section en sections plus petites\n"
-"e - éditer manuellement la section actuelle\n"
-"? - afficher l'aide\n"
-
-msgid "The selected hunks do not apply to the index!\n"
-msgstr "Les sections sélectionnées ne s'applique pas à l'index !\n"
-
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "fichier non-fusionné ignoré : %s\n"
-
-msgid "No other hunks to goto\n"
-msgstr "Aucune autre section à atteindre\n"
-
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "Nombre invalide : '%s'\n"
-
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "Désolé, %d seule section disponible.\n"
-msgstr[1] "Désolé, Seulement %d sections disponibles.\n"
-
-msgid "No other hunks to search\n"
-msgstr "Aucune autre section à rechercher\n"
-
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "Regex de recherche malformée %s : %s\n"
-
-msgid "No hunk matches the given pattern\n"
-msgstr "Aucune section ne correspond au motif donné\n"
-
-msgid "No previous hunk\n"
-msgstr "Pas de section précédente\n"
-
-msgid "No next hunk\n"
-msgstr "Pas de section suivante\n"
-
-msgid "Sorry, cannot split this hunk\n"
-msgstr "Désolé, impossible de découper cette section\n"
-
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "Découpée en %d section.\n"
-msgstr[1] "Découpée en %d sections.\n"
-
-msgid "Sorry, cannot edit this hunk\n"
-msgstr "Désolé, impossible d'éditer cette section\n"
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-msgid ""
-"status        - show paths with changes\n"
-"update        - add working tree state to the staged set of changes\n"
-"revert        - revert staged set of changes back to the HEAD version\n"
-"patch         - pick hunks and update selectively\n"
-"diff          - view diff between HEAD and index\n"
-"add untracked - add contents of untracked files to the staged set of "
-"changes\n"
-msgstr ""
-"status        - montrer les chemins modifiés\n"
-"update        - ajouter l'état de l'arbre de travail aux modifications à "
-"indexer\n"
-"revert        - faire revenir les modifications à indexer à la version HEAD\n"
-"patch         - sélectionner les sections et mettre à jour sélectivement\n"
-"diff          - visualiser les diff entre HEAD et l'index\n"
-"add untracked - ajouter les fichiers non-suivis aux modifications à indexer\n"
-
-msgid "missing --"
-msgstr "-- manquant"
-
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "mode de --patch inconnu : %s"
-
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "argument invalide %s, -- attendu"
-
 msgid "local zone differs from GMT by a non-minute interval\n"
 msgstr ""
 "la zone locale diffère du GMT par un intervalle supérieur à une minute\n"
@@ -22918,232 +22741,3 @@
 #, perl-format
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Souhaitez-vous réellement envoyer %s ?[y|N] : "
-
-#, c-format
-#~ msgid "unable to normalize object directory: %s"
-#~ msgstr "impossible de normaliser le répertoire d'objet : %s"
-
-#~ msgid "reset the bisection state"
-#~ msgstr "réinitialiser l'état de la bissection"
-
-#~ msgid "check whether bad or good terms exist"
-#~ msgstr "vérifier si les termes bons ou mauvais existent"
-
-#~ msgid "print out the bisect terms"
-#~ msgstr "afficher les termes de bissection"
-
-#~ msgid "start the bisect session"
-#~ msgstr "démarrer une session de bissection"
-
-#~ msgid "find the next bisection commit"
-#~ msgstr "trouver le prochain commit de bissection"
-
-#~ msgid "mark the state of ref (or refs)"
-#~ msgstr "marquer l'état d'une références (ou plusieurs)"
-
-#~ msgid "list the bisection steps so far"
-#~ msgstr "lister les étapes de bissection jusqu'ici"
-
-#~ msgid "replay the bisection process from the given file"
-#~ msgstr "rejouer le processus de bissection depuis le fichier fourni"
-
-#~ msgid "skip some commits for checkout"
-#~ msgstr "sauter certains commits pour l'extraction"
-
-#~ msgid "visualize the bisection"
-#~ msgstr "visualiser la bissection"
-
-#~ msgid "use <cmd>... to automatically bisect"
-#~ msgstr "utiliser <cmd>... pour bissecter automatiquement"
-
-#~ msgid "no log for BISECT_WRITE"
-#~ msgstr "pas de journal pour BISECT_WRITE"
-
-#~ msgid "Couldn't look up commit object for HEAD"
-#~ msgstr "Impossible de rechercher l'objet commit pour HEAD"
-
-#~ msgid "git bundle create [<options>] <file> <git-rev-list args>"
-#~ msgstr "git bundle create [<options>] <fichier> <args git-rev-list>"
-
-#, c-format
-#~ msgid "options '%s' and '%s %s' cannot be used together"
-#~ msgstr "les options '%s' et '%s %s' ne peuvent pas être utilisées ensemble"
-
-#~ msgid "git commit [<options>] [--] <pathspec>..."
-#~ msgstr "git commit [<options>] [--] <spécification-de-chemin>..."
-
-#~ msgid "git fsck [<options>] [<object>...]"
-#~ msgstr "git fsck [<options>] [<objet>...]"
-
-#~ msgid "git fsmonitor--daemon stop"
-#~ msgstr "git fsmonitor--daemon stop"
-
-#~ msgid "git fsmonitor--daemon status"
-#~ msgstr "git fsmonitor--daemon status"
-
-#~ msgid "failed to run 'git config'"
-#~ msgstr "échec du lancement de 'git config'"
-
-#, c-format
-#~ msgid "could not get 'onto': '%s'"
-#~ msgstr "impossible d'accéder 'onto' : '%s'"
-
-#~ msgid "Could not resolve HEAD to a revision"
-#~ msgstr "Impossible de résoudre le commit HEAD vers un révision"
-
-#, c-format
-#~ msgid "missing required file: %s"
-#~ msgstr "fichier nécessaire manquant : %s"
-
-#~ msgid "git revert [<options>] <commit-ish>..."
-#~ msgstr "git revert [<options>] <commit ou apparenté>..."
-
-#~ msgid "git revert <subcommand>"
-#~ msgstr "git revert <sous-commande>"
-
-#~ msgid "git cherry-pick [<options>] <commit-ish>..."
-#~ msgstr "git cherry-pick [<options>] <commit ou apparenté>..."
-
-#~ msgid "git cherry-pick <subcommand>"
-#~ msgstr "git cherry-pick <sous-commande>"
-
-#~ msgid "git rm [<options>] [--] <file>..."
-#~ msgstr "git rm [<options>] [--] <fichier>..."
-
-#~ msgid "using --group=trailer with stdin is not supported"
-#~ msgstr "l'utilisation de --group=trailer avec stdin n'est pas supportée"
-
-#~ msgid "git stash show [<options>] [<stash>]"
-#~ msgstr "git stash show [<options>] [<remise>]"
-
-#~ msgid "git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"
-#~ msgstr "git stash ( pop | apply ) [--index] [-q|--quiet] [<remise>]"
-
-#~ msgid ""
-#~ "git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-#~ "          [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
-#~ "          [--] [<pathspec>...]]"
-#~ msgstr ""
-#~ "git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-#~ "          [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
-#~ "          [--] [<spécificateur-de-chemin>...]]"
-
-#~ msgid ""
-#~ "git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-#~ "               [-u|--include-untracked] [-a|--all] [<message>]"
-#~ msgstr ""
-#~ "git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-#~ "               [-u|--include-untracked] [-a|--all] [<message>]"
-
-#~ msgid "path into the working tree"
-#~ msgstr "chemin dans la copie de travail"
-
-#~ msgid "recurse into submodules"
-#~ msgstr "parcourir récursivement les sous-modules"
-
-#~ msgid "check if it is safe to write to the .gitmodules file"
-#~ msgstr "vérifier si écrire dans le fichier .gitmodules est sur"
-
-#~ msgid "unset the config in the .gitmodules file"
-#~ msgstr "désactiver la configuration dans le fichier .gitmodules"
-
-#~ msgid "git submodule--helper config <name> [<value>]"
-#~ msgstr "git submodule--helper config name [<valeur>]"
-
-#~ msgid "git submodule--helper config --unset <name>"
-#~ msgstr "git submodule--helper config --unset <nom>"
-
-#, c-format
-#~ msgid "'%s' is not a valid submodule--helper subcommand"
-#~ msgstr "'%s' n'est pas une sous-commande valide de submodule--helper"
-
-#~ msgid "git upload-pack [<options>] <dir>"
-#~ msgstr "git upload-pack [<options>] <répertoire>"
-
-#~ msgid "git worktree add [<options>] <path> [<commit-ish>]"
-#~ msgstr "git worktree add [<options>] <chemin> [<commit>]"
-
-#~ msgid "git worktree lock [<options>] <path>"
-#~ msgstr "git worktree lock [<options>] <chemin>"
-
-#~ msgid "(stats|all)"
-#~ msgstr "(stats|all)"
-
-#~ msgid "git maintenance register"
-#~ msgstr "git maintenance register"
-
-#~ msgid "git maintenance unregister"
-#~ msgstr "git maintenance unregister"
-
-#~ msgid "git maintenance stop"
-#~ msgstr "git maintenance stop"
-
-#, c-format
-#~ msgid "could not parse colored hunk header '%.*s'"
-#~ msgstr "impossible d'analyser l'entête coloré de section '%.*s'"
-
-#, c-format
-#~ msgid "Unknown subcommand: %s"
-#~ msgstr "Sous-commande inconnue : %s"
-
-#~ msgid "checked out in another worktree"
-#~ msgstr "extrait dans un autre arbre de travail"
-
-#~ msgid "failed to open stdin of 'crontab'"
-#~ msgstr "échec à l'ouverture de stdin de 'crontab'"
-
-#, c-format
-#~ msgid "invalid subcommand: %s"
-#~ msgstr "sous-commande invalide : %s"
-
-#~ msgid "single arg format must be symmetric range"
-#~ msgstr "un format d'argument unique doit être une plage symétrique"
-
-#~ msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-#~ msgstr "git submodule--helper list [--prefix=<chemin>] [<chemin>...]"
-
-#, c-format
-#~ msgid "failed to get the default remote for submodule '%s'"
-#~ msgstr ""
-#~ "échec d'obtention du dépôt distant par défaut pour le sous-module '%s'"
-
-#, c-format
-#~ msgid "Invalid update mode '%s' for submodule path '%s'"
-#~ msgstr ""
-#~ "Mode de mise à jour '%s' invalide pour le chemin de sous-module '%s'"
-
-#~ msgid "path into the working tree, across nested submodule boundaries"
-#~ msgstr ""
-#~ "chemin dans la copie de travail, traversant les frontières de sous-modules"
-
-#~ msgid "rebase, merge, checkout or none"
-#~ msgstr "valeurs possibles : rebase, merge, checkout ou none"
-
-#~ msgid "bad value for update parameter"
-#~ msgstr "valeur invalide pour la mise à jour du paramètre"
-
-#~ msgid "Show three-way merge without touching index"
-#~ msgstr "Afficher la fusion à trois points sans modifier l'index"
-
-#, c-format
-#~ msgid "could not create directory for '%s'"
-#~ msgstr "impossible de créer le répertoire pour '%s'"
-
-#, c-format
-#~ msgid "Couldn't start hook '%s'\n"
-#~ msgstr "impossible de démarrer le crochet '%s'\n"
-
-#, c-format
-#~ msgid ""
-#~ "Note: %s not up to date and in way of checking out conflicted version; "
-#~ "old copy renamed to %s"
-#~ msgstr ""
-#~ "Note :%s pas à jour et au milieu de l'extraction d'une version "
-#~ "conflictuelle ; la vielle copie a été renommée en %s"
-
-#, c-format
-#~ msgid "%s: fast-forward"
-#~ msgstr "%s : avance rapide"
-
-#~ msgid "--preserve-merges was replaced by --rebase-merges"
-#~ msgstr "--preserve-merges a été remplacé par --rebase-merges"
diff --git a/po/id.po b/po/id.po
index 41465ee..e468b6d 100644
--- a/po/id.po
+++ b/po/id.po
@@ -7,8 +7,8 @@
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-11-30 11:05+0700\n"
-"PO-Revision-Date: 2022-11-30 20:45+0700\n"
+"POT-Creation-Date: 2023-03-02 15:18+0700\n"
+"PO-Revision-Date: 2023-03-02 17:52+0700\n"
 "Last-Translator: Bagas Sanjaya <bagasdotme@gmail.com>\n"
 "Language-Team: Indonesian\n"
 "Language: id\n"
@@ -26,19 +26,19 @@
 msgid "could not read index"
 msgstr "tidak dapat membaca indeks"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "binary"
 msgstr "biner"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "nothing"
 msgstr "tidak ada"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "unchanged"
 msgstr "tak berubah"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Update"
 msgstr "Perbarui"
 
@@ -51,15 +51,15 @@
 msgid "could not write index"
 msgstr "tidak dapat menulis indeks"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "%d jalur diperbarui\n"
 msgstr[1] "%d jalur diperbarui\n"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "catatan: %s sekarang tak terlacak.\n"
 
@@ -68,7 +68,7 @@
 msgid "make_cache_entry failed for path '%s'"
 msgstr "make_cache_entry gagal untuk jalur '%s'"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Revert"
 msgstr "Kembalikan"
 
@@ -76,24 +76,24 @@
 msgid "Could not parse HEAD^{tree}"
 msgstr "Tidak dapat menguraikan HEAD^{tree}"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "%d jalur dikembalikan\n"
 msgstr[1] "%d jalur dikembalikan\n"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 #, c-format
 msgid "No untracked files.\n"
 msgstr "Tidak ada berkas tak terlacak.\n"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Add untracked"
 msgstr "Tambahkan tak terlacak"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "%d jalur ditambahkan\n"
@@ -104,21 +104,21 @@
 msgid "ignoring unmerged: %s"
 msgstr "mengabaikan tak tergabung: %s"
 
-#: add-interactive.c add-patch.c git-add--interactive.perl
+#: add-interactive.c add-patch.c
 #, c-format
 msgid "Only binary files changed.\n"
 msgstr "Hanya berkas biner yang berubah.\n"
 
-#: add-interactive.c add-patch.c git-add--interactive.perl
+#: add-interactive.c add-patch.c
 #, c-format
 msgid "No changes.\n"
 msgstr "Tidak ada perubahan.\n"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Patch update"
 msgstr "Pembaruan tambalan"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Review diff"
 msgstr "Tinjau diff"
 
@@ -186,25 +186,25 @@
 msgid "(empty) select nothing"
 msgstr "(empty) tidak pilih apapun"
 
-#: add-interactive.c builtin/clean.c git-add--interactive.perl
+#: add-interactive.c builtin/clean.c
 msgid "*** Commands ***"
 msgstr "*** Perintah ***"
 
-#: add-interactive.c builtin/clean.c git-add--interactive.perl
+#: add-interactive.c builtin/clean.c
 msgid "What now"
 msgstr "Apa sekarang"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "staged"
 msgstr "tergelar"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "unstaged"
 msgstr "tak tergelar"
 
 #: add-interactive.c apply.c builtin/am.c builtin/bugreport.c builtin/clone.c
-#: builtin/diagnose.c builtin/fetch.c builtin/merge.c builtin/pull.c
-#: builtin/submodule--helper.c git-add--interactive.perl
+#: builtin/diagnose.c builtin/fetch.c builtin/hook.c builtin/merge.c
+#: builtin/pull.c builtin/submodule--helper.c
 msgid "path"
 msgstr "jalur"
 
@@ -212,28 +212,28 @@
 msgid "could not refresh index"
 msgstr "tidak dapat menyegarkan indeks"
 
-#: add-interactive.c builtin/clean.c git-add--interactive.perl
+#: add-interactive.c builtin/clean.c
 #, c-format
 msgid "Bye.\n"
 msgstr "Sampai jumpa.\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "Gelar perubahan mode [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "Gelar penghapusan [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "Gelar penambahan [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Gelar bingkah ini [y,n,q,a,d%s,?]? "
 
@@ -259,23 +259,23 @@
 "a - gelar bingkah ini dan semua bingkah selanjutnya dalam berkas\n"
 "d - jangan gelar bingkah ini atau bingkah selanjutnya dalam berkas\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "Stase perubahan mode [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "Stase penghapusan [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "Stase penambahan [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "Stase bingkah ini [y,n,q,a,d%s,?]? "
 
@@ -301,23 +301,23 @@
 "a - stase bingkah ini dan semua bingkah selanjutnya dalam berkas\n"
 "d - jangan stase bingkah ini atau bingkah selanjutnya dalam berkas\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "Batal gelar perubahan mode [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "Batal gelar penghapusan [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "Batal gelar penambahan [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Batal gelar bingkah ini [y,n,q,a,d%s,?]? "
 
@@ -343,23 +343,23 @@
 "a - batal gelar bingkah ini dan semua bingkah selanjutnya dalam berkas\n"
 "d - jangan batal gelar bingkah ini atau bingkah selanjutnya dalam berkas\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr "Terapkan perubahan mode ke indeks [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "Terapkan penghapusan ke indeks [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "Terapkan penambahan ke indeks [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "Terapkan bingkah ini ke indeks [y,n,q,a,d%s,?]? "
 
@@ -385,23 +385,23 @@
 "a - terapkan bingkah ini dan semua bingkah selanjutnya dalam berkas\n"
 "d - jangan terapkan bingkah ini atau bingkah selanjutnya dalam berkas\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr "Buang perubahan mode dari pohon kerja [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "Buang penghapusan dari pohon kerja [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "Buang penambahan dari pohon kerja [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
 msgstr "Buang bingkah ini dari pohon kerja [y,n,q,a,d%s,?]? "
 
@@ -427,23 +427,23 @@
 "a - buang hunk ini dan semua bingkah selanjutnya dalam berkas\n"
 "d - jangan buang hunk ini atau bingkah selanjutnya dalam berkas\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Buang perubahan mode dari indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Buang penghapusan dari indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Buang penambahan dari indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Buang bingkah ini dari indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
@@ -461,23 +461,23 @@
 "a - buang bingkah ini dan semua bingkah selanjutnya dalam berkas\n"
 "d - jangan buang bingkah ini atau bingkah selanjutnya dalam berkas\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Terapkan perubahan mode pada indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Terapkan penghapusan pada indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Terapkan penambahan pada indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Terapkan bingkah ini pada indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
@@ -495,23 +495,23 @@
 "a - terapkan bingkah ini dan semua bingkah selanjutnya dalam berkas\n"
 "d - jangan terapkan bingkah ini atau bingkah selanjutnya dalam berkas\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
 msgstr "Terapkan perubahan mode pada pohon kerja [y,n,q,a,d%s,?]?"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
 msgstr "Terapkan penghapusan pada pohon kerja [y,n,q,a,d%s,?]?"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
 msgstr "Terapkan penambahan pada pohon kerja [y,n,q,a,d%s,?]?"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
 msgstr "Terapkan bingkah ini pada pohon kerja [y,n,q,a,d%s,?]?"
 
@@ -581,7 +581,7 @@
 "tidak berakhir dengan:\n"
 "%.*s"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "Manual hunk edit mode -- see bottom for a quick guide.\n"
 msgstr "Mode sunting bingkah manual -- lihat dibawah untuk panduan cepat.\n"
 
@@ -598,9 +598,7 @@
 "Untuk menghapus baris '%c', hapuslahnya.\n"
 "Baris yang diawali dengan %c akan dihapus.\n"
 
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
 "edit again.  If all lines of the hunk are removed, then the edit is\n"
@@ -618,21 +616,13 @@
 msgid "'git apply --cached' failed"
 msgstr "'git apply --cached' gagal"
 
-#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr ""
@@ -643,11 +633,11 @@
 msgid "The selected hunks do not apply to the index!"
 msgstr "Bingkah yang dipilih tidak diterapkan pada indeks!"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "Apply them to the worktree anyway? "
 msgstr "Tetap terapkan pada pohon kerja? "
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "Nothing was applied.\n"
 msgstr "Tidak ada yang diterapkan.\n"
 
@@ -685,11 +675,11 @@
 msgid "No other hunks to goto"
 msgstr "Tidak ada bingkah lainnya untuk dikunjungi"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "go to which hunk (<ret> to see more)? "
 msgstr "pergi ke bingkah yang mana (<ret> untuk lihat lebih)? "
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "go to which hunk? "
 msgstr "pergi ke bingkah yang mana?"
 
@@ -709,7 +699,7 @@
 msgid "No other hunks to search"
 msgstr "Tidak ada bingkah lainnya untuk dicari"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "search for regex? "
 msgstr "cari untuk regex? "
 
@@ -1308,7 +1298,7 @@
 msgid "unable to add cache entry for %s"
 msgstr "tidak dapat menambahkan entri tembolok untuk %s"
 
-#: apply.c builtin/bisect--helper.c builtin/gc.c
+#: apply.c builtin/bisect.c builtin/gc.c
 #, c-format
 msgid "failed to write to '%s'"
 msgstr "gagal menulis ke '%s'"
@@ -1646,7 +1636,7 @@
 msgid "archive format"
 msgstr "format arsip"
 
-#: archive.c builtin/log.c
+#: archive.c builtin/log.c parse-options.h
 msgid "prefix"
 msgstr "prefiks"
 
@@ -1680,6 +1670,15 @@
 msgid "report archived files on stderr"
 msgstr "laporkan berkas terarsip ke error standar"
 
+#: archive.c builtin/clone.c builtin/fetch.c builtin/pack-objects.c
+#: builtin/pull.c
+msgid "time"
+msgstr "waktu"
+
+#: archive.c
+msgid "set modification time of archive entries"
+msgstr "setel waktu modifikasi entri arsip"
+
 #: archive.c
 msgid "set compression level"
 msgstr "setel level kompresi"
@@ -1736,6 +1735,15 @@
 msgstr "%.*s bukan sebuah nama atribut valid"
 
 #: attr.c
+msgid "unable to add additional attribute"
+msgstr "Tidak dapat menambahkan atribut tambahan"
+
+#: attr.c
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "mengabaikan baris atribut ke-%d yang terlalu panjang"
+
+#: attr.c
 #, c-format
 msgid "%s not allowed: %s:%d"
 msgstr "%s tidak diperbolehkan: %s:%d"
@@ -1748,6 +1756,21 @@
 "Pola negatif diabaikan di atribut git\n"
 "Gunakan '\\!' untuk tanda seru awal literal."
 
+#: attr.c
+#, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "tidak dapat menulis berkas gitattributes '%s'"
+
+#: attr.c
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "mengabaikan berkas gitattributes yang terlalu besar '%s'"
+
+#: attr.c
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "mengabaikan blob gitattributes '%s' yang terlalu besar"
+
 #: bisect.c
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
@@ -1881,8 +1904,8 @@
 "--reverse dan --first-parent bersama-sama butuh komit terbaru yang disebutkan"
 
 #: blame.c builtin/commit.c builtin/log.c builtin/merge.c
-#: builtin/pack-objects.c builtin/shortlog.c bundle.c midx.c pack-bitmap.c
-#: ref-filter.c remote.c sequencer.c submodule.c
+#: builtin/pack-objects.c builtin/shortlog.c midx.c pack-bitmap.c ref-filter.c
+#: remote.c sequencer.c submodule.c
 msgid "revision walk setup failed"
 msgstr "persiapan jalan revisi gagal"
 
@@ -2072,11 +2095,11 @@
 #: branch.c
 #, c-format
 msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
 msgstr ""
-"Anda dapat mencoba memperbarui submodul dengan 'git checkout %s && git "
-"submodule update --init'"
+"Anda dapat mencoba memperbarui submodul dengan 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
 
 #: branch.c
 #, c-format
@@ -2120,6 +2143,14 @@
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Perubahan tak tergelar setelah menyegarkan indeks:"
 
+#: builtin/add.c
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"setelan add.interactive.useBuiltin sudah dihapus!\n"
+"Selengkapnya lihat entrinya di 'git help config'."
+
 #: builtin/add.c builtin/rev-parse.c
 msgid "Could not read the index"
 msgstr "Tidak dapat membaca indeks"
@@ -2590,7 +2621,7 @@
 "Sepertinya Anda telah memindahkan HEAD sejak kegagalan 'am' terakhir.\n"
 "Tidak memutar ulang ke ORIG_HEAD"
 
-#: builtin/am.c builtin/bisect--helper.c worktree.c
+#: builtin/am.c builtin/bisect.c worktree.c
 #, c-format
 msgid "failed to read '%s'"
 msgstr "gagal membaca '%s'"
@@ -2613,6 +2644,10 @@
 msgstr "jalankan secara interaktif"
 
 #: builtin/am.c
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "lewati kail pre-applypatch dan applypatch-msg"
+
+#: builtin/am.c
 msgid "historical option -- no-op"
 msgstr "opsi bersejarah -- no-op"
 
@@ -2803,112 +2838,106 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: sebuah bilasan diharapkan"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [<komit>]"
-
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<istilah> --term-{old,"
-"good}=<istilah>] [--no-checkout] [--first-parent] [<jelek> [<bagus>...]] "
-"[--] [<jalur>...]"
+"git bisect start [--term-{new,bad}=<istilah> --term-{old, good}=<istilah>] "
+"[--no-checkout] [--first-parent] [<jelek> [<bagus>...]] [--] [<jalur>...]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (bad|new) [<revisi>]"
+#: builtin/bisect.c
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<revisi>...]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (good|old) [<revisi>...]"
+#: builtin/bisect.c
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<revisi>|<rentang>)...]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay <nama berkas>"
+#: builtin/bisect.c
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<komit>]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(<revisi>|<rentang>)...]"
+#: builtin/bisect.c
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <berkas log>"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run <perintah>..."
+#: builtin/bisect.c
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run <perintah>..."
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
 msgstr "tidak dapat membuka berkas '%s' dalam mode '%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "could not write to file '%s'"
 msgstr "tidak dapat menulis ke berkas '%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' for reading"
 msgstr "tidak dapat membuka berkas '%s' untuk dibaca"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' is not a valid term"
 msgstr "'%s' bukan istilah yang valid"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "can't use the builtin command '%s' as a term"
 msgstr "tidak dapat menggunakan perintah bawaan '%s' sebagai istilah"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "can't change the meaning of the term '%s'"
 msgstr "tidak dapat mengubah makna istilah '%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "please use two different terms"
 msgstr "mohon gunakan dua istilah yang berbeda"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "We are not bisecting.\n"
 msgstr "Kami tidak sedang membagi dua.\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' is not a valid commit"
 msgstr "'%s' bukan sebuah komit yang valid"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "could not check out original HEAD '%s'. Try 'git bisect reset <commit>'."
 msgstr ""
 "tidak dapat men-checkout HEAD asli '%s'. Coba 'git bisect reset <komit>'."
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Bad bisect_write argument: %s"
 msgstr "argument bisect_write jelek: %s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "couldn't get the oid of the rev '%s'"
 msgstr "tidak dapat mendapatkan oid revisi '%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "couldn't open the file '%s'"
 msgstr "tidak dapat membuka berkas '%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Invalid command: you're currently in a %s/%s bisect"
 msgstr "Perintah tidak valid: sekarang Anda berada dalam pembagian dua %s/%s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "You need to give me at least one %s and %s revision.\n"
@@ -2917,7 +2946,7 @@
 "Anda perlu berikan saya setidaknya satu revisi %s dan %s.\n"
 "Untuk itu Anda dapat menggunakan \"git bisect %s\" dan \"git bisect %s\"."
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "You need to start by \"git bisect start\".\n"
@@ -2928,7 +2957,7 @@
 "Lalu Anda perlu berikan saya setidaknya satu revisi %s dan %s.\n"
 "Untuk itu Anda dapat menggunakan \"git bisect %s\" dan \"git bisect %s\"."
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "bisecting only with a %s commit"
 msgstr "membagi dua hanya dengan sebuah komit %s"
@@ -2937,30 +2966,30 @@
 #. translation. The program will only accept English input
 #. at this point.
 #.
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "Are you sure [Y/n]? "
 msgstr "Anda yakin [Y/n]?"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "status: waiting for both good and bad commits\n"
 msgstr "status: menunggu komit bagus dan jelek\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "status: waiting for bad commit, %d good commit known\n"
 msgid_plural "status: waiting for bad commit, %d good commits known\n"
 msgstr[0] "status: menunggu komit jelek, %d komit bagus diketahui\n"
 msgstr[1] "status: menunggu komit jelek, %d komit bagus diketahui\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "status: waiting for good commit(s), bad commit known\n"
 msgstr "status: menunggu komit bagus, komit jelek diketahui\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "no terms defined"
 msgstr "tidak ada istilah yang didefinisikan"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "Your current terms are %s for the old state\n"
@@ -2969,7 +2998,7 @@
 "Istilah Anda saat ini adalah %s untuk keadaan lama\n"
 "dan %s untuk keadaan baru.\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "invalid argument %s for 'git bisect terms'.\n"
@@ -2978,52 +3007,48 @@
 "argumen %s tidak valid untuk 'git bisect terms'.\n"
 "Opsi yang didukung adalah: --term-good|--term-old dan --term-bad|--term-new."
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "revision walk setup failed\n"
 msgstr "setup jalan revisi gagal\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "tidak dapat membuka '%s' untuk menambahkan"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "'' is not a valid term"
 msgstr "'' bukan istilah yang valid"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "unrecognized option: '%s'"
 msgstr "opsi tidak dikenal: '%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' does not appear to be a valid revision"
 msgstr "'%s' sepertinya bukan revisi valid"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bad HEAD - I need a HEAD"
 msgstr "HEAD jelek - saya butuh HEAD"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
 msgstr "gagal men-checkout '%s'. Coba 'git bisect start <cabang valid>'."
 
-#: builtin/bisect--helper.c
-msgid "won't bisect on cg-seek'ed tree"
-msgstr "tidak akan membagi dua pada pohon yang di-cg-seek"
-
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bad HEAD - strange symbolic ref"
 msgstr "HEAD jelek - referensi simbolik aneh"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "invalid ref: '%s'"
 msgstr "referensi tidak valid: '%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "You need to start by \"git bisect start\"\n"
 msgstr "Anda perlu memulai dengan \"git bisect start\"\n"
 
@@ -3031,115 +3056,122 @@
 #. translation. The program will only accept English input
 #. at this point.
 #.
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "Do you want me to do it for you [Y/n]? "
 msgstr "Anda ingin saya melakukannya untuk Anda [Y/n]"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "Please call `--bisect-state` with at least one argument"
 msgstr "Mohon panggil `--bisect-state` dengan setidaknya satu argumen"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'git bisect %s' can take only one argument."
 msgstr "'git bisect %s' hanya dapat mengambil satu argumen."
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Bad rev input: %s"
 msgstr "Masukan revisi jelek: %s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Bad rev input (not a commit): %s"
 msgstr "Masukan revisi jelek (bukan sebuah komit): %s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "We are not bisecting."
 msgstr "Kami tidak sedang membagi dua."
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s'?? what are you talking about?"
 msgstr "'%s'?? Anda bilang tentang apa?"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot read file '%s' for replaying"
 msgstr "tidak dapat membuka berkas '%s' untuk memainkan ulang"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "running %s\n"
 msgstr "menjalankan %s\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bisect run failed: no command provided."
 msgstr "bisect run gagal: tidak ada perintah yang diberikan"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
-msgid "unable to verify '%s' on good revision"
-msgstr "tidak dapat memverifikasi '%s' pada revisi bagus"
+msgid "unable to verify %s on good revision"
+msgstr "tidak dapat memverifikasi %s pada revisi bagus"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "bogus exit code %d for good revision"
 msgstr "kode keluar gadungan %d untuk revisi bagu"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
-msgstr "bisect run gagal: kode keluar %d dari '%s' < 0 atau >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
+msgstr "bisect run gagal: kode keluar %d dari %s < 0 atau >= 128"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' for writing"
 msgstr "tidak dapat membuka berkas '%s' untuk ditulis"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bisect run cannot continue any more"
 msgstr "bisect run tidak dapat dilanjutkan lagi"
 
-#: builtin/bisect--helper.c
-#, c-format
+#: builtin/bisect.c
 msgid "bisect run success"
 msgstr "bisect run sukses"
 
-#: builtin/bisect--helper.c
-#, c-format
+#: builtin/bisect.c
 msgid "bisect found first bad commit"
 msgstr "pembagian dua menemukan komit jelek pertama"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
-msgstr ""
-"bisect run gagal: 'git bisect--helper --bisect-state %s' keluar dengan kode "
-"keluar %d"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
+msgstr "bisect run gagal: 'git bisect %s' keluar dengan kode keluar %d"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "--bisect-reset butuh baik tanpa argumen atau sebuah komit"
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "'%s' perlu baik tanpa argumen atau sebuah komit"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "--bisect-terms butuh 0 atau 1 argumen"
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "%s perlu sebuah argumen"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-next requires 0 arguments"
-msgstr "--bisect-next butuh 0 argumen"
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "'%s' butuh tanpa argumen"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-log requires 0 arguments"
-msgstr "--bisect-log butuh 0 argumen"
-
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "no logfile given"
 msgstr "tidak ada berkas log yang diberikan"
 
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "'%s' gagal: tidak ada perintah yang diberikan."
+
+#: builtin/bisect.c
+msgid "need a command"
+msgstr "butuh sebuah perintah"
+
+#: builtin/bisect.c builtin/cat-file.c
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "perintah tidak dikenal: '%s'"
+
 #: builtin/blame.c
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 msgstr "git blame [<opsi>] [<opsi revisi>] [<revisi>] [--] <berkas>"
@@ -3860,6 +3892,10 @@
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
 msgstr "git bundle unbundle [--progress] <berkas> [<nama referensi>...]"
 
+#: builtin/bundle.c
+msgid "need a <file> argument"
+msgstr "butuh sebuah argumen <berkas>"
+
 #: builtin/bundle.c builtin/pack-objects.c
 msgid "do not show progress meter"
 msgstr "jangan perlihatkan meteran perkembangan"
@@ -3930,11 +3966,6 @@
 msgstr "%s tidak mengambil argumen"
 
 #: builtin/cat-file.c
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "perintah tidak dikenal: '%s'"
-
-#: builtin/cat-file.c
 msgid "only one batch option may be specified"
 msgstr "hanya satu opsi setumpuk yang mungkin disebutkan"
 
@@ -4109,12 +4140,19 @@
 "hanya dua argumen yang diperbolehkan di dalam mode <tipe> <objek>, bukan %d"
 
 #: builtin/check-attr.c
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | <atribut>...] [--] <nama jalur>..."
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [source <mirip-pohon> [-a | --all | <atribut>...] [--] <nama "
+"jalur>..."
 
 #: builtin/check-attr.c
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | <attribut>...]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source <mirip-pohon>] [-a | --all | "
+"<attribut>...]"
 
 #: builtin/check-attr.c
 msgid "report all attributes set on file"
@@ -4132,6 +4170,14 @@
 msgid "terminate input and output records by a NUL character"
 msgstr "akhiri masukan dan keluarkan rekaman oleh sebuah karakter NUL"
 
+#: builtin/check-attr.c
+msgid "<tree-ish>"
+msgstr "<mirip-pohon>"
+
+#: builtin/check-attr.c
+msgid "which tree-ish to check attributes at"
+msgstr "mirip-pohon mana yang diperiksa atributnya"
+
 #: builtin/check-ignore.c builtin/checkout.c builtin/gc.c builtin/worktree.c
 msgid "suppress progress reporting"
 msgstr "padamkan pelaporan kemajuan"
@@ -4813,7 +4859,7 @@
 msgid "Would refuse to remove current working directory\n"
 msgstr "Akan menolak menghapus direktori kerja saat ini\n"
 
-#: builtin/clean.c git-add--interactive.perl
+#: builtin/clean.c
 #, c-format
 msgid ""
 "Prompt help:\n"
@@ -4826,7 +4872,7 @@
 "foo        - pilih item berdasarkan prefiks unik\n"
 "           - (kosong) tidak pilih apa-apa\n"
 
-#: builtin/clean.c git-add--interactive.perl
+#: builtin/clean.c
 #, c-format
 msgid ""
 "Prompt help:\n"
@@ -4847,8 +4893,8 @@
 "*          - pilih semua item\n"
 "           - (kosong) selesai memilih\n"
 
-#: builtin/clean.c git-add--interactive.perl
-#, c-format, perl-format
+#: builtin/clean.c
+#, c-format
 msgid "Huh (%s)?\n"
 msgstr "Huh (%s)?\n"
 
@@ -5039,10 +5085,6 @@
 msgid "create a shallow clone of that depth"
 msgstr "buat klon dangkal sedalam kedalaman tersebut"
 
-#: builtin/clone.c builtin/fetch.c builtin/pack-objects.c builtin/pull.c
-msgid "time"
-msgstr "waktu"
-
 #: builtin/clone.c
 msgid "create a shallow clone since a specific time"
 msgstr "buat klon dangkal sejak waktu yang disebutkan"
@@ -5338,6 +5380,10 @@
 msgstr "gagal mengambil objek dari URI bundel '%s'"
 
 #: builtin/clone.c
+msgid "failed to fetch advertised bundles"
+msgstr "gagal mengambil bundel yang diiklankan"
+
+#: builtin/clone.c
 msgid "remote transport reported error"
 msgstr "transportasi remote melaporkan kesalahan"
 
@@ -5714,7 +5760,7 @@
 "tidak dapat memilih karakter komentar yang tidak terpakai\n"
 "dalam pesan komit saat ini"
 
-#: builtin/commit.c
+#: builtin/commit.c builtin/merge-tree.c
 #, c-format
 msgid "could not lookup commit %s"
 msgstr "tidak dapat mencari komit %s"
@@ -6022,7 +6068,7 @@
 msgid "override date for commit"
 msgstr "timpa tanggal komit"
 
-#: builtin/commit.c parse-options.h ref-filter.h
+#: builtin/commit.c builtin/merge-tree.c parse-options.h ref-filter.h
 msgid "commit"
 msgstr "komit"
 
@@ -6176,7 +6222,7 @@
 msgid "git config [<options>]"
 msgstr "git config [<opsi>]"
 
-#: builtin/config.c builtin/env--helper.c
+#: builtin/config.c
 #, c-format
 msgid "unrecognized --type argument, %s"
 msgstr "argumen --type tidak dikenal %s"
@@ -6285,11 +6331,11 @@
 msgid "Type"
 msgstr "Tipe"
 
-#: builtin/config.c builtin/env--helper.c builtin/hash-object.c
+#: builtin/config.c builtin/hash-object.c
 msgid "type"
 msgstr "tipe"
 
-#: builtin/config.c builtin/env--helper.c
+#: builtin/config.c
 msgid "value is given this type"
 msgstr "Nilai diberikan tipe ini"
 
@@ -6344,7 +6390,7 @@
 "perlihatkan cakupan konfigurasi (pohon kerja, lokal, global, sistem, "
 "perintah)"
 
-#: builtin/config.c builtin/env--helper.c
+#: builtin/config.c
 msgid "value"
 msgstr "nilai"
 
@@ -6887,34 +6933,6 @@
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "tidak ada <perintah> yang diberikan untuk --extcmd=<perintah>"
 
-#: builtin/env--helper.c
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] <opsi> <variabel lingkungan>"
-
-#: builtin/env--helper.c
-msgid "default for git_env_*(...) to fall back on"
-msgstr "asali untuk git_env_*(...) agar kembali"
-
-#: builtin/env--helper.c
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr "jadi diam; hanya gunakan nilai git_env_*() sebagai kode keluar"
-
-#: builtin/env--helper.c
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr ""
-"opsi `--default' mengharapkan sebuah nilai boolean dengan `--type=bool`, "
-"bukan `%s`"
-
-#: builtin/env--helper.c
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not `"
-"%s`"
-msgstr ""
-"opsi `--default' mengharapkan sebuah nilai unsigned long dengan `--"
-"type=ulong`, bukan `%s`"
-
 #: builtin/fast-export.c
 msgid "git fast-export [<rev-list-opts>]"
 msgstr "git fast-export [<opsi rev-list>]"
@@ -7423,6 +7441,11 @@
 msgstr "--unshallow pada repositori penuh tidak masuk akal"
 
 #: builtin/fetch.c
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "gagal mengambil bundel dari '%s'"
+
+#: builtin/fetch.c
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all tidak mengambil argumen repositori"
 
@@ -8730,13 +8753,21 @@
 msgstr "'git help config' untuk informasi lebih lanjut"
 
 #: builtin/hook.c
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] <nama kait> [-- <argumen kait>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=<jalur>] <nama kait> [-- "
+"<argumen kait>]"
 
 #: builtin/hook.c
 msgid "silently ignore missing requested <hook-name>"
 msgstr "diam-diam abaikan <nama kait> yang diminta yang hilang"
 
+#: builtin/hook.c
+msgid "file to read into hooks' stdin"
+msgstr "gagal membaca masukan standar kait"
+
 #: builtin/index-pack.c
 #, c-format
 msgid "object type mismatch at %s"
@@ -9799,11 +9830,11 @@
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<kunci>]\n"
-"              [--symref] [<repositori> [<referensi>...]]"
+"              [--symref] [<repositori> [<pola>...]]"
 
 #: builtin/ls-remote.c
 msgid "do not print remote URL"
@@ -10126,9 +10157,17 @@
 msgstr "lakukan banyak penggabungan, satu per baris masukan"
 
 #: builtin/merge-tree.c
+msgid "specify a merge-base for the merge"
+msgstr "harus menyebutkan sebuah dasar penggabungan untuk penggabungan"
+
+#: builtin/merge-tree.c
 msgid "--trivial-merge is incompatible with all other options"
 msgstr "--trivial-merge tidak kompatibel dengan semua opsi lainnya"
 
+#: builtin/merge-tree.c
+msgid "--merge-base is incompatible with --stdin"
+msgstr "--merge-base tidak kompatibel dengan --stdin"
+
 #: builtin/merge-tree.c builtin/notes.c
 #, c-format
 msgid "malformed input line: '%s'."
@@ -12207,7 +12246,7 @@
 msgid "--delete doesn't make sense without any refs"
 msgstr "--delete tidak masuk akal tanpa referensi"
 
-#: builtin/push.c
+#: builtin/push.c t/helper/test-bundle-uri.c
 #, c-format
 msgid "bad repository '%s'"
 msgstr "repositori jelek '%s'"
@@ -12485,6 +12524,10 @@
 msgstr "tidak dapat mengganti ke %s"
 
 #: builtin/rebase.c
+msgid "apply options and merge options cannot be used together"
+msgstr "opsi apply dan opsi merge tidak dapat digunakan bersamaan"
+
+#: builtin/rebase.c
 #, c-format
 msgid ""
 "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask"
@@ -12769,8 +12812,20 @@
 msgstr "--strategy butuh --merge atau --interactive"
 
 #: builtin/rebase.c
-msgid "apply options and merge options cannot be used together"
-msgstr "opsi apply dan opsi merge tidak dapat digunakan bersamaan"
+msgid ""
+"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"autosquash"
+msgstr ""
+"opsi penerapan tidak kompatibel dengan rebase.autosquash. "
+"Pertimbangkanmenambahkan --no-autosquash"
+
+#: builtin/rebase.c
+msgid ""
+"apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
+"update-refs"
+msgstr ""
+"opsi penerapan tidak kompatibel dengan rebase.updateRefs. "
+"Pertimbangkanmenambahkan --no-update-refs"
 
 #: builtin/rebase.c
 #, c-format
@@ -15878,11 +15933,6 @@
 msgid "git submodule--helper <command>"
 msgstr "git submodule--helper <nama>"
 
-#: builtin/submodule--helper.c git.c
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s tidak mendukung --super-prefix"
-
 #: builtin/symbolic-ref.c
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
 msgstr "git symbolic-ref [-m <alasan>] <nama> <referensi>"
@@ -16805,6 +16855,11 @@
 
 #: bundle-uri.c
 #, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr "tidak dapat mengurai kunci daftar bundel %s dengan nilai '%s'"
+
+#: bundle-uri.c
+#, c-format
 msgid "bundle list at '%s' has no mode"
 msgstr "daftar bundel pada '%s' tidak punya mode"
 
@@ -16818,6 +16873,15 @@
 
 #: bundle-uri.c
 #, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "berkas yang diunduh dari '%s' bukan sebuah bundel"
+
+#: bundle-uri.c
+msgid "failed to store maximum creation token"
+msgstr "gagal menyimpan token pembuatan maksimum"
+
+#: bundle-uri.c
+#, c-format
 msgid "unrecognized bundle mode from URI '%s'"
 msgstr "mode bundel tidak dikenal dari URI '%s'"
 
@@ -16837,6 +16901,15 @@
 msgstr "berkas pada URI '%s' bukan sebuah bundel atau daftar bundel"
 
 #: bundle-uri.c
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: argumen tidak diharapkan: '%s'"
+
+#: bundle-uri.c
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: bilasan diharapkan setelah argumen"
+
+#: bundle-uri.c
 msgid "bundle-uri: got an empty line"
 msgstr "bundle-uri: dapat satu baris kosong"
 
@@ -16877,6 +16950,14 @@
 msgstr "perlu sebuah repositori untuk verifikasi bundel"
 
 #: bundle.c
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+"beberapa komit prasyarat ada pada penyimpanan objek, tetapi tidak terhubung "
+"ke riwayat repositori"
+
+#: bundle.c
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -18673,6 +18754,19 @@
 
 #: connect.c
 #, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "kesalahan pada baris tanggapan bundle-uri ke-%d: %s"
+
+#: connect.c
+msgid "expected flush after bundle-uri listing"
+msgstr "bilasan diharapkan setelah pendaftaran bundle-uri"
+
+#: connect.c
+msgid "expected response end packet after ref listing"
+msgstr "jawaban akhir paket diharapkan setelah penyebutan referensi"
+
+#: connect.c
+#, c-format
 msgid "invalid ls-refs response: %s"
 msgstr "jawaban ls-refs tidak valid: %s"
 
@@ -18681,10 +18775,6 @@
 msgstr "bilasan diharapkan setelah penyebutan referensi"
 
 #: connect.c
-msgid "expected response end packet after ref listing"
-msgstr "jawaban akhir paket diharapkan setelah penyebutan referensi"
-
-#: connect.c
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr "protokol '%s' tidak didukung"
@@ -20134,16 +20224,14 @@
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-"           <command> [<args>]"
+"           [--config-env=<name>=<envvar>] <command> [<args>]"
 msgstr ""
 "git [-v| --version] [-h | --help] [-C <jalur>] [-c <nama>=<nilai>]\n"
 "           [--exec-path[=<jalur>]] [--html-path] [--man-path] [--info-path]\n"
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<jalur>] [--work-tree=<jalur>] [--namespace=<nama>]\n"
-"           [--super-prefix=<jalur>] [--config-env=<nama>=<variabel "
-"lingkungan>]\n"
+"           [--config-env=<nama>=<variabel lingkungan>]\n"
 "           <perintah> [<argumen>]"
 
 #: git.c
@@ -20175,11 +20263,6 @@
 
 #: git.c
 #, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "tidak ada prefiks yang diberikan untuk --super-prefix\n"
-
-#: git.c
-#, c-format
 msgid "-c expects a configuration string\n"
 msgstr "-c mengharapkan sebuah untai konfigurasi\n"
 
@@ -20316,8 +20399,13 @@
 msgstr "gpg.ssh.defaultKeyCommand gagal: %s %s"
 
 #: gpg-interface.c
-msgid "gpg failed to sign the data"
-msgstr "gpg gagal menandatangani data"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg gagal menandatangani data:\n"
+"%s"
 
 #: gpg-interface.c
 msgid "user.signingKey needs to be set for ssh signing"
@@ -21706,6 +21794,11 @@
 
 #: object-file.c
 #, c-format
+msgid "unable to open loose object %s"
+msgstr "tidak dapat membuka objek longgar %s"
+
+#: object-file.c
+#, c-format
 msgid "unable to parse %s header"
 msgstr "tidak dapat menguraikan kepala %s"
 
@@ -21725,8 +21818,8 @@
 
 #: object-file.c
 #, c-format
-msgid "failed to read object %s"
-msgstr "gagal membaca objek %s"
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "objek longgar %s (disimpan di %s) rusak"
 
 #: object-file.c
 #, c-format
@@ -21735,11 +21828,6 @@
 
 #: object-file.c
 #, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "objek longgar %s (disimpan di %s) rusak"
-
-#: object-file.c
-#, c-format
 msgid "packed object %s (stored in %s) is corrupt"
 msgstr "objek terpak %s (disimpan di %s) rusak"
 
@@ -21754,10 +21842,6 @@
 msgstr "tidak dapat menyetel perizinan ke '%s'"
 
 #: object-file.c
-msgid "file write error"
-msgstr "kesalahan menulis berkas"
-
-#: object-file.c
 msgid "error when closing loose object file"
 msgstr "kesalahan saat menutup berkas objek longgar"
 
@@ -21817,12 +21901,13 @@
 msgstr "tidak dapat membaca objek untuk %s"
 
 #: object-file.c
-msgid "corrupt commit"
-msgstr "komit rusak"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "fsck objek gagal: %s"
 
 #: object-file.c
-msgid "corrupt tag"
-msgstr "tag rusak"
+msgid "refusing to create malformed object"
+msgstr "menolak membuat objek jelek"
 
 #: object-file.c
 #, c-format
@@ -22137,11 +22222,6 @@
 msgstr "tidak dapat fstat berkas bitmap"
 
 #: pack-bitmap.c
-#, c-format
-msgid "ignoring extra bitmap file: '%s'"
-msgstr "mengabaikan berkas bitmap tambahan: '%s'"
-
-#: pack-bitmap.c
 msgid "checksum doesn't match in MIDX and bitmap"
 msgstr "checksum tidak cocok di MIDX dan bitmap"
 
@@ -22469,6 +22549,10 @@
 msgstr "gunakan <n> digit untuk menampilkan nama objek"
 
 #: parse-options.h
+msgid "prefixed path to initial superproject"
+msgstr "jalur terprefiks ke superproyek awal"
+
+#: parse-options.h
 msgid "how to strip spaces and #comments from message"
 msgstr "bagaimana cara mengupas spasi dan #komentar dari pesan"
 
@@ -23071,6 +23155,16 @@
 
 #: ref-filter.c
 #, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) tidak mengambil argumen"
+
+#: ref-filter.c
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "argumen %%(%.*s) tidak dikenal: %s"
+
+#: ref-filter.c
+#, c-format
 msgid "expected format: %%(color:<color>)"
 msgstr "format yang diharapkan: %%(color:<warna>)"
 
@@ -23091,26 +23185,6 @@
 
 #: ref-filter.c
 #, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "argumen %%(%s) tidak dikenal: %s"
-
-#: ref-filter.c
-#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) tidak mengambil argumen"
-
-#: ref-filter.c
-#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) tidak mengambil argumen"
-
-#: ref-filter.c
-#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) tidak mengambil argumen"
-
-#: ref-filter.c
-#, c-format
 msgid "expected %%(trailers:key=<value>)"
 msgstr "diharapkan %%(trailers:key=<nilai>)"
 
@@ -23131,11 +23205,6 @@
 
 #: ref-filter.c
 #, c-format
-msgid "unrecognized email option: %s"
-msgstr "opsi surel tidak dikenal: %s"
-
-#: ref-filter.c
-#, c-format
 msgid "expected format: %%(align:<width>,<position>)"
 msgstr "format diharapkan: %%(align:<lebar>,<posisi>)"
 
@@ -23151,13 +23220,13 @@
 
 #: ref-filter.c
 #, c-format
-msgid "positive width expected with the %%(align) atom"
-msgstr "lebar positif diharapkan dengan atom %%(align)"
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "argumen %%(%s) tidak dikenal: %s"
 
 #: ref-filter.c
 #, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) tidak mengambil argumen"
+msgid "positive width expected with the %%(align) atom"
+msgstr "lebar positif diharapkan dengan atom %%(align)"
 
 #: ref-filter.c
 #, c-format
@@ -24687,6 +24756,28 @@
 
 #: sequencer.c
 #, c-format
+msgid "'%s' is not a valid label"
+msgstr "'%s' bukan label valid"
+
+#: sequencer.c
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "'%s' bukan nama referensi valid"
+
+#: sequencer.c
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr ""
+"update-ref memerlukan nama referensi terkualifikasi penuh, misalnya refs/"
+"heads/%s"
+
+#: sequencer.c
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "perintah tidak valid '%.*s'"
+
+#: sequencer.c
+#, c-format
 msgid "%s does not accept arguments: '%s'"
 msgstr "%s tidak menerima argumen: '%s'"
 
@@ -25660,6 +25751,19 @@
 msgid "failed to lstat '%s'"
 msgstr "gagal men-lstat '%s'"
 
+#: t/helper/test-bundle-uri.c
+msgid "no remote configured to get bundle URIs from"
+msgstr "tidak ada remote yang dikonfigurasi untuk mendapatkan URI bundel"
+
+#: t/helper/test-bundle-uri.c
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "remote '%s' tidak punya URL terkonfigurasi"
+
+#: t/helper/test-bundle-uri.c
+msgid "could not get the bundle-uri list"
+msgstr "tidak dapat mendapatkan daftar bundle-uri"
+
 #: t/helper/test-cache-tree.c
 msgid "test-tool cache-tree <options> (control|prime|update)"
 msgstr "test-tool cache-tree <opsi> (control|prime|update)"
@@ -26101,6 +26205,14 @@
 msgid "failed to push all needed submodules"
 msgstr "gagal mendorong semua submodul yang dibutuhkan"
 
+#: transport.c
+msgid "bundle-uri operation not supported by protocol"
+msgstr "operasi bundle-uri tidak didukung oleh protokol"
+
+#: transport.c
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr "tidak dapat menerima daftar bundle-uri teriklankan server"
+
 #: tree-walk.c
 msgid "too-short tree object"
 msgstr "objek pohon terlalu pendek"
@@ -27005,13 +27117,22 @@
 #: wt-status.c
 #, c-format
 msgid ""
-"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-"may speed it up, but you have to be careful not to forget to add\n"
-"new files yourself (see 'git help status')."
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
 msgstr ""
-"Butuh %.2f detik untuk menghitung berkas tak terlacak. 'status -uno'\n"
-"mungkin bisa mempercepat, tapi Anda harus berhati-hati jangan sampai lupa\n"
-"untuk tambahkan berkas baru sendiri (lihat 'git help status')."
+"Butuh %.2f detik untuk mengenumerasikan berkas tak terlacak,\n"
+"tapi hasilnya ditembolokkan, dan invokasi berikutnya mungkin\n"
+"lebih cepat."
+
+#: wt-status.c
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr "Butuh %.2f detik untuk mengenumerasikan berkas tak terlacak."
+
+#: wt-status.c
+msgid "See 'git help status' for information on how to improve this."
+msgstr ""
+"Lihat 'git help status' untuk informasi bagaimana meningkatkankeadaan ini."
 
 #: wt-status.c
 #, c-format
@@ -27190,241 +27311,6 @@
 msgid "Unable to determine absolute path of git directory"
 msgstr "Tidak dapat menentukan jalur absolut direktori git"
 
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#: git-add--interactive.perl
-#, perl-format
-msgid "%12s %12s %s"
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] ""
-msgstr[1] ""
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid ""
-"---\n"
-"To remove '%s' lines, make them ' ' lines (context).\n"
-"To remove '%s' lines, delete them.\n"
-"Lines starting with %s will be removed.\n"
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"y - stage this hunk\n"
-"n - do not stage this hunk\n"
-"q - quit; do not stage this hunk or any of the remaining ones\n"
-"a - stage this hunk and all later hunks in the file\n"
-"d - do not stage this hunk or any of the later hunks in the file"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"y - stash this hunk\n"
-"n - do not stash this hunk\n"
-"q - quit; do not stash this hunk or any of the remaining ones\n"
-"a - stash this hunk and all later hunks in the file\n"
-"d - do not stash this hunk or any of the later hunks in the file"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"y - unstage this hunk\n"
-"n - do not unstage this hunk\n"
-"q - quit; do not unstage this hunk or any of the remaining ones\n"
-"a - unstage this hunk and all later hunks in the file\n"
-"d - do not unstage this hunk or any of the later hunks in the file"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"y - apply this hunk to index\n"
-"n - do not apply this hunk to index\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"y - discard this hunk from worktree\n"
-"n - do not discard this hunk from worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"y - discard this hunk from index and worktree\n"
-"n - do not discard this hunk from index and worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"y - apply this hunk to index and worktree\n"
-"n - do not apply this hunk to index and worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"y - apply this hunk to worktree\n"
-"n - do not apply this hunk to worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid ""
-"g - select a hunk to go to\n"
-"/ - search for a hunk matching the given regex\n"
-"j - leave this hunk undecided, see next undecided hunk\n"
-"J - leave this hunk undecided, see next hunk\n"
-"k - leave this hunk undecided, see previous undecided hunk\n"
-"K - leave this hunk undecided, see previous hunk\n"
-"s - split the current hunk into smaller hunks\n"
-"e - manually edit the current hunk\n"
-"? - print help\n"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid "The selected hunks do not apply to the index!\n"
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid "No other hunks to goto\n"
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] ""
-msgstr[1] ""
-
-#: git-add--interactive.perl
-msgid "No other hunks to search\n"
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid "No hunk matches the given pattern\n"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid "No previous hunk\n"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid "No next hunk\n"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid "Sorry, cannot split this hunk\n"
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] ""
-msgstr[1] ""
-
-#: git-add--interactive.perl
-msgid "Sorry, cannot edit this hunk\n"
-msgstr ""
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-#: git-add--interactive.perl
-msgid ""
-"status        - show paths with changes\n"
-"update        - add working tree state to the staged set of changes\n"
-"revert        - revert staged set of changes back to the HEAD version\n"
-"patch         - pick hunks and update selectively\n"
-"diff          - view diff between HEAD and index\n"
-"add untracked - add contents of untracked files to the staged set of "
-"changes\n"
-msgstr ""
-
-#: git-add--interactive.perl
-msgid "missing --"
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr ""
-
 #: git-send-email.perl
 msgid "local zone differs from GMT by a non-minute interval\n"
 msgstr "zona lokal berbeda dari GMT oleh selang non-menit\n"
@@ -27808,147 +27694,3 @@
 #, perl-format
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Anda benar-benar ingin mengirim %s? [y|N]: "
-
-#, c-format
-#~ msgid "unable to normalize object directory: %s"
-#~ msgstr "tidak dapat menormalisasikan direktori objek: %s"
-
-#~ msgid "reset the bisection state"
-#~ msgstr "setel ulang keadaan pembagian dua"
-
-#~ msgid "check whether bad or good terms exist"
-#~ msgstr "periksa apakah ada istilah jelek atau bagus"
-
-#~ msgid "print out the bisect terms"
-#~ msgstr "cetak istilah pembagian dua"
-
-#~ msgid "start the bisect session"
-#~ msgstr "mulai sesi pembagian dua"
-
-#~ msgid "find the next bisection commit"
-#~ msgstr "temukan komit pembagian dua berikutnya"
-
-#~ msgid "mark the state of ref (or refs)"
-#~ msgstr "tandai keadaan referensi"
-
-#~ msgid "list the bisection steps so far"
-#~ msgstr "daftar langkah pembagian dua sejauh ini"
-
-#~ msgid "replay the bisection process from the given file"
-#~ msgstr "mainkan ulang proses pembagian dua dari berkas yang diberikan"
-
-#~ msgid "skip some commits for checkout"
-#~ msgstr "lewati beberapa komit untuk checkout"
-
-#~ msgid "visualize the bisection"
-#~ msgstr "visualisasikan pembagian dua"
-
-#~ msgid "use <cmd>... to automatically bisect"
-#~ msgstr "gunakan <cmd>... untuk bagi dua otomatis."
-
-#~ msgid "no log for BISECT_WRITE"
-#~ msgstr "tidak ada log untuk BISECT_WRITE"
-
-#~ msgid "Couldn't look up commit object for HEAD"
-#~ msgstr "Tidak dapat mencari objek komit untuk HEAD"
-
-#~ msgid "git bundle create [<options>] <file> <git-rev-list args>"
-#~ msgstr "git bundle create [<opsi>] <berkas> <argumen git-rev-list>"
-
-#, c-format
-#~ msgid "options '%s' and '%s %s' cannot be used together"
-#~ msgstr "opsi '%s' dan '%s %s' tidak dapat digunakan bersamaan"
-
-#~ msgid "git commit [<options>] [--] <pathspec>..."
-#~ msgstr "git commit [<opsi>] [--] <spek jalur>..."
-
-#~ msgid "git fsck [<options>] [<object>...]"
-#~ msgstr "git fsck [<opsi>] [<objek>...]"
-
-#~ msgid "git fsmonitor--daemon stop"
-#~ msgstr "git fsmonitor--daemon stop"
-
-#~ msgid "git fsmonitor--daemon status"
-#~ msgstr "git fsmonitor--daemon status"
-
-#~ msgid "failed to run 'git config'"
-#~ msgstr "gagal menjalankan 'git config'"
-
-#, c-format
-#~ msgid "could not get 'onto': '%s'"
-#~ msgstr "tidak dapat mendapatkan 'ke': '%s'"
-
-#~ msgid "Could not resolve HEAD to a revision"
-#~ msgstr "Tidak dapat menguraikan HEAD ke sebuah revisi"
-
-#, c-format
-#~ msgid "missing required file: %s"
-#~ msgstr "berkas yang diperlukan hilang: %s"
-
-#~ msgid "git revert [<options>] <commit-ish>..."
-#~ msgstr "git revert [<opsi>] <mirip-komit>..."
-
-#~ msgid "git revert <subcommand>"
-#~ msgstr "git revert <subperintah>"
-
-#~ msgid "git cherry-pick [<options>] <commit-ish>..."
-#~ msgstr "git cherry-pick [<opsi>] <mirip-komit>..."
-
-#~ msgid "git cherry-pick <subcommand>"
-#~ msgstr "git cherry-pick <subperintah>"
-
-#~ msgid "git rm [<options>] [--] <file>..."
-#~ msgstr "git rm [<opsi>] [--] <berkas>..."
-
-#~ msgid "using --group=trailer with stdin is not supported"
-#~ msgstr "mengguanakn --group=trailer dengan stdin tidak didukung"
-
-#~ msgid "git stash show [<options>] [<stash>]"
-#~ msgstr "git stash show [<opsi>] [<stase>]"
-
-#~ msgid "git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"
-#~ msgstr "git stash ( pop | apply ) [--index] [-q|--quiet] [<stase>]"
-
-#~ msgid ""
-#~ "git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-#~ "          [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
-#~ "          [--] [<pathspec>...]]"
-#~ msgstr ""
-#~ "git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-#~ "          [-u|--include-untracked] [-a|--all] [-m|--message <pesan>]\n"
-#~ "          [--] [<spek jalur>...]"
-
-#~ msgid ""
-#~ "git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-#~ "               [-u|--include-untracked] [-a|--all] [<message>]"
-#~ msgstr ""
-#~ "git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-#~ "               [-u|--include-untracked] [-a|--all] [<pesan>]"
-
-#~ msgid "path into the working tree"
-#~ msgstr "jalur ke dalam pohon kerja"
-
-#~ msgid "recurse into submodules"
-#~ msgstr "rekursi ke dalam submodul"
-
-#~ msgid "check if it is safe to write to the .gitmodules file"
-#~ msgstr "periksa apakah itu aman untuk menulis ke berkas .gitmodules"
-
-#~ msgid "unset the config in the .gitmodules file"
-#~ msgstr "batal setel konfigurasi dalam berkas .gitmodules"
-
-#~ msgid "git submodule--helper config --unset <name>"
-#~ msgstr "git submodule--helper config --unset <nama>"
-
-#, c-format
-#~ msgid "'%s' is not a valid submodule--helper subcommand"
-#~ msgstr "'%s' bukan subperintah submodule--helper valid"
-
-#~ msgid "git upload-pack [<options>] <dir>"
-#~ msgstr "git upload-pack [<opsi>] <direktori>"
-
-#~ msgid "git worktree add [<options>] <path> [<commit-ish>]"
-#~ msgstr "git worktree add [<opsi>] <jalur> [<mirip komit>]"
-
-#~ msgid "git worktree lock [<options>] <path>"
-#~ msgstr "git worktree lock [<opsi>] <jalur>"
diff --git a/po/sv.po b/po/sv.po
index 4b5fe17..0ba8585 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -1,14 +1,14 @@
 # Swedish translations for Git.
-# Copyright (C) 2010-2022 Peter Krefting <peter@softwolves.pp.se>
+# Copyright (C) 2010-2023 Peter Krefting <peter@softwolves.pp.se>
 # This file is distributed under the same license as the Git package.
-# Peter Krefting <peter@softwolves.pp.se>, 2010-2022.
+# Peter Krefting <peter@softwolves.pp.se>, 2010-2023.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.39.0\n"
+"Project-Id-Version: git 2.40.0\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-11-29 04:57+0000\n"
-"PO-Revision-Date: 2022-11-29 22:50+0100\n"
+"POT-Creation-Date: 2023-03-02 09:34+0100\n"
+"PO-Revision-Date: 2023-03-02 09:35+0100\n"
 "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
 "Language: sv\n"
@@ -44,13 +44,13 @@
 msgid "could not write index"
 msgstr "kunde inte skriva indexet"
 
-#, c-format, perl-format
+#, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "uppdaterade %d sökväg\n"
 msgstr[1] "uppdaterade %d sökvägar\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "observera: %s spåras inte längre.\n"
 
@@ -64,7 +64,7 @@
 msgid "Could not parse HEAD^{tree}"
 msgstr "kunde inte tolka HEAD^{tree}"
 
-#, c-format, perl-format
+#, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "återställde %d sökväg\n"
@@ -77,7 +77,7 @@
 msgid "Add untracked"
 msgstr "Lägg till ospårad"
 
-#, c-format, perl-format
+#, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "lade till %d sökväg\n"
@@ -171,19 +171,19 @@
 msgid "Bye.\n"
 msgstr "Hej då.\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "Köa ändrat läge [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "Köa borttagning [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "Köa tillägg [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Köa stycket [y,n,q,a,d%s,?]? "
 
@@ -207,19 +207,19 @@
 "a - köa stycket och alla följande i filen\n"
 "d - köa inte stycket eller något av de följande i filen\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "Stash:a ändrat läge [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "Stash:a borttagning [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "Stash:a tillägg [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "Stash:a stycket [y,n,q,a,d%s,?]? "
 
@@ -243,19 +243,19 @@
 "a - \"stash\":a stycket och alla följande i filen\n"
 "d - \"stash\":a inte stycket eller något av de följande i filen\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "Ta bort ändrat läge från kön [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "Ta bort borttagning från kön [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "Ta bort tillägg från kön [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Ta bort stycket från kön [y,n,q,a,d%s,?]? "
 
@@ -279,19 +279,19 @@
 "a - ta bort stycket och alla följande i filen från kön\n"
 "d - ta inte bort stycket eller något av de följande i filen från kön\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr "Applicera ändrat läge på indexet [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "Applicera borttagning på indexet [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "Applicera tillägg på indexet [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "Applicera stycket på indexet [y,n,q,a,d%s,?]? "
 
@@ -315,19 +315,19 @@
 "a - applicera stycket och alla följande i filen\n"
 "d - applicera inte stycket eller något av de följande i filen\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr "Kasta ändrat läge från arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "Kasta borttagning från arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "Kasta tillägg från arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
 msgstr "Kasta stycket från arbetskatalogen [y,n,q,a,d%s,?]? "
 
@@ -351,19 +351,19 @@
 "a - förkasta stycket och alla följande i filen\n"
 "d - förkasta inte stycket eller något av de följande i filen\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Kasta ändrat läge från indexet och arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Kasta borttagning från indexet och arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Kasta tillägg från indexet och arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Kasta stycket från indexet och arbetskatalogen [y,n,q,a,d%s,?]? "
 
@@ -380,19 +380,19 @@
 "a - förkasta stycket och alla följande i filen\n"
 "d - förkasta inte stycket eller något av de följande i filen\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Applicera ändrat läge på indexet och arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Applicera borttagning på indexet och arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Applicera tillägg på indexet och arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Applicera stycket på indexet och arbetskatalogen [y,n,q,a,d%s,?]? "
 
@@ -409,19 +409,19 @@
 "a - applicera stycket och alla följande i filen\n"
 "d - applicera inte stycket eller något av de följande i filen\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
 msgstr "Applicera ändrat läge på arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
 msgstr "Applicera borttagning på arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
 msgstr "Applicera tillägg på arbetskatalogen [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
 msgstr "Applicera stycket på arbetskatalogen [y,n,q,a,d%s,?]? "
 
@@ -497,8 +497,6 @@
 "Ta bort \"%c\" rader genom att radera dem.\n"
 "Rader som börjar med %c kommer att tas bort.\n"
 
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
 "edit again.  If all lines of the hunk are removed, then the edit is\n"
@@ -514,20 +512,12 @@
 msgid "'git apply --cached' failed"
 msgstr "\"git apply --cached\" misslyckades"
 
-#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr ""
@@ -1374,6 +1364,12 @@
 msgid "report archived files on stderr"
 msgstr "rapportera arkiverade filer på standard fel"
 
+msgid "time"
+msgstr "tid"
+
+msgid "set modification time of archive entries"
+msgstr "välj modifieringstid för arkivposter"
+
 msgid "set compression level"
 msgstr "välj komprimeringsgrad"
 
@@ -1414,6 +1410,13 @@
 msgid "%.*s is not a valid attribute name"
 msgstr "%-*s är inte ett giltigt namn på attribut"
 
+msgid "unable to add additional attribute"
+msgstr "Kunde inte lägga till ytterligare attribut"
+
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "ignorerar överlång attributrad %d"
+
 #, c-format
 msgid "%s not allowed: %s:%d"
 msgstr "%s inte tillåtet: %s:%d"
@@ -1426,6 +1429,18 @@
 "Använd '\\!' för att inleda med ett utropstecken."
 
 #, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "kan inte utföra fstat på gitattributes-filen \"%s\""
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "ignorerar allt för stor gitattributes-fil \"%s\""
+
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "ignorerar allt för stor gitattributes-objekt \"%s\""
+
+#, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Felaktigt citerat innehåll i filen \"%s\": %s"
 
@@ -1702,11 +1717,11 @@
 
 #, c-format
 msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
 msgstr ""
-"Du kan försöka uppdatera undermodulerna med \"git checkout %s && git "
-"submodule update --init\""
+"Du kan försöka uppdatera undermodulerna med \"git checkout --no-recurse-"
+"submodules %s && git submodule update --init\""
 
 #, c-format
 msgid "submodule '%s': cannot create branch '%s'"
@@ -1741,6 +1756,13 @@
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Oköade ändringar efter att ha uppdaterat indexet:"
 
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"inställningen add.interactive.useBuiltin har tagits bort!\n"
+"Se dess post i \"git help config\" för detaljer."
+
 msgid "Could not read the index"
 msgstr "Kunde inte läsa indexet"
 
@@ -2125,6 +2147,9 @@
 msgid "run interactively"
 msgstr "kör interaktivt"
 
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "förbigå pre-applypatch- och applypatch-msg-krokar"
+
 msgid "historical option -- no-op"
 msgstr "historisk flagga -- no-op"
 
@@ -2265,32 +2290,27 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: förväntade en tömning (flush)"
 
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [<incheckning>]"
-
 msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<dålig> [<bra>...]] [--] "
-"[<sökvägar>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<dålig> [<bra>...]] [--]    [<sökvägar>...]"
 
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (bad|new) [<incheckning>]"
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<incheckning>...]"
 
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (good|old) [<incheckning>...]"
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<incheckning>|<intervall>)...]"
 
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay <filnamn>"
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<incheckning>]"
 
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(<incheckning>|<intervall>)...]"
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <loggfil>"
 
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run <kommando>..."
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run <kommando>..."
 
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
@@ -2436,10 +2456,6 @@
 msgstr ""
 "misslyckades checka ut \"%s\". Försök \"git bisect reset <giltig_gren>\"."
 
-# cogito-relaterat
-msgid "won't bisect on cg-seek'ed tree"
-msgstr "kör inte \"bisect\" på träd där \"cg-seek\" använts"
-
 msgid "bad HEAD - strange symbolic ref"
 msgstr "felaktigt HEAD - konstig symbolisk referens"
 
@@ -2491,17 +2507,17 @@
 msgstr "bisect-körning misslyckades: inget kommando gavs."
 
 #, c-format
-msgid "unable to verify '%s' on good revision"
-msgstr "kan inte bekräfta \"%s\" på bra revision"
+msgid "unable to verify %s on good revision"
+msgstr "kan inte bekräfta %s på bra revision"
 
 #, c-format
 msgid "bogus exit code %d for good revision"
 msgstr "falsk slutkod %d för bra revision"
 
 #, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
 msgstr ""
-"\"bisect\"-körningen misslyckades: felkod %d från \"%s\" är < 0 eller >= 128"
+"\"bisect\"-körningen misslyckades: felkod %d från %s är < 0 eller >= 128"
 
 #, c-format
 msgid "cannot open file '%s' for writing"
@@ -2510,37 +2526,44 @@
 msgid "bisect run cannot continue any more"
 msgstr "\"bisect\"-körningen kan inte fortsätta längre"
 
-#, c-format
 msgid "bisect run success"
 msgstr "\"bisect\"-körningen lyckades"
 
-#, c-format
 msgid "bisect found first bad commit"
 msgstr "bisect hittade första trasiga incheckning"
 
 #, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
 msgstr ""
-"\"bisect\"-körningen misslyckades: \"git bisect--helper --bisect-state %s\" "
-"avslutades med felkoden %d"
+"\"bisect\"-körningen misslyckades: \"git bisect %s\" avslutades med felkoden "
+"%d"
 
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "--bisect-reset kräver antingen inget argument eller en incheckning"
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "\"%s\" kräver antingen inget argument eller en incheckning"
 
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "--bisect-terms kräver noll eller ett argument"
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "\"%s\" kräver noll eller ett argument"
 
-msgid "--bisect-next requires 0 arguments"
-msgstr "--bisect-next kräver 0 argument"
-
-msgid "--bisect-log requires 0 arguments"
-msgstr "--bisect-log kräver 0 argument"
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "\"%s\" kräver noll argument"
 
 msgid "no logfile given"
 msgstr "ingen loggfil angiven"
 
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "\"%s\" misslyckades: inget kommando gavs."
+
+msgid "need a command"
+msgstr "behöver ett kommando"
+
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "okänt kommando: \"%s\""
+
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 msgstr "git blame [<flaggor>] [<rev-flaggor>] [<rev>] [--] <fil>"
 
@@ -3109,6 +3132,9 @@
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
 msgstr "git bundle unbundle [--progress] <fil> [<refnamn>...]"
 
+msgid "need a <file> argument"
+msgstr "behöver ett <fil>-argument"
+
 msgid "do not show progress meter"
 msgstr "visa inte förloppsindikator"
 
@@ -3162,10 +3188,6 @@
 msgid "%s takes no arguments"
 msgstr "%s tar inget argument"
 
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "okänt kommando: \"%s\""
-
 msgid "only one batch option may be specified"
 msgstr "endast en buntflagga kan anges"
 
@@ -3300,11 +3322,17 @@
 msgid "only two arguments allowed in <type> <object> mode, not %d"
 msgstr "endast två argument krävs i <typ> <objekt>-läge, inte %d"
 
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | <attr>...] [--] <sökväg>..."
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [--source <träd:igt>] [-a | --all | <attr>...] [--] "
+"<sökväg>..."
 
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | <attr>...]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source <träd:igt>] [-a | --all | <attr>...]"
 
 msgid "report all attributes set on file"
 msgstr "visa alla attribut som satts på filen"
@@ -3318,6 +3346,12 @@
 msgid "terminate input and output records by a NUL character"
 msgstr "avsluta in- och utdataposter med NUL-tecken"
 
+msgid "<tree-ish>"
+msgstr "<träd-igt>"
+
+msgid "which tree-ish to check attributes at"
+msgstr "vilken träd-igt att kontrollera attribut på"
+
 msgid "suppress progress reporting"
 msgstr "undertryck förloppsrapportering"
 
@@ -3895,7 +3929,7 @@
 "*          - välj alla poster\n"
 "           - (tomt) avsluta markering\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Huh (%s)?\n"
 msgstr "Vadå (%s)?\n"
 
@@ -4044,9 +4078,6 @@
 msgid "create a shallow clone of that depth"
 msgstr "skapa en grund klon på detta djup"
 
-msgid "time"
-msgstr "tid"
-
 msgid "create a shallow clone since a specific time"
 msgstr "skapa en grund klon från en angiven tidpunkt"
 
@@ -4273,6 +4304,9 @@
 msgid "failed to fetch objects from bundle URI '%s'"
 msgstr "misslyckades hämta objekt från bunt-URI \"%s\""
 
+msgid "failed to fetch advertised bundles"
+msgstr "misslyckades hämta annonserade buntar"
+
 msgid "remote transport reported error"
 msgstr "fjärrtransport rapporterade fel"
 
@@ -5507,29 +5541,6 @@
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "inget <kommando> angavs för --extcmd=<kommando>"
 
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] <flaggor> <miljövariabel>"
-
-msgid "default for git_env_*(...) to fall back on"
-msgstr "standard för git_env_*(...) att falla tillbaka på"
-
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr "var tyst, använd bara git_env_*() som resultatvärde"
-
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr ""
-"flaggan \"--default\" förväntar ett sanningsvärde med \"--type=bool\", inte "
-"\"%s\""
-
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not `"
-"%s`"
-msgstr ""
-"flaggan \"--default\" förväntar ett teckenlöst långt värde med \"--type=ulong"
-"\", inte \"%s\""
-
 msgid "git fast-export [<rev-list-opts>]"
 msgstr "git fast-export [<rev-list-flaggor>]"
 
@@ -5922,6 +5933,10 @@
 msgid "--unshallow on a complete repository does not make sense"
 msgstr "--unshallow kan inte användas på ett komplett arkiv"
 
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "misslyckades hämta buntar från \"%s\""
+
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all tar inte namnet på ett arkiv som argument"
 
@@ -6945,12 +6960,19 @@
 msgid "'git help config' for more information"
 msgstr "\"git help config\" för mer information"
 
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] <krok-namn> [-- <krok-argument>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=<sökväg>] <krok-namn> [-- <krok-"
+"argument>]"
 
 msgid "silently ignore missing requested <hook-name>"
 msgstr "ignorera tyst om önskat <krok-namn> saknas"
 
+msgid "file to read into hooks' stdin"
+msgstr "misslyckades läsa till krokens standard in"
+
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "objekttyp stämmer inte överens vid %s"
@@ -7770,11 +7792,11 @@
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<nyckel>]\n"
-"              [--symref] [<arkiv> [<referenser>...]]"
+"              [--symref] [<arkiv> [<mönster>...]]"
 
 msgid "do not print remote URL"
 msgstr "visa inte fjärr-URL"
@@ -8018,9 +8040,15 @@
 msgid "perform multiple merges, one per line of input"
 msgstr "utför flera sammanslagningar, en per indatarad"
 
+msgid "specify a merge-base for the merge"
+msgstr "ange en sammanslagningsbas för sammanslagningen"
+
 msgid "--trivial-merge is incompatible with all other options"
 msgstr "--trivial-merge är inkompatibelt med andra flaggor"
 
+msgid "--merge-base is incompatible with --stdin"
+msgstr "--merge-base är inkompatibel med --stdin"
+
 #, c-format
 msgid "malformed input line: '%s'."
 msgstr "felaktig indatarad: \"%s\"."
@@ -9896,6 +9924,10 @@
 msgid "could not switch to %s"
 msgstr "kunde inte växla till %s"
 
+msgid "apply options and merge options cannot be used together"
+msgstr ""
+"appliceringsflaggor och sammanslagningsflaggor kan inte användas tillsammans"
+
 #, c-format
 msgid ""
 "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask"
@@ -10124,9 +10156,19 @@
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy kräver --merge eller --interactive"
 
-msgid "apply options and merge options cannot be used together"
+msgid ""
+"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"autosquash"
 msgstr ""
-"appliceringsflaggor och sammanslagningsflaggor kan inte användas tillsammans"
+"argument för \"apply\" är inkompatibla med rebase.autosquash. Överväg att "
+"lägga till --no-autosquash"
+
+msgid ""
+"apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
+"update-refs"
+msgstr ""
+"argument för \"apply\" är inkompatibla med rebase.updateRefs. Överväg att "
+"lägga till --no-update-refs"
 
 #, c-format
 msgid "Unknown rebase backend: %s"
@@ -12594,10 +12636,6 @@
 msgid "git submodule--helper <command>"
 msgstr "git submodule--helper <kommando>"
 
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s stöder inte --super-prefix"
-
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
 msgstr "git symbolic-ref [-m <orsak>] <namn> <ref>"
 
@@ -13328,6 +13366,10 @@
 msgstr "core.fsyncMethod = batch stöds inte på denna plattform"
 
 #, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr "kunde inte tolka listnyckeln %s med värdet \"%s\""
+
+#, c-format
 msgid "bundle list at '%s' has no mode"
 msgstr "buntlistan på \"%s\" har inget läge"
 
@@ -13338,6 +13380,13 @@
 msgstr "otillräckliga kapabiliteter"
 
 #, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "filen hämtad från \"%s\" är inte en bunt"
+
+msgid "failed to store maximum creation token"
+msgstr "misslyckades lagra maximal skaparsymbol"
+
+#, c-format
 msgid "unrecognized bundle mode from URI '%s'"
 msgstr "okänt buntlägre från URI:en \"%s\""
 
@@ -13353,6 +13402,13 @@
 msgid "file at URI '%s' is not a bundle or bundle list"
 msgstr "filen på URI:en \"%s\" är inte en bunt eller buntlista"
 
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: okänt argument: \"%s\""
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: förväntade \"flush\" efter argument"
+
 msgid "bundle-uri: got an empty line"
 msgstr "bunt-uri: fick en tom rad"
 
@@ -13384,6 +13440,13 @@
 msgid "need a repository to verify a bundle"
 msgstr "behöver ett arkiv för att bekräfta en bunt."
 
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+"några förutsättande incheckningar finns i objektkatalogen, men är inte "
+"anslutna i arkivets historik"
+
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -14789,15 +14852,22 @@
 msgstr "okänt objektformat \"%s\" angavs av servern"
 
 #, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "fel på bundle-uri-svar rad %d: %s"
+
+msgid "expected flush after bundle-uri listing"
+msgstr "förväntade \"flush\" efter bundle-uri-listan"
+
+msgid "expected response end packet after ref listing"
+msgstr "förväntade svarsavslutningspaket efter ref-listan"
+
+#, c-format
 msgid "invalid ls-refs response: %s"
 msgstr "ogiltigt svar på ls-refs: %s"
 
 msgid "expected flush after ref listing"
 msgstr "förväntade \"flush\" efter ref-listan"
 
-msgid "expected response end packet after ref listing"
-msgstr "förväntade svarsavslutningspaket efter ref-listan"
-
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr "protokollet \"%s\" stöds inte"
@@ -15945,8 +16015,7 @@
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-"           <command> [<args>]"
+"           [--config-env=<name>=<envvar>] <command> [<args>]"
 msgstr ""
 "git [-v | --version] [-h |--help] [-C <sökväg>] [-c <namn>=<värde>]\n"
 "           [--exec-path[=<sökväg>]] [--html-path] [--man-path] [--info-"
@@ -15954,8 +16023,7 @@
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<sökväg>] [--work-tree=<sökväg>] [--namespace=<namn>]\n"
-"           [--super-prefix=<sökväg>] [--config-env=<namn>=<miljövar>]\n"
-"           <kommando> [<flaggor>]"
+"           [--config-env=<namn>=<miljövar>] <kommando> [<flaggor>]"
 
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -15981,10 +16049,6 @@
 msgstr "ingen namnrymd angavs för --namespace\n"
 
 #, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "inget prefix angavs för --super-prefix\n"
-
-#, c-format
 msgid "-c expects a configuration string\n"
 msgstr "-c förväntar en konfigurationssträng\n"
 
@@ -16096,8 +16160,13 @@
 msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
 msgstr "gpg.ssh.defaultKeyCommand misslyckades: %s %s"
 
-msgid "gpg failed to sign the data"
-msgstr "gpg misslyckades signera data"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg misslyckades signera data:\n"
+"%s"
 
 msgid "user.signingKey needs to be set for ssh signing"
 msgstr "user.signingKey måste anges för ssh-signering"
@@ -17229,6 +17298,10 @@
 msgstr "skräp i slutet av löst objekt \"%s\""
 
 #, c-format
+msgid "unable to open loose object %s"
+msgstr "kan inte öppna lösa objekt %s"
+
+#, c-format
 msgid "unable to parse %s header"
 msgstr "kan inte tolka %s-huvud"
 
@@ -17244,18 +17317,14 @@
 msgstr "huvudet för %s är för långt, mer än %d byte"
 
 #, c-format
-msgid "failed to read object %s"
-msgstr "misslyckades läsa objektet %s"
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "löst objekt %s (lagrat i %s) är trasigt"
 
 #, c-format
 msgid "replacement %s not found for %s"
 msgstr "ersättningen %s hittades inte för %s"
 
 #, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "löst objekt %s (lagrat i %s) är trasigt"
-
-#, c-format
 msgid "packed object %s (stored in %s) is corrupt"
 msgstr "packat objekt %s (lagrat i %s) är trasigt"
 
@@ -17267,9 +17336,6 @@
 msgid "unable to set permission to '%s'"
 msgstr "kan inte sätta behörigheten till \"%s\""
 
-msgid "file write error"
-msgstr "fel vid skrivning av fil"
-
 msgid "error when closing loose object file"
 msgstr "fel vid stängning av fil för löst objekt"
 
@@ -17316,11 +17382,12 @@
 msgid "cannot read object for %s"
 msgstr "kan inte läsa objekt för %s"
 
-msgid "corrupt commit"
-msgstr "trasik incheckning"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "objekt klarar inte fsck: %s"
 
-msgid "corrupt tag"
-msgstr "trasig tagg"
+msgid "refusing to create malformed object"
+msgstr "vägrar skapa ett felaktigt format objekt"
 
 #, c-format
 msgid "read error while indexing %s"
@@ -17581,10 +17648,6 @@
 msgid "cannot fstat bitmap file"
 msgstr "kan inte utföra \"fstat\" på bitkartefil"
 
-#, c-format
-msgid "ignoring extra bitmap file: '%s'"
-msgstr "ignorerar extra bitkartefil: %s"
-
 msgid "checksum doesn't match in MIDX and bitmap"
 msgstr "checksumman stämmer inte i MIDX och bitkarta"
 
@@ -17849,6 +17912,9 @@
 msgid "use <n> digits to display object names"
 msgstr "använd <n> siffror för att visa objektnamn"
 
+msgid "prefixed path to initial superproject"
+msgstr "inledande sökväg till start-överprojekt"
+
 msgid "how to strip spaces and #comments from message"
 msgstr "hur blanksteg och #kommentarer ska tas bort från meddelande"
 
@@ -18351,6 +18417,14 @@
 msgstr "före %d, bakom %d"
 
 #, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) tar inte argument"
+
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "okänt %%(%.*s)-argument: %s"
+
+#, c-format
 msgid "expected format: %%(color:<color>)"
 msgstr "förväntat format: %%(color:<color>)"
 
@@ -18367,22 +18441,6 @@
 msgstr "Heltalsvärde förväntades refname:rstrip=%s"
 
 #, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "okänt %%(%s)-argument: %s"
-
-#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) tar inte argument"
-
-#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) tar inte argument"
-
-#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) tar inte argument"
-
-#, c-format
 msgid "expected %%(trailers:key=<value>)"
 msgstr "förväntade %%(trailers:key=<värde>)"
 
@@ -18399,10 +18457,6 @@
 msgstr "positivt värde förväntat \"%s\" i %%(%s)"
 
 #, c-format
-msgid "unrecognized email option: %s"
-msgstr "okänd e-postalternativ: %s"
-
-#, c-format
 msgid "expected format: %%(align:<width>,<position>)"
 msgstr "förväntat format: %%(align:<bredd>,<position>)"
 
@@ -18415,12 +18469,12 @@
 msgstr "okänd bredd:%s"
 
 #, c-format
-msgid "positive width expected with the %%(align) atom"
-msgstr "positiv bredd förväntad med atomen %%(align)"
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "okänt %%(%s)-argument: %s"
 
 #, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) tar inte argument"
+msgid "positive width expected with the %%(align) atom"
+msgstr "positiv bredd förväntad med atomen %%(align)"
 
 #, c-format
 msgid "malformed field name: %.*s"
@@ -19656,6 +19710,22 @@
 msgstr "git %s: misslyckades uppdatera indexet"
 
 #, c-format
+msgid "'%s' is not a valid label"
+msgstr "\"%s\" är inte en giltig etikett"
+
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "\"%s\" är inte ett giltigt referensnamn"
+
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr "update-ref kräver ett fullständigt referensnamn, t.ex refs/heads/%s"
+
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "ogiltigt kommando \"%.*s\""
+
+#, c-format
 msgid "%s does not accept arguments: '%s'"
 msgstr "%s tar inte argument: \"%s\""
 
@@ -20453,6 +20523,16 @@
 msgid "failed to lstat '%s'"
 msgstr "misslyckades ta status (lstat) på \"%s\""
 
+msgid "no remote configured to get bundle URIs from"
+msgstr "ingen fjärr att hämta bunt-URI:er från inställd"
+
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "fjärren \"%s\" har ingen URL konfigurerad"
+
+msgid "could not get the bundle-uri list"
+msgstr "kunde inte hämta bundle-uri-listan"
+
 msgid "test-tool cache-tree <options> (control|prime|update)"
 msgstr "test-tool cache-tree <flaggor> (control|prime|update)"
 
@@ -20806,6 +20886,12 @@
 msgid "failed to push all needed submodules"
 msgstr "kunde inte sända alla nödvändiga undermoduler"
 
+msgid "bundle-uri operation not supported by protocol"
+msgstr "bundle-uri-funktionen stöds inte av protokollet"
+
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr "kunde inte hämta bundle-uri-listan som servern annonserade"
+
 msgid "too-short tree object"
 msgstr "trädobjekt för kort"
 
@@ -21540,13 +21626,18 @@
 
 #, c-format
 msgid ""
-"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-"may speed it up, but you have to be careful not to forget to add\n"
-"new files yourself (see 'git help status')."
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
 msgstr ""
-"Det tog %.2f sekunder att räkna upp ospårade filer. \"status -uno\"\n"
-"kan gå snabbare, men du måste vara försiktig så du inte glömmer\n"
-"lägga till nya filer själv (se \"git help status\")."
+"Det tog %.2f sekunder att räkna upp ospårade filer,\n"
+"men resultaten cachelagrades och senare körningar kan bli snabbare."
+
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr "Det tog %.2f sekunder att räkna upp ospårade filer."
+
+msgid "See 'git help status' for information on how to improve this."
+msgstr "Se \"git help status\" för information om hur du kan förbättra detta."
 
 # %s är nästa sträng eller tom.
 #, c-format
@@ -21689,274 +21780,6 @@
 msgid "Unable to determine absolute path of git directory"
 msgstr "Kunde inte bestämma absolut sökväg till git-katalogen"
 
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#, perl-format
-msgid "%12s %12s %s"
-msgstr "%12s %12s %s"
-
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] "rörde %d sökväg\n"
-msgstr[1] "rörde %d sökvägar\n"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr ""
-"Om patchen kan appliceras rent kommer det redigerade stycket att\n"
-"köas omedelbart."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr ""
-"Om patchen kan appliceras rent kommer det redigerade stycket att\n"
-"läggas till i \"stash\" omedelbart."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr ""
-"Om patchen kan appliceras rent kommer det redigerade stycket att\n"
-"tas bort från kön omedelbart."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr ""
-"Om patchen kan appliceras rent kommer det redigerade stycket att\n"
-"markeras för applicering omedelbart."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr ""
-"Om patchen kan appliceras rent kommer det redigerade stycket att\n"
-"markeras för kasta omedelbart."
-
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr "misslyckades öppna styckeredigeringsfil för skrivning: %s"
-
-#, perl-format
-msgid ""
-"---\n"
-"To remove '%s' lines, make them ' ' lines (context).\n"
-"To remove '%s' lines, delete them.\n"
-"Lines starting with %s will be removed.\n"
-msgstr ""
-"---\n"
-"Ta bort \"%s\" rader genom att göra dem \" \"-rader (sammanhang).\n"
-"Ta bort \"%s\" rader genom att radera dem.\n"
-"Rader som börjar med %s kommer att tas bort.\n"
-
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr "misslyckades öppna styckesredigeringsfil för läsning: %s"
-
-msgid ""
-"y - stage this hunk\n"
-"n - do not stage this hunk\n"
-"q - quit; do not stage this hunk or any of the remaining ones\n"
-"a - stage this hunk and all later hunks in the file\n"
-"d - do not stage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - köa stycket\n"
-"n - köa inte stycket\n"
-"q - avsluta; köa inte stycket eller något av de följande\n"
-"a - köa stycket och alla följande i filen\n"
-"d - köa inte stycket eller något av de följande i filen"
-
-msgid ""
-"y - stash this hunk\n"
-"n - do not stash this hunk\n"
-"q - quit; do not stash this hunk or any of the remaining ones\n"
-"a - stash this hunk and all later hunks in the file\n"
-"d - do not stash this hunk or any of the later hunks in the file"
-msgstr ""
-"y - \"stash\":a stycket\n"
-"n - \"stash\":a inte stycket\n"
-"q - avsluta; \"stash\":a inte stycket eller något av de följande\n"
-"a - \"stash\":a stycket och alla följande i filen\n"
-"d - \"stash\":a inte stycket eller något av de följande i filen"
-
-msgid ""
-"y - unstage this hunk\n"
-"n - do not unstage this hunk\n"
-"q - quit; do not unstage this hunk or any of the remaining ones\n"
-"a - unstage this hunk and all later hunks in the file\n"
-"d - do not unstage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - ta bort stycket från kön\n"
-"n - ta inte bort stycket från kön\n"
-"q - avsluta; ta inte bort stycket eller något av de följande från kön\n"
-"a - ta bort stycket och alla följande i filen från kön\n"
-"d - ta inte bort stycket eller något av de följande i filen från kön"
-
-msgid ""
-"y - apply this hunk to index\n"
-"n - do not apply this hunk to index\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - applicera stycket på indexet\n"
-"n - applicera inte stycket på indexet\n"
-"q - avsluta; applicera inte stycket eller något av de följande\n"
-"a - applicera stycket och alla följande i filen\n"
-"d - applicera inte stycket eller något av de följande i filen"
-
-msgid ""
-"y - discard this hunk from worktree\n"
-"n - do not discard this hunk from worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - förkasta stycket från arbetskatalogen\n"
-"n - förkasta inte stycket från arbetskatalogen\n"
-"q - avsluta; förkasta inte stycket eller något av de följande\n"
-"a - förkasta stycket och alla följande i filen\n"
-"d - förkasta inte stycket eller något av de följande i filen"
-
-msgid ""
-"y - discard this hunk from index and worktree\n"
-"n - do not discard this hunk from index and worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - förkasta stycket från indexet och arbetskatalogen\n"
-"n - förkasta inte stycket från indexet och arbetskatalogen\n"
-"q - avsluta; förkasta inte stycket eller något av de följande\n"
-"a - förkasta stycket och alla följande i filen\n"
-"d - förkasta inte stycket eller något av de följande i filen"
-
-msgid ""
-"y - apply this hunk to index and worktree\n"
-"n - do not apply this hunk to index and worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - applicera stycket på indexet och arbetskatalogen\n"
-"n - applicera inte stycket på indexet och arbetskatalogen\n"
-"q - avsluta; applicera inte stycket eller något av de följande\n"
-"a - applicera stycket och alla följande i filen\n"
-"d - applicera inte stycket eller något av de följande i filen"
-
-msgid ""
-"y - apply this hunk to worktree\n"
-"n - do not apply this hunk to worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - applicera stycket på arbetskatalogen\n"
-"n - applicera inte stycket på arbetskatalogen\n"
-"q - avsluta; applicera inte stycket eller något av de följande\n"
-"a - applicera stycket och alla följande i filen\n"
-"d - applicera inte stycket eller något av de följande i filen"
-
-msgid ""
-"g - select a hunk to go to\n"
-"/ - search for a hunk matching the given regex\n"
-"j - leave this hunk undecided, see next undecided hunk\n"
-"J - leave this hunk undecided, see next hunk\n"
-"k - leave this hunk undecided, see previous undecided hunk\n"
-"K - leave this hunk undecided, see previous hunk\n"
-"s - split the current hunk into smaller hunks\n"
-"e - manually edit the current hunk\n"
-"? - print help\n"
-msgstr ""
-"g - välj ett stycke att gå till\n"
-"/ - sök efter stycke som motsvarar angivet reguljärt uttryck\n"
-"j - lämna stycket obestämt, se nästa obestämda stycke\n"
-"J - lämna stycket obestämt, se nästa stycke\n"
-"k - lämna stycket obestämt, se föregående obestämda stycke\n"
-"K - lämna stycket obestämt, se föregående stycke\n"
-"s - dela aktuellt stycke i mindre styckens\n"
-"e - redigera aktuellt stycke manuellt\n"
-"? - visa hjälp\n"
-
-msgid "The selected hunks do not apply to the index!\n"
-msgstr "Markerade stycken kan inte appliceras på indexet!\n"
-
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "ignorerar ej sammanslagen: %s\n"
-
-msgid "No other hunks to goto\n"
-msgstr "Inga andra stycken att gå till\n"
-
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "Ogiltigt siffervärde: \"%s\"\n"
-
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "Beklagar, det finns bara %d stycke.\n"
-msgstr[1] "Beklagar, det finns bara %d stycken.\n"
-
-msgid "No other hunks to search\n"
-msgstr "Inga andra stycken att söka efter\n"
-
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "Felaktigt format på reguljärt sökuttryck %s: %s\n"
-
-msgid "No hunk matches the given pattern\n"
-msgstr "Inga stycken motsvarar givet mönster\n"
-
-msgid "No previous hunk\n"
-msgstr "Inget föregående stycke\n"
-
-msgid "No next hunk\n"
-msgstr "Inget följande stycke\n"
-
-msgid "Sorry, cannot split this hunk\n"
-msgstr "Beklagar, kan inte dela stycket\n"
-
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "Dela i %d stycke.\n"
-msgstr[1] "Dela i %d stycken.\n"
-
-msgid "Sorry, cannot edit this hunk\n"
-msgstr "Beklagar, kan inte redigera stycket\n"
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-msgid ""
-"status        - show paths with changes\n"
-"update        - add working tree state to the staged set of changes\n"
-"revert        - revert staged set of changes back to the HEAD version\n"
-"patch         - pick hunks and update selectively\n"
-"diff          - view diff between HEAD and index\n"
-"add untracked - add contents of untracked files to the staged set of "
-"changes\n"
-msgstr ""
-"status        - visa sökvägar med ändringar\n"
-"update        - lägg arbetskatalogens tillstånd till köade ändringar\n"
-"revert        - återställ köade ändringar till HEAD-versionen\n"
-"patch         - välj och uppdatera valda stycken\n"
-"diff          - visa diff mellan HEAD och index\n"
-"add untracked - lägg till innehåll i ospårade filer till köade ändringar\n"
-
-msgid "missing --"
-msgstr "saknad --"
-
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "okänt läge för --patch: %s"
-
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "felaktigt argument %s, förväntar --"
-
 msgid "local zone differs from GMT by a non-minute interval\n"
 msgstr "lokal zon skiljer sig från GMT med delar av minuter\n"
 
diff --git a/po/tr.po b/po/tr.po
index 9afdc23..a24a7ae 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -1,8 +1,8 @@
 # Turkish translations for Git
 # Git Türkçe çevirileri
-# Copyright (C) 2020-2022 Emir SARI <emir_sari@icloud.com>
+# Copyright (C) 2020-2023 Emir SARI <emir_sari@icloud.com>
 # This file is distributed under the same license as the Git package.
-# Emir SARI <emir_sari@icloud.com>, 2020-2022
+# Emir SARI <emir_sari@icloud.com>, 2020-2023
 #
 # ######################################################### #
 #     Git Türkçe kavramlar dizini / Git Turkish Glossary    #
@@ -92,8 +92,8 @@
 msgstr ""
 "Project-Id-Version: Git Turkish Localization Project\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-12-07 17:32+0300\n"
-"PO-Revision-Date: 2022-12-07 18:00+0300\n"
+"POT-Creation-Date: 2023-03-03 11:32+0300\n"
+"PO-Revision-Date: 2023-03-03 11:40+0300\n"
 "Last-Translator: Emir SARI <emir_sari@icloud.com>\n"
 "Language-Team: Turkish (https://github.com/bitigchi/git-po/)\n"
 "Language: tr\n"
@@ -128,13 +128,13 @@
 msgid "could not write index"
 msgstr "indeks yazılamadı"
 
-#, c-format, perl-format
+#, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "%d yol güncellendi\n"
 msgstr[1] "%d yol güncellendi\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "not: %s artık izlenmiyor.\n"
 
@@ -148,7 +148,7 @@
 msgid "Could not parse HEAD^{tree}"
 msgstr "HEAD^{tree} ayrıştırılamadı"
 
-#, c-format, perl-format
+#, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "%d yol geri alındı\n"
@@ -161,7 +161,7 @@
 msgid "Add untracked"
 msgstr "İzlenmeyenleri ekle"
 
-#, c-format, perl-format
+#, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "%d yol eklendi\n"
@@ -255,19 +255,19 @@
 msgid "Bye.\n"
 msgstr "Güle güle.\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "Kip değişimi hazırlansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "Silme hazırlansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "Ekleme hazırlansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Bu parça hazırlansın mı [y,n,q,a,d%s,?]? "
 
@@ -291,19 +291,19 @@
 "a - bu parçayı ve sonraki tüm parçaları hazırla\n"
 "d - bu parçayı veya sonraki parçalardan herhangi birini hazırlama\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "Kip değişimi zulalansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "Silme zulalansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "Ekleme zulalansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "Bu parça zulalansın mı [y,n,q,a,d%s,?]? "
 
@@ -327,19 +327,19 @@
 "a - bu parçayı ve sonraki tüm parçaları zulala\n"
 "d - bu parçayı veya sonraki parçalardan herhangi birini zulalama\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "Kip değişimi hazırlıktan çıkarılsın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "Silme hazırlıktan çıkarılsın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "Ekleme hazırlıktan çıkarılsın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Bu parça hazırlıktan çıkarılsın mı [y,n,q,a,d%s,?]? "
 
@@ -363,19 +363,19 @@
 "a - bu parçayı ve sonraki tüm parçaları hazırlıktan çıkar\n"
 "d - bu parçayı veya sonraki parçalardan herhangi birini hazırlıktan çıkarma\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr "Kip değişimi indekse uygulansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "Silme indekse uygulansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "Ekleme indekse uygulansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "Bu parça indekse uygulansın mı [y,n,q,a,d%s,?]? "
 
@@ -399,19 +399,19 @@
 "a - bu parçayı ve sonraki tüm parçaları uygula\n"
 "d - bu parçayı veya sonraki parçalardan herhangi birini uygulama\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr "Kip değişimi çalışma ağacından atılsın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "Silme çalışma ağacından atılsın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "Ekleme çalışma ağacından atılsın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
 msgstr "Bu parça çalışma ağacından atılsın mı [y,n,q,a,d%s,?]? "
 
@@ -435,20 +435,20 @@
 "a - bu parçayı ve sonraki tüm parçaları at\n"
 "d - bu parçayı veya sonraki parçalardan herhangi birini atma\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Kip değişimi indeksten ve çalışma ağacından atılsın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Silme indeksten ve çalışma ağacından atılsın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Ekleme indeksten ve çalışma ağacından atılsın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Bu parça indeksten ve çalışma ağacından atılsın mı [y,n,q,a,d%s,?]? "
 
@@ -465,20 +465,20 @@
 "a - bu parçayı ve sonraki tüm parçaları at\n"
 "d - bu parçayı veya sonraki parçalardan herhangi birini atma\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Kip değişimi indekse ve çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Silme indekse ve çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Ekleme indekse ve çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Bu parça indekse ve çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
 
@@ -495,19 +495,19 @@
 "a - bu parçayı ve sonraki tüm parçaları uygula\n"
 "d - bu parçayı veya sonraki parçalardan herhangi birini uygulama\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
 msgstr "Kip değişimi çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
 msgstr "Silme çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
 msgstr "Ekleme çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
 msgstr "Bu parça çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
 
@@ -583,8 +583,6 @@
 "'%c' satır kaldırmak için onları silin.\n"
 "%c kaldırılacak.\n"
 
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
 "edit again.  If all lines of the hunk are removed, then the edit is\n"
@@ -600,20 +598,12 @@
 msgid "'git apply --cached' failed"
 msgstr "'git apply --cached' başarısız oldu"
 
-#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr ""
@@ -1444,6 +1434,12 @@
 msgid "report archived files on stderr"
 msgstr "arşivlenmiş dosyaları stderr'de raporla"
 
+msgid "time"
+msgstr "zaman"
+
+msgid "set modification time of archive entries"
+msgstr "arşiv girdilerinin değiştirilme zamanını ayarla"
+
 msgid "set compression level"
 msgstr "sıkıştırma düzeyini ayarla"
 
@@ -1484,6 +1480,13 @@
 msgid "%.*s is not a valid attribute name"
 msgstr "%.*s geçerli bir öznitelik adı değil"
 
+msgid "unable to add additional attribute"
+msgstr "ek öznitelik eklenemiyor"
+
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "pek uzun öznitelik satırı %d yok sayılıyor"
+
 #, c-format
 msgid "%s not allowed: %s:%d"
 msgstr "%s izin verilmiyor: %s:%d"
@@ -1496,6 +1499,18 @@
 "Gerçek öncü ünlem için '\\!' kullanın."
 
 #, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "fstat gitattributes dosyası '%s' bulunamıyor"
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "pek büyük gitattributes dosyası '%s' dosyası yok sayılıyor"
+
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "pek büyük gitattributes ikili nesnesi '%s' yok sayılıyor"
+
+#, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "'%s' dosyasında hatalı tırnağa alınmış içerik: %s"
 
@@ -1771,11 +1786,11 @@
 
 #, c-format
 msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
 msgstr ""
-"Altmodülleri güncellemeyi 'git checkout %s && git submodule update --init' "
-"kullanarak deneyebilirsiniz"
+"'git checkout --no-recurse-submodules %s && git submodule update --init' "
+"kullanarak altmodülleri güncellemeyi deneyebilirsiniz"
 
 #, c-format
 msgid "submodule '%s': cannot create branch '%s'"
@@ -1810,6 +1825,13 @@
 msgid "Unstaged changes after refreshing the index:"
 msgstr "İndeksi yeniledikten sonra hazırlanmamış değişiklikler:"
 
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"add.interactive.useBuiltin ayarı kaldırıldı!\n"
+"Ayrıntılar için onun 'git help config' içindeki girdisine bakın."
+
 msgid "Could not read the index"
 msgstr "İndeks okunamadı"
 
@@ -2200,6 +2222,9 @@
 msgid "run interactively"
 msgstr "etkileşimli olarak çalıştır"
 
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "pre-applypatch ve applypatch-msg kancalarını atla"
+
 msgid "historical option -- no-op"
 msgstr "tarihi seçenek -- no-op"
 
@@ -2342,32 +2367,27 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: Floş bekleniyordu"
 
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [<işleme>]"
-
 msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<terim> --term-{old,good}"
-"=<terim>] [--no-checkout] [--first-parent] [<kötü> [<iyi>...]] [--] "
-"[<yollar>...]"
+"git bisect start [--term-{new,bad}=<terim> --term-{old,good}=<terim>]    [--"
+"no-checkout] [--first-parent] [<kötü> [<iyi>...]] [--]    [<yol-blrtç>...]"
 
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (bad|new) [<rev>]"
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<rev>...]"
 
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (good|old) [<rev>...]"
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<rev>|<erim>)...]"
 
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay <dosyaadı>"
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<işleme>]"
 
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(<rev>|<erim>)...]"
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <günlük-dosyası>"
 
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run <komut>..."
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run <komut>..."
 
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
@@ -2511,9 +2531,6 @@
 msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
 msgstr "'%s' çıkış yapımı başarısız. 'git bisect start <geçerli-dal>' deneyin."
 
-msgid "won't bisect on cg-seek'ed tree"
-msgstr "cg-seek yapılmış bir ağaçta ikili arama yapılmayacak"
-
 msgid "bad HEAD - strange symbolic ref"
 msgstr "hatalı HEAD - tuhaf sembolik başvuru"
 
@@ -2565,17 +2582,16 @@
 msgstr "ikili arama başarısız: Komut verilmedi."
 
 #, c-format
-msgid "unable to verify '%s' on good revision"
-msgstr "'%s', iyi revizyonda doğrulanamadı"
+msgid "unable to verify %s on good revision"
+msgstr "%s, iyi revizyonda doğrulanamıyor"
 
 #, c-format
 msgid "bogus exit code %d for good revision"
 msgstr "iyi revizyon için anlamsız %d çıkış kodu"
 
 #, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
-msgstr ""
-"bisect çalıştırılamadı: çıkış kodu %d, '%s' konumundan, < 0 veya >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
+msgstr "bisect çalıştırılamadı: çıkış kodu %d, %s konumundan, < 0 veya >= 128"
 
 #, c-format
 msgid "cannot open file '%s' for writing"
@@ -2584,37 +2600,42 @@
 msgid "bisect run cannot continue any more"
 msgstr "ikili arama artık çalışmayı sürdüremiyor"
 
-#, c-format
 msgid "bisect run success"
 msgstr "ikili arama başarılı"
 
-#, c-format
 msgid "bisect found first bad commit"
 msgstr "ikili arama ilk hatalı işlemeyi buldu"
 
 #, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
-msgstr ""
-"ikili arama çalıştırılamadı: 'git bisect--helper --bisect-state %s', %d hata "
-"koduyla çıktı"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
+msgstr "ikili arama çalıştırılamadı: 'git bisect %s', %d hata koduyla çıktı"
 
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "--bisect-reset bir argüman veya işleme gerektirmiyor"
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "'%s', bir argüman veya işleme gerektirmiyor"
 
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "--bisect-terms 0 veya 1 argüman gerektiriyor"
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "'%s', 0 veya 1 argümanı gerektiriyor"
 
-msgid "--bisect-next requires 0 arguments"
-msgstr "--bisect-next 0 argüman gerektiriyor"
-
-msgid "--bisect-log requires 0 arguments"
-msgstr "--bisect-log 0 argüman gerektiriyor"
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "'%s', 0 argüman gerektiriyor"
 
 msgid "no logfile given"
 msgstr "hiçbir günlük dosyası verilmedi"
 
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "'%s' başarısız: Komut verilmedi."
+
+msgid "need a command"
+msgstr "bir komut gerekli"
+
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "bilinmeyen komut: '%s'"
+
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 msgstr "git blame [<seçenekler>] [<rev-sçnk>] [<rev>] [--] <dosya>"
 
@@ -2744,7 +2765,7 @@
 msgstr[1] "%s dosyasında yalnızca %lu satır var"
 
 msgid "Blaming lines"
-msgstr "Genel bakış satırları"
+msgstr "Satırlara bakılıyor"
 
 msgid "git branch [<options>] [-r | -a] [--merged] [--no-merged]"
 msgstr "git branch [<seçenekler>] [-r | -a] [--merged] [--no-merged]"
@@ -3181,6 +3202,9 @@
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
 msgstr "git bundle unbundle [--progress] <dosya> [<başvuru-adı>...]"
 
+msgid "need a <file> argument"
+msgstr "bir <dosya> argümanı gerekiyor"
+
 msgid "do not show progress meter"
 msgstr "ilerleme çubuğunu gösterme"
 
@@ -3234,10 +3258,6 @@
 msgid "%s takes no arguments"
 msgstr "%s, bir argüman almıyor"
 
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "bilinmeyen komut: '%s'"
-
 msgid "only one batch option may be specified"
 msgstr "yalnızca bir toplu iş seçeneği belirtilebilir"
 
@@ -3373,11 +3393,18 @@
 msgid "only two arguments allowed in <type> <object> mode, not %d"
 msgstr "<tür> <nesne> kipinde yalnızca iki argümana izin veriliyor, %d değil"
 
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | <öznitelik>...] [--] <yol-adı>..."
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [--source <ağacımsı>] [-a | --all | <öznitelik>...] [--] <yol-"
+"adı>..."
 
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | <öznitelik>...]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source <ağacımsı>] [-a | --all | "
+"<öznitelik>...]"
 
 msgid "report all attributes set on file"
 msgstr "tüm dosya özniteliklerini bildir"
@@ -3391,6 +3418,12 @@
 msgid "terminate input and output records by a NUL character"
 msgstr "girdi ve çıktı kayıtlarını bir NUL karakteri ile sonlandır"
 
+msgid "<tree-ish>"
+msgstr "<ağacımsı>"
+
+msgid "which tree-ish to check attributes at"
+msgstr "özniteliklerin hangi ağacımsıda denetleneceği"
+
 msgid "suppress progress reporting"
 msgstr "ilerleme bildirimini gizle"
 
@@ -3967,7 +4000,7 @@
 "*          - tüm ögeleri seç\n"
 "           - (boş) seçimi bitir\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Huh (%s)?\n"
 msgstr "Pardon (%s)?\n"
 
@@ -4116,9 +4149,6 @@
 msgid "create a shallow clone of that depth"
 msgstr "verilen derinlikte sığ bir depo oluştur"
 
-msgid "time"
-msgstr "zaman"
-
 msgid "create a shallow clone since a specific time"
 msgstr "verilen zamandan sonrasını içeren bir sığ depo oluştur"
 
@@ -4346,6 +4376,9 @@
 msgid "failed to fetch objects from bundle URI '%s'"
 msgstr "'%s' demet URI'sinden nesneler getirilemedi"
 
+msgid "failed to fetch advertised bundles"
+msgstr "tanıtılan demetler alınamadı"
+
 msgid "remote transport reported error"
 msgstr "uzak konum taşıması hata bildirdi"
 
@@ -5589,29 +5622,6 @@
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "--extcmd=<komut> için bir <komut> verilmedi"
 
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] <seçenekler> <ortam-dğşkn>"
-
-msgid "default for git_env_*(...) to fall back on"
-msgstr "git_env_*(...)'ın geri çekileceği öntanımlı"
-
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr "sessiz ol, yalnızca git_env_*() değerini çıkış kodu olarak kullan"
-
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr ""
-"--default seçeneği, --type=bool ile birlikte bir Boole değeri bekliyor, '%s' "
-"değil"
-
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not "
-"`%s`"
-msgstr ""
-"--default seçeneği, --type=ulong ile birlikte bir imzalanmamış uzun değer "
-"bekliyor, '%s' değil"
-
 msgid "git fast-export [<rev-list-opts>]"
 msgstr "git fast-export [<revizyon-listesi-seçenekleri>]"
 
@@ -6009,6 +6019,10 @@
 msgid "--unshallow on a complete repository does not make sense"
 msgstr "tam bir depo üzerinde --unshallow bir anlam ifade etmiyor"
 
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "'%s' konumundan demetler getirilemedi"
+
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all bir depo argümanı almıyor"
 
@@ -7028,12 +7042,19 @@
 msgid "'git help config' for more information"
 msgstr "ek bilgi için: 'git help config'"
 
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] <kanca-adı> [-- <kanca-argümanları>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=<yol>] <kanca-adı> [-- <kanca-"
+"argümanları>]"
 
 msgid "silently ignore missing requested <hook-name>"
 msgstr "istenen eksik <kanca-adı> sessizce yok sayılıyor"
 
+msgid "file to read into hooks' stdin"
+msgstr "kancaların stdin'ine okunacak dosya"
+
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "%s konumunda nesne türü uyuşmazlığı"
@@ -7856,11 +7877,11 @@
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<yürütülebilir>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<anahtar>]\n"
-"              [--symref] [<depo> [<başvurular>...]]"
+"              [--symref] [<depo> [<dizgiler>...]]"
 
 msgid "do not print remote URL"
 msgstr "uzak konum URL'sini yazdırma"
@@ -8104,9 +8125,15 @@
 msgid "perform multiple merges, one per line of input"
 msgstr "girdi satırı başına bir adet çoklu birleştirmeler gerçekleştir"
 
+msgid "specify a merge-base for the merge"
+msgstr "birleştirme için bir birleştirme temeli belirtilmeli"
+
 msgid "--trivial-merge is incompatible with all other options"
 msgstr "--trivial-merge, tüm diğer seçeneklerle uyumsuz"
 
+msgid "--merge-base is incompatible with --stdin"
+msgstr "--merge-base, --stdin ile uyumsuz"
+
 #, c-format
 msgid "malformed input line: '%s'."
 msgstr "hatalı oluşturulmuş girdi satırı: '%s'."
@@ -9985,6 +10012,9 @@
 msgid "could not switch to %s"
 msgstr "şuraya geçilemedi: %s"
 
+msgid "apply options and merge options cannot be used together"
+msgstr "uygulama seçenekleri ve birleştirme seçenekleri birlikte kullanılamaz"
+
 #, c-format
 msgid ""
 "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
@@ -10220,8 +10250,19 @@
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy, --merge veya --interactive gerektiriyor"
 
-msgid "apply options and merge options cannot be used together"
-msgstr "uygulama seçenekleri ve birleştirme seçenekleri birlikte kullanılamaz"
+msgid ""
+"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"autosquash"
+msgstr ""
+"uygulama seçenekleri, rebase.autosquash ile uyumlu değil. --no-autosquash "
+"eklemeyi düşünün"
+
+msgid ""
+"apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
+"update-refs"
+msgstr ""
+"uygulama seçenekleri, rebase.updateRefs ile uyumlu değil. --no-update-refs "
+"eklemeyi düşünün"
 
 #, c-format
 msgid "Unknown rebase backend: %s"
@@ -12698,10 +12739,6 @@
 msgid "git submodule--helper <command>"
 msgstr "git submodule--helper <komut>"
 
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s, --super-prefix desteklemiyor"
-
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
 msgstr "git symbolic-ref [-m <neden>] <ad> <başvuru>"
 
@@ -13426,6 +13463,10 @@
 msgstr "core.fsyncMethod = batch, bu platformda desteklenmiyor"
 
 #, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr "demet liste anahtarı %s ile '%s' değeri ayrıştırılamıyor"
+
+#, c-format
 msgid "bundle list at '%s' has no mode"
 msgstr "'%s' konumundaki demet listesinin kipi yok"
 
@@ -13436,6 +13477,13 @@
 msgstr "yetersiz yetenekler"
 
 #, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "'%s' konumundan indirilen dosya bir demet değil"
+
+msgid "failed to store maximum creation token"
+msgstr "en büyük oluşturma jetonu depolanamadı"
+
+#, c-format
 msgid "unrecognized bundle mode from URI '%s'"
 msgstr "'%s' URI'sinden tanımlanamayan demet kipi"
 
@@ -13451,6 +13499,13 @@
 msgid "file at URI '%s' is not a bundle or bundle list"
 msgstr "'%s' URI'sindeki dosya bir demet veya demet listesi değil"
 
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: beklenmedik argüman: '%s'"
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: argümanlardan sonra floş bekleniyordu"
+
 msgid "bundle-uri: got an empty line"
 msgstr "bundle-uri: boş bir satır alındı"
 
@@ -13482,6 +13537,13 @@
 msgid "need a repository to verify a bundle"
 msgstr "bir demeti doğrulamak için bir depo gerekiyor"
 
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+"nesne deposunda bazı önkoşul işlemeleri var; ancak deponun geçmişine bağlı "
+"değiller"
+
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -14882,15 +14944,22 @@
 msgstr "sunucu tarafından bilinmeyen nesne biçimi '%s' belirtildi"
 
 #, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "bundle-uri %d. yanıt satırında hata: %s"
+
+msgid "expected flush after bundle-uri listing"
+msgstr "bundle-uri listelemesinden sonra floş bekleniyordu"
+
+msgid "expected response end packet after ref listing"
+msgstr "başvuru listelemesinden sonra yanıt sonu paketi bekleniyordu"
+
+#, c-format
 msgid "invalid ls-refs response: %s"
 msgstr "geçersiz ls-refs yanıtı: %s"
 
 msgid "expected flush after ref listing"
 msgstr "başvuru listelemesinden sonra floş bekleniyordu"
 
-msgid "expected response end packet after ref listing"
-msgstr "başvuru listelemesinden sonra yanıt sonu paketi bekleniyordu"
-
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr "'%s' protokolü desteklenmiyor"
@@ -16041,16 +16110,14 @@
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-"           <command> [<args>]"
+"           [--config-env=<name>=<envvar>] <command> [<args>]"
 msgstr ""
 "git [-v | --version] [-h | --help] [-C <yol>] [-c <ad>=<değer>]\n"
 "           [--exec-path[=<yol>]] [--html-path] [--man-path] [--info-path]\n"
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<yol>] [--work-tree=<yol>] [--namespace=<ad>]\n"
-"           [--super-prefix=<yol>] [--config-env=<ad>=<çevredeğişkeni>]\n"
-"           <komut> [<argümanlar>]"
+"           [--config-env=<ad>=<çevre-değişkeni>] <komut> [<argümanlar>]"
 
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -16076,10 +16143,6 @@
 msgstr "--namespace için ad alanı verilmedi\n"
 
 #, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "--super-prefix için önek verilmedi\n"
-
-#, c-format
 msgid "-c expects a configuration string\n"
 msgstr "-c bir yapılandırma dizisi bekliyor\n"
 
@@ -16194,8 +16257,13 @@
 msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
 msgstr "gpg.ssh.defaultKeyCommand başarısız oldu: %s %s"
 
-msgid "gpg failed to sign the data"
-msgstr "gpg veriyi imzalayamadı"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg veriyi imzalayamadı:\n"
+"%s"
 
 msgid "user.signingKey needs to be set for ssh signing"
 msgstr "user.signingKey'in ssh imzalaması için ayarlanması gerekiyor"
@@ -17336,6 +17404,10 @@
 msgstr "gevşek nesne '%s' sonunda anlamsız veri"
 
 #, c-format
+msgid "unable to open loose object %s"
+msgstr "gevşek nesne %s açılamıyor"
+
+#, c-format
 msgid "unable to parse %s header"
 msgstr "%s üstbilgisi ayrıştırılamıyor"
 
@@ -17351,18 +17423,14 @@
 msgstr "%s üstbilgisi pek uzun, %d bayt'ı aşıyor"
 
 #, c-format
-msgid "failed to read object %s"
-msgstr "%s nesnesi okunamadı"
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "%s gevşek nesnesi (%s içinde depolanıyor) hasarlı"
 
 #, c-format
 msgid "replacement %s not found for %s"
 msgstr "%s yedeği %s için bulunamadı"
 
 #, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "%s gevşek nesnesi (%s içinde depolanıyor) hasarlı"
-
-#, c-format
 msgid "packed object %s (stored in %s) is corrupt"
 msgstr "paketlenmiş nesne %s (%s içinde depolanıyor) hasarlı"
 
@@ -17374,9 +17442,6 @@
 msgid "unable to set permission to '%s'"
 msgstr "'%s' ögesine izin ayarlanamıyor"
 
-msgid "file write error"
-msgstr "dosya yazım hatası"
-
 msgid "error when closing loose object file"
 msgstr "gevşek nesne dosyası kapatılırken hata"
 
@@ -17422,11 +17487,12 @@
 msgid "cannot read object for %s"
 msgstr "%s için nesne okunamıyor"
 
-msgid "corrupt commit"
-msgstr "hasarlı işleme"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "nesne fsck'yi başarısız ediyor: %s"
 
-msgid "corrupt tag"
-msgstr "hasarlı etiket"
+msgid "refusing to create malformed object"
+msgstr "hatalı oluşturulmuş nesne oluşturma reddediliyor"
 
 #, c-format
 msgid "read error while indexing %s"
@@ -17690,10 +17756,6 @@
 msgid "cannot fstat bitmap file"
 msgstr "biteşlem dosyası fstat yapılamıyor"
 
-#, c-format
-msgid "ignoring extra bitmap file: '%s'"
-msgstr "ek biteşlem dosyası yok sayılıyor: '%s'"
-
 msgid "checksum doesn't match in MIDX and bitmap"
 msgstr "sağlama toplamı, MIDX ve biteşlem içinde uymuyor"
 
@@ -17956,6 +18018,9 @@
 msgid "use <n> digits to display object names"
 msgstr "nesne adlarını görüntülemek için <n> basamak kullan"
 
+msgid "prefixed path to initial superproject"
+msgstr "yol, ilk üst projeye öneklendi"
+
 msgid "how to strip spaces and #comments from message"
 msgstr "iletiden boşlukları ve #yorumları çıkart"
 
@@ -18448,6 +18513,14 @@
 msgstr "%d önünde, %d arkasında"
 
 #, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) argüman almıyor"
+
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "tanımlanamayan %%(%.*s) argümanı: %s"
+
+#, c-format
 msgid "expected format: %%(color:<color>)"
 msgstr "beklenen biçim: %%(color:<renk>)"
 
@@ -18464,22 +18537,6 @@
 msgstr "Tamsayı değeri şunu bekliyordu: refname:rstrip=%s"
 
 #, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "tanımlanamayan %%(%s) argümanı: %s"
-
-#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) argüman almıyor"
-
-#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) argüman almıyor"
-
-#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) argüman almıyor"
-
-#, c-format
 msgid "expected %%(trailers:key=<value>)"
 msgstr "%%(trailers:key=<değer>) bekleniyordu"
 
@@ -18496,10 +18553,6 @@
 msgstr "pozitif değer şurada '%s' bekliyordu: %%(%s)"
 
 #, c-format
-msgid "unrecognized email option: %s"
-msgstr "tanımlanamayan e-posta seçeneği: %s"
-
-#, c-format
 msgid "expected format: %%(align:<width>,<position>)"
 msgstr "beklenen biçim: %%(align:<genişlik>,<konum>)"
 
@@ -18512,12 +18565,12 @@
 msgstr "tanımlanamayan genişlik:%s"
 
 #, c-format
-msgid "positive width expected with the %%(align) atom"
-msgstr "pozitif genişlik %%(align) ögeciği ile birlikte bekleniyordu"
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "tanımlanamayan %%(%s) argümanı: %s"
 
 #, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) argüman almıyor"
+msgid "positive width expected with the %%(align) atom"
+msgstr "pozitif genişlik %%(align) ögeciği ile birlikte bekleniyordu"
 
 #, c-format
 msgid "malformed field name: %.*s"
@@ -19755,6 +19808,23 @@
 msgstr "git %s: indeks yenilenemedi"
 
 #, c-format
+msgid "'%s' is not a valid label"
+msgstr "'%s', geçerli bir etiket değil"
+
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "'%s', geçerli bir başvuru adı değil"
+
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr ""
+"update-ref, tümüyle kalifiye bir başvuru adı gerektiriyor; örn. refs/heads/%s"
+
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "geçersiz komut %.*s"
+
+#, c-format
 msgid "%s does not accept arguments: '%s'"
 msgstr "%s argüman kabul etmiyor: '%s'"
 
@@ -20549,6 +20619,16 @@
 msgid "failed to lstat '%s'"
 msgstr "'%s', lstat yapılamadı"
 
+msgid "no remote configured to get bundle URIs from"
+msgstr "demet URI'lerini almak için bir uzak konum yapılandırılmamış"
+
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "'%s' uzak konumunun yapılandırılmış bir URL'si yok"
+
+msgid "could not get the bundle-uri list"
+msgstr "bundle-uri listesi alınamadı"
+
 msgid "test-tool cache-tree <options> (control|prime|update)"
 msgstr "test-tool cache-tree <seçenekler> (control|prime|update)"
 
@@ -20900,6 +20980,12 @@
 msgid "failed to push all needed submodules"
 msgstr "gereken tüm altmodüller itilemedi"
 
+msgid "bundle-uri operation not supported by protocol"
+msgstr "bundle-uri işlemi protokol tarafından desteklenmiyor"
+
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr "sunucu tarafından tanıtılan bundle-uri listesi alınamadı"
+
 msgid "too-short tree object"
 msgstr "ağaç nesnesi çok kısa"
 
@@ -21629,13 +21715,18 @@
 
 #, c-format
 msgid ""
-"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-"may speed it up, but you have to be careful not to forget to add\n"
-"new files yourself (see 'git help status')."
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
 msgstr ""
-"İzlenmeyen dosyaların ortaya dökülmesi %.2f saniye sürdü. 'status -uno'\n"
-"bunu hızlandırabilir; ancak yeni dosyaları eklemeyi unutmamanız\n"
-"konusunda dikkatli olmalısınız (ek bilgi için 'git help status')."
+"İzlenmeyen dosyaları ortaya dökme %.2f saniye sürdü;\n"
+"ancak sonuçlar önbelleğe alındı ve sonrakiler daha hızlı olabilir."
+
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr "İzlenmeyen dosyaları ortaya dökme %.2f saniye sürdü."
+
+msgid "See 'git help status' for information on how to improve this."
+msgstr "Bunu iyileştirme üzerine bilgi için 'git help status'a bakın."
 
 #, c-format
 msgid "Untracked files not listed%s"
@@ -21650,7 +21741,8 @@
 #, c-format
 msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
 msgstr ""
-"İşlemeye eklenen değişiklik yok (\"git add\" ve/veya \"git commit -a\" kullanın)\n"
+"İşlemeye eklenen değişiklik yok (\"git add\" ve/veya \"git commit -a\" "
+"kullanın)\n"
 
 #, c-format
 msgid "no changes added to commit\n"
@@ -21778,275 +21870,6 @@
 msgid "Unable to determine absolute path of git directory"
 msgstr "Git dizininin kesin yolu algılanamıyor"
 
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#, perl-format
-msgid "%12s %12s %s"
-msgstr "%12s %12s %s"
-
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] "%d yola dokunuldu\n"
-msgstr[1] "%d yola dokunuldu\n"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr ""
-"Eğer yama sorunsuzca uygulanırsa düzenlenen parça derhal hazırlama\n"
-"için imlenecektir."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr ""
-"Eğer yama sorunsuzca uygulanırsa düzenlenen parça derhal zulalama\n"
-"için imlenecektir."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr ""
-"Eğer yama sorunsuzca uygulanırsa, düzenlenen parça derhal hazırlıktan\n"
-"çıkarılma için imlenecektir."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr ""
-"Eğer yama sorunsuzca uygulanırsa düzenlenen parça derhal uygulama\n"
-"için imlenecektir."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr ""
-"Eğer yama sorunsuzca uygulanırsa düzenlenen parça derhal ıskartaya\n"
-"çıkarım için imlenecektir."
-
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr "parça düzenleme dosyası yazım için açılamadı: %s"
-
-#, perl-format
-msgid ""
-"---\n"
-"To remove '%s' lines, make them ' ' lines (context).\n"
-"To remove '%s' lines, delete them.\n"
-"Lines starting with %s will be removed.\n"
-msgstr ""
-"---\n"
-"'%s' satır kaldırmak için onları ' ' satır yapın (bağlam).\n"
-"'%s' satır kaldırmak için onları silin.\n"
-"%s ile başlayan satırlar kaldırılacaktır.\n"
-
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr "parça düzenleme dosyası okuma için açılamadı: %s"
-
-msgid ""
-"y - stage this hunk\n"
-"n - do not stage this hunk\n"
-"q - quit; do not stage this hunk or any of the remaining ones\n"
-"a - stage this hunk and all later hunks in the file\n"
-"d - do not stage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - bu parçayı hazırla\n"
-"n - bu parçayı hazırlama\n"
-"q - çık; bu parçayı veya kalanlardan herhangi birini hazırlama\n"
-"a - bu parçayı ve sonraki tüm parçaları hazırla\n"
-"d - bu parçayı veya sonraki parçalardan herhangi birini hazırlama"
-
-msgid ""
-"y - stash this hunk\n"
-"n - do not stash this hunk\n"
-"q - quit; do not stash this hunk or any of the remaining ones\n"
-"a - stash this hunk and all later hunks in the file\n"
-"d - do not stash this hunk or any of the later hunks in the file"
-msgstr ""
-"y - bu parçayı zulala\n"
-"n - bu parçayı zulalama\n"
-"q - çık; bu parçayı veya kalanlardan herhangi birini zulalama\n"
-"a - bu parçayı ve sonraki tüm parçaları zulala\n"
-"d - bu parçayı veya sonraki parçalardan herhangi birini zulalama"
-
-msgid ""
-"y - unstage this hunk\n"
-"n - do not unstage this hunk\n"
-"q - quit; do not unstage this hunk or any of the remaining ones\n"
-"a - unstage this hunk and all later hunks in the file\n"
-"d - do not unstage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - bu parçayı hazırlıktan çıkar\n"
-"n - bu parçayı hazırlıktan çıkarma\n"
-"q - çık; bu parçayı veya kalanlardan herhangi birini hazırlıktan çıkarma\n"
-"a - bu parçayı ve sonraki tüm parçaları hazırlıktan çıkar\n"
-"d - bu parçayı veya sonraki parçalardan herhangi birini hazırlıktan çıkarma"
-
-msgid ""
-"y - apply this hunk to index\n"
-"n - do not apply this hunk to index\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - bu parçayı indekse uygula\n"
-"n - bu parçayı indekse uygulama\n"
-"q - çık; bu parçayı veya kalanlardan herhangi birini uygulama\n"
-"a - bu parçayı ve sonraki tüm parçaları uygula\n"
-"d - bu parçayı veya sonraki parçalardan herhangi birini uygulama"
-
-msgid ""
-"y - discard this hunk from worktree\n"
-"n - do not discard this hunk from worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - bu parçayı çalışma ağacından at\n"
-"n - bu parçayı çalışma ağacından atma\n"
-"q - çık; bu parçayı veya kalanlardan herhangi birini atma\n"
-"a - bu parçayı ve sonraki tüm parçaları at\n"
-"d - bu parçayı veya sonraki parçalardan herhangi birini atma"
-
-msgid ""
-"y - discard this hunk from index and worktree\n"
-"n - do not discard this hunk from index and worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - bu parçayı çalışma ağacından ve indeksten at\n"
-"n - bu parçayı çalışma ağacından ve indeksten atma\n"
-"q - çık; bu parçayı veya kalanlardan herhangi birini atma\n"
-"a - bu parçayı ve sonraki tüm parçaları at\n"
-"d - bu parçayı veya sonraki parçalardan herhangi birini atma"
-
-msgid ""
-"y - apply this hunk to index and worktree\n"
-"n - do not apply this hunk to index and worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - bu parçayı indekse ve çalışma ağacına uygula\n"
-"n - bu parçayı indekse ve çalışma ağacına uygulama\n"
-"q - çık; bu parçayı veya kalanlardan herhangi birini uygulama\n"
-"a - bu parçayı ve sonraki tüm parçaları uygula\n"
-"d - bu parçayı veya sonraki parçalardan herhangi birini uygulama"
-
-msgid ""
-"y - apply this hunk to worktree\n"
-"n - do not apply this hunk to worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - bu parçayı çalışma ağacına uygula\n"
-"n - bu parçayı çalışma ağacına uygulama\n"
-"q - çık; bu parçayı veya kalanlardan herhangi birini uygulama\n"
-"a - bu parçayı ve sonraki tüm parçaları uygula\n"
-"d - bu parçayı veya sonraki parçalardan herhangi birini uygulama"
-
-msgid ""
-"g - select a hunk to go to\n"
-"/ - search for a hunk matching the given regex\n"
-"j - leave this hunk undecided, see next undecided hunk\n"
-"J - leave this hunk undecided, see next hunk\n"
-"k - leave this hunk undecided, see previous undecided hunk\n"
-"K - leave this hunk undecided, see previous hunk\n"
-"s - split the current hunk into smaller hunks\n"
-"e - manually edit the current hunk\n"
-"? - print help\n"
-msgstr ""
-"g - gidilecek bir parça seç\n"
-"/ - verilen düzenli ifade ile eşleşen bir parça ara\n"
-"j - bu parça için sonra karar ver, bir sonraki karar verilmemiş parçayı gör\n"
-"J - bu parça için sonra karar ver, bir sonraki parçayı gör\n"
-"k - bu parça için sonra karar ver, bir önceki karar verilmemiş parçayı gör\n"
-"K - bu parça için sonra karar ver, bir önceki parçayı gör\n"
-"s - geçerli parçayı daha ufak parçalara böl\n"
-"e - geçerli parçayı el ile düzenle\n"
-"? - yardımı yazdır\n"
-
-msgid "The selected hunks do not apply to the index!\n"
-msgstr "Seçili parçalar indekse uygulanamıyor!\n"
-
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "birleştirilmeyenler yok sayılıyor: %s\n"
-
-msgid "No other hunks to goto\n"
-msgstr "Gidilecek başka parça yok\n"
-
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "Geçersiz sayı: '%s'\n"
-
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "Üzgünüm, yalnızca %d parça kullanılabilir.\n"
-msgstr[1] "Üzgünüm, yalnızca %d parça kullanılabilir.\n"
-
-msgid "No other hunks to search\n"
-msgstr "Aranacak başka parça yok\n"
-
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "Hatalı oluşturulmuş arama düzenli ifadesi %s: %s\n"
-
-msgid "No hunk matches the given pattern\n"
-msgstr "Verilen dizgi ile hiçbir parça eşleşmiyor\n"
-
-msgid "No previous hunk\n"
-msgstr "Öncesinde parça yok\n"
-
-msgid "No next hunk\n"
-msgstr "Sonrasında parça yok\n"
-
-msgid "Sorry, cannot split this hunk\n"
-msgstr "Üzgünüm, bu parça bölünemiyor\n"
-
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "%d parçaya bölündü.\n"
-msgstr[1] "%d parçaya bölündü.\n"
-
-msgid "Sorry, cannot edit this hunk\n"
-msgstr "Üzgünüm, bu parça düzenlenemiyor\n"
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-msgid ""
-"status        - show paths with changes\n"
-"update        - add working tree state to the staged set of changes\n"
-"revert        - revert staged set of changes back to the HEAD version\n"
-"patch         - pick hunks and update selectively\n"
-"diff          - view diff between HEAD and index\n"
-"add untracked - add contents of untracked files to the staged set of "
-"changes\n"
-msgstr ""
-"status        - değişiklik içeren yolları göster\n"
-"update        - çalışma ağacı durumunu hazırlanan değişiklik setine ekle\n"
-"revert        - hazırlanan değişiklik setini HEAD sürümüne geri al\n"
-"patch         - parçaları seç ve seçici olarak güncelle\n"
-"diff          - HEAD ve indeks arasındaki diff'i (ayrımları) görüntüle\n"
-"add untracked - izlenmeyen dosyaların içeriğini hazırlanan değişiklik setine "
-"ekle\n"
-
-msgid "missing --"
-msgstr "-- eksik"
-
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "bilinmeyen --patch kipi: %s"
-
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "geçersiz argüman %s, -- bekleniyor"
-
 msgid "local zone differs from GMT by a non-minute interval\n"
 msgstr "yerel dilim GMT'den bir dakikadan az bir aralıkla ayrımlı\n"
 
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 1a0026a..2b88f9b 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -139,14 +139,14 @@
 #   upstream                         |  上游
 #   upstream branch                  |  上游分支
 #   working tree                     |  工作区
-# Fangyi Zhou <me@fangyi.io>, 2021-2022.
+# Fangyi Zhou <me@fangyi.io>, 2021-2023.
 #
 msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-12-01 14:04+0000\n"
-"PO-Revision-Date: 2022-12-01 14:17+0000\n"
+"POT-Creation-Date: 2023-03-07 23:37+0000\n"
+"PO-Revision-Date: 2023-03-07 23:40+0000\n"
 "Last-Translator: Fangyi Zhou <me@fangyi.io>\n"
 "Language-Team: GitHub <https://github.com/fangyi-zhou/git-po/>\n"
 "Language: zh_CN\n"
@@ -165,19 +165,19 @@
 msgid "could not read index"
 msgstr "不能读取索引"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "binary"
 msgstr "二进制"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "nothing"
 msgstr "无"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "unchanged"
 msgstr "没有修改"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Update"
 msgstr "更新"
 
@@ -190,15 +190,15 @@
 msgid "could not write index"
 msgstr "不能写入索引"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "更新了 %d 个路径\n"
 msgstr[1] "更新了 %d 个路径\n"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "说明:%s 现已成为未跟踪的。\n"
 
@@ -207,7 +207,7 @@
 msgid "make_cache_entry failed for path '%s'"
 msgstr "对路径 '%s' 的 make_cache_entry 操作失败"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Revert"
 msgstr "还原"
 
@@ -215,24 +215,24 @@
 msgid "Could not parse HEAD^{tree}"
 msgstr "不能解析 HEAD^{tree}"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "还原了 %d 个路径\n"
 msgstr[1] "还原了 %d 个路径\n"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 #, c-format
 msgid "No untracked files.\n"
 msgstr "没有未跟踪的文件。\n"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Add untracked"
 msgstr "添加未跟踪的"
 
-#: add-interactive.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-interactive.c
+#, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "增加了 %d 个路径\n"
@@ -243,21 +243,21 @@
 msgid "ignoring unmerged: %s"
 msgstr "忽略未合入的:%s"
 
-#: add-interactive.c add-patch.c git-add--interactive.perl
+#: add-interactive.c add-patch.c
 #, c-format
 msgid "Only binary files changed.\n"
 msgstr "只有二进制文件被修改。\n"
 
-#: add-interactive.c add-patch.c git-add--interactive.perl
+#: add-interactive.c add-patch.c
 #, c-format
 msgid "No changes.\n"
 msgstr "没有修改。\n"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Patch update"
 msgstr "补丁更新"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "Review diff"
 msgstr "检视 diff"
 
@@ -325,25 +325,25 @@
 msgid "(empty) select nothing"
 msgstr "(空)不选择任何内容"
 
-#: add-interactive.c builtin/clean.c git-add--interactive.perl
+#: add-interactive.c builtin/clean.c
 msgid "*** Commands ***"
 msgstr "*** 命令 ***"
 
-#: add-interactive.c builtin/clean.c git-add--interactive.perl
+#: add-interactive.c builtin/clean.c
 msgid "What now"
 msgstr "请选择"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "staged"
 msgstr "缓存"
 
-#: add-interactive.c git-add--interactive.perl
+#: add-interactive.c
 msgid "unstaged"
 msgstr "未缓存"
 
 #: add-interactive.c apply.c builtin/am.c builtin/bugreport.c builtin/clone.c
-#: builtin/diagnose.c builtin/fetch.c builtin/merge.c builtin/pull.c
-#: builtin/submodule--helper.c git-add--interactive.perl
+#: builtin/diagnose.c builtin/fetch.c builtin/hook.c builtin/merge.c
+#: builtin/pull.c builtin/submodule--helper.c
 msgid "path"
 msgstr "路径"
 
@@ -351,28 +351,28 @@
 msgid "could not refresh index"
 msgstr "不能刷新索引"
 
-#: add-interactive.c builtin/clean.c git-add--interactive.perl
+#: add-interactive.c builtin/clean.c
 #, c-format
 msgid "Bye.\n"
 msgstr "再见。\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "暂存模式变更 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "暂存删除动作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "暂存添加动作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "暂存该块 [y,n,q,a,d%s,?]? "
 
@@ -396,23 +396,23 @@
 "a - 暂存该块和本文件中后面的全部块\n"
 "d - 不暂存该块和本文件中后面的全部块\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "贮藏模式变更 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "贮藏删除动作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "贮藏添加动作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "贮藏该块 [y,n,q,a,d%s,?]? "
 
@@ -436,23 +436,23 @@
 "a - 贮藏该块和本文件中后面的全部块\n"
 "d - 不贮藏该块和本文件中后面的全部块\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "取消暂存模式变更 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "取消暂存删除动作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "取消暂存添加动作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "取消暂存该块 [y,n,q,a,d%s,?]? "
 
@@ -476,23 +476,23 @@
 "a - 取消暂存该块和本文件中后面的全部块\n"
 "d - 不要取消暂存该块和本文件中后面的全部块\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr "将模式变更应用到索引 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "将删除操作应用到索引 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "将添加操作应用到索引 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "将该块应用到索引 [y,n,q,a,d%s,?]? "
 
@@ -516,23 +516,23 @@
 "a - 应用该块和本文件中后面的全部块\n"
 "d - 不要应用该块和本文件中后面的全部块\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr "从工作区中丢弃模式变更 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "从工作区中丢弃删除动作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "从工作区中丢弃添加动作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
 msgstr "从工作区中丢弃该块 [y,n,q,a,d%s,?]? "
 
@@ -556,23 +556,23 @@
 "a - 丢弃该块和本文件中后面的全部块\n"
 "d - 不要丢弃该块和本文件中后面的全部块\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "从索引和工作区中丢弃模式变更 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "从索引和工作区中丢弃删除动作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "从索引和工作区中丢弃添加动作 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "从索引和工作区中丢弃该块 [y,n,q,a,d%s,?]? "
 
@@ -590,23 +590,23 @@
 "a - 丢弃该块和本文件中后面的全部块\n"
 "d - 不要丢弃该块和本文件中后面的全部块\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "将模式变更应用到索引和工作区 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "将删除操作应用到索引和工作区 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "将添加操作应用到索引和工作区 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "将该块应用到索引和工作区 [y,n,q,a,d%s,?]? "
 
@@ -624,23 +624,23 @@
 "a - 应用该块和本文件中后面的全部块\n"
 "d - 不要应用该块和本文件中后面的全部块\n"
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
 msgstr "将模式变更应用到工作区 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
 msgstr "将删除操作应用到工作区 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
 msgstr "将添加操作应用到工作区 [y,n,q,a,d%s,?]? "
 
-#: add-patch.c git-add--interactive.perl
-#, c-format, perl-format
+#: add-patch.c
+#, c-format
 msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
 msgstr "将该块应用到工作区 [y,n,q,a,d%s,?]? "
 
@@ -708,7 +708,7 @@
 "\t不是结尾于:\n"
 "%.*s"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "Manual hunk edit mode -- see bottom for a quick guide.\n"
 msgstr "手动块编辑模式 -- 查看底部的快速指南。\n"
 
@@ -725,9 +725,7 @@
 "要删除 '%c' 开始的行,删除它们。\n"
 "以 %c 开始的行将被删除。\n"
 
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
 "edit again.  If all lines of the hunk are removed, then the edit is\n"
@@ -744,21 +742,13 @@
 msgid "'git apply --cached' failed"
 msgstr "'git apply --cached' 失败"
 
-#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr "您的编辑块不能被应用。重新编辑(选择 \"no\" 丢弃!) [y/n]? "
@@ -767,11 +757,11 @@
 msgid "The selected hunks do not apply to the index!"
 msgstr "选中的块不能应用到索引!"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "Apply them to the worktree anyway? "
 msgstr "无论如何都要应用到工作区么?"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "Nothing was applied.\n"
 msgstr "未应用。\n"
 
@@ -809,11 +799,11 @@
 msgid "No other hunks to goto"
 msgstr "没有其它可供跳转的块"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "go to which hunk (<ret> to see more)? "
 msgstr "跳转到哪个块(<回车> 查看更多)? "
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "go to which hunk? "
 msgstr "跳转到哪个块?"
 
@@ -833,7 +823,7 @@
 msgid "No other hunks to search"
 msgstr "没有其它可供查找的块"
 
-#: add-patch.c git-add--interactive.perl
+#: add-patch.c
 msgid "search for regex? "
 msgstr "使用正则表达式搜索?"
 
@@ -1413,7 +1403,7 @@
 msgid "unable to add cache entry for %s"
 msgstr "无法为 %s 添加缓存条目"
 
-#: apply.c builtin/bisect--helper.c builtin/gc.c
+#: apply.c builtin/bisect.c builtin/gc.c
 #, c-format
 msgid "failed to write to '%s'"
 msgstr "无法写入 '%s'"
@@ -1748,7 +1738,7 @@
 msgid "archive format"
 msgstr "归档格式"
 
-#: archive.c builtin/log.c
+#: archive.c builtin/log.c parse-options.h
 msgid "prefix"
 msgstr "前缀"
 
@@ -1782,6 +1772,15 @@
 msgid "report archived files on stderr"
 msgstr "在标准错误上报告归档文件"
 
+#: archive.c builtin/clone.c builtin/fetch.c builtin/pack-objects.c
+#: builtin/pull.c
+msgid "time"
+msgstr "时间"
+
+#: archive.c
+msgid "set modification time of archive entries"
+msgstr "设置归档条目的修改时间"
+
 #: archive.c
 msgid "set compression level"
 msgstr "设置压缩级别"
@@ -1838,6 +1837,15 @@
 msgstr "%.*s 不是一个有效的属性名"
 
 #: attr.c
+msgid "unable to add additional attribute"
+msgstr "不能添加额外属性"
+
+#: attr.c
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "忽略过长的属性行 %d"
+
+#: attr.c
 #, c-format
 msgid "%s not allowed: %s:%d"
 msgstr "不允许 %s:%s:%d"
@@ -1850,6 +1858,21 @@
 "负值模版在 git attributes 中被忽略\n"
 "当字符串确实要以感叹号开始时,使用 '\\!'。"
 
+#: attr.c
+#, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "无法 fstat gitattributes 文件 '%s'"
+
+#: attr.c
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "忽略过大的 gitattributes 文件 '%s'"
+
+#: attr.c
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "忽略过大的 gitattributes 数据对象 '%s'"
+
 #: bisect.c
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
@@ -1982,8 +2005,8 @@
 msgstr "--reverse 和 --first-parent 共用,需要指定最新的提交"
 
 #: blame.c builtin/commit.c builtin/log.c builtin/merge.c
-#: builtin/pack-objects.c builtin/shortlog.c bundle.c midx.c pack-bitmap.c
-#: ref-filter.c remote.c sequencer.c submodule.c
+#: builtin/pack-objects.c builtin/shortlog.c midx.c pack-bitmap.c ref-filter.c
+#: remote.c sequencer.c submodule.c
 msgid "revision walk setup failed"
 msgstr "版本遍历初始化失败"
 
@@ -2161,10 +2184,11 @@
 #: branch.c
 #, c-format
 msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
 msgstr ""
-"你可以用 'git checkout %s && git submodule update --init' 来尝试更新子模组"
+"你可以用 'git checkout --no-recurse-submodules %s && git submodule update --"
+"init' 来尝试更新子模组"
 
 #: branch.c
 #, c-format
@@ -2208,6 +2232,14 @@
 msgid "Unstaged changes after refreshing the index:"
 msgstr "刷新索引之后尚未被暂存的变更:"
 
+#: builtin/add.c
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"设置 add.interactive.useBuiltin 已经被移除!\n"
+"查看 'git help config' 中的相关条目以获取更多信息。"
+
 #: builtin/add.c builtin/rev-parse.c
 msgid "Could not read the index"
 msgstr "不能读取索引"
@@ -2659,7 +2691,7 @@
 "Not rewinding to ORIG_HEAD"
 msgstr "您好像在上一次 'am' 失败后移动了 HEAD。未回退至 ORIG_HEAD"
 
-#: builtin/am.c builtin/bisect--helper.c worktree.c
+#: builtin/am.c builtin/bisect.c worktree.c
 #, c-format
 msgid "failed to read '%s'"
 msgstr "无法读取 '%s'"
@@ -2682,6 +2714,10 @@
 msgstr "以交互式方式运行"
 
 #: builtin/am.c
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "绕过 pre-applypatch 和 applypatch-msg 钩子"
+
+#: builtin/am.c
 msgid "historical option -- no-op"
 msgstr "老的参数 —— 无作用"
 
@@ -2870,110 +2906,105 @@
 msgid "git archive: expected a flush"
 msgstr "git archive:应有一个 flush 包"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [<提交>]"
-
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<术语> --term-{old,good}"
-"=<术语>] [--no-checkout] [--first-parent] [<坏> [<好>...]] [--] [<路径>...]"
+"git bisect start [--term-{new,bad}=<术语> --term-{old,good}=<术语>]    [--no-"
+"checkout] [--first-parent] [<坏> [<好>...]] [--]    [<路径规格>...]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (bad|new) [<版本>]"
+#: builtin/bisect.c
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<版本>...]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (good|old) [<版本>...]"
+#: builtin/bisect.c
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<版本>|<范围>)...]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay <文件>"
+#: builtin/bisect.c
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<提交>]"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(<版本>|<范围>)...]"
+#: builtin/bisect.c
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <日志文件>"
 
-#: builtin/bisect--helper.c
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run <命令>..."
+#: builtin/bisect.c
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run <命令>..."
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
 msgstr "不能以 '%2$s' 模式打开文件 '%1$s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "could not write to file '%s'"
 msgstr "不能写入文件 '%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' for reading"
 msgstr "不能打开文件 '%s' 来读取"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' is not a valid term"
 msgstr "'%s' 不是一个有效的术语"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "can't use the builtin command '%s' as a term"
 msgstr "不能使用内置命令 '%s' 作为术语"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "can't change the meaning of the term '%s'"
 msgstr "不能修改术语 '%s' 的含义"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "please use two different terms"
 msgstr "请使用两个不同的术语"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "We are not bisecting.\n"
 msgstr "我们没有在二分查找。\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' is not a valid commit"
 msgstr "'%s' 不是一个有效的提交"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "could not check out original HEAD '%s'. Try 'git bisect reset <commit>'."
 msgstr "不能检出原始 HEAD '%s'。尝试 'git bisect reset <提交>'。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Bad bisect_write argument: %s"
 msgstr "坏的 bisect_write 参数:%s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "couldn't get the oid of the rev '%s'"
 msgstr "无法获取版本 '%s' 的对象 ID"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "couldn't open the file '%s'"
 msgstr "无法打开文件 '%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Invalid command: you're currently in a %s/%s bisect"
 msgstr "无效的命令:您当前正处于一个 %s/%s 二分查找中"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "You need to give me at least one %s and %s revision.\n"
@@ -2982,7 +3013,7 @@
 "您需要给我至少一个 %s 和一个 %s 版本。\n"
 "为此您可以用 \"git bisect %s\" 和 \"git bisect %s\"。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "You need to start by \"git bisect start\".\n"
@@ -2993,7 +3024,7 @@
 "然后需要提供我至少一个 %s 和一个 %s 版本。\n"
 "为此您可以用 \"git bisect %s\" 和 \"git bisect %s\" 命令。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "bisecting only with a %s commit"
 msgstr "在只有一个 %s 提交的情况下二分查找"
@@ -3002,37 +3033,37 @@
 #. translation. The program will only accept English input
 #. at this point.
 #.
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "Are you sure [Y/n]? "
 msgstr "您确认么[Y/n]? "
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "status: waiting for both good and bad commits\n"
 msgstr "状态:正在等待好的和坏的提交\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "status: waiting for bad commit, %d good commit known\n"
 msgid_plural "status: waiting for bad commit, %d good commits known\n"
 msgstr[0] "状态:正在等待坏的提交,已知 %d 个好的提交\n"
 msgstr[1] "状态:正在等待坏的提交,已知 %d 个好的提交\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "status: waiting for good commit(s), bad commit known\n"
 msgstr "状态:正在等待好的提交,已知坏的提交\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "no terms defined"
 msgstr "未定义术语"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "Your current terms are %s for the old state\n"
 "and %s for the new state.\n"
 msgstr "您当前针对旧状态的术语是 %s,对新状态的术语是 %s。\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "invalid argument %s for 'git bisect terms'.\n"
@@ -3041,52 +3072,48 @@
 "命令 'git bisect terms' 的参数 %s 无效。\n"
 "支持的选项有:--term-good|--term-old 和 --term-bad|--term-new。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "revision walk setup failed\n"
 msgstr "版本遍历设置失败\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "无法打开 '%s' 进行追加"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "'' is not a valid term"
 msgstr "'' 不是一个有效的术语"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "unrecognized option: '%s'"
 msgstr "未识别的选项:'%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' does not appear to be a valid revision"
 msgstr "'%s' 看起来不是一个有效的版本"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bad HEAD - I need a HEAD"
 msgstr "坏的 HEAD - 我需要一个 HEAD"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
 msgstr "检出 '%s' 失败。尝试 'git bisect start <有效分支>'。"
 
-#: builtin/bisect--helper.c
-msgid "won't bisect on cg-seek'ed tree"
-msgstr "不会在做了 cg-seek 的树上做二分查找"
-
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bad HEAD - strange symbolic ref"
 msgstr "坏的 HEAD - 奇怪的符号引用"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "invalid ref: '%s'"
 msgstr "无效的引用:'%s'"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "You need to start by \"git bisect start\"\n"
 msgstr "您需要执行 \"git bisect start\" 来开始\n"
 
@@ -3094,113 +3121,122 @@
 #. translation. The program will only accept English input
 #. at this point.
 #.
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "Do you want me to do it for you [Y/n]? "
 msgstr "您想让我为您这样做么[Y/n]? "
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "Please call `--bisect-state` with at least one argument"
 msgstr "请使用至少一个参数调用 `--bisect-state`"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'git bisect %s' can take only one argument."
 msgstr "'git bisect %s' 只能带一个参数。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Bad rev input: %s"
 msgstr "坏的版本输入:%s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "Bad rev input (not a commit): %s"
 msgstr "坏的版本输入(不是提交):%s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "We are not bisecting."
 msgstr "我们没有在二分查找。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "'%s'?? what are you talking about?"
 msgstr "'%s'?? 您在说什么?"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot read file '%s' for replaying"
 msgstr "不能读取文件 '%s' 来重放"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "running %s\n"
 msgstr "正在执行 %s\n"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bisect run failed: no command provided."
 msgstr "二分查找运行失败:没有提供命令。"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
-msgid "unable to verify '%s' on good revision"
-msgstr "无法在好版本中验证 '%s'"
+msgid "unable to verify %s on good revision"
+msgstr "无法在好版本中验证 %s"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "bogus exit code %d for good revision"
 msgstr "好版本返回错误的退出码 %d"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
-msgstr "二分查找运行失败:命令 '%2$s' 的退出码 %1$d < 0 或 >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
+msgstr "二分查找运行失败:命令 %2$s 的退出码 %1$d < 0 或 >= 128"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' for writing"
 msgstr "无法打开文件 '%s' 进行写入"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "bisect run cannot continue any more"
 msgstr "二分查找不能继续运行"
 
-#: builtin/bisect--helper.c
-#, c-format
+#: builtin/bisect.c
 msgid "bisect run success"
 msgstr "二分查找运行成功"
 
-#: builtin/bisect--helper.c
-#, c-format
+#: builtin/bisect.c
 msgid "bisect found first bad commit"
 msgstr "二分查找找到了第一个坏的提交"
 
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 #, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
-msgstr "二分查找运行失败:'git bisect--helper --bisect-state %s' 退出码为 %d"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
+msgstr "二分查找运行失败:'git bisect %s' 退出码为 %d"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "--bisect-reset 无需参数或者需要一个提交"
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "'%s' 无需参数或者需要一个提交"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "--bisect-terms 需要 0 或 1 个参数"
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "'%s' 无需参数或者需要一个参数"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-next requires 0 arguments"
-msgstr "--bisect-next 需要 0 个参数"
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "'%s' 无需参数"
 
-#: builtin/bisect--helper.c
-msgid "--bisect-log requires 0 arguments"
-msgstr "--bisect-log 需要 0 个参数"
-
-#: builtin/bisect--helper.c
+#: builtin/bisect.c
 msgid "no logfile given"
 msgstr "未提供日志文件"
 
+#: builtin/bisect.c
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "'%s' 运行失败:没有提供命令。"
+
+#: builtin/bisect.c
+msgid "need a command"
+msgstr "需要一个命令"
+
+#: builtin/bisect.c builtin/cat-file.c
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "未知命令:'%s'"
+
 #: builtin/blame.c
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 msgstr "git blame [<选项>] [<版本选项>] [<版本>] [--] <文件>"
@@ -3912,6 +3948,10 @@
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
 msgstr "git bundle unbundle [--progress] <文件> [<引用名>...]"
 
+#: builtin/bundle.c
+msgid "need a <file> argument"
+msgstr "需要一个 <文件> 参数"
+
 #: builtin/bundle.c builtin/pack-objects.c
 msgid "do not show progress meter"
 msgstr "不显示进度表"
@@ -3982,11 +4022,6 @@
 msgstr "%s 不需要参数"
 
 #: builtin/cat-file.c
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "未知命令:'%s'"
-
-#: builtin/cat-file.c
 msgid "only one batch option may be specified"
 msgstr "只能指定一个批处理选项"
 
@@ -4155,12 +4190,17 @@
 msgstr "<类型> <对象> 模式只允许两个参数,而不是 %d 个"
 
 #: builtin/check-attr.c
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | <属性>...] [--] <路径名>..."
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [--source <树对象>] [-a | --all | <属性>...] [--] <路径名>..."
 
 #: builtin/check-attr.c
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | <属性>...]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source <树对象>] [-a | --all | <属性>...]"
 
 #: builtin/check-attr.c
 msgid "report all attributes set on file"
@@ -4178,6 +4218,14 @@
 msgid "terminate input and output records by a NUL character"
 msgstr "输入和输出的记录使用 NUL 字符终结"
 
+#: builtin/check-attr.c
+msgid "<tree-ish>"
+msgstr "<树对象>"
+
+#: builtin/check-attr.c
+msgid "which tree-ish to check attributes at"
+msgstr "要用哪一个树对象来检查属性"
+
 #: builtin/check-ignore.c builtin/checkout.c builtin/gc.c builtin/worktree.c
 msgid "suppress progress reporting"
 msgstr "不显示进度报告"
@@ -4849,7 +4897,7 @@
 msgid "Would refuse to remove current working directory\n"
 msgstr "将拒绝删除当前工作目录\n"
 
-#: builtin/clean.c git-add--interactive.perl
+#: builtin/clean.c
 #, c-format
 msgid ""
 "Prompt help:\n"
@@ -4862,7 +4910,7 @@
 "foo        - 通过唯一前缀选择一个选项\n"
 "           - (空)什么也不选择\n"
 
-#: builtin/clean.c git-add--interactive.perl
+#: builtin/clean.c
 #, c-format
 msgid ""
 "Prompt help:\n"
@@ -4883,8 +4931,8 @@
 "*          - 选择所有选项\n"
 "           - (空)结束选择\n"
 
-#: builtin/clean.c git-add--interactive.perl
-#, c-format, perl-format
+#: builtin/clean.c
+#, c-format
 msgid "Huh (%s)?\n"
 msgstr "嗯(%s)?\n"
 
@@ -5073,10 +5121,6 @@
 msgid "create a shallow clone of that depth"
 msgstr "创建一个指定深度的浅克隆"
 
-#: builtin/clone.c builtin/fetch.c builtin/pack-objects.c builtin/pull.c
-msgid "time"
-msgstr "时间"
-
 #: builtin/clone.c
 msgid "create a shallow clone since a specific time"
 msgstr "从一个特定时间创建一个浅克隆"
@@ -5365,6 +5409,10 @@
 msgstr "无法从归档包 URI '%s' 获取对象"
 
 #: builtin/clone.c
+msgid "failed to fetch advertised bundles"
+msgstr "无法获取公布的归档包"
+
+#: builtin/clone.c
 msgid "remote transport reported error"
 msgstr "远程传输报告错误"
 
@@ -5733,7 +5781,7 @@
 "in the current commit message"
 msgstr "无法选择一个未被当前提交说明使用的注释字符"
 
-#: builtin/commit.c
+#: builtin/commit.c builtin/merge-tree.c
 #, c-format
 msgid "could not lookup commit %s"
 msgstr "不能查询提交 %s"
@@ -6035,7 +6083,7 @@
 msgid "override date for commit"
 msgstr "提交时覆盖日期"
 
-#: builtin/commit.c parse-options.h ref-filter.h
+#: builtin/commit.c builtin/merge-tree.c parse-options.h ref-filter.h
 msgid "commit"
 msgstr "提交"
 
@@ -6186,7 +6234,7 @@
 msgid "git config [<options>]"
 msgstr "git config [<选项>]"
 
-#: builtin/config.c builtin/env--helper.c
+#: builtin/config.c
 #, c-format
 msgid "unrecognized --type argument, %s"
 msgstr "未能识别的 --type 参数,%s"
@@ -6295,11 +6343,11 @@
 msgid "Type"
 msgstr "类型"
 
-#: builtin/config.c builtin/env--helper.c builtin/hash-object.c
+#: builtin/config.c builtin/hash-object.c
 msgid "type"
 msgstr "类型"
 
-#: builtin/config.c builtin/env--helper.c
+#: builtin/config.c
 msgid "value is given this type"
 msgstr "取值为该类型"
 
@@ -6351,7 +6399,7 @@
 msgid "show scope of config (worktree, local, global, system, command)"
 msgstr "显示配置的作用域(工作区、本地、全局、系统、命令)"
 
-#: builtin/config.c builtin/env--helper.c
+#: builtin/config.c
 msgid "value"
 msgstr "取值"
 
@@ -6886,30 +6934,6 @@
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "没有为 --extcmd=<命令> 参数提供 <命令>"
 
-#: builtin/env--helper.c
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] <选项> <环境变量>"
-
-#: builtin/env--helper.c
-msgid "default for git_env_*(...) to fall back on"
-msgstr "git_env_*(...) 的默认值"
-
-#: builtin/env--helper.c
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr "安静模式,只使用 git_env_*() 的值作为退出码"
-
-#: builtin/env--helper.c
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr "选项 `--default' 和 `--type=bool` 期望一个布尔值,不是 `%s`"
-
-#: builtin/env--helper.c
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not "
-"`%s`"
-msgstr "选项 `--default' 和 `--type=ulong` 期望一个无符号长整型,不是 `%s`"
-
 #: builtin/fast-export.c
 msgid "git fast-export [<rev-list-opts>]"
 msgstr "git fast-export [<rev-list 选项>]"
@@ -7404,6 +7428,11 @@
 msgstr "对于一个完整的仓库,参数 --unshallow 没有意义"
 
 #: builtin/fetch.c
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "无法从 '%s' 获取归档包"
+
+#: builtin/fetch.c
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all 不能带一个仓库参数"
 
@@ -8694,13 +8723,21 @@
 msgstr "'git help config' 获取更多信息"
 
 #: builtin/hook.c
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] <钩子名称> [-- <钩子参数>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=<路径>] <钩子名称> [-- <钩子参数"
+">]"
 
 #: builtin/hook.c
 msgid "silently ignore missing requested <hook-name>"
 msgstr "静默地忽略缺失的 <钩子名称>"
 
+#: builtin/hook.c
+msgid "file to read into hooks' stdin"
+msgstr "读取至钩子标准输入的文件"
+
 #: builtin/index-pack.c
 #, c-format
 msgid "object type mismatch at %s"
@@ -9749,11 +9786,11 @@
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<可执行文件>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<键>]\n"
-"              [--symref] [<仓库> [<引用>...]]"
+"              [--symref] [<仓库> [<模式>...]]"
 
 #: builtin/ls-remote.c
 msgid "do not print remote URL"
@@ -10073,9 +10110,17 @@
 msgstr "实施多个合并,每输入行一个"
 
 #: builtin/merge-tree.c
+msgid "specify a merge-base for the merge"
+msgstr "指定用于合并的合并基线"
+
+#: builtin/merge-tree.c
 msgid "--trivial-merge is incompatible with all other options"
 msgstr "--trivial-merge 与其他所有选项不兼容"
 
+#: builtin/merge-tree.c
+msgid "--merge-base is incompatible with --stdin"
+msgstr "--merge-base 与 --stdin 不兼容"
+
 #: builtin/merge-tree.c builtin/notes.c
 #, c-format
 msgid "malformed input line: '%s'."
@@ -12088,7 +12133,7 @@
 msgid "--delete doesn't make sense without any refs"
 msgstr "--delete 未接任何引用没有意义"
 
-#: builtin/push.c
+#: builtin/push.c t/helper/test-bundle-uri.c
 #, c-format
 msgid "bad repository '%s'"
 msgstr "坏的仓库 '%s'"
@@ -12358,6 +12403,10 @@
 msgstr "无法切换到 %s"
 
 #: builtin/rebase.c
+msgid "apply options and merge options cannot be used together"
+msgstr "应用选项和合并选项不能同时使用"
+
+#: builtin/rebase.c
 #, c-format
 msgid ""
 "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
@@ -12636,8 +12685,16 @@
 msgstr "--strategy 需要 --merge 或 --interactive"
 
 #: builtin/rebase.c
-msgid "apply options and merge options cannot be used together"
-msgstr "应用选项和合并选项不能同时使用"
+msgid ""
+"apply options are incompatible with rebase.autosquash.  Consider adding --no-"
+"autosquash"
+msgstr "应用的选项与 rebase.autosquash 不兼容。考虑加上 --no-autosquash"
+
+#: builtin/rebase.c
+msgid ""
+"apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
+"update-refs"
+msgstr "应用的选项与 rebase.updateRefs 不兼容。考虑加上 --no-update-refs"
 
 #: builtin/rebase.c
 #, c-format
@@ -15680,11 +15737,6 @@
 msgid "git submodule--helper <command>"
 msgstr "git submodule--helper <命令>"
 
-#: builtin/submodule--helper.c git.c
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s 不支持 --super-prefix"
-
 #: builtin/symbolic-ref.c
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
 msgstr "git symbolic-ref [-m <理由>] <名称> <引用>"
@@ -16590,6 +16642,11 @@
 
 #: bundle-uri.c
 #, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr "不能解析归档包列表键 %s 的值 '%s'"
+
+#: bundle-uri.c
+#, c-format
 msgid "bundle list at '%s' has no mode"
 msgstr "在 '%s' 的归档包列表没有模式"
 
@@ -16603,6 +16660,15 @@
 
 #: bundle-uri.c
 #, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "下载自 '%s' 的文件不是归档包"
+
+#: bundle-uri.c
+msgid "failed to store maximum creation token"
+msgstr "无法储存最大的创建令牌"
+
+#: bundle-uri.c
+#, c-format
 msgid "unrecognized bundle mode from URI '%s'"
 msgstr "不可辨认的归档包模式来自 URI '%s'"
 
@@ -16622,6 +16688,15 @@
 msgstr "位于 URI '%s' 的文件不是归档包或归档包列表"
 
 #: bundle-uri.c
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: 意外的参数:'%s'"
+
+#: bundle-uri.c
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: 在参数之后应有一个 flush"
+
+#: bundle-uri.c
 msgid "bundle-uri: got an empty line"
 msgstr "bundle-uri: 获得了空行"
 
@@ -16662,6 +16737,12 @@
 msgstr "需要一个仓库来校验一个归档包"
 
 #: bundle.c
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr "一些前置提交存在于对象储存中,但未连接于本仓库的历史"
+
+#: bundle.c
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -18439,6 +18520,19 @@
 
 #: connect.c
 #, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "于 bundle-uri 响应行 %d 发生错误:%s"
+
+#: connect.c
+msgid "expected flush after bundle-uri listing"
+msgstr "在 bundle-uri 列表之后应该有一个 flush 包"
+
+#: connect.c
+msgid "expected response end packet after ref listing"
+msgstr "在引用列表之后应该有响应结束包"
+
+#: connect.c
+#, c-format
 msgid "invalid ls-refs response: %s"
 msgstr "无效的 ls-refs 响应:%s"
 
@@ -18447,10 +18541,6 @@
 msgstr "在引用列表之后应该有一个 flush 包"
 
 #: connect.c
-msgid "expected response end packet after ref listing"
-msgstr "在引用列表之后应该有响应结束包"
-
-#: connect.c
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr "不支持 '%s' 协议"
@@ -19861,16 +19951,14 @@
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-"           <command> [<args>]"
+"           [--config-env=<name>=<envvar>] <command> [<args>]"
 msgstr ""
-"git [-v | --version] [--help] [-C <路径>] [-c <名称>=<取值>]\n"
+"git [-v | --version] [-h | --help] [-C <路径>] [-c <名称>=<取值>]\n"
 "           [--exec-path[=<路径>]] [--html-path] [--man-path] [--info-path]\n"
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<路径>] [--work-tree=<路径>] [--namespace=<名称>]\n"
-"           [--super-prefix=<路径>] [--config-env=<名称>=<环境变量>]\n"
-"           <命令> [<参数>]"
+"           [--config-env=<名称>=<环境变量>] <命令> [<参数>]"
 
 #: git.c
 msgid ""
@@ -19901,11 +19989,6 @@
 
 #: git.c
 #, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "没有为 --super-prefix 提供前缀\n"
-
-#: git.c
-#, c-format
 msgid "-c expects a configuration string\n"
 msgstr "应为 -c 提供一个配置字符串\n"
 
@@ -20038,8 +20121,13 @@
 msgstr "gpg.ssh.defaultKeyCommand 失败:%s %s"
 
 #: gpg-interface.c
-msgid "gpg failed to sign the data"
-msgstr "gpg 无法为数据签名"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg 无法为数据签名:\n"
+"%s"
 
 #: gpg-interface.c
 msgid "user.signingKey needs to be set for ssh signing"
@@ -21386,6 +21474,11 @@
 
 #: object-file.c
 #, c-format
+msgid "unable to open loose object %s"
+msgstr "无法打开松散对象 %s"
+
+#: object-file.c
+#, c-format
 msgid "unable to parse %s header"
 msgstr "无法解析 %s 头部"
 
@@ -21405,8 +21498,8 @@
 
 #: object-file.c
 #, c-format
-msgid "failed to read object %s"
-msgstr "无法读取对象 %s"
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "松散对象 %s(保存在 %s)已损坏"
 
 #: object-file.c
 #, c-format
@@ -21415,11 +21508,6 @@
 
 #: object-file.c
 #, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "松散对象 %s(保存在 %s)已损坏"
-
-#: object-file.c
-#, c-format
 msgid "packed object %s (stored in %s) is corrupt"
 msgstr "打包对象 %s(保存在 %s)已损坏"
 
@@ -21434,10 +21522,6 @@
 msgstr "无法为 '%s' 设置权限"
 
 #: object-file.c
-msgid "file write error"
-msgstr "文件写错误"
-
-#: object-file.c
 msgid "error when closing loose object file"
 msgstr "关闭松散对象文件时出错"
 
@@ -21495,12 +21579,13 @@
 msgstr "不能读取对象 %s"
 
 #: object-file.c
-msgid "corrupt commit"
-msgstr "损坏的提交"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "对象 fsck 失败:%s"
 
 #: object-file.c
-msgid "corrupt tag"
-msgstr "损坏的标签"
+msgid "refusing to create malformed object"
+msgstr "拒绝创建格式错误的对象"
 
 #: object-file.c
 #, c-format
@@ -21811,11 +21896,6 @@
 msgstr "不能对位图文件调用 fstat"
 
 #: pack-bitmap.c
-#, c-format
-msgid "ignoring extra bitmap file: '%s'"
-msgstr "忽略额外的位图文件:'%s'"
-
-#: pack-bitmap.c
 msgid "checksum doesn't match in MIDX and bitmap"
 msgstr "MIDX 和位图中的校验码不匹配"
 
@@ -22142,6 +22222,10 @@
 msgstr "用 <n> 位数字显示对象名"
 
 #: parse-options.h
+msgid "prefixed path to initial superproject"
+msgstr "用来初始化父项目的前缀路径"
+
+#: parse-options.h
 msgid "how to strip spaces and #comments from message"
 msgstr "设置如何删除提交说明里的空格和#注释"
 
@@ -22725,6 +22809,16 @@
 
 #: ref-filter.c
 #, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) 不带参数"
+
+#: ref-filter.c
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "未能识别的 %%(%.*s) 参数:%s"
+
+#: ref-filter.c
+#, c-format
 msgid "expected format: %%(color:<color>)"
 msgstr "期望的格式:%%(color:<颜色>)"
 
@@ -22745,26 +22839,6 @@
 
 #: ref-filter.c
 #, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "未能识别的 %%(%s) 参数:%s"
-
-#: ref-filter.c
-#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) 不带参数"
-
-#: ref-filter.c
-#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) 不带参数"
-
-#: ref-filter.c
-#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) 不带参数"
-
-#: ref-filter.c
-#, c-format
 msgid "expected %%(trailers:key=<value>)"
 msgstr "预期 %%(trailers:key=<值>)"
 
@@ -22785,11 +22859,6 @@
 
 #: ref-filter.c
 #, c-format
-msgid "unrecognized email option: %s"
-msgstr "未识别的邮件选项:%s"
-
-#: ref-filter.c
-#, c-format
 msgid "expected format: %%(align:<width>,<position>)"
 msgstr "期望的格式:%%(align:<宽度>,<位置>)"
 
@@ -22805,13 +22874,13 @@
 
 #: ref-filter.c
 #, c-format
-msgid "positive width expected with the %%(align) atom"
-msgstr "元素 %%(align) 需要一个正数的宽度"
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "未能识别的 %%(%s) 参数:%s"
 
 #: ref-filter.c
 #, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) 不带参数"
+msgid "positive width expected with the %%(align) atom"
+msgstr "元素 %%(align) 需要一个正数的宽度"
 
 #: ref-filter.c
 #, c-format
@@ -24317,6 +24386,26 @@
 
 #: sequencer.c
 #, c-format
+msgid "'%s' is not a valid label"
+msgstr "'%s' 不是一个有效的标签"
+
+#: sequencer.c
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "'%s' 不是一个有效的引用名"
+
+#: sequencer.c
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr "update-ref 需要一个完整的引用名,例如:refs/heads/%s"
+
+#: sequencer.c
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "无效命令 '%.*s'"
+
+#: sequencer.c
+#, c-format
 msgid "%s does not accept arguments: '%s'"
 msgstr "%s 不接受参数:'%s'"
 
@@ -25274,6 +25363,19 @@
 msgid "failed to lstat '%s'"
 msgstr "无法执行 lstat '%s'"
 
+#: t/helper/test-bundle-uri.c
+msgid "no remote configured to get bundle URIs from"
+msgstr "没有远程被设置为可以获取归档包 URI"
+
+#: t/helper/test-bundle-uri.c
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "远程 '%s' 没有设置 URL"
+
+#: t/helper/test-bundle-uri.c
+msgid "could not get the bundle-uri list"
+msgstr "无法获取 bundle-uri 列表"
+
 #: t/helper/test-cache-tree.c
 msgid "test-tool cache-tree <options> (control|prime|update)"
 msgstr "test-tool cache-tree <选项> (control|prime|update)"
@@ -25710,6 +25812,14 @@
 msgid "failed to push all needed submodules"
 msgstr "不能推送全部需要的子模组"
 
+#: transport.c
+msgid "bundle-uri operation not supported by protocol"
+msgstr "协议不支持 bundle-uri 操作"
+
+#: transport.c
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr "无法获取服务器公布的 bundle-uri 列表"
+
 #: tree-walk.c
 msgid "too-short tree object"
 msgstr "太短的树对象"
@@ -26627,12 +26737,20 @@
 #: wt-status.c
 #, c-format
 msgid ""
-"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-"may speed it up, but you have to be careful not to forget to add\n"
-"new files yourself (see 'git help status')."
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
 msgstr ""
-"耗费了 %.2f 秒以枚举未跟踪的文件。'status -uno' 也许能提高速度,\n"
-"但您需要小心不要忘了添加新文件(参见 'git help status')。"
+"枚举未追踪的文件花了 %.2f 秒,\n"
+"结果已被缓存,后续的执行会更快。"
+
+#: wt-status.c
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr "枚举未追踪的文件花了 %.2f 秒。"
+
+#: wt-status.c
+msgid "See 'git help status' for information on how to improve this."
+msgstr "参见 'git help status' 来获取如何改善的信息。"
 
 #: wt-status.c
 #, c-format
@@ -26805,300 +26923,6 @@
 msgid "Unable to determine absolute path of git directory"
 msgstr "不能确定 git 目录的绝对路径"
 
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#: git-add--interactive.perl
-#, perl-format
-msgid "%12s %12s %s"
-msgstr "%12s %12s %s"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] "触碰了 %d 个路径\n"
-msgstr[1] "触碰了 %d 个路径\n"
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr "如果补丁能干净地应用,编辑块将立即标记为暂存。"
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr "如果补丁能干净地应用,编辑块将立即标记为贮藏。"
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr "如果补丁能干净地应用,编辑块将立即标记为未暂存。"
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr "如果补丁能干净地应用,编辑块将立即标记为应用。"
-
-#: git-add--interactive.perl
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr "如果补丁能干净地应用,编辑块将立即标记为丢弃。"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr "无法为写入打开块编辑文件:%s"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid ""
-"---\n"
-"To remove '%s' lines, make them ' ' lines (context).\n"
-"To remove '%s' lines, delete them.\n"
-"Lines starting with %s will be removed.\n"
-msgstr ""
-"---\n"
-"要删除 '%s' 开始的行,使其成为 ' ' 开始的行(上下文)。\n"
-"要删除 '%s' 开始的行,删除它们。\n"
-"以 %s 开始的行将被删除。\n"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr "无法读取块编辑文件:%s"
-
-#: git-add--interactive.perl
-msgid ""
-"y - stage this hunk\n"
-"n - do not stage this hunk\n"
-"q - quit; do not stage this hunk or any of the remaining ones\n"
-"a - stage this hunk and all later hunks in the file\n"
-"d - do not stage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - 暂存该块\n"
-"n - 不要暂存该块\n"
-"q - 退出。不暂存该块及后面的全部块\n"
-"a - 暂存该块和本文件中后面的全部块\n"
-"d - 不暂存该块和本文件中后面的全部块"
-
-#: git-add--interactive.perl
-msgid ""
-"y - stash this hunk\n"
-"n - do not stash this hunk\n"
-"q - quit; do not stash this hunk or any of the remaining ones\n"
-"a - stash this hunk and all later hunks in the file\n"
-"d - do not stash this hunk or any of the later hunks in the file"
-msgstr ""
-"y - 贮藏该块\n"
-"n - 不要贮藏该块\n"
-"q - 退出。不贮藏该块及后面的全部块\n"
-"a - 贮藏该块和本文件中后面的全部块\n"
-"d - 不贮藏该块和本文件中后面的全部块"
-
-#: git-add--interactive.perl
-msgid ""
-"y - unstage this hunk\n"
-"n - do not unstage this hunk\n"
-"q - quit; do not unstage this hunk or any of the remaining ones\n"
-"a - unstage this hunk and all later hunks in the file\n"
-"d - do not unstage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - 不暂存该块\n"
-"n - 不要不暂存该块\n"
-"q - 退出。不要不暂存该块及后面的全部块\n"
-"a - 不暂存该块和本文件中后面的全部块\n"
-"d - 不要不暂存该块和本文件中后面的全部块"
-
-#: git-add--interactive.perl
-msgid ""
-"y - apply this hunk to index\n"
-"n - do not apply this hunk to index\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - 在索引中应用该块\n"
-"n - 不要在索引中应用该块\n"
-"q - 退出。不要应用该块及后面的全部块\n"
-"a - 应用该块和本文件中后面的全部块\n"
-"d - 不要应用该块和本文件中后面的全部块"
-
-#: git-add--interactive.perl
-msgid ""
-"y - discard this hunk from worktree\n"
-"n - do not discard this hunk from worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - 在工作区中丢弃该块\n"
-"n - 不要在工作区中丢弃该块\n"
-"q - 退出。不要丢弃该块及后面的全部块\n"
-"a - 丢弃该块和本文件中后面的全部块\n"
-"d - 不要丢弃该块和本文件中后面的全部块"
-
-#: git-add--interactive.perl
-msgid ""
-"y - discard this hunk from index and worktree\n"
-"n - do not discard this hunk from index and worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - 在索引和工作区中丢弃该块\n"
-"n - 不要在索引和工作区中丢弃该块\n"
-"q - 退出。不要丢弃该块及后面的全部块\n"
-"a - 丢弃该块和本文件中后面的全部块\n"
-"d - 不要丢弃该块和本文件中后面的全部块"
-
-#: git-add--interactive.perl
-msgid ""
-"y - apply this hunk to index and worktree\n"
-"n - do not apply this hunk to index and worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - 在索引和工作区中应用该块\n"
-"n - 不要在索引和工作区中应用该块\n"
-"q - 退出。不要应用该块及后面的全部块\n"
-"a - 应用该块和本文件中后面的全部块\n"
-"d - 不要应用该块和本文件中后面的全部块"
-
-#: git-add--interactive.perl
-msgid ""
-"y - apply this hunk to worktree\n"
-"n - do not apply this hunk to worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - 在工作区中应用该块\n"
-"n - 不要在工作区中应用该块\n"
-"q - 退出。不要应用该块及后面的全部块\n"
-"a - 应用该块和本文件中后面的全部块\n"
-"d - 不要应用该块和本文件中后面的全部块"
-
-#: git-add--interactive.perl
-msgid ""
-"g - select a hunk to go to\n"
-"/ - search for a hunk matching the given regex\n"
-"j - leave this hunk undecided, see next undecided hunk\n"
-"J - leave this hunk undecided, see next hunk\n"
-"k - leave this hunk undecided, see previous undecided hunk\n"
-"K - leave this hunk undecided, see previous hunk\n"
-"s - split the current hunk into smaller hunks\n"
-"e - manually edit the current hunk\n"
-"? - print help\n"
-msgstr ""
-"g - 选择跳转到一个块\n"
-"/ - 查找和给定正则表达式匹配的块\n"
-"j - 维持该块未决状态,查看下一个未决块\n"
-"J - 维持该块未决状态,查看下一个块\n"
-"k - 维持该块未决状态,查看上一个未决块\n"
-"K - 维持该块未决状态,查看上一个块\n"
-"s - 拆分当前块为更小的块\n"
-"e - 手动编辑当前块\n"
-"? - 显示帮助\n"
-
-#: git-add--interactive.perl
-msgid "The selected hunks do not apply to the index!\n"
-msgstr "选中的块不能应用到索引!\n"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "忽略未合入的:%s\n"
-
-#: git-add--interactive.perl
-msgid "No other hunks to goto\n"
-msgstr "没有其它可供跳转的块\n"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "无效数字:'%s'\n"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "对不起,只有 %d 个可用块。\n"
-msgstr[1] "对不起,只有 %d 个可用块。\n"
-
-#: git-add--interactive.perl
-msgid "No other hunks to search\n"
-msgstr "没有其它可供查找的块\n"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "错误的正则表达式 %s:%s\n"
-
-#: git-add--interactive.perl
-msgid "No hunk matches the given pattern\n"
-msgstr "没有和给定模式相匹配的块\n"
-
-#: git-add--interactive.perl
-msgid "No previous hunk\n"
-msgstr "没有前一个块\n"
-
-#: git-add--interactive.perl
-msgid "No next hunk\n"
-msgstr "没有下一个块\n"
-
-#: git-add--interactive.perl
-msgid "Sorry, cannot split this hunk\n"
-msgstr "对不起,不能拆分这个块\n"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "拆分为 %d 块。\n"
-msgstr[1] "拆分为 %d 块。\n"
-
-#: git-add--interactive.perl
-msgid "Sorry, cannot edit this hunk\n"
-msgstr "对不起,不能编辑这个块\n"
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-#: git-add--interactive.perl
-msgid ""
-"status        - show paths with changes\n"
-"update        - add working tree state to the staged set of changes\n"
-"revert        - revert staged set of changes back to the HEAD version\n"
-"patch         - pick hunks and update selectively\n"
-"diff          - view diff between HEAD and index\n"
-"add untracked - add contents of untracked files to the staged set of "
-"changes\n"
-msgstr ""
-"status        - 显示含变更的路径\n"
-"update        - 添加工作区状态至暂存列表\n"
-"revert        - 还原修改的暂存集至 HEAD 版本\n"
-"patch         - 挑选块并且有选择地更新\n"
-"diff          - 显示 HEAD 和索引间差异\n"
-"add untracked - 添加未跟踪文件的内容至暂存列表\n"
-
-#: git-add--interactive.perl
-msgid "missing --"
-msgstr "缺失 --"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "未知的 --patch 模式:%s"
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "无效的参数 %s,期望是 --"
-
 #: git-send-email.perl
 msgid "local zone differs from GMT by a non-minute interval\n"
 msgstr "本地时间和 GMT 有不到一分钟间隔\n"
diff --git a/range-diff.c b/range-diff.c
index 8255ab4..4bd65ab 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -383,11 +383,14 @@ static void output_pair_header(struct diff_options *diffopt,
 	const char *color_new = diff_get_color_opt(diffopt, DIFF_FILE_NEW);
 	const char *color_commit = diff_get_color_opt(diffopt, DIFF_COMMIT);
 	const char *color;
+	int abbrev = diffopt->abbrev;
+
+	if (abbrev < 0)
+		abbrev = DEFAULT_ABBREV;
 
 	if (!dashes->len)
 		strbuf_addchars(dashes, '-',
-				strlen(find_unique_abbrev(oid,
-							  DEFAULT_ABBREV)));
+				strlen(find_unique_abbrev(oid, abbrev)));
 
 	if (!b_util) {
 		color = color_old;
@@ -409,7 +412,7 @@ static void output_pair_header(struct diff_options *diffopt,
 		strbuf_addf(buf, "%*s:  %s ", patch_no_width, "-", dashes->buf);
 	else
 		strbuf_addf(buf, "%*d:  %s ", patch_no_width, a_util->i + 1,
-			    find_unique_abbrev(&a_util->oid, DEFAULT_ABBREV));
+			    find_unique_abbrev(&a_util->oid, abbrev));
 
 	if (status == '!')
 		strbuf_addf(buf, "%s%s", color_reset, color);
@@ -421,7 +424,7 @@ static void output_pair_header(struct diff_options *diffopt,
 		strbuf_addf(buf, " %*s:  %s", patch_no_width, "-", dashes->buf);
 	else
 		strbuf_addf(buf, " %*d:  %s", patch_no_width, b_util->i + 1,
-			    find_unique_abbrev(&b_util->oid, DEFAULT_ABBREV));
+			    find_unique_abbrev(&b_util->oid, abbrev));
 
 	commit = lookup_commit_reference(the_repository, oid);
 	if (commit) {
diff --git a/read-cache.c b/read-cache.c
index 383ec6d..342723e 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -488,11 +488,11 @@ int ie_modified(struct index_state *istate,
 	return 0;
 }
 
-int base_name_compare(const char *name1, int len1, int mode1,
-		      const char *name2, int len2, int mode2)
+int base_name_compare(const char *name1, size_t len1, int mode1,
+		      const char *name2, size_t len2, int mode2)
 {
 	unsigned char c1, c2;
-	int len = len1 < len2 ? len1 : len2;
+	size_t len = len1 < len2 ? len1 : len2;
 	int cmp;
 
 	cmp = memcmp(name1, name2, len);
@@ -517,11 +517,12 @@ int base_name_compare(const char *name1, int len1, int mode1,
  * This is used by routines that want to traverse the git namespace
  * but then handle conflicting entries together when possible.
  */
-int df_name_compare(const char *name1, int len1, int mode1,
-		    const char *name2, int len2, int mode2)
+int df_name_compare(const char *name1, size_t len1, int mode1,
+		    const char *name2, size_t len2, int mode2)
 {
-	int len = len1 < len2 ? len1 : len2, cmp;
 	unsigned char c1, c2;
+	size_t len = len1 < len2 ? len1 : len2;
+	int cmp;
 
 	cmp = memcmp(name1, name2, len);
 	if (cmp)
@@ -1783,6 +1784,8 @@ static int verify_hdr(const struct cache_header *hdr, unsigned long size)
 	git_hash_ctx c;
 	unsigned char hash[GIT_MAX_RAWSZ];
 	int hdr_version;
+	unsigned char *start, *end;
+	struct object_id oid;
 
 	if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
 		return error(_("bad signature 0x%08x"), hdr->hdr_signature);
@@ -1793,10 +1796,16 @@ static int verify_hdr(const struct cache_header *hdr, unsigned long size)
 	if (!verify_index_checksum)
 		return 0;
 
+	end = (unsigned char *)hdr + size;
+	start = end - the_hash_algo->rawsz;
+	oidread(&oid, start);
+	if (oideq(&oid, null_oid()))
+		return 0;
+
 	the_hash_algo->init_fn(&c);
 	the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
 	the_hash_algo->final_fn(hash, &c);
-	if (!hasheq(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
+	if (!hasheq(hash, start))
 		return error(_("bad index file sha1 signature"));
 	return 0;
 }
@@ -2258,12 +2267,10 @@ static void set_new_index_sparsity(struct index_state *istate)
 	 * If the index's repo exists, mark it sparse according to
 	 * repo settings.
 	 */
-	if (istate->repo) {
-		prepare_repo_settings(istate->repo);
-		if (!istate->repo->settings.command_requires_full_index &&
-		    is_sparse_index_allowed(istate, 0))
-			istate->sparse_index = 1;
-	}
+	prepare_repo_settings(istate->repo);
+	if (!istate->repo->settings.command_requires_full_index &&
+	    is_sparse_index_allowed(istate, 0))
+		istate->sparse_index = 1;
 }
 
 /* remember to discard_cache() before reading a different cache! */
@@ -2288,8 +2295,6 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
 	fd = open(path, O_RDONLY);
 	if (fd < 0) {
 		if (!must_exist && errno == ENOENT) {
-			if (!istate->repo)
-				istate->repo = the_repository;
 			set_new_index_sparsity(istate);
 			return 0;
 		}
@@ -2391,9 +2396,6 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
 	trace2_data_intmax("index", the_repository, "read/cache_nr",
 			   istate->cache_nr);
 
-	if (!istate->repo)
-		istate->repo = the_repository;
-
 	/*
 	 * If the command explicitly requires a full index, force it
 	 * to be full. Otherwise, correct the sparsity based on repository
@@ -2456,9 +2458,10 @@ int read_index_from(struct index_state *istate, const char *path,
 
 	trace_performance_enter();
 	if (split_index->base)
-		discard_index(split_index->base);
+		release_index(split_index->base);
 	else
-		CALLOC_ARRAY(split_index->base, 1);
+		ALLOC_ARRAY(split_index->base, 1);
+	index_state_init(split_index->base, istate->repo);
 
 	base_oid_hex = oid_to_hex(&split_index->base_oid);
 	base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_oid_hex);
@@ -2497,7 +2500,13 @@ int is_index_unborn(struct index_state *istate)
 	return (!istate->cache_nr && !istate->timestamp.sec);
 }
 
-void discard_index(struct index_state *istate)
+void index_state_init(struct index_state *istate, struct repository *r)
+{
+	struct index_state blank = INDEX_STATE_INIT(r);
+	memcpy(istate, &blank, sizeof(*istate));
+}
+
+void release_index(struct index_state *istate)
 {
 	/*
 	 * Cache entries in istate->cache[] should have been allocated
@@ -2509,20 +2518,17 @@ void discard_index(struct index_state *istate)
 	validate_cache_entries(istate);
 
 	resolve_undo_clear_index(istate);
-	istate->cache_nr = 0;
-	istate->cache_changed = 0;
-	istate->timestamp.sec = 0;
-	istate->timestamp.nsec = 0;
 	free_name_hash(istate);
 	cache_tree_free(&(istate->cache_tree));
-	istate->initialized = 0;
-	istate->fsmonitor_has_run_once = 0;
-	FREE_AND_NULL(istate->fsmonitor_last_update);
-	FREE_AND_NULL(istate->cache);
-	istate->cache_alloc = 0;
+	free(istate->fsmonitor_last_update);
+	free(istate->cache);
 	discard_split_index(istate);
 	free_untracked_cache(istate->untracked);
-	istate->untracked = NULL;
+
+	if (istate->sparse_checkout_patterns) {
+		clear_pattern_list(istate->sparse_checkout_patterns);
+		FREE_AND_NULL(istate->sparse_checkout_patterns);
+	}
 
 	if (istate->ce_mem_pool) {
 		mem_pool_discard(istate->ce_mem_pool, should_validate_cache_entries());
@@ -2530,6 +2536,12 @@ void discard_index(struct index_state *istate)
 	}
 }
 
+void discard_index(struct index_state *istate)
+{
+	release_index(istate);
+	index_state_init(istate, istate->repo);
+}
+
 /*
  * Validate the cache entries of this index.
  * All cache entries associated with this index
@@ -2881,9 +2893,13 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 	int ieot_entries = 1;
 	struct index_entry_offset_table *ieot = NULL;
 	int nr, nr_threads;
+	struct repository *r = istate->repo;
 
 	f = hashfd(tempfile->fd, tempfile->filename.buf);
 
+	prepare_repo_settings(r);
+	f->skip_hash = r->settings.index_skip_hash;
+
 	for (i = removed = extended = 0; i < entries; i++) {
 		if (cache[i]->ce_flags & CE_REMOVE)
 			removed++;
diff --git a/ref-filter.c b/ref-filter.c
index 9713036..f8203c6 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -228,6 +228,22 @@ static int strbuf_addf_ret(struct strbuf *sb, int ret, const char *fmt, ...)
 	return ret;
 }
 
+static int err_no_arg(struct strbuf *sb, const char *name)
+{
+	size_t namelen = strchrnul(name, ':') - name;
+	strbuf_addf(sb, _("%%(%.*s) does not take arguments"),
+		    (int)namelen, name);
+	return -1;
+}
+
+static int err_bad_arg(struct strbuf *sb, const char *name, const char *arg)
+{
+	size_t namelen = strchrnul(name, ':') - name;
+	strbuf_addf(sb, _("unrecognized %%(%.*s) argument: %s"),
+		    (int)namelen, name, arg);
+	return -1;
+}
+
 static int color_atom_parser(struct ref_format *format, struct used_atom *atom,
 			     const char *color_value, struct strbuf *err)
 {
@@ -262,7 +278,7 @@ static int refname_atom_parser_internal(struct refname_atom *atom, const char *a
 		if (strtol_i(arg, 10, &atom->rstrip))
 			return strbuf_addf_ret(err, -1, _("Integer value expected refname:rstrip=%s"), arg);
 	} else
-		return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), name, arg);
+		return err_bad_arg(err, name, arg);
 	return 0;
 }
 
@@ -317,7 +333,7 @@ static int objecttype_atom_parser(struct ref_format *format, struct used_atom *a
 				  const char *arg, struct strbuf *err)
 {
 	if (arg)
-		return strbuf_addf_ret(err, -1, _("%%(objecttype) does not take arguments"));
+		return err_no_arg(err, "objecttype");
 	if (*atom->name == '*')
 		oi_deref.info.typep = &oi_deref.type;
 	else
@@ -341,7 +357,7 @@ static int objectsize_atom_parser(struct ref_format *format, struct used_atom *a
 		else
 			oi.info.disk_sizep = &oi.disk_size;
 	} else
-		return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "objectsize", arg);
+		return err_bad_arg(err, "objectsize", arg);
 	return 0;
 }
 
@@ -349,7 +365,7 @@ static int deltabase_atom_parser(struct ref_format *format, struct used_atom *at
 				 const char *arg, struct strbuf *err)
 {
 	if (arg)
-		return strbuf_addf_ret(err, -1, _("%%(deltabase) does not take arguments"));
+		return err_no_arg(err, "deltabase");
 	if (*atom->name == '*')
 		oi_deref.info.delta_base_oid = &oi_deref.delta_base_oid;
 	else
@@ -361,7 +377,7 @@ static int body_atom_parser(struct ref_format *format, struct used_atom *atom,
 			    const char *arg, struct strbuf *err)
 {
 	if (arg)
-		return strbuf_addf_ret(err, -1, _("%%(body) does not take arguments"));
+		return err_no_arg(err, "body");
 	atom->u.contents.option = C_BODY_DEP;
 	return 0;
 }
@@ -374,7 +390,7 @@ static int subject_atom_parser(struct ref_format *format, struct used_atom *atom
 	else if (!strcmp(arg, "sanitize"))
 		atom->u.contents.option = C_SUB_SANITIZE;
 	else
-		return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "subject", arg);
+		return err_bad_arg(err, "subject", arg);
 	return 0;
 }
 
@@ -428,7 +444,7 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
 		if (strtoul_ui(arg, 10, &atom->u.contents.nlines))
 			return strbuf_addf_ret(err, -1, _("positive value expected contents:lines=%s"), arg);
 	} else
-		return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "contents", arg);
+		return err_bad_arg(err, "contents", arg);
 	return 0;
 }
 
@@ -440,7 +456,7 @@ static int raw_atom_parser(struct ref_format *format, struct used_atom *atom,
 	else if (!strcmp(arg, "size"))
 		atom->u.raw_data.option = RAW_LENGTH;
 	else
-		return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "raw", arg);
+		return err_bad_arg(err, "raw", arg);
 	return 0;
 }
 
@@ -459,7 +475,7 @@ static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
 		if (atom->u.oid.length < MINIMUM_ABBREV)
 			atom->u.oid.length = MINIMUM_ABBREV;
 	} else
-		return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), atom->name, arg);
+		return err_bad_arg(err, atom->name, arg);
 	return 0;
 }
 
@@ -473,7 +489,7 @@ static int person_email_atom_parser(struct ref_format *format, struct used_atom
 	else if (!strcmp(arg, "localpart"))
 		atom->u.email_option.option = EO_LOCALPART;
 	else
-		return strbuf_addf_ret(err, -1, _("unrecognized email option: %s"), arg);
+		return err_bad_arg(err, atom->name, arg);
 	return 0;
 }
 
@@ -557,7 +573,7 @@ static int if_atom_parser(struct ref_format *format, struct used_atom *atom,
 	} else if (skip_prefix(arg, "notequals=", &atom->u.if_then_else.str)) {
 		atom->u.if_then_else.cmp_status = COMPARE_UNEQUAL;
 	} else
-		return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "if", arg);
+		return err_bad_arg(err, "if", arg);
 	return 0;
 }
 
@@ -565,14 +581,16 @@ static int rest_atom_parser(struct ref_format *format, struct used_atom *atom,
 			    const char *arg, struct strbuf *err)
 {
 	if (arg)
-		return strbuf_addf_ret(err, -1, _("%%(rest) does not take arguments"));
+		return err_no_arg(err, "rest");
 	format->use_rest = 1;
 	return 0;
 }
 
 static int head_atom_parser(struct ref_format *format, struct used_atom *atom,
-			    const char *arg, struct strbuf *unused_err)
+			    const char *arg, struct strbuf *err)
 {
+	if (arg)
+		return err_no_arg(err, "HEAD");
 	atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
 	return 0;
 }
@@ -1191,7 +1209,7 @@ static const char *copy_name(const char *buf)
 {
 	const char *cp;
 	for (cp = buf; *cp && *cp != '\n'; cp++) {
-		if (!strncmp(cp, " <", 2))
+		if (starts_with(cp, " <"))
 			return xmemdupz(buf, cp - buf);
 	}
 	return xstrdup("");
@@ -1358,6 +1376,7 @@ static void find_subpos(const char *buf,
 
 	/* parse signature first; we might not even have a subject line */
 	parse_signature(buf, end - buf, &payload, &signature);
+	strbuf_release(&payload);
 
 	/* skip past header until we hit empty line */
 	while (*buf && *buf != '\n') {
diff --git a/refs.c b/refs.c
index e31dbcd..aeae31c 100644
--- a/refs.c
+++ b/refs.c
@@ -1310,65 +1310,68 @@ int update_ref(const char *msg, const char *refname,
 			       old_oid, flags, onerr);
 }
 
+/*
+ * Check that the string refname matches a rule of the form
+ * "{prefix}%.*s{suffix}". So "foo/bar/baz" would match the rule
+ * "foo/%.*s/baz", and return the string "bar".
+ */
+static const char *match_parse_rule(const char *refname, const char *rule,
+				    size_t *len)
+{
+	/*
+	 * Check that rule matches refname up to the first percent in the rule.
+	 * We can bail immediately if not, but otherwise we leave "rule" at the
+	 * %-placeholder, and "refname" at the start of the potential matched
+	 * name.
+	 */
+	while (*rule != '%') {
+		if (!*rule)
+			BUG("rev-parse rule did not have percent");
+		if (*refname++ != *rule++)
+			return NULL;
+	}
+
+	/*
+	 * Check that our "%" is the expected placeholder. This assumes there
+	 * are no other percents (placeholder or quoted) in the string, but
+	 * that is sufficient for our rev-parse rules.
+	 */
+	if (!skip_prefix(rule, "%.*s", &rule))
+		return NULL;
+
+	/*
+	 * And now check that our suffix (if any) matches.
+	 */
+	if (!strip_suffix(refname, rule, len))
+		return NULL;
+
+	return refname; /* len set by strip_suffix() */
+}
+
 char *refs_shorten_unambiguous_ref(struct ref_store *refs,
 				   const char *refname, int strict)
 {
 	int i;
-	static char **scanf_fmts;
-	static int nr_rules;
-	char *short_name;
 	struct strbuf resolved_buf = STRBUF_INIT;
 
-	if (!nr_rules) {
-		/*
-		 * Pre-generate scanf formats from ref_rev_parse_rules[].
-		 * Generate a format suitable for scanf from a
-		 * ref_rev_parse_rules rule by interpolating "%s" at the
-		 * location of the "%.*s".
-		 */
-		size_t total_len = 0;
-		size_t offset = 0;
-
-		/* the rule list is NULL terminated, count them first */
-		for (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++)
-			/* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */
-			total_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;
-
-		scanf_fmts = xmalloc(st_add(st_mult(sizeof(char *), nr_rules), total_len));
-
-		offset = 0;
-		for (i = 0; i < nr_rules; i++) {
-			assert(offset < total_len);
-			scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;
-			offset += xsnprintf(scanf_fmts[i], total_len - offset,
-					    ref_rev_parse_rules[i], 2, "%s") + 1;
-		}
-	}
-
-	/* bail out if there are no rules */
-	if (!nr_rules)
-		return xstrdup(refname);
-
-	/* buffer for scanf result, at most refname must fit */
-	short_name = xstrdup(refname);
-
 	/* skip first rule, it will always match */
-	for (i = nr_rules - 1; i > 0 ; --i) {
+	for (i = NUM_REV_PARSE_RULES - 1; i > 0 ; --i) {
 		int j;
 		int rules_to_fail = i;
-		int short_name_len;
+		const char *short_name;
+		size_t short_name_len;
 
-		if (1 != sscanf(refname, scanf_fmts[i], short_name))
+		short_name = match_parse_rule(refname, ref_rev_parse_rules[i],
+					      &short_name_len);
+		if (!short_name)
 			continue;
 
-		short_name_len = strlen(short_name);
-
 		/*
 		 * in strict mode, all (except the matched one) rules
 		 * must fail to resolve to a valid non-ambiguous ref
 		 */
 		if (strict)
-			rules_to_fail = nr_rules;
+			rules_to_fail = NUM_REV_PARSE_RULES;
 
 		/*
 		 * check if the short name resolves to a valid ref,
@@ -1388,7 +1391,8 @@ char *refs_shorten_unambiguous_ref(struct ref_store *refs,
 			 */
 			strbuf_reset(&resolved_buf);
 			strbuf_addf(&resolved_buf, rule,
-				    short_name_len, short_name);
+				    cast_size_t_to_int(short_name_len),
+				    short_name);
 			if (refs_ref_exists(refs, resolved_buf.buf))
 				break;
 		}
@@ -1399,12 +1403,11 @@ char *refs_shorten_unambiguous_ref(struct ref_store *refs,
 		 */
 		if (j == rules_to_fail) {
 			strbuf_release(&resolved_buf);
-			return short_name;
+			return xmemdupz(short_name, short_name_len);
 		}
 	}
 
 	strbuf_release(&resolved_buf);
-	free(short_name);
 	return xstrdup(refname);
 }
 
diff --git a/remote.h b/remote.h
index 1c4621b..1ebbe42 100644
--- a/remote.h
+++ b/remote.h
@@ -234,6 +234,11 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
 			     const struct string_list *server_options,
 			     int stateless_rpc);
 
+/* Used for protocol v2 in order to retrieve refs from a remote */
+struct bundle_list;
+int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
+			  struct bundle_list *bundles, int stateless_rpc);
+
 int resolve_remote_symref(struct ref *ref, struct ref *list);
 
 /*
diff --git a/repo-settings.c b/repo-settings.c
index 3021921..3dbd3f0 100644
--- a/repo-settings.c
+++ b/repo-settings.c
@@ -47,6 +47,7 @@ void prepare_repo_settings(struct repository *r)
 	}
 	if (manyfiles) {
 		r->settings.index_version = 4;
+		r->settings.index_skip_hash = 1;
 		r->settings.core_untracked_cache = UNTRACKED_CACHE_WRITE;
 	}
 
@@ -61,6 +62,7 @@ void prepare_repo_settings(struct repository *r)
 	repo_cfg_bool(r, "pack.usesparse", &r->settings.pack_use_sparse, 1);
 	repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1);
 	repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0);
+	repo_cfg_bool(r, "index.skiphash", &r->settings.index_skip_hash, r->settings.index_skip_hash);
 
 	/*
 	 * The GIT_TEST_MULTI_PACK_INDEX variable is special in that
diff --git a/repository.c b/repository.c
index 3427085..3b943d2 100644
--- a/repository.c
+++ b/repository.c
@@ -28,6 +28,8 @@ void initialize_the_repository(void)
 	the_repo.remote_state = remote_state_new();
 	the_repo.parsed_objects = parsed_object_pool_new();
 
+	index_state_init(&the_index, the_repository);
+
 	repo_set_hash_algo(&the_repo, GIT_HASH_SHA1);
 }
 
@@ -269,6 +271,8 @@ void repo_clear(struct repository *repo)
 	parsed_object_pool_clear(repo->parsed_objects);
 	FREE_AND_NULL(repo->parsed_objects);
 
+	FREE_AND_NULL(repo->settings.fsmonitor);
+
 	if (repo->config) {
 		git_configset_clear(repo->config);
 		FREE_AND_NULL(repo->config);
@@ -302,14 +306,13 @@ int repo_read_index(struct repository *repo)
 {
 	int res;
 
-	if (!repo->index)
-		CALLOC_ARRAY(repo->index, 1);
-
 	/* Complete the double-reference */
-	if (!repo->index->repo)
-		repo->index->repo = repo;
-	else if (repo->index->repo != repo)
+	if (!repo->index) {
+		ALLOC_ARRAY(repo->index, 1);
+		index_state_init(repo->index, repo);
+	} else if (repo->index->repo != repo) {
 		BUG("repo's index should point back at itself");
+	}
 
 	res = read_index_from(repo->index, repo->index_file, repo->gitdir);
 
diff --git a/repository.h b/repository.h
index 6c461c5..e8c67ff 100644
--- a/repository.h
+++ b/repository.h
@@ -42,6 +42,7 @@ struct repo_settings {
 	struct fsmonitor_settings *fsmonitor; /* lazily loaded */
 
 	int index_version;
+	int index_skip_hash;
 	enum untracked_cache_setting core_untracked_cache;
 
 	int pack_use_sparse;
diff --git a/revision.c b/revision.c
index ec441b8..21f5f57 100644
--- a/revision.c
+++ b/revision.c
@@ -1813,7 +1813,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
 	worktrees = get_worktrees();
 	for (p = worktrees; *p; p++) {
 		struct worktree *wt = *p;
-		struct index_state istate = { NULL };
+		struct index_state istate = INDEX_STATE_INIT(revs->repo);
 
 		if (wt->is_current)
 			continue; /* current index already taken care of */
@@ -3059,6 +3059,7 @@ void release_revisions(struct rev_info *revs)
 	date_mode_release(&revs->date_mode);
 	release_revisions_mailmap(revs->mailmap);
 	free_grep_patterns(&revs->grep_filter);
+	graph_clear(revs->graph);
 	/* TODO (need to handle "no_free"): diff_free(&revs->diffopt) */
 	diff_free(&revs->pruning);
 	reflog_walk_info_release(revs->reflog_info);
diff --git a/run-command.c b/run-command.c
index 48b9ba6..6bd16ac 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1019,7 +1019,7 @@ static void *run_thread(void *data)
 		sigset_t mask;
 		sigemptyset(&mask);
 		sigaddset(&mask, SIGPIPE);
-		if (pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) {
+		if (pthread_sigmask(SIG_BLOCK, &mask, NULL)) {
 			ret = error("unable to block SIGPIPE in async thread");
 			return (void *)ret;
 		}
@@ -1586,6 +1586,14 @@ static int pp_start_one(struct parallel_processes *pp,
 	if (i == opts->processes)
 		BUG("bookkeeping is hard");
 
+	/*
+	 * By default, do not inherit stdin from the parent process - otherwise,
+	 * all children would share stdin! Users may overwrite this to provide
+	 * something to the child's stdin by having their 'get_next_task'
+	 * callback assign 0 to .no_stdin and an appropriate integer to .in.
+	 */
+	pp->children[i].process.no_stdin = 1;
+
 	code = opts->get_next_task(&pp->children[i].process,
 				   opts->ungroup ? NULL : &pp->children[i].err,
 				   opts->data,
@@ -1601,7 +1609,6 @@ static int pp_start_one(struct parallel_processes *pp,
 		pp->children[i].process.err = -1;
 		pp->children[i].process.stdout_to_stderr = 1;
 	}
-	pp->children[i].process.no_stdin = 1;
 
 	if (start_command(&pp->children[i].process)) {
 		if (opts->start_failure)
@@ -1632,9 +1639,7 @@ static void pp_buffer_stderr(struct parallel_processes *pp,
 			     const struct run_process_parallel_opts *opts,
 			     int output_timeout)
 {
-	int i;
-
-	while ((i = poll(pp->pfd, opts->processes, output_timeout) < 0)) {
+	while (poll(pp->pfd, opts->processes, output_timeout) < 0) {
 		if (errno == EINTR)
 			continue;
 		pp_cleanup(pp, opts);
@@ -1853,7 +1858,7 @@ enum start_bg_result start_bg_command(struct child_process *cmd,
 		 *
 		 * We also assume that `start_command()` does not add
 		 * us to the cleanup list.  And that it calls
-		 * calls `child_process_clear()`.
+		 * `child_process_clear()`.
 		 */
 		sbgr = SBGR_ERROR;
 		goto done;
diff --git a/scalar.c b/scalar.c
index 6c52243..ca19b95 100644
--- a/scalar.c
+++ b/scalar.c
@@ -143,6 +143,7 @@ static int set_recommended_config(int reconfigure)
 		{ "credential.validate", "false", 1 }, /* GCM4W-only */
 		{ "gc.auto", "0", 1 },
 		{ "gui.GCWarning", "false", 1 },
+		{ "index.skipHash", "false", 1 },
 		{ "index.threads", "true", 1 },
 		{ "index.version", "4", 1 },
 		{ "merge.stat", "false", 1 },
@@ -261,7 +262,7 @@ static int register_dir(void)
 		return error(_("could not set recommended config"));
 
 	if (toggle_maintenance(1))
-		return error(_("could not turn on maintenance"));
+		warning(_("could not turn on maintenance"));
 
 	if (have_fsmonitor_support() && start_fsmonitor_daemon()) {
 		return error(_("could not start the FSMonitor daemon"));
@@ -404,7 +405,7 @@ void load_builtin_commands(const char *prefix, struct cmdnames *cmds)
 static int cmd_clone(int argc, const char **argv)
 {
 	const char *branch = NULL;
-	int full_clone = 0, single_branch = 0;
+	int full_clone = 0, single_branch = 0, show_progress = isatty(2);
 	struct option clone_options[] = {
 		OPT_STRING('b', "branch", &branch, N_("<branch>"),
 			   N_("branch to checkout after clone")),
@@ -499,7 +500,9 @@ static int cmd_clone(int argc, const char **argv)
 	if (set_recommended_config(0))
 		return error(_("could not configure '%s'"), dir);
 
-	if ((res = run_git("fetch", "--quiet", "origin", NULL))) {
+	if ((res = run_git("fetch", "--quiet",
+				show_progress ? "--progress" : "--no-progress",
+				"origin", NULL))) {
 		warning(_("partial clone failed; attempting full clone"));
 
 		if (set_config("remote.origin.promisor") ||
@@ -508,7 +511,9 @@ static int cmd_clone(int argc, const char **argv)
 			goto cleanup;
 		}
 
-		if ((res = run_git("fetch", "--quiet", "origin", NULL)))
+		if ((res = run_git("fetch", "--quiet",
+					show_progress ? "--progress" : "--no-progress",
+					"origin", NULL)))
 			goto cleanup;
 	}
 
diff --git a/sequencer.c b/sequencer.c
index f51d403..1c96a75 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -351,10 +351,25 @@ static const char *gpg_sign_opt_quoted(struct replay_opts *opts)
 	return buf.buf;
 }
 
+void replay_opts_release(struct replay_opts *opts)
+{
+	free(opts->gpg_sign);
+	free(opts->reflog_action);
+	free(opts->default_strategy);
+	free(opts->strategy);
+	for (size_t i = 0; i < opts->xopts_nr; i++)
+		free(opts->xopts[i]);
+	free(opts->xopts);
+	strbuf_release(&opts->current_fixups);
+	if (opts->revs)
+		release_revisions(opts->revs);
+	free(opts->revs);
+}
+
 int sequencer_remove_state(struct replay_opts *opts)
 {
 	struct strbuf buf = STRBUF_INIT;
-	int i, ret = 0;
+	int ret = 0;
 
 	if (is_rebase_i(opts) &&
 	    strbuf_read_file(&buf, rebase_path_refs_to_delete(), 0) > 0) {
@@ -373,15 +388,6 @@ int sequencer_remove_state(struct replay_opts *opts)
 		}
 	}
 
-	free(opts->gpg_sign);
-	free(opts->reflog_action);
-	free(opts->default_strategy);
-	free(opts->strategy);
-	for (i = 0; i < opts->xopts_nr; i++)
-		free(opts->xopts[i]);
-	free(opts->xopts);
-	strbuf_release(&opts->current_fixups);
-
 	strbuf_reset(&buf);
 	strbuf_addstr(&buf, get_dir(opts));
 	if (remove_dir_recursively(&buf, 0))
@@ -2271,8 +2277,10 @@ static int do_pick_commit(struct repository *r,
 		reword = 1;
 	else if (is_fixup(command)) {
 		if (update_squash_messages(r, command, commit,
-					   opts, item->flags))
-			return -1;
+					   opts, item->flags)) {
+			res = -1;
+			goto leave;
+		}
 		flags |= AMEND_MSG;
 		if (!final_fixup)
 			msg_file = rebase_path_squash_msg();
@@ -2282,9 +2290,11 @@ static int do_pick_commit(struct repository *r,
 		} else {
 			const char *dest = git_path_squash_msg(r);
 			unlink(dest);
-			if (copy_file(dest, rebase_path_squash_msg(), 0666))
-				return error(_("could not rename '%s' to '%s'"),
-					     rebase_path_squash_msg(), dest);
+			if (copy_file(dest, rebase_path_squash_msg(), 0666)) {
+				res = error(_("could not rename '%s' to '%s'"),
+					    rebase_path_squash_msg(), dest);
+				goto leave;
+			}
 			unlink(git_path_merge_msg(r));
 			msg_file = dest;
 			flags |= EDIT_MSG;
@@ -2322,7 +2332,6 @@ static int do_pick_commit(struct repository *r,
 		free_commit_list(common);
 		free_commit_list(remotes);
 	}
-	strbuf_release(&msgbuf);
 
 	/*
 	 * If the merge was clean or if it failed due to conflict, we write
@@ -2396,6 +2405,7 @@ static int do_pick_commit(struct repository *r,
 leave:
 	free_message(commit, &msg);
 	free(author);
+	strbuf_release(&msgbuf);
 	update_abort_safety_file();
 
 	return res;
@@ -2469,12 +2479,39 @@ static int is_command(enum todo_command command, const char **bol)
 {
 	const char *str = todo_command_info[command].str;
 	const char nick = todo_command_info[command].c;
-	const char *p = *bol + 1;
+	const char *p = *bol;
 
-	return skip_prefix(*bol, str, bol) ||
-		((nick && **bol == nick) &&
-		 (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || !*p) &&
-		 (*bol = p));
+	return (skip_prefix(p, str, &p) || (nick && *p++ == nick)) &&
+		(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || !*p) &&
+		(*bol = p);
+}
+
+static int check_label_or_ref_arg(enum todo_command command, const char *arg)
+{
+	switch (command) {
+	case TODO_LABEL:
+		/*
+		 * '#' is not a valid label as the merge command uses it to
+		 * separate merge parents from the commit subject.
+		 */
+		if (!strcmp(arg, "#") ||
+		    check_refname_format(arg, REFNAME_ALLOW_ONELEVEL))
+			return error(_("'%s' is not a valid label"), arg);
+		break;
+
+	case TODO_UPDATE_REF:
+		if (check_refname_format(arg, REFNAME_ALLOW_ONELEVEL))
+			return error(_("'%s' is not a valid refname"), arg);
+		if (check_refname_format(arg, 0))
+			return error(_("update-ref requires a fully qualified "
+				       "refname e.g. refs/heads/%s"), arg);
+		break;
+
+	default:
+		BUG("unexpected todo_command");
+	}
+
+	return 0;
 }
 
 static int parse_insn_line(struct repository *r, struct todo_item *item,
@@ -2503,7 +2540,8 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
 			break;
 		}
 	if (i >= TODO_COMMENT)
-		return -1;
+		return error(_("invalid command '%.*s'"),
+			     (int)strcspn(bol, " \t\r\n"), bol);
 
 	/* Eat up extra spaces/ tabs before object name */
 	padding = strspn(bol, " \t");
@@ -2525,19 +2563,26 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
 
 	if (item->command == TODO_EXEC || item->command == TODO_LABEL ||
 	    item->command == TODO_RESET || item->command == TODO_UPDATE_REF) {
+		int ret = 0;
+
 		item->commit = NULL;
 		item->arg_offset = bol - buf;
 		item->arg_len = (int)(eol - bol);
-		return 0;
+		if (item->command == TODO_LABEL ||
+		    item->command == TODO_UPDATE_REF) {
+			saved = *eol;
+			*eol = '\0';
+			ret = check_label_or_ref_arg(item->command, bol);
+			*eol = saved;
+		}
+		return ret;
 	}
 
 	if (item->command == TODO_FIXUP) {
-		if (skip_prefix(bol, "-C", &bol) &&
-		   (*bol == ' ' || *bol == '\t')) {
+		if (skip_prefix(bol, "-C", &bol)) {
 			bol += strspn(bol, " \t");
 			item->flags |= TODO_REPLACE_FIXUP_MSG;
-		} else if (skip_prefix(bol, "-c", &bol) &&
-				  (*bol == ' ' || *bol == '\t')) {
+		} else if (skip_prefix(bol, "-c", &bol)) {
 			bol += strspn(bol, " \t");
 			item->flags |= TODO_EDIT_FIXUP_MSG;
 		}
@@ -2896,6 +2941,7 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
 	strbuf_reset(buf);
 	if (!read_oneliner(buf, rebase_path_strategy(), 0))
 		return;
+	free(opts->strategy);
 	opts->strategy = strbuf_detach(buf, NULL);
 	if (!read_oneliner(buf, rebase_path_strategy_opts(), 0))
 		return;
@@ -4833,8 +4879,7 @@ static int pick_commits(struct repository *r,
 		if (!stat(rebase_path_rewritten_list(), &st) &&
 				st.st_size > 0) {
 			struct child_process child = CHILD_PROCESS_INIT;
-			const char *post_rewrite_hook =
-				find_hook("post-rewrite");
+			struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
 
 			child.in = open(rebase_path_rewritten_list(), O_RDONLY);
 			child.git_cmd = 1;
@@ -4844,18 +4889,9 @@ static int pick_commits(struct repository *r,
 			/* we don't care if this copying failed */
 			run_command(&child);
 
-			if (post_rewrite_hook) {
-				struct child_process hook = CHILD_PROCESS_INIT;
-
-				hook.in = open(rebase_path_rewritten_list(),
-					O_RDONLY);
-				hook.stdout_to_stderr = 1;
-				hook.trace2_hook_name = "post-rewrite";
-				strvec_push(&hook.args, post_rewrite_hook);
-				strvec_push(&hook.args, "rebase");
-				/* we don't care if this hook failed */
-				run_command(&hook);
-			}
+			hook_opt.path_to_stdin = rebase_path_rewritten_list();
+			strvec_push(&hook_opt.args, "rebase");
+			run_hooks_opt("post-rewrite", &hook_opt);
 		}
 		apply_autostash(rebase_path_autostash());
 
@@ -5744,8 +5780,8 @@ static void todo_list_add_exec_commands(struct todo_list *todo_list,
 
 		base_items[i].command = TODO_EXEC;
 		base_items[i].offset_in_buf = base_offset;
-		base_items[i].arg_offset = base_offset + strlen("exec ");
-		base_items[i].arg_len = command_len - strlen("exec ");
+		base_items[i].arg_offset = base_offset;
+		base_items[i].arg_len = command_len;
 
 		base_offset += command_len + 1;
 	}
diff --git a/sequencer.h b/sequencer.h
index 888c18a..3bcdfa1 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -158,6 +158,7 @@ int sequencer_pick_revisions(struct repository *repo,
 int sequencer_continue(struct repository *repo, struct replay_opts *opts);
 int sequencer_rollback(struct repository *repo, struct replay_opts *opts);
 int sequencer_skip(struct repository *repo, struct replay_opts *opts);
+void replay_opts_release(struct replay_opts *opts);
 int sequencer_remove_state(struct replay_opts *opts);
 
 #define TODO_LIST_KEEP_EMPTY (1U << 0)
diff --git a/serve.c b/serve.c
index 733347f..cbf4a14 100644
--- a/serve.c
+++ b/serve.c
@@ -7,6 +7,7 @@
 #include "protocol-caps.h"
 #include "serve.h"
 #include "upload-pack.h"
+#include "bundle-uri.h"
 
 static int advertise_sid = -1;
 static int client_hash_algo = GIT_HASH_SHA1;
@@ -135,6 +136,11 @@ static struct protocol_capability capabilities[] = {
 		.advertise = always_advertise,
 		.command = cap_object_info,
 	},
+	{
+		.name = "bundle-uri",
+		.advertise = bundle_uri_advertise,
+		.command = bundle_uri_command,
+	},
 };
 
 void protocol_v2_advertise_capabilities(void)
diff --git a/sparse-index.c b/sparse-index.c
index 8c269da..147a133 100644
--- a/sparse-index.c
+++ b/sparse-index.c
@@ -128,9 +128,6 @@ int is_sparse_index_allowed(struct index_state *istate, int flags)
 	if (!core_apply_sparse_checkout || !core_sparse_checkout_cone)
 		return 0;
 
-	if (!istate->repo)
-		istate->repo = the_repository;
-
 	if (!(flags & SPARSE_INDEX_MEMORY_ONLY)) {
 		int test_env;
 
@@ -299,7 +296,7 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
 	 * If the index is already full, then keep it full. We will convert
 	 * it to a sparse index on write, if possible.
 	 */
-	if (!istate || istate->sparse_index == INDEX_EXPANDED)
+	if (istate->sparse_index == INDEX_EXPANDED)
 		return;
 
 	/*
@@ -327,9 +324,6 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
 			pl = NULL;
 	}
 
-	if (!istate->repo)
-		istate->repo = the_repository;
-
 	/*
 	 * A NULL pattern set indicates we are expanding a full index, so
 	 * we use a special region name that indicates the full expansion.
@@ -424,6 +418,8 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
 
 void ensure_full_index(struct index_state *istate)
 {
+	if (!istate)
+		BUG("ensure_full_index() must get an index!");
 	expand_index(istate, NULL);
 }
 
@@ -547,12 +543,9 @@ void expand_to_path(struct index_state *istate,
 	if (in_expand_to_path)
 		return;
 
-	if (!istate || !istate->sparse_index)
+	if (!istate->sparse_index)
 		return;
 
-	if (!istate->repo)
-		istate->repo = the_repository;
-
 	in_expand_to_path = 1;
 
 	/*
diff --git a/split-index.c b/split-index.c
index 9d0ccc3..5d0f047 100644
--- a/split-index.c
+++ b/split-index.c
@@ -90,7 +90,8 @@ void move_cache_to_base_index(struct index_state *istate)
 		mem_pool_combine(istate->ce_mem_pool, istate->split_index->base->ce_mem_pool);
 	}
 
-	CALLOC_ARRAY(si->base, 1);
+	ALLOC_ARRAY(si->base, 1);
+	index_state_init(si->base, istate->repo);
 	si->base->version = istate->version;
 	/* zero timestamp disables racy test in ce_write_index() */
 	si->base->timestamp = istate->timestamp;
diff --git a/strbuf.c b/strbuf.c
index 0890b14..c383f41 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -1200,3 +1200,9 @@ int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
 	free(path2);
 	return res;
 }
+
+void strbuf_strip_file_from_path(struct strbuf *sb)
+{
+	char *path_sep = find_last_dir_sep(sb->buf);
+	strbuf_setlen(sb, path_sep ? path_sep - sb->buf + 1 : 0);
+}
diff --git a/strbuf.h b/strbuf.h
index 76965a1..f6dbb96 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -664,6 +664,17 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
 int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
 			      const char *const *env);
 
+/*
+ * Remove the filename from the provided path string. If the path
+ * contains a trailing separator, then the path is considered a directory
+ * and nothing is modified.
+ *
+ * Examples:
+ * - "/path/to/file" -> "/path/to/"
+ * - "/path/to/dir/" -> "/path/to/dir/"
+ */
+void strbuf_strip_file_from_path(struct strbuf *sb);
+
 void strbuf_add_lines(struct strbuf *sb,
 		      const char *prefix,
 		      const char *buf,
diff --git a/streaming.c b/streaming.c
index 7b2f8b2..27841dc 100644
--- a/streaming.c
+++ b/streaming.c
@@ -38,7 +38,7 @@ struct git_istream {
 
 	union {
 		struct {
-			char *buf; /* from read_object() */
+			char *buf; /* from oid_object_info_extended() */
 			unsigned long read_ptr;
 		} incore;
 
@@ -388,12 +388,17 @@ static ssize_t read_istream_incore(struct git_istream *st, char *buf, size_t sz)
 static int open_istream_incore(struct git_istream *st, struct repository *r,
 			       const struct object_id *oid, enum object_type *type)
 {
-	st->u.incore.buf = read_object_file_extended(r, oid, type, &st->size, 0);
+	struct object_info oi = OBJECT_INFO_INIT;
+
 	st->u.incore.read_ptr = 0;
 	st->close = close_istream_incore;
 	st->read = read_istream_incore;
 
-	return st->u.incore.buf ? 0 : -1;
+	oi.typep = type;
+	oi.sizep = &st->size;
+	oi.contentp = (void **)&st->u.incore.buf;
+	return oid_object_info_extended(r, oid, &oi,
+					OBJECT_INFO_DIE_IF_CORRUPT);
 }
 
 /*****************************************************************************
diff --git a/submodule.c b/submodule.c
index 0b87ae6..397e413 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2078,14 +2078,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)
 	strbuf_release(&config_path);
 }
 
-static const char *get_super_prefix_or_empty(void)
-{
-	const char *s = get_super_prefix();
-	if (!s)
-		s = "";
-	return s;
-}
-
 static int submodule_has_dirty_index(const struct submodule *sub)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2107,7 +2099,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)
 	return finish_command(&cp);
 }
 
-static void submodule_reset_index(const char *path)
+static void submodule_reset_index(const char *path, const char *super_prefix)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
 
@@ -2120,10 +2112,10 @@ static void submodule_reset_index(const char *path)
 	cp.no_stdin = 1;
 	cp.dir = path;
 
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	/* TODO: determine if this might overwright untracked files */
 	strvec_pushl(&cp.args, "read-tree", "-u", "--reset", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
+		     (super_prefix ? super_prefix : ""), path);
 
 	strvec_push(&cp.args, empty_tree_oid_hex());
 
@@ -2136,10 +2128,9 @@ static void submodule_reset_index(const char *path)
  * For edge cases (a submodule coming into existence or removing a submodule)
  * pass NULL for old or new respectively.
  */
-int submodule_move_head(const char *path,
-			 const char *old_head,
-			 const char *new_head,
-			 unsigned flags)
+int submodule_move_head(const char *path, const char *super_prefix,
+			const char *old_head, const char *new_head,
+			unsigned flags)
 {
 	int ret = 0;
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2176,7 +2167,8 @@ int submodule_move_head(const char *path,
 	if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
 		if (old_head) {
 			if (!submodule_uses_gitfile(path))
-				absorb_git_dir_into_superproject(path);
+				absorb_git_dir_into_superproject(path,
+								 super_prefix);
 			else {
 				char *dotgit = xstrfmt("%s/.git", path);
 				char *git_dir = xstrdup(read_gitfile(dotgit));
@@ -2202,7 +2194,7 @@ int submodule_move_head(const char *path,
 			strbuf_release(&gitdir);
 
 			/* make sure the index is clean as well */
-			submodule_reset_index(path);
+			submodule_reset_index(path, super_prefix);
 		}
 
 		if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
@@ -2220,9 +2212,9 @@ int submodule_move_head(const char *path,
 	cp.no_stdin = 1;
 	cp.dir = path;
 
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	strvec_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
+		     (super_prefix ? super_prefix : ""), path);
 
 	if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
 		strvec_push(&cp.args, "-n");
@@ -2350,7 +2342,8 @@ int validate_submodule_path(const char *path)
  * Embeds a single submodules git directory into the superprojects git dir,
  * non recursively.
  */
-static void relocate_single_git_dir_into_superproject(const char *path)
+static void relocate_single_git_dir_into_superproject(const char *path,
+						      const char *super_prefix)
 {
 	char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
 	struct strbuf new_gitdir = STRBUF_INIT;
@@ -2383,7 +2376,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)
 	real_new_git_dir = real_pathdup(new_gitdir.buf, 1);
 
 	fprintf(stderr, _("Migrating git directory of '%s%s' from\n'%s' to\n'%s'\n"),
-		get_super_prefix_or_empty(), path,
+		super_prefix ? super_prefix : "", path,
 		real_old_git_dir, real_new_git_dir);
 
 	relocate_gitdir(path, real_old_git_dir, real_new_git_dir);
@@ -2394,7 +2387,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)
 	strbuf_release(&new_gitdir);
 }
 
-static void absorb_git_dir_into_superproject_recurse(const char *path)
+static void absorb_git_dir_into_superproject_recurse(const char *path,
+						     const char *super_prefix)
 {
 
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2405,10 +2399,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
 	cp.dir = path;
 	cp.git_cmd = 1;
 	cp.no_stdin = 1;
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	strvec_pushl(&cp.args, "submodule--helper",
 		     "absorbgitdirs", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
+		     super_prefix : "", path);
+
 	prepare_submodule_repo_env(&cp.env);
 	if (run_command(&cp))
 		die(_("could not recurse into submodule '%s'"), path);
@@ -2419,7 +2414,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
  * having its git directory within the working tree to the git dir nested
  * in its superprojects git dir under modules/.
  */
-void absorb_git_dir_into_superproject(const char *path)
+void absorb_git_dir_into_superproject(const char *path,
+				      const char *super_prefix)
 {
 	int err_code;
 	const char *sub_git_dir;
@@ -2465,14 +2461,14 @@ void absorb_git_dir_into_superproject(const char *path)
 		char *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);
 
 		if (!starts_with(real_sub_git_dir, real_common_git_dir))
-			relocate_single_git_dir_into_superproject(path);
+			relocate_single_git_dir_into_superproject(path, super_prefix);
 
 		free(real_sub_git_dir);
 		free(real_common_git_dir);
 	}
 	strbuf_release(&gitdir);
 
-	absorb_git_dir_into_superproject_recurse(path);
+	absorb_git_dir_into_superproject_recurse(path, super_prefix);
 }
 
 int get_superproject_working_tree(struct strbuf *buf)
diff --git a/submodule.h b/submodule.h
index fb770f1..b50d29e 100644
--- a/submodule.h
+++ b/submodule.h
@@ -155,9 +155,8 @@ int validate_submodule_path(const char *path);
 
 #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)
 #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)
-int submodule_move_head(const char *path,
-			const char *old,
-			const char *new_head,
+int submodule_move_head(const char *path, const char *super_prefix,
+			const char *old_head, const char *new_head,
 			unsigned flags);
 
 void submodule_unset_core_worktree(const struct submodule *sub);
@@ -169,7 +168,8 @@ void submodule_unset_core_worktree(const struct submodule *sub);
  */
 void prepare_submodule_repo_env(struct strvec *env);
 
-void absorb_git_dir_into_superproject(const char *path);
+void absorb_git_dir_into_superproject(const char *path,
+				      const char *super_prefix);
 
 /*
  * Return the absolute path of the working tree of the superproject, which this
diff --git a/t/README b/t/README
index 979b2d4..29576c3 100644
--- a/t/README
+++ b/t/README
@@ -449,10 +449,6 @@
 GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path
 by overriding the minimum number of cache entries required per thread.
 
-GIT_TEST_ADD_I_USE_BUILTIN=<boolean>, when false, disables the
-built-in version of git add -i. See 'add.interactive.useBuiltin' in
-git-config(1).
-
 GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading
 of the index for the whole test suite by bypassing the default number of
 cache entries and thread minimums. Setting this to 1 will make the
diff --git a/t/helper/test-bundle-uri.c b/t/helper/test-bundle-uri.c
index 25afd39..b18e760 100644
--- a/t/helper/test-bundle-uri.c
+++ b/t/helper/test-bundle-uri.c
@@ -3,6 +3,10 @@
 #include "bundle-uri.h"
 #include "strbuf.h"
 #include "string-list.h"
+#include "transport.h"
+#include "ref-filter.h"
+#include "remote.h"
+#include "refs.h"
 
 enum input_mode {
 	KEY_VALUE_PAIRS,
@@ -36,6 +40,8 @@ static int cmd__bundle_uri_parse(int argc, const char **argv, enum input_mode mo
 
 	init_bundle_list(&list);
 
+	list.baseURI = xstrdup("<uri>");
+
 	switch (mode) {
 	case KEY_VALUE_PAIRS:
 		if (argc != 1)
@@ -68,6 +74,39 @@ static int cmd__bundle_uri_parse(int argc, const char **argv, enum input_mode mo
 	usage_with_options(usage, options);
 }
 
+static int cmd_ls_remote(int argc, const char **argv)
+{
+	const char *dest;
+	struct remote *remote;
+	struct transport *transport;
+	int status = 0;
+
+	dest = argc > 1 ? argv[1] : NULL;
+
+	remote = remote_get(dest);
+	if (!remote) {
+		if (dest)
+			die(_("bad repository '%s'"), dest);
+		die(_("no remote configured to get bundle URIs from"));
+	}
+	if (!remote->url_nr)
+		die(_("remote '%s' has no configured URL"), dest);
+
+	transport = transport_get(remote, NULL);
+	if (transport_get_remote_bundle_uri(transport) < 0) {
+		error(_("could not get the bundle-uri list"));
+		status = 1;
+		goto cleanup;
+	}
+
+	print_bundle_list(stdout, transport->bundles);
+
+cleanup:
+	if (transport_disconnect(transport))
+		return 1;
+	return status;
+}
+
 int cmd__bundle_uri(int argc, const char **argv)
 {
 	const char *usage[] = {
@@ -88,6 +127,8 @@ int cmd__bundle_uri(int argc, const char **argv)
 		return cmd__bundle_uri_parse(argc - 1, argv + 1, KEY_VALUE_PAIRS);
 	if (!strcmp(argv[1], "parse-config"))
 		return cmd__bundle_uri_parse(argc - 1, argv + 1, CONFIG_FILE);
+	if (!strcmp(argv[1], "ls-remote"))
+		return cmd_ls_remote(argc - 1, argv + 1);
 	error("there is no test-tool bundle-uri tool '%s'", argv[1]);
 
 usage:
diff --git a/t/helper/test-ctype.c b/t/helper/test-ctype.c
index 92c4c23..b21bd67 100644
--- a/t/helper/test-ctype.c
+++ b/t/helper/test-ctype.c
@@ -11,9 +11,14 @@ static void report_error(const char *class, int ch)
 
 static int is_in(const char *s, int ch)
 {
-	/* We can't find NUL using strchr.  It's classless anyway. */
+	/*
+	 * We can't find NUL using strchr. Accept it as the first
+	 * character in the spec -- there are no empty classes.
+	 */
 	if (ch == '\0')
-		return 0;
+		return ch == *s;
+	if (*s == '\0')
+		s++;
 	return !!strchr(s, ch);
 }
 
@@ -28,6 +33,20 @@ static int is_in(const char *s, int ch)
 #define DIGIT "0123456789"
 #define LOWER "abcdefghijklmnopqrstuvwxyz"
 #define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define PUNCT "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
+#define ASCII \
+	"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
+	"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
+	"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" \
+	"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \
+	"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \
+	"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" \
+	"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \
+	"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+#define CNTRL \
+	"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
+	"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
+	"\x7f"
 
 int cmd__ctype(int argc, const char **argv)
 {
@@ -38,6 +57,13 @@ int cmd__ctype(int argc, const char **argv)
 	TEST_CLASS(is_glob_special, "*?[\\");
 	TEST_CLASS(is_regex_special, "$()*+.?[\\^{|");
 	TEST_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~");
+	TEST_CLASS(isascii, ASCII);
+	TEST_CLASS(islower, LOWER);
+	TEST_CLASS(isupper, UPPER);
+	TEST_CLASS(iscntrl, CNTRL);
+	TEST_CLASS(ispunct, PUNCT);
+	TEST_CLASS(isxdigit, DIGIT "abcdefABCDEF");
+	TEST_CLASS(isprint, LOWER UPPER DIGIT PUNCT " ");
 
 	return rc;
 }
diff --git a/t/helper/test-dir-iterator.c b/t/helper/test-dir-iterator.c
index 659b6bf..6b297bd 100644
--- a/t/helper/test-dir-iterator.c
+++ b/t/helper/test-dir-iterator.c
@@ -15,7 +15,7 @@ static const char *error_name(int error_number)
 
 /*
  * usage:
- * tool-test dir-iterator [--follow-symlinks] [--pedantic] directory_path
+ * tool-test dir-iterator [--pedantic] directory_path
  */
 int cmd__dir_iterator(int argc, const char **argv)
 {
@@ -24,9 +24,7 @@ int cmd__dir_iterator(int argc, const char **argv)
 	int iter_status;
 
 	for (++argv, --argc; *argv && starts_with(*argv, "--"); ++argv, --argc) {
-		if (strcmp(*argv, "--follow-symlinks") == 0)
-			flags |= DIR_ITERATOR_FOLLOW_SYMLINKS;
-		else if (strcmp(*argv, "--pedantic") == 0)
+		if (strcmp(*argv, "--pedantic") == 0)
 			flags |= DIR_ITERATOR_PEDANTIC;
 		else
 			die("invalid option '%s'", *argv);
diff --git a/builtin/env--helper.c b/t/helper/test-env-helper.c
similarity index 71%
rename from builtin/env--helper.c
rename to t/helper/test-env-helper.c
index ea04c16..66c88b8 100644
--- a/builtin/env--helper.c
+++ b/t/helper/test-env-helper.c
@@ -1,9 +1,9 @@
-#include "builtin.h"
+#include "test-tool.h"
 #include "config.h"
 #include "parse-options.h"
 
 static char const * const env__helper_usage[] = {
-	N_("git env--helper --type=[bool|ulong] <options> <env-var>"),
+	"test-tool env-helper --type=[bool|ulong] <options> <env-var>",
 	NULL
 };
 
@@ -24,12 +24,12 @@ static int option_parse_type(const struct option *opt, const char *arg,
 	else if (!strcmp(arg, "ulong"))
 		*cmdmode = ENV_HELPER_TYPE_ULONG;
 	else
-		die(_("unrecognized --type argument, %s"), arg);
+		die("unrecognized --type argument, %s", arg);
 
 	return 0;
 }
 
-int cmd_env__helper(int argc, const char **argv, const char *prefix)
+int cmd__env_helper(int argc, const char **argv)
 {
 	int exit_code = 0;
 	const char *env_variable = NULL;
@@ -39,17 +39,17 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)
 	unsigned long ret_ulong, default_ulong;
 	enum cmdmode cmdmode = 0;
 	struct option opts[] = {
-		OPT_CALLBACK_F(0, "type", &cmdmode, N_("type"),
-			       N_("value is given this type"), PARSE_OPT_NONEG,
+		OPT_CALLBACK_F(0, "type", &cmdmode, "type",
+			       "value is given this type", PARSE_OPT_NONEG,
 			       option_parse_type),
-		OPT_STRING(0, "default", &env_default, N_("value"),
-			   N_("default for git_env_*(...) to fall back on")),
+		OPT_STRING(0, "default", &env_default, "value",
+			   "default for git_env_*(...) to fall back on"),
 		OPT_BOOL(0, "exit-code", &exit_code,
-			 N_("be quiet only use git_env_*() value as exit code")),
+			 "be quiet only use git_env_*() value as exit code"),
 		OPT_END(),
 	};
 
-	argc = parse_options(argc, argv, prefix, opts, env__helper_usage,
+	argc = parse_options(argc, argv, NULL, opts, env__helper_usage,
 			     PARSE_OPT_KEEP_UNKNOWN_OPT);
 	if (env_default && !*env_default)
 		usage_with_options(env__helper_usage, opts);
@@ -64,7 +64,7 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)
 		if (env_default) {
 			default_int = git_parse_maybe_bool(env_default);
 			if (default_int == -1) {
-				error(_("option `--default' expects a boolean value with `--type=bool`, not `%s`"),
+				error("option `--default' expects a boolean value with `--type=bool`, not `%s`",
 				      env_default);
 				usage_with_options(env__helper_usage, opts);
 			}
@@ -79,7 +79,7 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)
 	case ENV_HELPER_TYPE_ULONG:
 		if (env_default) {
 			if (!git_parse_ulong(env_default, &default_ulong)) {
-				error(_("option `--default' expects an unsigned long value with `--type=ulong`, not `%s`"),
+				error("option `--default' expects an unsigned long value with `--type=ulong`, not `%s`",
 				      env_default);
 				usage_with_options(env__helper_usage, opts);
 			}
diff --git a/t/helper/test-fake-ssh.c b/t/helper/test-fake-ssh.c
index 2e576bc..27323cb 100644
--- a/t/helper/test-fake-ssh.c
+++ b/t/helper/test-fake-ssh.c
@@ -17,6 +17,7 @@ int cmd_main(int argc, const char **argv)
 	f = fopen(buf.buf, "w");
 	if (!f)
 		die("Could not write to %s", buf.buf);
+	strbuf_release(&buf);
 	for (i = 0; i < argc; i++)
 		fprintf(f, "%s%s", i > 0 ? " " : "", i > 0 ? argv[i] : "ssh:");
 	fprintf(f, "\n");
diff --git a/t/helper/test-genzeros.c b/t/helper/test-genzeros.c
index 8ca988d..47af843 100644
--- a/t/helper/test-genzeros.c
+++ b/t/helper/test-genzeros.c
@@ -17,15 +17,16 @@ int cmd__genzeros(int argc, const char **argv)
 
 	/* Writing out individual NUL bytes is slow... */
 	while (count < 0)
-		if (write(1, zeros, ARRAY_SIZE(zeros)) < 0)
-			return -1;
+		if (xwrite(1, zeros, ARRAY_SIZE(zeros)) < 0)
+			die_errno("write error");
 
 	while (count > 0) {
-		n = write(1, zeros, count < ARRAY_SIZE(zeros) ?
-			  count : ARRAY_SIZE(zeros));
+		n = xwrite(1, zeros,
+			   count < ARRAY_SIZE(zeros)
+			   ? count : ARRAY_SIZE(zeros));
 
 		if (n < 0)
-			return -1;
+			die_errno("write error");
 
 		count -= n;
 	}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 7eb1a26..abe8a78 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -28,6 +28,7 @@ static struct test_cmd cmds[] = {
 	{ "dump-fsmonitor", cmd__dump_fsmonitor },
 	{ "dump-split-index", cmd__dump_split_index },
 	{ "dump-untracked-cache", cmd__dump_untracked_cache },
+	{ "env-helper", cmd__env_helper },
 	{ "example-decorate", cmd__example_decorate },
 	{ "fast-rebase", cmd__fast_rebase },
 	{ "fsmonitor-client", cmd__fsmonitor_client },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 2e20a16..ea26724 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -22,6 +22,7 @@ int cmd__dump_fsmonitor(int argc, const char **argv);
 int cmd__dump_split_index(int argc, const char **argv);
 int cmd__dump_untracked_cache(int argc, const char **argv);
 int cmd__dump_reftable(int argc, const char **argv);
+int cmd__env_helper(int argc, const char **argv);
 int cmd__example_decorate(int argc, const char **argv);
 int cmd__fast_rebase(int argc, const char **argv);
 int cmd__fsmonitor_client(int argc, const char **argv);
diff --git a/t/interop/interop-lib.sh b/t/interop/interop-lib.sh
index 3e0a291..62f4481 100644
--- a/t/interop/interop-lib.sh
+++ b/t/interop/interop-lib.sh
@@ -68,7 +68,7 @@
 	wrap_git .bin/git.a "$DIR_A" &&
 	wrap_git .bin/git.b "$DIR_B" &&
 	write_script .bin/git <<-\EOF &&
-	echo >&2 fatal: test tried to run generic git
+	echo >&2 fatal: test tried to run generic git: $*
 	exit 1
 	EOF
 	PATH=$(pwd)/.bin:$PATH
diff --git a/t/lib-bundle-uri-protocol.sh b/t/lib-bundle-uri-protocol.sh
new file mode 100644
index 0000000..a4a1af8
--- /dev/null
+++ b/t/lib-bundle-uri-protocol.sh
@@ -0,0 +1,216 @@
+# Set up and run tests of the 'bundle-uri' command in protocol v2
+#
+# The test that includes this script should set BUNDLE_URI_PROTOCOL
+# to one of "file", "git", or "http".
+
+BUNDLE_URI_TEST_PARENT=
+BUNDLE_URI_TEST_URI=
+BUNDLE_URI_TEST_BUNDLE_URI=
+case "$BUNDLE_URI_PROTOCOL" in
+file)
+	BUNDLE_URI_PARENT=file_parent
+	BUNDLE_URI_REPO_URI="file://$PWD/file_parent"
+	BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URI/fake.bdl"
+	test_set_prereq BUNDLE_URI_FILE
+	;;
+git)
+	. "$TEST_DIRECTORY"/lib-git-daemon.sh
+	start_git_daemon --export-all --enable=receive-pack
+	BUNDLE_URI_PARENT="$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent"
+	BUNDLE_URI_REPO_URI="$GIT_DAEMON_URL/parent"
+	BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl"
+	test_set_prereq BUNDLE_URI_GIT
+	;;
+http)
+	. "$TEST_DIRECTORY"/lib-httpd.sh
+	start_httpd
+	BUNDLE_URI_PARENT="$HTTPD_DOCUMENT_ROOT_PATH/http_parent"
+	BUNDLE_URI_REPO_URI="$HTTPD_URL/smart/http_parent"
+	BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl"
+	test_set_prereq BUNDLE_URI_HTTP
+	;;
+*)
+	BUG "Need to pass valid BUNDLE_URI_PROTOCOL (was \"$BUNDLE_URI_PROTOCOL\")"
+	;;
+esac
+
+test_expect_success "setup protocol v2 $BUNDLE_URI_PROTOCOL:// tests" '
+	git init "$BUNDLE_URI_PARENT" &&
+	test_commit -C "$BUNDLE_URI_PARENT" one &&
+	git -C "$BUNDLE_URI_PARENT" config uploadpack.advertiseBundleURIs true
+'
+
+case "$BUNDLE_URI_PROTOCOL" in
+http)
+	test_expect_success "setup config for $BUNDLE_URI_PROTOCOL:// tests" '
+		git -C "$BUNDLE_URI_PARENT" config http.receivepack true
+	'
+	;;
+*)
+	;;
+esac
+BUNDLE_URI_BUNDLE_URI_ESCAPED=$(echo "$BUNDLE_URI_BUNDLE_URI" | test_uri_escape)
+
+test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: no bundle-uri" '
+	test_when_finished "rm -f log" &&
+	test_when_finished "git -C \"$BUNDLE_URI_PARENT\" config uploadpack.advertiseBundleURIs true" &&
+	git -C "$BUNDLE_URI_PARENT" config uploadpack.advertiseBundleURIs false &&
+
+	GIT_TRACE_PACKET="$PWD/log" \
+	git \
+		-c protocol.version=2 \
+		ls-remote --symref "$BUNDLE_URI_REPO_URI" \
+		>actual 2>err &&
+
+	# Server responded using protocol v2
+	grep "< version 2" log &&
+
+	! grep bundle-uri log
+'
+
+test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: have bundle-uri" '
+	test_when_finished "rm -f log" &&
+
+	GIT_TRACE_PACKET="$PWD/log" \
+	git \
+		-c protocol.version=2 \
+		ls-remote --symref "$BUNDLE_URI_REPO_URI" \
+		>actual 2>err &&
+
+	# Server responded using protocol v2
+	grep "< version 2" log &&
+
+	# Server advertised bundle-uri capability
+	grep "< bundle-uri" log
+'
+
+test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: request bundle-uris" '
+	test_when_finished "rm -rf log* cloned*" &&
+
+	GIT_TRACE_PACKET="$PWD/log" \
+	git \
+		-c transfer.bundleURI=false \
+		-c protocol.version=2 \
+		clone "$BUNDLE_URI_REPO_URI" cloned \
+		>actual 2>err &&
+
+	# Server responded using protocol v2
+	grep "< version 2" log &&
+
+	# Server advertised bundle-uri capability
+	grep "< bundle-uri" log &&
+
+	# Client did not issue bundle-uri command
+	! grep "> command=bundle-uri" log &&
+
+	GIT_TRACE_PACKET="$PWD/log" \
+	git \
+		-c transfer.bundleURI=true \
+		-c protocol.version=2 \
+		clone "$BUNDLE_URI_REPO_URI" cloned2 \
+		>actual 2>err &&
+
+	# Server responded using protocol v2
+	grep "< version 2" log &&
+
+	# Server advertised bundle-uri capability
+	grep "< bundle-uri" log &&
+
+	# Client issued bundle-uri command
+	grep "> command=bundle-uri" log &&
+
+	GIT_TRACE_PACKET="$PWD/log3" \
+	git \
+		-c transfer.bundleURI=true \
+		-c protocol.version=2 \
+		clone --bundle-uri="$BUNDLE_URI_BUNDLE_URI" \
+		"$BUNDLE_URI_REPO_URI" cloned3 \
+		>actual 2>err &&
+
+	# Server responded using protocol v2
+	grep "< version 2" log3 &&
+
+	# Server advertised bundle-uri capability
+	grep "< bundle-uri" log3 &&
+
+	# Client did not issue bundle-uri command (--bundle-uri override)
+	! grep "> command=bundle-uri" log3
+'
+
+# The remaining tests will all assume transfer.bundleURI=true
+#
+# This test can be removed when transfer.bundleURI is enabled by default.
+test_expect_success 'enable transfer.bundleURI for remaining tests' '
+	git config --global transfer.bundleURI true
+'
+
+test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2" '
+	test_config -C "$BUNDLE_URI_PARENT" \
+		bundle.only.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED" &&
+
+	# All data about bundle URIs
+	cat >expect <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+	[bundle "only"]
+		uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED
+	EOF
+
+	test-tool bundle-uri \
+		ls-remote \
+		"$BUNDLE_URI_REPO_URI" \
+		>actual &&
+	test_cmp_config_output expect actual
+'
+
+test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 and extra data" '
+	test_config -C "$BUNDLE_URI_PARENT" \
+		bundle.only.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED" &&
+
+	# Extra data should be ignored
+	test_config -C "$BUNDLE_URI_PARENT" bundle.only.extra bogus &&
+
+	# All data about bundle URIs
+	cat >expect <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+	[bundle "only"]
+		uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED
+	EOF
+
+	test-tool bundle-uri \
+		ls-remote \
+		"$BUNDLE_URI_REPO_URI" \
+		>actual &&
+	test_cmp_config_output expect actual
+'
+
+test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 with list" '
+	test_config -C "$BUNDLE_URI_PARENT" \
+		bundle.bundle1.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl" &&
+	test_config -C "$BUNDLE_URI_PARENT" \
+		bundle.bundle2.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-2.bdl" &&
+	test_config -C "$BUNDLE_URI_PARENT" \
+		bundle.bundle3.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-3.bdl" &&
+
+	# All data about bundle URIs
+	cat >expect <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+	[bundle "bundle1"]
+		uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl
+	[bundle "bundle2"]
+		uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-2.bdl
+	[bundle "bundle3"]
+		uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-3.bdl
+	EOF
+
+	test-tool bundle-uri \
+		ls-remote \
+		"$BUNDLE_URI_REPO_URI" \
+		>actual &&
+	test_cmp_config_output expect actual
+'
diff --git a/t/lib-diff-alternative.sh b/t/lib-diff-alternative.sh
index 8d1e408..a8f5d32 100644
--- a/t/lib-diff-alternative.sh
+++ b/t/lib-diff-alternative.sh
@@ -105,10 +105,46 @@
  }
 EOF
 
+	cat >expect_diffstat <<EOF
+ file1 => file2 | 21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+EOF
+
 	STRATEGY=$1
 
+	test_expect_success "$STRATEGY diff from attributes" '
+		echo "file* diff=driver" >.gitattributes &&
+		git config diff.driver.algorithm "$STRATEGY" &&
+		test_must_fail git diff --no-index file1 file2 > output &&
+		cat expect &&
+		cat output &&
+		test_cmp expect output
+	'
+
+	test_expect_success "$STRATEGY diff from attributes has valid diffstat" '
+		echo "file* diff=driver" >.gitattributes &&
+		git config diff.driver.algorithm "$STRATEGY" &&
+		test_must_fail git diff --stat --no-index file1 file2 > output &&
+		test_cmp expect_diffstat output
+	'
+
 	test_expect_success "$STRATEGY diff" '
-		test_must_fail git diff --no-index "--$STRATEGY" file1 file2 > output &&
+		test_must_fail git diff --no-index "--diff-algorithm=$STRATEGY" file1 file2 > output &&
+		test_cmp expect output
+	'
+
+	test_expect_success "$STRATEGY diff command line precedence before attributes" '
+		echo "file* diff=driver" >.gitattributes &&
+		git config diff.driver.algorithm myers &&
+		test_must_fail git diff --no-index "--diff-algorithm=$STRATEGY" file1 file2 > output &&
+		test_cmp expect output
+	'
+
+	test_expect_success "$STRATEGY diff attributes precedence before config" '
+		git config diff.algorithm default &&
+		echo "file* diff=driver" >.gitattributes &&
+		git config diff.driver.algorithm "$STRATEGY" &&
+		test_must_fail git diff --no-index file1 file2 > output &&
 		test_cmp expect output
 	'
 
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 8f59e9d..09cf5ed 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -25,6 +25,7 @@
 #    LIB_HTTPD_DAV               enable DAV
 #    LIB_HTTPD_SVN               enable SVN at given location (e.g. "svn")
 #    LIB_HTTPD_SSL               enable SSL
+#    LIB_HTTPD_PROXY             enable proxy
 #
 # Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at>
 #
@@ -133,6 +134,7 @@
 prepare_httpd() {
 	mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH"
 	cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH"
+	cp "$TEST_PATH"/proxy-passwd "$HTTPD_ROOT_PATH"
 	install_script incomplete-length-upload-pack-v2-http.sh
 	install_script incomplete-body-upload-pack-v2-http.sh
 	install_script error-no-report.sh
@@ -176,6 +178,11 @@
 			export LIB_HTTPD_SVN LIB_HTTPD_SVNPATH
 		fi
 	fi
+
+	if test -n "$LIB_HTTPD_PROXY"
+	then
+		HTTPD_PARA="$HTTPD_PARA -DPROXY"
+	fi
 }
 
 enable_http2 () {
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 693b75e..31f82fa 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -47,6 +47,22 @@
 	LoadModule authz_host_module modules/mod_authz_host.so
 </IfModule>
 
+<IfDefine PROXY>
+<IfModule !mod_proxy.c>
+	LoadModule proxy_module modules/mod_proxy.so
+</IfModule>
+<IfModule !mod_proxy_http.c>
+	LoadModule proxy_http_module modules/mod_proxy_http.so
+</IfModule>
+ProxyRequests On
+<Proxy "*">
+	AuthType Basic
+	AuthName "proxy-auth"
+	AuthUserFile proxy-passwd
+	Require valid-user
+</Proxy>
+</IfDefine>
+
 <IfModule !mod_authn_core.c>
 	LoadModule authn_core_module modules/mod_authn_core.so
 </IfModule>
diff --git a/t/lib-httpd/proxy-passwd b/t/lib-httpd/proxy-passwd
new file mode 100644
index 0000000..77c2513
--- /dev/null
+++ b/t/lib-httpd/proxy-passwd
@@ -0,0 +1 @@
+proxuser:2x7tAukjAED5M
diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index b575413..7ca5b91 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -60,7 +60,7 @@
 		">")
 			echo >> "$1";;
 		bad)
-			action="badcmd";;
+			action="pickled";;
 		fakesha)
 			test \& != "$action" || action=pick
 			echo "$action XXXXXXX False commit" >> "$1"
@@ -211,6 +211,9 @@
 # usage: set_replace_editor <file>
 #
 # Replace the todo file with the exact contents of the given file.
+# N.B. sets GIT_SEQUENCE_EDITOR rather than EDITOR so it can be
+# combined with set_fake_editor to reword commits and replace the
+# todo list
 set_replace_editor () {
 	cat >script <<-\EOF &&
 	cat FILENAME >"$1"
@@ -219,6 +222,7 @@
 	cat "$1"
 	EOF
 
-	sed -e "s/FILENAME/$1/g" <script | write_script fake-editor.sh &&
-	test_set_editor "$(pwd)/fake-editor.sh"
+	sed -e "s/FILENAME/$1/g" script |
+		write_script fake-sequence-editor.sh &&
+	test_set_sequence_editor "$(pwd)/fake-sequence-editor.sh"
 }
diff --git a/t/perf/p7822-grep-perl-character.sh b/t/perf/p7822-grep-perl-character.sh
new file mode 100755
index 0000000..87009c6
--- /dev/null
+++ b/t/perf/p7822-grep-perl-character.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+test_description="git-grep's perl regex
+
+If GIT_PERF_GREP_THREADS is set to a list of threads (e.g. '1 4 8'
+etc.) we will test the patterns under those numbers of threads.
+"
+
+. ./perf-lib.sh
+
+test_perf_large_repo
+test_checkout_worktree
+
+if test -n "$GIT_PERF_GREP_THREADS"
+then
+	test_set_prereq PERF_GREP_ENGINES_THREADS
+fi
+
+for pattern in \
+	'\\bhow' \
+	'\\bÆvar' \
+	'\\d+ \\bÆvar' \
+	'\\bBelón\\b' \
+	'\\w{12}\\b'
+do
+	echo '$pattern' >pat
+	if ! test_have_prereq PERF_GREP_ENGINES_THREADS
+	then
+		test_perf "grep -P '$pattern'" --prereq PCRE "
+			git -P grep -f pat || :
+		"
+	else
+		for threads in $GIT_PERF_GREP_THREADS
+		do
+			test_perf "grep -P '$pattern' with $threads threads" --prereq PTHREADS,PCRE "
+				git -c grep.threads=$threads -P grep -f pat || :
+			"
+		done
+	fi
+done
+
+test_done
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 2ba219b..402b201 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -815,7 +815,8 @@
 	grep "^00*\$" actual &&
 	rawsz="$(test_oid rawsz)" &&
 	hexsz="$(test_oid hexsz)" &&
-	test "$hexsz" -eq $(wc -c <actual) &&
+	# +1 accounts for the trailing newline
+	test $(( $hexsz + 1)) -eq $(wc -c <actual) &&
 	test $(( $rawsz * 2)) -eq "$hexsz"
 '
 
@@ -826,7 +827,7 @@
 	grep "^00*\$" actual &&
 	rawsz="$(test_oid rawsz)" &&
 	hexsz="$(test_oid hexsz)" &&
-	test $(wc -c <actual) -eq 40 &&
+	test $(wc -c <actual) -eq 41 &&
 	test "$rawsz" -eq 20 &&
 	test "$hexsz" -eq 40
 '
@@ -838,7 +839,7 @@
 	grep "^00*\$" actual &&
 	rawsz="$(test_oid rawsz)" &&
 	hexsz="$(test_oid hexsz)" &&
-	test $(wc -c <actual) -eq 64 &&
+	test $(wc -c <actual) -eq 65 &&
 	test "$rawsz" -eq 32 &&
 	test "$hexsz" -eq 64
 '
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index d0284fe..89b306c 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -25,7 +25,15 @@
 	git check-attr test -- "$path" >actual &&
 	echo "\"$quoted_path\": test: $expect" >expect &&
 	test_cmp expect actual
+}
 
+attr_check_source () {
+	path="$1" expect="$2" source="$3" git_opts="$4" &&
+
+	git $git_opts check-attr --source $source test -- "$path" >actual 2>err &&
+	echo "$path: test: $expect" >expect &&
+	test_cmp expect actual &&
+	test_must_be_empty err
 }
 
 test_expect_success 'open-quoted pathname' '
@@ -33,7 +41,6 @@
 	attr_check a unspecified
 '
 
-
 test_expect_success 'setup' '
 	mkdir -p a/b/d a/c b &&
 	(
@@ -80,12 +87,23 @@
 	EOF
 '
 
+test_expect_success 'setup branches' '
+	mkdir -p foo/bar &&
+	test_commit --printf "add .gitattributes" foo/bar/.gitattributes \
+		"f test=f\na/i test=n\n" tag-1 &&
+	test_commit --printf "add .gitattributes" foo/bar/.gitattributes \
+		"g test=g\na/i test=m\n" tag-2 &&
+	rm foo/bar/.gitattributes
+'
+
 test_expect_success 'command line checks' '
 	test_must_fail git check-attr &&
 	test_must_fail git check-attr -- &&
 	test_must_fail git check-attr test &&
 	test_must_fail git check-attr test -- &&
 	test_must_fail git check-attr -- f &&
+	test_must_fail git check-attr --source &&
+	test_must_fail git check-attr --source not-a-valid-ref &&
 	echo "f" | test_must_fail git check-attr --stdin &&
 	echo "f" | test_must_fail git check-attr --stdin -- f &&
 	echo "f" | test_must_fail git check-attr --stdin test -- f &&
@@ -203,9 +221,12 @@
 	test_cmp expect actual
 '
 
-test_expect_success 'attribute test: --all option' '
+test_expect_success 'setup --all option' '
 	grep -v unspecified <expect-all | sort >specified-all &&
-	sed -e "s/:.*//" <expect-all | uniq >stdin-all &&
+	sed -e "s/:.*//" <expect-all | uniq >stdin-all
+'
+
+test_expect_success 'attribute test: --all option' '
 	git check-attr --stdin --all <stdin-all >tmp &&
 	sort tmp >actual &&
 	test_cmp specified-all actual
@@ -284,6 +305,15 @@
 	)
 '
 
+test_expect_success 'using --source' '
+	attr_check_source foo/bar/f f tag-1 &&
+	attr_check_source foo/bar/a/i n tag-1 &&
+	attr_check_source foo/bar/f unspecified tag-2 &&
+	attr_check_source foo/bar/a/i m tag-2 &&
+	attr_check_source foo/bar/g g tag-2 &&
+	attr_check_source foo/bar/g unspecified tag-1
+'
+
 test_expect_success 'setup bare' '
 	git clone --template= --bare . bare.git
 '
@@ -303,6 +333,18 @@
 	)
 '
 
+test_expect_success 'bare repository: with --source' '
+	(
+		cd bare.git &&
+		attr_check_source foo/bar/f f tag-1 &&
+		attr_check_source foo/bar/a/i n tag-1 &&
+		attr_check_source foo/bar/f unspecified tag-2 &&
+		attr_check_source foo/bar/a/i m tag-2 &&
+		attr_check_source foo/bar/g g tag-2 &&
+		attr_check_source foo/bar/g unspecified tag-1
+	)
+'
+
 test_expect_success 'bare repository: check that --cached honors index' '
 	(
 		cd bare.git &&
@@ -400,7 +442,7 @@
 
 test_expect_success EXPENSIVE 'large attributes file ignored in tree' '
 	test_when_finished "rm .gitattributes" &&
-	dd if=/dev/zero of=.gitattributes bs=101M count=1 2>/dev/null &&
+	dd if=/dev/zero of=.gitattributes bs=1048576 count=101 2>/dev/null &&
 	git check-attr --all path >/dev/null 2>err &&
 	echo "warning: ignoring overly large gitattributes file ${SQ}.gitattributes${SQ}" >expect &&
 	test_cmp expect err
@@ -428,7 +470,7 @@
 
 test_expect_success EXPENSIVE 'large attributes file ignored in index' '
 	test_when_finished "git update-index --remove .gitattributes" &&
-	blob=$(dd if=/dev/zero bs=101M count=1 2>/dev/null | git hash-object -w --stdin) &&
+	blob=$(dd if=/dev/zero bs=1048576 count=101 2>/dev/null | git hash-object -w --stdin) &&
 	git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
 	git check-attr --cached --all path >/dev/null 2>err &&
 	echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect &&
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index 2490162..e18b160 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -88,6 +88,13 @@
 check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 +0000'
 check_parse '2008-02-14 20:30:45 -0500' '2008-02-14 20:30:45 -0500'
 check_parse '2008.02.14 20:30:45 -0500' '2008-02-14 20:30:45 -0500'
+check_parse '20080214T20:30:45' '2008-02-14 20:30:45 +0000'
+check_parse '20080214T20:30' '2008-02-14 20:30:00 +0000'
+check_parse '20080214T20' '2008-02-14 20:00:00 +0000'
+check_parse '20080214T203045' '2008-02-14 20:30:45 +0000'
+check_parse '20080214T2030' '2008-02-14 20:30:00 +0000'
+check_parse '20080214T000000.20' '2008-02-14 00:00:00 +0000'
+check_parse '20080214T00:00:00.20' '2008-02-14 00:00:00 +0000'
 check_parse '20080214T203045-04:00' '2008-02-14 20:30:45 -0400'
 check_parse '20080214T203045 -04:00' '2008-02-14 20:30:45 -0400'
 check_parse '20080214T203045.019-04:00' '2008-02-14 20:30:45 -0400'
@@ -99,6 +106,7 @@
 check_parse '2008-02-14 20:30:45 -:30' '2008-02-14 20:30:45 +0000'
 check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500'
 check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5
+check_parse 'Thu, 7 Apr 2005 15:14:13 -0700' '2005-04-07 15:14:13 -0700'
 
 check_approxidate() {
 	echo "$1 -> $2 +0000" >expect
diff --git a/t/t0007-git-var.sh b/t/t0007-git-var.sh
index e56f4b9..eeb8539 100755
--- a/t/t0007-git-var.sh
+++ b/t/t0007-git-var.sh
@@ -5,6 +5,12 @@
 TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
+sane_unset_all_editors () {
+	sane_unset GIT_EDITOR &&
+	sane_unset VISUAL &&
+	sane_unset EDITOR
+}
+
 test_expect_success 'get GIT_AUTHOR_IDENT' '
 	test_tick &&
 	echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect &&
@@ -47,6 +53,100 @@
 	)
 '
 
+test_expect_success 'get GIT_EDITOR without configuration' '
+	(
+		sane_unset_all_editors &&
+		test_expect_code 1 git var GIT_EDITOR >out &&
+		test_must_be_empty out
+	)
+'
+
+test_expect_success 'get GIT_EDITOR with configuration' '
+	test_config core.editor foo &&
+	(
+		sane_unset_all_editors &&
+		echo foo >expect &&
+		git var GIT_EDITOR >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'get GIT_EDITOR with environment variable GIT_EDITOR' '
+	(
+		sane_unset_all_editors &&
+		echo bar >expect &&
+		GIT_EDITOR=bar git var GIT_EDITOR >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'get GIT_EDITOR with environment variable EDITOR' '
+	(
+		sane_unset_all_editors &&
+		echo bar >expect &&
+		EDITOR=bar git var GIT_EDITOR >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'get GIT_EDITOR with configuration and environment variable GIT_EDITOR' '
+	test_config core.editor foo &&
+	(
+		sane_unset_all_editors &&
+		echo bar >expect &&
+		GIT_EDITOR=bar git var GIT_EDITOR >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'get GIT_EDITOR with configuration and environment variable EDITOR' '
+	test_config core.editor foo &&
+	(
+		sane_unset_all_editors &&
+		echo foo >expect &&
+		EDITOR=bar git var GIT_EDITOR >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR without configuration' '
+	(
+		sane_unset GIT_SEQUENCE_EDITOR &&
+		git var GIT_EDITOR >expect &&
+		git var GIT_SEQUENCE_EDITOR >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration' '
+	test_config sequence.editor foo &&
+	(
+		sane_unset GIT_SEQUENCE_EDITOR &&
+		echo foo >expect &&
+		git var GIT_SEQUENCE_EDITOR >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR with environment variable' '
+	(
+		sane_unset GIT_SEQUENCE_EDITOR &&
+		echo bar >expect &&
+		GIT_SEQUENCE_EDITOR=bar git var GIT_SEQUENCE_EDITOR >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration and environment variable' '
+	test_config sequence.editor foo &&
+	(
+		sane_unset GIT_SEQUENCE_EDITOR &&
+		echo bar >expect &&
+		GIT_SEQUENCE_EDITOR=bar git var GIT_SEQUENCE_EDITOR >actual &&
+		test_cmp expect actual
+	)
+'
+
 # For git var -l, we check only a representative variable;
 # testing the whole output would make our test too brittle with
 # respect to unrelated changes in the test suite's environment.
diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh
index 2e42fba..fc14ba0 100755
--- a/t/t0017-env-helper.sh
+++ b/t/t0017-env-helper.sh
@@ -1,87 +1,87 @@
 #!/bin/sh
 
-test_description='test env--helper'
+test_description='test test-tool env-helper'
 
 TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 
-test_expect_success 'env--helper usage' '
-	test_must_fail git env--helper &&
-	test_must_fail git env--helper --type=bool &&
-	test_must_fail git env--helper --type=ulong &&
-	test_must_fail git env--helper --type=bool &&
-	test_must_fail git env--helper --type=bool --default &&
-	test_must_fail git env--helper --type=bool --default= &&
-	test_must_fail git env--helper --defaultxyz
+test_expect_success 'test-tool env-helper usage' '
+	test_must_fail test-tool env-helper &&
+	test_must_fail test-tool env-helper --type=bool &&
+	test_must_fail test-tool env-helper --type=ulong &&
+	test_must_fail test-tool env-helper --type=bool &&
+	test_must_fail test-tool env-helper --type=bool --default &&
+	test_must_fail test-tool env-helper --type=bool --default= &&
+	test_must_fail test-tool env-helper --defaultxyz
 '
 
-test_expect_success 'env--helper bad default values' '
-	test_must_fail git env--helper --type=bool --default=1xyz MISSING &&
-	test_must_fail git env--helper --type=ulong --default=1xyz MISSING
+test_expect_success 'test-tool env-helper bad default values' '
+	test_must_fail test-tool env-helper --type=bool --default=1xyz MISSING &&
+	test_must_fail test-tool env-helper --type=ulong --default=1xyz MISSING
 '
 
-test_expect_success 'env--helper --type=bool' '
+test_expect_success 'test-tool env-helper --type=bool' '
 	# Test various --default bool values
 	echo true >expected &&
-	git env--helper --type=bool --default=1 MISSING >actual &&
+	test-tool env-helper --type=bool --default=1 MISSING >actual &&
 	test_cmp expected actual &&
-	git env--helper --type=bool --default=yes MISSING >actual &&
+	test-tool env-helper --type=bool --default=yes MISSING >actual &&
 	test_cmp expected actual &&
-	git env--helper --type=bool --default=true MISSING >actual &&
+	test-tool env-helper --type=bool --default=true MISSING >actual &&
 	test_cmp expected actual &&
 	echo false >expected &&
-	test_must_fail git env--helper --type=bool --default=0 MISSING >actual &&
+	test_must_fail test-tool env-helper --type=bool --default=0 MISSING >actual &&
 	test_cmp expected actual &&
-	test_must_fail git env--helper --type=bool --default=no MISSING >actual &&
+	test_must_fail test-tool env-helper --type=bool --default=no MISSING >actual &&
 	test_cmp expected actual &&
-	test_must_fail git env--helper --type=bool --default=false MISSING >actual &&
+	test_must_fail test-tool env-helper --type=bool --default=false MISSING >actual &&
 	test_cmp expected actual &&
 
 	# No output with --exit-code
-	git env--helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err &&
+	test-tool env-helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err &&
 	test_must_be_empty actual.out &&
 	test_must_be_empty actual.err &&
-	test_must_fail git env--helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err &&
+	test_must_fail test-tool env-helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err &&
 	test_must_be_empty actual.out &&
 	test_must_be_empty actual.err &&
 
 	# Existing variable
-	EXISTS=true git env--helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err &&
+	EXISTS=true test-tool env-helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err &&
 	test_must_be_empty actual.out &&
 	test_must_be_empty actual.err &&
 	test_must_fail \
 		env EXISTS=false \
-		git env--helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err &&
+		test-tool env-helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err &&
 	test_must_be_empty actual.out &&
 	test_must_be_empty actual.err
 '
 
-test_expect_success 'env--helper --type=ulong' '
+test_expect_success 'test-tool env-helper --type=ulong' '
 	echo 1234567890 >expected &&
-	git env--helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err &&
+	test-tool env-helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err &&
 	test_cmp expected actual.out &&
 	test_must_be_empty actual.err &&
 
 	echo 0 >expected &&
-	test_must_fail git env--helper --type=ulong --default=0 MISSING >actual &&
+	test_must_fail test-tool env-helper --type=ulong --default=0 MISSING >actual &&
 	test_cmp expected actual &&
 
-	git env--helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err &&
+	test-tool env-helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err &&
 	test_must_be_empty actual.out &&
 	test_must_be_empty actual.err &&
 
-	EXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err &&
+	EXISTS=1234567890 test-tool env-helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err &&
 	test_must_be_empty actual.out &&
 	test_must_be_empty actual.err &&
 
 	echo 1234567890 >expected &&
-	EXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err &&
+	EXISTS=1234567890 test-tool env-helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err &&
 	test_cmp expected actual.out &&
 	test_must_be_empty actual.err
 '
 
-test_expect_success 'env--helper reads config thanks to trace2' '
+test_expect_success 'test-tool env-helper reads config thanks to trace2' '
 	mkdir home &&
 	git config -f home/.gitconfig include.path cycle &&
 	git config -f home/cycle include.path .gitconfig &&
@@ -93,7 +93,7 @@
 
 	test_must_fail \
 		env HOME="$(pwd)/home" GIT_TEST_ENV_HELPER=true \
-		git -C cycle env--helper --type=bool --default=0 --exit-code GIT_TEST_ENV_HELPER 2>err &&
+		test-tool -C cycle env-helper --type=bool --default=0 --exit-code GIT_TEST_ENV_HELPER 2>err &&
 	grep "exceeded maximum include depth" err
 '
 
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index abecd75..46abbee 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -8,8 +8,8 @@
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-TEST_ROOT="$PWD"
-PATH=$TEST_ROOT:$PATH
+PATH=$PWD:$PATH
+TEST_ROOT="$(pwd)"
 
 write_script <<\EOF "$TEST_ROOT/rot13.sh"
 tr \
diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh
index f9bbb91..5758055 100755
--- a/t/t0023-crlf-am.sh
+++ b/t/t0023-crlf-am.sh
@@ -2,6 +2,7 @@
 
 test_description='Test am with auto.crlf'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 cat >patchfile <<\EOF
diff --git a/t/t0066-dir-iterator.sh b/t/t0066-dir-iterator.sh
index 04b8116..7d0a0da 100755
--- a/t/t0066-dir-iterator.sh
+++ b/t/t0066-dir-iterator.sh
@@ -106,13 +106,7 @@
 	ln -s d dir4/a/e &&
 	ln -s ../b dir4/a/f &&
 
-	mkdir -p dir5/a/b &&
-	mkdir -p dir5/a/c &&
-	ln -s ../c dir5/a/b/d &&
-	ln -s ../ dir5/a/b/e &&
-	ln -s ../../ dir5/a/b/f &&
-
-	ln -s dir4 dir6
+	ln -s dir4 dir5
 '
 
 test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default' '
@@ -131,44 +125,10 @@
 	test_cmp expected-no-follow-sorted-output actual-no-follow-sorted-output
 '
 
-test_expect_success SYMLINKS 'dir-iterator should follow symlinks w/ follow flag' '
-	cat >expected-follow-sorted-output <<-EOF &&
-	[d] (a) [a] ./dir4/a
-	[d] (a/f) [f] ./dir4/a/f
-	[d] (a/f/c) [c] ./dir4/a/f/c
-	[d] (b) [b] ./dir4/b
-	[d] (b/c) [c] ./dir4/b/c
-	[f] (a/d) [d] ./dir4/a/d
-	[f] (a/e) [e] ./dir4/a/e
-	EOF
-
-	test-tool dir-iterator --follow-symlinks ./dir4 >out &&
-	sort out >actual-follow-sorted-output &&
-
-	test_cmp expected-follow-sorted-output actual-follow-sorted-output
-'
-
 test_expect_success SYMLINKS 'dir-iterator does not resolve top-level symlinks' '
-	test_must_fail test-tool dir-iterator ./dir6 >out &&
+	test_must_fail test-tool dir-iterator ./dir5 >out &&
 
 	grep "ENOTDIR" out
 '
 
-test_expect_success SYMLINKS 'dir-iterator resolves top-level symlinks w/ follow flag' '
-	cat >expected-follow-sorted-output <<-EOF &&
-	[d] (a) [a] ./dir6/a
-	[d] (a/f) [f] ./dir6/a/f
-	[d] (a/f/c) [c] ./dir6/a/f/c
-	[d] (b) [b] ./dir6/b
-	[d] (b/c) [c] ./dir6/b/c
-	[f] (a/d) [d] ./dir6/a/d
-	[f] (a/e) [e] ./dir6/a/e
-	EOF
-
-	test-tool dir-iterator --follow-symlinks ./dir6 >out &&
-	sort out >actual-follow-sorted-output &&
-
-	test_cmp expected-follow-sorted-output actual-follow-sorted-output
-'
-
 test_done
diff --git a/t/t0068-for-each-repo.sh b/t/t0068-for-each-repo.sh
index c6e0d65..3648d43 100755
--- a/t/t0068-for-each-repo.sh
+++ b/t/t0068-for-each-repo.sh
@@ -2,6 +2,7 @@
 
 test_description='git for-each-repo builtin'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'run based on configured value' '
diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh
index 8d59905..574de34 100755
--- a/t/t0070-fundamental.sh
+++ b/t/t0070-fundamental.sh
@@ -6,6 +6,7 @@
 Verify wrappers and compatibility functions.
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'character classes (isspace, isalpha etc.)' '
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index 3485c05..c66d91e 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -35,6 +35,16 @@
 	test -z "$pass" || echo password=$pass
 	EOF
 
+	write_script git-credential-verbatim-with-expiry <<-\EOF &&
+	user=$1; shift
+	pass=$1; shift
+	pexpiry=$1; shift
+	. ./dump
+	test -z "$user" || echo username=$user
+	test -z "$pass" || echo password=$pass
+	test -z "$pexpiry" || echo password_expiry_utc=$pexpiry
+	EOF
+
 	PATH="$PWD:$PATH"
 '
 
@@ -109,6 +119,43 @@
 	EOF
 '
 
+test_expect_success 'credential_fill populates password_expiry_utc' '
+	check fill "verbatim-with-expiry one two 9999999999" <<-\EOF
+	protocol=http
+	host=example.com
+	--
+	protocol=http
+	host=example.com
+	username=one
+	password=two
+	password_expiry_utc=9999999999
+	--
+	verbatim-with-expiry: get
+	verbatim-with-expiry: protocol=http
+	verbatim-with-expiry: host=example.com
+	EOF
+'
+
+test_expect_success 'credential_fill ignores expired password' '
+	check fill "verbatim-with-expiry one two 5" "verbatim three four" <<-\EOF
+	protocol=http
+	host=example.com
+	--
+	protocol=http
+	host=example.com
+	username=three
+	password=four
+	--
+	verbatim-with-expiry: get
+	verbatim-with-expiry: protocol=http
+	verbatim-with-expiry: host=example.com
+	verbatim: get
+	verbatim: protocol=http
+	verbatim: host=example.com
+	verbatim: username=one
+	EOF
+'
+
 test_expect_success 'credential_fill passes along metadata' '
 	check fill "verbatim one two" <<-\EOF
 	protocol=ftp
@@ -149,6 +196,24 @@
 	EOF
 '
 
+test_expect_success 'credential_approve stores password expiry' '
+	check approve useless <<-\EOF
+	protocol=http
+	host=example.com
+	username=foo
+	password=bar
+	password_expiry_utc=9999999999
+	--
+	--
+	useless: store
+	useless: protocol=http
+	useless: host=example.com
+	useless: username=foo
+	useless: password=bar
+	useless: password_expiry_utc=9999999999
+	EOF
+'
+
 test_expect_success 'do not bother storing password-less credential' '
 	check approve useless <<-\EOF
 	protocol=http
@@ -159,6 +224,17 @@
 	EOF
 '
 
+test_expect_success 'credential_approve does not store expired password' '
+	check approve useless <<-\EOF
+	protocol=http
+	host=example.com
+	username=foo
+	password=bar
+	password_expiry_utc=5
+	--
+	--
+	EOF
+'
 
 test_expect_success 'credential_reject calls all helpers' '
 	check reject useless "verbatim one two" <<-\EOF
@@ -181,6 +257,24 @@
 	EOF
 '
 
+test_expect_success 'credential_reject erases credential regardless of expiry' '
+	check reject useless <<-\EOF
+	protocol=http
+	host=example.com
+	username=foo
+	password=bar
+	password_expiry_utc=5
+	--
+	--
+	useless: erase
+	useless: protocol=http
+	useless: host=example.com
+	useless: username=foo
+	useless: password=bar
+	useless: password_expiry_utc=5
+	EOF
+'
+
 test_expect_success 'usernames can be preserved' '
 	check fill "verbatim \"\" three" <<-\EOF
 	protocol=http
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index 516a611..3fb1b0c 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -370,7 +370,7 @@
 	cat <<-EOF >expect &&
 		error: Updating '\''fictional/a'\'' would lose untracked files in it
 	EOF
-	test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual &&
+	test_must_fail git read-tree --super-prefix fictional/ -u -m "$treeH" "$treeM" 2>actual &&
 	test_cmp expect actual
 '
 
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 23b8942..2d875b1 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -292,8 +292,8 @@
 commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1)
 commit_size=$(($(test_oid hexsz) + 137))
 commit_content="tree $tree_sha1
-author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0000000000 +0000
-committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0000000000 +0000
+author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0 +0000
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0 +0000
 
 $commit_message"
 
@@ -304,7 +304,7 @@
 tag hellotag
 tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
 tag_description="This is a tag"
-tag_content="$tag_header_without_timestamp 0000000000 +0000
+tag_content="$tag_header_without_timestamp 0 +0000
 
 $tag_description"
 
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index ac5ad8c..ac3d173 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -203,23 +203,34 @@
 test_expect_success 'too-short tree' '
 	echo abc >malformed-tree &&
 	test_must_fail git hash-object -t tree malformed-tree 2>err &&
-	test_i18ngrep "too-short tree object" err
+	grep "too-short tree object" err
 '
 
 test_expect_success 'malformed mode in tree' '
-	hex_sha1=$(echo foo | git hash-object --stdin -w) &&
-	bin_sha1=$(echo $hex_sha1 | hex2oct) &&
-	printf "9100644 \0$bin_sha1" >tree-with-malformed-mode &&
+	hex_oid=$(echo foo | git hash-object --stdin -w) &&
+	bin_oid=$(echo $hex_oid | hex2oct) &&
+	printf "9100644 \0$bin_oid" >tree-with-malformed-mode &&
 	test_must_fail git hash-object -t tree tree-with-malformed-mode 2>err &&
-	test_i18ngrep "malformed mode in tree entry" err
+	grep "malformed mode in tree entry" err
 '
 
 test_expect_success 'empty filename in tree' '
-	hex_sha1=$(echo foo | git hash-object --stdin -w) &&
-	bin_sha1=$(echo $hex_sha1 | hex2oct) &&
-	printf "100644 \0$bin_sha1" >tree-with-empty-filename &&
+	hex_oid=$(echo foo | git hash-object --stdin -w) &&
+	bin_oid=$(echo $hex_oid | hex2oct) &&
+	printf "100644 \0$bin_oid" >tree-with-empty-filename &&
 	test_must_fail git hash-object -t tree tree-with-empty-filename 2>err &&
-	test_i18ngrep "empty filename in tree entry" err
+	grep "empty filename in tree entry" err
+'
+
+test_expect_success 'duplicate filename in tree' '
+	hex_oid=$(echo foo | git hash-object --stdin -w) &&
+	bin_oid=$(echo $hex_oid | hex2oct) &&
+	{
+		printf "100644 file\0$bin_oid" &&
+		printf "100644 file\0$bin_oid"
+	} >tree-with-duplicate-filename &&
+	test_must_fail git hash-object -t tree tree-with-duplicate-filename 2>err &&
+	grep "duplicateEntries" err
 '
 
 test_expect_success 'corrupt commit' '
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index 742f0fa..595b24c 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -12,6 +12,7 @@
 '
 
 TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-read-tree.sh
 
diff --git a/t/t1022-read-tree-partial-clone.sh b/t/t1022-read-tree-partial-clone.sh
index da53971..cca4380 100755
--- a/t/t1022-read-tree-partial-clone.sh
+++ b/t/t1022-read-tree-partial-clone.sh
@@ -3,7 +3,7 @@
 test_description='git read-tree in partial clones'
 
 TEST_NO_CREATE_REPO=1
-
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'read-tree in partial clone prefetches in one batch' '
diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index 93a2f91..1b6437e 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -8,6 +8,8 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Remove a default ACL from the test dir if possible.
@@ -25,6 +27,7 @@
 for u in 002 022
 do
 	test_expect_success POSIXPERM "shared=1 does not clear bits preset by umask $u" '
+		test_when_finished "rm -rf sub" &&
 		mkdir sub && (
 			cd sub &&
 			umask $u &&
@@ -42,12 +45,9 @@
 			;;
 		esac
 	'
-	rm -rf sub
 done
 
 test_expect_success 'shared=all' '
-	mkdir sub &&
-	cd sub &&
 	git init --template= --shared=all &&
 	test 2 = $(git config core.sharedrepository)
 '
@@ -132,6 +132,7 @@
 '
 
 test_expect_success POSIXPERM 'forced modes' '
+	test_when_finished "rm -rf new" &&
 	mkdir -p templates/hooks &&
 	echo update-server-info >templates/hooks/post-update &&
 	chmod +x templates/hooks/post-update &&
@@ -140,7 +141,8 @@
 	(
 		cd new &&
 		umask 002 &&
-		git init --shared=0660 --template=templates &&
+		git init --shared=0660 --template=../templates &&
+		test_path_is_file .git/hooks/post-update &&
 		>frotz &&
 		git add frotz &&
 		git commit -a -m initial &&
@@ -173,6 +175,7 @@
 '
 
 test_expect_success POSIXPERM 'remote init does not use config from cwd' '
+	test_when_finished "rm -rf child.git" &&
 	git config core.sharedrepository 0666 &&
 	umask 0022 &&
 	git init --bare child.git &&
@@ -192,7 +195,7 @@
 '
 
 test_expect_success POSIXPERM 're-init respects core.sharedrepository (remote)' '
-	rm -rf child.git &&
+	test_when_finished "rm -rf child.git" &&
 	umask 0022 &&
 	git init --bare --shared=0666 child.git &&
 	test_path_is_missing child.git/foo &&
@@ -203,7 +206,7 @@
 '
 
 test_expect_success POSIXPERM 'template can set core.sharedrepository' '
-	rm -rf child.git &&
+	test_when_finished "rm -rf child.git" &&
 	umask 0022 &&
 	git config core.sharedrepository 0666 &&
 	cp .git/config templates/config &&
diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh
index 0acabb6..70389fa 100755
--- a/t/t1302-repo-version.sh
+++ b/t/t1302-repo-version.sh
@@ -5,6 +5,7 @@
 
 test_description='Test repository version check'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
@@ -27,7 +28,7 @@
 '
 
 test_expect_success 'gitdir selection on normal repos' '
-	echo $(test_oid version) >expect &&
+	test_oid version >expect &&
 	git config core.repositoryformatversion >actual &&
 	git -C test config core.repositoryformatversion >actual2 &&
 	test_cmp expect actual &&
diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh
index c69ae41..31b89dd 100755
--- a/t/t1304-default-acl.sh
+++ b/t/t1304-default-acl.sh
@@ -9,6 +9,7 @@
 # => this must come before . ./test-lib.sh
 umask 077
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # We need an arbitrary other user give permission to using ACLs. root
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index d708acd..be23be3 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -189,4 +189,38 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'symbolic-ref --short handles complex utf8 case' '
+	name="测试-加-增加-加-增加" &&
+	git symbolic-ref TEST_SYMREF "refs/heads/$name" &&
+	# In the real world, we saw problems with this case only
+	# when the locale includes UTF-8. Set it here to try to make things as
+	# hard as possible for us to pass, but in practice we should do the
+	# right thing regardless (and of course some platforms may not even
+	# have this locale).
+	LC_ALL=en_US.UTF-8 git symbolic-ref --short TEST_SYMREF >actual &&
+	echo "$name" >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'symbolic-ref --short handles name with suffix' '
+	git symbolic-ref TEST_SYMREF "refs/remotes/origin/HEAD" &&
+	git symbolic-ref --short TEST_SYMREF >actual &&
+	echo "origin" >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'symbolic-ref --short handles almost-matching name' '
+	git symbolic-ref TEST_SYMREF "refs/headsXfoo" &&
+	git symbolic-ref --short TEST_SYMREF >actual &&
+	echo "headsXfoo" >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'symbolic-ref --short handles name with percent' '
+	git symbolic-ref TEST_SYMREF "refs/heads/%foo" &&
+	git symbolic-ref --short TEST_SYMREF >actual &&
+	echo "%foo" >expect &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh
index 13c2b43..b5606d9 100755
--- a/t/t1404-update-ref-errors.sh
+++ b/t/t1404-update-ref-errors.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='Test git update-ref error handling'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Create some references, perhaps run pack-refs --all, then try to
diff --git a/t/t1408-packed-refs.sh b/t/t1408-packed-refs.sh
index 41ba1f1..9469c79 100755
--- a/t/t1408-packed-refs.sh
+++ b/t/t1408-packed-refs.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t1409-avoid-packing-refs.sh b/t/t1409-avoid-packing-refs.sh
index be12fb6..f23c015 100755
--- a/t/t1409-avoid-packing-refs.sh
+++ b/t/t1409-avoid-packing-refs.sh
@@ -2,6 +2,7 @@
 
 test_description='avoid rewriting packed-refs unnecessarily'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Add an identifying mark to the packed-refs file header line. This
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index aa59954..6c45965 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -7,6 +7,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check_have () {
diff --git a/t/t1413-reflog-detach.sh b/t/t1413-reflog-detach.sh
index 934688a..d2a4822 100755
--- a/t/t1413-reflog-detach.sh
+++ b/t/t1413-reflog-detach.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 reset_state () {
diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh
index 2773172..b32ca79 100755
--- a/t/t1416-ref-transaction-hooks.sh
+++ b/t/t1416-ref-transaction-hooks.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index de0f6d5..fdb886d 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -212,7 +212,7 @@
 test_expect_success 'email with embedded > is not okay' '
 	git cat-file commit HEAD >basis &&
 	sed "s/@[a-z]/&>/" basis >bad-email &&
-	new=$(git hash-object -t commit -w --stdin <bad-email) &&
+	new=$(git hash-object --literally -t commit -w --stdin <bad-email) &&
 	test_when_finished "remove_object $new" &&
 	git update-ref refs/heads/bogus "$new" &&
 	test_when_finished "git update-ref -d refs/heads/bogus" &&
@@ -223,7 +223,7 @@
 test_expect_success 'missing < email delimiter is reported nicely' '
 	git cat-file commit HEAD >basis &&
 	sed "s/<//" basis >bad-email-2 &&
-	new=$(git hash-object -t commit -w --stdin <bad-email-2) &&
+	new=$(git hash-object --literally -t commit -w --stdin <bad-email-2) &&
 	test_when_finished "remove_object $new" &&
 	git update-ref refs/heads/bogus "$new" &&
 	test_when_finished "git update-ref -d refs/heads/bogus" &&
@@ -234,7 +234,7 @@
 test_expect_success 'missing email is reported nicely' '
 	git cat-file commit HEAD >basis &&
 	sed "s/[a-z]* <[^>]*>//" basis >bad-email-3 &&
-	new=$(git hash-object -t commit -w --stdin <bad-email-3) &&
+	new=$(git hash-object --literally -t commit -w --stdin <bad-email-3) &&
 	test_when_finished "remove_object $new" &&
 	git update-ref refs/heads/bogus "$new" &&
 	test_when_finished "git update-ref -d refs/heads/bogus" &&
@@ -245,7 +245,7 @@
 test_expect_success '> in name is reported' '
 	git cat-file commit HEAD >basis &&
 	sed "s/ </> </" basis >bad-email-4 &&
-	new=$(git hash-object -t commit -w --stdin <bad-email-4) &&
+	new=$(git hash-object --literally -t commit -w --stdin <bad-email-4) &&
 	test_when_finished "remove_object $new" &&
 	git update-ref refs/heads/bogus "$new" &&
 	test_when_finished "git update-ref -d refs/heads/bogus" &&
@@ -258,7 +258,7 @@
 	git cat-file commit HEAD >basis &&
 	sed "s/^\\(author .*>\\) [0-9]*/\\1 18446744073709551617/" \
 		<basis >bad-timestamp &&
-	new=$(git hash-object -t commit -w --stdin <bad-timestamp) &&
+	new=$(git hash-object --literally -t commit -w --stdin <bad-timestamp) &&
 	test_when_finished "remove_object $new" &&
 	git update-ref refs/heads/bogus "$new" &&
 	test_when_finished "git update-ref -d refs/heads/bogus" &&
@@ -269,7 +269,7 @@
 test_expect_success 'commit with NUL in header' '
 	git cat-file commit HEAD >basis &&
 	sed "s/author ./author Q/" <basis | q_to_nul >commit-NUL-header &&
-	new=$(git hash-object -t commit -w --stdin <commit-NUL-header) &&
+	new=$(git hash-object --literally -t commit -w --stdin <commit-NUL-header) &&
 	test_when_finished "remove_object $new" &&
 	git update-ref refs/heads/bogus "$new" &&
 	test_when_finished "git update-ref -d refs/heads/bogus" &&
@@ -292,7 +292,7 @@
 			git cat-file tree $T &&
 			git cat-file tree $T
 		) |
-		git hash-object -w -t tree --stdin
+		git hash-object --literally -w -t tree --stdin
 	) &&
 	test_must_fail git fsck 2>out &&
 	test_i18ngrep "error in tree .*contains duplicate file entries" out
@@ -426,7 +426,7 @@
 	This is an invalid tag.
 	EOF
 
-	tag=$(git hash-object -t tag -w --stdin <wrong-tag) &&
+	tag=$(git hash-object --literally -t tag -w --stdin <wrong-tag) &&
 	test_when_finished "remove_object $tag" &&
 	echo $tag >.git/refs/tags/wrong &&
 	test_when_finished "git update-ref -d refs/tags/wrong" &&
@@ -558,7 +558,7 @@
 test_expect_success 'force fsck to ignore double author' '
 	git cat-file commit HEAD >basis &&
 	sed "s/^author .*/&,&/" <basis | tr , \\n >multiple-authors &&
-	new=$(git hash-object -t commit -w --stdin <multiple-authors) &&
+	new=$(git hash-object --literally -t commit -w --stdin <multiple-authors) &&
 	test_when_finished "remove_object $new" &&
 	git update-ref refs/heads/bogus "$new" &&
 	test_when_finished "git update-ref -d refs/heads/bogus" &&
@@ -573,7 +573,7 @@
 	(git init null-blob &&
 	 cd null-blob &&
 	 sha=$(printf "100644 file$_bz$_bzoid" |
-	       git hash-object -w --stdin -t tree) &&
+	       git hash-object --literally -w --stdin -t tree) &&
 	  git fsck 2>out &&
 	  test_i18ngrep "warning.*null sha1" out
 	)
@@ -583,7 +583,7 @@
 	(git init null-commit &&
 	 cd null-commit &&
 	 sha=$(printf "160000 submodule$_bz$_bzoid" |
-	       git hash-object -w --stdin -t tree) &&
+	       git hash-object --literally -w --stdin -t tree) &&
 	  git fsck 2>out &&
 	  test_i18ngrep "warning.*null sha1" out
 	)
@@ -648,7 +648,7 @@
 		git commit --allow-empty -m "initial commitQNUL after message" &&
 		git cat-file commit HEAD >original &&
 		q_to_nul <original >munged &&
-		git hash-object -w -t commit --stdin <munged >name &&
+		git hash-object --literally -w -t commit --stdin <munged >name &&
 		git branch bad $(cat name) &&
 
 		test_must_fail git -c fsck.nulInCommit=error fsck 2>warn.1 &&
@@ -794,8 +794,8 @@
 	git cat-file commit HEAD >basis &&
 	sed "s/</one/" basis >one &&
 	sed "s/</foo/" basis >two &&
-	one=$(git hash-object -t commit -w one) &&
-	two=$(git hash-object -t commit -w two) &&
+	one=$(git hash-object --literally -t commit -w one) &&
+	two=$(git hash-object --literally -t commit -w two) &&
 	pack=$(
 		{
 			echo $one &&
diff --git a/t/t1451-fsck-buffer.sh b/t/t1451-fsck-buffer.sh
new file mode 100755
index 0000000..3413da4
--- /dev/null
+++ b/t/t1451-fsck-buffer.sh
@@ -0,0 +1,142 @@
+#!/bin/sh
+
+test_description='fsck on buffers without NUL termination
+
+The goal here is to make sure that the various fsck parsers never look
+past the end of the buffer they are given, even when encountering broken
+or truncated objects.
+
+We have to use "hash-object" for this because most code paths that read objects
+append an extra NUL for safety after the buffer. But hash-object, since it is
+reading straight from a file (and possibly even mmap-ing it) cannot always do
+so.
+
+These tests _might_ catch such overruns in normal use, but should be run with
+ASan or valgrind for more confidence.
+'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+# the general idea for tags and commits is to build up the "base" file
+# progressively, and then test new truncations on top of it.
+reset () {
+	test_expect_success 'reset input to empty' '
+		>base
+	'
+}
+
+add () {
+	content="$1"
+	type=${content%% *}
+	test_expect_success "add $type line" '
+		echo "$content" >>base
+	'
+}
+
+check () {
+	type=$1
+	fsck=$2
+	content=$3
+	test_expect_success "truncated $type ($fsck, \"$content\")" '
+		# do not pipe into hash-object here; we want to increase
+		# the chance that it uses a fixed-size buffer or mmap,
+		# and a pipe would be read into a strbuf.
+		{
+			cat base &&
+			echo "$content"
+		} >input &&
+		test_must_fail git hash-object -t "$type" input 2>err &&
+		grep "$fsck" err
+	'
+}
+
+test_expect_success 'create valid objects' '
+	git commit --allow-empty -m foo &&
+	commit=$(git rev-parse --verify HEAD) &&
+	tree=$(git rev-parse --verify HEAD^{tree})
+'
+
+reset
+check commit missingTree ""
+check commit missingTree "tr"
+check commit missingTree "tree"
+check commit badTreeSha1 "tree "
+check commit badTreeSha1 "tree 1234"
+add "tree $tree"
+
+# these expect missingAuthor because "parent" is optional
+check commit missingAuthor ""
+check commit missingAuthor "par"
+check commit missingAuthor "parent"
+check commit badParentSha1 "parent "
+check commit badParentSha1 "parent 1234"
+add "parent $commit"
+
+check commit missingAuthor ""
+check commit missingAuthor "au"
+check commit missingAuthor "author"
+ident_checks () {
+	check $1 missingEmail "$2 "
+	check $1 missingEmail "$2 name"
+	check $1 badEmail "$2 name <"
+	check $1 badEmail "$2 name <email"
+	check $1 missingSpaceBeforeDate "$2 name <email>"
+	check $1 badDate "$2 name <email> "
+	check $1 badDate "$2 name <email> 1234"
+	check $1 badTimezone "$2 name <email> 1234 "
+	check $1 badTimezone "$2 name <email> 1234 +"
+}
+ident_checks commit author
+add "author name <email> 1234 +0000"
+
+check commit missingCommitter ""
+check commit missingCommitter "co"
+check commit missingCommitter "committer"
+ident_checks commit committer
+add "committer name <email> 1234 +0000"
+
+reset
+check tag missingObject ""
+check tag missingObject "obj"
+check tag missingObject "object"
+check tag badObjectSha1 "object "
+check tag badObjectSha1 "object 1234"
+add "object $commit"
+
+check tag missingType ""
+check tag missingType "ty"
+check tag missingType "type"
+check tag badType "type "
+check tag badType "type com"
+add "type commit"
+
+check tag missingTagEntry ""
+check tag missingTagEntry "ta"
+check tag missingTagEntry "tag"
+check tag badTagName "tag "
+add "tag foo"
+
+check tag missingTagger ""
+check tag missingTagger "ta"
+check tag missingTagger "tagger"
+ident_checks tag tagger
+
+# trees are a binary format and can't use our earlier helpers
+test_expect_success 'truncated tree (short hash)' '
+	printf "100644 foo\0\1\1\1\1" >input &&
+	test_must_fail git hash-object -t tree input 2>err &&
+	grep badTree err
+'
+
+test_expect_success 'truncated tree (missing nul)' '
+	# these two things are indistinguishable to the parser. The important
+	# thing about this is example is that there are enough bytes to
+	# make up a hash, and that there is no NUL (and we confirm that the
+	# parser does not walk past the end of the buffer).
+	printf "100644 a long filename, or a hash with missing nul?" >input &&
+	test_must_fail git hash-object -t tree input 2>err &&
+	grep badTree err
+'
+
+test_done
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index 81de584..37ee509 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -195,7 +195,7 @@
 '
 
 test_expect_success 'rev-parse --show-object-format in repo' '
-	echo "$(test_oid algo)" >expect &&
+	test_oid algo >expect &&
 	git rev-parse --show-object-format >actual &&
 	test_cmp expect actual &&
 	git rev-parse --show-object-format=storage >actual &&
diff --git a/t/t1501-work-tree.sh b/t/t1501-work-tree.sh
index b755580..ae6528a 100755
--- a/t/t1501-work-tree.sh
+++ b/t/t1501-work-tree.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test separate work tree'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t1509-root-work-tree.sh b/t/t1509-root-work-tree.sh
index 553a3f6..c799f5b 100755
--- a/t/t1509-root-work-tree.sh
+++ b/t/t1509-root-work-tree.sh
@@ -221,7 +221,8 @@
 	rm -rf /.git &&
 	echo "Initialized empty Git repository in /.git/" > expected &&
 	git init > result &&
-	test_cmp expected result
+	test_cmp expected result &&
+	git config --global --add safe.directory /
 '
 
 test_vars 'auto gitdir, root' ".git" "/" ""
@@ -242,7 +243,7 @@
 # DESTROYYYYY!!!!!
 test_expect_success 'setup' '
 	rm -rf /refs /objects /info /hooks &&
-	rm -f /expected /ls.expected /me /result &&
+	rm -f /HEAD /expected /ls.expected /me /result &&
 	cd / &&
 	echo "Initialized empty Git repository in /" > expected &&
 	git init --bare > result &&
@@ -255,4 +256,9 @@
 
 test_vars 'auto gitdir, root' "/" "" ""
 
+test_expect_success 'cleanup root' '
+	rm -rf /.git /refs /objects /info /hooks /branches /foo &&
+	rm -f /HEAD /config /description /expected /ls.expected /me /result
+'
+
 test_done
diff --git a/t/t1600-index.sh b/t/t1600-index.sh
index 010989f..9368d82 100755
--- a/t/t1600-index.sh
+++ b/t/t1600-index.sh
@@ -65,6 +65,37 @@
 	)
 '
 
+test_expect_success 'index.skipHash config option' '
+	rm -f .git/index &&
+	git -c index.skipHash=true add a &&
+	test_trailing_hash .git/index >hash &&
+	echo $(test_oid zero) >expect &&
+	test_cmp expect hash &&
+	git fsck &&
+
+	rm -f .git/index &&
+	git -c feature.manyFiles=true add a &&
+	test_trailing_hash .git/index >hash &&
+	cmp expect hash &&
+
+	rm -f .git/index &&
+	git -c feature.manyFiles=true \
+	    -c index.skipHash=false add a &&
+	test_trailing_hash .git/index >hash &&
+	! cmp expect hash &&
+
+	test_commit start &&
+	git -c protocol.file.allow=always submodule add ./ sub &&
+	git config index.skipHash false &&
+	git -C sub config index.skipHash true &&
+	rm -f .git/modules/sub/index &&
+	>sub/file &&
+	git -C sub add a &&
+	test_trailing_hash .git/modules/sub/index >hash &&
+	test_cmp expect hash &&
+	git -C sub fsck
+'
+
 test_index_version () {
 	INDEX_VERSION_CONFIG=$1 &&
 	FEATURE_MANY_FILES=$2 &&
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
index 2ef3579..3506f62 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -177,4 +177,22 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'stdin to hooks' '
+	write_script .git/hooks/test-hook <<-\EOF &&
+	echo BEGIN stdin
+	cat
+	echo END stdin
+	EOF
+
+	cat >expect <<-EOF &&
+	BEGIN stdin
+	hello
+	END stdin
+	EOF
+
+	echo hello >input &&
+	git hook run --to-stdin=input test-hook 2>actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh
index 1f6c4ed..4b6372f 100755
--- a/t/t2012-checkout-last.sh
+++ b/t/t2012-checkout-last.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh
index 9425aae..fb0e1388 100755
--- a/t/t2015-checkout-unborn.sh
+++ b/t/t2015-checkout-unborn.sh
@@ -9,11 +9,12 @@
 
 test_expect_success 'setup' '
 	mkdir parent &&
-	(cd parent &&
-	 git init &&
-	 echo content >file &&
-	 git add file &&
-	 git commit -m base
+	(
+		cd parent &&
+		git init &&
+		echo content >file &&
+		git add file &&
+		git commit -m base
 	) &&
 	git fetch parent main:origin
 '
diff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh
index a5822e4..747eb55 100755
--- a/t/t2016-checkout-patch.sh
+++ b/t/t2016-checkout-patch.sh
@@ -4,12 +4,6 @@
 
 . ./lib-patch-mode.sh
 
-if ! test_have_prereq ADD_I_USE_BUILTIN && ! test_have_prereq PERL
-then
-	skip_all='skipping interactive add tests, PERL not set'
-	test_done
-fi
-
 test_expect_success 'setup' '
 	mkdir dir &&
 	echo parent > dir/foo &&
diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh
index 771c3c3..8581ad3 100755
--- a/t/t2018-checkout-branch.sh
+++ b/t/t2018-checkout-branch.sh
@@ -3,6 +3,7 @@
 test_description='checkout'
 
 TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Arguments: [!] <branch> <oid> [<checkout options>]
diff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh
index 8f13341..3832c3d 100755
--- a/t/t2025-checkout-no-overlay.sh
+++ b/t/t2025-checkout-no-overlay.sh
@@ -2,6 +2,7 @@
 
 test_description='checkout --no-overlay <tree-ish> -- <pathspec>'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh
index 3d28c7f..568a47e 100755
--- a/t/t2401-worktree-prune.sh
+++ b/t/t2401-worktree-prune.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success initialize '
diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh
index 79e0fce..9ad9be0 100755
--- a/t/t2402-worktree-list.sh
+++ b/t/t2402-worktree-list.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh
index 5c44453..8970780 100755
--- a/t/t2406-worktree-repair.sh
+++ b/t/t2406-worktree-repair.sh
@@ -2,6 +2,7 @@
 
 test_description='test git worktree repair'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t3009-ls-files-others-nonsubmodule.sh b/t/t3009-ls-files-others-nonsubmodule.sh
index 963f346..14218b3 100755
--- a/t/t3009-ls-files-others-nonsubmodule.sh
+++ b/t/t3009-ls-files-others-nonsubmodule.sh
@@ -18,6 +18,7 @@
       git repository with a commit and an untracked file
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup: directories' '
diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh
index 580e158..0541787 100755
--- a/t/t3010-ls-files-killed-modified.sh
+++ b/t/t3010-ls-files-killed-modified.sh
@@ -41,6 +41,8 @@
 We should report path0, path1, path2/file2, path3/file3, path7 and path8
 modified without reporting path9 and path10.  submod1 is also modified.
 '
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'git update-index --add to add various paths.' '
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index f1f09ab..3884694 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -2,6 +2,7 @@
 
 test_description='fetching and pushing project with subproject'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh
index 52f76f7..c4a72ae 100755
--- a/t/t3060-ls-files-with-tree.sh
+++ b/t/t3060-ls-files-with-tree.sh
@@ -8,6 +8,8 @@
 This test runs git ls-files --with-tree and in particular in
 a scenario known to trigger a crash with some versions of git.
 '
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t3104-ls-tree-format.sh b/t/t3104-ls-tree-format.sh
index 805b30f..3adb206 100755
--- a/t/t3104-ls-tree-format.sh
+++ b/t/t3104-ls-tree-format.sh
@@ -20,7 +20,6 @@
 	format=$1 &&
 	opts=$2 &&
 	fmtopts=$3 &&
-	shift 2 &&
 
 	test_expect_success "ls-tree '--format=<$format>' is like options '$opts $fmtopts'" '
 		git ls-tree $opts -r HEAD >expect &&
diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh
index 84dd0cd..b5f4d6a 100755
--- a/t/t3206-range-diff.sh
+++ b/t/t3206-range-diff.sh
@@ -33,6 +33,26 @@
 	u3 sha256:736c4bc
 	u4 sha256:673e77d
 
+	# topic (abbrev=10)
+	t1_abbrev sha1:4de457d2c0
+	t2_abbrev sha1:fccce22f8c
+	t3_abbrev sha1:147e64ef53
+	t4_abbrev sha1:a63e992599
+	t1_abbrev sha256:b89f8b9092
+	t2_abbrev sha256:5f12aadf34
+	t3_abbrev sha256:ea8b273a6c
+	t4_abbrev sha256:14b73361fc
+
+	# unmodified (abbrev=10)
+	u1_abbrev sha1:35b9b25f76
+	u2_abbrev sha1:de345ab3de
+	u3_abbrev sha1:9af6654000
+	u4_abbrev sha1:2901f773f3
+	u1_abbrev sha256:e3731be242
+	u2_abbrev sha256:14fadf8cee
+	u3_abbrev sha256:736c4bcb44
+	u4_abbrev sha256:673e77d589
+
 	# reordered
 	r1 sha1:aca177a
 	r2 sha1:14ad629
@@ -153,6 +173,18 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'simple A..B A..C (unmodified) with --abbrev' '
+	git range-diff --no-color --abbrev=10 main..topic main..unmodified \
+		>actual &&
+	cat >expect <<-EOF &&
+	1:  $(test_oid t1_abbrev) = 1:  $(test_oid u1_abbrev) s/5/A/
+	2:  $(test_oid t2_abbrev) = 2:  $(test_oid u2_abbrev) s/4/A/
+	3:  $(test_oid t3_abbrev) = 3:  $(test_oid u3_abbrev) s/11/B/
+	4:  $(test_oid t4_abbrev) = 4:  $(test_oid u4_abbrev) s/12/B/
+	EOF
+	test_cmp expect actual
+'
+
 test_expect_success 'A^! and A^-<n> (unmodified)' '
 	git range-diff --no-color topic^! unmodified^-1 >actual &&
 	cat >expect <<-EOF &&
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index 577f32d..07a0ff9 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -12,6 +12,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'enable reflogs' '
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 462cefd..ff0afad 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1449,14 +1449,15 @@
 
 test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = warn' '
 	cat >expect <<-EOF &&
-	error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4)
+	error: invalid command '\''pickled'\''
+	error: invalid line 1: pickled $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4)
 	Warning: some commits may have been dropped accidentally.
 	Dropped commits (newer to older):
 	 - $(git rev-list --pretty=oneline --abbrev-commit -1 primary)
 	 - $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4)
 	To avoid this message, use "drop" to explicitly remove a commit.
 	EOF
-	head -n4 expect >expect.2 &&
+	head -n5 expect >expect.2 &&
 	tail -n1 expect >>expect.2 &&
 	tail -n4 expect.2 >expect.3 &&
 	test_config rebase.missingCommitsCheck warn &&
@@ -1467,7 +1468,7 @@
 			git rebase -i --root &&
 		cp .git/rebase-merge/git-rebase-todo.backup orig &&
 		FAKE_LINES="2 3 4" git rebase --edit-todo 2>actual.2 &&
-		head -n6 actual.2 >actual &&
+		head -n7 actual.2 >actual &&
 		test_cmp expect actual &&
 		cp orig .git/rebase-merge/git-rebase-todo &&
 		FAKE_LINES="1 2 3 4" git rebase --edit-todo 2>actual.2 &&
@@ -1483,7 +1484,8 @@
 
 test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = error' '
 	cat >expect <<-EOF &&
-	error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4)
+	error: invalid command '\''pickled'\''
+	error: invalid line 1: pickled $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4)
 	Warning: some commits may have been dropped accidentally.
 	Dropped commits (newer to older):
 	 - $(git rev-list --pretty=oneline --abbrev-commit -1 primary)
@@ -1583,7 +1585,7 @@
 		set_fake_editor &&
 		test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \
 		git rebase -i --root 2>actual &&
-		test_i18ngrep "badcmd $(git rev-list --oneline -1 primary~1)" \
+		test_i18ngrep "pickled $(git rev-list --oneline -1 primary~1)" \
 				actual &&
 		test_i18ngrep "You can fix this with .git rebase --edit-todo.." \
 				actual &&
@@ -2072,6 +2074,7 @@
 '
 
 test_expect_success '--update-refs: check failed ref update' '
+	test_when_finished "test_might_fail git rebase --abort" &&
 	git checkout -B update-refs-error no-conflict-branch &&
 	git branch -f base HEAD~4 &&
 	git branch -f first HEAD~3 &&
@@ -2123,6 +2126,28 @@
 	test_cmp expect err.trimmed
 '
 
+test_expect_success 'bad labels and refs rejected when parsing todo list' '
+	test_when_finished "test_might_fail git rebase --abort" &&
+	cat >todo <<-\EOF &&
+	exec >execed
+	label #
+	label :invalid
+	update-ref :bad
+	update-ref topic
+	EOF
+	rm -f execed &&
+	(
+		set_replace_editor todo &&
+		test_must_fail git rebase -i HEAD 2>err
+	) &&
+	grep "'\''#'\'' is not a valid label" err &&
+	grep "'\'':invalid'\'' is not a valid label" err &&
+	grep "'\'':bad'\'' is not a valid refname" err &&
+	grep "update-ref requires a fully qualified refname e.g. refs/heads/topic" \
+		err &&
+	test_path_is_missing execed
+'
+
 # This must be the last test in this file
 test_expect_success '$EDITOR and friends are unchanged' '
 	test_editor_unchanged
diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh
index 2524331..8979bc3 100755
--- a/t/t3405-rebase-malformed.sh
+++ b/t/t3405-rebase-malformed.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-rebase.sh
 
diff --git a/t/t3409-rebase-environ.sh b/t/t3409-rebase-environ.sh
index 83ffb39..acaf555 100755
--- a/t/t3409-rebase-environ.sh
+++ b/t/t3409-rebase-environ.sh
@@ -2,6 +2,7 @@
 
 test_description='git rebase interactive environment'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index 58371d8..e75b3d0 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -7,6 +7,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 log_with_names () {
diff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh
index 9fab0d7..e845683 100755
--- a/t/t3413-rebase-hook.sh
+++ b/t/t3413-rebase-hook.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t3416-rebase-onto-threedots.sh b/t/t3416-rebase-onto-threedots.sh
index ea501f2..f8c4ed7 100755
--- a/t/t3416-rebase-onto-threedots.sh
+++ b/t/t3416-rebase-onto-threedots.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-rebase.sh"
 
diff --git a/t/t3419-rebase-patch-id.sh b/t/t3419-rebase-patch-id.sh
index 7181f17..6c61f24 100755
--- a/t/t3419-rebase-patch-id.sh
+++ b/t/t3419-rebase-patch-id.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 scramble () {
diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh
index 6dabb05..4711b37 100755
--- a/t/t3422-rebase-incompatible-options.sh
+++ b/t/t3422-rebase-incompatible-options.sh
@@ -25,11 +25,11 @@
 '
 
 #
-# Rebase has lots of useful options like --whitepsace=fix, which are
-# actually all built in terms of flags to git-am.  Since neither
-# --merge nor --interactive (nor any options that imply those two) use
-# git-am, using them together will result in flags like --whitespace=fix
-# being ignored.  Make sure rebase warns the user and aborts instead.
+# Rebase has a couple options which are specific to the apply backend,
+# and several options which are specific to the merge backend.  Flags
+# from the different sets cannot work together, and we do not want to
+# just ignore one of the sets of flags.  Make sure rebase warns the
+# user and aborts instead.
 #
 
 test_rebase_am_only () {
@@ -50,6 +50,11 @@
 		test_must_fail git rebase $opt --strategy-option=ours A
 	"
 
+	test_expect_success "$opt incompatible with --autosquash" "
+		git checkout B^0 &&
+		test_must_fail git rebase $opt --autosquash A
+	"
+
 	test_expect_success "$opt incompatible with --interactive" "
 		git checkout B^0 &&
 		test_must_fail git rebase $opt --interactive A
@@ -60,9 +65,65 @@
 		test_must_fail git rebase $opt --exec 'true' A
 	"
 
+	test_expect_success "$opt incompatible with --keep-empty" "
+		git checkout B^0 &&
+		test_must_fail git rebase $opt --keep-empty A
+	"
+
+	test_expect_success "$opt incompatible with --empty=..." "
+		git checkout B^0 &&
+		test_must_fail git rebase $opt --empty=ask A
+	"
+
+	test_expect_success "$opt incompatible with --no-reapply-cherry-picks" "
+		git checkout B^0 &&
+		test_must_fail git rebase $opt --no-reapply-cherry-picks A
+	"
+
+	test_expect_success "$opt incompatible with --reapply-cherry-picks" "
+		git checkout B^0 &&
+		test_must_fail git rebase $opt --reapply-cherry-picks A
+	"
+
+	test_expect_success "$opt incompatible with --update-refs" "
+		git checkout B^0 &&
+		test_must_fail git rebase $opt --update-refs A
+	"
+
+	test_expect_success "$opt incompatible with --root without --onto" "
+		git checkout B^0 &&
+		test_must_fail git rebase $opt --root A
+	"
+
+	test_expect_success "$opt incompatible with rebase.autosquash" "
+		git checkout B^0 &&
+		test_must_fail git -c rebase.autosquash=true rebase $opt A 2>err &&
+		grep -e --no-autosquash err
+	"
+
+	test_expect_success "$opt incompatible with rebase.updateRefs" "
+		git checkout B^0 &&
+		test_must_fail git -c rebase.updateRefs=true rebase $opt A 2>err &&
+		grep -e --no-update-refs err
+	"
+
+	test_expect_success "$opt okay with overridden rebase.autosquash" "
+		test_when_finished \"git reset --hard B^0\" &&
+		git checkout B^0 &&
+		git -c rebase.autosquash=true rebase --no-autosquash $opt A
+	"
+
+	test_expect_success "$opt okay with overridden rebase.updateRefs" "
+		test_when_finished \"git reset --hard B^0\" &&
+		git checkout B^0 &&
+		git -c rebase.updateRefs=true rebase --no-update-refs $opt A
+	"
 }
 
+# Check options which imply --apply
 test_rebase_am_only --whitespace=fix
 test_rebase_am_only -C4
+# Also check an explicit --apply
+test_rebase_am_only --apply
 
 test_done
diff --git a/t/t3423-rebase-reword.sh b/t/t3423-rebase-reword.sh
index 4859bb8..2fab703 100755
--- a/t/t3423-rebase-reword.sh
+++ b/t/t3423-rebase-reword.sh
@@ -2,6 +2,7 @@
 
 test_description='git rebase interactive with rewording'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh
index 63acc1e..a16428b 100755
--- a/t/t3425-rebase-topology-merges.sh
+++ b/t/t3425-rebase-topology-merges.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='rebase topology tests with merges'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-rebase.sh
 
diff --git a/t/t3428-rebase-signoff.sh b/t/t3428-rebase-signoff.sh
index f6993b7..e1b1e94 100755
--- a/t/t3428-rebase-signoff.sh
+++ b/t/t3428-rebase-signoff.sh
@@ -5,6 +5,7 @@
 This test runs git rebase --signoff and make sure that it works.
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # A simple file to commit
diff --git a/t/t3429-rebase-edit-todo.sh b/t/t3429-rebase-edit-todo.sh
index abd66f3..8e0d039 100755
--- a/t/t3429-rebase-edit-todo.sh
+++ b/t/t3429-rebase-edit-todo.sh
@@ -2,6 +2,7 @@
 
 test_description='rebase should reread the todo file if an exec modifies it'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-rebase.sh
 
diff --git a/t/t3431-rebase-fork-point.sh b/t/t3431-rebase-fork-point.sh
index 70e8136..4bfc779 100755
--- a/t/t3431-rebase-fork-point.sh
+++ b/t/t3431-rebase-fork-point.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # A---B---D---E    (main)
diff --git a/t/t3432-rebase-fast-forward.sh b/t/t3432-rebase-fast-forward.sh
index 5086e14..7f1a5dd 100755
--- a/t/t3432-rebase-fast-forward.sh
+++ b/t/t3432-rebase-fast-forward.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t3433-rebase-across-mode-change.sh b/t/t3433-rebase-across-mode-change.sh
index 05df964..c8172b0 100755
--- a/t/t3433-rebase-across-mode-change.sh
+++ b/t/t3433-rebase-across-mode-change.sh
@@ -2,6 +2,7 @@
 
 test_description='git rebase across mode change'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh
index c023fef..dd3b301 100755
--- a/t/t3437-rebase-fixup-options.sh
+++ b/t/t3437-rebase-fixup-options.sh
@@ -14,6 +14,7 @@
 "amend!" upon --autosquash.
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
@@ -50,6 +51,7 @@
 	body
 	EOF
 
+	test_commit initial &&
 	test_commit A A &&
 	test_commit B B &&
 	get_author HEAD >expected-author &&
@@ -208,4 +210,29 @@
 		actual-squash-message
 '
 
+test_expect_success 'fixup -[Cc]<commit> works' '
+	test_when_finished "test_might_fail git rebase --abort" &&
+	cat >todo <<-\EOF &&
+	pick A
+	fixup -CA1
+	pick B
+	fixup -cA2
+	EOF
+	(
+		set_replace_editor todo &&
+		FAKE_COMMIT_MESSAGE="edited and fixed up" \
+			git rebase -i initial initial
+	) &&
+	git log --pretty=format:%B initial.. >actual &&
+	cat >expect <<-EOF &&
+	edited and fixed up
+	$EMPTY
+	new subject
+	$EMPTY
+	new
+	body
+	EOF
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t3438-rebase-broken-files.sh b/t/t3438-rebase-broken-files.sh
index b92a3ce..c614c4f 100755
--- a/t/t3438-rebase-broken-files.sh
+++ b/t/t3438-rebase-broken-files.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='rebase behavior when on-disk files are broken'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'set up conflicting branches' '
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 1f4cfc3..2f3e3e2 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -13,6 +13,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t3502-cherry-pick-merge.sh b/t/t3502-cherry-pick-merge.sh
index 5495eac..1b2c0d6 100755
--- a/t/t3502-cherry-pick-merge.sh
+++ b/t/t3502-cherry-pick-merge.sh
@@ -11,6 +11,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t3503-cherry-pick-root.sh b/t/t3503-cherry-pick-root.sh
index 95fe4fe..76d393d 100755
--- a/t/t3503-cherry-pick-root.sh
+++ b/t/t3503-cherry-pick-root.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh
index 7e11bd4..b71bad1 100755
--- a/t/t3506-cherry-pick-ff.sh
+++ b/t/t3506-cherry-pick-ff.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh
index 84a587d..dd5d92e 100755
--- a/t/t3511-cherry-pick-x.sh
+++ b/t/t3511-cherry-pick-x.sh
@@ -2,6 +2,7 @@
 
 test_description='Test cherry-pick -x and -s'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 pristine_detach () {
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index 5841f28..3a99837 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -7,7 +7,7 @@
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-if test_have_prereq !ADD_I_USE_BUILTIN,!PERL
+if test_have_prereq !PERL
 then
 	skip_all='skipping add -i (scripted) tests, perl not available'
 	test_done
@@ -46,6 +46,21 @@
 	)
 }
 
+test_expect_success 'warn about add.interactive.useBuiltin' '
+	cat >expect <<-\EOF &&
+	warning: the add.interactive.useBuiltin setting has been removed!
+	See its entry in '\''git help config'\'' for details.
+	No changes.
+	EOF
+
+	for v in = =true =false
+	do
+		git -c "add.interactive.useBuiltin$v" add -p >out 2>actual &&
+		test_must_be_empty out &&
+		test_cmp expect actual || return 1
+	done
+'
+
 test_expect_success 'setup (initial)' '
 	echo content >file &&
 	git add file &&
@@ -547,15 +562,7 @@
 	! grep "^+15" actual
 '
 
-test_expect_success 'setup ADD_I_USE_BUILTIN check' '
-	result=success &&
-	if ! test_have_prereq ADD_I_USE_BUILTIN
-	then
-		result=failure
-	fi
-'
-
-test_expect_$result 'split hunk "add -p (no, yes, edit)"' '
+test_expect_success 'split hunk "add -p (no, yes, edit)"' '
 	test_write_lines 5 10 20 21 30 31 40 50 60 >test &&
 	git reset &&
 	# test sequence is s(plit), n(o), y(es), e(dit)
@@ -579,7 +586,7 @@
 	test_must_fail git grep --cached before
 '
 
-test_expect_$result 'edit, adding lines to the first hunk' '
+test_expect_success 'edit, adding lines to the first hunk' '
 	test_write_lines 10 11 20 30 40 50 51 60 >test &&
 	git reset &&
 	tr _ " " >patch <<-EOF &&
diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh
index e3cf0ff..d3e428f 100755
--- a/t/t3800-mktag.sh
+++ b/t/t3800-mktag.sh
@@ -4,6 +4,7 @@
 
 test_description='git mktag: tag object verify test'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 ###########################################################
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index de1da46..f3313b8 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -2281,7 +2281,25 @@
 	test_line_count = 1 output
 '
 
-test_expect_success 'format-patch --pretty=mboxrd' '
+test_expect_success 'format-patch with format.attach' '
+	test_when_finished "rm -fr patches" &&
+	separator=attachment-separator &&
+	test_config format.attach "$separator" &&
+	filename=$(git format-patch -o patches -1) &&
+	grep "^Content-Type: multipart/.*$separator" "$filename"
+'
+
+test_expect_success 'format-patch with format.attach=disabled' '
+	test_when_finished "rm -fr patches" &&
+	separator=attachment-separator &&
+	test_config_global format.attach "$separator" &&
+	test_config format.attach "" &&
+	filename=$(git format-patch -o patches -1) &&
+	# The output should not even declare content type for text/plain.
+	! grep "^Content-Type: multipart/" "$filename"
+'
+
+test_expect_success '-c format.mboxrd format-patch' '
 	sp=" " &&
 	cat >msg <<-INPUT_END &&
 	mboxrd should escape the body
@@ -2316,7 +2334,9 @@
 	INPUT_END
 
 	C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) &&
-	git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch &&
+	git -c format.mboxrd format-patch --stdout -1 $C~1..$C >patch &&
+	git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >compat &&
+	test_cmp patch compat &&
 	git grep -h --no-index -A11 \
 		"^>From could trip up a loose mbox parser" patch >actual &&
 	test_cmp expect actual
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index f3e20dd..b298f22 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -1638,7 +1638,7 @@
 	test_cmp expect actual
 '
 
-test_expect_success !SANITIZE_LEAK 'no effect on show from --color-moved with --word-diff' '
+test_expect_success 'no effect on show from --color-moved with --word-diff' '
 	git show --color-moved --word-diff >actual &&
 	git show --word-diff >expect &&
 	test_cmp expect actual
@@ -2024,7 +2024,7 @@
 	test_cmp expected actual
 '
 
-test_expect_success !SANITIZE_LEAK 'move detection with submodules' '
+test_expect_success 'move detection with submodules' '
 	test_create_repo bananas &&
 	echo ripe >bananas/recipe &&
 	git -C bananas add recipe &&
diff --git a/t/t4018/java-class-brace-on-separate-line b/t/t4018/java-class-brace-on-separate-line
new file mode 100644
index 0000000..8795acd
--- /dev/null
+++ b/t/t4018/java-class-brace-on-separate-line
@@ -0,0 +1,6 @@
+class RIGHT
+{
+    static int ONE;
+    static int TWO;
+    static int ChangeMe;
+}
diff --git a/t/t4018/java-class-space-before-type-parameters b/t/t4018/java-class-space-before-type-parameters
new file mode 100644
index 0000000..0bdef1d
--- /dev/null
+++ b/t/t4018/java-class-space-before-type-parameters
@@ -0,0 +1,6 @@
+class RIGHT <TYPE, PARAMS, AFTER, SPACE> {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    private A ChangeMe;
+}
diff --git a/t/t4018/java-class-type-parameters b/t/t4018/java-class-type-parameters
new file mode 100644
index 0000000..579aa7a
--- /dev/null
+++ b/t/t4018/java-class-type-parameters
@@ -0,0 +1,6 @@
+class RIGHT<A, B> {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    private A ChangeMe;
+}
diff --git a/t/t4018/java-class-type-parameters-implements b/t/t4018/java-class-type-parameters-implements
new file mode 100644
index 0000000..b8038b1
--- /dev/null
+++ b/t/t4018/java-class-type-parameters-implements
@@ -0,0 +1,6 @@
+class RIGHT<A, B> implements List<A> {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    private A ChangeMe;
+}
diff --git a/t/t4018/java-interface-type-parameters b/t/t4018/java-interface-type-parameters
new file mode 100644
index 0000000..a4baa1a
--- /dev/null
+++ b/t/t4018/java-interface-type-parameters
@@ -0,0 +1,6 @@
+interface RIGHT<A, B> {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    public B foo(A ChangeMe);
+}
diff --git a/t/t4018/java-interface-type-parameters-extends b/t/t4018/java-interface-type-parameters-extends
new file mode 100644
index 0000000..31d7fb3
--- /dev/null
+++ b/t/t4018/java-interface-type-parameters-extends
@@ -0,0 +1,6 @@
+interface RIGHT<A, B> extends Function<A, B> {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    public B foo(A ChangeMe);
+}
diff --git a/t/t4018/java-non-sealed b/t/t4018/java-non-sealed
new file mode 100644
index 0000000..069087c
--- /dev/null
+++ b/t/t4018/java-non-sealed
@@ -0,0 +1,8 @@
+public abstract sealed class SealedClass {
+    public static non-sealed class RIGHT extends SealedClass {
+        static int ONE;
+        static int TWO;
+        static int THREE;
+        private int ChangeMe;
+    }
+}
diff --git a/t/t4018/java-record b/t/t4018/java-record
new file mode 100644
index 0000000..97aa819
--- /dev/null
+++ b/t/t4018/java-record
@@ -0,0 +1,6 @@
+public record RIGHT(int comp1, double comp2, String comp3) {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    static int ChangeMe;
+}
diff --git a/t/t4018/java-record-space-before-components b/t/t4018/java-record-space-before-components
new file mode 100644
index 0000000..9827f22
--- /dev/null
+++ b/t/t4018/java-record-space-before-components
@@ -0,0 +1,6 @@
+public record RIGHT (String components, String after, String space) {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    static int ChangeMe;
+}
diff --git a/t/t4018/java-record-type-parameters b/t/t4018/java-record-type-parameters
new file mode 100644
index 0000000..f62a035
--- /dev/null
+++ b/t/t4018/java-record-type-parameters
@@ -0,0 +1,6 @@
+public record RIGHT<A, N extends Number>(A comp1, N comp2, int comp3) {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    static int ChangeMe;
+}
diff --git a/t/t4018/java-sealed b/t/t4018/java-sealed
new file mode 100644
index 0000000..785fbc6
--- /dev/null
+++ b/t/t4018/java-sealed
@@ -0,0 +1,7 @@
+public abstract sealed class Sealed { // RIGHT
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    public final class ChangeMe extends Sealed {
+    }
+}
diff --git a/t/t4018/java-sealed-permits b/t/t4018/java-sealed-permits
new file mode 100644
index 0000000..18dd489
--- /dev/null
+++ b/t/t4018/java-sealed-permits
@@ -0,0 +1,6 @@
+public abstract sealed class RIGHT permits PermittedA, PermittedB {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    private int ChangeMe;
+}
diff --git a/t/t4018/java-sealed-type-parameters b/t/t4018/java-sealed-type-parameters
new file mode 100644
index 0000000..e6530c4
--- /dev/null
+++ b/t/t4018/java-sealed-type-parameters
@@ -0,0 +1,6 @@
+public abstract sealed class RIGHT<A, B> {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    private int ChangeMe;
+}
diff --git a/t/t4018/java-sealed-type-parameters-implements-permits b/t/t4018/java-sealed-type-parameters-implements-permits
new file mode 100644
index 0000000..bd6e6d3
--- /dev/null
+++ b/t/t4018/java-sealed-type-parameters-implements-permits
@@ -0,0 +1,6 @@
+public abstract sealed class RIGHT<A, B> implements List<A> permits PermittedA, PermittedB {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    private int ChangeMe;
+}
diff --git a/t/t4018/java-sealed-type-parameters-permits b/t/t4018/java-sealed-type-parameters-permits
new file mode 100644
index 0000000..25a0da6
--- /dev/null
+++ b/t/t4018/java-sealed-type-parameters-permits
@@ -0,0 +1,6 @@
+public abstract sealed class RIGHT<A, B> permits PermittedA, PermittedB {
+    static int ONE;
+    static int TWO;
+    static int THREE;
+    private int ChangeMe;
+}
diff --git a/t/t4044-diff-index-unique-abbrev.sh b/t/t4044-diff-index-unique-abbrev.sh
index 29e49d2..9f6043d 100755
--- a/t/t4044-diff-index-unique-abbrev.sh
+++ b/t/t4044-diff-index-unique-abbrev.sh
@@ -34,12 +34,12 @@
 	100644 blob $(test_oid hash2)	foo
 	EOF
 
-	echo "$(test_oid val1)" > foo &&
+	test_oid val1 > foo &&
 	git add foo &&
 	git commit -m "initial" &&
 	git cat-file -p HEAD: > actual &&
 	test_cmp expect_initial actual &&
-	echo "$(test_oid val2)" > foo &&
+	test_oid val2 > foo &&
 	git commit -a -m "update" &&
 	git cat-file -p HEAD: > actual &&
 	test_cmp expect_update actual
diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh
index 5e1bbb5..9b46c4c 100755
--- a/t/t4045-diff-relative.sh
+++ b/t/t4045-diff-relative.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='diff --relative tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh
index 0ae0cd3..ffaf693 100755
--- a/t/t4046-diff-unmerged.sh
+++ b/t/t4046-diff-unmerged.sh
@@ -86,4 +86,14 @@
 	test_cmp diff-files-3.expect diff-files-3.actual
 '
 
+test_expect_success 'diff --stat' '
+	for path in $paths
+	do
+		echo " $path | Unmerged" || return 1
+	done >diff-stat.expect &&
+	echo " 0 files changed" >>diff-stat.expect &&
+	git diff --cached --stat >diff-stat.actual &&
+	test_cmp diff-stat.expect diff-stat.actual
+'
+
 test_done
diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh
index b5c281e..3ee27e2 100755
--- a/t/t4052-stat-output.sh
+++ b/t/t4052-stat-output.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 3feadf0..4e9fa04 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -2,6 +2,7 @@
 
 test_description='diff --no-index'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t4054-diff-bogus-tree.sh b/t/t4054-diff-bogus-tree.sh
index 294fb55..05c88f8 100755
--- a/t/t4054-diff-bogus-tree.sh
+++ b/t/t4054-diff-bogus-tree.sh
@@ -10,7 +10,7 @@
 	bogus_tree=$(
 		printf "100644 fooQ$name" |
 		q_to_nul |
-		git hash-object -w --stdin -t tree
+		git hash-object --literally -w --stdin -t tree
 	)
 '
 
diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh
index 54614b8..2501c89 100755
--- a/t/t4058-diff-duplicates.sh
+++ b/t/t4058-diff-duplicates.sh
@@ -29,7 +29,7 @@
 		make_tree_entry "$1" "$2" "$3"
 		shift; shift; shift
 	done |
-	git hash-object -w -t tree --stdin
+	git hash-object --literally -w -t tree --stdin
 }
 
 # this is kind of a convoluted setup, but matches
diff --git a/t/t4067-diff-partial-clone.sh b/t/t4067-diff-partial-clone.sh
index 28f42a4..f60f5cb 100755
--- a/t/t4067-diff-partial-clone.sh
+++ b/t/t4067-diff-partial-clone.sh
@@ -2,6 +2,7 @@
 
 test_description='behavior of diff when reading objects in a partial clone'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'git show batches blobs' '
diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh
index 1618a6d..e9a87d7 100755
--- a/t/t4111-apply-subdir.sh
+++ b/t/t4111-apply-subdir.sh
@@ -2,6 +2,7 @@
 
 test_description='patching from inconvenient places'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t4135-apply-weird-filenames.sh b/t/t4135-apply-weird-filenames.sh
index 6bc3fb9..d3502c6 100755
--- a/t/t4135-apply-weird-filenames.sh
+++ b/t/t4135-apply-weird-filenames.sh
@@ -2,6 +2,7 @@
 
 test_description='git apply with weird postimage filenames'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index cdad4b6..78cf1c8 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -345,6 +345,21 @@
 	test_cmp_rev first HEAD
 '
 
+test_expect_success 'am with failing applypatch-msg hook (no verify)' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+	test_hook applypatch-msg <<-\EOF &&
+	echo hook-message >"$1"
+	exit 1
+	EOF
+	git am --no-verify patch1 &&
+	test_path_is_missing .git/rebase-apply &&
+	git diff --exit-code second &&
+	git log -1 --format=format:%B >actual &&
+	test_cmp msg actual
+'
+
 test_expect_success 'am with pre-applypatch hook' '
 	rm -fr .git/rebase-apply &&
 	git reset --hard &&
@@ -374,6 +389,23 @@
 	test_cmp_rev first HEAD
 '
 
+test_expect_success 'am with failing pre-applypatch hook (no verify)' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+	touch empty-file &&
+	test_hook pre-applypatch <<-\EOF &&
+	rm empty-file
+	exit 1
+	EOF
+	git am --no-verify patch1 &&
+	test_path_is_missing .git/rebase-apply &&
+	test_path_is_file empty-file &&
+	git diff --exit-code second &&
+	git log -1 --format=format:%B >actual &&
+	test_cmp msg actual
+'
+
 test_expect_success 'am with post-applypatch hook' '
 	rm -fr .git/rebase-apply &&
 	git reset --hard &&
@@ -1033,7 +1065,7 @@
 	>From extra escape for reversibility
 	INPUT_END
 	git commit -F msg &&
-	git format-patch --pretty=mboxrd --stdout -1 >mboxrd1 &&
+	git -c format.mboxrd format-patch --stdout -1 >mboxrd1 &&
 	grep "^>From could trip up a loose mbox parser" mboxrd1 &&
 	git checkout -f first &&
 	git am --patch-format=mboxrd mboxrd1 &&
diff --git a/t/t4152-am-subjects.sh b/t/t4152-am-subjects.sh
index 4c68245..9f2edba 100755
--- a/t/t4152-am-subjects.sh
+++ b/t/t4152-am-subjects.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test subject preservation with format-patch | am'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 make_patches() {
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index cd1cab3..fa7f987 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -1022,4 +1022,69 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'git cat-file -s returns correct size with --use-mailmap' '
+	test_when_finished "rm .mailmap" &&
+	cat >.mailmap <<-\EOF &&
+	C O Mitter <committer@example.com> Orig <orig@example.com>
+	EOF
+	git cat-file commit HEAD >commit.out &&
+	echo $(wc -c <commit.out) >expect &&
+	git cat-file --use-mailmap commit HEAD >commit.out &&
+	echo $(wc -c <commit.out) >>expect &&
+	git cat-file -s HEAD >actual &&
+	git cat-file --use-mailmap -s HEAD >>actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git cat-file -s returns correct size with --use-mailmap for tag objects' '
+	test_when_finished "rm .mailmap" &&
+	cat >.mailmap <<-\EOF &&
+	Orig <orig@example.com> C O Mitter <committer@example.com>
+	EOF
+	git tag -a -m "annotated tag" v3 &&
+	git cat-file tag v3 >tag.out &&
+	echo $(wc -c <tag.out) >expect &&
+	git cat-file --use-mailmap tag v3 >tag.out &&
+	echo $(wc -c <tag.out) >>expect &&
+	git cat-file -s v3 >actual &&
+	git cat-file --use-mailmap -s v3 >>actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-check returns correct size with --use-mailmap' '
+	test_when_finished "rm .mailmap" &&
+	cat >.mailmap <<-\EOF &&
+	C O Mitter <committer@example.com> Orig <orig@example.com>
+	EOF
+	git cat-file commit HEAD >commit.out &&
+	commit_size=$(wc -c <commit.out) &&
+	commit_sha=$(git rev-parse HEAD) &&
+	echo $commit_sha commit $commit_size >expect &&
+	git cat-file --use-mailmap commit HEAD >commit.out &&
+	commit_size=$(wc -c <commit.out) &&
+	echo $commit_sha commit $commit_size >>expect &&
+	echo "HEAD" >in &&
+	git cat-file --batch-check <in >actual &&
+	git cat-file --use-mailmap --batch-check <in >>actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command returns correct size with --use-mailmap' '
+	test_when_finished "rm .mailmap" &&
+	cat >.mailmap <<-\EOF &&
+	C O Mitter <committer@example.com> Orig <orig@example.com>
+	EOF
+	git cat-file commit HEAD >commit.out &&
+	commit_size=$(wc -c <commit.out) &&
+	commit_sha=$(git rev-parse HEAD) &&
+	echo $commit_sha commit $commit_size >expect &&
+	git cat-file --use-mailmap commit HEAD >commit.out &&
+	commit_size=$(wc -c <commit.out) &&
+	echo $commit_sha commit $commit_size >>expect &&
+	echo "info HEAD" >in &&
+	git cat-file --batch-command <in >actual &&
+	git cat-file --use-mailmap --batch-command <in >>actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 3e7ad9d..4cf8a77 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -1094,4 +1094,31 @@
 	test_cmp expect error
 '
 
+# pretty-formats note wide char limitations, and add tests
+test_expect_failure 'wide and decomposed characters column counting' '
+
+# from t/lib-unicode-nfc-nfd.sh hex values converted to octal
+	utf8_nfc=$(printf "\303\251") && # e acute combined.
+	utf8_nfd=$(printf "\145\314\201") && # e with a combining acute (i.e. decomposed)
+	utf8_emoji=$(printf "\360\237\221\250") &&
+
+# replacement character when requesting a wide char fits in a single display colum.
+# "half wide" alternative could be a plain ASCII dot `.`
+	utf8_vert_ell=$(printf "\342\213\256") &&
+
+# use ${xxx} here!
+	nfc10="${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}" &&
+	nfd10="${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}" &&
+	emoji5="${utf8_emoji}${utf8_emoji}${utf8_emoji}${utf8_emoji}${utf8_emoji}" &&
+# emoji5 uses 10 display columns
+
+	test_commit "abcdefghij" &&
+	test_commit --no-tag "${nfc10}" &&
+	test_commit --no-tag "${nfd10}" &&
+	test_commit --no-tag "${emoji5}" &&
+	printf "${utf8_emoji}..${utf8_emoji}${utf8_vert_ell}\n${utf8_nfd}..${utf8_nfd}${utf8_nfd}\n${utf8_nfc}..${utf8_nfc}${utf8_nfc}\na..ij\n" >expected &&
+	git log --format="%<(5,mtrunc)%s" -4 >actual &&
+	test_cmp expected actual
+'
+
 test_done
diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh
index 30a2198..e89e1f5 100755
--- a/t/t4212-log-corrupt.sh
+++ b/t/t4212-log-corrupt.sh
@@ -10,7 +10,7 @@
 
 	git cat-file commit HEAD |
 	sed "/^author /s/>/>-<>/" >broken_email.commit &&
-	git hash-object -w -t commit broken_email.commit >broken_email.hash &&
+	git hash-object --literally -w -t commit broken_email.commit >broken_email.hash &&
 	git update-ref refs/heads/broken_email $(cat broken_email.hash)
 '
 
@@ -46,7 +46,7 @@
 munge_author_date () {
 	git cat-file commit "$1" >commit.orig &&
 	sed "s/^\(author .*>\) [0-9]*/\1 $2/" <commit.orig >commit.munge &&
-	git hash-object -w -t commit commit.munge
+	git hash-object --literally -w -t commit commit.munge
 }
 
 test_expect_success 'unparsable dates produce sentinel value' '
diff --git a/t/t4213-log-tabexpand.sh b/t/t4213-log-tabexpand.sh
index 53a4af3..590fce9 100755
--- a/t/t4213-log-tabexpand.sh
+++ b/t/t4213-log-tabexpand.sh
@@ -2,6 +2,7 @@
 
 test_description='log/show --expand-tabs'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 HT="	"
diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh
index 54be7da..45f1d4f 100755
--- a/t/t4254-am-corrupt.sh
+++ b/t/t4254-am-corrupt.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='git am with corrupt input'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 make_mbox_with_nul () {
diff --git a/t/t4256-am-format-flowed.sh b/t/t4256-am-format-flowed.sh
index 2369c4e..1015273 100755
--- a/t/t4256-am-format-flowed.sh
+++ b/t/t4256-am-format-flowed.sh
@@ -2,6 +2,7 @@
 
 test_description='test format=flowed support of git am'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t4257-am-interactive.sh b/t/t4257-am-interactive.sh
index aed8f4d..f26d7fd 100755
--- a/t/t4257-am-interactive.sh
+++ b/t/t4257-am-interactive.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='am --interactive tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'set up patches to apply' '
diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
index cac8559..250f721 100755
--- a/t/t4301-merge-tree-write-tree.sh
+++ b/t/t4301-merge-tree-write-tree.sh
@@ -141,7 +141,7 @@
 #   Commit O: foo, olddir/{a,b,c}
 #   Commit A: modify foo, newdir/{a,b,c}
 #   Commit B: modify foo differently & rename foo -> olddir/bar
-#   Expected: CONFLICT(content) for for newdir/bar (not olddir/bar or foo)
+#   Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
 
 test_expect_success 'directory rename + content conflict' '
 	# Setup
@@ -653,7 +653,7 @@
 #   Commit O: foo, olddir/{a,b,c}
 #   Commit A: delete foo, rename olddir/ -> newdir/, add newdir/bar/file
 #   Commit B: modify foo & rename foo -> olddir/bar
-#   Expected: CONFLICT(content) for for newdir/bar (not olddir/bar or foo)
+#   Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
 
 test_expect_success 'directory rename + rename/delete + modify/delete + directory/file conflict' '
 	# Setup
@@ -860,4 +860,66 @@
 	test_cmp expect actual
 '
 
+
+test_expect_success '--merge-base is incompatible with --stdin' '
+	test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect &&
+
+	grep "^fatal: --merge-base is incompatible with --stdin" expect
+'
+
+# specify merge-base as parent of branch2
+# git merge-tree --write-tree --merge-base=c2 c1 c3
+#   Commit c1: add file1
+#   Commit c2: add file2 after c1
+#   Commit c3: add file3 after c2
+#   Expected: add file3, and file2 does NOT appear
+
+test_expect_success 'specify merge-base as parent of branch2' '
+	# Setup
+	test_when_finished "rm -rf base-b2-p" &&
+	git init base-b2-p &&
+	test_commit -C base-b2-p c1 file1 &&
+	test_commit -C base-b2-p c2 file2 &&
+	test_commit -C base-b2-p c3 file3 &&
+
+	# Testing
+	TREE_OID=$(git -C base-b2-p merge-tree --write-tree --merge-base=c2 c1 c3) &&
+
+	q_to_tab <<-EOF >expect &&
+	100644 blob $(git -C base-b2-p rev-parse c1:file1)Qfile1
+	100644 blob $(git -C base-b2-p rev-parse c3:file3)Qfile3
+	EOF
+
+	git -C base-b2-p ls-tree $TREE_OID >actual &&
+	test_cmp expect actual
+'
+
+# Since the earlier tests have verified that individual merge-tree calls
+# are doing the right thing, this test case is only used to verify that
+# we can also trigger merges via --stdin, and that when we do we get
+# the same answer as running a bunch of separate merges.
+
+test_expect_success 'check the input format when --stdin is passed' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	test_commit -C repo c1 &&
+	test_commit -C repo c2 &&
+	test_commit -C repo c3 &&
+	printf "c1 c3\nc2 -- c1 c3\nc2 c3" | git -C repo merge-tree --stdin >actual &&
+
+	printf "1\0" >expect &&
+	git -C repo merge-tree --write-tree -z c1 c3 >>expect &&
+	printf "\0" >>expect &&
+
+	printf "1\0" >>expect &&
+	git -C repo merge-tree --write-tree -z --merge-base=c2 c1 c3 >>expect &&
+	printf "\0" >>expect &&
+
+	printf "1\0" >>expect &&
+	git -C repo merge-tree --write-tree -z c2 c3 >>expect &&
+	printf "\0" >>expect &&
+
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index d473048..918a2fc 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -105,6 +105,18 @@
 	'
 }
 
+check_mtime() {
+	dir=$1
+	path_in_archive=$2
+	mtime=$3
+
+	test_expect_success " validate mtime of $path_in_archive" '
+		test-tool chmtime --get $dir/$path_in_archive >actual.mtime &&
+		echo $mtime >expect.mtime &&
+		test_cmp expect.mtime actual.mtime
+	'
+}
+
 test_expect_success 'setup' '
 	test_oid_cache <<-EOF
 	obj sha1:19f9c8273ec45a8938e6999cb59b3ff66739902a
@@ -174,6 +186,13 @@
 
 check_tar b
 
+test_expect_success 'git archive --mtime' '
+	git archive --mtime=2002-02-02T02:02:02-0200 HEAD >with_mtime.tar
+'
+
+check_tar with_mtime
+check_mtime with_mtime a/a 1012622522
+
 test_expect_success 'git archive --prefix=prefix/' '
 	git archive --prefix=prefix/ HEAD >with_prefix.tar
 '
@@ -402,11 +421,11 @@
 
 test_expect_success 'archive and :(glob)' '
 	git archive -v HEAD -- ":(glob)**/sh" >/dev/null 2>actual &&
-	cat >expect <<EOF &&
-a/
-a/bin/
-a/bin/sh
-EOF
+	cat >expect <<-\EOF &&
+	a/
+	a/bin/
+	a/bin/sh
+	EOF
 	test_cmp expect actual
 '
 
diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh
index 2f6eef5..04d300e 100755
--- a/t/t5001-archive-attr.sh
+++ b/t/t5001-archive-attr.sh
@@ -3,6 +3,7 @@
 test_description='git archive attribute tests'
 
 TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 SUBSTFORMAT='%H (%h)%n'
diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh
index ae508e2..9f2c6da 100755
--- a/t/t5004-archive-corner-cases.sh
+++ b/t/t5004-archive-corner-cases.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test corner cases of git-archive'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # the 10knuls.tar file is used to test for an empty git generated tar
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index b0095ab..f89809b 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -4,6 +4,8 @@
 #
 
 test_description='pack index with 64-bit offsets and object CRC'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
@@ -263,7 +265,7 @@
 This is an invalid tag.
 EOF
 
-	tag=$(git hash-object -t tag -w --stdin <wrong-tag) &&
+	tag=$(git hash-object -t tag -w --stdin --literally <wrong-tag) &&
 	pack1=$(echo $tag $sha | git pack-objects tag-test) &&
 	echo remove tag object &&
 	thirtyeight=${tag#??} &&
diff --git a/t/t5306-pack-nobase.sh b/t/t5306-pack-nobase.sh
index 51973f4..846c5ca 100755
--- a/t/t5306-pack-nobase.sh
+++ b/t/t5306-pack-nobase.sh
@@ -6,6 +6,8 @@
 test_description='git-pack-object with missing base
 
 '
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Create A-B chain
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 6d693ee..7d8dee4 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -428,8 +428,9 @@
 			test_line_count = 2 packs &&
 			test_line_count = 2 bitmaps &&
 
-			git rev-list --use-bitmap-index HEAD 2>err &&
-			grep "ignoring extra bitmap file" err
+			GIT_TRACE2_EVENT=$(pwd)/trace2.txt git rev-list --use-bitmap-index HEAD &&
+			grep "opened bitmap" trace2.txt &&
+			grep "ignoring extra bitmap" trace2.txt
 		)
 	'
 }
diff --git a/t/t5312-prune-corruption.sh b/t/t5312-prune-corruption.sh
index 9d8e249..230cb38 100755
--- a/t/t5312-prune-corruption.sh
+++ b/t/t5312-prune-corruption.sh
@@ -14,6 +14,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'disable reflogs' '
diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh
index cc4cfaa..ceaa670 100755
--- a/t/t5313-pack-bounds-checks.sh
+++ b/t/t5313-pack-bounds-checks.sh
@@ -59,7 +59,7 @@
 test_expect_success 'set up base packfile and variables' '
 	# the hash of this content starts with ff, which
 	# makes some later computations much simpler
-	echo $(test_oid oidfff) >file &&
+	test_oid oidfff >file &&
 	git add file &&
 	git commit -m base &&
 	git repack -ad &&
diff --git a/t/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh
index bb633c9..b26d476 100755
--- a/t/t5317-pack-objects-filter-objects.sh
+++ b/t/t5317-pack-objects-filter-objects.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Test blob:none filter.
@@ -24,8 +25,9 @@
 }
 
 test_expect_success 'verify blob count in normal packfile' '
-	git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 |
-	test_parse_ls_files_stage_oids |
+	git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 \
+		>ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	git -C r1 pack-objects --revs --stdout >all.pack <<-EOF &&
@@ -123,8 +125,8 @@
 '
 
 test_expect_success 'verify blob count in normal packfile' '
-	git -C r2 ls-files -s large.1000 large.10000 |
-	test_parse_ls_files_stage_oids |
+	git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	git -C r2 pack-objects --revs --stdout >all.pack <<-EOF &&
@@ -161,8 +163,8 @@
 '
 
 test_expect_success 'verify blob:limit=1001' '
-	git -C r2 ls-files -s large.1000 |
-	test_parse_ls_files_stage_oids |
+	git -C r2 ls-files -s large.1000 >ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	git -C r2 pack-objects --revs --stdout --filter=blob:limit=1001 >filter.pack <<-EOF &&
@@ -179,8 +181,8 @@
 '
 
 test_expect_success 'verify blob:limit=10001' '
-	git -C r2 ls-files -s large.1000 large.10000 |
-	test_parse_ls_files_stage_oids |
+	git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	git -C r2 pack-objects --revs --stdout --filter=blob:limit=10001 >filter.pack <<-EOF &&
@@ -197,8 +199,8 @@
 '
 
 test_expect_success 'verify blob:limit=1k' '
-	git -C r2 ls-files -s large.1000 |
-	test_parse_ls_files_stage_oids |
+	git -C r2 ls-files -s large.1000 >ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	git -C r2 pack-objects --revs --stdout --filter=blob:limit=1k >filter.pack <<-EOF &&
@@ -215,8 +217,8 @@
 '
 
 test_expect_success 'verify explicitly specifying oversized blob in input' '
-	git -C r2 ls-files -s large.1000 large.10000 |
-	test_parse_ls_files_stage_oids |
+	git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	echo HEAD >objects &&
@@ -233,8 +235,8 @@
 '
 
 test_expect_success 'verify blob:limit=1m' '
-	git -C r2 ls-files -s large.1000 large.10000 |
-	test_parse_ls_files_stage_oids |
+	git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	git -C r2 pack-objects --revs --stdout --filter=blob:limit=1m >filter.pack <<-EOF &&
@@ -264,6 +266,44 @@
 	test_cmp expected observed
 '
 
+test_expect_success 'verify small limit and big limit results in small limit' '
+	git -C r2 ls-files -s large.1000 >ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
+	sort >expected &&
+
+	git -C r2 pack-objects --revs --stdout --filter=blob:limit=1001 \
+		--filter=blob:limit=10001 >filter.pack <<-EOF &&
+	HEAD
+	EOF
+	git -C r2 index-pack ../filter.pack &&
+
+	git -C r2 verify-pack -v ../filter.pack >verify_result &&
+	grep blob verify_result |
+	parse_verify_pack_blob_oid |
+	sort >observed &&
+
+	test_cmp expected observed
+'
+
+test_expect_success 'verify big limit and small limit results in small limit' '
+	git -C r2 ls-files -s large.1000 >ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
+	sort >expected &&
+
+	git -C r2 pack-objects --revs --stdout --filter=blob:limit=10001 \
+		--filter=blob:limit=1001 >filter.pack <<-EOF &&
+	HEAD
+	EOF
+	git -C r2 index-pack ../filter.pack &&
+
+	git -C r2 verify-pack -v ../filter.pack >verify_result &&
+	grep blob verify_result |
+	parse_verify_pack_blob_oid |
+	sort >observed &&
+
+	test_cmp expected observed
+'
+
 # Test sparse:path=<path> filter.
 # !!!!
 # NOTE: sparse:path filter support has been dropped for security reasons,
@@ -289,8 +329,9 @@
 '
 
 test_expect_success 'verify blob count in normal packfile' '
-	git -C r3 ls-files -s sparse1 sparse2 dir1/sparse1 dir1/sparse2 |
-	test_parse_ls_files_stage_oids |
+	git -C r3 ls-files -s sparse1 sparse2 dir1/sparse1 dir1/sparse2 \
+		>ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	git -C r3 pack-objects --revs --stdout >all.pack <<-EOF &&
@@ -341,8 +382,9 @@
 '
 
 test_expect_success 'verify blob count in normal packfile' '
-	git -C r4 ls-files -s pattern sparse1 sparse2 dir1/sparse1 dir1/sparse2 |
-	test_parse_ls_files_stage_oids |
+	git -C r4 ls-files -s pattern sparse1 sparse2 dir1/sparse1 dir1/sparse2 \
+		>ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	git -C r4 pack-objects --revs --stdout >all.pack <<-EOF &&
@@ -359,8 +401,8 @@
 '
 
 test_expect_success 'verify sparse:oid=OID' '
-	git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 |
-	test_parse_ls_files_stage_oids |
+	git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	git -C r4 ls-files -s pattern >staged &&
@@ -379,8 +421,8 @@
 '
 
 test_expect_success 'verify sparse:oid=oid-ish' '
-	git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 |
-	test_parse_ls_files_stage_oids |
+	git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	git -C r4 pack-objects --revs --stdout --filter=sparse:oid=main:pattern >filter.pack <<-EOF &&
@@ -400,8 +442,9 @@
 # This models previously omitted objects that we did not receive.
 
 test_expect_success 'setup r1 - delete loose blobs' '
-	git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 |
-	test_parse_ls_files_stage_oids |
+	git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 \
+		>ls_files_result &&
+	test_parse_ls_files_stage_oids <ls_files_result |
 	sort >expected &&
 
 	for id in `cat expected | sed "s|..|&/|"`
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index b5f9b10..499d5d4 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -1015,4 +1015,20 @@
 	grep "not a git repository" err
 '
 
+test_expect_success 'repack with delta islands' '
+	git init repo &&
+	test_when_finished "rm -fr repo" &&
+	(
+		cd repo &&
+
+		test_commit first &&
+		git repack &&
+		test_commit second &&
+		git repack &&
+
+		git multi-pack-index write &&
+		git -c repack.useDeltaIslands=true multi-pack-index repack
+	)
+'
+
 test_done
diff --git a/t/t5330-no-lazy-fetch-with-commit-graph.sh b/t/t5330-no-lazy-fetch-with-commit-graph.sh
index 2cc7fd7..5eb28f0 100755
--- a/t/t5330-no-lazy-fetch-with-commit-graph.sh
+++ b/t/t5330-no-lazy-fetch-with-commit-graph.sh
@@ -2,6 +2,7 @@
 
 test_description='test for no lazy fetch with the commit-graph'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup: prepare a repository with a commit' '
diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh
index 978f240..cfaae54 100755
--- a/t/t5403-post-checkout-hook.sh
+++ b/t/t5403-post-checkout-hook.sh
@@ -7,6 +7,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t5405-send-pack-rewind.sh b/t/t5405-send-pack-rewind.sh
index 11f0323..1686ac1 100755
--- a/t/t5405-send-pack-rewind.sh
+++ b/t/t5405-send-pack-rewind.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh
index dcbeb42..d6a9946 100755
--- a/t/t5406-remote-rejects.sh
+++ b/t/t5406-remote-rejects.sh
@@ -2,6 +2,7 @@
 
 test_description='remote push rejects are reported by client'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t5502-quickfetch.sh b/t/t5502-quickfetch.sh
index b160f8b..7b3ff21 100755
--- a/t/t5502-quickfetch.sh
+++ b/t/t5502-quickfetch.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh
index ac4099c..0b8ab4a 100755
--- a/t/t5504-fetch-receive-strict.sh
+++ b/t/t5504-fetch-receive-strict.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup and inject "corrupt or missing" object' '
@@ -138,7 +139,7 @@
 EOF
 
 test_expect_success 'setup bogus commit' '
-	commit="$(git hash-object -t commit -w --stdin <bogus-commit)"
+	commit="$(git hash-object --literally -t commit -w --stdin <bogus-commit)"
 '
 
 test_expect_success 'fsck with no skipList input' '
diff --git a/t/t5506-remote-groups.sh b/t/t5506-remote-groups.sh
index 5bac03e..0e17617 100755
--- a/t/t5506-remote-groups.sh
+++ b/t/t5506-remote-groups.sh
@@ -99,4 +99,13 @@
 	! repo_fetched two
 '
 
+test_expect_success 'updating group in parallel with a duplicate remote does not fail (fetch)' '
+	mark fetch-group-duplicate &&
+	update_repo one &&
+	git config --add remotes.duplicate one &&
+	git config --add remotes.duplicate one &&
+	git -c fetch.parallel=2 remote update duplicate &&
+	repo_fetched one
+'
+
 test_done
diff --git a/t/t5507-remote-environment.sh b/t/t5507-remote-environment.sh
index e614929..c6a6957 100755
--- a/t/t5507-remote-environment.sh
+++ b/t/t5507-remote-environment.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='check environment showed to remote side of transports'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'set up "remote" push situation' '
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 211afe1..854ebd3 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -806,6 +806,14 @@
 	)
 '
 
+# fetches from first configured url
+test_expect_success 'fetch from multiple configured URLs in single remote' '
+	git init url1 &&
+	git remote add multipleurls url1 &&
+	git remote set-url --add multipleurls url2 &&
+	git fetch multipleurls
+'
+
 # configured prune tests
 
 set_config_tristate () {
diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh
index 511ba3b..54f422c 100755
--- a/t/t5514-fetch-multiple.sh
+++ b/t/t5514-fetch-multiple.sh
@@ -197,4 +197,9 @@
 	test_i18ngrep "could not fetch .two.*128" err
 '
 
+test_expect_success 'git fetch --multiple --jobs=0 picks a default' '
+	(cd test &&
+	 git fetch --multiple --jobs=0)
+'
+
 test_done
diff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh
index bcff460..394bc60 100755
--- a/t/t5522-pull-symlink.sh
+++ b/t/t5522-pull-symlink.sh
@@ -2,6 +2,7 @@
 
 test_description='pulling from symlinked subdir'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # The scenario we are building:
diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh
index fdb4292..c9acc07 100755
--- a/t/t5523-push-upstream.sh
+++ b/t/t5523-push-upstream.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
diff --git a/t/t5527-fetch-odd-refs.sh b/t/t5527-fetch-odd-refs.sh
index e2770e4..98ece27 100755
--- a/t/t5527-fetch-odd-refs.sh
+++ b/t/t5527-fetch-odd-refs.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # afterwards we will have:
diff --git a/t/t5529-push-errors.sh b/t/t5529-push-errors.sh
index ce85fd3..0247137 100755
--- a/t/t5529-push-errors.sh
+++ b/t/t5529-push-errors.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='detect some push errors early (before contacting remote)'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup commits' '
diff --git a/t/t5544-pack-objects-hook.sh b/t/t5544-pack-objects-hook.sh
index 54f54f8..1a9e14b 100755
--- a/t/t5544-pack-objects-hook.sh
+++ b/t/t5544-pack-objects-hook.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test custom script in place of pack-objects'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'create some history to fetch' '
diff --git a/t/t5546-receive-limits.sh b/t/t5546-receive-limits.sh
index 0b0e987..eed3c9d 100755
--- a/t/t5546-receive-limits.sh
+++ b/t/t5546-receive-limits.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='check receive input limits'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Let's run tests with different unpack limits: 1 and 10000
diff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh
index 1876fb3..9f899b8 100755
--- a/t/t5547-push-quarantine.sh
+++ b/t/t5547-push-quarantine.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='check quarantine of objects during push'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'create picky dest repo' '
diff --git a/t/t5554-noop-fetch-negotiator.sh b/t/t5554-noop-fetch-negotiator.sh
index 2ac7b58..06991e8 100755
--- a/t/t5554-noop-fetch-negotiator.sh
+++ b/t/t5554-noop-fetch-negotiator.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test noop fetch negotiator'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'noop negotiator does not emit any "have"' '
diff --git a/t/t5558-clone-bundle-uri.sh b/t/t5558-clone-bundle-uri.sh
index 9155f31..afd5692 100755
--- a/t/t5558-clone-bundle-uri.sh
+++ b/t/t5558-clone-bundle-uri.sh
@@ -285,6 +285,8 @@
 '
 
 test_expect_success 'clone bundle list (HTTP, no heuristic)' '
+	test_when_finished rm -f trace*.txt &&
+
 	cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" &&
 	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
 	[bundle]
@@ -304,12 +306,26 @@
 		uri = $HTTPD_URL/bundle-4.bundle
 	EOF
 
-	git clone --bundle-uri="$HTTPD_URL/bundle-list" \
+	GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" \
+		git clone --bundle-uri="$HTTPD_URL/bundle-list" \
 		clone-from clone-list-http  2>err &&
 	! grep "Repository lacks these prerequisite commits" err &&
 
 	git -C clone-from for-each-ref --format="%(objectname)" >oids &&
-	git -C clone-list-http cat-file --batch-check <oids
+	git -C clone-list-http cat-file --batch-check <oids &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-1.bundle
+	$HTTPD_URL/bundle-2.bundle
+	$HTTPD_URL/bundle-3.bundle
+	$HTTPD_URL/bundle-4.bundle
+	$HTTPD_URL/bundle-list
+	EOF
+
+	# Sort the list, since the order is not well-defined
+	# without a heuristic.
+	test_remote_https_urls <trace-clone.txt | sort >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'clone bundle list (HTTP, any mode)' '
@@ -350,6 +366,658 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'clone bundle list (http, creationToken)' '
+	test_when_finished rm -f trace*.txt &&
+
+	cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" &&
+	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "bundle-1"]
+		uri = bundle-1.bundle
+		creationToken = 1
+
+	[bundle "bundle-2"]
+		uri = bundle-2.bundle
+		creationToken = 2
+
+	[bundle "bundle-3"]
+		uri = bundle-3.bundle
+		creationToken = 3
+
+	[bundle "bundle-4"]
+		uri = bundle-4.bundle
+		creationToken = 4
+	EOF
+
+	GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" git \
+		clone --bundle-uri="$HTTPD_URL/bundle-list" \
+		"$HTTPD_URL/smart/fetch.git" clone-list-http-2 &&
+
+	git -C clone-from for-each-ref --format="%(objectname)" >oids &&
+	git -C clone-list-http-2 cat-file --batch-check <oids &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/bundle-4.bundle
+	$HTTPD_URL/bundle-3.bundle
+	$HTTPD_URL/bundle-2.bundle
+	$HTTPD_URL/bundle-1.bundle
+	EOF
+
+	test_remote_https_urls <trace-clone.txt >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'clone incomplete bundle list (http, creationToken)' '
+	test_when_finished rm -f trace*.txt &&
+
+	cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" &&
+	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "bundle-1"]
+		uri = bundle-1.bundle
+		creationToken = 1
+	EOF
+
+	GIT_TRACE2_EVENT=$(pwd)/trace-clone.txt \
+	git clone --bundle-uri="$HTTPD_URL/bundle-list" \
+		--single-branch --branch=base --no-tags \
+		"$HTTPD_URL/smart/fetch.git" clone-token-http &&
+
+	test_cmp_config -C clone-token-http "$HTTPD_URL/bundle-list" fetch.bundleuri &&
+	test_cmp_config -C clone-token-http 1 fetch.bundlecreationtoken &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/bundle-1.bundle
+	EOF
+
+	test_remote_https_urls <trace-clone.txt >actual &&
+	test_cmp expect actual &&
+
+	# We now have only one bundle ref.
+	git -C clone-token-http for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+	cat >expect <<-\EOF &&
+	refs/bundles/base
+	EOF
+	test_cmp expect refs &&
+
+	# Add remaining bundles, exercising the "deepening" strategy
+	# for downloading via the creationToken heurisitc.
+	cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle "bundle-2"]
+		uri = bundle-2.bundle
+		creationToken = 2
+
+	[bundle "bundle-3"]
+		uri = bundle-3.bundle
+		creationToken = 3
+
+	[bundle "bundle-4"]
+		uri = bundle-4.bundle
+		creationToken = 4
+	EOF
+
+	GIT_TRACE2_EVENT="$(pwd)/trace1.txt" \
+		git -C clone-token-http fetch origin --no-tags \
+		refs/heads/merge:refs/heads/merge &&
+	test_cmp_config -C clone-token-http 4 fetch.bundlecreationtoken &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/bundle-4.bundle
+	$HTTPD_URL/bundle-3.bundle
+	$HTTPD_URL/bundle-2.bundle
+	EOF
+
+	test_remote_https_urls <trace1.txt >actual &&
+	test_cmp expect actual &&
+
+	# We now have all bundle refs.
+	git -C clone-token-http for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+
+	cat >expect <<-\EOF &&
+	refs/bundles/base
+	refs/bundles/left
+	refs/bundles/merge
+	refs/bundles/right
+	EOF
+	test_cmp expect refs
+'
+
+test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' '
+	test_when_finished rm -rf fetch-http-4 trace*.txt &&
+
+	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "bundle-1"]
+		uri = bundle-1.bundle
+		creationToken = 1
+	EOF
+
+	GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" \
+	git clone --single-branch --branch=base \
+		--bundle-uri="$HTTPD_URL/bundle-list" \
+		"$HTTPD_URL/smart/fetch.git" fetch-http-4 &&
+
+	test_cmp_config -C fetch-http-4 "$HTTPD_URL/bundle-list" fetch.bundleuri &&
+	test_cmp_config -C fetch-http-4 1 fetch.bundlecreationtoken &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/bundle-1.bundle
+	EOF
+
+	test_remote_https_urls <trace-clone.txt >actual &&
+	test_cmp expect actual &&
+
+	# only received base ref from bundle-1
+	git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+	cat >expect <<-\EOF &&
+	refs/bundles/base
+	EOF
+	test_cmp expect refs &&
+
+	cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle "bundle-2"]
+		uri = bundle-2.bundle
+		creationToken = 2
+	EOF
+
+	# Fetch the objects for bundle-2 _and_ bundle-3.
+	GIT_TRACE2_EVENT="$(pwd)/trace1.txt" \
+		git -C fetch-http-4 fetch origin --no-tags \
+		refs/heads/left:refs/heads/left \
+		refs/heads/right:refs/heads/right &&
+	test_cmp_config -C fetch-http-4 2 fetch.bundlecreationtoken &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/bundle-2.bundle
+	EOF
+
+	test_remote_https_urls <trace1.txt >actual &&
+	test_cmp expect actual &&
+
+	# received left from bundle-2
+	git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+	cat >expect <<-\EOF &&
+	refs/bundles/base
+	refs/bundles/left
+	EOF
+	test_cmp expect refs &&
+
+	# No-op fetch
+	GIT_TRACE2_EVENT="$(pwd)/trace1b.txt" \
+		git -C fetch-http-4 fetch origin --no-tags \
+		refs/heads/left:refs/heads/left \
+		refs/heads/right:refs/heads/right &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	EOF
+	test_remote_https_urls <trace1b.txt >actual &&
+	test_cmp expect actual &&
+
+	cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle "bundle-3"]
+		uri = bundle-3.bundle
+		creationToken = 3
+
+	[bundle "bundle-4"]
+		uri = bundle-4.bundle
+		creationToken = 4
+	EOF
+
+	# This fetch should skip bundle-3.bundle, since its objects are
+	# already local (we have the requisite commits for bundle-4.bundle).
+	GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+		git -C fetch-http-4 fetch origin --no-tags \
+		refs/heads/merge:refs/heads/merge &&
+	test_cmp_config -C fetch-http-4 4 fetch.bundlecreationtoken &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/bundle-4.bundle
+	EOF
+
+	test_remote_https_urls <trace2.txt >actual &&
+	test_cmp expect actual &&
+
+	# received merge ref from bundle-4, but right is missing
+	# because we did not download bundle-3.
+	git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+
+	cat >expect <<-\EOF &&
+	refs/bundles/base
+	refs/bundles/left
+	refs/bundles/merge
+	EOF
+	test_cmp expect refs &&
+
+	# No-op fetch
+	GIT_TRACE2_EVENT="$(pwd)/trace2b.txt" \
+		git -C fetch-http-4 fetch origin &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	EOF
+	test_remote_https_urls <trace2b.txt >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'creationToken heuristic with failed downloads (clone)' '
+	test_when_finished rm -rf download-* trace*.txt &&
+
+	# Case 1: base bundle does not exist, nothing can unbundle
+	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "bundle-1"]
+		uri = fake.bundle
+		creationToken = 1
+
+	[bundle "bundle-2"]
+		uri = bundle-2.bundle
+		creationToken = 2
+
+	[bundle "bundle-3"]
+		uri = bundle-3.bundle
+		creationToken = 3
+
+	[bundle "bundle-4"]
+		uri = bundle-4.bundle
+		creationToken = 4
+	EOF
+
+	GIT_TRACE2_EVENT="$(pwd)/trace-clone-1.txt" \
+	git clone --single-branch --branch=base \
+		--bundle-uri="$HTTPD_URL/bundle-list" \
+		"$HTTPD_URL/smart/fetch.git" download-1 &&
+
+	# Bundle failure does not set these configs.
+	test_must_fail git -C download-1 config fetch.bundleuri &&
+	test_must_fail git -C download-1 config fetch.bundlecreationtoken &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/bundle-4.bundle
+	$HTTPD_URL/bundle-3.bundle
+	$HTTPD_URL/bundle-2.bundle
+	$HTTPD_URL/fake.bundle
+	EOF
+	test_remote_https_urls <trace-clone-1.txt >actual &&
+	test_cmp expect actual &&
+
+	# All bundles failed to unbundle
+	git -C download-1 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+	test_must_be_empty refs &&
+
+	# Case 2: middle bundle does not exist, only two bundles can unbundle
+	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "bundle-1"]
+		uri = bundle-1.bundle
+		creationToken = 1
+
+	[bundle "bundle-2"]
+		uri = fake.bundle
+		creationToken = 2
+
+	[bundle "bundle-3"]
+		uri = bundle-3.bundle
+		creationToken = 3
+
+	[bundle "bundle-4"]
+		uri = bundle-4.bundle
+		creationToken = 4
+	EOF
+
+	GIT_TRACE2_EVENT="$(pwd)/trace-clone-2.txt" \
+	git clone --single-branch --branch=base \
+		--bundle-uri="$HTTPD_URL/bundle-list" \
+		"$HTTPD_URL/smart/fetch.git" download-2 &&
+
+	# Bundle failure does not set these configs.
+	test_must_fail git -C download-2 config fetch.bundleuri &&
+	test_must_fail git -C download-2 config fetch.bundlecreationtoken &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/bundle-4.bundle
+	$HTTPD_URL/bundle-3.bundle
+	$HTTPD_URL/fake.bundle
+	$HTTPD_URL/bundle-1.bundle
+	EOF
+	test_remote_https_urls <trace-clone-2.txt >actual &&
+	test_cmp expect actual &&
+
+	# bundle-1 and bundle-3 could unbundle, but bundle-4 could not
+	git -C download-2 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+	cat >expect <<-EOF &&
+	refs/bundles/base
+	refs/bundles/right
+	EOF
+	test_cmp expect refs &&
+
+	# Case 3: top bundle does not exist, rest unbundle fine.
+	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "bundle-1"]
+		uri = bundle-1.bundle
+		creationToken = 1
+
+	[bundle "bundle-2"]
+		uri = bundle-2.bundle
+		creationToken = 2
+
+	[bundle "bundle-3"]
+		uri = bundle-3.bundle
+		creationToken = 3
+
+	[bundle "bundle-4"]
+		uri = fake.bundle
+		creationToken = 4
+	EOF
+
+	GIT_TRACE2_EVENT="$(pwd)/trace-clone-3.txt" \
+	git clone --single-branch --branch=base \
+		--bundle-uri="$HTTPD_URL/bundle-list" \
+		"$HTTPD_URL/smart/fetch.git" download-3 &&
+
+	# As long as we have continguous successful downloads,
+	# we _do_ set these configs.
+	test_cmp_config -C download-3 "$HTTPD_URL/bundle-list" fetch.bundleuri &&
+	test_cmp_config -C download-3 3 fetch.bundlecreationtoken &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/fake.bundle
+	$HTTPD_URL/bundle-3.bundle
+	$HTTPD_URL/bundle-2.bundle
+	$HTTPD_URL/bundle-1.bundle
+	EOF
+	test_remote_https_urls <trace-clone-3.txt >actual &&
+	test_cmp expect actual &&
+
+	# fake.bundle did not unbundle, but the others did.
+	git -C download-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+	cat >expect <<-EOF &&
+	refs/bundles/base
+	refs/bundles/left
+	refs/bundles/right
+	EOF
+	test_cmp expect refs
+'
+
+# Expand the bundle list to include other interesting shapes, specifically
+# interesting for use when fetching from a previous state.
+#
+# ---------------- bundle-7
+#       7
+#     _/|\_
+# ---/--|--\------ bundle-6
+#   5   |   6
+# --|---|---|----- bundle-4
+#   |   4   |
+#   |  / \  /
+# --|-|---|/------ bundle-3 (the client will be caught up to this point.)
+#   \ |   3
+# ---\|---|------- bundle-2
+#     2   |
+# ----|---|------- bundle-1
+#      \ /
+#       1
+#       |
+# (previous commits)
+test_expect_success 'expand incremental bundle list' '
+	(
+		cd clone-from &&
+		git checkout -b lefter left &&
+		test_commit 5 &&
+		git checkout -b righter right &&
+		test_commit 6 &&
+		git checkout -b top lefter &&
+		git merge -m "7" merge righter &&
+
+		git bundle create bundle-6.bundle lefter righter --not left right &&
+		git bundle create bundle-7.bundle top --not lefter merge righter &&
+
+		cp bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/"
+	) &&
+	git -C "$HTTPD_DOCUMENT_ROOT_PATH/fetch.git" fetch origin +refs/heads/*:refs/heads/*
+'
+
+test_expect_success 'creationToken heuristic with failed downloads (fetch)' '
+	test_when_finished rm -rf download-* trace*.txt &&
+
+	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "bundle-1"]
+		uri = bundle-1.bundle
+		creationToken = 1
+
+	[bundle "bundle-2"]
+		uri = bundle-2.bundle
+		creationToken = 2
+
+	[bundle "bundle-3"]
+		uri = bundle-3.bundle
+		creationToken = 3
+	EOF
+
+	git clone --single-branch --branch=left \
+		--bundle-uri="$HTTPD_URL/bundle-list" \
+		"$HTTPD_URL/smart/fetch.git" fetch-base &&
+	test_cmp_config -C fetch-base "$HTTPD_URL/bundle-list" fetch.bundleURI &&
+	test_cmp_config -C fetch-base 3 fetch.bundleCreationToken &&
+
+	# Case 1: all bundles exist: successful unbundling of all bundles
+	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "bundle-1"]
+		uri = bundle-1.bundle
+		creationToken = 1
+
+	[bundle "bundle-2"]
+		uri = bundle-2.bundle
+		creationToken = 2
+
+	[bundle "bundle-3"]
+		uri = bundle-3.bundle
+		creationToken = 3
+
+	[bundle "bundle-4"]
+		uri = bundle-4.bundle
+		creationToken = 4
+
+	[bundle "bundle-6"]
+		uri = bundle-6.bundle
+		creationToken = 6
+
+	[bundle "bundle-7"]
+		uri = bundle-7.bundle
+		creationToken = 7
+	EOF
+
+	cp -r fetch-base fetch-1 &&
+	GIT_TRACE2_EVENT="$(pwd)/trace-fetch-1.txt" \
+		git -C fetch-1 fetch origin &&
+	test_cmp_config -C fetch-1 7 fetch.bundlecreationtoken &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/bundle-7.bundle
+	$HTTPD_URL/bundle-6.bundle
+	$HTTPD_URL/bundle-4.bundle
+	EOF
+	test_remote_https_urls <trace-fetch-1.txt >actual &&
+	test_cmp expect actual &&
+
+	# Check which bundles have unbundled by refs
+	git -C fetch-1 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+	cat >expect <<-EOF &&
+	refs/bundles/base
+	refs/bundles/left
+	refs/bundles/lefter
+	refs/bundles/merge
+	refs/bundles/right
+	refs/bundles/righter
+	refs/bundles/top
+	EOF
+	test_cmp expect refs &&
+
+	# Case 2: middle bundle does not exist, only bundle-4 can unbundle
+	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "bundle-1"]
+		uri = bundle-1.bundle
+		creationToken = 1
+
+	[bundle "bundle-2"]
+		uri = bundle-2.bundle
+		creationToken = 2
+
+	[bundle "bundle-3"]
+		uri = bundle-3.bundle
+		creationToken = 3
+
+	[bundle "bundle-4"]
+		uri = bundle-4.bundle
+		creationToken = 4
+
+	[bundle "bundle-6"]
+		uri = fake.bundle
+		creationToken = 6
+
+	[bundle "bundle-7"]
+		uri = bundle-7.bundle
+		creationToken = 7
+	EOF
+
+	cp -r fetch-base fetch-2 &&
+	GIT_TRACE2_EVENT="$(pwd)/trace-fetch-2.txt" \
+		git -C fetch-2 fetch origin &&
+
+	# Since bundle-7 fails to unbundle, do not update creation token.
+	test_cmp_config -C fetch-2 3 fetch.bundlecreationtoken &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/bundle-7.bundle
+	$HTTPD_URL/fake.bundle
+	$HTTPD_URL/bundle-4.bundle
+	EOF
+	test_remote_https_urls <trace-fetch-2.txt >actual &&
+	test_cmp expect actual &&
+
+	# Check which bundles have unbundled by refs
+	git -C fetch-2 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+	cat >expect <<-EOF &&
+	refs/bundles/base
+	refs/bundles/left
+	refs/bundles/merge
+	refs/bundles/right
+	EOF
+	test_cmp expect refs &&
+
+	# Case 3: top bundle does not exist, rest unbundle fine.
+	cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "bundle-1"]
+		uri = bundle-1.bundle
+		creationToken = 1
+
+	[bundle "bundle-2"]
+		uri = bundle-2.bundle
+		creationToken = 2
+
+	[bundle "bundle-3"]
+		uri = bundle-3.bundle
+		creationToken = 3
+
+	[bundle "bundle-4"]
+		uri = bundle-4.bundle
+		creationToken = 4
+
+	[bundle "bundle-6"]
+		uri = bundle-6.bundle
+		creationToken = 6
+
+	[bundle "bundle-7"]
+		uri = fake.bundle
+		creationToken = 7
+	EOF
+
+	cp -r fetch-base fetch-3 &&
+	GIT_TRACE2_EVENT="$(pwd)/trace-fetch-3.txt" \
+		git -C fetch-3 fetch origin &&
+
+	# As long as we have continguous successful downloads,
+	# we _do_ set the maximum creation token.
+	test_cmp_config -C fetch-3 6 fetch.bundlecreationtoken &&
+
+	# NOTE: the fetch skips bundle-4 since bundle-6 successfully
+	# unbundles itself and bundle-7 failed to download.
+	cat >expect <<-EOF &&
+	$HTTPD_URL/bundle-list
+	$HTTPD_URL/fake.bundle
+	$HTTPD_URL/bundle-6.bundle
+	EOF
+	test_remote_https_urls <trace-fetch-3.txt >actual &&
+	test_cmp expect actual &&
+
+	# Check which bundles have unbundled by refs
+	git -C fetch-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs &&
+	cat >expect <<-EOF &&
+	refs/bundles/base
+	refs/bundles/left
+	refs/bundles/lefter
+	refs/bundles/right
+	refs/bundles/righter
+	EOF
+	test_cmp expect refs
+'
+
 # Do not add tests here unless they use the HTTP server, as they will
 # not run unless the HTTP dependencies exist.
 
diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh
index d30cf4f..f75068d 100755
--- a/t/t5560-http-backend-noserver.sh
+++ b/t/t5560-http-backend-noserver.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY"
diff --git a/t/t5561-http-backend.sh b/t/t5561-http-backend.sh
index 9c57d84..e1d3b8c 100755
--- a/t/t5561-http-backend.sh
+++ b/t/t5561-http-backend.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-httpd.sh
 
diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh
index b68ec22..7ee9858 100755
--- a/t/t5562-http-backend-content-length.sh
+++ b/t/t5562-http-backend-content-length.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test git-http-backend respects CONTENT_LENGTH'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_lazy_prereq GZIP 'gzip --version'
diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh
new file mode 100755
index 0000000..9da5134
--- /dev/null
+++ b/t/t5564-http-proxy.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+test_description="test fetching through http proxy"
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+
+LIB_HTTPD_PROXY=1
+start_httpd
+
+test_expect_success 'setup repository' '
+	test_commit foo &&
+	git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+	git push --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git"
+'
+
+setup_askpass_helper
+
+# sanity check that our test setup is correctly using proxy
+test_expect_success 'proxy requires password' '
+	test_config_global http.proxy $HTTPD_DEST &&
+	test_must_fail git clone $HTTPD_URL/smart/repo.git 2>err &&
+	grep "error.*407" err
+'
+
+test_expect_success 'clone through proxy with auth' '
+	test_when_finished "rm -rf clone" &&
+	test_config_global http.proxy http://proxuser:proxpass@$HTTPD_DEST &&
+	GIT_TRACE_CURL=$PWD/trace git clone $HTTPD_URL/smart/repo.git clone &&
+	grep -i "Proxy-Authorization: Basic <redacted>" trace
+'
+
+test_expect_success 'clone can prompt for proxy password' '
+	test_when_finished "rm -rf clone" &&
+	test_config_global http.proxy http://proxuser@$HTTPD_DEST &&
+	set_askpass nobody proxpass &&
+	GIT_TRACE_CURL=$PWD/trace git clone $HTTPD_URL/smart/repo.git clone &&
+	expect_askpass pass proxuser
+'
+
+test_done
diff --git a/t/t5573-pull-verify-signatures.sh b/t/t5573-pull-verify-signatures.sh
index a53dd85..1221ac0 100755
--- a/t/t5573-pull-verify-signatures.sh
+++ b/t/t5573-pull-verify-signatures.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='pull signature verification tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-gpg.sh"
 
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index fd02984..17c287d 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -787,6 +787,111 @@
 	git clone --no-reject-shallow $HTTPD_URL/smart/repo.git repo
 '
 
+test_expect_success 'auto-discover bundle URI from HTTP clone' '
+	test_when_finished rm -rf trace.txt repo2 "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" &&
+	git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/everything.bundle" --all &&
+	git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" &&
+
+	git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+		uploadpack.advertiseBundleURIs true &&
+	git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+		bundle.version 1 &&
+	git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+		bundle.mode all &&
+	git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+		bundle.everything.uri "$HTTPD_URL/everything.bundle" &&
+
+	GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+		git -c protocol.version=2 \
+		    -c transfer.bundleURI=true clone \
+		$HTTPD_URL/smart/repo2.git repo2 &&
+	cat >pattern <<-EOF &&
+	"event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\]
+	EOF
+	grep -f pattern trace.txt
+'
+
+test_expect_success 'auto-discover multiple bundles from HTTP clone' '
+	test_when_finished rm -rf trace.txt repo3 "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" &&
+
+	test_commit -C src new &&
+	git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/new.bundle" HEAD~1..HEAD &&
+	git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" &&
+
+	git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+		uploadpack.advertiseBundleURIs true &&
+	git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+		bundle.version 1 &&
+	git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+		bundle.mode all &&
+
+	git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+		bundle.everything.uri "$HTTPD_URL/everything.bundle" &&
+	git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+		bundle.new.uri "$HTTPD_URL/new.bundle" &&
+
+	GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+		git -c protocol.version=2 \
+		    -c transfer.bundleURI=true clone \
+		$HTTPD_URL/smart/repo3.git repo3 &&
+
+	# We should fetch _both_ bundles
+	cat >pattern <<-EOF &&
+	"event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\]
+	EOF
+	grep -f pattern trace.txt &&
+	cat >pattern <<-EOF &&
+	"event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/new.bundle"\]
+	EOF
+	grep -f pattern trace.txt
+'
+
+test_expect_success 'auto-discover multiple bundles from HTTP clone: creationToken heuristic' '
+	test_when_finished rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/repo4.git" &&
+	test_when_finished rm -rf clone-heuristic trace*.txt &&
+
+	test_commit -C src newest &&
+	git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/newest.bundle" HEAD~1..HEAD &&
+	git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo4.git" &&
+
+	cat >>"$HTTPD_DOCUMENT_ROOT_PATH/repo4.git/config" <<-EOF &&
+	[uploadPack]
+		advertiseBundleURIs = true
+
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+
+	[bundle "everything"]
+		uri = $HTTPD_URL/everything.bundle
+		creationtoken = 1
+
+	[bundle "new"]
+		uri = $HTTPD_URL/new.bundle
+		creationtoken = 2
+
+	[bundle "newest"]
+		uri = $HTTPD_URL/newest.bundle
+		creationtoken = 3
+	EOF
+
+	GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" \
+		git -c protocol.version=2 \
+		    -c transfer.bundleURI=true clone \
+		"$HTTPD_URL/smart/repo4.git" clone-heuristic &&
+
+	cat >expect <<-EOF &&
+	$HTTPD_URL/newest.bundle
+	$HTTPD_URL/new.bundle
+	$HTTPD_URL/everything.bundle
+	EOF
+
+	# We should fetch all bundles in the expected order.
+	test_remote_https_urls <trace-clone.txt >actual &&
+	test_cmp expect actual
+'
+
 # DO NOT add non-httpd-specific tests here, because the last part of this
 # test script is only executed when httpd is available and enabled.
 
diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh
index 7ccebb4..83e3c97 100755
--- a/t/t5604-clone-reference.sh
+++ b/t/t5604-clone-reference.sh
@@ -7,6 +7,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 base_dir=$(pwd)
diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh
index cf221e9..27f9f77 100755
--- a/t/t5606-clone-options.sh
+++ b/t/t5606-clone-options.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t5610-clone-detached.sh b/t/t5610-clone-detached.sh
index a7ec21e..022ed3d 100755
--- a/t/t5610-clone-detached.sh
+++ b/t/t5610-clone-detached.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 head_is_detached() {
diff --git a/t/t5611-clone-config.sh b/t/t5611-clone-config.sh
index 4b38772..727caff 100755
--- a/t/t5611-clone-config.sh
+++ b/t/t5611-clone-config.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'clone -c sets config in cloned repo' '
diff --git a/t/t5613-info-alternate.sh b/t/t5613-info-alternate.sh
index 895f46b..7708cba 100755
--- a/t/t5613-info-alternate.sh
+++ b/t/t5613-info-alternate.sh
@@ -4,6 +4,8 @@
 #
 
 test_description='test transitive info/alternate entries'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'preparing first repository' '
diff --git a/t/t5614-clone-submodules-shallow.sh b/t/t5614-clone-submodules-shallow.sh
index 0c85ef8..c2a2bb4 100755
--- a/t/t5614-clone-submodules-shallow.sh
+++ b/t/t5614-clone-submodules-shallow.sh
@@ -2,6 +2,7 @@
 
 test_description='Test shallow cloning of repos with submodules'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 pwd=$(pwd)
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 037941b..f519d2a 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -644,6 +644,49 @@
 	grep "loosen_unused_packed_objects/loosened:0" trace
 '
 
+test_expect_success 'lazy-fetch in submodule succeeds' '
+	# setup
+	test_config_global protocol.file.allow always &&
+
+	test_when_finished "rm -rf src-sub" &&
+	git init src-sub &&
+	git -C src-sub config uploadpack.allowfilter 1 &&
+	git -C src-sub config uploadpack.allowanysha1inwant 1 &&
+
+	# This blob must be missing in the subsequent commit.
+	echo foo >src-sub/file &&
+	git -C src-sub add file &&
+	git -C src-sub commit -m "submodule one" &&
+	SUB_ONE=$(git -C src-sub rev-parse HEAD) &&
+
+	echo bar >src-sub/file &&
+	git -C src-sub add file &&
+	git -C src-sub commit -m "submodule two" &&
+	SUB_TWO=$(git -C src-sub rev-parse HEAD) &&
+
+	test_when_finished "rm -rf src-super" &&
+	git init src-super &&
+	git -C src-super config uploadpack.allowfilter 1 &&
+	git -C src-super config uploadpack.allowanysha1inwant 1 &&
+	git -C src-super submodule add ../src-sub src-sub &&
+
+	git -C src-super/src-sub checkout $SUB_ONE &&
+	git -C src-super add src-sub &&
+	git -C src-super commit -m "superproject one" &&
+
+	git -C src-super/src-sub checkout $SUB_TWO &&
+	git -C src-super add src-sub &&
+	git -C src-super commit -m "superproject two" &&
+
+	# the fetch
+	test_when_finished "rm -rf client" &&
+	git clone --filter=blob:none --also-filter-submodules \
+		--recurse-submodules "file://$(pwd)/src-super" client &&
+
+	# Trigger lazy-fetch from the superproject
+	git -C client restore --recurse-submodules --source=HEAD^ :/
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
diff --git a/t/t5617-clone-submodules-remote.sh b/t/t5617-clone-submodules-remote.sh
index 6884338..5a4d793 100755
--- a/t/t5617-clone-submodules-remote.sh
+++ b/t/t5617-clone-submodules-remote.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 pwd=$(pwd)
diff --git a/t/t5618-alternate-refs.sh b/t/t5618-alternate-refs.sh
index 3353216..f905db0 100755
--- a/t/t5618-alternate-refs.sh
+++ b/t/t5618-alternate-refs.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test handling of --alternate-refs traversal'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Avoid test_commit because we want a specific and known set of refs:
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 1896f67..f21e5e9 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -13,7 +13,7 @@
 	wrong_algo sha1:sha256
 	wrong_algo sha256:sha1
 	EOF
-	cat >expect <<-EOF &&
+	cat >expect.base <<-EOF &&
 	version 2
 	agent=git/$(git version | cut -d" " -f3)
 	ls-refs=unborn
@@ -21,8 +21,11 @@
 	server-option
 	object-format=$(test_oid algo)
 	object-info
+	EOF
+	cat >expect.trailer <<-EOF &&
 	0000
 	EOF
+	cat expect.base expect.trailer >expect &&
 
 	GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
 		--advertise-capabilities >out &&
@@ -342,4 +345,39 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'test capability advertisement with uploadpack.advertiseBundleURIs' '
+	test_config uploadpack.advertiseBundleURIs true &&
+
+	cat >expect.extra <<-EOF &&
+	bundle-uri
+	EOF
+	cat expect.base \
+	    expect.extra \
+	    expect.trailer >expect &&
+
+	GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
+		--advertise-capabilities >out &&
+	test-tool pkt-line unpack <out >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'basics of bundle-uri: dies if not enabled' '
+	test-tool pkt-line pack >in <<-EOF &&
+	command=bundle-uri
+	0000
+	EOF
+
+	cat >err.expect <<-\EOF &&
+	fatal: invalid command '"'"'bundle-uri'"'"'
+	EOF
+
+	cat >expect <<-\EOF &&
+	ERR serve: invalid command '"'"'bundle-uri'"'"'
+	EOF
+
+	test_must_fail test-tool serve-v2 --stateless-rpc <in >out 2>err.actual &&
+	test_cmp err.expect err.actual &&
+	test_must_be_empty out
+'
+
 test_done
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index b33cd4a..e4db751 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -1114,7 +1114,7 @@
 
 	This commit object intentionally broken
 	EOF
-	BOGUS=$(git -C "$P" hash-object -t commit -w --stdin <bogus-commit) &&
+	BOGUS=$(git -C "$P" hash-object -t commit -w --stdin --literally <bogus-commit) &&
 	git -C "$P" branch bogus-branch "$BOGUS" &&
 
 	echo my-blob >"$P/my-blob" &&
diff --git a/t/t5705-session-id-in-capabilities.sh b/t/t5705-session-id-in-capabilities.sh
index ed38c76..b8a722e 100755
--- a/t/t5705-session-id-in-capabilities.sh
+++ b/t/t5705-session-id-in-capabilities.sh
@@ -2,6 +2,7 @@
 
 test_description='session ID in capabilities'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 REPO="$(pwd)/repo"
diff --git a/t/t5730-protocol-v2-bundle-uri-file.sh b/t/t5730-protocol-v2-bundle-uri-file.sh
new file mode 100755
index 0000000..37bdb72
--- /dev/null
+++ b/t/t5730-protocol-v2-bundle-uri-file.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description="Test bundle-uri with protocol v2 and 'file://' transport"
+
+TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# Test protocol v2 with 'file://' transport
+#
+BUNDLE_URI_PROTOCOL=file
+. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh
+
+test_done
diff --git a/t/t5731-protocol-v2-bundle-uri-git.sh b/t/t5731-protocol-v2-bundle-uri-git.sh
new file mode 100755
index 0000000..8add1b3
--- /dev/null
+++ b/t/t5731-protocol-v2-bundle-uri-git.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description="Test bundle-uri with protocol v2 and 'git://' transport"
+
+TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# Test protocol v2 with 'git://' transport
+#
+BUNDLE_URI_PROTOCOL=git
+. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh
+
+test_done
diff --git a/t/t5732-protocol-v2-bundle-uri-http.sh b/t/t5732-protocol-v2-bundle-uri-http.sh
new file mode 100755
index 0000000..129daa0
--- /dev/null
+++ b/t/t5732-protocol-v2-bundle-uri-http.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description="Test bundle-uri with protocol v2 and 'http://' transport"
+
+TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# Test protocol v2 with 'http://' transport
+#
+BUNDLE_URI_PROTOCOL=http
+. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh
+
+test_done
diff --git a/t/t5750-bundle-uri-parse.sh b/t/t5750-bundle-uri-parse.sh
index c2fe3f9..81bdf58 100755
--- a/t/t5750-bundle-uri-parse.sh
+++ b/t/t5750-bundle-uri-parse.sh
@@ -30,6 +30,58 @@
 	test_cmp_config_output expect actual
 '
 
+test_expect_success 'bundle_uri_parse_line(): relative URIs' '
+	cat >in <<-\EOF &&
+	bundle.one.uri=bundle.bdl
+	bundle.two.uri=../bundle.bdl
+	bundle.three.uri=sub/dir/bundle.bdl
+	EOF
+
+	cat >expect <<-\EOF &&
+	[bundle]
+		version = 1
+		mode = all
+	[bundle "one"]
+		uri = <uri>/bundle.bdl
+	[bundle "two"]
+		uri = bundle.bdl
+	[bundle "three"]
+		uri = <uri>/sub/dir/bundle.bdl
+	EOF
+
+	test-tool bundle-uri parse-key-values in >actual 2>err &&
+	test_must_be_empty err &&
+	test_cmp_config_output expect actual
+'
+
+test_expect_success 'bundle_uri_parse_line(): relative URIs and parent paths' '
+	cat >in <<-\EOF &&
+	bundle.one.uri=bundle.bdl
+	bundle.two.uri=../bundle.bdl
+	bundle.three.uri=../../bundle.bdl
+	EOF
+
+	cat >expect <<-\EOF &&
+	[bundle]
+		version = 1
+		mode = all
+	[bundle "one"]
+		uri = <uri>/bundle.bdl
+	[bundle "two"]
+		uri = bundle.bdl
+	[bundle "three"]
+		uri = <uri>/../bundle.bdl
+	EOF
+
+	# TODO: We would prefer if parsing a bundle list would not cause
+	# a die() and instead would give a warning and allow the rest of
+	# a Git command to continue. This test_must_fail is necessary for
+	# now until the interface for relative_url() allows for reporting
+	# an error instead of die()ing.
+	test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err &&
+	grep "fatal: cannot strip one component off url" err
+'
+
 test_expect_success 'bundle_uri_parse_line() parsing edge cases: empty key or value' '
 	cat >in <<-\EOF &&
 	=bogus-value
@@ -136,6 +188,36 @@
 	test_cmp_config_output expect actual
 '
 
+test_expect_success 'parse config format: relative URIs' '
+	cat >in <<-\EOF &&
+	[bundle]
+		version = 1
+		mode = all
+	[bundle "one"]
+		uri = bundle.bdl
+	[bundle "two"]
+		uri = ../bundle.bdl
+	[bundle "three"]
+		uri = sub/dir/bundle.bdl
+	EOF
+
+	cat >expect <<-\EOF &&
+	[bundle]
+		version = 1
+		mode = all
+	[bundle "one"]
+		uri = <uri>/bundle.bdl
+	[bundle "two"]
+		uri = bundle.bdl
+	[bundle "three"]
+		uri = <uri>/sub/dir/bundle.bdl
+	EOF
+
+	test-tool bundle-uri parse-config in >actual 2>err &&
+	test_must_be_empty err &&
+	test_cmp_config_output expect actual
+'
+
 test_expect_success 'parse config format edge cases: empty key or value' '
 	cat >in1 <<-\EOF &&
 	= bogus-value
@@ -168,4 +250,41 @@
 	test_cmp_config_output expect actual
 '
 
+test_expect_success 'parse config format: creationToken heuristic' '
+	cat >expect <<-\EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+	[bundle "one"]
+		uri = http://example.com/bundle.bdl
+		creationToken = 123456
+	[bundle "two"]
+		uri = https://example.com/bundle.bdl
+		creationToken = 12345678901234567890
+	[bundle "three"]
+		uri = file:///usr/share/git/bundle.bdl
+		creationToken = 1
+	EOF
+
+	test-tool bundle-uri parse-config expect >actual 2>err &&
+	test_must_be_empty err &&
+	test_cmp_config_output expect actual
+'
+
+test_expect_success 'parse config format edge cases: creationToken heuristic' '
+	cat >expect <<-\EOF &&
+	[bundle]
+		version = 1
+		mode = all
+		heuristic = creationToken
+	[bundle "one"]
+		uri = http://example.com/bundle.bdl
+		creationToken = bogus
+	EOF
+
+	test-tool bundle-uri parse-config expect >actual 2>err &&
+	grep "could not parse bundle list key creationToken with value '\''bogus'\''" err
+'
+
 test_done
diff --git a/t/t5810-proto-disable-local.sh b/t/t5810-proto-disable-local.sh
index c1ef99b..8626102 100755
--- a/t/t5810-proto-disable-local.sh
+++ b/t/t5810-proto-disable-local.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test disabling of local paths in clone/fetch'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-proto-disable.sh"
 
diff --git a/t/t5813-proto-disable-ssh.sh b/t/t5813-proto-disable-ssh.sh
index 3f084ee..2e975dc 100755
--- a/t/t5813-proto-disable-ssh.sh
+++ b/t/t5813-proto-disable-ssh.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test disabling of git-over-ssh in clone/fetch'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-proto-disable.sh"
 
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 1f7d7dd..5cf2cee 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -326,19 +326,16 @@
 c3
 EOF
 
-#
-# this test fails on --topo-order - a fix is required
-#
-#test_output_expect_success '--max-age=c3, --topo-order' "git rev-list --topo-order --max-age=$(commit_date c3) l5" <<EOF
-#l5
-#l4
-#l3
-#a4
-#c3
-#b4
-#a3
-#a2
-#EOF
+test_output_expect_success '--max-age=c3, --topo-order' "git rev-list --topo-order --max-age=$(commit_date c3) l5" <<EOF
+l5
+l4
+l3
+a4
+c3
+b4
+a3
+a2
+EOF
 
 test_output_expect_success 'one specified head reachable from another a4, c3, --topo-order' "list_duplicates git rev-list --topo-order a4 c3" <<EOF
 EOF
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index bad02cf..b2e422c 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -2,6 +2,7 @@
 
 test_description='git rev-list should notice bad commits'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Note:
diff --git a/t/t6014-rev-list-all.sh b/t/t6014-rev-list-all.sh
index c9bedd2..16b8bd1 100755
--- a/t/t6014-rev-list-all.sh
+++ b/t/t6014-rev-list-all.sh
@@ -2,6 +2,7 @@
 
 test_description='--all includes detached HEADs'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index 3a1cf30..7d40994 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -566,4 +566,44 @@
 	grep "cannot clone from filtered bundle" err
 '
 
+test_expect_success 'verify catches unreachable, broken prerequisites' '
+	test_when_finished rm -rf clone-from clone-to &&
+	git init clone-from &&
+	(
+		cd clone-from &&
+		git checkout -b base &&
+		test_commit A &&
+		git checkout -b tip &&
+		git commit --allow-empty -m "will drop by shallow" &&
+		git commit --allow-empty -m "will keep by shallow" &&
+		git commit --allow-empty -m "for bundle, not clone" &&
+		git bundle create tip.bundle tip~1..tip &&
+		git reset --hard HEAD~1 &&
+		git checkout base
+	) &&
+	BAD_OID=$(git -C clone-from rev-parse tip~1) &&
+	TIP_OID=$(git -C clone-from rev-parse tip) &&
+	git clone --depth=1 --no-single-branch \
+		"file://$(pwd)/clone-from" clone-to &&
+	(
+		cd clone-to &&
+
+		# Set up broken history by removing shallow markers
+		git update-ref -d refs/remotes/origin/tip &&
+		rm .git/shallow &&
+
+		# Verify should fail
+		test_must_fail git bundle verify \
+			../clone-from/tip.bundle 2>err &&
+		grep "some prerequisite commits .* are not connected" err &&
+		test_line_count = 1 err &&
+
+		# Unbundling should fail
+		test_must_fail git bundle unbundle \
+			../clone-from/tip.bundle 2>err &&
+		grep "some prerequisite commits .* are not connected" err &&
+		test_line_count = 1 err
+	)
+'
+
 test_done
diff --git a/t/t6021-rev-list-exclude-hidden.sh b/t/t6021-rev-list-exclude-hidden.sh
index 32b2b09..11c50b7 100755
--- a/t/t6021-rev-list-exclude-hidden.sh
+++ b/t/t6021-rev-list-exclude-hidden.sh
@@ -2,6 +2,7 @@
 
 test_description='git rev-list --exclude-hidden test'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 6dbbe62..3ba4fdf 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -34,6 +34,36 @@
 HASH3=
 HASH4=
 
+test_bisect_usage () {
+	local code="$1" &&
+	shift &&
+	cat >expect &&
+	test_expect_code $code "$@" >out 2>actual &&
+	test_must_be_empty out &&
+	test_cmp expect actual
+}
+
+test_expect_success 'bisect usage' "
+	test_bisect_usage 1 git bisect reset extra1 extra2 <<-\EOF &&
+	error: 'git bisect reset' requires either no argument or a commit
+	EOF
+	test_bisect_usage 1 git bisect terms extra1 extra2 <<-\EOF &&
+	error: 'git bisect terms' requires 0 or 1 argument
+	EOF
+	test_bisect_usage 1 git bisect next extra1 <<-\EOF &&
+	error: 'git bisect next' requires 0 arguments
+	EOF
+	test_bisect_usage 1 git bisect log extra1 <<-\EOF &&
+	error: We are not bisecting.
+	EOF
+	test_bisect_usage 1 git bisect replay <<-\EOF &&
+	error: no logfile given
+	EOF
+	test_bisect_usage 1 git bisect run <<-\EOF
+	error: 'git bisect run' failed: no command provided.
+	EOF
+"
+
 test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' '
      add_line_into_file "1: Hello World" hello &&
      HASH1=$(git rev-parse --verify HEAD) &&
@@ -252,6 +282,124 @@
 	grep $HASH4 my_bisect_log.txt
 '
 
+test_bisect_run_args () {
+	test_when_finished "rm -f run.sh actual" &&
+	>actual &&
+	cat >expect.args &&
+	cat <&6 >expect.out &&
+	cat <&7 >expect.err &&
+	write_script run.sh <<-\EOF &&
+	while test $# != 0
+	do
+		echo "<$1>" &&
+		shift
+	done >actual.args
+	EOF
+
+	test_when_finished "git bisect reset" &&
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	git bisect run ./run.sh $@ >actual.out.raw 2>actual.err &&
+	# Prune just the log output
+	sed -n \
+		-e '/^Author:/d' \
+		-e '/^Date:/d' \
+		-e '/^$/d' \
+		-e '/^commit /d' \
+		-e '/^ /d' \
+		-e 'p' \
+		<actual.out.raw >actual.out &&
+	test_cmp expect.out actual.out &&
+	test_cmp expect.err actual.err &&
+	test_cmp expect.args actual.args
+}
+
+test_expect_success 'git bisect run: args, stdout and stderr with no arguments' "
+	test_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+	EOF_ARGS
+	running './run.sh'
+	$HASH4 is the first bad commit
+	bisect found first bad commit
+	EOF_OUT
+	EOF_ERR
+"
+
+test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' "
+	test_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+	<-->
+	EOF_ARGS
+	running './run.sh' '--'
+	$HASH4 is the first bad commit
+	bisect found first bad commit
+	EOF_OUT
+	EOF_ERR
+"
+
+test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' "
+	test_bisect_run_args --log foo --no-log bar <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+	<--log>
+	<foo>
+	<--no-log>
+	<bar>
+	EOF_ARGS
+	running './run.sh' '--log' 'foo' '--no-log' 'bar'
+	$HASH4 is the first bad commit
+	bisect found first bad commit
+	EOF_OUT
+	EOF_ERR
+"
+
+test_expect_success 'git bisect run: args, stdout and stderr: "--bisect-start" argument' "
+	test_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+	<--bisect-start>
+	EOF_ARGS
+	running './run.sh' '--bisect-start'
+	$HASH4 is the first bad commit
+	bisect found first bad commit
+	EOF_OUT
+	EOF_ERR
+"
+
+test_expect_success 'git bisect run: negative exit code' "
+	write_script fail.sh <<-'EOF' &&
+	exit 255
+	EOF
+	cat <<-'EOF' >expect &&
+	bisect run failed: exit code -1 from './fail.sh' is < 0 or >= 128
+	EOF
+	test_when_finished 'git bisect reset' &&
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	! git bisect run ./fail.sh 2>err &&
+	sed -En 's/.*(bisect.*code) (-?[0-9]+) (from.*)/\1 -1 \3/p' err >actual &&
+	test_cmp expect actual
+"
+
+test_expect_success 'git bisect run: unable to verify on good' "
+	write_script fail.sh <<-'EOF' &&
+	head=\$(git rev-parse --verify HEAD)
+	good=\$(git rev-parse --verify $HASH1)
+	if test "\$head" = "\$good"
+	then
+		exit 255
+	else
+		exit 127
+	fi
+	EOF
+	cat <<-'EOF' >expect &&
+	unable to verify './fail.sh' on good revision
+	EOF
+	test_when_finished 'git bisect reset' &&
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	! git bisect run ./fail.sh 2>err &&
+	sed -n 's/.*\(unable to verify.*\)/\1/p' err >actual &&
+	test_cmp expect actual
+"
+
 # We want to automatically find the commit that
 # added "Another" into hello.
 test_expect_success '"git bisect run" simple case' '
@@ -910,6 +1058,16 @@
 	git bisect reset
 '
 
+test_expect_success 'bogus command does not start bisect' '
+	git bisect reset &&
+	test_must_fail git bisect --bisect-terms 1 2 2>out &&
+	! grep "You need to start" out &&
+	test_must_fail git bisect --bisect-terms 2>out &&
+	! grep "You need to start" out &&
+	grep "git bisect.*visualize" out &&
+	git bisect reset
+'
+
 test_expect_success 'bisect replay with term1 and term2' '
 	git bisect replay log_to_replay.txt >bisect_result &&
 	grep "$HASH2 is the first term1 commit" bisect_result &&
@@ -1000,7 +1158,6 @@
 	test_path_is_missing ".git/BISECT_LOG" &&
 	test_path_is_missing ".git/BISECT_RUN" &&
 	test_path_is_missing ".git/BISECT_TERMS" &&
-	test_path_is_missing ".git/head-name" &&
 	test_path_is_missing ".git/BISECT_HEAD" &&
 	test_path_is_missing ".git/BISECT_START"
 '
@@ -1063,4 +1220,14 @@
 	grep -F "waiting for good commit(s), bad commit known" output
 '
 
+test_expect_success 'verify correct error message' '
+	git bisect reset &&
+	git bisect start $HASH4 $HASH1 &&
+	write_script test_script.sh <<-\EOF &&
+	rm .git/BISECT*
+	EOF
+	test_must_fail git bisect run ./test_script.sh 2>error &&
+	grep "git bisect good.*exited with error code" error
+'
+
 test_done
diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh
index ed449ab..1a8b64c 100755
--- a/t/t6060-merge-index.sh
+++ b/t/t6060-merge-index.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='basic git merge-index / git-merge-one-file tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup diverging branches' '
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 9a35e78..c9afcef 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -657,4 +657,10 @@
 
 check_describe -C disjoint2 "B-3-gHASH" HEAD
 
+test_expect_success 'setup misleading taggerdates' '
+	GIT_COMMITTER_DATE="2006-12-12 12:31" git tag -a -m "another tag" newer-tag-older-commit unique-file~1
+'
+
+check_describe newer-tag-older-commit~1 --contains unique-file~2
+
 test_done
diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh
index cada952..9fdafeb 100755
--- a/t/t6132-pathspec-exclude.sh
+++ b/t/t6132-pathspec-exclude.sh
@@ -293,11 +293,7 @@
 	test_cmp expect actual
 '
 
-test_lazy_prereq ADD_I_USE_BUILTIN_OR_PERL '
-	test_have_prereq ADD_I_USE_BUILTIN || test_have_prereq PERL
-'
-
-test_expect_success ADD_I_USE_BUILTIN_OR_PERL 'add -p with all negative' '
+test_expect_success 'add -p with all negative' '
 	H=$(git rev-parse HEAD) &&
 	git reset --hard $H &&
 	git clean -f &&
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index fa38b87..c466fd9 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -606,7 +606,7 @@
 	git tag -a -m "Broken tag" taggerless &&
 	git tag -f taggerless $(git cat-file tag taggerless |
 		sed -e "/^tagger /d" |
-		git hash-object --stdin -w -t tag)
+		git hash-object --literally --stdin -w -t tag)
 '
 
 test_atom refs/tags/taggerless type 'commit'
@@ -1242,6 +1242,24 @@
 	test_must_fail git for-each-ref --format="%(rest)" refs/heads/main
 '
 
+test_expect_success 'HEAD atom does not take arguments' '
+	test_must_fail git for-each-ref --format="%(HEAD:foo)" 2>err &&
+	echo "fatal: %(HEAD) does not take arguments" >expect &&
+	test_cmp expect err
+'
+
+test_expect_success 'subject atom rejects unknown arguments' '
+	test_must_fail git for-each-ref --format="%(subject:foo)" 2>err &&
+	echo "fatal: unrecognized %(subject) argument: foo" >expect &&
+	test_cmp expect err
+'
+
+test_expect_success 'refname atom rejects unknown arguments' '
+	test_must_fail git for-each-ref --format="%(refname:foo)" 2>err &&
+	echo "fatal: unrecognized %(refname) argument: foo" >expect &&
+	test_cmp expect err
+'
+
 test_expect_success 'trailer parsing not fooled by --- line' '
 	git commit --allow-empty -F - <<-\EOF &&
 	this is the subject
diff --git a/t/t6301-for-each-ref-errors.sh b/t/t6301-for-each-ref-errors.sh
index 40edf9d..bfda1f4 100755
--- a/t/t6301-for-each-ref-errors.sh
+++ b/t/t6301-for-each-ref-errors.sh
@@ -2,6 +2,7 @@
 
 test_description='for-each-ref errors for broken refs'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 ZEROS=$ZERO_OID
diff --git a/t/t6401-merge-criss-cross.sh b/t/t6401-merge-criss-cross.sh
index 9d5e992..1962310 100755
--- a/t/t6401-merge-criss-cross.sh
+++ b/t/t6401-merge-criss-cross.sh
@@ -8,6 +8,8 @@
 
 
 test_description='Test criss-cross merge'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'prepare repository' '
diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh
index 8650a88..5e4e4dd 100755
--- a/t/t6406-merge-attr.sh
+++ b/t/t6406-merge-attr.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t6407-merge-binary.sh b/t/t6407-merge-binary.sh
index e8a2871..0753fc9 100755
--- a/t/t6407-merge-binary.sh
+++ b/t/t6407-merge-binary.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t6415-merge-dir-to-symlink.sh b/t/t6415-merge-dir-to-symlink.sh
index 2655e29..ae00492 100755
--- a/t/t6415-merge-dir-to-symlink.sh
+++ b/t/t6415-merge-dir-to-symlink.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'create a commit where dir a/b changed to symlink' '
diff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh
index 5413e5d..711b709 100755
--- a/t/t6421-merge-partial-clone.sh
+++ b/t/t6421-merge-partial-clone.sh
@@ -155,7 +155,7 @@
 #   Commit A:
 #     (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/
 #      -> folder/, move e into newsubdir, add newfile.rs, remove f, modify
-#      both both Makefiles and jumps)
+#      both Makefiles and jumps)
 #              general/{jump1_A, jump2_A}
 #              basename/subdir/{numbers_A, sequence_A, values_A}
 #              folder/subdir/{a,b,c,d,Makefile_TOP_A}
@@ -343,7 +343,7 @@
 #   Commit A:
 #     (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/
 #      -> folder/, move e into newsubdir, add newfile.rs, remove f, modify
-#      both both Makefiles and jumps)
+#      both Makefiles and jumps)
 #              general/{jump1_A, jump2_A}
 #              basename/subdir/{numbers_A, sequence_A, values_A}
 #              folder/subdir/{a,b,c,d,Makefile_TOP_A}
diff --git a/t/t6422-merge-rename-corner-cases.sh b/t/t6422-merge-rename-corner-cases.sh
index 346253c..076b6a7 100755
--- a/t/t6422-merge-rename-corner-cases.sh
+++ b/t/t6422-merge-rename-corner-cases.sh
@@ -1159,7 +1159,6 @@
 	#   4) There should not be any three~* files in the working
 	#      tree
 	test_setup_collision_conflict () {
-	#test_expect_success "setup simple $sideL/$sideR conflict" '
 		git init simple_${sideL}_${sideR} &&
 		(
 			cd simple_${sideL}_${sideR} &&
@@ -1236,7 +1235,6 @@
 			fi &&
 			test_tick && git commit -m R
 		)
-	#'
 	}
 
 	test_expect_success "check simple $sideL/$sideR conflict" '
diff --git a/t/t6426-merge-skip-unneeded-updates.sh b/t/t6426-merge-skip-unneeded-updates.sh
index 2bb8e7f..fd21c1a 100755
--- a/t/t6426-merge-skip-unneeded-updates.sh
+++ b/t/t6426-merge-skip-unneeded-updates.sh
@@ -378,42 +378,30 @@
 		test_i18ngrep "CONFLICT (.*/add):" out &&
 		test_must_be_empty err &&
 
-		# Make sure c WAS updated
+		git ls-files -s >index_files &&
+		test_line_count = 2 index_files &&
+
+		# Ensure b was removed
+		test_path_is_missing b &&
+
+		# Make sure c WAS updated...
 		test-tool chmtime --get c >new-mtime &&
-		test $(cat old-mtime) -lt $(cat new-mtime)
+		test $(cat old-mtime) -lt $(cat new-mtime) &&
 
-		# FIXME: rename/add conflicts are horribly broken right now;
-		# when I get back to my patch series fixing it and
-		# rename/rename(2to1) conflicts to bring them in line with
-		# how add/add conflicts behave, then checks like the below
-		# could be added.  But that patch series is waiting until
-		# the rename-directory-detection series lands, which this
-		# is part of.  And in the mean time, I do not want to further
-		# enforce broken behavior.  So for now, the main test is the
-		# one above that err is an empty file.
+		# ...and has correct index entries and working tree contents
+		git rev-parse >actual :2:c :3:c &&
+		git rev-parse >expect A:c  A:b  &&
+		test_cmp expect actual &&
 
-		#git ls-files -s >index_files &&
-		#test_line_count = 2 index_files &&
-
-		#git rev-parse >actual :2:c :3:c &&
-		#git rev-parse >expect A:b  A:c  &&
-		#test_cmp expect actual &&
-
-		#git cat-file -p A:b >>merged &&
-		#git cat-file -p A:c >>merge-me &&
-		#>empty &&
-		#test_must_fail git merge-file \
-		#	-L "Temporary merge branch 1" \
-		#	-L "" \
-		#	-L "Temporary merge branch 2" \
-		#	merged empty merge-me &&
-		#sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal &&
-
-		#git hash-object c               >actual &&
-		#git hash-object merged-internal >expect &&
-		#test_cmp expect actual &&
-
-		#test_path_is_missing b
+		git cat-file -p A:b >>merge-me &&
+		git cat-file -p A:c >>merged &&
+		>empty &&
+		test_must_fail git merge-file \
+			-L "HEAD" \
+			-L "" \
+			-L "B^0" \
+			merged empty merge-me &&
+		test_cmp merged c
 	)
 '
 
diff --git a/t/t6435-merge-sparse.sh b/t/t6435-merge-sparse.sh
index fde4aa3..78628fb 100755
--- a/t/t6435-merge-sparse.sh
+++ b/t/t6435-merge-sparse.sh
@@ -3,6 +3,7 @@
 test_description='merge with sparse files'
 
 TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # test_file $filename $content
diff --git a/t/t6439-merge-co-error-msgs.sh b/t/t6439-merge-co-error-msgs.sh
index 52cf0c8..0cbec57 100755
--- a/t/t6439-merge-co-error-msgs.sh
+++ b/t/t6439-merge-co-error-msgs.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 
diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh
index 1066245..3968b47 100755
--- a/t/t6501-freshen-objects.sh
+++ b/t/t6501-freshen-objects.sh
@@ -28,6 +28,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # We care about reachability, so we do not want to use
diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh
index 10faa64..6f526c3 100755
--- a/t/t7030-verify-tag.sh
+++ b/t/t7030-verify-tag.sh
@@ -115,7 +115,7 @@
 
 test_expect_success GPG 'detect fudged signature' '
 	git cat-file tag seventh-signed >raw &&
-	sed -e "/^tag / s/seventh/7th forged/" raw >forged1 &&
+	sed -e "/^tag / s/seventh/7th-forged/" raw >forged1 &&
 	git hash-object -w -t tag forged1 >forged1.tag &&
 	test_must_fail git verify-tag $(cat forged1.tag) 2>actual1 &&
 	grep "BAD signature from" actual1 &&
diff --git a/t/t7031-verify-tag-signed-ssh.sh b/t/t7031-verify-tag-signed-ssh.sh
index 1cb36b9..36eb86a 100755
--- a/t/t7031-verify-tag-signed-ssh.sh
+++ b/t/t7031-verify-tag-signed-ssh.sh
@@ -125,7 +125,7 @@
 test_expect_success GPGSSH 'detect fudged ssh signature' '
 	test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
 	git cat-file tag seventh-signed >raw &&
-	sed -e "/^tag / s/seventh/7th forged/" raw >forged1 &&
+	sed -e "/^tag / s/seventh/7th-forged/" raw >forged1 &&
 	git hash-object -w -t tag forged1 >forged1.tag &&
 	test_must_fail git verify-tag $(cat forged1.tag) 2>actual1 &&
 	grep "${GPGSSH_BAD_SIGNATURE}" actual1 &&
diff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh
index a60153f..18bbd99 100755
--- a/t/t7103-reset-bare.sh
+++ b/t/t7103-reset-bare.sh
@@ -63,7 +63,7 @@
 	test_must_fail git reset --mixed HEAD^
 '
 
-test_expect_success !SANITIZE_LEAK '"soft" reset is allowed in bare' '
+test_expect_success '"soft" reset is allowed in bare' '
 	git reset --soft HEAD^ &&
 	git show --pretty=format:%s >out &&
 	echo one >expect &&
diff --git a/t/t7105-reset-patch.sh b/t/t7105-reset-patch.sh
index fc2a6cf..9b46da7 100755
--- a/t/t7105-reset-patch.sh
+++ b/t/t7105-reset-patch.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='git reset --patch'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./lib-patch-mode.sh
 
 test_expect_success PERL 'setup' '
diff --git a/t/t7106-reset-unborn-branch.sh b/t/t7106-reset-unborn-branch.sh
index ecb85c3..a0b67a0 100755
--- a/t/t7106-reset-unborn-branch.sh
+++ b/t/t7106-reset-unborn-branch.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='git reset should work on unborn branch'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t7107-reset-pathspec-file.sh b/t/t7107-reset-pathspec-file.sh
index 523efbe..af5ea40 100755
--- a/t/t7107-reset-pathspec-file.sh
+++ b/t/t7107-reset-pathspec-file.sh
@@ -2,6 +2,7 @@
 
 test_description='reset --pathspec-from-file'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_tick
diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh
index a07e8b8..d82a321 100755
--- a/t/t7301-clean-interactive.sh
+++ b/t/t7301-clean-interactive.sh
@@ -2,6 +2,7 @@
 
 test_description='git clean -i basic tests'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh
index ebeca12..b19792b 100755
--- a/t/t7402-submodule-rebase.sh
+++ b/t/t7402-submodule-rebase.sh
@@ -5,6 +5,7 @@
 
 test_description='Test rebasing, stashing, etc. with submodules'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh
index ea92ef5..ff09443 100755
--- a/t/t7403-submodule-sync.sh
+++ b/t/t7403-submodule-sync.sh
@@ -11,6 +11,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t7409-submodule-detached-work-tree.sh b/t/t7409-submodule-detached-work-tree.sh
index 374ed48..574a6fc 100755
--- a/t/t7409-submodule-detached-work-tree.sh
+++ b/t/t7409-submodule-detached-work-tree.sh
@@ -13,6 +13,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh
index 2859695..f778321 100755
--- a/t/t7412-submodule-absorbgitdirs.sh
+++ b/t/t7412-submodule-absorbgitdirs.sh
@@ -10,6 +10,7 @@
 . ./test-lib.sh
 
 test_expect_success 'setup a real submodule' '
+	cwd="$(pwd)" &&
 	git init sub1 &&
 	test_commit -C sub1 first &&
 	git submodule add ./sub1 &&
@@ -18,13 +19,21 @@
 '
 
 test_expect_success 'absorb the git dir' '
+	>expect &&
+	>actual &&
 	>expect.1 &&
 	>expect.2 &&
 	>actual.1 &&
 	>actual.2 &&
 	git status >expect.1 &&
 	git -C sub1 rev-parse HEAD >expect.2 &&
-	git submodule absorbgitdirs &&
+	cat >expect <<-EOF &&
+	Migrating git directory of '\''sub1'\'' from
+	'\''$cwd/sub1/.git'\'' to
+	'\''$cwd/.git/modules/sub1'\''
+	EOF
+	git submodule absorbgitdirs 2>actual &&
+	test_cmp expect actual &&
 	git fsck &&
 	test -f sub1/.git &&
 	test -d .git/modules/sub1 &&
@@ -37,7 +46,8 @@
 test_expect_success 'absorbing does not fail for deinitialized submodules' '
 	test_when_finished "git submodule update --init" &&
 	git submodule deinit --all &&
-	git submodule absorbgitdirs &&
+	git submodule absorbgitdirs 2>err &&
+	test_must_be_empty err &&
 	test -d .git/modules/sub1 &&
 	test -d sub1 &&
 	! test -e sub1/.git
@@ -56,7 +66,13 @@
 test_expect_success 'absorb the git dir in a nested submodule' '
 	git status >expect.1 &&
 	git -C sub1/nested rev-parse HEAD >expect.2 &&
-	git submodule absorbgitdirs &&
+	cat >expect <<-EOF &&
+	Migrating git directory of '\''sub1/nested'\'' from
+	'\''$cwd/sub1/nested/.git'\'' to
+	'\''$cwd/.git/modules/sub1/modules/nested'\''
+	EOF
+	git submodule absorbgitdirs 2>actual &&
+	test_cmp expect actual &&
 	test -f sub1/nested/.git &&
 	test -d .git/modules/sub1/modules/nested &&
 	git status >actual.1 &&
@@ -87,7 +103,13 @@
 test_expect_success 'absorb the git dir in a nested submodule' '
 	git status >expect.1 &&
 	git -C sub1/nested rev-parse HEAD >expect.2 &&
-	git submodule absorbgitdirs &&
+	cat >expect <<-EOF &&
+	Migrating git directory of '\''sub1'\'' from
+	'\''$cwd/sub1/.git'\'' to
+	'\''$cwd/.git/modules/sub1'\''
+	EOF
+	git submodule absorbgitdirs 2>actual &&
+	test_cmp expect actual &&
 	test -f sub1/.git &&
 	test -f sub1/nested/.git &&
 	test -d .git/modules/sub1/modules/nested &&
@@ -97,6 +119,27 @@
 	test_cmp expect.2 actual.2
 '
 
+test_expect_success 'absorb the git dir outside of primary worktree' '
+	test_when_finished "rm -rf repo-bare.git" &&
+	git clone --bare . repo-bare.git &&
+	test_when_finished "rm -rf repo-wt" &&
+	git -C repo-bare.git worktree add ../repo-wt &&
+
+	test_when_finished "rm -f .gitconfig" &&
+	test_config_global protocol.file.allow always &&
+	git -C repo-wt submodule update --init &&
+	git init repo-wt/sub2 &&
+	test_commit -C repo-wt/sub2 A &&
+	git -C repo-wt submodule add ./sub2 sub2 &&
+	cat >expect <<-EOF &&
+	Migrating git directory of '\''sub2'\'' from
+	'\''$cwd/repo-wt/sub2/.git'\'' to
+	'\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\''
+	EOF
+	git -C repo-wt submodule absorbgitdirs 2>actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'setup a gitlink with missing .gitmodules entry' '
 	git init sub2 &&
 	test_commit -C sub2 first &&
@@ -107,7 +150,11 @@
 test_expect_success 'absorbing the git dir fails for incomplete submodules' '
 	git status >expect.1 &&
 	git -C sub2 rev-parse HEAD >expect.2 &&
-	test_must_fail git submodule absorbgitdirs &&
+	cat >expect <<-\EOF &&
+	fatal: could not lookup name for submodule '\''sub2'\''
+	EOF
+	test_must_fail git submodule absorbgitdirs 2>actual &&
+	test_cmp expect actual &&
 	git -C sub2 fsck &&
 	test -d sub2/.git &&
 	git status >actual &&
@@ -127,8 +174,11 @@
 '
 
 test_expect_success 'absorbing fails for a submodule with multiple worktrees' '
-	test_must_fail git submodule absorbgitdirs sub3 2>error &&
-	test_i18ngrep "not supported" error
+	cat >expect <<-\EOF &&
+	fatal: could not lookup name for submodule '\''sub2'\''
+	EOF
+	test_must_fail git submodule absorbgitdirs 2>actual &&
+	test_cmp expect actual
 '
 
 test_done
diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh
index 3ebd985..7cf72b9 100755
--- a/t/t7416-submodule-dash-url.sh
+++ b/t/t7416-submodule-dash-url.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='check handling of disallowed .gitmodule urls'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh
index 8f94129..60d6275 100755
--- a/t/t7450-bad-git-dotfiles.sh
+++ b/t/t7450-bad-git-dotfiles.sh
@@ -12,6 +12,8 @@
 
   - symlinked .gitmodules, etc
 '
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-pack.sh
 
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index a39de8c..07ca46f 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'with no hook' '
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 2b7ef6c..aed07c5 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1676,4 +1676,74 @@
 	! test_is_magic_mtime .git/index
 '
 
+test_expect_success 'setup slow status advice' '
+	GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main git init slowstatus &&
+	(
+		cd slowstatus &&
+		cat >.gitignore <<-\EOF &&
+		/actual
+		/expected
+		/out
+		EOF
+		git add .gitignore &&
+		git commit -m "Add .gitignore" &&
+		git config advice.statusuoption true
+	)
+'
+
+test_expect_success 'slow status advice when core.untrackedCache and fsmonitor are unset' '
+	(
+		cd slowstatus &&
+		git config core.untrackedCache false &&
+		git config core.fsmonitor false &&
+		GIT_TEST_UF_DELAY_WARNING=1 git status >actual &&
+		cat >expected <<-\EOF &&
+		On branch main
+
+		It took 3.25 seconds to enumerate untracked files.
+		See '\''git help status'\'' for information on how to improve this.
+
+		nothing to commit, working tree clean
+		EOF
+		test_cmp expected actual
+	)
+'
+
+test_expect_success 'slow status advice when core.untrackedCache true, but not fsmonitor' '
+	(
+		cd slowstatus &&
+		git config core.untrackedCache true &&
+		git config core.fsmonitor false &&
+		GIT_TEST_UF_DELAY_WARNING=1 git status >actual &&
+		cat >expected <<-\EOF &&
+		On branch main
+
+		It took 3.25 seconds to enumerate untracked files.
+		See '\''git help status'\'' for information on how to improve this.
+
+		nothing to commit, working tree clean
+		EOF
+		test_cmp expected actual
+	)
+'
+
+test_expect_success 'slow status advice when core.untrackedCache true, and fsmonitor' '
+	(
+		cd slowstatus &&
+		git config core.untrackedCache true &&
+		git config core.fsmonitor true &&
+		GIT_TEST_UF_DELAY_WARNING=1 git status >actual &&
+		cat >expected <<-\EOF &&
+		On branch main
+
+		It took 3.25 seconds to enumerate untracked files,
+		but the results were cached, and subsequent runs may be faster.
+		See '\''git help status'\'' for information on how to improve this.
+
+		nothing to commit, working tree clean
+		EOF
+		test_cmp expected actual
+	)
+'
+
 test_done
diff --git a/t/t7509-commit-authorship.sh b/t/t7509-commit-authorship.sh
index 21c668f..5d89094 100755
--- a/t/t7509-commit-authorship.sh
+++ b/t/t7509-commit-authorship.sh
@@ -105,7 +105,7 @@
 test_expect_success '--amend option with missing author' '
 	git cat-file commit Initial >tmp &&
 	sed "s/author [^<]* </author </" tmp >malformed &&
-	sha=$(git hash-object -t commit -w malformed) &&
+	sha=$(git hash-object --literally -t commit -w malformed) &&
 	test_when_finished "remove_object $sha" &&
 	git checkout $sha &&
 	test_when_finished "git checkout Initial" &&
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
index 8593b7e..48f86cb 100755
--- a/t/t7510-signed-commit.sh
+++ b/t/t7510-signed-commit.sh
@@ -202,7 +202,7 @@
 	git cat-file commit seventh-signed >raw &&
 	cat raw >forged2 &&
 	echo Qwik | tr "Q" "\000" >>forged2 &&
-	git hash-object -w -t commit forged2 >forged2.commit &&
+	git hash-object --literally -w -t commit forged2 >forged2.commit &&
 	test_must_fail git verify-commit $(cat forged2.commit) &&
 	git show --pretty=short --show-signature $(cat forged2.commit) >actual2 &&
 	grep "BAD signature from" actual2 &&
@@ -387,4 +387,48 @@
 	! grep "BAD signature from" actual
 '
 
+test_expect_success 'custom `gpg.program`' '
+	write_script fake-gpg <<-\EOF &&
+	args="$*"
+
+	# skip uninteresting options
+	while case "$1" in
+	--status-fd=*|--keyid-format=*) ;; # skip
+	*) break;;
+	esac; do shift; done
+
+	case "$1" in
+	-bsau)
+		test -z "$LET_GPG_PROGRAM_FAIL" || {
+			echo "zOMG signing failed!" >&2
+			exit 1
+		}
+		cat >sign.file
+		echo "[GNUPG:] SIG_CREATED $args" >&2
+		echo "-----BEGIN PGP MESSAGE-----"
+		echo "$args"
+		echo "-----END PGP MESSAGE-----"
+		;;
+	--verify)
+		cat "$2" >verify.file
+		exit 0
+		;;
+	*)
+		echo "Unhandled args: $*" >&2
+		exit 1
+		;;
+	esac
+	EOF
+
+	test_config gpg.program "$(pwd)/fake-gpg" &&
+	git commit -S --allow-empty -m signed-commit &&
+	test_path_exists sign.file &&
+	git show --show-signature &&
+	test_path_exists verify.file &&
+
+	test_must_fail env LET_GPG_PROGRAM_FAIL=1 \
+	git commit -S --allow-empty -m must-fail 2>err &&
+	grep zOMG err
+'
+
 test_done
diff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh
index 163ae80..efc6496 100755
--- a/t/t7517-per-repo-email.sh
+++ b/t/t7517-per-repo-email.sh
@@ -9,6 +9,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup a likely user.useConfigOnly use case' '
diff --git a/t/t7520-ignored-hook-warning.sh b/t/t7520-ignored-hook-warning.sh
index dc57526..184b258 100755
--- a/t/t7520-ignored-hook-warning.sh
+++ b/t/t7520-ignored-hook-warning.sh
@@ -2,6 +2,7 @@
 
 test_description='ignored hook warning'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
index 4abc74d..4c0327b 100755
--- a/t/t7527-builtin-fsmonitor.sh
+++ b/t/t7527-builtin-fsmonitor.sh
@@ -866,27 +866,9 @@
 # the submodule, and someone does a `git submodule absorbgitdirs`
 # in the super, Git will recursively invoke `git submodule--helper`
 # to do the work and this may try to read the index.  This will
-# try to start the daemon in the submodule *and* pass (either
-# directly or via inheritance) the `--super-prefix` arg to the
-# `git fsmonitor--daemon start` command inside the submodule.
-# This causes a warning because fsmonitor--daemon does take that
-# global arg (see the table in git.c)
-#
-# This causes a warning when trying to start the daemon that is
-# somewhat confusing.  It does not seem to hurt anything because
-# the fsmonitor code maps the query failure into a trivial response
-# and does the work anyway.
-#
-# It would be nice to silence the warning, however.
+# try to start the daemon in the submodule.
 
-have_t2_error_event () {
-	log=$1
-	msg="fsmonitor--daemon doesnQt support --super-prefix" &&
-
-	tr '\047' Q <$1 | grep -e "$msg"
-}
-
-test_expect_success "stray submodule super-prefix warning" '
+test_expect_success "submodule absorbgitdirs implicitly starts daemon" '
 	test_when_finished "rm -rf super; \
 			    rm -rf sub;   \
 			    rm super-sub.trace" &&
@@ -904,21 +886,31 @@
 
 	test_path_is_dir super/dir_1/dir_2/sub/.git &&
 
+	cwd="$(cd super && pwd)" &&
+	cat >expect <<-EOF &&
+	Migrating git directory of '\''dir_1/dir_2/sub'\'' from
+	'\''$cwd/dir_1/dir_2/sub/.git'\'' to
+	'\''$cwd/.git/modules/dir_1/dir_2/sub'\''
+	EOF
 	GIT_TRACE2_EVENT="$PWD/super-sub.trace" \
-		git -C super submodule absorbgitdirs &&
+		git -C super submodule absorbgitdirs >out 2>actual &&
+	test_cmp expect actual &&
+	test_must_be_empty out &&
 
-	! have_t2_error_event super-sub.trace
+	# Confirm that the trace2 log contains a record of the
+	# daemon starting.
+	test_subcommand git fsmonitor--daemon start <super-sub.trace
 '
 
 # On a case-insensitive file system, confirm that the daemon
 # notices when the .git directory is moved/renamed/deleted
-# regardless of how it is spelled in the the FS event.
+# regardless of how it is spelled in the FS event.
 # That is, does the FS event receive the spelling of the
 # operation or does it receive the spelling preserved with
 # the file/directory.
 #
 test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' '
-#	test_when_finished "stop_daemon_delete_repo test_insensitive" &&
+	test_when_finished "stop_daemon_delete_repo test_insensitive" &&
 
 	git init test_insensitive &&
 
@@ -930,8 +922,8 @@
 	test_path_is_dir test_insensitive/.git &&
 	test_path_is_dir test_insensitive/.GIT &&
 
-	# Rename .git using an alternate spelling to verify that that
-	# daemon detects it and automatically shuts down.
+	# Rename .git using an alternate spelling to verify that
+	# the daemon detects it and automatically shuts down.
 	mv test_insensitive/.GIT test_insensitive/.FOO &&
 
 	# See [1] above.
diff --git a/t/t7528-signed-commit-ssh.sh b/t/t7528-signed-commit-ssh.sh
index f47e995..065f780 100755
--- a/t/t7528-signed-commit-ssh.sh
+++ b/t/t7528-signed-commit-ssh.sh
@@ -270,7 +270,7 @@
 	git cat-file commit seventh-signed >raw &&
 	cat raw >forged2 &&
 	echo Qwik | tr "Q" "\000" >>forged2 &&
-	git hash-object -w -t commit forged2 >forged2.commit &&
+	git hash-object --literally -w -t commit forged2 >forged2.commit &&
 	test_must_fail git verify-commit $(cat forged2.commit) &&
 	git show --pretty=short --show-signature $(cat forged2.commit) >actual2 &&
 	grep "${GPGSSH_BAD_SIGNATURE}" actual2 &&
diff --git a/t/t7605-merge-resolve.sh b/t/t7605-merge-resolve.sh
index 5d56c38..62d935d 100755
--- a/t/t7605-merge-resolve.sh
+++ b/t/t7605-merge-resolve.sh
@@ -4,6 +4,7 @@
 
 Testing the resolve strategy.'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh
index 61330f7..f5c90cc 100755
--- a/t/t7612-merge-verify-signatures.sh
+++ b/t/t7612-merge-verify-signatures.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-gpg.sh"
 
diff --git a/t/t7614-merge-signoff.sh b/t/t7614-merge-signoff.sh
index fee258d..cf96a35 100755
--- a/t/t7614-merge-signoff.sh
+++ b/t/t7614-merge-signoff.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Setup test files
diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh
index b7ac4f5..ebb2678 100755
--- a/t/t7701-repack-unpack-unreachable.sh
+++ b/t/t7701-repack-unpack-unreachable.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 fsha1=
diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh
index d751d48..8bcd39e 100755
--- a/t/t8003-blame-corner-cases.sh
+++ b/t/t8003-blame-corner-cases.sh
@@ -201,7 +201,7 @@
 
 some message
 EOF
-  COMMIT=$(git hash-object -t commit -w badcommit) &&
+  COMMIT=$(git hash-object --literally -t commit -w badcommit) &&
   git --no-pager blame $COMMIT -- uno >/dev/null
 '
 
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 0f08a95..2ff8249 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -2335,6 +2335,12 @@
 		"$(pwd)/0001-add-main.patch"
 '
 
+test_expect_success $PREREQ 'send-email relays -v 3 to format-patch' '
+	test_when_finished "rm -f out" &&
+	git send-email --dry-run -v 3 -1 >out &&
+	grep "PATCH v3" out
+'
+
 test_expect_success $PREREQ 'test that sendmail config is rejected' '
 	test_config sendmail.program sendmail &&
 	test_must_fail git send-email \
diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh
index f00deaf..14a704d 100755
--- a/t/t9003-help-autocorrect.sh
+++ b/t/t9003-help-autocorrect.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='help.autocorrect finding a match'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
@@ -60,4 +62,10 @@
 	test_line_count = 1 actual
 '
 
+test_expect_success 'autocorrect works in work tree created from bare repo' '
+	git clone --bare . bare.git &&
+	git -C bare.git worktree add ../worktree &&
+	git -C worktree -c help.autocorrect=immediate stauts
+'
+
 test_done
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index 3cab0b9..bca496c 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -3,7 +3,6 @@
 # Copyright (c) 2006 Eric Wong
 test_description='git svn commit-diff clobber'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 test_expect_success 'initialize repo' '
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 419f055..743fbe1 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -5,7 +5,6 @@
 
 test_description='git svn dcommit can commit renames of files with ugly names'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 test_expect_success 'load repository with strange names' '
diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh
index 8201c3e..088d1c5 100755
--- a/t/t9119-git-svn-info.sh
+++ b/t/t9119-git-svn-info.sh
@@ -28,7 +28,7 @@
 	rm -f tmp.expect tmp.actual
 }
 
-quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')"
+quoted_svnrepo="$(echo $svnrepo | test_uri_escape)"
 
 test_expect_success 'setup repository and import' '
 	mkdir info &&
diff --git a/t/t9146-git-svn-empty-dirs.sh b/t/t9146-git-svn-empty-dirs.sh
index 79c26ed..09606f1 100755
--- a/t/t9146-git-svn-empty-dirs.sh
+++ b/t/t9146-git-svn-empty-dirs.sh
@@ -4,7 +4,6 @@
 
 test_description='git svn creates empty directories'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 test_expect_success 'initialize repo' '
diff --git a/t/t9148-git-svn-propset.sh b/t/t9148-git-svn-propset.sh
index 6cc76a0..aebb289 100755
--- a/t/t9148-git-svn-propset.sh
+++ b/t/t9148-git-svn-propset.sh
@@ -5,7 +5,6 @@
 
 test_description='git svn propset tests'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 test_expect_success 'setup propset via import' '
diff --git a/t/t9160-git-svn-preserve-empty-dirs.sh b/t/t9160-git-svn-preserve-empty-dirs.sh
index 9cf7a14..36c6b1a 100755
--- a/t/t9160-git-svn-preserve-empty-dirs.sh
+++ b/t/t9160-git-svn-preserve-empty-dirs.sh
@@ -9,7 +9,6 @@
 directories, and checks that corresponding directories are created in the
 local Git repository with placeholder files.'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 GIT_REPO=git-svn-repo
diff --git a/t/t9164-git-svn-dcommit-concurrent.sh b/t/t9164-git-svn-dcommit-concurrent.sh
index 1465156..c8e6c07 100755
--- a/t/t9164-git-svn-dcommit-concurrent.sh
+++ b/t/t9164-git-svn-dcommit-concurrent.sh
@@ -5,7 +5,6 @@
 
 test_description='concurrent git svn dcommit'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 
diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh
index 25f500c..4432a30 100755
--- a/t/t9210-scalar.sh
+++ b/t/t9210-scalar.sh
@@ -104,6 +104,13 @@
 	test_cmp_config -C test/src true core.fsmonitor
 '
 
+test_expect_success 'scalar register warns when background maintenance fails' '
+	git init register-repo &&
+	GIT_TEST_MAINT_SCHEDULER="crontab:false,launchctl:false,schtasks:false" \
+		scalar register register-repo 2>err &&
+	grep "could not turn on maintenance" err
+'
+
 test_expect_success 'scalar unregister' '
 	git init vanish/src &&
 	scalar register vanish/src &&
diff --git a/t/t9211-scalar-clone.sh b/t/t9211-scalar-clone.sh
index dd33d87..872ad1c 100755
--- a/t/t9211-scalar-clone.sh
+++ b/t/t9211-scalar-clone.sh
@@ -3,6 +3,7 @@
 test_description='test the `scalar clone` subcommand'
 
 . ./test-lib.sh
+. "${TEST_DIRECTORY}/lib-terminal.sh"
 
 GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt,launchctl:true,schtasks:true"
 export GIT_TEST_MAINT_SCHEDULER
@@ -148,4 +149,35 @@
 	cleanup_clone $enlistment
 '
 
+test_expect_success TTY 'progress with tty' '
+	enlistment=progress1 &&
+
+	test_config -C to-clone uploadpack.allowfilter true &&
+	test_config -C to-clone uploadpack.allowanysha1inwant true &&
+
+	test_terminal env GIT_PROGRESS_DELAY=0 \
+		scalar clone "file://$(pwd)/to-clone" "$enlistment" 2>stderr &&
+	grep "Enumerating objects" stderr >actual &&
+	test_line_count = 2 actual &&
+	cleanup_clone $enlistment
+'
+
+test_expect_success 'progress without tty' '
+	enlistment=progress2 &&
+
+	test_config -C to-clone uploadpack.allowfilter true &&
+	test_config -C to-clone uploadpack.allowanysha1inwant true &&
+
+	GIT_PROGRESS_DELAY=0 scalar clone "file://$(pwd)/to-clone" "$enlistment" 2>stderr &&
+	! grep "Enumerating objects" stderr &&
+	! grep "Updating files" stderr &&
+	cleanup_clone $enlistment
+'
+
+test_expect_success 'scalar clone warns when background maintenance fails' '
+	GIT_TEST_MAINT_SCHEDULER="crontab:false,launchctl:false,schtasks:false" \
+		scalar clone "file://$(pwd)/to-clone" maint-fail 2>err &&
+	grep "could not turn on maintenance" err
+'
+
 test_done
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index ff21a12..26c25c0 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -373,7 +373,7 @@
 
 test_expect_success 'cope with tagger-less tags' '
 
-	TAG=$(git hash-object -t tag -w tag-content) &&
+	TAG=$(git hash-object --literally -t tag -w tag-content) &&
 	git update-ref refs/tags/sonnenschein $TAG &&
 	git fast-export -C -C --signed-tags=strip --all > output &&
 	test $(grep -c "^tag " output) = 4 &&
diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh
index b105d6d..ccc8212 100755
--- a/t/t9700-perl-git.sh
+++ b/t/t9700-perl-git.sh
@@ -13,37 +13,36 @@
 
 # set up test repository
 
-test_expect_success \
-    'set up test repository' \
-    'echo "test file 1" > file1 &&
-     echo "test file 2" > file2 &&
-     mkdir directory1 &&
-     echo "in directory1" >> directory1/file &&
-     mkdir directory2 &&
-     echo "in directory2" >> directory2/file &&
-     git add . &&
-     git commit -m "first commit" &&
+test_expect_success 'set up test repository' '
+	echo "test file 1" >file1 &&
+	echo "test file 2" >file2 &&
+	mkdir directory1 &&
+	echo "in directory1" >>directory1/file &&
+	mkdir directory2 &&
+	echo "in directory2" >>directory2/file &&
+	git add . &&
+	git commit -m "first commit" &&
 
-     echo "new file in subdir 2" > directory2/file2 &&
-     git add . &&
-     git commit -m "commit in directory2" &&
+	echo "new file in subdir 2" >directory2/file2 &&
+	git add . &&
+	git commit -m "commit in directory2" &&
 
-     echo "changed file 1" > file1 &&
-     git commit -a -m "second commit" &&
+	echo "changed file 1" >file1 &&
+	git commit -a -m "second commit" &&
 
-     git config --add color.test.slot1 green &&
-     git config --add test.string value &&
-     git config --add test.dupstring value1 &&
-     git config --add test.dupstring value2 &&
-     git config --add test.booltrue true &&
-     git config --add test.boolfalse no &&
-     git config --add test.boolother other &&
-     git config --add test.int 2k &&
-     git config --add test.path "~/foo" &&
-     git config --add test.pathexpanded "$HOME/foo" &&
-     git config --add test.pathmulti foo &&
-     git config --add test.pathmulti bar
-     '
+	git config --add color.test.slot1 green &&
+	git config --add test.string value &&
+	git config --add test.dupstring value1 &&
+	git config --add test.dupstring value2 &&
+	git config --add test.booltrue true &&
+	git config --add test.boolfalse no &&
+	git config --add test.boolother other &&
+	git config --add test.int 2k &&
+	git config --add test.path "~/foo" &&
+	git config --add test.pathexpanded "$HOME/foo" &&
+	git config --add test.pathmulti foo &&
+	git config --add test.pathmulti bar
+'
 
 test_expect_success 'set up bare repository' '
 	git init --bare bare.git
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 43de868..d6c0478 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2255,6 +2255,36 @@
 	EOF
 '
 
+test_expect_success 'checkout does not match ref names of a different case' '
+	test_completion "git checkout M" ""
+'
+
+test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+	(
+		GIT_COMPLETION_IGNORE_CASE=1 &&
+		test_completion "git checkout M" <<-\EOF
+		main Z
+		mybranch Z
+		mytag Z
+		EOF
+	)
+'
+
+test_expect_success 'checkout completes pseudo refs' '
+	test_completion "git checkout H" <<-\EOF
+	HEAD Z
+	EOF
+'
+
+test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+	(
+		GIT_COMPLETION_IGNORE_CASE=1 &&
+		test_completion "git checkout h" <<-\EOF
+		HEAD Z
+		EOF
+	)
+'
+
 test_expect_success 'git -C <path> checkout uses the right repo' '
 	test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
 	branch-in-other Z
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 796093a..999d46f 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -32,6 +32,14 @@
 	export EDITOR
 }
 
+# Like test_set_editor but sets GIT_SEQUENCE_EDITOR instead of EDITOR
+test_set_sequence_editor () {
+	FAKE_SEQUENCE_EDITOR="$1"
+	export FAKE_SEQUENCE_EDITOR
+	GIT_SEQUENCE_EDITOR='"$FAKE_SEQUENCE_EDITOR"'
+	export GIT_SEQUENCE_EDITOR
+}
+
 test_decode_color () {
 	awk '
 		function name(n) {
@@ -1016,7 +1024,7 @@
 	fi
 
 	case "$1" in
-	git|__git*|test-tool|test_terminal)
+	git|__git*|scalar|test-tool|test_terminal)
 		return 0
 		;;
 	*)
@@ -1422,7 +1430,7 @@
 		BUG "test_bool_env requires two parameters (variable name and default value)"
 	fi
 
-	git env--helper --type=bool --default="$2" --exit-code "$1"
+	test-tool env-helper --type=bool --default="$2" --exit-code "$1"
 	ret=$?
 	case $ret in
 	0|1)	# unset or valid bool value
@@ -1450,72 +1458,6 @@
 	error "$2"
 }
 
-# The following mingw_* functions obey POSIX shell syntax, but are actually
-# bash scripts, and are meant to be used only with bash on Windows.
-
-# A test_cmp function that treats LF and CRLF equal and avoids to fork
-# diff when possible.
-mingw_test_cmp () {
-	# Read text into shell variables and compare them. If the results
-	# are different, use regular diff to report the difference.
-	local test_cmp_a= test_cmp_b=
-
-	# When text came from stdin (one argument is '-') we must feed it
-	# to diff.
-	local stdin_for_diff=
-
-	# Since it is difficult to detect the difference between an
-	# empty input file and a failure to read the files, we go straight
-	# to diff if one of the inputs is empty.
-	if test -s "$1" && test -s "$2"
-	then
-		# regular case: both files non-empty
-		mingw_read_file_strip_cr_ test_cmp_a <"$1"
-		mingw_read_file_strip_cr_ test_cmp_b <"$2"
-	elif test -s "$1" && test "$2" = -
-	then
-		# read 2nd file from stdin
-		mingw_read_file_strip_cr_ test_cmp_a <"$1"
-		mingw_read_file_strip_cr_ test_cmp_b
-		stdin_for_diff='<<<"$test_cmp_b"'
-	elif test "$1" = - && test -s "$2"
-	then
-		# read 1st file from stdin
-		mingw_read_file_strip_cr_ test_cmp_a
-		mingw_read_file_strip_cr_ test_cmp_b <"$2"
-		stdin_for_diff='<<<"$test_cmp_a"'
-	fi
-	test -n "$test_cmp_a" &&
-	test -n "$test_cmp_b" &&
-	test "$test_cmp_a" = "$test_cmp_b" ||
-	eval "diff -u \"\$@\" $stdin_for_diff"
-}
-
-# $1 is the name of the shell variable to fill in
-mingw_read_file_strip_cr_ () {
-	# Read line-wise using LF as the line separator
-	# and use IFS to strip CR.
-	local line
-	while :
-	do
-		if IFS=$'\r' read -r -d $'\n' line
-		then
-			# good
-			line=$line$'\n'
-		else
-			# we get here at EOF, but also if the last line
-			# was not terminated by LF; in the latter case,
-			# some text was read
-			if test -z "$line"
-			then
-				# EOF, really
-				break
-			fi
-		fi
-		eval "$1=\$$1\$line"
-	done
-}
-
 # Like "env FOO=BAR some-program", but run inside a subshell, which means
 # it also works for shell functions (though those functions cannot impact
 # the environment outside of the test_env invocation).
@@ -1682,7 +1624,7 @@
 	then
 		BUG "undefined key '$1'"
 	fi &&
-	eval "printf '%s' \"\${$var}\""
+	eval "printf '%s\n' \"\${$var}\""
 }
 
 # Insert a slash into an object ID so it can be used to reference a location
@@ -1751,6 +1693,13 @@
 	return 1
 }
 
+# Poor man's URI escaping. Good enough for the test suite whose trash
+# directory has a space in it. See 93c3fcbe4d4 (git-svn: attempt to
+# mimic SVN 1.7 URL canonicalization, 2012-07-28) for prior art.
+test_uri_escape() {
+	sed 's/ /%20/g'
+}
+
 # Check that the given command was invoked as part of the
 # trace2-format trace on stdin.
 #
@@ -1826,6 +1775,14 @@
 	return 0
 }
 
+# Given a GIT_TRACE2_EVENT log over stdin, writes to stdout a list of URLs
+# sent to git-remote-https child processes.
+test_remote_https_urls() {
+	grep -e '"event":"child_start".*"argv":\["git-remote-https",".*"\]' |
+		sed -e 's/{"event":"child_start".*"argv":\["git-remote-https","//g' \
+		    -e 's/"\]}//g'
+}
+
 # Print the destination of symlink(s) provided as arguments. Basically
 # the same as the readlink command, but it's not available everywhere.
 test_readlink () {
@@ -1875,3 +1832,11 @@
 	sort config-actual >sorted-actual &&
 	test_cmp sorted-expect sorted-actual
 }
+
+# Given a filename, extract its trailing hash as a hex string
+test_trailing_hash () {
+	local file="$1" &&
+	tail -c $(test_oid rawsz) "$file" |
+		test-tool hexdump |
+		sed "s/ //g"
+}
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 251b22b..93df6d6 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -646,12 +646,6 @@
 
 export _x05 _x35 LF u200c EMPTY_TREE EMPTY_BLOB ZERO_OID OID_REGEX
 
-# Each test should start with something like this, after copyright notices:
-#
-# test_description='Description of this test...
-# This test checks if command xyzzy does the right thing...
-# '
-# . ./test-lib.sh
 test "x$TERM" != "xdumb" && (
 		test -t 1 &&
 		tput bold >/dev/null 2>&1 &&
@@ -1543,8 +1537,8 @@
 	# Normalize with test_bool_env
 	passes_sanitize_leak=
 
-	# We need to see TEST_PASSES_SANITIZE_LEAK in "git
-	# env--helper" (via test_bool_env)
+	# We need to see TEST_PASSES_SANITIZE_LEAK in "test-tool
+	# env-helper" (via test_bool_env)
 	export TEST_PASSES_SANITIZE_LEAK
 	if test_bool_env TEST_PASSES_SANITIZE_LEAK false
 	then
@@ -1683,7 +1677,7 @@
 # The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and
 # thus needs to be set up really early, and set an internal variable
 # for convenience so the hot test_set_prereq() codepath doesn't need
-# to call "git env--helper" (via test_bool_env). Only do that work
+# to call "test-tool env-helper" (via test_bool_env). Only do that work
 # if needed by seeing if GIT_TEST_FAIL_PREREQS is set at all.
 GIT_TEST_FAIL_PREREQS_INTERNAL=
 if test -n "$GIT_TEST_FAIL_PREREQS"
@@ -1722,7 +1716,7 @@
 	test_set_prereq SED_STRIPS_CR
 	test_set_prereq GREP_STRIPS_CR
 	test_set_prereq WINDOWS
-	GIT_TEST_CMP=mingw_test_cmp
+	GIT_TEST_CMP="GIT_DIR=/dev/null git diff --no-index --ignore-cr-at-eol --"
 	;;
 *CYGWIN*)
 	test_set_prereq POSIXPERM
@@ -1938,10 +1932,6 @@
 	esac
 '
 
-test_lazy_prereq ADD_I_USE_BUILTIN '
-	test_bool_env GIT_TEST_ADD_I_USE_BUILTIN true
-'
-
 # Ensure that no test accidentally triggers a Git command
 # that runs the actual maintenance scheduler, affecting a user's
 # system permanently.
diff --git a/trace.c b/trace.c
index 794a087..efa4e2d 100644
--- a/trace.c
+++ b/trace.c
@@ -291,10 +291,9 @@ static const char *quote_crnl(const char *path)
 	return new_path.buf;
 }
 
-/* FIXME: move prefix to startup_info struct and get rid of this arg */
-void trace_repo_setup(const char *prefix)
+void trace_repo_setup(void)
 {
-	const char *git_work_tree;
+	const char *git_work_tree, *prefix = startup_info->prefix;
 	char *cwd;
 
 	if (!trace_want(&trace_setup_key))
@@ -305,7 +304,7 @@ void trace_repo_setup(const char *prefix)
 	if (!(git_work_tree = get_git_work_tree()))
 		git_work_tree = "(null)";
 
-	if (!prefix)
+	if (!startup_info->prefix)
 		prefix = "(null)";
 
 	trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
diff --git a/trace.h b/trace.h
index 4e771f8..b6e35b9 100644
--- a/trace.h
+++ b/trace.h
@@ -93,7 +93,7 @@ extern struct trace_key trace_default_key;
 extern struct trace_key trace_perf_key;
 extern struct trace_key trace_setup_key;
 
-void trace_repo_setup(const char *prefix);
+void trace_repo_setup(void);
 
 /**
  * Checks whether the trace key is enabled. Used to prevent expensive
diff --git a/transport-helper.c b/transport-helper.c
index e95267a..3ea7c2b 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -1267,9 +1267,22 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
 	return ret;
 }
 
+static int get_bundle_uri(struct transport *transport)
+{
+	get_helper(transport);
+
+	if (process_connect(transport, 0)) {
+		do_take_over(transport);
+		return transport->vtable->get_bundle_uri(transport);
+	}
+
+	return -1;
+}
+
 static struct transport_vtable vtable = {
 	.set_option	= set_helper_option,
 	.get_refs_list	= get_refs_list,
+	.get_bundle_uri = get_bundle_uri,
 	.fetch_refs	= fetch_refs,
 	.push_refs	= push_refs,
 	.connect	= connect_helper,
diff --git a/transport-internal.h b/transport-internal.h
index c4ca0b7..90ea749 100644
--- a/transport-internal.h
+++ b/transport-internal.h
@@ -27,6 +27,13 @@ struct transport_vtable {
 				     struct transport_ls_refs_options *transport_options);
 
 	/**
+	 * Populates the remote side's bundle-uri under protocol v2,
+	 * if the "bundle-uri" capability was advertised. Returns 0 if
+	 * OK, negative values on error.
+	 */
+	int (*get_bundle_uri)(struct transport *transport);
+
+	/**
 	 * Fetch the objects for the given refs. Note that this gets
 	 * an array, and should ignore the list structure.
 	 *
diff --git a/transport.c b/transport.c
index e7b9719..77a61a9 100644
--- a/transport.c
+++ b/transport.c
@@ -22,6 +22,7 @@
 #include "protocol.h"
 #include "object-store.h"
 #include "color.h"
+#include "bundle-uri.h"
 
 static int transport_use_color = -1;
 static char transport_colors[][COLOR_MAXLEN] = {
@@ -197,7 +198,7 @@ struct git_transport_data {
 	struct git_transport_options options;
 	struct child_process *conn;
 	int fd[2];
-	unsigned got_remote_heads : 1;
+	unsigned finished_handshake : 1;
 	enum protocol_version version;
 	struct oid_array extra_have;
 	struct oid_array shallow;
@@ -344,7 +345,7 @@ static struct ref *handshake(struct transport *transport, int for_push,
 	case protocol_unknown_version:
 		BUG("unknown protocol version");
 	}
-	data->got_remote_heads = 1;
+	data->finished_handshake = 1;
 	transport->hash_algo = reader.hash_algo;
 
 	if (reader.line_peeked)
@@ -359,6 +360,39 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
 	return handshake(transport, for_push, options, 1);
 }
 
+static int get_bundle_uri(struct transport *transport)
+{
+	struct git_transport_data *data = transport->data;
+	struct packet_reader reader;
+	int stateless_rpc = transport->stateless_rpc;
+
+	if (!transport->bundles) {
+		CALLOC_ARRAY(transport->bundles, 1);
+		init_bundle_list(transport->bundles);
+	}
+
+	if (!data->finished_handshake) {
+		struct ref *refs = handshake(transport, 0, NULL, 0);
+
+		if (refs)
+			free_refs(refs);
+	}
+
+	/*
+	 * "Support" protocol v0 and v2 without bundle-uri support by
+	 * silently degrading to a NOOP.
+	 */
+	if (!server_supports_v2("bundle-uri"))
+		return 0;
+
+	packet_reader_init(&reader, data->fd[0], NULL, 0,
+			   PACKET_READ_CHOMP_NEWLINE |
+			   PACKET_READ_GENTLE_ON_EOF);
+
+	return get_remote_bundle_uri(data->fd[1], &reader,
+				     transport->bundles, stateless_rpc);
+}
+
 static int fetch_refs_via_pack(struct transport *transport,
 			       int nr_heads, struct ref **to_fetch)
 {
@@ -394,7 +428,7 @@ static int fetch_refs_via_pack(struct transport *transport,
 	args.negotiation_tips = data->options.negotiation_tips;
 	args.reject_shallow_remote = transport->smart_options->reject_shallow;
 
-	if (!data->got_remote_heads) {
+	if (!data->finished_handshake) {
 		int i;
 		int must_list_refs = 0;
 		for (i = 0; i < nr_heads; i++) {
@@ -434,7 +468,7 @@ static int fetch_refs_via_pack(struct transport *transport,
 			  to_fetch, nr_heads, &data->shallow,
 			  &transport->pack_lockfiles, data->version);
 
-	data->got_remote_heads = 0;
+	data->finished_handshake = 0;
 	data->options.self_contained_and_connected =
 		args.self_contained_and_connected;
 	data->options.connectivity_checked = args.connectivity_checked;
@@ -819,7 +853,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
 	if (transport_color_config() < 0)
 		return -1;
 
-	if (!data->got_remote_heads)
+	if (!data->finished_handshake)
 		get_refs_via_connect(transport, 1, NULL);
 
 	memset(&args, 0, sizeof(args));
@@ -867,7 +901,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
 	else
 		ret = finish_connect(data->conn);
 	data->conn = NULL;
-	data->got_remote_heads = 0;
+	data->finished_handshake = 0;
 
 	return ret;
 }
@@ -887,7 +921,7 @@ static int disconnect_git(struct transport *transport)
 {
 	struct git_transport_data *data = transport->data;
 	if (data->conn) {
-		if (data->got_remote_heads && !transport->stateless_rpc)
+		if (data->finished_handshake && !transport->stateless_rpc)
 			packet_flush(data->fd[1]);
 		close(data->fd[0]);
 		if (data->fd[1] >= 0)
@@ -902,6 +936,7 @@ static int disconnect_git(struct transport *transport)
 
 static struct transport_vtable taken_over_vtable = {
 	.get_refs_list	= get_refs_via_connect,
+	.get_bundle_uri = get_bundle_uri,
 	.fetch_refs	= fetch_refs_via_pack,
 	.push_refs	= git_transport_push,
 	.disconnect	= disconnect_git
@@ -921,7 +956,7 @@ void transport_take_over(struct transport *transport,
 	data->conn = child;
 	data->fd[0] = data->conn->out;
 	data->fd[1] = data->conn->in;
-	data->got_remote_heads = 0;
+	data->finished_handshake = 0;
 	transport->data = data;
 
 	transport->vtable = &taken_over_vtable;
@@ -1054,6 +1089,7 @@ static struct transport_vtable bundle_vtable = {
 
 static struct transport_vtable builtin_smart_vtable = {
 	.get_refs_list	= get_refs_via_connect,
+	.get_bundle_uri = get_bundle_uri,
 	.fetch_refs	= fetch_refs_via_pack,
 	.push_refs	= git_transport_push,
 	.connect	= connect_git,
@@ -1068,6 +1104,9 @@ struct transport *transport_get(struct remote *remote, const char *url)
 	ret->progress = isatty(2);
 	string_list_init_dup(&ret->pack_lockfiles);
 
+	CALLOC_ARRAY(ret->bundles, 1);
+	init_bundle_list(ret->bundles);
+
 	if (!remote)
 		BUG("No remote provided to transport_get()");
 
@@ -1118,7 +1157,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
 		ret->smart_options = &(data->options);
 
 		data->conn = NULL;
-		data->got_remote_heads = 0;
+		data->finished_handshake = 0;
 	} else {
 		/* Unknown protocol in URL. Pass to external handler. */
 		int len = external_specification_len(url);
@@ -1482,6 +1521,34 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
 	return rc;
 }
 
+int transport_get_remote_bundle_uri(struct transport *transport)
+{
+	int value = 0;
+	const struct transport_vtable *vtable = transport->vtable;
+
+	/* Check config only once. */
+	if (transport->got_remote_bundle_uri)
+		return 0;
+	transport->got_remote_bundle_uri = 1;
+
+	/*
+	 * Don't request bundle-uri from the server unless configured to
+	 * do so by the transfer.bundleURI=true config option.
+	 */
+	if (git_config_get_bool("transfer.bundleuri", &value) || !value)
+		return 0;
+
+	if (!transport->bundles->baseURI)
+		transport->bundles->baseURI = xstrdup(transport->url);
+
+	if (!vtable->get_bundle_uri)
+		return error(_("bundle-uri operation not supported by protocol"));
+
+	if (vtable->get_bundle_uri(transport) < 0)
+		return error(_("could not retrieve server-advertised bundle-uri list"));
+	return 0;
+}
+
 void transport_unlock_pack(struct transport *transport, unsigned int flags)
 {
 	int in_signal_handler = !!(flags & TRANSPORT_UNLOCK_PACK_IN_SIGNAL_HANDLER);
@@ -1512,6 +1579,8 @@ int transport_disconnect(struct transport *transport)
 		ret = transport->vtable->disconnect(transport);
 	if (transport->got_remote_refs)
 		free_refs((void *)transport->remote_refs);
+	clear_bundle_list(transport->bundles);
+	free(transport->bundles);
 	free(transport);
 	return ret;
 }
diff --git a/transport.h b/transport.h
index b5bf7b3..85150f5 100644
--- a/transport.h
+++ b/transport.h
@@ -62,6 +62,7 @@ enum transport_family {
 	TRANSPORT_FAMILY_IPV6
 };
 
+struct bundle_list;
 struct transport {
 	const struct transport_vtable *vtable;
 
@@ -76,6 +77,18 @@ struct transport {
 	 */
 	unsigned got_remote_refs : 1;
 
+	/**
+	 * Indicates whether we already called get_bundle_uri_list(); set by
+	 * transport.c::transport_get_remote_bundle_uri().
+	 */
+	unsigned got_remote_bundle_uri : 1;
+
+	/*
+	 * The results of "command=bundle-uri", if both sides support
+	 * the "bundle-uri" capability.
+	 */
+	struct bundle_list *bundles;
+
 	/*
 	 * Transports that call take-over destroys the data specific to
 	 * the transport type while doing so, and cannot be reused.
@@ -281,6 +294,12 @@ void transport_ls_refs_options_release(struct transport_ls_refs_options *opts);
 const struct ref *transport_get_remote_refs(struct transport *transport,
 					    struct transport_ls_refs_options *transport_options);
 
+/**
+ * Retrieve bundle URI(s) from a remote. Populates "struct
+ * transport"'s "bundle_uri" and "got_remote_bundle_uri".
+ */
+int transport_get_remote_bundle_uri(struct transport *transport);
+
 /*
  * Fetch the hash algorithm used by a remote.
  *
diff --git a/unpack-trees.c b/unpack-trees.c
index d11bef9..3d05e45 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -70,7 +70,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
 	  ? ((o)->msgs[(type)])      \
 	  : (unpack_plumbing_errors[(type)]) )
 
-static const char *super_prefixed(const char *path)
+static const char *super_prefixed(const char *path, const char *super_prefix)
 {
 	/*
 	 * It is necessary and sufficient to have two static buffers
@@ -82,7 +82,6 @@ static const char *super_prefixed(const char *path)
 	static unsigned idx = ARRAY_SIZE(buf) - 1;
 
 	if (super_prefix_len < 0) {
-		const char *super_prefix = get_super_prefix();
 		if (!super_prefix) {
 			super_prefix_len = 0;
 		} else {
@@ -235,7 +234,8 @@ static int add_rejected_path(struct unpack_trees_options *o,
 		return -1;
 
 	if (!o->show_all_errors)
-		return error(ERRORMSG(o, e), super_prefixed(path));
+		return error(ERRORMSG(o, e), super_prefixed(path,
+							    o->super_prefix));
 
 	/*
 	 * Otherwise, insert in a list for future display by
@@ -262,7 +262,8 @@ static void display_error_msgs(struct unpack_trees_options *o)
 			error_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			error(ERRORMSG(o, e), super_prefixed(path.buf));
+			error(ERRORMSG(o, e), super_prefixed(path.buf,
+							     o->super_prefix));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -289,7 +290,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)
 			warning_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			warning(ERRORMSG(o, e), super_prefixed(path.buf));
+			warning(ERRORMSG(o, e), super_prefixed(path.buf,
+							       o->super_prefix));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -311,7 +313,8 @@ static int check_submodule_move_head(const struct cache_entry *ce,
 	if (o->reset)
 		flags |= SUBMODULE_MOVE_HEAD_FORCE;
 
-	if (submodule_move_head(ce->name, old_id, new_id, flags))
+	if (submodule_move_head(ce->name, o->super_prefix, old_id, new_id,
+				flags))
 		return add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
 	return 0;
 }
@@ -414,6 +417,7 @@ static int check_updates(struct unpack_trees_options *o,
 	int i, pc_workers, pc_threshold;
 
 	trace_performance_enter();
+	state.super_prefix = o->super_prefix;
 	state.force = 1;
 	state.quiet = 1;
 	state.refresh_cache = 1;
@@ -444,7 +448,7 @@ static int check_updates(struct unpack_trees_options *o,
 
 		if (ce->ce_flags & CE_WT_REMOVE) {
 			display_progress(progress, ++cnt);
-			unlink_entry(ce);
+			unlink_entry(ce, o->super_prefix);
 		}
 	}
 
@@ -1876,7 +1880,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 	prepare_repo_settings(repo);
 	if (repo->settings.command_requires_full_index) {
 		ensure_full_index(o->src_index);
-		ensure_full_index(o->dst_index);
+		if (o->dst_index)
+			ensure_full_index(o->dst_index);
 	}
 
 	if (o->reset == UNPACK_RESET_OVERWRITE_UNTRACKED &&
@@ -1900,7 +1905,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 		populate_from_existing_patterns(o, &pl);
 	}
 
-	memset(&o->result, 0, sizeof(o->result));
+	index_state_init(&o->result, o->src_index->repo);
 	o->result.initialized = 1;
 	o->result.timestamp.sec = o->src_index->timestamp.sec;
 	o->result.timestamp.nsec = o->src_index->timestamp.nsec;
@@ -2958,8 +2963,8 @@ int bind_merge(const struct cache_entry * const *src,
 	if (a && old)
 		return o->quiet ? -1 :
 			error(ERRORMSG(o, ERROR_BIND_OVERLAP),
-			      super_prefixed(a->name),
-			      super_prefixed(old->name));
+			      super_prefixed(a->name, o->super_prefix),
+			      super_prefixed(old->name, o->super_prefix));
 	if (!a)
 		return keep_entry(old, o);
 	else
@@ -3020,7 +3025,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,
 
 	if (worktree && untracked)
 		return error(_("worktree and untracked commit have duplicate entries: %s"),
-			     super_prefixed(worktree->name));
+			     super_prefixed(worktree->name, o->super_prefix));
 
 	return merged_entry(worktree ? worktree : untracked, NULL, o);
 }
diff --git a/unpack-trees.h b/unpack-trees.h
index 6ab0d74..3a7b3e5 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -75,6 +75,7 @@ struct unpack_trees_options {
 		     skip_cache_tree_update;
 	enum unpack_trees_reset_type reset;
 	const char *prefix;
+	const char *super_prefix;
 	int cache_bottom;
 	struct pathspec *pathspec;
 	merge_fn_t fn;
diff --git a/urlmatch.c b/urlmatch.c
index b615adc..620a648 100644
--- a/urlmatch.c
+++ b/urlmatch.c
@@ -209,7 +209,7 @@ static char *url_normalize_1(const char *url, struct url_info *out_info, char al
 	 */
 	if (!url_len || strchr(":/?#", *url)) {
 		/* Missing host invalid for all URL schemes except file */
-		if (strncmp(norm.buf, "file:", 5)) {
+		if (!starts_with(norm.buf, "file:")) {
 			if (out_info) {
 				out_info->url = NULL;
 				out_info->err = _("missing host and scheme is not 'file:'");
@@ -268,11 +268,11 @@ static char *url_normalize_1(const char *url, struct url_info *out_info, char al
 		if (url == slash_ptr) {
 			/* Skip ":" port with no number, it's same as default */
 		} else if (slash_ptr - url == 2 &&
-			   !strncmp(norm.buf, "http:", 5) &&
+			   starts_with(norm.buf, "http:") &&
 			   !strncmp(url, "80", 2)) {
 			/* Skip http :80 as it's the default */
 		} else if (slash_ptr - url == 3 &&
-			   !strncmp(norm.buf, "https:", 6) &&
+			   starts_with(norm.buf, "https:") &&
 			   !strncmp(url, "443", 3)) {
 			/* Skip https :443 as it's the default */
 		} else {
diff --git a/userdiff.c b/userdiff.c
index e25356a..58a3d59 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -170,8 +170,8 @@ PATTERNS("html",
 	 "[^<>= \t]+"),
 PATTERNS("java",
 	 "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
-	 /* Class, enum, and interface declarations */
-	 "^[ \t]*(([a-z]+[ \t]+)*(class|enum|interface)[ \t]+[A-Za-z][A-Za-z0-9_$]*[ \t]+.*)$\n"
+	 /* Class, enum, interface, and record declarations */
+	 "^[ \t]*(([a-z-]+[ \t]+)*(class|enum|interface|record)[ \t]+.*)$\n"
 	 /* Method definitions; note that constructor signatures are not */
 	 /* matched because they are indistinguishable from method calls. */
 	 "^[ \t]*(([A-Za-z_<>&][][?&<>.,A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$",
@@ -293,7 +293,7 @@ PATTERNS("scheme",
 	 "|([^][)(}{[ \t])+"),
 PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
 	 "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"),
-{ "default", NULL, -1, { NULL, 0 } },
+{ "default", NULL, NULL, -1, { NULL, 0 } },
 };
 #undef PATTERNS
 #undef IPATTERN
@@ -394,6 +394,8 @@ int userdiff_config(const char *k, const char *v)
 		return parse_bool(&drv->textconv_want_cache, k, v);
 	if (!strcmp(type, "wordregex"))
 		return git_config_string(&drv->word_regex, k, v);
+	if (!strcmp(type, "algorithm"))
+		return git_config_string(&drv->algorithm, k, v);
 
 	return 0;
 }
@@ -413,7 +415,7 @@ struct userdiff_driver *userdiff_find_by_path(struct index_state *istate,
 		check = attr_check_initl("diff", NULL);
 	if (!path)
 		return NULL;
-	git_check_attr(istate, path, check);
+	git_check_attr(istate, NULL, path, check);
 
 	if (ATTR_TRUE(check->items[0].value))
 		return &driver_true;
diff --git a/userdiff.h b/userdiff.h
index aee91bc..24419db 100644
--- a/userdiff.h
+++ b/userdiff.h
@@ -14,6 +14,7 @@ struct userdiff_funcname {
 struct userdiff_driver {
 	const char *name;
 	const char *external;
+	const char *algorithm;
 	int binary;
 	struct userdiff_funcname funcname;
 	const char *word_regex;
diff --git a/ws.c b/ws.c
index 46a77bc..da3d0e2 100644
--- a/ws.c
+++ b/ws.c
@@ -29,6 +29,7 @@ unsigned parse_whitespace_rule(const char *string)
 		int i;
 		size_t len;
 		const char *ep;
+		const char *arg;
 		int negated = 0;
 
 		string = string + strspn(string, ", \t\n\r");
@@ -52,15 +53,15 @@ unsigned parse_whitespace_rule(const char *string)
 				rule |= whitespace_rule_names[i].rule_bits;
 			break;
 		}
-		if (strncmp(string, "tabwidth=", 9) == 0) {
-			unsigned tabwidth = atoi(string + 9);
+		if (skip_prefix(string, "tabwidth=", &arg)) {
+			unsigned tabwidth = atoi(arg);
 			if (0 < tabwidth && tabwidth < 0100) {
 				rule &= ~WS_TAB_WIDTH_MASK;
 				rule |= tabwidth;
 			}
 			else
 				warning("tabwidth %.*s out of range",
-					(int)(len - 9), string + 9);
+					(int)(ep - arg), arg);
 		}
 		string = ep;
 	}
@@ -78,7 +79,7 @@ unsigned whitespace_rule(struct index_state *istate, const char *pathname)
 	if (!attr_whitespace_rule)
 		attr_whitespace_rule = attr_check_initl("whitespace", NULL);
 
-	git_check_attr(istate, pathname, attr_whitespace_rule);
+	git_check_attr(istate, NULL, pathname, attr_whitespace_rule);
 	value = attr_whitespace_rule->items[0].value;
 	if (ATTR_TRUE(value)) {
 		/* true (whitespace) */
diff --git a/wt-status.c b/wt-status.c
index 76e37a8..3162241 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -18,8 +18,10 @@
 #include "worktree.h"
 #include "lockfile.h"
 #include "sequencer.h"
+#include "fsmonitor-settings.h"
 
 #define AB_DELAY_WARNING_IN_MS (2 * 1000)
+#define UF_DELAY_WARNING_IN_MS (2 * 1000)
 
 static const char cut_line[] =
 "------------------------ >8 ------------------------\n";
@@ -1205,6 +1207,13 @@ static void wt_longstatus_print_tracking(struct wt_status *s)
 	strbuf_release(&sb);
 }
 
+static int uf_was_slow(struct wt_status *s)
+{
+	if (getenv("GIT_TEST_UF_DELAY_WARNING"))
+		s->untracked_in_ms = 3250;
+	return UF_DELAY_WARNING_IN_MS < s->untracked_in_ms;
+}
+
 static void show_merge_in_progress(struct wt_status *s,
 				   const char *color)
 {
@@ -1814,6 +1823,7 @@ static void wt_longstatus_print(struct wt_status *s)
 {
 	const char *branch_color = color(WT_STATUS_ONBRANCH, s);
 	const char *branch_status_color = color(WT_STATUS_HEADER, s);
+	enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(s->repo);
 
 	if (s->branch) {
 		const char *on_what = _("On branch ");
@@ -1870,13 +1880,21 @@ static void wt_longstatus_print(struct wt_status *s)
 		wt_longstatus_print_other(s, &s->untracked, _("Untracked files"), "add");
 		if (s->show_ignored_mode)
 			wt_longstatus_print_other(s, &s->ignored, _("Ignored files"), "add -f");
-		if (advice_enabled(ADVICE_STATUS_U_OPTION) && 2000 < s->untracked_in_ms) {
+		if (advice_enabled(ADVICE_STATUS_U_OPTION) && uf_was_slow(s)) {
 			status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");
+			if (fsm_mode > FSMONITOR_MODE_DISABLED) {
+				status_printf_ln(s, GIT_COLOR_NORMAL,
+						_("It took %.2f seconds to enumerate untracked files,\n"
+						"but the results were cached, and subsequent runs may be faster."),
+						s->untracked_in_ms / 1000.0);
+			} else {
+				status_printf_ln(s, GIT_COLOR_NORMAL,
+						_("It took %.2f seconds to enumerate untracked files."),
+						s->untracked_in_ms / 1000.0);
+			}
 			status_printf_ln(s, GIT_COLOR_NORMAL,
-					 _("It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-					   "may speed it up, but you have to be careful not to forget to add\n"
-					   "new files yourself (see 'git help status')."),
-					 s->untracked_in_ms / 1000.0);
+					_("See 'git help status' for information on how to improve this."));
+			status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");
 		}
 	} else if (s->committable)
 		status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),