Sync with 2.48.2

* maint-2.48:
  Git 2.48.2
  Git 2.47.3
  Git 2.46.4
  Git 2.45.4
  Git 2.44.4
  Git 2.43.7
  wincred: avoid buffer overflow in wcsncat()
  bundle-uri: fix arbitrary file writes via parameter injection
  config: quote values containing CR character
  git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls
  git-gui: do not mistake command arguments as redirection operators
  git-gui: introduce function git_redir for git calls with redirections
  git-gui: pass redirections as separate argument to git_read
  git-gui: pass redirections as separate argument to _open_stdout_stderr
  git-gui: convert git_read*, git_write to be non-variadic
  git-gui: override exec and open only on Windows
  gitk: sanitize 'open' arguments: revisit recently updated 'open' calls
  git-gui: use git_read in githook_read
  git-gui: sanitize $PATH on all platforms
  git-gui: break out a separate function git_read_nice
  git-gui: assure PATH has only absolute elements.
  git-gui: remove option --stderr from git_read
  git-gui: cleanup git-bash menu item
  git-gui: sanitize 'exec' arguments: background
  git-gui: avoid auto_execok in do_windows_shortcut
  git-gui: sanitize 'exec' arguments: simple cases
  git-gui: avoid auto_execok for git-bash menu item
  git-gui: treat file names beginning with "|" as relative paths
  git-gui: remove unused proc is_shellscript
  git-gui: remove git config --list handling for git < 1.5.3
  git-gui: remove special treatment of Windows from open_cmd_pipe
  git-gui: remove HEAD detachment implementation for git < 1.5.3
  git-gui: use only the configured shell
  git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
  git-gui: make _shellpath usable on startup
  git-gui: use [is_Windows], not bad _shellpath
  git-gui: _which, only add .exe suffix if not present
  gitk: encode arguments correctly with "open"
  gitk: sanitize 'open' arguments: command pipeline
  gitk: collect construction of blameargs into a single conditional
  gitk: sanitize 'open' arguments: simple commands, readable and writable
  gitk: sanitize 'open' arguments: simple commands with redirections
  gitk: sanitize 'open' arguments: simple commands
  gitk: sanitize 'exec' arguments: redirect to process
  gitk: sanitize 'exec' arguments: redirections and background
  gitk: sanitize 'exec' arguments: redirections
  gitk: sanitize 'exec' arguments: 'eval exec'
  gitk: sanitize 'exec' arguments: simple cases
  gitk: have callers of diffcmd supply pipe symbol when necessary
  gitk: treat file names beginning with "|" as relative paths

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/.editorconfig b/.editorconfig
index 15d6cbe..2d3929b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -4,7 +4,7 @@
 
 # The settings for C (*.c and *.h) files are mirrored in .clang-format.  Keep
 # them in sync.
-[{*.{c,h,sh,perl,pl,pm,txt},config.mak.*,Makefile}]
+[{*.{c,h,sh,bash,perl,pl,pm,txt,adoc},config.mak.*,Makefile}]
 indent_style = tab
 tab_width = 8
 
diff --git a/.gitattributes b/.gitattributes
index 158c3d4..c6a0b35 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -7,12 +7,12 @@
 *.py text eol=lf diff=python
 *.bat text eol=crlf
 CODE_OF_CONDUCT.md -whitespace
-/Documentation/**/*.txt text eol=lf
+/Documentation/**/*.adoc 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
+/Documentation/git-merge.adoc conflict-marker-size=32
+/Documentation/gitk.adoc conflict-marker-size=32
+/Documentation/user-manual.adoc conflict-marker-size=32
 /t/t????-*.sh conflict-marker-size=32
diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
index 48341e8..124301d 100644
--- a/.github/workflows/coverity.yml
+++ b/.github/workflows/coverity.yml
@@ -45,7 +45,7 @@
       - run: ci/install-dependencies.sh
         if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos')
         env:
-          distro: ${{ matrix.os }}
+          CI_JOB_IMAGE: ${{ matrix.os }}
 
       # The Coverity site says the tool is usually updated twice yearly, so the
       # MD5 of download can be used to determine whether there's been an update.
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 900be99..1c8260e 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -248,6 +248,58 @@
       with:
         name: failed-tests-windows-vs-${{ matrix.nr }}
         path: ${{env.FAILED_TEST_ARTIFACTS}}
+
+  windows-meson-build:
+    name: win+Meson build
+    needs: ci-config
+    if: needs.ci-config.outputs.enabled == 'yes'
+    runs-on: windows-latest
+    concurrency:
+      group: windows-meson-build-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    steps:
+    - uses: actions/checkout@v4
+    - uses: actions/setup-python@v5
+    - name: Set up dependencies
+      shell: pwsh
+      run: pip install meson ninja
+    - name: Setup
+      shell: pwsh
+      run: meson setup build -Dperl=disabled -Dcredential_helpers=wincred
+    - name: Compile
+      shell: pwsh
+      run: meson compile -C build
+    - name: Upload build artifacts
+      uses: actions/upload-artifact@v4
+      with:
+        name: windows-meson-artifacts
+        path: build
+  windows-meson-test:
+    name: win+Meson test
+    runs-on: windows-latest
+    needs: [ci-config, windows-meson-build]
+    strategy:
+      fail-fast: false
+      matrix:
+        nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+    concurrency:
+      group: windows-meson-test-${{ matrix.nr }}-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    steps:
+    - uses: actions/checkout@v4
+    - uses: actions/setup-python@v5
+    - name: Set up dependencies
+      shell: pwsh
+      run: pip install meson ninja
+    - name: Download build artifacts
+      uses: actions/download-artifact@v4
+      with:
+        name: windows-meson-artifacts
+        path: build
+    - name: Test
+      shell: pwsh
+      run: meson test -C build --list | Select-Object -Skip 1 | Select-String .* | Group-Object -Property { $_.LineNumber % 10 } | Where-Object Name -EQ ${{ matrix.nr }} | ForEach-Object { meson test -C build --no-rebuild --print-errorlogs $_.Group }
+
   regular:
     name: ${{matrix.vector.jobname}} (${{matrix.vector.pool}})
     needs: ci-config
@@ -259,20 +311,6 @@
       fail-fast: false
       matrix:
         vector:
-          - jobname: linux-sha256
-            cc: clang
-            pool: ubuntu-latest
-          - jobname: linux-reftable
-            cc: clang
-            pool: ubuntu-latest
-          - jobname: linux-gcc
-            cc: gcc
-            cc_package: gcc-8
-            pool: ubuntu-20.04
-          - jobname: linux-TEST-vars
-            cc: gcc
-            cc_package: gcc-8
-            pool: ubuntu-20.04
           - jobname: osx-clang
             cc: clang
             pool: macos-13
@@ -285,26 +323,11 @@
           - jobname: osx-meson
             cc: clang
             pool: macos-13
-          - jobname: linux-gcc-default
-            cc: gcc
-            pool: ubuntu-latest
-          - jobname: linux-leaks
-            cc: gcc
-            pool: ubuntu-latest
-          - jobname: linux-reftable-leaks
-            cc: gcc
-            pool: ubuntu-latest
-          - jobname: linux-asan-ubsan
-            cc: clang
-            pool: ubuntu-latest
-          - jobname: linux-meson
-            cc: gcc
-            pool: ubuntu-latest
     env:
       CC: ${{matrix.vector.cc}}
       CC_PACKAGE: ${{matrix.vector.cc_package}}
       jobname: ${{matrix.vector.jobname}}
-      distro: ${{matrix.vector.pool}}
+      CI_JOB_IMAGE: ${{matrix.vector.pool}}
       TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t
     runs-on: ${{matrix.vector.pool}}
     steps:
@@ -342,27 +365,48 @@
       fail-fast: false
       matrix:
         vector:
-        - jobname: linux-musl
-          image: alpine
-          distro: alpine-latest
+        - jobname: linux-sha256
+          image: ubuntu:rolling
+          cc: clang
+        - jobname: linux-reftable
+          image: ubuntu:rolling
+          cc: clang
+        - jobname: linux-TEST-vars
+          image: ubuntu:20.04
+          cc: gcc
+          cc_package: gcc-8
+        - jobname: linux-breaking-changes
+          cc: gcc
+          image: ubuntu:rolling
+        - jobname: linux-leaks
+          image: ubuntu:rolling
+          cc: gcc
+        - jobname: linux-reftable-leaks
+          image: ubuntu:rolling
+          cc: gcc
+        - jobname: linux-asan-ubsan
+          image: ubuntu:rolling
+          cc: clang
+        - jobname: linux-meson
+          image: ubuntu:rolling
+          cc: gcc
+        - jobname: linux-musl-meson
+          image: alpine:latest
         # Supported until 2025-04-02.
         - jobname: linux32
           image: i386/ubuntu:focal
-          distro: ubuntu32-20.04
         - jobname: pedantic
-          image: fedora
-          distro: fedora-latest
+          image: fedora:latest
         # A RHEL 8 compatible distro.  Supported until 2029-05-31.
         - jobname: almalinux-8
           image: almalinux:8
-          distro: almalinux-8
         # Supported until 2026-08-31.
         - jobname: debian-11
           image: debian:11
-          distro: debian-11
     env:
       jobname: ${{matrix.vector.jobname}}
-      distro: ${{matrix.vector.distro}}
+      CC: ${{matrix.vector.cc}}
+      CI_JOB_IMAGE: ${{matrix.vector.image}}
     runs-on: ubuntu-latest
     container: ${{matrix.vector.image}}
     steps:
@@ -371,10 +415,12 @@
       run: apt -q update && apt -q -y install libc6-amd64 lib64stdc++6
     - uses: actions/checkout@v4
     - run: ci/install-dependencies.sh
-    - run: ci/run-build-and-tests.sh
+    - run: useradd builder --create-home
+    - run: chown -R builder .
+    - run: sudo --preserve-env --set-home --user=builder ci/run-build-and-tests.sh
     - name: print test failures
       if: failure() && env.FAILED_TEST_ARTIFACTS != ''
-      run: ci/print-test-failures.sh
+      run: sudo --preserve-env --set-home --user=builder ci/print-test-failures.sh
     - name: Upload failed tests' directories
       if: failure() && env.FAILED_TEST_ARTIFACTS != ''
       uses: actions/upload-artifact@v4
@@ -400,20 +446,11 @@
     if: needs.ci-config.outputs.enabled == 'yes'
     env:
       jobname: sparse
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     concurrency:
       group: sparse-${{ github.ref }}
       cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
     steps:
-    - name: Download a current `sparse` package
-      # Ubuntu's `sparse` version is too old for us
-      uses: git-for-windows/get-azure-pipelines-artifact@v0
-      with:
-        repository: git/git
-        definitionId: 10
-        artifact: sparse-20.04
-    - name: Install the current `sparse` package
-      run: sudo dpkg -i sparse-20.04/sparse_*.deb
     - uses: actions/checkout@v4
     - name: Install other dependencies
       run: ci/install-dependencies.sh
diff --git a/.gitignore b/.gitignore
index e82aa19..08a66ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@
 /git-apply
 /git-archimport
 /git-archive
+/git-backfill
 /git-bisect
 /git-blame
 /git-branch
@@ -250,3 +251,5 @@
 /git.VC.db
 *.dSYM
 /contrib/buildsystems/out
+/contrib/libgit-rs/target
+/contrib/libgit-sys/target
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9254e01..2805cde 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -36,41 +36,36 @@
       fi
   parallel:
     matrix:
-      - jobname: linux-old
-        image: ubuntu:20.04
-        CC: gcc
       - jobname: linux-sha256
-        image: ubuntu:latest
+        image: ubuntu:rolling
         CC: clang
       - jobname: linux-reftable
-        image: ubuntu:latest
+        image: ubuntu:rolling
         CC: clang
-      - jobname: linux-gcc
+      - jobname: linux-breaking-changes
         image: ubuntu:20.04
         CC: gcc
-        CC_PACKAGE: gcc-8
       - jobname: linux-TEST-vars
         image: ubuntu:20.04
         CC: gcc
         CC_PACKAGE: gcc-8
-      - jobname: linux-gcc-default
-        image: ubuntu:latest
-        CC: gcc
       - jobname: linux-leaks
-        image: ubuntu:latest
+        image: ubuntu:rolling
         CC: gcc
       - jobname: linux-reftable-leaks
-        image: ubuntu:latest
+        image: ubuntu:rolling
         CC: gcc
       - jobname: linux-asan-ubsan
-        image: ubuntu:latest
+        image: ubuntu:rolling
         CC: clang
       - jobname: pedantic
         image: fedora:latest
-      - jobname: linux-musl
+      - jobname: linux-musl-meson
         image: alpine:latest
+      - jobname: linux32
+        image: i386/ubuntu:20.04
       - jobname: linux-meson
-        image: ubuntu:latest
+        image: ubuntu:rolling
         CC: gcc
   artifacts:
     paths:
@@ -149,6 +144,44 @@
     - git-sdk/usr/bin/bash.exe -l -c 'ci/print-test-failures.sh'
   parallel: 10
 
+.msvc-meson:
+  tags:
+    - saas-windows-medium-amd64
+  before_script:
+    - choco install -y git meson ninja openssl
+    - Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1
+    - refreshenv
+    # The certificate store for Python on Windows is broken and fails to fetch
+    # certificates, see https://bugs.python.org/issue36011. This seems to
+    # mostly be an issue with how the GitLab image is set up as it is a
+    # non-issue on GitHub Actions. Work around the issue by importing
+    # cetrificates manually.
+    - Invoke-WebRequest https://curl.haxx.se/ca/cacert.pem -OutFile cacert.pem
+    - openssl pkcs12 -export -nokeys -in cacert.pem -out certs.pfx -passout "pass:"
+    - Import-PfxCertificate -CertStoreLocation Cert:\LocalMachine\Root -FilePath certs.pfx
+
+build:msvc-meson:
+  extends: .msvc-meson
+  stage: build
+  script:
+    - meson setup build -Dperl=disabled -Dbackend_max_links=1 -Dcredential_helpers=wincred
+    - meson compile -C build
+  artifacts:
+    paths:
+      - build
+
+test:msvc-meson:
+  extends: .msvc-meson
+  stage: test
+  when: manual
+  timeout: 6h
+  needs:
+    - job: "build:msvc-meson"
+      artifacts: true
+  script:
+    - meson test -C build --list | Select-Object -Skip 1 | Select-String .* | Group-Object -Property { $_.LineNumber % $Env:CI_NODE_TOTAL + 1 } | Where-Object Name -EQ $Env:CI_NODE_INDEX | ForEach-Object { meson test -C build --no-rebuild --print-errorlogs $_.Group; if (!$?) { exit $LASTEXITCODE } }
+  parallel: 10
+
 test:fuzz-smoke-tests:
   image: ubuntu:latest
   stage: test
@@ -183,7 +216,7 @@
   # be defined in all pipelines.
   script:
     - |
-      R=${CI_MERGE_REQUEST_TARGET_BRANCH_SHA-${CI_MERGE_REQUEST_DIFF_BASE_SHA:?}} || exit
+      R=${CI_MERGE_REQUEST_TARGET_BRANCH_SHA:-${CI_MERGE_REQUEST_DIFF_BASE_SHA:?}} || exit
       ./ci/check-whitespace.sh "$R"
   rules:
     - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
@@ -203,7 +236,7 @@
   # be defined in all pipelines.
   script:
     - |
-      R=${CI_MERGE_REQUEST_TARGET_BRANCH_SHA-${CI_MERGE_REQUEST_DIFF_BASE_SHA:?}} || exit
+      R=${CI_MERGE_REQUEST_TARGET_BRANCH_SHA:-${CI_MERGE_REQUEST_DIFF_BASE_SHA:?}} || exit
       ./ci/run-style-check.sh "$R"
   rules:
     - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
diff --git a/Documentation/.gitattributes b/Documentation/.gitattributes
deleted file mode 100644
index ddb0301..0000000
--- a/Documentation/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-*.txt whitespace
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
index 9f4bb3c..dd54cc7 100644
--- a/Documentation/.gitignore
+++ b/Documentation/.gitignore
@@ -6,11 +6,11 @@
 *.pdf
 git.info
 gitman.info
-howto-index.txt
+howto-index.adoc
 doc.dep
-cmds-*.txt
-mergetools-*.txt
-SubmittingPatches.txt
+cmds-*.adoc
+mergetools-*.adoc
+SubmittingPatches.adoc
 tmp-doc-diff/
 tmp-meson-diff/
 GIT-ASCIIDOCFLAGS
diff --git a/Documentation/BreakingChanges.txt b/Documentation/BreakingChanges.adoc
similarity index 81%
rename from Documentation/BreakingChanges.txt
rename to Documentation/BreakingChanges.adoc
index 27acff8..bdfad29 100644
--- a/Documentation/BreakingChanges.txt
+++ b/Documentation/BreakingChanges.adoc
@@ -66,22 +66,21 @@
 decisions in this document, are necessary but not sufficient.
 Because such changes are expected to be numerous, and the design and
 implementation of them are expected to span over time, they have to
-be deployable trivially at such a version boundary.
+be deployable trivially at such a version boundary, prepared over long
+time.
 
 The breaking changes MUST be guarded with the a compile-time switch,
 WITH_BREAKING_CHANGES, to help this process.  When built with it,
 the resulting Git binary together with its documentation would
 behave as if these breaking changes slated for the next big version
-boundary are already in effect.  We may also want to have a CI job
-or two to exercise the work-in-progress version of Git with these
-breaking changes.
+boundary are already in effect.  We also have a CI job to exercise
+the work-in-progress version of Git with these breaking changes.
 
 
 == Git 3.0
 
 The following subsections document upcoming breaking changes for Git 3.0. There
-is no planned release date for this breaking version yet.  The early
-adopter configuration used for changes for this release is `feature.git3`.
+is no planned release date for this breaking version yet.
 
 Proposed changes and removals only include items which are "ready" to be done.
 In other words, this is not supposed to be a wishlist of features that should
@@ -154,6 +153,31 @@
     <CAKvOHKAFXQwt4D8yUCCkf_TQL79mYaJ=KAKhtpDNTvHJFuX1NA@mail.gmail.com>,
     <20230323204047.GA9290@coredump.intra.peff.net>,
 
+* Support for storing shorthands for remote URLs in "$GIT_COMMON_DIR/branches/"
+  and "$GIT_COMMON_DIR/remotes/" has been long superseded by storing remotes in
+  the repository configuration.
++
+The mechanism has originally been introduced in f170e4b39d ([PATCH] fetch/pull:
+short-hand notation for remote repositories., 2005-07-16) and was superseded by
+6687f8fea2 ([PATCH] Use .git/remote/origin, not .git/branches/origin.,
+2005-08-20), where we switched from ".git/branches/" to ".git/remotes/". That
+commit already mentions an upcoming deprecation of the ".git/branches/"
+directory, and starting with a1d4aa7424 (Add repository-layout document.,
+2005-09-01) we have also marked this layout as deprecated. Eventually we also
+started to migrate away from ".git/remotes/" in favor of config-based remotes,
+and we have marked the directory as legacy in 3d3d282146 (Documentation:
+Grammar correction, wording fixes and cleanup, 2011-08-23)
++
+As our documentation mentions, these directories are unlikely to be used in
+modern repositories and most users aren't even aware of these mechanisms. They
+have been deprecated for almost 20 years and 14 years respectively, and we are
+not aware of any active users that have complained about this deprecation.
+Furthermore, the ".git/branches/" directory is nowadays misleadingly named and
+may cause confusion as "branches" are almost exclusively used in the context of
+references.
++
+These features will be removed.
+
 == Superseded features that will not be deprecated
 
 Some features have gained newer replacements that aim to improve the design in
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index ba047ed..a0e7041 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -44,7 +44,7 @@
 uses (even if it doesn't match the overall style of existing code).
 
 But if you must have a list of rules, here are some language
-specific ones. Note that Documentation/ToolsForGit.txt document
+specific ones. Note that Documentation/ToolsForGit.adoc document
 has a collection of tips to help you use some external tools
 to conform to these guidelines.
 
@@ -755,7 +755,7 @@
 Writing Documentation:
 
  Most (if not all) of the documentation pages are written in the
- AsciiDoc format in *.txt files (e.g. Documentation/git.txt), and
+ AsciiDoc format in *.adoc files (e.g. Documentation/git.adoc), and
  processed into HTML and manpages (e.g. git.html and git.1 in the
  same directory).
 
diff --git a/Documentation/DecisionMaking.txt b/Documentation/DecisionMaking.adoc
similarity index 100%
rename from Documentation/DecisionMaking.txt
rename to Documentation/DecisionMaking.adoc
diff --git a/Documentation/Makefile b/Documentation/Makefile
index aedfe99..671267a 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,3 +1,6 @@
+# The default target of this Makefile is...
+all::
+
 # Import tree-wide shared Makefile behavior and libraries
 include ../shared.mak
 
@@ -17,56 +20,56 @@
 -include GIT-EXCLUDED-PROGRAMS
 
 MAN1_TXT += $(filter-out \
-		$(patsubst %,%.txt,$(EXCLUDED_PROGRAMS)) \
-		$(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
-		$(wildcard git-*.txt))
-MAN1_TXT += git.txt
-MAN1_TXT += gitk.txt
-MAN1_TXT += gitweb.txt
-MAN1_TXT += scalar.txt
+		$(patsubst %,%.adoc,$(EXCLUDED_PROGRAMS)) \
+		$(addsuffix .adoc, $(ARTICLES) $(SP_ARTICLES)), \
+		$(wildcard git-*.adoc))
+MAN1_TXT += git.adoc
+MAN1_TXT += gitk.adoc
+MAN1_TXT += gitweb.adoc
+MAN1_TXT += scalar.adoc
 
 # man5 / man7 guides (note: new guides should also be added to command-list.txt)
-MAN5_TXT += gitattributes.txt
-MAN5_TXT += gitformat-bundle.txt
-MAN5_TXT += gitformat-chunk.txt
-MAN5_TXT += gitformat-commit-graph.txt
-MAN5_TXT += gitformat-index.txt
-MAN5_TXT += gitformat-pack.txt
-MAN5_TXT += gitformat-signature.txt
-MAN5_TXT += githooks.txt
-MAN5_TXT += gitignore.txt
-MAN5_TXT += gitmailmap.txt
-MAN5_TXT += gitmodules.txt
-MAN5_TXT += gitprotocol-capabilities.txt
-MAN5_TXT += gitprotocol-common.txt
-MAN5_TXT += gitprotocol-http.txt
-MAN5_TXT += gitprotocol-pack.txt
-MAN5_TXT += gitprotocol-v2.txt
-MAN5_TXT += gitrepository-layout.txt
-MAN5_TXT += gitweb.conf.txt
+MAN5_TXT += gitattributes.adoc
+MAN5_TXT += gitformat-bundle.adoc
+MAN5_TXT += gitformat-chunk.adoc
+MAN5_TXT += gitformat-commit-graph.adoc
+MAN5_TXT += gitformat-index.adoc
+MAN5_TXT += gitformat-pack.adoc
+MAN5_TXT += gitformat-signature.adoc
+MAN5_TXT += githooks.adoc
+MAN5_TXT += gitignore.adoc
+MAN5_TXT += gitmailmap.adoc
+MAN5_TXT += gitmodules.adoc
+MAN5_TXT += gitprotocol-capabilities.adoc
+MAN5_TXT += gitprotocol-common.adoc
+MAN5_TXT += gitprotocol-http.adoc
+MAN5_TXT += gitprotocol-pack.adoc
+MAN5_TXT += gitprotocol-v2.adoc
+MAN5_TXT += gitrepository-layout.adoc
+MAN5_TXT += gitweb.conf.adoc
 
-MAN7_TXT += gitcli.txt
-MAN7_TXT += gitcore-tutorial.txt
-MAN7_TXT += gitcredentials.txt
-MAN7_TXT += gitcvs-migration.txt
-MAN7_TXT += gitdiffcore.txt
-MAN7_TXT += giteveryday.txt
-MAN7_TXT += gitfaq.txt
-MAN7_TXT += gitglossary.txt
-MAN7_TXT += gitpacking.txt
-MAN7_TXT += gitnamespaces.txt
-MAN7_TXT += gitremote-helpers.txt
-MAN7_TXT += gitrevisions.txt
-MAN7_TXT += gitsubmodules.txt
-MAN7_TXT += gittutorial-2.txt
-MAN7_TXT += gittutorial.txt
-MAN7_TXT += gitworkflows.txt
+MAN7_TXT += gitcli.adoc
+MAN7_TXT += gitcore-tutorial.adoc
+MAN7_TXT += gitcredentials.adoc
+MAN7_TXT += gitcvs-migration.adoc
+MAN7_TXT += gitdiffcore.adoc
+MAN7_TXT += giteveryday.adoc
+MAN7_TXT += gitfaq.adoc
+MAN7_TXT += gitglossary.adoc
+MAN7_TXT += gitpacking.adoc
+MAN7_TXT += gitnamespaces.adoc
+MAN7_TXT += gitremote-helpers.adoc
+MAN7_TXT += gitrevisions.adoc
+MAN7_TXT += gitsubmodules.adoc
+MAN7_TXT += gittutorial-2.adoc
+MAN7_TXT += gittutorial.adoc
+MAN7_TXT += gitworkflows.adoc
 
-HOWTO_TXT += $(wildcard howto/*.txt)
+HOWTO_TXT += $(wildcard howto/*.adoc)
 
-DOC_DEP_TXT += $(wildcard *.txt)
-DOC_DEP_TXT += $(wildcard config/*.txt)
-DOC_DEP_TXT += $(wildcard includes/*.txt)
+DOC_DEP_TXT += $(wildcard *.adoc)
+DOC_DEP_TXT += $(wildcard config/*.adoc)
+DOC_DEP_TXT += $(wildcard includes/*.adoc)
 
 ifdef MAN_FILTER
 MAN_TXT = $(filter $(MAN_FILTER),$(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT))
@@ -75,8 +78,8 @@
 MAN_FILTER = $(MAN_TXT)
 endif
 
-MAN_XML = $(patsubst %.txt,%.xml,$(MAN_TXT))
-MAN_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
+MAN_XML = $(patsubst %.adoc,%.xml,$(MAN_TXT))
+MAN_HTML = $(patsubst %.adoc,%.html,$(MAN_TXT))
 GIT_MAN_REF = master
 
 OBSOLETE_HTML += everyday.html
@@ -103,7 +106,7 @@
 SP_ARTICLES += howto/keep-canonical-history-correct
 SP_ARTICLES += howto/maintain-git
 SP_ARTICLES += howto/coordinate-embargoed-releases
-API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
+API_DOCS = $(patsubst %.adoc,%,$(filter-out technical/api-index-skel.adoc technical/api-index.adoc, $(wildcard technical/api-*.adoc)))
 SP_ARTICLES += $(API_DOCS)
 
 TECH_DOCS += DecisionMaking
@@ -136,9 +139,9 @@
 HTML_FILTER ?= $(ARTICLES_HTML) $(OBSOLETE_HTML)
 DOC_HTML = $(MAN_HTML) $(filter $(HTML_FILTER),$(ARTICLES_HTML) $(OBSOLETE_HTML))
 
-DOC_MAN1 = $(patsubst %.txt,%.1,$(filter $(MAN_FILTER),$(MAN1_TXT)))
-DOC_MAN5 = $(patsubst %.txt,%.5,$(filter $(MAN_FILTER),$(MAN5_TXT)))
-DOC_MAN7 = $(patsubst %.txt,%.7,$(filter $(MAN_FILTER),$(MAN7_TXT)))
+DOC_MAN1 = $(patsubst %.adoc,%.1,$(filter $(MAN_FILTER),$(MAN1_TXT)))
+DOC_MAN5 = $(patsubst %.adoc,%.5,$(filter $(MAN_FILTER),$(MAN5_TXT)))
+DOC_MAN7 = $(patsubst %.adoc,%.7,$(filter $(MAN_FILTER),$(MAN7_TXT)))
 
 prefix ?= $(HOME)
 bindir ?= $(prefix)/bin
@@ -221,6 +224,10 @@
 	$(QUIET_GEN)$(call version_gen,"$(shell pwd)/..",$<,$@)
 endif
 
+ifdef WITH_BREAKING_CHANGES
+ASCIIDOC_EXTRA += -awith-breaking-changes
+endif
+
 ASCIIDOC_DEPS += docinfo.html
 
 SHELL_PATH ?= $(SHELL)
@@ -238,7 +245,7 @@
 ASCIIDOC_EXTRA += -a 'git-default-editor=$(DEFAULT_EDITOR_SQ)'
 endif
 
-all: html man
+all:: html man
 
 html: $(DOC_HTML)
 
@@ -278,7 +285,7 @@
 install-html: html
 	'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
 
-mergetools_txt = mergetools-diff.txt mergetools-merge.txt
+mergetools_txt = mergetools-diff.adoc mergetools-merge.adoc
 
 #
 # Determine "include::" file references in asciidoc files.
@@ -294,18 +301,18 @@
 -include doc.dep
 endif
 
-cmds_txt = cmds-ancillaryinterrogators.txt \
-	cmds-ancillarymanipulators.txt \
-	cmds-mainporcelain.txt \
-	cmds-plumbinginterrogators.txt \
-	cmds-plumbingmanipulators.txt \
-	cmds-synchingrepositories.txt \
-	cmds-synchelpers.txt \
-	cmds-guide.txt \
-	cmds-developerinterfaces.txt \
-	cmds-userinterfaces.txt \
-	cmds-purehelpers.txt \
-	cmds-foreignscminterface.txt
+cmds_txt = cmds-ancillaryinterrogators.adoc \
+	cmds-ancillarymanipulators.adoc \
+	cmds-mainporcelain.adoc \
+	cmds-plumbinginterrogators.adoc \
+	cmds-plumbingmanipulators.adoc \
+	cmds-synchingrepositories.adoc \
+	cmds-synchelpers.adoc \
+	cmds-guide.adoc \
+	cmds-developerinterfaces.adoc \
+	cmds-userinterfaces.adoc \
+	cmds-purehelpers.adoc \
+	cmds-foreignscminterface.adoc
 
 $(cmds_txt): cmd-list.made
 
@@ -313,10 +320,10 @@
 	$(QUIET_GEN)$(PERL_PATH) ./cmd-list.perl .. . $(cmds_txt) && \
 	date >$@
 
-mergetools-%.txt: generate-mergetool-list.sh ../git-mergetool--lib.sh $(wildcard ../mergetools/*)
-mergetools-diff.txt:
+mergetools-%.adoc: generate-mergetool-list.sh ../git-mergetool--lib.sh $(wildcard ../mergetools/*)
+mergetools-diff.adoc:
 	$(QUIET_GEN)$(SHELL_PATH) ./generate-mergetool-list.sh .. diff $@
-mergetools-merge.txt:
+mergetools-merge.adoc:
 	$(QUIET_GEN)$(SHELL_PATH) ./generate-mergetool-list.sh .. merge $@
 
 TRACK_ASCIIDOCFLAGS = $(subst ','\'',$(ASCIIDOC_COMMON):$(ASCIIDOC_HTML):$(ASCIIDOC_DOCBOOK))
@@ -333,9 +340,9 @@
 	$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7
 	$(RM) *.texi *.texi+ *.texi++ git.info gitman.info
 	$(RM) *.pdf
-	$(RM) howto-index.txt howto/*.html doc.dep
-	$(RM) technical/*.html technical/api-index.txt
-	$(RM) SubmittingPatches.txt
+	$(RM) howto-index.adoc howto/*.html doc.dep
+	$(RM) technical/*.html technical/api-index.adoc
+	$(RM) SubmittingPatches.adoc
 	$(RM) $(cmds_txt) $(mergetools_txt) *.made
 	$(RM) GIT-ASCIIDOCFLAGS
 	$(RM) asciidoc.conf asciidoctor-extensions.rb
@@ -344,10 +351,10 @@
 docinfo.html: docinfo-html.in
 	$(QUIET_GEN)$(RM) $@ && cat $< >$@
 
-$(MAN_HTML): %.html : %.txt $(ASCIIDOC_DEPS)
+$(MAN_HTML): %.html : %.adoc $(ASCIIDOC_DEPS)
 	$(QUIET_ASCIIDOC)$(TXT_TO_HTML) -d manpage -o $@ $<
 
-$(OBSOLETE_HTML): %.html : %.txto $(ASCIIDOC_DEPS)
+$(OBSOLETE_HTML): %.html : %.adoco $(ASCIIDOC_DEPS)
 	$(QUIET_ASCIIDOC)$(TXT_TO_HTML) -o $@ $<
 
 manpage-prereqs := $(wildcard manpage*.xsl)
@@ -360,22 +367,22 @@
 %.7 : %.xml $(manpage-prereqs)
 	$(manpage-cmd)
 
-%.xml : %.txt $(ASCIIDOC_DEPS)
+%.xml : %.adoc $(ASCIIDOC_DEPS)
 	$(QUIET_ASCIIDOC)$(TXT_TO_XML) -d manpage -o $@ $<
 
-user-manual.xml: user-manual.txt $(ASCIIDOC_DEPS)
+user-manual.xml: user-manual.adoc $(ASCIIDOC_DEPS)
 	$(QUIET_ASCIIDOC)$(TXT_TO_XML) -d book -o $@ $<
 
-technical/api-index.txt: technical/api-index-skel.txt \
-	technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
-	$(QUIET_GEN)'$(SHELL_PATH_SQ)' technical/api-index.sh ./technical ./technical/api-index.txt
+technical/api-index.adoc: technical/api-index-skel.adoc \
+	technical/api-index.sh $(patsubst %,%.adoc,$(API_DOCS))
+	$(QUIET_GEN)'$(SHELL_PATH_SQ)' technical/api-index.sh ./technical ./technical/api-index.adoc
 
 technical/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
-$(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.txt \
+$(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.adoc \
 	$(ASCIIDOC_DEPS)
-	$(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.txt
+	$(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.adoc
 
-SubmittingPatches.txt: SubmittingPatches
+SubmittingPatches.adoc: SubmittingPatches
 	$(QUIET_GEN) cp $< $@
 
 XSLT = docbook.xsl
@@ -409,19 +416,19 @@
 gitman.info: gitman.texi
 	$(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $<
 
-$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
+$(patsubst %.adoc,%.texi,$(MAN_TXT)): %.texi : %.xml
 	$(QUIET_DB2TEXI)$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@
 
-howto-index.txt: howto/howto-index.sh $(HOWTO_TXT)
+howto-index.adoc: howto/howto-index.sh $(HOWTO_TXT)
 	$(QUIET_GEN)'$(SHELL_PATH_SQ)' ./howto/howto-index.sh $(sort $(HOWTO_TXT)) >$@
 
-$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt $(ASCIIDOC_DEPS)
-	$(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.txt
+$(patsubst %,%.html,$(ARTICLES)) : %.html : %.adoc $(ASCIIDOC_DEPS)
+	$(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.adoc
 
 WEBDOC_DEST = /pub/software/scm/git/docs
 
 howto/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
-$(patsubst %.txt,%.html,$(HOWTO_TXT)): %.html : %.txt $(ASCIIDOC_DEPS)
+$(patsubst %.adoc,%.html,$(HOWTO_TXT)): %.html : %.adoc $(ASCIIDOC_DEPS)
 	$(QUIET_ASCIIDOC) \
 	sed -e '1,/^$$/d' $< | \
 	$(TXT_TO_HTML) - >$@
@@ -452,9 +459,9 @@
 	@for i in $(MAN1_TXT); do echo $$i; done
 
 ## Lint: gitlink
-LINT_DOCS_GITLINK = $(patsubst %.txt,.build/lint-docs/gitlink/%.ok,$(HOWTO_TXT) $(DOC_DEP_TXT))
+LINT_DOCS_GITLINK = $(patsubst %.adoc,.build/lint-docs/gitlink/%.ok,$(HOWTO_TXT) $(DOC_DEP_TXT))
 $(LINT_DOCS_GITLINK): lint-gitlink.perl
-$(LINT_DOCS_GITLINK): .build/lint-docs/gitlink/%.ok: %.txt
+$(LINT_DOCS_GITLINK): .build/lint-docs/gitlink/%.ok: %.adoc
 	$(call mkdir_p_parent_template)
 	$(QUIET_LINT_GITLINK)$(PERL_PATH) lint-gitlink.perl \
 		$< \
@@ -466,17 +473,17 @@
 lint-docs-gitlink: $(LINT_DOCS_GITLINK)
 
 ## Lint: man-end-blurb
-LINT_DOCS_MAN_END_BLURB = $(patsubst %.txt,.build/lint-docs/man-end-blurb/%.ok,$(MAN_TXT))
+LINT_DOCS_MAN_END_BLURB = $(patsubst %.adoc,.build/lint-docs/man-end-blurb/%.ok,$(MAN_TXT))
 $(LINT_DOCS_MAN_END_BLURB): lint-man-end-blurb.perl
-$(LINT_DOCS_MAN_END_BLURB): .build/lint-docs/man-end-blurb/%.ok: %.txt
+$(LINT_DOCS_MAN_END_BLURB): .build/lint-docs/man-end-blurb/%.ok: %.adoc
 	$(call mkdir_p_parent_template)
 	$(QUIET_LINT_MANEND)$(PERL_PATH) lint-man-end-blurb.perl $< >$@
 .PHONY: lint-docs-man-end-blurb
 
 ## Lint: man-section-order
-LINT_DOCS_MAN_SECTION_ORDER = $(patsubst %.txt,.build/lint-docs/man-section-order/%.ok,$(MAN_TXT))
+LINT_DOCS_MAN_SECTION_ORDER = $(patsubst %.adoc,.build/lint-docs/man-section-order/%.ok,$(MAN_TXT))
 $(LINT_DOCS_MAN_SECTION_ORDER): lint-man-section-order.perl
-$(LINT_DOCS_MAN_SECTION_ORDER): .build/lint-docs/man-section-order/%.ok: %.txt
+$(LINT_DOCS_MAN_SECTION_ORDER): .build/lint-docs/man-section-order/%.ok: %.adoc
 	$(call mkdir_p_parent_template)
 	$(QUIET_LINT_MANSEC)$(PERL_PATH) lint-man-section-order.perl $< >$@
 .PHONY: lint-docs-man-section-order
@@ -485,10 +492,10 @@
 .PHONY: lint-docs-fsck-msgids
 LINT_DOCS_FSCK_MSGIDS = .build/lint-docs/fsck-msgids.ok
 $(LINT_DOCS_FSCK_MSGIDS): lint-fsck-msgids.perl
-$(LINT_DOCS_FSCK_MSGIDS): ../fsck.h fsck-msgids.txt
+$(LINT_DOCS_FSCK_MSGIDS): ../fsck.h fsck-msgids.adoc
 	$(call mkdir_p_parent_template)
 	$(QUIET_GEN)$(PERL_PATH) lint-fsck-msgids.perl \
-		../fsck.h fsck-msgids.txt $@
+		../fsck.h fsck-msgids.adoc $@
 
 lint-docs-fsck-msgids: $(LINT_DOCS_FSCK_MSGIDS)
 
@@ -501,11 +508,11 @@
 	@mkdir -p tmp-meson-diff && \
 	awk "/^manpages = {$$/ {flag=1 ; next } /^}$$/ { flag=0 } flag { gsub(/^  \047/, \"\"); gsub(/\047 : [157],\$$/, \"\"); print }" meson.build | \
 		grep -v -e '#' -e '^$$' | \
-		sort >tmp-meson-diff/meson.txt && \
-	ls git*.txt scalar.txt | grep -v -e git-bisect-lk2009.txt -e git-tools.txt >tmp-meson-diff/actual.txt && \
-	if ! cmp tmp-meson-diff/meson.txt tmp-meson-diff/actual.txt; then \
+		sort >tmp-meson-diff/meson.adoc && \
+	ls git*.adoc scalar.adoc | grep -v -e git-bisect-lk2009.adoc -e git-tools.adoc >tmp-meson-diff/actual.adoc && \
+	if ! cmp tmp-meson-diff/meson.adoc tmp-meson-diff/actual.adoc; then \
 		echo "Meson man pages differ from actual man pages:"; \
-		diff -u tmp-meson-diff/meson.txt tmp-meson-diff/actual.txt; \
+		diff -u tmp-meson-diff/meson.adoc tmp-meson-diff/actual.adoc; \
 		exit 1; \
 	fi
 
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.adoc
similarity index 98%
rename from Documentation/MyFirstContribution.txt
rename to Documentation/MyFirstContribution.adoc
index e41654c..afcf4b4 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.adoc
@@ -21,7 +21,7 @@
 useful additional context:
 
 - `Documentation/SubmittingPatches`
-- `Documentation/howto/new-command.txt`
+- `Documentation/howto/new-command.adoc`
 
 [[getting-help]]
 === Getting Help
@@ -331,7 +331,7 @@
 apply standard precedence rules. `git_config_get_string_tmp()` will look up
 a specific key ("user.name") and give you the value. There are a number of
 single-key lookup functions like this one; you can see them all (and more info
-about how to use `git_config()`) in `Documentation/technical/api-config.txt`.
+about how to use `git_config()`) in `Documentation/technical/api-config.adoc`.
 
 You should see that the name printed matches the one you see when you run:
 
@@ -461,10 +461,10 @@
 
 Your new command is undocumented! Let's fix that.
 
-Take a look at `Documentation/git-*.txt`. These are the manpages for the
+Take a look at `Documentation/git-*.adoc`. These are the manpages for the
 subcommands that Git knows about. You can open these up and take a look to get
 acquainted with the format, but then go ahead and make a new file
-`Documentation/git-psuh.txt`. Like with most of the documentation in the Git
+`Documentation/git-psuh.adoc`. Like with most of the documentation in the Git
 project, help pages are written with AsciiDoc (see CodingGuidelines, "Writing
 Documentation" section). Use the following template to fill out your own
 manpage:
@@ -543,7 +543,7 @@
 That's because `-h` is a special case which your command should handle by
 printing usage.
 
-Take a look at `Documentation/technical/api-parse-options.txt`. This is a handy
+Take a look at `Documentation/technical/api-parse-options.adoc`. This is a handy
 tool for pulling out options you need to be able to handle, and it takes a
 usage string.
 
@@ -1088,14 +1088,14 @@
 The one generated for `psuh` from the sample implementation looks like this:
 
 ----
- Documentation/git-psuh.txt | 40 +++++++++++++++++++++
- Makefile                   |  1 +
- builtin.h                  |  1 +
- builtin/psuh.c             | 73 ++++++++++++++++++++++++++++++++++++++
- git.c                      |  1 +
- t/t9999-psuh-tutorial.sh   | 12 +++++++
+ Documentation/git-psuh.adoc | 40 +++++++++++++++++++++
+ Makefile                    |  1 +
+ builtin.h                   |  1 +
+ builtin/psuh.c              | 73 ++++++++++++++++++++++++++++++++++++++
+ git.c                       |  1 +
+ t/t9999-psuh-tutorial.sh    | 12 +++++++
  6 files changed, 128 insertions(+)
- create mode 100644 Documentation/git-psuh.txt
+ create mode 100644 Documentation/git-psuh.adoc
  create mode 100644 builtin/psuh.c
  create mode 100755 t/t9999-psuh-tutorial.sh
 ----
diff --git a/Documentation/MyFirstObjectWalk.txt b/Documentation/MyFirstObjectWalk.adoc
similarity index 98%
rename from Documentation/MyFirstObjectWalk.txt
rename to Documentation/MyFirstObjectWalk.adoc
index dec8afe..d6e9dfd 100644
--- a/Documentation/MyFirstObjectWalk.txt
+++ b/Documentation/MyFirstObjectWalk.adoc
@@ -15,7 +15,7 @@
 
 === Related Reading
 
-- `Documentation/user-manual.txt` under "Hacking Git" contains some coverage of
+- `Documentation/user-manual.adoc` under "Hacking Git" contains some coverage of
   the revision walker in its various incarnations.
 - `revision.h`
 - https://eagain.net/articles/git-for-computer-scientists/[Git for Computer Scientists]
@@ -112,7 +112,7 @@
 ----
 
 NOTE: For a more exhaustive overview of the new command process, take a look at
-`Documentation/MyFirstContribution.txt`.
+`Documentation/MyFirstContribution.adoc`.
 
 NOTE: A reference implementation can be found at
 https://github.com/nasamuffin/git/tree/revwalk.
@@ -132,7 +132,7 @@
 Per entry, we find:
 
 `item` is the object provided upon which to base the object walk. Items in Git
-can be blobs, trees, commits, or tags. (See `Documentation/gittutorial-2.txt`.)
+can be blobs, trees, commits, or tags. (See `Documentation/gittutorial-2.adoc`.)
 
 `name` is the object ID (OID) of the object - a hex string you may be familiar
 with from using Git to organize your source in the past. Check the tutorial
@@ -141,7 +141,7 @@
 
 `whence` indicates some information about what to do with the parents of the
 specified object. We'll explore this flag more later on; take a look at
-`Documentation/revisions.txt` to get an idea of what could set the `whence`
+`Documentation/revisions.adoc` to get an idea of what could set the `whence`
 value.
 
 `flags` are used to hint the beginning of the revision walk and are the first
@@ -153,7 +153,7 @@
 
 This one is quite a bit longer, and many fields are only used during the walk
 by `revision.c` - not configuration options. Most of the configurable flags in
-`struct rev_info` have a mirror in `Documentation/rev-list-options.txt`. It's a
+`struct rev_info` have a mirror in `Documentation/rev-list-options.adoc`. It's a
 good idea to take some time and read through that document.
 
 == Basic Commit Walk
@@ -710,7 +710,7 @@
 === Adding a Filter
 
 There are a handful of filters that we can apply to the object walk laid out in
-`Documentation/rev-list-options.txt`. These filters are typically useful for
+`Documentation/rev-list-options.adoc`. These filters are typically useful for
 operations such as creating packfiles or performing a partial clone. They are
 defined in `list-objects-filter-options.h`. For the purposes of this tutorial we
 will use the "tree:1" filter, which causes the walk to omit all trees and blobs
diff --git a/Documentation/RelNotes/1.5.0.1.txt b/Documentation/RelNotes/1.5.0.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.0.1.txt
rename to Documentation/RelNotes/1.5.0.1.adoc
diff --git a/Documentation/RelNotes/1.5.0.2.txt b/Documentation/RelNotes/1.5.0.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.0.2.txt
rename to Documentation/RelNotes/1.5.0.2.adoc
diff --git a/Documentation/RelNotes/1.5.0.3.txt b/Documentation/RelNotes/1.5.0.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.0.3.txt
rename to Documentation/RelNotes/1.5.0.3.adoc
diff --git a/Documentation/RelNotes/1.5.0.4.txt b/Documentation/RelNotes/1.5.0.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.0.4.txt
rename to Documentation/RelNotes/1.5.0.4.adoc
diff --git a/Documentation/RelNotes/1.5.0.5.txt b/Documentation/RelNotes/1.5.0.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.0.5.txt
rename to Documentation/RelNotes/1.5.0.5.adoc
diff --git a/Documentation/RelNotes/1.5.0.6.txt b/Documentation/RelNotes/1.5.0.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.0.6.txt
rename to Documentation/RelNotes/1.5.0.6.adoc
diff --git a/Documentation/RelNotes/1.5.0.7.txt b/Documentation/RelNotes/1.5.0.7.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.0.7.txt
rename to Documentation/RelNotes/1.5.0.7.adoc
diff --git a/Documentation/RelNotes/1.5.0.txt b/Documentation/RelNotes/1.5.0.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.0.txt
rename to Documentation/RelNotes/1.5.0.adoc
diff --git a/Documentation/RelNotes/1.5.1.1.txt b/Documentation/RelNotes/1.5.1.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.1.1.txt
rename to Documentation/RelNotes/1.5.1.1.adoc
diff --git a/Documentation/RelNotes/1.5.1.2.txt b/Documentation/RelNotes/1.5.1.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.1.2.txt
rename to Documentation/RelNotes/1.5.1.2.adoc
diff --git a/Documentation/RelNotes/1.5.1.3.txt b/Documentation/RelNotes/1.5.1.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.1.3.txt
rename to Documentation/RelNotes/1.5.1.3.adoc
diff --git a/Documentation/RelNotes/1.5.1.4.txt b/Documentation/RelNotes/1.5.1.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.1.4.txt
rename to Documentation/RelNotes/1.5.1.4.adoc
diff --git a/Documentation/RelNotes/1.5.1.5.txt b/Documentation/RelNotes/1.5.1.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.1.5.txt
rename to Documentation/RelNotes/1.5.1.5.adoc
diff --git a/Documentation/RelNotes/1.5.1.6.txt b/Documentation/RelNotes/1.5.1.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.1.6.txt
rename to Documentation/RelNotes/1.5.1.6.adoc
diff --git a/Documentation/RelNotes/1.5.1.txt b/Documentation/RelNotes/1.5.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.1.txt
rename to Documentation/RelNotes/1.5.1.adoc
diff --git a/Documentation/RelNotes/1.5.2.1.txt b/Documentation/RelNotes/1.5.2.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.2.1.txt
rename to Documentation/RelNotes/1.5.2.1.adoc
diff --git a/Documentation/RelNotes/1.5.2.2.txt b/Documentation/RelNotes/1.5.2.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.2.2.txt
rename to Documentation/RelNotes/1.5.2.2.adoc
diff --git a/Documentation/RelNotes/1.5.2.3.txt b/Documentation/RelNotes/1.5.2.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.2.3.txt
rename to Documentation/RelNotes/1.5.2.3.adoc
diff --git a/Documentation/RelNotes/1.5.2.4.txt b/Documentation/RelNotes/1.5.2.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.2.4.txt
rename to Documentation/RelNotes/1.5.2.4.adoc
diff --git a/Documentation/RelNotes/1.5.2.5.txt b/Documentation/RelNotes/1.5.2.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.2.5.txt
rename to Documentation/RelNotes/1.5.2.5.adoc
diff --git a/Documentation/RelNotes/1.5.2.txt b/Documentation/RelNotes/1.5.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.2.txt
rename to Documentation/RelNotes/1.5.2.adoc
diff --git a/Documentation/RelNotes/1.5.3.1.txt b/Documentation/RelNotes/1.5.3.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.3.1.txt
rename to Documentation/RelNotes/1.5.3.1.adoc
diff --git a/Documentation/RelNotes/1.5.3.2.txt b/Documentation/RelNotes/1.5.3.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.3.2.txt
rename to Documentation/RelNotes/1.5.3.2.adoc
diff --git a/Documentation/RelNotes/1.5.3.3.txt b/Documentation/RelNotes/1.5.3.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.3.3.txt
rename to Documentation/RelNotes/1.5.3.3.adoc
diff --git a/Documentation/RelNotes/1.5.3.4.txt b/Documentation/RelNotes/1.5.3.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.3.4.txt
rename to Documentation/RelNotes/1.5.3.4.adoc
diff --git a/Documentation/RelNotes/1.5.3.5.txt b/Documentation/RelNotes/1.5.3.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.3.5.txt
rename to Documentation/RelNotes/1.5.3.5.adoc
diff --git a/Documentation/RelNotes/1.5.3.6.txt b/Documentation/RelNotes/1.5.3.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.3.6.txt
rename to Documentation/RelNotes/1.5.3.6.adoc
diff --git a/Documentation/RelNotes/1.5.3.7.txt b/Documentation/RelNotes/1.5.3.7.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.3.7.txt
rename to Documentation/RelNotes/1.5.3.7.adoc
diff --git a/Documentation/RelNotes/1.5.3.8.txt b/Documentation/RelNotes/1.5.3.8.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.3.8.txt
rename to Documentation/RelNotes/1.5.3.8.adoc
diff --git a/Documentation/RelNotes/1.5.3.txt b/Documentation/RelNotes/1.5.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.3.txt
rename to Documentation/RelNotes/1.5.3.adoc
diff --git a/Documentation/RelNotes/1.5.4.1.txt b/Documentation/RelNotes/1.5.4.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.4.1.txt
rename to Documentation/RelNotes/1.5.4.1.adoc
diff --git a/Documentation/RelNotes/1.5.4.2.txt b/Documentation/RelNotes/1.5.4.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.4.2.txt
rename to Documentation/RelNotes/1.5.4.2.adoc
diff --git a/Documentation/RelNotes/1.5.4.3.txt b/Documentation/RelNotes/1.5.4.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.4.3.txt
rename to Documentation/RelNotes/1.5.4.3.adoc
diff --git a/Documentation/RelNotes/1.5.4.4.txt b/Documentation/RelNotes/1.5.4.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.4.4.txt
rename to Documentation/RelNotes/1.5.4.4.adoc
diff --git a/Documentation/RelNotes/1.5.4.5.txt b/Documentation/RelNotes/1.5.4.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.4.5.txt
rename to Documentation/RelNotes/1.5.4.5.adoc
diff --git a/Documentation/RelNotes/1.5.4.6.txt b/Documentation/RelNotes/1.5.4.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.4.6.txt
rename to Documentation/RelNotes/1.5.4.6.adoc
diff --git a/Documentation/RelNotes/1.5.4.7.txt b/Documentation/RelNotes/1.5.4.7.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.4.7.txt
rename to Documentation/RelNotes/1.5.4.7.adoc
diff --git a/Documentation/RelNotes/1.5.4.txt b/Documentation/RelNotes/1.5.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.4.txt
rename to Documentation/RelNotes/1.5.4.adoc
diff --git a/Documentation/RelNotes/1.5.5.1.txt b/Documentation/RelNotes/1.5.5.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.5.1.txt
rename to Documentation/RelNotes/1.5.5.1.adoc
diff --git a/Documentation/RelNotes/1.5.5.2.txt b/Documentation/RelNotes/1.5.5.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.5.2.txt
rename to Documentation/RelNotes/1.5.5.2.adoc
diff --git a/Documentation/RelNotes/1.5.5.3.txt b/Documentation/RelNotes/1.5.5.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.5.3.txt
rename to Documentation/RelNotes/1.5.5.3.adoc
diff --git a/Documentation/RelNotes/1.5.5.4.txt b/Documentation/RelNotes/1.5.5.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.5.4.txt
rename to Documentation/RelNotes/1.5.5.4.adoc
diff --git a/Documentation/RelNotes/1.5.5.5.txt b/Documentation/RelNotes/1.5.5.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.5.5.txt
rename to Documentation/RelNotes/1.5.5.5.adoc
diff --git a/Documentation/RelNotes/1.5.5.6.txt b/Documentation/RelNotes/1.5.5.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.5.6.txt
rename to Documentation/RelNotes/1.5.5.6.adoc
diff --git a/Documentation/RelNotes/1.5.5.txt b/Documentation/RelNotes/1.5.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.5.txt
rename to Documentation/RelNotes/1.5.5.adoc
diff --git a/Documentation/RelNotes/1.5.6.1.txt b/Documentation/RelNotes/1.5.6.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.6.1.txt
rename to Documentation/RelNotes/1.5.6.1.adoc
diff --git a/Documentation/RelNotes/1.5.6.2.txt b/Documentation/RelNotes/1.5.6.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.6.2.txt
rename to Documentation/RelNotes/1.5.6.2.adoc
diff --git a/Documentation/RelNotes/1.5.6.3.txt b/Documentation/RelNotes/1.5.6.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.6.3.txt
rename to Documentation/RelNotes/1.5.6.3.adoc
diff --git a/Documentation/RelNotes/1.5.6.4.txt b/Documentation/RelNotes/1.5.6.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.6.4.txt
rename to Documentation/RelNotes/1.5.6.4.adoc
diff --git a/Documentation/RelNotes/1.5.6.5.txt b/Documentation/RelNotes/1.5.6.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.6.5.txt
rename to Documentation/RelNotes/1.5.6.5.adoc
diff --git a/Documentation/RelNotes/1.5.6.6.txt b/Documentation/RelNotes/1.5.6.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.6.6.txt
rename to Documentation/RelNotes/1.5.6.6.adoc
diff --git a/Documentation/RelNotes/1.5.6.txt b/Documentation/RelNotes/1.5.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.5.6.txt
rename to Documentation/RelNotes/1.5.6.adoc
diff --git a/Documentation/RelNotes/1.6.0.1.txt b/Documentation/RelNotes/1.6.0.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.0.1.txt
rename to Documentation/RelNotes/1.6.0.1.adoc
diff --git a/Documentation/RelNotes/1.6.0.2.txt b/Documentation/RelNotes/1.6.0.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.0.2.txt
rename to Documentation/RelNotes/1.6.0.2.adoc
diff --git a/Documentation/RelNotes/1.6.0.3.txt b/Documentation/RelNotes/1.6.0.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.0.3.txt
rename to Documentation/RelNotes/1.6.0.3.adoc
diff --git a/Documentation/RelNotes/1.6.0.4.txt b/Documentation/RelNotes/1.6.0.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.0.4.txt
rename to Documentation/RelNotes/1.6.0.4.adoc
diff --git a/Documentation/RelNotes/1.6.0.5.txt b/Documentation/RelNotes/1.6.0.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.0.5.txt
rename to Documentation/RelNotes/1.6.0.5.adoc
diff --git a/Documentation/RelNotes/1.6.0.6.txt b/Documentation/RelNotes/1.6.0.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.0.6.txt
rename to Documentation/RelNotes/1.6.0.6.adoc
diff --git a/Documentation/RelNotes/1.6.0.txt b/Documentation/RelNotes/1.6.0.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.0.txt
rename to Documentation/RelNotes/1.6.0.adoc
diff --git a/Documentation/RelNotes/1.6.1.1.txt b/Documentation/RelNotes/1.6.1.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.1.1.txt
rename to Documentation/RelNotes/1.6.1.1.adoc
diff --git a/Documentation/RelNotes/1.6.1.2.txt b/Documentation/RelNotes/1.6.1.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.1.2.txt
rename to Documentation/RelNotes/1.6.1.2.adoc
diff --git a/Documentation/RelNotes/1.6.1.3.txt b/Documentation/RelNotes/1.6.1.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.1.3.txt
rename to Documentation/RelNotes/1.6.1.3.adoc
diff --git a/Documentation/RelNotes/1.6.1.4.txt b/Documentation/RelNotes/1.6.1.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.1.4.txt
rename to Documentation/RelNotes/1.6.1.4.adoc
diff --git a/Documentation/RelNotes/1.6.1.txt b/Documentation/RelNotes/1.6.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.1.txt
rename to Documentation/RelNotes/1.6.1.adoc
diff --git a/Documentation/RelNotes/1.6.2.1.txt b/Documentation/RelNotes/1.6.2.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.2.1.txt
rename to Documentation/RelNotes/1.6.2.1.adoc
diff --git a/Documentation/RelNotes/1.6.2.2.txt b/Documentation/RelNotes/1.6.2.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.2.2.txt
rename to Documentation/RelNotes/1.6.2.2.adoc
diff --git a/Documentation/RelNotes/1.6.2.3.txt b/Documentation/RelNotes/1.6.2.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.2.3.txt
rename to Documentation/RelNotes/1.6.2.3.adoc
diff --git a/Documentation/RelNotes/1.6.2.4.txt b/Documentation/RelNotes/1.6.2.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.2.4.txt
rename to Documentation/RelNotes/1.6.2.4.adoc
diff --git a/Documentation/RelNotes/1.6.2.5.txt b/Documentation/RelNotes/1.6.2.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.2.5.txt
rename to Documentation/RelNotes/1.6.2.5.adoc
diff --git a/Documentation/RelNotes/1.6.2.txt b/Documentation/RelNotes/1.6.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.2.txt
rename to Documentation/RelNotes/1.6.2.adoc
diff --git a/Documentation/RelNotes/1.6.3.1.txt b/Documentation/RelNotes/1.6.3.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.3.1.txt
rename to Documentation/RelNotes/1.6.3.1.adoc
diff --git a/Documentation/RelNotes/1.6.3.2.txt b/Documentation/RelNotes/1.6.3.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.3.2.txt
rename to Documentation/RelNotes/1.6.3.2.adoc
diff --git a/Documentation/RelNotes/1.6.3.3.txt b/Documentation/RelNotes/1.6.3.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.3.3.txt
rename to Documentation/RelNotes/1.6.3.3.adoc
diff --git a/Documentation/RelNotes/1.6.3.4.txt b/Documentation/RelNotes/1.6.3.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.3.4.txt
rename to Documentation/RelNotes/1.6.3.4.adoc
diff --git a/Documentation/RelNotes/1.6.3.txt b/Documentation/RelNotes/1.6.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.3.txt
rename to Documentation/RelNotes/1.6.3.adoc
diff --git a/Documentation/RelNotes/1.6.4.1.txt b/Documentation/RelNotes/1.6.4.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.4.1.txt
rename to Documentation/RelNotes/1.6.4.1.adoc
diff --git a/Documentation/RelNotes/1.6.4.2.txt b/Documentation/RelNotes/1.6.4.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.4.2.txt
rename to Documentation/RelNotes/1.6.4.2.adoc
diff --git a/Documentation/RelNotes/1.6.4.3.txt b/Documentation/RelNotes/1.6.4.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.4.3.txt
rename to Documentation/RelNotes/1.6.4.3.adoc
diff --git a/Documentation/RelNotes/1.6.4.4.txt b/Documentation/RelNotes/1.6.4.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.4.4.txt
rename to Documentation/RelNotes/1.6.4.4.adoc
diff --git a/Documentation/RelNotes/1.6.4.5.txt b/Documentation/RelNotes/1.6.4.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.4.5.txt
rename to Documentation/RelNotes/1.6.4.5.adoc
diff --git a/Documentation/RelNotes/1.6.4.txt b/Documentation/RelNotes/1.6.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.4.txt
rename to Documentation/RelNotes/1.6.4.adoc
diff --git a/Documentation/RelNotes/1.6.5.1.txt b/Documentation/RelNotes/1.6.5.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.5.1.txt
rename to Documentation/RelNotes/1.6.5.1.adoc
diff --git a/Documentation/RelNotes/1.6.5.2.txt b/Documentation/RelNotes/1.6.5.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.5.2.txt
rename to Documentation/RelNotes/1.6.5.2.adoc
diff --git a/Documentation/RelNotes/1.6.5.3.txt b/Documentation/RelNotes/1.6.5.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.5.3.txt
rename to Documentation/RelNotes/1.6.5.3.adoc
diff --git a/Documentation/RelNotes/1.6.5.4.txt b/Documentation/RelNotes/1.6.5.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.5.4.txt
rename to Documentation/RelNotes/1.6.5.4.adoc
diff --git a/Documentation/RelNotes/1.6.5.5.txt b/Documentation/RelNotes/1.6.5.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.5.5.txt
rename to Documentation/RelNotes/1.6.5.5.adoc
diff --git a/Documentation/RelNotes/1.6.5.6.txt b/Documentation/RelNotes/1.6.5.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.5.6.txt
rename to Documentation/RelNotes/1.6.5.6.adoc
diff --git a/Documentation/RelNotes/1.6.5.7.txt b/Documentation/RelNotes/1.6.5.7.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.5.7.txt
rename to Documentation/RelNotes/1.6.5.7.adoc
diff --git a/Documentation/RelNotes/1.6.5.8.txt b/Documentation/RelNotes/1.6.5.8.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.5.8.txt
rename to Documentation/RelNotes/1.6.5.8.adoc
diff --git a/Documentation/RelNotes/1.6.5.9.txt b/Documentation/RelNotes/1.6.5.9.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.5.9.txt
rename to Documentation/RelNotes/1.6.5.9.adoc
diff --git a/Documentation/RelNotes/1.6.5.txt b/Documentation/RelNotes/1.6.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.5.txt
rename to Documentation/RelNotes/1.6.5.adoc
diff --git a/Documentation/RelNotes/1.6.6.1.txt b/Documentation/RelNotes/1.6.6.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.6.1.txt
rename to Documentation/RelNotes/1.6.6.1.adoc
diff --git a/Documentation/RelNotes/1.6.6.2.txt b/Documentation/RelNotes/1.6.6.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.6.2.txt
rename to Documentation/RelNotes/1.6.6.2.adoc
diff --git a/Documentation/RelNotes/1.6.6.3.txt b/Documentation/RelNotes/1.6.6.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.6.3.txt
rename to Documentation/RelNotes/1.6.6.3.adoc
diff --git a/Documentation/RelNotes/1.6.6.txt b/Documentation/RelNotes/1.6.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.6.6.txt
rename to Documentation/RelNotes/1.6.6.adoc
diff --git a/Documentation/RelNotes/1.7.0.1.txt b/Documentation/RelNotes/1.7.0.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.0.1.txt
rename to Documentation/RelNotes/1.7.0.1.adoc
diff --git a/Documentation/RelNotes/1.7.0.2.txt b/Documentation/RelNotes/1.7.0.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.0.2.txt
rename to Documentation/RelNotes/1.7.0.2.adoc
diff --git a/Documentation/RelNotes/1.7.0.3.txt b/Documentation/RelNotes/1.7.0.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.0.3.txt
rename to Documentation/RelNotes/1.7.0.3.adoc
diff --git a/Documentation/RelNotes/1.7.0.4.txt b/Documentation/RelNotes/1.7.0.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.0.4.txt
rename to Documentation/RelNotes/1.7.0.4.adoc
diff --git a/Documentation/RelNotes/1.7.0.5.txt b/Documentation/RelNotes/1.7.0.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.0.5.txt
rename to Documentation/RelNotes/1.7.0.5.adoc
diff --git a/Documentation/RelNotes/1.7.0.6.txt b/Documentation/RelNotes/1.7.0.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.0.6.txt
rename to Documentation/RelNotes/1.7.0.6.adoc
diff --git a/Documentation/RelNotes/1.7.0.7.txt b/Documentation/RelNotes/1.7.0.7.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.0.7.txt
rename to Documentation/RelNotes/1.7.0.7.adoc
diff --git a/Documentation/RelNotes/1.7.0.8.txt b/Documentation/RelNotes/1.7.0.8.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.0.8.txt
rename to Documentation/RelNotes/1.7.0.8.adoc
diff --git a/Documentation/RelNotes/1.7.0.9.txt b/Documentation/RelNotes/1.7.0.9.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.0.9.txt
rename to Documentation/RelNotes/1.7.0.9.adoc
diff --git a/Documentation/RelNotes/1.7.0.txt b/Documentation/RelNotes/1.7.0.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.0.txt
rename to Documentation/RelNotes/1.7.0.adoc
diff --git a/Documentation/RelNotes/1.7.1.1.txt b/Documentation/RelNotes/1.7.1.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.1.1.txt
rename to Documentation/RelNotes/1.7.1.1.adoc
diff --git a/Documentation/RelNotes/1.7.1.2.txt b/Documentation/RelNotes/1.7.1.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.1.2.txt
rename to Documentation/RelNotes/1.7.1.2.adoc
diff --git a/Documentation/RelNotes/1.7.1.3.txt b/Documentation/RelNotes/1.7.1.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.1.3.txt
rename to Documentation/RelNotes/1.7.1.3.adoc
diff --git a/Documentation/RelNotes/1.7.1.4.txt b/Documentation/RelNotes/1.7.1.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.1.4.txt
rename to Documentation/RelNotes/1.7.1.4.adoc
diff --git a/Documentation/RelNotes/1.7.1.txt b/Documentation/RelNotes/1.7.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.1.txt
rename to Documentation/RelNotes/1.7.1.adoc
diff --git a/Documentation/RelNotes/1.7.10.1.txt b/Documentation/RelNotes/1.7.10.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.10.1.txt
rename to Documentation/RelNotes/1.7.10.1.adoc
diff --git a/Documentation/RelNotes/1.7.10.2.txt b/Documentation/RelNotes/1.7.10.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.10.2.txt
rename to Documentation/RelNotes/1.7.10.2.adoc
diff --git a/Documentation/RelNotes/1.7.10.3.txt b/Documentation/RelNotes/1.7.10.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.10.3.txt
rename to Documentation/RelNotes/1.7.10.3.adoc
diff --git a/Documentation/RelNotes/1.7.10.4.txt b/Documentation/RelNotes/1.7.10.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.10.4.txt
rename to Documentation/RelNotes/1.7.10.4.adoc
diff --git a/Documentation/RelNotes/1.7.10.5.txt b/Documentation/RelNotes/1.7.10.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.10.5.txt
rename to Documentation/RelNotes/1.7.10.5.adoc
diff --git a/Documentation/RelNotes/1.7.10.txt b/Documentation/RelNotes/1.7.10.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.10.txt
rename to Documentation/RelNotes/1.7.10.adoc
diff --git a/Documentation/RelNotes/1.7.11.1.txt b/Documentation/RelNotes/1.7.11.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.11.1.txt
rename to Documentation/RelNotes/1.7.11.1.adoc
diff --git a/Documentation/RelNotes/1.7.11.2.txt b/Documentation/RelNotes/1.7.11.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.11.2.txt
rename to Documentation/RelNotes/1.7.11.2.adoc
diff --git a/Documentation/RelNotes/1.7.11.3.txt b/Documentation/RelNotes/1.7.11.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.11.3.txt
rename to Documentation/RelNotes/1.7.11.3.adoc
diff --git a/Documentation/RelNotes/1.7.11.4.txt b/Documentation/RelNotes/1.7.11.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.11.4.txt
rename to Documentation/RelNotes/1.7.11.4.adoc
diff --git a/Documentation/RelNotes/1.7.11.5.txt b/Documentation/RelNotes/1.7.11.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.11.5.txt
rename to Documentation/RelNotes/1.7.11.5.adoc
diff --git a/Documentation/RelNotes/1.7.11.6.txt b/Documentation/RelNotes/1.7.11.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.11.6.txt
rename to Documentation/RelNotes/1.7.11.6.adoc
diff --git a/Documentation/RelNotes/1.7.11.7.txt b/Documentation/RelNotes/1.7.11.7.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.11.7.txt
rename to Documentation/RelNotes/1.7.11.7.adoc
diff --git a/Documentation/RelNotes/1.7.11.txt b/Documentation/RelNotes/1.7.11.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.11.txt
rename to Documentation/RelNotes/1.7.11.adoc
diff --git a/Documentation/RelNotes/1.7.12.1.txt b/Documentation/RelNotes/1.7.12.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.12.1.txt
rename to Documentation/RelNotes/1.7.12.1.adoc
diff --git a/Documentation/RelNotes/1.7.12.2.txt b/Documentation/RelNotes/1.7.12.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.12.2.txt
rename to Documentation/RelNotes/1.7.12.2.adoc
diff --git a/Documentation/RelNotes/1.7.12.3.txt b/Documentation/RelNotes/1.7.12.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.12.3.txt
rename to Documentation/RelNotes/1.7.12.3.adoc
diff --git a/Documentation/RelNotes/1.7.12.4.txt b/Documentation/RelNotes/1.7.12.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.12.4.txt
rename to Documentation/RelNotes/1.7.12.4.adoc
diff --git a/Documentation/RelNotes/1.7.12.txt b/Documentation/RelNotes/1.7.12.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.12.txt
rename to Documentation/RelNotes/1.7.12.adoc
diff --git a/Documentation/RelNotes/1.7.2.1.txt b/Documentation/RelNotes/1.7.2.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.2.1.txt
rename to Documentation/RelNotes/1.7.2.1.adoc
diff --git a/Documentation/RelNotes/1.7.2.2.txt b/Documentation/RelNotes/1.7.2.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.2.2.txt
rename to Documentation/RelNotes/1.7.2.2.adoc
diff --git a/Documentation/RelNotes/1.7.2.3.txt b/Documentation/RelNotes/1.7.2.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.2.3.txt
rename to Documentation/RelNotes/1.7.2.3.adoc
diff --git a/Documentation/RelNotes/1.7.2.4.txt b/Documentation/RelNotes/1.7.2.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.2.4.txt
rename to Documentation/RelNotes/1.7.2.4.adoc
diff --git a/Documentation/RelNotes/1.7.2.5.txt b/Documentation/RelNotes/1.7.2.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.2.5.txt
rename to Documentation/RelNotes/1.7.2.5.adoc
diff --git a/Documentation/RelNotes/1.7.2.txt b/Documentation/RelNotes/1.7.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.2.txt
rename to Documentation/RelNotes/1.7.2.adoc
diff --git a/Documentation/RelNotes/1.7.3.1.txt b/Documentation/RelNotes/1.7.3.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.3.1.txt
rename to Documentation/RelNotes/1.7.3.1.adoc
diff --git a/Documentation/RelNotes/1.7.3.2.txt b/Documentation/RelNotes/1.7.3.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.3.2.txt
rename to Documentation/RelNotes/1.7.3.2.adoc
diff --git a/Documentation/RelNotes/1.7.3.3.txt b/Documentation/RelNotes/1.7.3.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.3.3.txt
rename to Documentation/RelNotes/1.7.3.3.adoc
diff --git a/Documentation/RelNotes/1.7.3.4.txt b/Documentation/RelNotes/1.7.3.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.3.4.txt
rename to Documentation/RelNotes/1.7.3.4.adoc
diff --git a/Documentation/RelNotes/1.7.3.5.txt b/Documentation/RelNotes/1.7.3.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.3.5.txt
rename to Documentation/RelNotes/1.7.3.5.adoc
diff --git a/Documentation/RelNotes/1.7.3.txt b/Documentation/RelNotes/1.7.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.3.txt
rename to Documentation/RelNotes/1.7.3.adoc
diff --git a/Documentation/RelNotes/1.7.4.1.txt b/Documentation/RelNotes/1.7.4.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.4.1.txt
rename to Documentation/RelNotes/1.7.4.1.adoc
diff --git a/Documentation/RelNotes/1.7.4.2.txt b/Documentation/RelNotes/1.7.4.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.4.2.txt
rename to Documentation/RelNotes/1.7.4.2.adoc
diff --git a/Documentation/RelNotes/1.7.4.3.txt b/Documentation/RelNotes/1.7.4.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.4.3.txt
rename to Documentation/RelNotes/1.7.4.3.adoc
diff --git a/Documentation/RelNotes/1.7.4.4.txt b/Documentation/RelNotes/1.7.4.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.4.4.txt
rename to Documentation/RelNotes/1.7.4.4.adoc
diff --git a/Documentation/RelNotes/1.7.4.5.txt b/Documentation/RelNotes/1.7.4.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.4.5.txt
rename to Documentation/RelNotes/1.7.4.5.adoc
diff --git a/Documentation/RelNotes/1.7.4.txt b/Documentation/RelNotes/1.7.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.4.txt
rename to Documentation/RelNotes/1.7.4.adoc
diff --git a/Documentation/RelNotes/1.7.5.1.txt b/Documentation/RelNotes/1.7.5.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.5.1.txt
rename to Documentation/RelNotes/1.7.5.1.adoc
diff --git a/Documentation/RelNotes/1.7.5.2.txt b/Documentation/RelNotes/1.7.5.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.5.2.txt
rename to Documentation/RelNotes/1.7.5.2.adoc
diff --git a/Documentation/RelNotes/1.7.5.3.txt b/Documentation/RelNotes/1.7.5.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.5.3.txt
rename to Documentation/RelNotes/1.7.5.3.adoc
diff --git a/Documentation/RelNotes/1.7.5.4.txt b/Documentation/RelNotes/1.7.5.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.5.4.txt
rename to Documentation/RelNotes/1.7.5.4.adoc
diff --git a/Documentation/RelNotes/1.7.5.txt b/Documentation/RelNotes/1.7.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.5.txt
rename to Documentation/RelNotes/1.7.5.adoc
diff --git a/Documentation/RelNotes/1.7.6.1.txt b/Documentation/RelNotes/1.7.6.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.6.1.txt
rename to Documentation/RelNotes/1.7.6.1.adoc
diff --git a/Documentation/RelNotes/1.7.6.2.txt b/Documentation/RelNotes/1.7.6.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.6.2.txt
rename to Documentation/RelNotes/1.7.6.2.adoc
diff --git a/Documentation/RelNotes/1.7.6.3.txt b/Documentation/RelNotes/1.7.6.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.6.3.txt
rename to Documentation/RelNotes/1.7.6.3.adoc
diff --git a/Documentation/RelNotes/1.7.6.4.txt b/Documentation/RelNotes/1.7.6.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.6.4.txt
rename to Documentation/RelNotes/1.7.6.4.adoc
diff --git a/Documentation/RelNotes/1.7.6.5.txt b/Documentation/RelNotes/1.7.6.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.6.5.txt
rename to Documentation/RelNotes/1.7.6.5.adoc
diff --git a/Documentation/RelNotes/1.7.6.6.txt b/Documentation/RelNotes/1.7.6.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.6.6.txt
rename to Documentation/RelNotes/1.7.6.6.adoc
diff --git a/Documentation/RelNotes/1.7.6.txt b/Documentation/RelNotes/1.7.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.6.txt
rename to Documentation/RelNotes/1.7.6.adoc
diff --git a/Documentation/RelNotes/1.7.7.1.txt b/Documentation/RelNotes/1.7.7.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.7.1.txt
rename to Documentation/RelNotes/1.7.7.1.adoc
diff --git a/Documentation/RelNotes/1.7.7.2.txt b/Documentation/RelNotes/1.7.7.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.7.2.txt
rename to Documentation/RelNotes/1.7.7.2.adoc
diff --git a/Documentation/RelNotes/1.7.7.3.txt b/Documentation/RelNotes/1.7.7.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.7.3.txt
rename to Documentation/RelNotes/1.7.7.3.adoc
diff --git a/Documentation/RelNotes/1.7.7.4.txt b/Documentation/RelNotes/1.7.7.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.7.4.txt
rename to Documentation/RelNotes/1.7.7.4.adoc
diff --git a/Documentation/RelNotes/1.7.7.5.txt b/Documentation/RelNotes/1.7.7.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.7.5.txt
rename to Documentation/RelNotes/1.7.7.5.adoc
diff --git a/Documentation/RelNotes/1.7.7.6.txt b/Documentation/RelNotes/1.7.7.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.7.6.txt
rename to Documentation/RelNotes/1.7.7.6.adoc
diff --git a/Documentation/RelNotes/1.7.7.7.txt b/Documentation/RelNotes/1.7.7.7.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.7.7.txt
rename to Documentation/RelNotes/1.7.7.7.adoc
diff --git a/Documentation/RelNotes/1.7.7.txt b/Documentation/RelNotes/1.7.7.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.7.txt
rename to Documentation/RelNotes/1.7.7.adoc
diff --git a/Documentation/RelNotes/1.7.8.1.txt b/Documentation/RelNotes/1.7.8.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.8.1.txt
rename to Documentation/RelNotes/1.7.8.1.adoc
diff --git a/Documentation/RelNotes/1.7.8.2.txt b/Documentation/RelNotes/1.7.8.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.8.2.txt
rename to Documentation/RelNotes/1.7.8.2.adoc
diff --git a/Documentation/RelNotes/1.7.8.3.txt b/Documentation/RelNotes/1.7.8.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.8.3.txt
rename to Documentation/RelNotes/1.7.8.3.adoc
diff --git a/Documentation/RelNotes/1.7.8.4.txt b/Documentation/RelNotes/1.7.8.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.8.4.txt
rename to Documentation/RelNotes/1.7.8.4.adoc
diff --git a/Documentation/RelNotes/1.7.8.5.txt b/Documentation/RelNotes/1.7.8.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.8.5.txt
rename to Documentation/RelNotes/1.7.8.5.adoc
diff --git a/Documentation/RelNotes/1.7.8.6.txt b/Documentation/RelNotes/1.7.8.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.8.6.txt
rename to Documentation/RelNotes/1.7.8.6.adoc
diff --git a/Documentation/RelNotes/1.7.8.txt b/Documentation/RelNotes/1.7.8.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.8.txt
rename to Documentation/RelNotes/1.7.8.adoc
diff --git a/Documentation/RelNotes/1.7.9.1.txt b/Documentation/RelNotes/1.7.9.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.9.1.txt
rename to Documentation/RelNotes/1.7.9.1.adoc
diff --git a/Documentation/RelNotes/1.7.9.2.txt b/Documentation/RelNotes/1.7.9.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.9.2.txt
rename to Documentation/RelNotes/1.7.9.2.adoc
diff --git a/Documentation/RelNotes/1.7.9.3.txt b/Documentation/RelNotes/1.7.9.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.9.3.txt
rename to Documentation/RelNotes/1.7.9.3.adoc
diff --git a/Documentation/RelNotes/1.7.9.4.txt b/Documentation/RelNotes/1.7.9.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.9.4.txt
rename to Documentation/RelNotes/1.7.9.4.adoc
diff --git a/Documentation/RelNotes/1.7.9.5.txt b/Documentation/RelNotes/1.7.9.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.9.5.txt
rename to Documentation/RelNotes/1.7.9.5.adoc
diff --git a/Documentation/RelNotes/1.7.9.6.txt b/Documentation/RelNotes/1.7.9.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.9.6.txt
rename to Documentation/RelNotes/1.7.9.6.adoc
diff --git a/Documentation/RelNotes/1.7.9.7.txt b/Documentation/RelNotes/1.7.9.7.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.9.7.txt
rename to Documentation/RelNotes/1.7.9.7.adoc
diff --git a/Documentation/RelNotes/1.7.9.txt b/Documentation/RelNotes/1.7.9.adoc
similarity index 100%
rename from Documentation/RelNotes/1.7.9.txt
rename to Documentation/RelNotes/1.7.9.adoc
diff --git a/Documentation/RelNotes/1.8.0.1.txt b/Documentation/RelNotes/1.8.0.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.0.1.txt
rename to Documentation/RelNotes/1.8.0.1.adoc
diff --git a/Documentation/RelNotes/1.8.0.2.txt b/Documentation/RelNotes/1.8.0.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.0.2.txt
rename to Documentation/RelNotes/1.8.0.2.adoc
diff --git a/Documentation/RelNotes/1.8.0.3.txt b/Documentation/RelNotes/1.8.0.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.0.3.txt
rename to Documentation/RelNotes/1.8.0.3.adoc
diff --git a/Documentation/RelNotes/1.8.0.txt b/Documentation/RelNotes/1.8.0.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.0.txt
rename to Documentation/RelNotes/1.8.0.adoc
diff --git a/Documentation/RelNotes/1.8.1.1.txt b/Documentation/RelNotes/1.8.1.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.1.1.txt
rename to Documentation/RelNotes/1.8.1.1.adoc
diff --git a/Documentation/RelNotes/1.8.1.2.txt b/Documentation/RelNotes/1.8.1.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.1.2.txt
rename to Documentation/RelNotes/1.8.1.2.adoc
diff --git a/Documentation/RelNotes/1.8.1.3.txt b/Documentation/RelNotes/1.8.1.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.1.3.txt
rename to Documentation/RelNotes/1.8.1.3.adoc
diff --git a/Documentation/RelNotes/1.8.1.4.txt b/Documentation/RelNotes/1.8.1.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.1.4.txt
rename to Documentation/RelNotes/1.8.1.4.adoc
diff --git a/Documentation/RelNotes/1.8.1.5.txt b/Documentation/RelNotes/1.8.1.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.1.5.txt
rename to Documentation/RelNotes/1.8.1.5.adoc
diff --git a/Documentation/RelNotes/1.8.1.6.txt b/Documentation/RelNotes/1.8.1.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.1.6.txt
rename to Documentation/RelNotes/1.8.1.6.adoc
diff --git a/Documentation/RelNotes/1.8.1.txt b/Documentation/RelNotes/1.8.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.1.txt
rename to Documentation/RelNotes/1.8.1.adoc
diff --git a/Documentation/RelNotes/1.8.2.1.txt b/Documentation/RelNotes/1.8.2.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.2.1.txt
rename to Documentation/RelNotes/1.8.2.1.adoc
diff --git a/Documentation/RelNotes/1.8.2.2.txt b/Documentation/RelNotes/1.8.2.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.2.2.txt
rename to Documentation/RelNotes/1.8.2.2.adoc
diff --git a/Documentation/RelNotes/1.8.2.3.txt b/Documentation/RelNotes/1.8.2.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.2.3.txt
rename to Documentation/RelNotes/1.8.2.3.adoc
diff --git a/Documentation/RelNotes/1.8.2.txt b/Documentation/RelNotes/1.8.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.2.txt
rename to Documentation/RelNotes/1.8.2.adoc
diff --git a/Documentation/RelNotes/1.8.3.1.txt b/Documentation/RelNotes/1.8.3.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.3.1.txt
rename to Documentation/RelNotes/1.8.3.1.adoc
diff --git a/Documentation/RelNotes/1.8.3.2.txt b/Documentation/RelNotes/1.8.3.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.3.2.txt
rename to Documentation/RelNotes/1.8.3.2.adoc
diff --git a/Documentation/RelNotes/1.8.3.3.txt b/Documentation/RelNotes/1.8.3.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.3.3.txt
rename to Documentation/RelNotes/1.8.3.3.adoc
diff --git a/Documentation/RelNotes/1.8.3.4.txt b/Documentation/RelNotes/1.8.3.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.3.4.txt
rename to Documentation/RelNotes/1.8.3.4.adoc
diff --git a/Documentation/RelNotes/1.8.3.txt b/Documentation/RelNotes/1.8.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.3.txt
rename to Documentation/RelNotes/1.8.3.adoc
diff --git a/Documentation/RelNotes/1.8.4.1.txt b/Documentation/RelNotes/1.8.4.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.4.1.txt
rename to Documentation/RelNotes/1.8.4.1.adoc
diff --git a/Documentation/RelNotes/1.8.4.2.txt b/Documentation/RelNotes/1.8.4.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.4.2.txt
rename to Documentation/RelNotes/1.8.4.2.adoc
diff --git a/Documentation/RelNotes/1.8.4.3.txt b/Documentation/RelNotes/1.8.4.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.4.3.txt
rename to Documentation/RelNotes/1.8.4.3.adoc
diff --git a/Documentation/RelNotes/1.8.4.4.txt b/Documentation/RelNotes/1.8.4.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.4.4.txt
rename to Documentation/RelNotes/1.8.4.4.adoc
diff --git a/Documentation/RelNotes/1.8.4.5.txt b/Documentation/RelNotes/1.8.4.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.4.5.txt
rename to Documentation/RelNotes/1.8.4.5.adoc
diff --git a/Documentation/RelNotes/1.8.4.txt b/Documentation/RelNotes/1.8.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.4.txt
rename to Documentation/RelNotes/1.8.4.adoc
diff --git a/Documentation/RelNotes/1.8.5.1.txt b/Documentation/RelNotes/1.8.5.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.5.1.txt
rename to Documentation/RelNotes/1.8.5.1.adoc
diff --git a/Documentation/RelNotes/1.8.5.2.txt b/Documentation/RelNotes/1.8.5.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.5.2.txt
rename to Documentation/RelNotes/1.8.5.2.adoc
diff --git a/Documentation/RelNotes/1.8.5.3.txt b/Documentation/RelNotes/1.8.5.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.5.3.txt
rename to Documentation/RelNotes/1.8.5.3.adoc
diff --git a/Documentation/RelNotes/1.8.5.4.txt b/Documentation/RelNotes/1.8.5.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.5.4.txt
rename to Documentation/RelNotes/1.8.5.4.adoc
diff --git a/Documentation/RelNotes/1.8.5.5.txt b/Documentation/RelNotes/1.8.5.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.5.5.txt
rename to Documentation/RelNotes/1.8.5.5.adoc
diff --git a/Documentation/RelNotes/1.8.5.6.txt b/Documentation/RelNotes/1.8.5.6.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.5.6.txt
rename to Documentation/RelNotes/1.8.5.6.adoc
diff --git a/Documentation/RelNotes/1.8.5.txt b/Documentation/RelNotes/1.8.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.8.5.txt
rename to Documentation/RelNotes/1.8.5.adoc
diff --git a/Documentation/RelNotes/1.9.0.txt b/Documentation/RelNotes/1.9.0.adoc
similarity index 100%
rename from Documentation/RelNotes/1.9.0.txt
rename to Documentation/RelNotes/1.9.0.adoc
diff --git a/Documentation/RelNotes/1.9.1.txt b/Documentation/RelNotes/1.9.1.adoc
similarity index 100%
rename from Documentation/RelNotes/1.9.1.txt
rename to Documentation/RelNotes/1.9.1.adoc
diff --git a/Documentation/RelNotes/1.9.2.txt b/Documentation/RelNotes/1.9.2.adoc
similarity index 100%
rename from Documentation/RelNotes/1.9.2.txt
rename to Documentation/RelNotes/1.9.2.adoc
diff --git a/Documentation/RelNotes/1.9.3.txt b/Documentation/RelNotes/1.9.3.adoc
similarity index 100%
rename from Documentation/RelNotes/1.9.3.txt
rename to Documentation/RelNotes/1.9.3.adoc
diff --git a/Documentation/RelNotes/1.9.4.txt b/Documentation/RelNotes/1.9.4.adoc
similarity index 100%
rename from Documentation/RelNotes/1.9.4.txt
rename to Documentation/RelNotes/1.9.4.adoc
diff --git a/Documentation/RelNotes/1.9.5.txt b/Documentation/RelNotes/1.9.5.adoc
similarity index 100%
rename from Documentation/RelNotes/1.9.5.txt
rename to Documentation/RelNotes/1.9.5.adoc
diff --git a/Documentation/RelNotes/2.0.0.txt b/Documentation/RelNotes/2.0.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.0.0.txt
rename to Documentation/RelNotes/2.0.0.adoc
diff --git a/Documentation/RelNotes/2.0.1.txt b/Documentation/RelNotes/2.0.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.0.1.txt
rename to Documentation/RelNotes/2.0.1.adoc
diff --git a/Documentation/RelNotes/2.0.2.txt b/Documentation/RelNotes/2.0.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.0.2.txt
rename to Documentation/RelNotes/2.0.2.adoc
diff --git a/Documentation/RelNotes/2.0.3.txt b/Documentation/RelNotes/2.0.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.0.3.txt
rename to Documentation/RelNotes/2.0.3.adoc
diff --git a/Documentation/RelNotes/2.0.4.txt b/Documentation/RelNotes/2.0.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.0.4.txt
rename to Documentation/RelNotes/2.0.4.adoc
diff --git a/Documentation/RelNotes/2.0.5.txt b/Documentation/RelNotes/2.0.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.0.5.txt
rename to Documentation/RelNotes/2.0.5.adoc
diff --git a/Documentation/RelNotes/2.1.0.txt b/Documentation/RelNotes/2.1.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.1.0.txt
rename to Documentation/RelNotes/2.1.0.adoc
diff --git a/Documentation/RelNotes/2.1.1.txt b/Documentation/RelNotes/2.1.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.1.1.txt
rename to Documentation/RelNotes/2.1.1.adoc
diff --git a/Documentation/RelNotes/2.1.2.txt b/Documentation/RelNotes/2.1.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.1.2.txt
rename to Documentation/RelNotes/2.1.2.adoc
diff --git a/Documentation/RelNotes/2.1.3.txt b/Documentation/RelNotes/2.1.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.1.3.txt
rename to Documentation/RelNotes/2.1.3.adoc
diff --git a/Documentation/RelNotes/2.1.4.txt b/Documentation/RelNotes/2.1.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.1.4.txt
rename to Documentation/RelNotes/2.1.4.adoc
diff --git a/Documentation/RelNotes/2.10.0.txt b/Documentation/RelNotes/2.10.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.10.0.txt
rename to Documentation/RelNotes/2.10.0.adoc
diff --git a/Documentation/RelNotes/2.10.1.txt b/Documentation/RelNotes/2.10.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.10.1.txt
rename to Documentation/RelNotes/2.10.1.adoc
diff --git a/Documentation/RelNotes/2.10.2.txt b/Documentation/RelNotes/2.10.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.10.2.txt
rename to Documentation/RelNotes/2.10.2.adoc
diff --git a/Documentation/RelNotes/2.10.3.txt b/Documentation/RelNotes/2.10.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.10.3.txt
rename to Documentation/RelNotes/2.10.3.adoc
diff --git a/Documentation/RelNotes/2.10.4.txt b/Documentation/RelNotes/2.10.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.10.4.txt
rename to Documentation/RelNotes/2.10.4.adoc
diff --git a/Documentation/RelNotes/2.10.5.txt b/Documentation/RelNotes/2.10.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.10.5.txt
rename to Documentation/RelNotes/2.10.5.adoc
diff --git a/Documentation/RelNotes/2.11.0.txt b/Documentation/RelNotes/2.11.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.11.0.txt
rename to Documentation/RelNotes/2.11.0.adoc
diff --git a/Documentation/RelNotes/2.11.1.txt b/Documentation/RelNotes/2.11.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.11.1.txt
rename to Documentation/RelNotes/2.11.1.adoc
diff --git a/Documentation/RelNotes/2.11.2.txt b/Documentation/RelNotes/2.11.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.11.2.txt
rename to Documentation/RelNotes/2.11.2.adoc
diff --git a/Documentation/RelNotes/2.11.3.txt b/Documentation/RelNotes/2.11.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.11.3.txt
rename to Documentation/RelNotes/2.11.3.adoc
diff --git a/Documentation/RelNotes/2.11.4.txt b/Documentation/RelNotes/2.11.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.11.4.txt
rename to Documentation/RelNotes/2.11.4.adoc
diff --git a/Documentation/RelNotes/2.12.0.txt b/Documentation/RelNotes/2.12.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.12.0.txt
rename to Documentation/RelNotes/2.12.0.adoc
diff --git a/Documentation/RelNotes/2.12.1.txt b/Documentation/RelNotes/2.12.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.12.1.txt
rename to Documentation/RelNotes/2.12.1.adoc
diff --git a/Documentation/RelNotes/2.12.2.txt b/Documentation/RelNotes/2.12.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.12.2.txt
rename to Documentation/RelNotes/2.12.2.adoc
diff --git a/Documentation/RelNotes/2.12.3.txt b/Documentation/RelNotes/2.12.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.12.3.txt
rename to Documentation/RelNotes/2.12.3.adoc
diff --git a/Documentation/RelNotes/2.12.4.txt b/Documentation/RelNotes/2.12.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.12.4.txt
rename to Documentation/RelNotes/2.12.4.adoc
diff --git a/Documentation/RelNotes/2.12.5.txt b/Documentation/RelNotes/2.12.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.12.5.txt
rename to Documentation/RelNotes/2.12.5.adoc
diff --git a/Documentation/RelNotes/2.13.0.txt b/Documentation/RelNotes/2.13.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.13.0.txt
rename to Documentation/RelNotes/2.13.0.adoc
diff --git a/Documentation/RelNotes/2.13.1.txt b/Documentation/RelNotes/2.13.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.13.1.txt
rename to Documentation/RelNotes/2.13.1.adoc
diff --git a/Documentation/RelNotes/2.13.2.txt b/Documentation/RelNotes/2.13.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.13.2.txt
rename to Documentation/RelNotes/2.13.2.adoc
diff --git a/Documentation/RelNotes/2.13.3.txt b/Documentation/RelNotes/2.13.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.13.3.txt
rename to Documentation/RelNotes/2.13.3.adoc
diff --git a/Documentation/RelNotes/2.13.4.txt b/Documentation/RelNotes/2.13.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.13.4.txt
rename to Documentation/RelNotes/2.13.4.adoc
diff --git a/Documentation/RelNotes/2.13.5.txt b/Documentation/RelNotes/2.13.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.13.5.txt
rename to Documentation/RelNotes/2.13.5.adoc
diff --git a/Documentation/RelNotes/2.13.6.txt b/Documentation/RelNotes/2.13.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.13.6.txt
rename to Documentation/RelNotes/2.13.6.adoc
diff --git a/Documentation/RelNotes/2.13.7.txt b/Documentation/RelNotes/2.13.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.13.7.txt
rename to Documentation/RelNotes/2.13.7.adoc
diff --git a/Documentation/RelNotes/2.14.0.txt b/Documentation/RelNotes/2.14.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.14.0.txt
rename to Documentation/RelNotes/2.14.0.adoc
diff --git a/Documentation/RelNotes/2.14.1.txt b/Documentation/RelNotes/2.14.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.14.1.txt
rename to Documentation/RelNotes/2.14.1.adoc
diff --git a/Documentation/RelNotes/2.14.2.txt b/Documentation/RelNotes/2.14.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.14.2.txt
rename to Documentation/RelNotes/2.14.2.adoc
diff --git a/Documentation/RelNotes/2.14.3.txt b/Documentation/RelNotes/2.14.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.14.3.txt
rename to Documentation/RelNotes/2.14.3.adoc
diff --git a/Documentation/RelNotes/2.14.4.txt b/Documentation/RelNotes/2.14.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.14.4.txt
rename to Documentation/RelNotes/2.14.4.adoc
diff --git a/Documentation/RelNotes/2.14.5.txt b/Documentation/RelNotes/2.14.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.14.5.txt
rename to Documentation/RelNotes/2.14.5.adoc
diff --git a/Documentation/RelNotes/2.14.6.txt b/Documentation/RelNotes/2.14.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.14.6.txt
rename to Documentation/RelNotes/2.14.6.adoc
diff --git a/Documentation/RelNotes/2.15.0.txt b/Documentation/RelNotes/2.15.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.15.0.txt
rename to Documentation/RelNotes/2.15.0.adoc
diff --git a/Documentation/RelNotes/2.15.1.txt b/Documentation/RelNotes/2.15.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.15.1.txt
rename to Documentation/RelNotes/2.15.1.adoc
diff --git a/Documentation/RelNotes/2.15.2.txt b/Documentation/RelNotes/2.15.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.15.2.txt
rename to Documentation/RelNotes/2.15.2.adoc
diff --git a/Documentation/RelNotes/2.15.3.txt b/Documentation/RelNotes/2.15.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.15.3.txt
rename to Documentation/RelNotes/2.15.3.adoc
diff --git a/Documentation/RelNotes/2.15.4.txt b/Documentation/RelNotes/2.15.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.15.4.txt
rename to Documentation/RelNotes/2.15.4.adoc
diff --git a/Documentation/RelNotes/2.16.0.txt b/Documentation/RelNotes/2.16.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.16.0.txt
rename to Documentation/RelNotes/2.16.0.adoc
diff --git a/Documentation/RelNotes/2.16.1.txt b/Documentation/RelNotes/2.16.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.16.1.txt
rename to Documentation/RelNotes/2.16.1.adoc
diff --git a/Documentation/RelNotes/2.16.2.txt b/Documentation/RelNotes/2.16.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.16.2.txt
rename to Documentation/RelNotes/2.16.2.adoc
diff --git a/Documentation/RelNotes/2.16.3.txt b/Documentation/RelNotes/2.16.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.16.3.txt
rename to Documentation/RelNotes/2.16.3.adoc
diff --git a/Documentation/RelNotes/2.16.4.txt b/Documentation/RelNotes/2.16.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.16.4.txt
rename to Documentation/RelNotes/2.16.4.adoc
diff --git a/Documentation/RelNotes/2.16.5.txt b/Documentation/RelNotes/2.16.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.16.5.txt
rename to Documentation/RelNotes/2.16.5.adoc
diff --git a/Documentation/RelNotes/2.16.6.txt b/Documentation/RelNotes/2.16.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.16.6.txt
rename to Documentation/RelNotes/2.16.6.adoc
diff --git a/Documentation/RelNotes/2.17.0.txt b/Documentation/RelNotes/2.17.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.17.0.txt
rename to Documentation/RelNotes/2.17.0.adoc
diff --git a/Documentation/RelNotes/2.17.1.txt b/Documentation/RelNotes/2.17.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.17.1.txt
rename to Documentation/RelNotes/2.17.1.adoc
diff --git a/Documentation/RelNotes/2.17.2.txt b/Documentation/RelNotes/2.17.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.17.2.txt
rename to Documentation/RelNotes/2.17.2.adoc
diff --git a/Documentation/RelNotes/2.17.3.txt b/Documentation/RelNotes/2.17.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.17.3.txt
rename to Documentation/RelNotes/2.17.3.adoc
diff --git a/Documentation/RelNotes/2.17.4.txt b/Documentation/RelNotes/2.17.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.17.4.txt
rename to Documentation/RelNotes/2.17.4.adoc
diff --git a/Documentation/RelNotes/2.17.5.txt b/Documentation/RelNotes/2.17.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.17.5.txt
rename to Documentation/RelNotes/2.17.5.adoc
diff --git a/Documentation/RelNotes/2.17.6.txt b/Documentation/RelNotes/2.17.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.17.6.txt
rename to Documentation/RelNotes/2.17.6.adoc
diff --git a/Documentation/RelNotes/2.18.0.txt b/Documentation/RelNotes/2.18.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.18.0.txt
rename to Documentation/RelNotes/2.18.0.adoc
diff --git a/Documentation/RelNotes/2.18.1.txt b/Documentation/RelNotes/2.18.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.18.1.txt
rename to Documentation/RelNotes/2.18.1.adoc
diff --git a/Documentation/RelNotes/2.18.2.txt b/Documentation/RelNotes/2.18.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.18.2.txt
rename to Documentation/RelNotes/2.18.2.adoc
diff --git a/Documentation/RelNotes/2.18.3.txt b/Documentation/RelNotes/2.18.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.18.3.txt
rename to Documentation/RelNotes/2.18.3.adoc
diff --git a/Documentation/RelNotes/2.18.4.txt b/Documentation/RelNotes/2.18.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.18.4.txt
rename to Documentation/RelNotes/2.18.4.adoc
diff --git a/Documentation/RelNotes/2.18.5.txt b/Documentation/RelNotes/2.18.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.18.5.txt
rename to Documentation/RelNotes/2.18.5.adoc
diff --git a/Documentation/RelNotes/2.19.0.txt b/Documentation/RelNotes/2.19.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.19.0.txt
rename to Documentation/RelNotes/2.19.0.adoc
diff --git a/Documentation/RelNotes/2.19.1.txt b/Documentation/RelNotes/2.19.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.19.1.txt
rename to Documentation/RelNotes/2.19.1.adoc
diff --git a/Documentation/RelNotes/2.19.2.txt b/Documentation/RelNotes/2.19.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.19.2.txt
rename to Documentation/RelNotes/2.19.2.adoc
diff --git a/Documentation/RelNotes/2.19.3.txt b/Documentation/RelNotes/2.19.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.19.3.txt
rename to Documentation/RelNotes/2.19.3.adoc
diff --git a/Documentation/RelNotes/2.19.4.txt b/Documentation/RelNotes/2.19.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.19.4.txt
rename to Documentation/RelNotes/2.19.4.adoc
diff --git a/Documentation/RelNotes/2.19.5.txt b/Documentation/RelNotes/2.19.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.19.5.txt
rename to Documentation/RelNotes/2.19.5.adoc
diff --git a/Documentation/RelNotes/2.19.6.txt b/Documentation/RelNotes/2.19.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.19.6.txt
rename to Documentation/RelNotes/2.19.6.adoc
diff --git a/Documentation/RelNotes/2.2.0.txt b/Documentation/RelNotes/2.2.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.2.0.txt
rename to Documentation/RelNotes/2.2.0.adoc
diff --git a/Documentation/RelNotes/2.2.1.txt b/Documentation/RelNotes/2.2.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.2.1.txt
rename to Documentation/RelNotes/2.2.1.adoc
diff --git a/Documentation/RelNotes/2.2.2.txt b/Documentation/RelNotes/2.2.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.2.2.txt
rename to Documentation/RelNotes/2.2.2.adoc
diff --git a/Documentation/RelNotes/2.2.3.txt b/Documentation/RelNotes/2.2.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.2.3.txt
rename to Documentation/RelNotes/2.2.3.adoc
diff --git a/Documentation/RelNotes/2.20.0.txt b/Documentation/RelNotes/2.20.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.20.0.txt
rename to Documentation/RelNotes/2.20.0.adoc
diff --git a/Documentation/RelNotes/2.20.1.txt b/Documentation/RelNotes/2.20.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.20.1.txt
rename to Documentation/RelNotes/2.20.1.adoc
diff --git a/Documentation/RelNotes/2.20.2.txt b/Documentation/RelNotes/2.20.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.20.2.txt
rename to Documentation/RelNotes/2.20.2.adoc
diff --git a/Documentation/RelNotes/2.20.3.txt b/Documentation/RelNotes/2.20.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.20.3.txt
rename to Documentation/RelNotes/2.20.3.adoc
diff --git a/Documentation/RelNotes/2.20.4.txt b/Documentation/RelNotes/2.20.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.20.4.txt
rename to Documentation/RelNotes/2.20.4.adoc
diff --git a/Documentation/RelNotes/2.20.5.txt b/Documentation/RelNotes/2.20.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.20.5.txt
rename to Documentation/RelNotes/2.20.5.adoc
diff --git a/Documentation/RelNotes/2.21.0.txt b/Documentation/RelNotes/2.21.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.21.0.txt
rename to Documentation/RelNotes/2.21.0.adoc
diff --git a/Documentation/RelNotes/2.21.1.txt b/Documentation/RelNotes/2.21.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.21.1.txt
rename to Documentation/RelNotes/2.21.1.adoc
diff --git a/Documentation/RelNotes/2.21.2.txt b/Documentation/RelNotes/2.21.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.21.2.txt
rename to Documentation/RelNotes/2.21.2.adoc
diff --git a/Documentation/RelNotes/2.21.3.txt b/Documentation/RelNotes/2.21.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.21.3.txt
rename to Documentation/RelNotes/2.21.3.adoc
diff --git a/Documentation/RelNotes/2.21.4.txt b/Documentation/RelNotes/2.21.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.21.4.txt
rename to Documentation/RelNotes/2.21.4.adoc
diff --git a/Documentation/RelNotes/2.22.0.txt b/Documentation/RelNotes/2.22.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.22.0.txt
rename to Documentation/RelNotes/2.22.0.adoc
diff --git a/Documentation/RelNotes/2.22.1.txt b/Documentation/RelNotes/2.22.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.22.1.txt
rename to Documentation/RelNotes/2.22.1.adoc
diff --git a/Documentation/RelNotes/2.22.2.txt b/Documentation/RelNotes/2.22.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.22.2.txt
rename to Documentation/RelNotes/2.22.2.adoc
diff --git a/Documentation/RelNotes/2.22.3.txt b/Documentation/RelNotes/2.22.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.22.3.txt
rename to Documentation/RelNotes/2.22.3.adoc
diff --git a/Documentation/RelNotes/2.22.4.txt b/Documentation/RelNotes/2.22.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.22.4.txt
rename to Documentation/RelNotes/2.22.4.adoc
diff --git a/Documentation/RelNotes/2.22.5.txt b/Documentation/RelNotes/2.22.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.22.5.txt
rename to Documentation/RelNotes/2.22.5.adoc
diff --git a/Documentation/RelNotes/2.23.0.txt b/Documentation/RelNotes/2.23.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.23.0.txt
rename to Documentation/RelNotes/2.23.0.adoc
diff --git a/Documentation/RelNotes/2.23.1.txt b/Documentation/RelNotes/2.23.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.23.1.txt
rename to Documentation/RelNotes/2.23.1.adoc
diff --git a/Documentation/RelNotes/2.23.2.txt b/Documentation/RelNotes/2.23.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.23.2.txt
rename to Documentation/RelNotes/2.23.2.adoc
diff --git a/Documentation/RelNotes/2.23.3.txt b/Documentation/RelNotes/2.23.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.23.3.txt
rename to Documentation/RelNotes/2.23.3.adoc
diff --git a/Documentation/RelNotes/2.23.4.txt b/Documentation/RelNotes/2.23.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.23.4.txt
rename to Documentation/RelNotes/2.23.4.adoc
diff --git a/Documentation/RelNotes/2.24.0.txt b/Documentation/RelNotes/2.24.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.24.0.txt
rename to Documentation/RelNotes/2.24.0.adoc
diff --git a/Documentation/RelNotes/2.24.1.txt b/Documentation/RelNotes/2.24.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.24.1.txt
rename to Documentation/RelNotes/2.24.1.adoc
diff --git a/Documentation/RelNotes/2.24.2.txt b/Documentation/RelNotes/2.24.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.24.2.txt
rename to Documentation/RelNotes/2.24.2.adoc
diff --git a/Documentation/RelNotes/2.24.3.txt b/Documentation/RelNotes/2.24.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.24.3.txt
rename to Documentation/RelNotes/2.24.3.adoc
diff --git a/Documentation/RelNotes/2.24.4.txt b/Documentation/RelNotes/2.24.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.24.4.txt
rename to Documentation/RelNotes/2.24.4.adoc
diff --git a/Documentation/RelNotes/2.25.0.txt b/Documentation/RelNotes/2.25.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.25.0.txt
rename to Documentation/RelNotes/2.25.0.adoc
diff --git a/Documentation/RelNotes/2.25.1.txt b/Documentation/RelNotes/2.25.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.25.1.txt
rename to Documentation/RelNotes/2.25.1.adoc
diff --git a/Documentation/RelNotes/2.25.2.txt b/Documentation/RelNotes/2.25.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.25.2.txt
rename to Documentation/RelNotes/2.25.2.adoc
diff --git a/Documentation/RelNotes/2.25.3.txt b/Documentation/RelNotes/2.25.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.25.3.txt
rename to Documentation/RelNotes/2.25.3.adoc
diff --git a/Documentation/RelNotes/2.25.4.txt b/Documentation/RelNotes/2.25.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.25.4.txt
rename to Documentation/RelNotes/2.25.4.adoc
diff --git a/Documentation/RelNotes/2.25.5.txt b/Documentation/RelNotes/2.25.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.25.5.txt
rename to Documentation/RelNotes/2.25.5.adoc
diff --git a/Documentation/RelNotes/2.26.0.txt b/Documentation/RelNotes/2.26.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.26.0.txt
rename to Documentation/RelNotes/2.26.0.adoc
diff --git a/Documentation/RelNotes/2.26.1.txt b/Documentation/RelNotes/2.26.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.26.1.txt
rename to Documentation/RelNotes/2.26.1.adoc
diff --git a/Documentation/RelNotes/2.26.2.txt b/Documentation/RelNotes/2.26.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.26.2.txt
rename to Documentation/RelNotes/2.26.2.adoc
diff --git a/Documentation/RelNotes/2.26.3.txt b/Documentation/RelNotes/2.26.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.26.3.txt
rename to Documentation/RelNotes/2.26.3.adoc
diff --git a/Documentation/RelNotes/2.27.0.txt b/Documentation/RelNotes/2.27.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.27.0.txt
rename to Documentation/RelNotes/2.27.0.adoc
diff --git a/Documentation/RelNotes/2.27.1.txt b/Documentation/RelNotes/2.27.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.27.1.txt
rename to Documentation/RelNotes/2.27.1.adoc
diff --git a/Documentation/RelNotes/2.28.0.txt b/Documentation/RelNotes/2.28.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.28.0.txt
rename to Documentation/RelNotes/2.28.0.adoc
diff --git a/Documentation/RelNotes/2.28.1.txt b/Documentation/RelNotes/2.28.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.28.1.txt
rename to Documentation/RelNotes/2.28.1.adoc
diff --git a/Documentation/RelNotes/2.29.0.txt b/Documentation/RelNotes/2.29.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.29.0.txt
rename to Documentation/RelNotes/2.29.0.adoc
diff --git a/Documentation/RelNotes/2.29.1.txt b/Documentation/RelNotes/2.29.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.29.1.txt
rename to Documentation/RelNotes/2.29.1.adoc
diff --git a/Documentation/RelNotes/2.29.2.txt b/Documentation/RelNotes/2.29.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.29.2.txt
rename to Documentation/RelNotes/2.29.2.adoc
diff --git a/Documentation/RelNotes/2.29.3.txt b/Documentation/RelNotes/2.29.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.29.3.txt
rename to Documentation/RelNotes/2.29.3.adoc
diff --git a/Documentation/RelNotes/2.3.0.txt b/Documentation/RelNotes/2.3.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.0.txt
rename to Documentation/RelNotes/2.3.0.adoc
diff --git a/Documentation/RelNotes/2.3.1.txt b/Documentation/RelNotes/2.3.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.1.txt
rename to Documentation/RelNotes/2.3.1.adoc
diff --git a/Documentation/RelNotes/2.3.10.txt b/Documentation/RelNotes/2.3.10.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.10.txt
rename to Documentation/RelNotes/2.3.10.adoc
diff --git a/Documentation/RelNotes/2.3.2.txt b/Documentation/RelNotes/2.3.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.2.txt
rename to Documentation/RelNotes/2.3.2.adoc
diff --git a/Documentation/RelNotes/2.3.3.txt b/Documentation/RelNotes/2.3.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.3.txt
rename to Documentation/RelNotes/2.3.3.adoc
diff --git a/Documentation/RelNotes/2.3.4.txt b/Documentation/RelNotes/2.3.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.4.txt
rename to Documentation/RelNotes/2.3.4.adoc
diff --git a/Documentation/RelNotes/2.3.5.txt b/Documentation/RelNotes/2.3.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.5.txt
rename to Documentation/RelNotes/2.3.5.adoc
diff --git a/Documentation/RelNotes/2.3.6.txt b/Documentation/RelNotes/2.3.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.6.txt
rename to Documentation/RelNotes/2.3.6.adoc
diff --git a/Documentation/RelNotes/2.3.7.txt b/Documentation/RelNotes/2.3.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.7.txt
rename to Documentation/RelNotes/2.3.7.adoc
diff --git a/Documentation/RelNotes/2.3.8.txt b/Documentation/RelNotes/2.3.8.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.8.txt
rename to Documentation/RelNotes/2.3.8.adoc
diff --git a/Documentation/RelNotes/2.3.9.txt b/Documentation/RelNotes/2.3.9.adoc
similarity index 100%
rename from Documentation/RelNotes/2.3.9.txt
rename to Documentation/RelNotes/2.3.9.adoc
diff --git a/Documentation/RelNotes/2.30.0.txt b/Documentation/RelNotes/2.30.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.30.0.txt
rename to Documentation/RelNotes/2.30.0.adoc
diff --git a/Documentation/RelNotes/2.30.1.txt b/Documentation/RelNotes/2.30.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.30.1.txt
rename to Documentation/RelNotes/2.30.1.adoc
diff --git a/Documentation/RelNotes/2.30.2.txt b/Documentation/RelNotes/2.30.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.30.2.txt
rename to Documentation/RelNotes/2.30.2.adoc
diff --git a/Documentation/RelNotes/2.30.3.txt b/Documentation/RelNotes/2.30.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.30.3.txt
rename to Documentation/RelNotes/2.30.3.adoc
diff --git a/Documentation/RelNotes/2.30.4.txt b/Documentation/RelNotes/2.30.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.30.4.txt
rename to Documentation/RelNotes/2.30.4.adoc
diff --git a/Documentation/RelNotes/2.30.5.txt b/Documentation/RelNotes/2.30.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.30.5.txt
rename to Documentation/RelNotes/2.30.5.adoc
diff --git a/Documentation/RelNotes/2.30.6.txt b/Documentation/RelNotes/2.30.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.30.6.txt
rename to Documentation/RelNotes/2.30.6.adoc
diff --git a/Documentation/RelNotes/2.30.7.txt b/Documentation/RelNotes/2.30.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.30.7.txt
rename to Documentation/RelNotes/2.30.7.adoc
diff --git a/Documentation/RelNotes/2.30.8.txt b/Documentation/RelNotes/2.30.8.adoc
similarity index 100%
rename from Documentation/RelNotes/2.30.8.txt
rename to Documentation/RelNotes/2.30.8.adoc
diff --git a/Documentation/RelNotes/2.30.9.txt b/Documentation/RelNotes/2.30.9.adoc
similarity index 100%
rename from Documentation/RelNotes/2.30.9.txt
rename to Documentation/RelNotes/2.30.9.adoc
diff --git a/Documentation/RelNotes/2.31.0.txt b/Documentation/RelNotes/2.31.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.31.0.txt
rename to Documentation/RelNotes/2.31.0.adoc
diff --git a/Documentation/RelNotes/2.31.1.txt b/Documentation/RelNotes/2.31.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.31.1.txt
rename to Documentation/RelNotes/2.31.1.adoc
diff --git a/Documentation/RelNotes/2.31.2.txt b/Documentation/RelNotes/2.31.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.31.2.txt
rename to Documentation/RelNotes/2.31.2.adoc
diff --git a/Documentation/RelNotes/2.31.3.txt b/Documentation/RelNotes/2.31.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.31.3.txt
rename to Documentation/RelNotes/2.31.3.adoc
diff --git a/Documentation/RelNotes/2.31.4.txt b/Documentation/RelNotes/2.31.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.31.4.txt
rename to Documentation/RelNotes/2.31.4.adoc
diff --git a/Documentation/RelNotes/2.31.5.txt b/Documentation/RelNotes/2.31.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.31.5.txt
rename to Documentation/RelNotes/2.31.5.adoc
diff --git a/Documentation/RelNotes/2.31.6.txt b/Documentation/RelNotes/2.31.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.31.6.txt
rename to Documentation/RelNotes/2.31.6.adoc
diff --git a/Documentation/RelNotes/2.31.7.txt b/Documentation/RelNotes/2.31.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.31.7.txt
rename to Documentation/RelNotes/2.31.7.adoc
diff --git a/Documentation/RelNotes/2.31.8.txt b/Documentation/RelNotes/2.31.8.adoc
similarity index 100%
rename from Documentation/RelNotes/2.31.8.txt
rename to Documentation/RelNotes/2.31.8.adoc
diff --git a/Documentation/RelNotes/2.32.0.txt b/Documentation/RelNotes/2.32.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.32.0.txt
rename to Documentation/RelNotes/2.32.0.adoc
diff --git a/Documentation/RelNotes/2.32.1.txt b/Documentation/RelNotes/2.32.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.32.1.txt
rename to Documentation/RelNotes/2.32.1.adoc
diff --git a/Documentation/RelNotes/2.32.2.txt b/Documentation/RelNotes/2.32.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.32.2.txt
rename to Documentation/RelNotes/2.32.2.adoc
diff --git a/Documentation/RelNotes/2.32.3.txt b/Documentation/RelNotes/2.32.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.32.3.txt
rename to Documentation/RelNotes/2.32.3.adoc
diff --git a/Documentation/RelNotes/2.32.4.txt b/Documentation/RelNotes/2.32.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.32.4.txt
rename to Documentation/RelNotes/2.32.4.adoc
diff --git a/Documentation/RelNotes/2.32.5.txt b/Documentation/RelNotes/2.32.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.32.5.txt
rename to Documentation/RelNotes/2.32.5.adoc
diff --git a/Documentation/RelNotes/2.32.6.txt b/Documentation/RelNotes/2.32.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.32.6.txt
rename to Documentation/RelNotes/2.32.6.adoc
diff --git a/Documentation/RelNotes/2.32.7.txt b/Documentation/RelNotes/2.32.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.32.7.txt
rename to Documentation/RelNotes/2.32.7.adoc
diff --git a/Documentation/RelNotes/2.33.0.txt b/Documentation/RelNotes/2.33.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.33.0.txt
rename to Documentation/RelNotes/2.33.0.adoc
diff --git a/Documentation/RelNotes/2.33.1.txt b/Documentation/RelNotes/2.33.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.33.1.txt
rename to Documentation/RelNotes/2.33.1.adoc
diff --git a/Documentation/RelNotes/2.33.2.txt b/Documentation/RelNotes/2.33.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.33.2.txt
rename to Documentation/RelNotes/2.33.2.adoc
diff --git a/Documentation/RelNotes/2.33.3.txt b/Documentation/RelNotes/2.33.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.33.3.txt
rename to Documentation/RelNotes/2.33.3.adoc
diff --git a/Documentation/RelNotes/2.33.4.txt b/Documentation/RelNotes/2.33.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.33.4.txt
rename to Documentation/RelNotes/2.33.4.adoc
diff --git a/Documentation/RelNotes/2.33.5.txt b/Documentation/RelNotes/2.33.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.33.5.txt
rename to Documentation/RelNotes/2.33.5.adoc
diff --git a/Documentation/RelNotes/2.33.6.txt b/Documentation/RelNotes/2.33.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.33.6.txt
rename to Documentation/RelNotes/2.33.6.adoc
diff --git a/Documentation/RelNotes/2.33.7.txt b/Documentation/RelNotes/2.33.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.33.7.txt
rename to Documentation/RelNotes/2.33.7.adoc
diff --git a/Documentation/RelNotes/2.33.8.txt b/Documentation/RelNotes/2.33.8.adoc
similarity index 100%
rename from Documentation/RelNotes/2.33.8.txt
rename to Documentation/RelNotes/2.33.8.adoc
diff --git a/Documentation/RelNotes/2.34.0.txt b/Documentation/RelNotes/2.34.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.34.0.txt
rename to Documentation/RelNotes/2.34.0.adoc
diff --git a/Documentation/RelNotes/2.34.1.txt b/Documentation/RelNotes/2.34.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.34.1.txt
rename to Documentation/RelNotes/2.34.1.adoc
diff --git a/Documentation/RelNotes/2.34.2.txt b/Documentation/RelNotes/2.34.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.34.2.txt
rename to Documentation/RelNotes/2.34.2.adoc
diff --git a/Documentation/RelNotes/2.34.3.txt b/Documentation/RelNotes/2.34.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.34.3.txt
rename to Documentation/RelNotes/2.34.3.adoc
diff --git a/Documentation/RelNotes/2.34.4.txt b/Documentation/RelNotes/2.34.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.34.4.txt
rename to Documentation/RelNotes/2.34.4.adoc
diff --git a/Documentation/RelNotes/2.34.5.txt b/Documentation/RelNotes/2.34.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.34.5.txt
rename to Documentation/RelNotes/2.34.5.adoc
diff --git a/Documentation/RelNotes/2.34.6.txt b/Documentation/RelNotes/2.34.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.34.6.txt
rename to Documentation/RelNotes/2.34.6.adoc
diff --git a/Documentation/RelNotes/2.34.7.txt b/Documentation/RelNotes/2.34.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.34.7.txt
rename to Documentation/RelNotes/2.34.7.adoc
diff --git a/Documentation/RelNotes/2.34.8.txt b/Documentation/RelNotes/2.34.8.adoc
similarity index 100%
rename from Documentation/RelNotes/2.34.8.txt
rename to Documentation/RelNotes/2.34.8.adoc
diff --git a/Documentation/RelNotes/2.35.0.txt b/Documentation/RelNotes/2.35.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.35.0.txt
rename to Documentation/RelNotes/2.35.0.adoc
diff --git a/Documentation/RelNotes/2.35.1.txt b/Documentation/RelNotes/2.35.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.35.1.txt
rename to Documentation/RelNotes/2.35.1.adoc
diff --git a/Documentation/RelNotes/2.35.2.txt b/Documentation/RelNotes/2.35.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.35.2.txt
rename to Documentation/RelNotes/2.35.2.adoc
diff --git a/Documentation/RelNotes/2.35.3.txt b/Documentation/RelNotes/2.35.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.35.3.txt
rename to Documentation/RelNotes/2.35.3.adoc
diff --git a/Documentation/RelNotes/2.35.4.txt b/Documentation/RelNotes/2.35.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.35.4.txt
rename to Documentation/RelNotes/2.35.4.adoc
diff --git a/Documentation/RelNotes/2.35.5.txt b/Documentation/RelNotes/2.35.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.35.5.txt
rename to Documentation/RelNotes/2.35.5.adoc
diff --git a/Documentation/RelNotes/2.35.6.txt b/Documentation/RelNotes/2.35.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.35.6.txt
rename to Documentation/RelNotes/2.35.6.adoc
diff --git a/Documentation/RelNotes/2.35.7.txt b/Documentation/RelNotes/2.35.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.35.7.txt
rename to Documentation/RelNotes/2.35.7.adoc
diff --git a/Documentation/RelNotes/2.35.8.txt b/Documentation/RelNotes/2.35.8.adoc
similarity index 100%
rename from Documentation/RelNotes/2.35.8.txt
rename to Documentation/RelNotes/2.35.8.adoc
diff --git a/Documentation/RelNotes/2.36.0.txt b/Documentation/RelNotes/2.36.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.36.0.txt
rename to Documentation/RelNotes/2.36.0.adoc
diff --git a/Documentation/RelNotes/2.36.1.txt b/Documentation/RelNotes/2.36.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.36.1.txt
rename to Documentation/RelNotes/2.36.1.adoc
diff --git a/Documentation/RelNotes/2.36.2.txt b/Documentation/RelNotes/2.36.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.36.2.txt
rename to Documentation/RelNotes/2.36.2.adoc
diff --git a/Documentation/RelNotes/2.36.3.txt b/Documentation/RelNotes/2.36.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.36.3.txt
rename to Documentation/RelNotes/2.36.3.adoc
diff --git a/Documentation/RelNotes/2.36.4.txt b/Documentation/RelNotes/2.36.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.36.4.txt
rename to Documentation/RelNotes/2.36.4.adoc
diff --git a/Documentation/RelNotes/2.36.5.txt b/Documentation/RelNotes/2.36.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.36.5.txt
rename to Documentation/RelNotes/2.36.5.adoc
diff --git a/Documentation/RelNotes/2.36.6.txt b/Documentation/RelNotes/2.36.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.36.6.txt
rename to Documentation/RelNotes/2.36.6.adoc
diff --git a/Documentation/RelNotes/2.37.0.txt b/Documentation/RelNotes/2.37.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.37.0.txt
rename to Documentation/RelNotes/2.37.0.adoc
diff --git a/Documentation/RelNotes/2.37.1.txt b/Documentation/RelNotes/2.37.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.37.1.txt
rename to Documentation/RelNotes/2.37.1.adoc
diff --git a/Documentation/RelNotes/2.37.2.txt b/Documentation/RelNotes/2.37.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.37.2.txt
rename to Documentation/RelNotes/2.37.2.adoc
diff --git a/Documentation/RelNotes/2.37.3.txt b/Documentation/RelNotes/2.37.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.37.3.txt
rename to Documentation/RelNotes/2.37.3.adoc
diff --git a/Documentation/RelNotes/2.37.4.txt b/Documentation/RelNotes/2.37.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.37.4.txt
rename to Documentation/RelNotes/2.37.4.adoc
diff --git a/Documentation/RelNotes/2.37.5.txt b/Documentation/RelNotes/2.37.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.37.5.txt
rename to Documentation/RelNotes/2.37.5.adoc
diff --git a/Documentation/RelNotes/2.37.6.txt b/Documentation/RelNotes/2.37.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.37.6.txt
rename to Documentation/RelNotes/2.37.6.adoc
diff --git a/Documentation/RelNotes/2.37.7.txt b/Documentation/RelNotes/2.37.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.37.7.txt
rename to Documentation/RelNotes/2.37.7.adoc
diff --git a/Documentation/RelNotes/2.38.0.txt b/Documentation/RelNotes/2.38.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.38.0.txt
rename to Documentation/RelNotes/2.38.0.adoc
diff --git a/Documentation/RelNotes/2.38.1.txt b/Documentation/RelNotes/2.38.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.38.1.txt
rename to Documentation/RelNotes/2.38.1.adoc
diff --git a/Documentation/RelNotes/2.38.2.txt b/Documentation/RelNotes/2.38.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.38.2.txt
rename to Documentation/RelNotes/2.38.2.adoc
diff --git a/Documentation/RelNotes/2.38.3.txt b/Documentation/RelNotes/2.38.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.38.3.txt
rename to Documentation/RelNotes/2.38.3.adoc
diff --git a/Documentation/RelNotes/2.38.4.txt b/Documentation/RelNotes/2.38.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.38.4.txt
rename to Documentation/RelNotes/2.38.4.adoc
diff --git a/Documentation/RelNotes/2.38.5.txt b/Documentation/RelNotes/2.38.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.38.5.txt
rename to Documentation/RelNotes/2.38.5.adoc
diff --git a/Documentation/RelNotes/2.39.0.txt b/Documentation/RelNotes/2.39.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.39.0.txt
rename to Documentation/RelNotes/2.39.0.adoc
diff --git a/Documentation/RelNotes/2.39.1.txt b/Documentation/RelNotes/2.39.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.39.1.txt
rename to Documentation/RelNotes/2.39.1.adoc
diff --git a/Documentation/RelNotes/2.39.2.txt b/Documentation/RelNotes/2.39.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.39.2.txt
rename to Documentation/RelNotes/2.39.2.adoc
diff --git a/Documentation/RelNotes/2.39.3.txt b/Documentation/RelNotes/2.39.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.39.3.txt
rename to Documentation/RelNotes/2.39.3.adoc
diff --git a/Documentation/RelNotes/2.39.4.txt b/Documentation/RelNotes/2.39.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.39.4.txt
rename to Documentation/RelNotes/2.39.4.adoc
diff --git a/Documentation/RelNotes/2.39.5.txt b/Documentation/RelNotes/2.39.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.39.5.txt
rename to Documentation/RelNotes/2.39.5.adoc
diff --git a/Documentation/RelNotes/2.4.0.txt b/Documentation/RelNotes/2.4.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.0.txt
rename to Documentation/RelNotes/2.4.0.adoc
diff --git a/Documentation/RelNotes/2.4.1.txt b/Documentation/RelNotes/2.4.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.1.txt
rename to Documentation/RelNotes/2.4.1.adoc
diff --git a/Documentation/RelNotes/2.4.10.txt b/Documentation/RelNotes/2.4.10.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.10.txt
rename to Documentation/RelNotes/2.4.10.adoc
diff --git a/Documentation/RelNotes/2.4.11.txt b/Documentation/RelNotes/2.4.11.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.11.txt
rename to Documentation/RelNotes/2.4.11.adoc
diff --git a/Documentation/RelNotes/2.4.12.txt b/Documentation/RelNotes/2.4.12.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.12.txt
rename to Documentation/RelNotes/2.4.12.adoc
diff --git a/Documentation/RelNotes/2.4.2.txt b/Documentation/RelNotes/2.4.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.2.txt
rename to Documentation/RelNotes/2.4.2.adoc
diff --git a/Documentation/RelNotes/2.4.3.txt b/Documentation/RelNotes/2.4.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.3.txt
rename to Documentation/RelNotes/2.4.3.adoc
diff --git a/Documentation/RelNotes/2.4.4.txt b/Documentation/RelNotes/2.4.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.4.txt
rename to Documentation/RelNotes/2.4.4.adoc
diff --git a/Documentation/RelNotes/2.4.5.txt b/Documentation/RelNotes/2.4.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.5.txt
rename to Documentation/RelNotes/2.4.5.adoc
diff --git a/Documentation/RelNotes/2.4.6.txt b/Documentation/RelNotes/2.4.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.6.txt
rename to Documentation/RelNotes/2.4.6.adoc
diff --git a/Documentation/RelNotes/2.4.7.txt b/Documentation/RelNotes/2.4.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.7.txt
rename to Documentation/RelNotes/2.4.7.adoc
diff --git a/Documentation/RelNotes/2.4.8.txt b/Documentation/RelNotes/2.4.8.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.8.txt
rename to Documentation/RelNotes/2.4.8.adoc
diff --git a/Documentation/RelNotes/2.4.9.txt b/Documentation/RelNotes/2.4.9.adoc
similarity index 100%
rename from Documentation/RelNotes/2.4.9.txt
rename to Documentation/RelNotes/2.4.9.adoc
diff --git a/Documentation/RelNotes/2.40.0.txt b/Documentation/RelNotes/2.40.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.40.0.txt
rename to Documentation/RelNotes/2.40.0.adoc
diff --git a/Documentation/RelNotes/2.40.1.txt b/Documentation/RelNotes/2.40.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.40.1.txt
rename to Documentation/RelNotes/2.40.1.adoc
diff --git a/Documentation/RelNotes/2.40.2.txt b/Documentation/RelNotes/2.40.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.40.2.txt
rename to Documentation/RelNotes/2.40.2.adoc
diff --git a/Documentation/RelNotes/2.40.3.txt b/Documentation/RelNotes/2.40.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.40.3.txt
rename to Documentation/RelNotes/2.40.3.adoc
diff --git a/Documentation/RelNotes/2.40.4.txt b/Documentation/RelNotes/2.40.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.40.4.txt
rename to Documentation/RelNotes/2.40.4.adoc
diff --git a/Documentation/RelNotes/2.41.0.txt b/Documentation/RelNotes/2.41.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.41.0.txt
rename to Documentation/RelNotes/2.41.0.adoc
diff --git a/Documentation/RelNotes/2.41.1.txt b/Documentation/RelNotes/2.41.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.41.1.txt
rename to Documentation/RelNotes/2.41.1.adoc
diff --git a/Documentation/RelNotes/2.41.2.txt b/Documentation/RelNotes/2.41.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.41.2.txt
rename to Documentation/RelNotes/2.41.2.adoc
diff --git a/Documentation/RelNotes/2.41.3.txt b/Documentation/RelNotes/2.41.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.41.3.txt
rename to Documentation/RelNotes/2.41.3.adoc
diff --git a/Documentation/RelNotes/2.42.0.txt b/Documentation/RelNotes/2.42.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.42.0.txt
rename to Documentation/RelNotes/2.42.0.adoc
diff --git a/Documentation/RelNotes/2.42.1.txt b/Documentation/RelNotes/2.42.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.42.1.txt
rename to Documentation/RelNotes/2.42.1.adoc
diff --git a/Documentation/RelNotes/2.42.2.txt b/Documentation/RelNotes/2.42.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.42.2.txt
rename to Documentation/RelNotes/2.42.2.adoc
diff --git a/Documentation/RelNotes/2.42.3.txt b/Documentation/RelNotes/2.42.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.42.3.txt
rename to Documentation/RelNotes/2.42.3.adoc
diff --git a/Documentation/RelNotes/2.42.4.txt b/Documentation/RelNotes/2.42.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.42.4.txt
rename to Documentation/RelNotes/2.42.4.adoc
diff --git a/Documentation/RelNotes/2.43.0.txt b/Documentation/RelNotes/2.43.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.43.0.txt
rename to Documentation/RelNotes/2.43.0.adoc
diff --git a/Documentation/RelNotes/2.43.1.txt b/Documentation/RelNotes/2.43.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.43.1.txt
rename to Documentation/RelNotes/2.43.1.adoc
diff --git a/Documentation/RelNotes/2.43.2.txt b/Documentation/RelNotes/2.43.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.43.2.txt
rename to Documentation/RelNotes/2.43.2.adoc
diff --git a/Documentation/RelNotes/2.43.3.txt b/Documentation/RelNotes/2.43.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.43.3.txt
rename to Documentation/RelNotes/2.43.3.adoc
diff --git a/Documentation/RelNotes/2.43.4.txt b/Documentation/RelNotes/2.43.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.43.4.txt
rename to Documentation/RelNotes/2.43.4.adoc
diff --git a/Documentation/RelNotes/2.43.5.txt b/Documentation/RelNotes/2.43.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.43.5.txt
rename to Documentation/RelNotes/2.43.5.adoc
diff --git a/Documentation/RelNotes/2.43.6.txt b/Documentation/RelNotes/2.43.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.43.6.txt
rename to Documentation/RelNotes/2.43.6.adoc
diff --git a/Documentation/RelNotes/2.44.0.txt b/Documentation/RelNotes/2.44.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.44.0.txt
rename to Documentation/RelNotes/2.44.0.adoc
diff --git a/Documentation/RelNotes/2.44.1.txt b/Documentation/RelNotes/2.44.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.44.1.txt
rename to Documentation/RelNotes/2.44.1.adoc
diff --git a/Documentation/RelNotes/2.44.2.txt b/Documentation/RelNotes/2.44.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.44.2.txt
rename to Documentation/RelNotes/2.44.2.adoc
diff --git a/Documentation/RelNotes/2.44.3.txt b/Documentation/RelNotes/2.44.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.44.3.txt
rename to Documentation/RelNotes/2.44.3.adoc
diff --git a/Documentation/RelNotes/2.45.0.txt b/Documentation/RelNotes/2.45.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.45.0.txt
rename to Documentation/RelNotes/2.45.0.adoc
diff --git a/Documentation/RelNotes/2.45.1.txt b/Documentation/RelNotes/2.45.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.45.1.txt
rename to Documentation/RelNotes/2.45.1.adoc
diff --git a/Documentation/RelNotes/2.45.2.txt b/Documentation/RelNotes/2.45.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.45.2.txt
rename to Documentation/RelNotes/2.45.2.adoc
diff --git a/Documentation/RelNotes/2.45.3.txt b/Documentation/RelNotes/2.45.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.45.3.txt
rename to Documentation/RelNotes/2.45.3.adoc
diff --git a/Documentation/RelNotes/2.46.0.txt b/Documentation/RelNotes/2.46.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.46.0.txt
rename to Documentation/RelNotes/2.46.0.adoc
diff --git a/Documentation/RelNotes/2.46.1.txt b/Documentation/RelNotes/2.46.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.46.1.txt
rename to Documentation/RelNotes/2.46.1.adoc
diff --git a/Documentation/RelNotes/2.46.2.txt b/Documentation/RelNotes/2.46.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.46.2.txt
rename to Documentation/RelNotes/2.46.2.adoc
diff --git a/Documentation/RelNotes/2.46.3.txt b/Documentation/RelNotes/2.46.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.46.3.txt
rename to Documentation/RelNotes/2.46.3.adoc
diff --git a/Documentation/RelNotes/2.47.0.txt b/Documentation/RelNotes/2.47.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.47.0.txt
rename to Documentation/RelNotes/2.47.0.adoc
diff --git a/Documentation/RelNotes/2.47.1.txt b/Documentation/RelNotes/2.47.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.47.1.txt
rename to Documentation/RelNotes/2.47.1.adoc
diff --git a/Documentation/RelNotes/2.47.2.txt b/Documentation/RelNotes/2.47.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.47.2.txt
rename to Documentation/RelNotes/2.47.2.adoc
diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.48.0.txt
rename to Documentation/RelNotes/2.48.0.adoc
diff --git a/Documentation/RelNotes/2.48.1.txt b/Documentation/RelNotes/2.48.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.48.1.txt
rename to Documentation/RelNotes/2.48.1.adoc
diff --git a/Documentation/RelNotes/2.49.0.adoc b/Documentation/RelNotes/2.49.0.adoc
new file mode 100644
index 0000000..494c830
--- /dev/null
+++ b/Documentation/RelNotes/2.49.0.adoc
@@ -0,0 +1,288 @@
+Git v2.49 Release Notes
+=======================
+
+UI, Workflows & Features
+------------------------
+
+ * Completion script updates for zsh
+
+ * "git pack-objects" and its wrapper "git repack" learned an option
+   to use an alternative path-hash function to improve delta-base
+   selection to produce a packfile with deeper history than window
+   size.
+
+ * "git gc" learned the "--expire-to" option and passes it down to
+   underlying "git repack".
+
+ * "[help] autocorrect = 1" used to be a way to say "please wait for
+   0.1 second after suggesting a typofix of the command name before
+   running that command"; now it means "yes, if there is a plausible
+   typofix for the command name, please run it immediately".
+
+ * "git clone" learned to make a shallow clone for a single commit
+   that is not necessarily be at the tip of any branch.
+
+ * Lazy-loading missing files in a blobless clone on demand is costly
+   as it tends to be one-blob-at-a-time.  "git backfill" is introduced
+   to help bulk-download necessary files beforehand.
+
+ * "git push --atomic --porcelain" used to ignore failures from the
+   other side, losing the error status from the child process, which
+   has been corrected.
+
+ * "git rev-list --missing=" learned to accept "print-info" that gives
+   known details expected of the missing objects, like path and type.
+
+ * Comes with an updated "gitk".
+
+ * The documentation of "git commit" and "git rebase" now refer to
+   commit titles as such, not "subject".
+
+ * The value of "uname -s" is by default sent over the wire as a part
+   of the "version" capability.
+
+ * "git refs migrate" can optionally be told not to migrate the reflog.
+
+ * The netrc support (via the cURL library) for the HTTP transport has
+   been re-enabled.
+
+ * Removal of ".git/branches" and ".git/remotes" support in the
+   BreakingChanges document has been further clarified.
+
+ * What happens to submodules during merge has been documented in a
+   bit more detail.
+
+
+Performance, Internal Implementation, Development Support etc.
+--------------------------------------------------------------
+
+ * More -Wsign-compare fixes.
+
+ * meson-based build now supports the unsafe-sha1 build knob.
+
+ * The meson-based build procedure covers contrib/ and other places as
+   well.
+
+ * The code to check LSan results has been simplified and made more
+   robust.
+   (merge 164a2516eb jk/lsan-race-ignore-false-positive later to maint).
+
+ * More code paths have a repository passed through the callchain,
+   instead of assuming the primary the_repository object.
+
+ * Move a few more unit tests to the clar test framework.
+
+ * Introduce a new API to visit objects in batches based on a common
+   path, or by type.
+
+ * Following the procedure we established to introduce breaking
+   changes for Git 3.0, allow an early opt-in for removing support of
+   $GIT_DIR/branches/ and $GIT_DIR/remotes/ directories to configure
+   remotes.
+
+ * The code paths to interact with zlib has been cleaned up in
+   preparation for building with zlib-ng.
+
+ * Foreign language interface for Rust into our code base has been added.
+
+ * All the documentation .txt files have been renamed to .adoc to help
+   content aware editors.
+
+ * "git difftool" code clean-up.
+
+ * Rename processing in the recursive merge backend has seen a micro
+   optimization.
+
+ * The path.[ch] API takes an explicit repository parameter passed
+   throughout the callchain, instead of relying on the_repository
+   singleton instance.
+
+ * Large-object promisor protocol extension has been introduced.
+
+ * The editorconfig file is updated to tell us that bash scripts are
+   similar to general Bourne shell scripts.
+
+ * Meson-based build procedure forgot to build some docs, which has
+   been corrected.
+
+
+Fixes since v2.48
+-----------------
+
+ * "git submodule" learned various ways to spell the same option,
+   e.g. "--branch=B" can be spelled "--branch B" or "-bB".
+   (merge b86f0f9071 re/submodule-parse-opt later to maint).
+
+ * Tweak the help text used for the option value placeholders by
+   parse-options API so that translations can customize the "<>"
+   placeholder signal (e.g. "--option=<value>").
+   (merge 5b34dd08d0 as/long-option-help-i18n later to maint).
+
+ * CI jobs gave sporadic failures, which turns out that that the
+   object finalization code was giving an error when it did not have
+   to.
+   (merge d7fcbe2c56 ps/object-collision-check later to maint).
+
+ * The code to compute "unique" name used git_rand() which can fail or
+   get stuck; the callsite does not require cryptographic security.
+   Introduce the "insecure" mode and use it appropriately.
+   (merge 0b4f8afef6 ps/reftable-get-random-fix later to maint).
+
+ * A misconfigured "fsck.skiplist" configuration variable was not
+   diagnosed as an error, which has been corrected.
+   (merge ca7158076f jt/fsck-skiplist-parse-fix later to maint).
+
+ * Extended SHA-1 expression parser did not work well when a branch
+   with an unusual name (e.g. "foo{bar") is involved.
+   (merge 191f0c8db2 en/object-name-with-funny-refname-fix later to maint).
+
+ * The meson build procedure looked for the 'version-def.h' file in a
+   wrong directory, which has been corrected.
+   (merge 4771501c0a tc/meson-use-our-version-def-h later to maint).
+
+ * The meson build procedure for Documentation/technical/ hierarchy was
+   missing necessary dependencies, which has been corrected.
+   (merge 1dca492edd sj/meson-doc-technical-dependency-fix later to maint).
+
+ * The "instaweb" bound only to local IP address without "--local" and
+   to all addresses with "--local", which was the other way around, when
+   using Python's http.server class, which has been corrected.
+   (merge 76baf97fa1 ak/instaweb-python-port-binding-fix later to maint).
+
+ * Document that it is insecure to use Personal Access Tokens, which
+   some hosting providers take as username/password, embedded in URLs.
+   (merge a90ff409f0 mh/doc-credential-helpers-with-pat later to maint).
+
+ * The help text from "git $cmd -h" appear on the standard output for
+   some $cmd and the standard error for others.  The built-in commands
+   have been fixed to show them on the standard output consistently.
+   (merge f66d1423f5 jc/show-usage-help later to maint).
+
+ * The meson-driven build is now aware of "git-subtree" housed in
+   contrib/subtree hierarchy.
+   (merge 8454b42f94 ps/build-meson-subtree later to maint).
+
+ * It was possible for "git unpack-objects" and "git index-pack" to
+   make an unaligned access, which has been corrected.
+   (merge 98046591b9 jk/pack-header-parse-alignment-fix later to maint).
+
+ * The "cache" credential back-end did not handle authtype correctly,
+   which has been corrected.
+   (merge 0b43274850 mh/credential-cache-authtype-request-fix later to maint).
+
+ * "git branch --sort=..." and "git for-each-ref --format=... --sort=..."
+   did not work as expected with some atoms, which has been corrected.
+   (merge c5490ce9d1 rs/ref-fitler-used-atoms-value-fix later to maint).
+
+ * reflog entries for symbolic ref updates were broken, which has been
+   corrected.
+   (merge 3519492430 kn/reflog-symref-fix later to maint).
+
+ * The trace2 code was not prepared to show a configuration variable
+   that is set to true using the valueless true syntax, which has been
+   corrected.
+   (merge 2fd367cf63 am/trace2-with-valueless-true later to maint).
+
+ * The "git refs migrate" command did not migrate the reflog for
+   refs/stash, which is the contents of the stashes, which has been
+   corrected.
+   (merge a0bea0978f ps/reflog-migration-with-logall-fix later to maint).
+
+ * Doc and short-help text for "show-index" has been clarified to
+   stress that the command reads its data from the standard input.
+   (merge 49edce4ff9 jc/show-index-h-update later to maint).
+
+ * The API around choosing to use unsafe variant of SHA-1
+   implementation has been updated in an attempt to make it harder to
+   abuse.
+   (merge 04292c3796 tb/unsafe-hash-cleanup later to maint).
+
+ * Fix bugs in an earlier attempt to fix "git refs migration".
+   (merge f11f0a5a2d kn/reflog-migration-fix-fix later to maint).
+
+ * The code path used when "git fetch" fetches from a bundle file
+   closed the same file descriptor twice, which sometimes broke things
+   unexpectedly when the file descriptor was reused, which has been
+   corrected.
+   (merge 9a84794ad8 js/bundle-unbundle-fd-reuse-fix later to maint).
+
+ * "git init" to reinitialize a repository that already exists cannot
+   change the hash function and ref backends; such a request is
+   silently ignored now.
+   (merge 7e88640cd1 ps/setup-reinit-fixes later to maint).
+
+ * "git apply" internally uses unsigned long for line numbers and uses
+   strtoul() to parse numbers on the hunk headers.  It however forgot
+   to check parse errors.
+   (merge a206058fda pw/apply-ulong-overflow-check later to maint).
+
+ * Two CI tasks, whitespace check and style check, work on the
+   difference from the base version and the version being checked, but
+   the base was computed incorrectly in GitLab CI in some cases, which
+   has been corrected.
+   (merge acc4fb302b jt/gitlab-ci-base-fix later to maint).
+
+ * "git repack --keep-unreachable" to send unreachable objects to the
+   main pack "git repack -ad" produces did not work when there is no
+   existing packs, which has been corrected.
+   (merge 414c82300a ps/repack-keep-unreachable-in-unpacked-repo later to maint).
+
+ * Going into a secondary worktree and asking "is the main worktree
+   bare?" did not work correctly when per-worktree configuration
+   option was in use, which has been corrected.
+
+ * Fetching into a bare repository incorrectly assumed it always used
+   a mirror layout when deciding to update remote-tracking HEAD, which
+   has been corrected.
+   (merge 93dc16483a bf/fetch-set-head-fix later to maint).
+
+ * A thunderbird helper script lost its bashism.
+   (merge 59d26bd961 bc/contrib-thunderbird-patch-inline-fix later to maint).
+
+ * The -G/-S options to the "diff" family of commands caused us to hit
+   a BUG() when they get no values; they have been corrected.
+   (merge a620046b29 bc/diff-reject-empty-arg-to-pickaxe later to maint).
+
+ * "git merge-tree --stdin" has been improved (including a workaround
+   for a deadlock).
+   (merge 6a9ae81015 pw/merge-tree-stdin-deadlock-fix later to maint).
+
+ * Correct the default target in Documentation/Makefile, and
+   future-proof all Makefiles from similar breakages by declaring the
+   default target (which happens to be "all") upfront.
+   (merge 5309c1e9fb ad/set-default-target-in-makefiles later to maint).
+
+ * "git check-mailmap" used to segfault when queried without human
+   readable name.
+   (merge bb60c52131 jk/check-mailmap-wo-name-fix later to maint).
+
+ * Support for renaming of symbolic links on Windows has been improved.
+
+ * "git rebase -i" failed to allow rewording an empty commit that has
+   been fast-forwarded.
+   (merge af8fc7be10 pw/rebase-i-ff-empty-commit later to maint).
+
+ * The use of "paste" command for aggregating the test results have
+   been corrected.
+   (merge ce98863204 dk/test-aggregate-results-paste-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge ddb5287894 jk/t7407-use-test-grep later to maint).
+   (merge 21e1b44865 aj/difftool-config-doc-fix later to maint).
+   (merge 6a63995335 mh/gitattr-doc-markup-fix later to maint).
+   (merge 43850dcf9c sk/unit-test-hash later to maint).
+   (merge 4ad47d2de3 jc/cli-doc-option-and-config later to maint).
+   (merge 2d0ff147e5 jp/t8002-printf-fix later to maint).
+   (merge 69666e6746 ja/doc-restore-markup-update later to maint).
+   (merge d11d003ba5 sk/strlen-returns-size_t later to maint).
+   (merge 77b2d29e91 ja/doc-notes-markup-updates later to maint).
+   (merge 6979bf6f8f jk/combine-diff-cleanup later to maint).
+   (merge 8705c9bd13 kn/pack-write-with-reduced-globals later to maint).
+   (merge 087740d65a ps/leakfixes-0129 later to maint).
+   (merge 6bba6f604b jp/doc-trailer-config later to maint).
+   (merge f1cc562b77 lo/t7603-path-is-file-update later to maint).
+   (merge 45761988ac en/doc-renormalize later to maint).
+   (merge 832f56f06a jc/doc-boolean-synonyms later to maint).
+   (merge 3eeed876a9 ac/doc-http-ssl-type-config later to maint).
+   (merge c268e3285d jc/breaking-changes-early-adopter-option later to maint).
+   (merge 0d03fda6a5 pb/doc-follow-remote-head later to maint).
diff --git a/Documentation/RelNotes/2.5.0.txt b/Documentation/RelNotes/2.5.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.5.0.txt
rename to Documentation/RelNotes/2.5.0.adoc
diff --git a/Documentation/RelNotes/2.5.1.txt b/Documentation/RelNotes/2.5.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.5.1.txt
rename to Documentation/RelNotes/2.5.1.adoc
diff --git a/Documentation/RelNotes/2.5.2.txt b/Documentation/RelNotes/2.5.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.5.2.txt
rename to Documentation/RelNotes/2.5.2.adoc
diff --git a/Documentation/RelNotes/2.5.3.txt b/Documentation/RelNotes/2.5.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.5.3.txt
rename to Documentation/RelNotes/2.5.3.adoc
diff --git a/Documentation/RelNotes/2.5.4.txt b/Documentation/RelNotes/2.5.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.5.4.txt
rename to Documentation/RelNotes/2.5.4.adoc
diff --git a/Documentation/RelNotes/2.5.5.txt b/Documentation/RelNotes/2.5.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.5.5.txt
rename to Documentation/RelNotes/2.5.5.adoc
diff --git a/Documentation/RelNotes/2.5.6.txt b/Documentation/RelNotes/2.5.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.5.6.txt
rename to Documentation/RelNotes/2.5.6.adoc
diff --git a/Documentation/RelNotes/2.6.0.txt b/Documentation/RelNotes/2.6.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.6.0.txt
rename to Documentation/RelNotes/2.6.0.adoc
diff --git a/Documentation/RelNotes/2.6.1.txt b/Documentation/RelNotes/2.6.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.6.1.txt
rename to Documentation/RelNotes/2.6.1.adoc
diff --git a/Documentation/RelNotes/2.6.2.txt b/Documentation/RelNotes/2.6.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.6.2.txt
rename to Documentation/RelNotes/2.6.2.adoc
diff --git a/Documentation/RelNotes/2.6.3.txt b/Documentation/RelNotes/2.6.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.6.3.txt
rename to Documentation/RelNotes/2.6.3.adoc
diff --git a/Documentation/RelNotes/2.6.4.txt b/Documentation/RelNotes/2.6.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.6.4.txt
rename to Documentation/RelNotes/2.6.4.adoc
diff --git a/Documentation/RelNotes/2.6.5.txt b/Documentation/RelNotes/2.6.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.6.5.txt
rename to Documentation/RelNotes/2.6.5.adoc
diff --git a/Documentation/RelNotes/2.6.6.txt b/Documentation/RelNotes/2.6.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.6.6.txt
rename to Documentation/RelNotes/2.6.6.adoc
diff --git a/Documentation/RelNotes/2.6.7.txt b/Documentation/RelNotes/2.6.7.adoc
similarity index 100%
rename from Documentation/RelNotes/2.6.7.txt
rename to Documentation/RelNotes/2.6.7.adoc
diff --git a/Documentation/RelNotes/2.7.0.txt b/Documentation/RelNotes/2.7.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.7.0.txt
rename to Documentation/RelNotes/2.7.0.adoc
diff --git a/Documentation/RelNotes/2.7.1.txt b/Documentation/RelNotes/2.7.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.7.1.txt
rename to Documentation/RelNotes/2.7.1.adoc
diff --git a/Documentation/RelNotes/2.7.2.txt b/Documentation/RelNotes/2.7.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.7.2.txt
rename to Documentation/RelNotes/2.7.2.adoc
diff --git a/Documentation/RelNotes/2.7.3.txt b/Documentation/RelNotes/2.7.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.7.3.txt
rename to Documentation/RelNotes/2.7.3.adoc
diff --git a/Documentation/RelNotes/2.7.4.txt b/Documentation/RelNotes/2.7.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.7.4.txt
rename to Documentation/RelNotes/2.7.4.adoc
diff --git a/Documentation/RelNotes/2.7.5.txt b/Documentation/RelNotes/2.7.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.7.5.txt
rename to Documentation/RelNotes/2.7.5.adoc
diff --git a/Documentation/RelNotes/2.7.6.txt b/Documentation/RelNotes/2.7.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.7.6.txt
rename to Documentation/RelNotes/2.7.6.adoc
diff --git a/Documentation/RelNotes/2.8.0.txt b/Documentation/RelNotes/2.8.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.8.0.txt
rename to Documentation/RelNotes/2.8.0.adoc
diff --git a/Documentation/RelNotes/2.8.1.txt b/Documentation/RelNotes/2.8.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.8.1.txt
rename to Documentation/RelNotes/2.8.1.adoc
diff --git a/Documentation/RelNotes/2.8.2.txt b/Documentation/RelNotes/2.8.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.8.2.txt
rename to Documentation/RelNotes/2.8.2.adoc
diff --git a/Documentation/RelNotes/2.8.3.txt b/Documentation/RelNotes/2.8.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.8.3.txt
rename to Documentation/RelNotes/2.8.3.adoc
diff --git a/Documentation/RelNotes/2.8.4.txt b/Documentation/RelNotes/2.8.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.8.4.txt
rename to Documentation/RelNotes/2.8.4.adoc
diff --git a/Documentation/RelNotes/2.8.5.txt b/Documentation/RelNotes/2.8.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.8.5.txt
rename to Documentation/RelNotes/2.8.5.adoc
diff --git a/Documentation/RelNotes/2.8.6.txt b/Documentation/RelNotes/2.8.6.adoc
similarity index 100%
rename from Documentation/RelNotes/2.8.6.txt
rename to Documentation/RelNotes/2.8.6.adoc
diff --git a/Documentation/RelNotes/2.9.0.txt b/Documentation/RelNotes/2.9.0.adoc
similarity index 100%
rename from Documentation/RelNotes/2.9.0.txt
rename to Documentation/RelNotes/2.9.0.adoc
diff --git a/Documentation/RelNotes/2.9.1.txt b/Documentation/RelNotes/2.9.1.adoc
similarity index 100%
rename from Documentation/RelNotes/2.9.1.txt
rename to Documentation/RelNotes/2.9.1.adoc
diff --git a/Documentation/RelNotes/2.9.2.txt b/Documentation/RelNotes/2.9.2.adoc
similarity index 100%
rename from Documentation/RelNotes/2.9.2.txt
rename to Documentation/RelNotes/2.9.2.adoc
diff --git a/Documentation/RelNotes/2.9.3.txt b/Documentation/RelNotes/2.9.3.adoc
similarity index 100%
rename from Documentation/RelNotes/2.9.3.txt
rename to Documentation/RelNotes/2.9.3.adoc
diff --git a/Documentation/RelNotes/2.9.4.txt b/Documentation/RelNotes/2.9.4.adoc
similarity index 100%
rename from Documentation/RelNotes/2.9.4.txt
rename to Documentation/RelNotes/2.9.4.adoc
diff --git a/Documentation/RelNotes/2.9.5.txt b/Documentation/RelNotes/2.9.5.adoc
similarity index 100%
rename from Documentation/RelNotes/2.9.5.txt
rename to Documentation/RelNotes/2.9.5.adoc
diff --git a/Documentation/ReviewingGuidelines.txt b/Documentation/ReviewingGuidelines.adoc
similarity index 100%
rename from Documentation/ReviewingGuidelines.txt
rename to Documentation/ReviewingGuidelines.adoc
diff --git a/Documentation/ToolsForGit.txt b/Documentation/ToolsForGit.adoc
similarity index 100%
rename from Documentation/ToolsForGit.txt
rename to Documentation/ToolsForGit.adoc
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.adoc
similarity index 98%
rename from Documentation/blame-options.txt
rename to Documentation/blame-options.adoc
index 552dcc6..aa77406 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.adoc
@@ -18,7 +18,7 @@
 '<start>' and '<end>' are optional. `-L <start>` or `-L <start>,` spans from
 '<start>' to end of file. `-L ,<end>` spans from start of file to '<end>'.
 +
-include::line-range-format.txt[]
+include::line-range-format.adoc[]
 
 -l::
 	Show long rev (Default: off).
diff --git a/Documentation/build-docdep.perl b/Documentation/build-docdep.perl
index 315efaa..781da12 100755
--- a/Documentation/build-docdep.perl
+++ b/Documentation/build-docdep.perl
@@ -4,15 +4,15 @@
 my %include = ();
 my %included = ();
 
-for my $text (<*.txt>) {
-    open I, '<', $text || die "cannot read: $text";
+for my $adoc (<*.adoc>) {
+    open I, '<', $adoc || die "cannot read: $adoc";
     while (<I>) {
 	if (/^include::/) {
 	    chomp;
 	    s/^include::\s*//;
 	    s/\[\]//;
 	    s/{build_dir}/${build_dir}/;
-	    $include{$text}{$_} = 1;
+	    $include{$adoc}{$_} = 1;
 	    $included{$_} = 1;
 	}
     }
@@ -23,14 +23,14 @@
 my $changed = 1;
 while ($changed) {
     $changed = 0;
-    while (my ($text, $included) = each %include) {
+    while (my ($adoc, $included) = each %include) {
 	for my $i (keys %$included) {
-	    # $text has include::$i; if $i includes $j
-	    # $text indirectly includes $j.
+	    # $adoc has include::$i; if $i includes $j
+	    # $adoc indirectly includes $j.
 	    if (exists $include{$i}) {
 		for my $j (keys %{$include{$i}}) {
-		    if (!exists $include{$text}{$j}) {
-			$include{$text}{$j} = 1;
+		    if (!exists $include{$adoc}{$j}) {
+			$include{$adoc}{$j} = 1;
 			$included{$j} = 1;
 			$changed = 1;
 		    }
@@ -40,10 +40,10 @@
     }
 }
 
-foreach my $text (sort keys %include) {
-    my $included = $include{$text};
-    if (! exists $included{$text} &&
-	(my $base = $text) =~ s/\.txt$//) {
+foreach my $adoc (sort keys %include) {
+    my $included = $include{$adoc};
+    if (! exists $included{$adoc} &&
+	(my $base = $adoc) =~ s/\.adoc$//) {
 	print "$base.html $base.xml : ", join(" ", sort keys %$included), "\n";
     }
 }
diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl
index e260a98..0a0c1b3 100755
--- a/Documentation/cmd-list.perl
+++ b/Documentation/cmd-list.perl
@@ -5,11 +5,11 @@
 sub format_one {
 	my ($source_dir, $out, $nameattr) = @_;
 	my ($name, $attr) = @$nameattr;
-	my ($path) = "$source_dir/Documentation/$name.txt";
+	my ($path) = "$source_dir/Documentation/$name.adoc";
 	my ($state, $description);
 	my $mansection;
 	$state = 0;
-	open I, '<', "$path" or die "No such file $path.txt";
+	open I, '<', "$path" or die "No such file $path.adoc";
 	while (<I>) {
 		if (/^(?:git|scalar)[a-z0-9-]*\(([0-9])\)$/) {
 			$mansection = $1;
@@ -30,7 +30,7 @@
 	}
 	close I;
 	if (!defined $description) {
-		die "No description found in $path.txt";
+		die "No description found in $path.adoc";
 	}
 	if (my ($verify_name, $text) = ($description =~ /^($name) - (.*)/)) {
 		print $out "linkgit:$name\[$mansection\]::\n\t";
@@ -63,7 +63,7 @@
 close IN;
 
 for my $out (@categories) {
-	my ($cat) = $out =~ /^cmds-(.*)\.txt$/;
+	my ($cat) = $out =~ /^cmds-(.*)\.adoc$/;
 	my ($path) = "$build_dir/$out";
 	open O, '>', "$path+" or die "Cannot open output file $out+";
 	for (@{$cmds{$cat}}) {
diff --git a/Documentation/config.txt b/Documentation/config.adoc
similarity index 84%
rename from Documentation/config.txt
rename to Documentation/config.adoc
index 8c0b3ed..cc76925 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.adoc
@@ -372,186 +372,188 @@
 names do not conflict with those that are used by Git itself and
 other popular tools, and describe them in your documentation.
 
-include::config/add.txt[]
+include::config/add.adoc[]
 
-include::config/advice.txt[]
+include::config/advice.adoc[]
 
-include::config/alias.txt[]
+include::config/alias.adoc[]
 
-include::config/am.txt[]
+include::config/am.adoc[]
 
-include::config/apply.txt[]
+include::config/apply.adoc[]
 
-include::config/attr.txt[]
+include::config/attr.adoc[]
 
-include::config/bitmap-pseudo-merge.txt[]
+include::config/bitmap-pseudo-merge.adoc[]
 
-include::config/blame.txt[]
+include::config/blame.adoc[]
 
-include::config/branch.txt[]
+include::config/branch.adoc[]
 
-include::config/browser.txt[]
+include::config/browser.adoc[]
 
-include::config/bundle.txt[]
+include::config/bundle.adoc[]
 
-include::config/checkout.txt[]
+include::config/checkout.adoc[]
 
-include::config/clean.txt[]
+include::config/clean.adoc[]
 
-include::config/clone.txt[]
+include::config/clone.adoc[]
 
-include::config/color.txt[]
+include::config/color.adoc[]
 
-include::config/column.txt[]
+include::config/column.adoc[]
 
-include::config/commit.txt[]
+include::config/commit.adoc[]
 
-include::config/commitgraph.txt[]
+include::config/commitgraph.adoc[]
 
-include::config/completion.txt[]
+include::config/completion.adoc[]
 
-include::config/core.txt[]
+include::config/core.adoc[]
 
-include::config/credential.txt[]
+include::config/credential.adoc[]
 
-include::config/diff.txt[]
+include::config/diff.adoc[]
 
-include::config/difftool.txt[]
+include::config/difftool.adoc[]
 
-include::config/extensions.txt[]
+include::config/extensions.adoc[]
 
-include::config/fastimport.txt[]
+include::config/fastimport.adoc[]
 
-include::config/feature.txt[]
+include::config/feature.adoc[]
 
-include::config/fetch.txt[]
+include::config/fetch.adoc[]
 
-include::config/filter.txt[]
+include::config/filter.adoc[]
 
-include::config/format.txt[]
+include::config/format.adoc[]
 
-include::config/fsck.txt[]
+include::config/fsck.adoc[]
 
-include::config/fsmonitor--daemon.txt[]
+include::config/fsmonitor--daemon.adoc[]
 
-include::config/gc.txt[]
+include::config/gc.adoc[]
 
-include::config/gitcvs.txt[]
+include::config/gitcvs.adoc[]
 
-include::config/gitweb.txt[]
+include::config/gitweb.adoc[]
 
-include::config/gpg.txt[]
+include::config/gpg.adoc[]
 
-include::config/grep.txt[]
+include::config/grep.adoc[]
 
-include::config/gui.txt[]
+include::config/gui.adoc[]
 
-include::config/guitool.txt[]
+include::config/guitool.adoc[]
 
-include::config/help.txt[]
+include::config/help.adoc[]
 
-include::config/http.txt[]
+include::config/http.adoc[]
 
-include::config/i18n.txt[]
+include::config/i18n.adoc[]
 
-include::config/imap.txt[]
+include::config/imap.adoc[]
 
-include::config/includeif.txt[]
+include::config/includeif.adoc[]
 
-include::config/index.txt[]
+include::config/index.adoc[]
 
-include::config/init.txt[]
+include::config/init.adoc[]
 
-include::config/instaweb.txt[]
+include::config/instaweb.adoc[]
+
+include::config/interactive.adoc[]
 
-include::config/interactive.txt[]
+include::config/log.adoc[]
 
-include::config/log.txt[]
+include::config/lsrefs.adoc[]
 
-include::config/lsrefs.txt[]
+include::config/mailinfo.adoc[]
 
-include::config/mailinfo.txt[]
+include::config/mailmap.adoc[]
 
-include::config/mailmap.txt[]
+include::config/maintenance.adoc[]
 
-include::config/maintenance.txt[]
+include::config/man.adoc[]
 
-include::config/man.txt[]
+include::config/merge.adoc[]
 
-include::config/merge.txt[]
+include::config/mergetool.adoc[]
 
-include::config/mergetool.txt[]
+include::config/notes.adoc[]
 
-include::config/notes.txt[]
+include::config/pack.adoc[]
 
-include::config/pack.txt[]
+include::config/pager.adoc[]
 
-include::config/pager.txt[]
+include::config/pretty.adoc[]
 
-include::config/pretty.txt[]
+include::config/promisor.adoc[]
 
-include::config/promisor.txt[]
+include::config/protocol.adoc[]
 
-include::config/protocol.txt[]
+include::config/pull.adoc[]
 
-include::config/pull.txt[]
+include::config/push.adoc[]
 
-include::config/push.txt[]
+include::config/rebase.adoc[]
 
-include::config/rebase.txt[]
+include::config/receive.adoc[]
 
-include::config/receive.txt[]
+include::config/reftable.adoc[]
 
-include::config/reftable.txt[]
+include::config/remote.adoc[]
 
-include::config/remote.txt[]
+include::config/remotes.adoc[]
 
-include::config/remotes.txt[]
+include::config/repack.adoc[]
 
-include::config/repack.txt[]
+include::config/rerere.adoc[]
 
-include::config/rerere.txt[]
+include::config/revert.adoc[]
 
-include::config/revert.txt[]
+include::config/safe.adoc[]
 
-include::config/safe.txt[]
+include::config/sendemail.adoc[]
 
-include::config/sendemail.txt[]
+include::config/sequencer.adoc[]
 
-include::config/sequencer.txt[]
+include::config/showbranch.adoc[]
 
-include::config/showbranch.txt[]
+include::config/sparse.adoc[]
 
-include::config/sparse.txt[]
+include::config/splitindex.adoc[]
 
-include::config/splitindex.txt[]
+include::config/ssh.adoc[]
 
-include::config/ssh.txt[]
+include::config/stash.adoc[]
 
-include::config/stash.txt[]
+include::config/status.adoc[]
 
-include::config/status.txt[]
+include::config/submodule.adoc[]
 
-include::config/submodule.txt[]
+include::config/tag.adoc[]
 
-include::config/tag.txt[]
+include::config/tar.adoc[]
 
-include::config/tar.txt[]
+include::config/trace2.adoc[]
 
-include::config/trace2.txt[]
+include::config/trailer.adoc[]
 
-include::config/transfer.txt[]
+include::config/transfer.adoc[]
 
-include::config/uploadarchive.txt[]
+include::config/uploadarchive.adoc[]
 
-include::config/uploadpack.txt[]
+include::config/uploadpack.adoc[]
 
-include::config/url.txt[]
+include::config/url.adoc[]
 
-include::config/user.txt[]
+include::config/user.adoc[]
 
-include::config/versionsort.txt[]
+include::config/versionsort.adoc[]
 
-include::config/web.txt[]
+include::config/web.adoc[]
 
-include::config/worktree.txt[]
+include::config/worktree.adoc[]
diff --git a/Documentation/config/add.txt b/Documentation/config/add.adoc
similarity index 100%
rename from Documentation/config/add.txt
rename to Documentation/config/add.adoc
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.adoc
similarity index 100%
rename from Documentation/config/advice.txt
rename to Documentation/config/advice.adoc
diff --git a/Documentation/config/alias.txt b/Documentation/config/alias.adoc
similarity index 100%
rename from Documentation/config/alias.txt
rename to Documentation/config/alias.adoc
diff --git a/Documentation/config/am.txt b/Documentation/config/am.adoc
similarity index 100%
rename from Documentation/config/am.txt
rename to Documentation/config/am.adoc
diff --git a/Documentation/config/apply.txt b/Documentation/config/apply.adoc
similarity index 100%
rename from Documentation/config/apply.txt
rename to Documentation/config/apply.adoc
diff --git a/Documentation/config/attr.txt b/Documentation/config/attr.adoc
similarity index 100%
rename from Documentation/config/attr.txt
rename to Documentation/config/attr.adoc
diff --git a/Documentation/config/bitmap-pseudo-merge.txt b/Documentation/config/bitmap-pseudo-merge.adoc
similarity index 100%
rename from Documentation/config/bitmap-pseudo-merge.txt
rename to Documentation/config/bitmap-pseudo-merge.adoc
diff --git a/Documentation/config/blame.txt b/Documentation/config/blame.adoc
similarity index 100%
rename from Documentation/config/blame.txt
rename to Documentation/config/blame.adoc
diff --git a/Documentation/config/branch.txt b/Documentation/config/branch.adoc
similarity index 100%
rename from Documentation/config/branch.txt
rename to Documentation/config/branch.adoc
diff --git a/Documentation/config/browser.txt b/Documentation/config/browser.adoc
similarity index 100%
rename from Documentation/config/browser.txt
rename to Documentation/config/browser.adoc
diff --git a/Documentation/config/bundle.txt b/Documentation/config/bundle.adoc
similarity index 100%
rename from Documentation/config/bundle.txt
rename to Documentation/config/bundle.adoc
diff --git a/Documentation/config/checkout.txt b/Documentation/config/checkout.adoc
similarity index 100%
rename from Documentation/config/checkout.txt
rename to Documentation/config/checkout.adoc
diff --git a/Documentation/config/clean.txt b/Documentation/config/clean.adoc
similarity index 100%
rename from Documentation/config/clean.txt
rename to Documentation/config/clean.adoc
diff --git a/Documentation/config/clone.txt b/Documentation/config/clone.adoc
similarity index 100%
rename from Documentation/config/clone.txt
rename to Documentation/config/clone.adoc
diff --git a/Documentation/config/color.txt b/Documentation/config/color.adoc
similarity index 100%
rename from Documentation/config/color.txt
rename to Documentation/config/color.adoc
diff --git a/Documentation/config/column.txt b/Documentation/config/column.adoc
similarity index 100%
rename from Documentation/config/column.txt
rename to Documentation/config/column.adoc
diff --git a/Documentation/config/commit.txt b/Documentation/config/commit.adoc
similarity index 67%
rename from Documentation/config/commit.txt
rename to Documentation/config/commit.adoc
index 62f0d92..d3f4624 100644
--- a/Documentation/config/commit.txt
+++ b/Documentation/config/commit.adoc
@@ -1,29 +1,34 @@
-commit.cleanup::
+ifdef::git-commit[]
+:see-git-commit:
+endif::git-commit[]
+ifndef::git-commit[]
+:see-git-commit: See linkgit:git-commit[1] for details.
+endif::git-commit[]
+`commit.cleanup`::
 	This setting overrides the default of the `--cleanup` option in
-	`git commit`. See linkgit:git-commit[1] for details. Changing the
-	default can be useful when you always want to keep lines that begin
+	`git commit`. {see-git-commit} Changing the default can be useful
+	when you always want to keep lines that begin
 	with the comment character `#` in your log message, in which case you
 	would do `git config commit.cleanup whitespace` (note that you will
 	have to remove the help lines that begin with `#` in the commit log
 	template yourself, if you do this).
 
-commit.gpgSign::
-
+`commit.gpgSign`::
 	A boolean to specify whether all commits should be GPG signed.
 	Use of this option when doing operations such as rebase can
 	result in a large number of commits being signed. It may be
 	convenient to use an agent to avoid typing your GPG passphrase
 	several times.
 
-commit.status::
+`commit.status`::
 	A boolean to enable/disable inclusion of status information in the
 	commit message template when using an editor to prepare the commit
-	message.  Defaults to true.
+	message.  Defaults to `true`.
 
-commit.template::
+`commit.template`::
 	Specify the pathname of a file to use as the template for
 	new commit messages.
 
-commit.verbose::
+`commit.verbose`::
 	A boolean or int to specify the level of verbosity with `git commit`.
-	See linkgit:git-commit[1].
+	{see-git-commit}
diff --git a/Documentation/config/commitgraph.txt b/Documentation/config/commitgraph.adoc
similarity index 100%
rename from Documentation/config/commitgraph.txt
rename to Documentation/config/commitgraph.adoc
diff --git a/Documentation/config/completion.txt b/Documentation/config/completion.adoc
similarity index 100%
rename from Documentation/config/completion.txt
rename to Documentation/config/completion.adoc
diff --git a/Documentation/config/core.txt b/Documentation/config/core.adoc
similarity index 100%
rename from Documentation/config/core.txt
rename to Documentation/config/core.adoc
diff --git a/Documentation/config/credential.txt b/Documentation/config/credential.adoc
similarity index 100%
rename from Documentation/config/credential.txt
rename to Documentation/config/credential.adoc
diff --git a/Documentation/config/diff.txt b/Documentation/config/diff.adoc
similarity index 99%
rename from Documentation/config/diff.txt
rename to Documentation/config/diff.adoc
index fdae13a..1135a62 100644
--- a/Documentation/config/diff.txt
+++ b/Documentation/config/diff.adoc
@@ -218,8 +218,6 @@
 	Set this option to `true` to make the diff driver cache the text
 	conversion outputs.  See linkgit:gitattributes[5] for details.
 
-include::{build_dir}/mergetools-diff.txt[]
-
 `diff.indentHeuristic`::
 	Set this option to `false` to disable the default heuristics
 	that shift diff hunk boundaries to make patches easier to read.
diff --git a/Documentation/config/difftool.txt b/Documentation/config/difftool.adoc
similarity index 97%
rename from Documentation/config/difftool.txt
rename to Documentation/config/difftool.adoc
index 447c40d..4f7d40c 100644
--- a/Documentation/config/difftool.txt
+++ b/Documentation/config/difftool.adoc
@@ -13,6 +13,8 @@
 	and requires that a corresponding difftool.<guitool>.cmd variable
 	is defined.
 
+include::{build_dir}/mergetools-diff.adoc[]
+
 difftool.<tool>.cmd::
 	Specify the command to invoke the specified diff tool.
 	The specified command is evaluated in shell with the following
diff --git a/Documentation/config/extensions.txt b/Documentation/config/extensions.adoc
similarity index 98%
rename from Documentation/config/extensions.txt
rename to Documentation/config/extensions.adoc
index 5cb4721..9e2f321 100644
--- a/Documentation/config/extensions.txt
+++ b/Documentation/config/extensions.adoc
@@ -56,7 +56,7 @@
 refStorage::
 	Specify the ref storage format to use. The acceptable values are:
 +
-include::../ref-storage-format.txt[]
+include::../ref-storage-format.adoc[]
 
 +
 Note that this setting should only be set by linkgit:git-init[1] or
diff --git a/Documentation/config/fastimport.txt b/Documentation/config/fastimport.adoc
similarity index 100%
rename from Documentation/config/fastimport.txt
rename to Documentation/config/fastimport.adoc
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.adoc
similarity index 100%
rename from Documentation/config/feature.txt
rename to Documentation/config/feature.adoc
diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.adoc
similarity index 100%
rename from Documentation/config/fetch.txt
rename to Documentation/config/fetch.adoc
diff --git a/Documentation/config/filter.txt b/Documentation/config/filter.adoc
similarity index 100%
rename from Documentation/config/filter.txt
rename to Documentation/config/filter.adoc
diff --git a/Documentation/config/fmt-merge-msg.txt b/Documentation/config/fmt-merge-msg.adoc
similarity index 100%
rename from Documentation/config/fmt-merge-msg.txt
rename to Documentation/config/fmt-merge-msg.adoc
diff --git a/Documentation/config/format.txt b/Documentation/config/format.adoc
similarity index 100%
rename from Documentation/config/format.txt
rename to Documentation/config/format.adoc
diff --git a/Documentation/config/fsck.txt b/Documentation/config/fsck.adoc
similarity index 100%
rename from Documentation/config/fsck.txt
rename to Documentation/config/fsck.adoc
diff --git a/Documentation/config/fsmonitor--daemon.txt b/Documentation/config/fsmonitor--daemon.adoc
similarity index 100%
rename from Documentation/config/fsmonitor--daemon.txt
rename to Documentation/config/fsmonitor--daemon.adoc
diff --git a/Documentation/config/gc.txt b/Documentation/config/gc.adoc
similarity index 100%
rename from Documentation/config/gc.txt
rename to Documentation/config/gc.adoc
diff --git a/Documentation/config/gitcvs.txt b/Documentation/config/gitcvs.adoc
similarity index 100%
rename from Documentation/config/gitcvs.txt
rename to Documentation/config/gitcvs.adoc
diff --git a/Documentation/config/gitweb.txt b/Documentation/config/gitweb.adoc
similarity index 100%
rename from Documentation/config/gitweb.txt
rename to Documentation/config/gitweb.adoc
diff --git a/Documentation/config/gpg.txt b/Documentation/config/gpg.adoc
similarity index 100%
rename from Documentation/config/gpg.txt
rename to Documentation/config/gpg.adoc
diff --git a/Documentation/config/grep.txt b/Documentation/config/grep.adoc
similarity index 100%
rename from Documentation/config/grep.txt
rename to Documentation/config/grep.adoc
diff --git a/Documentation/config/gui.txt b/Documentation/config/gui.adoc
similarity index 100%
rename from Documentation/config/gui.txt
rename to Documentation/config/gui.adoc
diff --git a/Documentation/config/guitool.txt b/Documentation/config/guitool.adoc
similarity index 100%
rename from Documentation/config/guitool.txt
rename to Documentation/config/guitool.adoc
diff --git a/Documentation/config/help.txt b/Documentation/config/help.adoc
similarity index 80%
rename from Documentation/config/help.txt
rename to Documentation/config/help.adoc
index 610701f..b369589 100644
--- a/Documentation/config/help.txt
+++ b/Documentation/config/help.adoc
@@ -11,13 +11,14 @@
 	If git detects typos and can identify exactly one valid command similar
 	to the error, git will try to suggest the correct command or even
 	run the suggestion automatically. Possible config values are:
-	 - 0 (default): show the suggested command.
-	 - positive number: run the suggested command after specified
+	 - 0, "false", "off", "no", "show": show the suggested command (default).
+	 - 1, "true", "on", "yes", "immediate": run the suggested command
+immediately.
+	 - positive number > 1: run the suggested command after specified
 deciseconds (0.1 sec).
-	 - "immediate": run the suggested command immediately.
+	 - "never": don't run or show any suggested command.
 	 - "prompt": show the suggestion and prompt for confirmation to run
 the command.
-	 - "never": don't run or show any suggested command.
 
 help.htmlPath::
 	Specify the path where the HTML documentation resides. File system paths
diff --git a/Documentation/config/http.txt b/Documentation/config/http.adoc
similarity index 94%
rename from Documentation/config/http.txt
rename to Documentation/config/http.adoc
index a14371b..22a8803 100644
--- a/Documentation/config/http.txt
+++ b/Documentation/config/http.adoc
@@ -216,6 +216,21 @@
 	This option is ignored if cURL lacks support for choosing the SSL
 	backend at runtime.
 
+http.sslCertType::
+	Type of client certificate used when fetching or pushing over HTTPS.
+	"PEM", "DER" are supported when using openssl or gnutls backends. "P12"
+	is supported on "openssl", "schannel", "securetransport", and gnutls 8.11+.
+	See also libcurl `CURLOPT_SSLCERTTYPE`. Can be overridden by the
+	`GIT_SSL_CERT_TYPE` environment variable.
+
+http.sslKeyType::
+	Type of client private key used when fetching or pushing over HTTPS. (e.g.
+	"PEM", "DER", or "ENG"). Only applicable when using "openssl" backend. "DER"
+	is not supported with openssl. Particularly useful when set to "ENG" for
+	authenticating with PKCS#11 tokens, with a PKCS#11 URL in sslCert option.
+	See also libcurl `CURLOPT_SSLKEYTYPE`. Can be overridden by the
+	`GIT_SSL_KEY_TYPE` environment variable.
+
 http.schannelCheckRevoke::
 	Used to enforce or disable certificate revocation checks in cURL
 	when http.sslBackend is set to "schannel". Defaults to `true` if
diff --git a/Documentation/config/i18n.txt b/Documentation/config/i18n.adoc
similarity index 100%
rename from Documentation/config/i18n.txt
rename to Documentation/config/i18n.adoc
diff --git a/Documentation/config/imap.txt b/Documentation/config/imap.adoc
similarity index 100%
rename from Documentation/config/imap.txt
rename to Documentation/config/imap.adoc
diff --git a/Documentation/config/includeif.txt b/Documentation/config/includeif.adoc
similarity index 100%
rename from Documentation/config/includeif.txt
rename to Documentation/config/includeif.adoc
diff --git a/Documentation/config/index.txt b/Documentation/config/index.adoc
similarity index 100%
rename from Documentation/config/index.txt
rename to Documentation/config/index.adoc
diff --git a/Documentation/config/init.txt b/Documentation/config/init.adoc
similarity index 100%
rename from Documentation/config/init.txt
rename to Documentation/config/init.adoc
diff --git a/Documentation/config/instaweb.txt b/Documentation/config/instaweb.adoc
similarity index 100%
rename from Documentation/config/instaweb.txt
rename to Documentation/config/instaweb.adoc
diff --git a/Documentation/config/interactive.txt b/Documentation/config/interactive.adoc
similarity index 100%
rename from Documentation/config/interactive.txt
rename to Documentation/config/interactive.adoc
diff --git a/Documentation/config/log.txt b/Documentation/config/log.adoc
similarity index 100%
rename from Documentation/config/log.txt
rename to Documentation/config/log.adoc
diff --git a/Documentation/config/lsrefs.txt b/Documentation/config/lsrefs.adoc
similarity index 100%
rename from Documentation/config/lsrefs.txt
rename to Documentation/config/lsrefs.adoc
diff --git a/Documentation/config/mailinfo.txt b/Documentation/config/mailinfo.adoc
similarity index 100%
rename from Documentation/config/mailinfo.txt
rename to Documentation/config/mailinfo.adoc
diff --git a/Documentation/config/mailmap.txt b/Documentation/config/mailmap.adoc
similarity index 100%
rename from Documentation/config/mailmap.txt
rename to Documentation/config/mailmap.adoc
diff --git a/Documentation/config/maintenance.txt b/Documentation/config/maintenance.adoc
similarity index 100%
rename from Documentation/config/maintenance.txt
rename to Documentation/config/maintenance.adoc
diff --git a/Documentation/config/man.txt b/Documentation/config/man.adoc
similarity index 100%
rename from Documentation/config/man.txt
rename to Documentation/config/man.adoc
diff --git a/Documentation/config/merge.txt b/Documentation/config/merge.adoc
similarity index 96%
rename from Documentation/config/merge.txt
rename to Documentation/config/merge.adoc
index 82554d6..d2d0f21 100644
--- a/Documentation/config/merge.txt
+++ b/Documentation/config/merge.adoc
@@ -37,7 +37,7 @@
 	If true, this is equivalent to the --verify-signatures command
 	line option. See linkgit:git-merge[1] for details.
 
-include::fmt-merge-msg.txt[]
+include::fmt-merge-msg.adoc[]
 
 merge.renameLimit::
 	The number of files to consider in the exhaustive portion of
@@ -69,7 +69,8 @@
 	Tell Git that canonical representation of files in the
 	repository has changed over time (e.g. earlier commits record
 	text files with CRLF line endings, but recent ones use LF line
-	endings).  In such a repository, Git can convert the data
+	endings).  In such a repository, for each file where a
+	three-way content merge is needed, Git can convert the data
 	recorded in commits to a canonical form before performing a
 	merge to reduce unnecessary conflicts.  For more information,
 	see section "Merging branches with differing checkin/checkout
@@ -101,7 +102,7 @@
 	Any other value is treated as a custom merge tool and requires that a
 	corresponding mergetool.<guitool>.cmd variable is defined.
 
-include::{build_dir}/mergetools-merge.txt[]
+include::{build_dir}/mergetools-merge.adoc[]
 
 merge.verbosity::
 	Controls the amount of output shown by the recursive merge
diff --git a/Documentation/config/mergetool.txt b/Documentation/config/mergetool.adoc
similarity index 100%
rename from Documentation/config/mergetool.txt
rename to Documentation/config/mergetool.adoc
diff --git a/Documentation/config/notes.txt b/Documentation/config/notes.adoc
similarity index 72%
rename from Documentation/config/notes.txt
rename to Documentation/config/notes.adoc
index 43db8e8..b7e5364 100644
--- a/Documentation/config/notes.txt
+++ b/Documentation/config/notes.adoc
@@ -1,4 +1,4 @@
-notes.mergeStrategy::
+`notes.mergeStrategy`::
 	Which merge strategy to choose by default when resolving notes
 	conflicts.  Must be one of `manual`, `ours`, `theirs`, `union`, or
 	`cat_sort_uniq`.  Defaults to `manual`.  See the "NOTES MERGE STRATEGIES"
@@ -7,17 +7,17 @@
 This setting can be overridden by passing the `--strategy` option to
 linkgit:git-notes[1].
 
-notes.<name>.mergeStrategy::
+`notes.<name>.mergeStrategy`::
 	Which merge strategy to choose when doing a notes merge into
-	refs/notes/<name>.  This overrides the more general
-	"notes.mergeStrategy".  See the "NOTES MERGE STRATEGIES" section in
+	`refs/notes/<name>`.  This overrides the more general
+	`notes.mergeStrategy`.  See the "NOTES MERGE STRATEGIES" section in
 	linkgit:git-notes[1] for more information on the available strategies.
 
-notes.displayRef::
+`notes.displayRef`::
 	Which ref (or refs, if a glob or specified more than once), in
 	addition to the default set by `core.notesRef` or
 	`GIT_NOTES_REF`, to read notes from when showing commit
-	messages with the 'git log' family of commands.
+	messages with the `git log` family of commands.
 +
 This setting can be overridden with the `GIT_NOTES_DISPLAY_REF`
 environment variable, which must be a colon separated list of refs or
@@ -26,27 +26,27 @@
 A warning will be issued for refs that do not exist,
 but a glob that does not match any refs is silently ignored.
 +
-This setting can be disabled by the `--no-notes` option to the 'git
-log' family of commands, or by the `--notes=<ref>` option accepted by
+This setting can be disabled by the `--no-notes` option to the linkgit:git-log[1]
+family of commands, or by the `--notes=<ref>` option accepted by
 those commands.
 +
-The effective value of "core.notesRef" (possibly overridden by
-GIT_NOTES_REF) is also implicitly added to the list of refs to be
+The effective value of `core.notesRef` (possibly overridden by
+`GIT_NOTES_REF`) is also implicitly added to the list of refs to be
 displayed.
 
-notes.rewrite.<command>::
-	When rewriting commits with <command> (currently `amend` or
+`notes.rewrite.<command>`::
+	When rewriting commits with _<command>_ (currently `amend` or
 	`rebase`), if this variable is `false`, git will not copy
 	notes from the original to the rewritten commit.  Defaults to
-	`true`.  See also "`notes.rewriteRef`" below.
+	`true`.  See also `notes.rewriteRef` below.
 +
 This setting can be overridden with the `GIT_NOTES_REWRITE_REF`
 environment variable, which must be a colon separated list of refs or
 globs.
 
-notes.rewriteMode::
+`notes.rewriteMode`::
 	When copying notes during a rewrite (see the
-	"notes.rewrite.<command>" option), determines what to do if
+	`notes.rewrite.<command>` option), determines what to do if
 	the target commit already has a note.  Must be one of
 	`overwrite`, `concatenate`, `cat_sort_uniq`, or `ignore`.
 	Defaults to `concatenate`.
@@ -54,7 +54,7 @@
 This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`
 environment variable.
 
-notes.rewriteRef::
+`notes.rewriteRef`::
 	When copying notes during a rewrite, specifies the (fully
 	qualified) ref whose notes should be copied.  May be a glob,
 	in which case notes in all matching refs will be copied.  You
diff --git a/Documentation/config/pack.txt b/Documentation/config/pack.adoc
similarity index 100%
rename from Documentation/config/pack.txt
rename to Documentation/config/pack.adoc
diff --git a/Documentation/config/pager.txt b/Documentation/config/pager.adoc
similarity index 100%
rename from Documentation/config/pager.txt
rename to Documentation/config/pager.adoc
diff --git a/Documentation/config/pretty.txt b/Documentation/config/pretty.adoc
similarity index 100%
rename from Documentation/config/pretty.txt
rename to Documentation/config/pretty.adoc
diff --git a/Documentation/config/promisor.adoc b/Documentation/config/promisor.adoc
new file mode 100644
index 0000000..9192acf
--- /dev/null
+++ b/Documentation/config/promisor.adoc
@@ -0,0 +1,30 @@
+promisor.quiet::
+	If set to "true" assume `--quiet` when fetching additional
+	objects for a partial clone.
+
+promisor.advertise::
+	If set to "true", a server will use the "promisor-remote"
+	capability, see linkgit:gitprotocol-v2[5], to advertise the
+	promisor remotes it is using, if it uses some. Default is
+	"false", which means the "promisor-remote" capability is not
+	advertised.
+
+promisor.acceptFromServer::
+	If set to "all", a client will accept all the promisor remotes
+	a server might advertise using the "promisor-remote"
+	capability. If set to "knownName" the client will accept
+	promisor remotes which are already configured on the client
+	and have the same name as those advertised by the client. This
+	is not very secure, but could be used in a corporate setup
+	where servers and clients are trusted to not switch name and
+	URLs. If set to "knownUrl", the client will accept promisor
+	remotes which have both the same name and the same URL
+	configured on the client as the name and URL advertised by the
+	server. This is more secure than "all" or "knownName", so it
+	should be used if possible instead of those options. Default
+	is "none", which means no promisor remote advertised by a
+	server will be accepted. By accepting a promisor remote, the
+	client agrees that the server might omit objects that are
+	lazily fetchable from this promisor remote from its responses
+	to "fetch" and "clone" requests from the client. See
+	linkgit:gitprotocol-v2[5].
diff --git a/Documentation/config/promisor.txt b/Documentation/config/promisor.txt
deleted file mode 100644
index 98c5cb2..0000000
--- a/Documentation/config/promisor.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-promisor.quiet::
-	If set to "true" assume `--quiet` when fetching additional
-	objects for a partial clone.
diff --git a/Documentation/config/protocol.txt b/Documentation/config/protocol.adoc
similarity index 100%
rename from Documentation/config/protocol.txt
rename to Documentation/config/protocol.adoc
diff --git a/Documentation/config/pull.txt b/Documentation/config/pull.adoc
similarity index 100%
rename from Documentation/config/pull.txt
rename to Documentation/config/pull.adoc
diff --git a/Documentation/config/push.txt b/Documentation/config/push.adoc
similarity index 100%
rename from Documentation/config/push.txt
rename to Documentation/config/push.adoc
diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.adoc
similarity index 100%
rename from Documentation/config/rebase.txt
rename to Documentation/config/rebase.adoc
diff --git a/Documentation/config/receive.txt b/Documentation/config/receive.adoc
similarity index 100%
rename from Documentation/config/receive.txt
rename to Documentation/config/receive.adoc
diff --git a/Documentation/config/reftable.txt b/Documentation/config/reftable.adoc
similarity index 100%
rename from Documentation/config/reftable.txt
rename to Documentation/config/reftable.adoc
diff --git a/Documentation/config/remote.txt b/Documentation/config/remote.adoc
similarity index 92%
rename from Documentation/config/remote.txt
rename to Documentation/config/remote.adoc
index 4118c21..25fe219 100644
--- a/Documentation/config/remote.txt
+++ b/Documentation/config/remote.adoc
@@ -101,21 +101,21 @@
 	The default set of server options used when fetching from this remote.
 	These server options can be overridden by the `--server-option=` command
 	line arguments.
-
-remote.<name>.followRemoteHEAD::
-	How linkgit:git-fetch[1] should handle updates to `remotes/<name>/HEAD`.
-	The default value is "create", which will create `remotes/<name>/HEAD`
-	if it exists on the remote, but not locally, but will not touch an
-	already existing local reference. Setting to "warn" will print
-	a message if the remote has a different value, than the local one and
-	in case there is no local reference, it behaves like "create".
-	A variant on "warn" is "warn-if-not-$branch", which behaves like
-	"warn", but if `HEAD` on the remote is `$branch` it will be silent.
-	Setting to "always" will silently update it to the value on the remote.
-	Finally, setting it to "never" will never change or create the local
-	reference.
 +
 This is a multi-valued variable, and an empty value can be used in a higher
 priority configuration file (e.g. `.git/config` in a repository) to clear
 the values inherited from a lower priority configuration files (e.g.
 `$HOME/.gitconfig`).
+
+remote.<name>.followRemoteHEAD::
+	How linkgit:git-fetch[1] should handle updates to `remotes/<name>/HEAD`.
+	The default value is "create", which will create `remotes/<name>/HEAD`
+	if it exists on the remote, but not locally; this will not touch an
+	already existing local reference. Setting it to "warn" will print
+	a message if the remote has a different value than the local one;
+	in case there is no local reference, it behaves like "create".
+	A variant on "warn" is "warn-if-not-$branch", which behaves like
+	"warn", but if `HEAD` on the remote is `$branch` it will be silent.
+	Setting it to "always" will silently update `remotes/<name>/HEAD` to
+	the value on the remote.  Finally, setting it to "never" will never
+	change or create the local reference.
diff --git a/Documentation/config/remotes.txt b/Documentation/config/remotes.adoc
similarity index 100%
rename from Documentation/config/remotes.txt
rename to Documentation/config/remotes.adoc
diff --git a/Documentation/config/repack.txt b/Documentation/config/repack.adoc
similarity index 100%
rename from Documentation/config/repack.txt
rename to Documentation/config/repack.adoc
diff --git a/Documentation/config/rerere.txt b/Documentation/config/rerere.adoc
similarity index 100%
rename from Documentation/config/rerere.txt
rename to Documentation/config/rerere.adoc
diff --git a/Documentation/config/revert.txt b/Documentation/config/revert.adoc
similarity index 100%
rename from Documentation/config/revert.txt
rename to Documentation/config/revert.adoc
diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.adoc
similarity index 100%
rename from Documentation/config/safe.txt
rename to Documentation/config/safe.adoc
diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.adoc
similarity index 100%
rename from Documentation/config/sendemail.txt
rename to Documentation/config/sendemail.adoc
diff --git a/Documentation/config/sequencer.txt b/Documentation/config/sequencer.adoc
similarity index 100%
rename from Documentation/config/sequencer.txt
rename to Documentation/config/sequencer.adoc
diff --git a/Documentation/config/showbranch.txt b/Documentation/config/showbranch.adoc
similarity index 100%
rename from Documentation/config/showbranch.txt
rename to Documentation/config/showbranch.adoc
diff --git a/Documentation/config/sparse.txt b/Documentation/config/sparse.adoc
similarity index 100%
rename from Documentation/config/sparse.txt
rename to Documentation/config/sparse.adoc
diff --git a/Documentation/config/splitindex.txt b/Documentation/config/splitindex.adoc
similarity index 100%
rename from Documentation/config/splitindex.txt
rename to Documentation/config/splitindex.adoc
diff --git a/Documentation/config/ssh.txt b/Documentation/config/ssh.adoc
similarity index 100%
rename from Documentation/config/ssh.txt
rename to Documentation/config/ssh.adoc
diff --git a/Documentation/config/stash.txt b/Documentation/config/stash.adoc
similarity index 100%
rename from Documentation/config/stash.txt
rename to Documentation/config/stash.adoc
diff --git a/Documentation/config/status.txt b/Documentation/config/status.adoc
similarity index 100%
rename from Documentation/config/status.txt
rename to Documentation/config/status.adoc
diff --git a/Documentation/config/submodule.txt b/Documentation/config/submodule.adoc
similarity index 100%
rename from Documentation/config/submodule.txt
rename to Documentation/config/submodule.adoc
diff --git a/Documentation/config/tag.txt b/Documentation/config/tag.adoc
similarity index 100%
rename from Documentation/config/tag.txt
rename to Documentation/config/tag.adoc
diff --git a/Documentation/config/tar.txt b/Documentation/config/tar.adoc
similarity index 100%
rename from Documentation/config/tar.txt
rename to Documentation/config/tar.adoc
diff --git a/Documentation/config/trace2.txt b/Documentation/config/trace2.adoc
similarity index 98%
rename from Documentation/config/trace2.txt
rename to Documentation/config/trace2.adoc
index 3b6bca2..05639ce 100644
--- a/Documentation/config/trace2.txt
+++ b/Documentation/config/trace2.adoc
@@ -17,7 +17,7 @@
 	It may be overridden by the `GIT_TRACE2_EVENT` environment variable.
 	The following table shows possible values.
 +
-include::../trace2-target-values.txt[]
+include::../trace2-target-values.adoc[]
 
 trace2.normalBrief::
 	Boolean.  When true `time`, `filename`, and `line` fields are
diff --git a/Documentation/config/trailer.adoc b/Documentation/config/trailer.adoc
new file mode 100644
index 0000000..60bc221
--- /dev/null
+++ b/Documentation/config/trailer.adoc
@@ -0,0 +1,136 @@
+trailer.separators::
+	This option tells which characters are recognized as trailer
+	separators. By default only ':' is recognized as a trailer
+	separator, except that '=' is always accepted on the command
+	line for compatibility with other git commands.
++
+The first character given by this option will be the default character
+used when another separator is not specified in the config for this
+trailer.
++
+For example, if the value for this option is "%=$", then only lines
+using the format '<key><sep><value>' with <sep> containing '%', '='
+or '$' and then spaces will be considered trailers. And '%' will be
+the default separator used, so by default trailers will appear like:
+'<key>% <value>' (one percent sign and one space will appear between
+the key and the value).
+
+trailer.where::
+	This option tells where a new trailer will be added.
++
+This can be `end`, which is the default, `start`, `after` or `before`.
++
+If it is `end`, then each new trailer will appear at the end of the
+existing trailers.
++
+If it is `start`, then each new trailer will appear at the start,
+instead of the end, of the existing trailers.
++
+If it is `after`, then each new trailer will appear just after the
+last trailer with the same <key>.
++
+If it is `before`, then each new trailer will appear just before the
+first trailer with the same <key>.
+
+trailer.ifexists::
+	This option makes it possible to choose what action will be
+	performed when there is already at least one trailer with the
+	same <key> in the input.
++
+The valid values for this option are: `addIfDifferentNeighbor` (this
+is the default), `addIfDifferent`, `add`, `replace` or `doNothing`.
++
+With `addIfDifferentNeighbor`, a new trailer will be added only if no
+trailer with the same (<key>, <value>) pair is above or below the line
+where the new trailer will be added.
++
+With `addIfDifferent`, a new trailer will be added only if no trailer
+with the same (<key>, <value>) pair is already in the input.
++
+With `add`, a new trailer will be added, even if some trailers with
+the same (<key>, <value>) pair are already in the input.
++
+With `replace`, an existing trailer with the same <key> will be
+deleted and the new trailer will be added. The deleted trailer will be
+the closest one (with the same <key>) to the place where the new one
+will be added.
++
+With `doNothing`, nothing will be done; that is no new trailer will be
+added if there is already one with the same <key> in the input.
+
+trailer.ifmissing::
+	This option makes it possible to choose what action will be
+	performed when there is not yet any trailer with the same
+	<key> in the input.
++
+The valid values for this option are: `add` (this is the default) and
+`doNothing`.
++
+With `add`, a new trailer will be added.
++
+With `doNothing`, nothing will be done.
+
+trailer.<keyAlias>.key::
+	Defines a <keyAlias> for the <key>. The <keyAlias> must be a
+	prefix (case does not matter) of the <key>. For example, in `git
+	config trailer.ack.key "Acked-by"` the "Acked-by" is the <key> and
+	the "ack" is the <keyAlias>. This configuration allows the shorter
+	`--trailer "ack:..."` invocation on the command line using the "ack"
+	<keyAlias> instead of the longer `--trailer "Acked-by:..."`.
++
+At the end of the <key>, a separator can appear and then some
+space characters. By default the only valid separator is ':',
+but this can be changed using the `trailer.separators` config
+variable.
++
+If there is a separator in the key, then it overrides the default
+separator when adding the trailer.
+
+trailer.<keyAlias>.where::
+	This option takes the same values as the 'trailer.where'
+	configuration variable and it overrides what is specified by
+	that option for trailers with the specified <keyAlias>.
+
+trailer.<keyAlias>.ifexists::
+	This option takes the same values as the 'trailer.ifexists'
+	configuration variable and it overrides what is specified by
+	that option for trailers with the specified <keyAlias>.
+
+trailer.<keyAlias>.ifmissing::
+	This option takes the same values as the 'trailer.ifmissing'
+	configuration variable and it overrides what is specified by
+	that option for trailers with the specified <keyAlias>.
+
+trailer.<keyAlias>.command::
+	Deprecated in favor of 'trailer.<keyAlias>.cmd'.
+	This option behaves in the same way as 'trailer.<keyAlias>.cmd', except
+	that it doesn't pass anything as argument to the specified command.
+	Instead the first occurrence of substring $ARG is replaced by the
+	<value> that would be passed as argument.
++
+Note that $ARG in the user's command is
+only replaced once and that the original way of replacing $ARG is not safe.
++
+When both 'trailer.<keyAlias>.cmd' and 'trailer.<keyAlias>.command' are given
+for the same <keyAlias>, 'trailer.<keyAlias>.cmd' is used and
+'trailer.<keyAlias>.command' is ignored.
+
+trailer.<keyAlias>.cmd::
+	This option can be used to specify a shell command that will be called
+	once to automatically add a trailer with the specified <keyAlias>, and then
+	called each time a '--trailer <keyAlias>=<value>' argument is specified to
+	modify the <value> of the trailer that this option would produce.
++
+When the specified command is first called to add a trailer
+with the specified <keyAlias>, the behavior is as if a special
+'--trailer <keyAlias>=<value>' argument was added at the beginning
+of the "git interpret-trailers" command, where <value>
+is taken to be the standard output of the command with any
+leading and trailing whitespace trimmed off.
++
+If some '--trailer <keyAlias>=<value>' arguments are also passed
+on the command line, the command is called again once for each
+of these arguments with the same <keyAlias>. And the <value> part
+of these arguments, if any, will be passed to the command as its
+first argument. This way the command can produce a <value> computed
+from the <value> passed in the '--trailer <keyAlias>=<value>' argument.
diff --git a/Documentation/config/transfer.txt b/Documentation/config/transfer.adoc
similarity index 100%
rename from Documentation/config/transfer.txt
rename to Documentation/config/transfer.adoc
diff --git a/Documentation/config/uploadarchive.txt b/Documentation/config/uploadarchive.adoc
similarity index 100%
rename from Documentation/config/uploadarchive.txt
rename to Documentation/config/uploadarchive.adoc
diff --git a/Documentation/config/uploadpack.txt b/Documentation/config/uploadpack.adoc
similarity index 100%
rename from Documentation/config/uploadpack.txt
rename to Documentation/config/uploadpack.adoc
diff --git a/Documentation/config/url.txt b/Documentation/config/url.adoc
similarity index 100%
rename from Documentation/config/url.txt
rename to Documentation/config/url.adoc
diff --git a/Documentation/config/user.txt b/Documentation/config/user.adoc
similarity index 100%
rename from Documentation/config/user.txt
rename to Documentation/config/user.adoc
diff --git a/Documentation/config/versionsort.txt b/Documentation/config/versionsort.adoc
similarity index 100%
rename from Documentation/config/versionsort.txt
rename to Documentation/config/versionsort.adoc
diff --git a/Documentation/config/web.txt b/Documentation/config/web.adoc
similarity index 100%
rename from Documentation/config/web.txt
rename to Documentation/config/web.adoc
diff --git a/Documentation/config/worktree.txt b/Documentation/config/worktree.adoc
similarity index 100%
rename from Documentation/config/worktree.txt
rename to Documentation/config/worktree.adoc
diff --git a/Documentation/date-formats.txt b/Documentation/date-formats.adoc
similarity index 100%
rename from Documentation/date-formats.txt
rename to Documentation/date-formats.adoc
diff --git a/Documentation/diff-format.txt b/Documentation/diff-format.adoc
similarity index 98%
rename from Documentation/diff-format.txt
rename to Documentation/diff-format.adoc
index c72fb37..80e36e1 100644
--- a/Documentation/diff-format.txt
+++ b/Documentation/diff-format.adoc
@@ -121,7 +121,7 @@
 all parents.
 
 
-include::diff-generate-patch.txt[]
+include::diff-generate-patch.adoc[]
 
 
 other diff formats
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.adoc
similarity index 100%
rename from Documentation/diff-generate-patch.txt
rename to Documentation/diff-generate-patch.adoc
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.adoc
similarity index 100%
rename from Documentation/diff-options.txt
rename to Documentation/diff-options.adoc
diff --git a/Documentation/everyday.txto b/Documentation/everyday.adoco
similarity index 100%
rename from Documentation/everyday.txto
rename to Documentation/everyday.adoco
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.adoc
similarity index 100%
rename from Documentation/fetch-options.txt
rename to Documentation/fetch-options.adoc
diff --git a/Documentation/fsck-msgids.txt b/Documentation/fsck-msgids.adoc
similarity index 100%
rename from Documentation/fsck-msgids.txt
rename to Documentation/fsck-msgids.adoc
diff --git a/Documentation/git-add.txt b/Documentation/git-add.adoc
similarity index 99%
rename from Documentation/git-add.txt
rename to Documentation/git-add.adoc
index 5f2c359..eba0b41 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.adoc
@@ -437,10 +437,10 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
 :git-add: 1
-include::config/add.txt[]
+include::config/add.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-am.txt b/Documentation/git-am.adoc
similarity index 98%
rename from Documentation/git-am.txt
rename to Documentation/git-am.adoc
index 69d5cc9..221070d 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.adoc
@@ -120,7 +120,7 @@
 	am.threeWay configuration variable. For more information,
 	see am.threeWay in linkgit:git-config[1].
 
-include::rerere-options.txt[]
+include::rerere-options.adoc[]
 
 --ignore-space-change::
 --ignore-whitespace::
@@ -284,9 +284,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/am.txt[]
+include::config/am.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-annotate.txt b/Documentation/git-annotate.adoc
similarity index 95%
rename from Documentation/git-annotate.txt
rename to Documentation/git-annotate.adoc
index 5ae8aab..965bc67 100644
--- a/Documentation/git-annotate.txt
+++ b/Documentation/git-annotate.adoc
@@ -22,7 +22,7 @@
 
 OPTIONS
 -------
-include::blame-options.txt[]
+include::blame-options.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.adoc
similarity index 98%
rename from Documentation/git-apply.txt
rename to Documentation/git-apply.adoc
index dd4a61e..952518b 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.adoc
@@ -270,9 +270,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/apply.txt[]
+include::config/apply.adoc[]
 
 SUBMODULES
 ----------
diff --git a/Documentation/git-archimport.txt b/Documentation/git-archimport.adoc
similarity index 100%
rename from Documentation/git-archimport.txt
rename to Documentation/git-archimport.adoc
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.adoc
similarity index 100%
rename from Documentation/git-archive.txt
rename to Documentation/git-archive.adoc
diff --git a/Documentation/git-backfill.adoc b/Documentation/git-backfill.adoc
new file mode 100644
index 0000000..9562305
--- /dev/null
+++ b/Documentation/git-backfill.adoc
@@ -0,0 +1,71 @@
+git-backfill(1)
+===============
+
+NAME
+----
+git-backfill - Download missing objects in a partial clone
+
+
+SYNOPSIS
+--------
+[synopsis]
+git backfill [--min-batch-size=<n>] [--[no-]sparse]
+
+DESCRIPTION
+-----------
+
+Blobless partial clones are created using `git clone --filter=blob:none`
+and then configure the local repository such that the Git client avoids
+downloading blob objects unless they are required for a local operation.
+This initially means that the clone and later fetches download reachable
+commits and trees but no blobs. Later operations that change the `HEAD`
+pointer, such as `git checkout` or `git merge`, may need to download
+missing blobs in order to complete their operation.
+
+In the worst cases, commands that compute blob diffs, such as `git blame`,
+become very slow as they download the missing blobs in single-blob
+requests to satisfy the missing object as the Git command needs it. This
+leads to multiple download requests and no ability for the Git server to
+provide delta compression across those objects.
+
+The `git backfill` command provides a way for the user to request that
+Git downloads the missing blobs (with optional filters) such that the
+missing blobs representing historical versions of files can be downloaded
+in batches. The `backfill` command attempts to optimize the request by
+grouping blobs that appear at the same path, hopefully leading to good
+delta compression in the packfile sent by the server.
+
+In this way, `git backfill` provides a mechanism to break a large clone
+into smaller chunks. Starting with a blobless partial clone with `git
+clone --filter=blob:none` and then running `git backfill` in the local
+repository provides a way to download all reachable objects in several
+smaller network calls than downloading the entire repository at clone
+time.
+
+By default, `git backfill` downloads all blobs reachable from the `HEAD`
+commit. This set can be restricted or expanded using various options.
+
+THIS COMMAND IS EXPERIMENTAL. ITS BEHAVIOR MAY CHANGE IN THE FUTURE.
+
+
+OPTIONS
+-------
+
+`--min-batch-size=<n>`::
+	Specify a minimum size for a batch of missing objects to request
+	from the server. This size may be exceeded by the last set of
+	blobs seen at a given path. The default minimum batch size is
+	50,000.
+
+`--[no-]sparse`::
+	Only download objects if they appear at a path that matches the
+	current sparse-checkout. If the sparse-checkout feature is enabled,
+	then `--sparse` is assumed and can be disabled with `--no-sparse`.
+
+SEE ALSO
+--------
+linkgit:git-clone[1].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.adoc
similarity index 100%
rename from Documentation/git-bisect-lk2009.txt
rename to Documentation/git-bisect-lk2009.adoc
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.adoc
similarity index 100%
rename from Documentation/git-bisect.txt
rename to Documentation/git-bisect.adoc
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.adoc
similarity index 98%
rename from Documentation/git-blame.txt
rename to Documentation/git-blame.adoc
index b1d7fb5..f75ed44 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.adoc
@@ -48,7 +48,7 @@
 
 OPTIONS
 -------
-include::blame-options.txt[]
+include::blame-options.adoc[]
 
 -c::
 	Use the same output mode as linkgit:git-annotate[1] (Default: off).
@@ -244,9 +244,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/blame.txt[]
+include::config/blame.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.adoc
similarity index 98%
rename from Documentation/git-branch.txt
rename to Documentation/git-branch.adoc
index 0b08442..7a073a3 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.adoc
@@ -345,9 +345,9 @@
 `--list` is used or implied. The default is to use a pager.
 See linkgit:git-config[1].
 
-include::includes/cmd-config-section-rest.txt[]
+include::includes/cmd-config-section-rest.adoc[]
 
-include::config/branch.txt[]
+include::config/branch.adoc[]
 
 EXAMPLES
 --------
@@ -415,7 +415,7 @@
 - `--no-merged` is used to find branches which are candidates for merging
   into HEAD, since those branches are not fully contained by HEAD.
 
-include::ref-reachability-filters.txt[]
+include::ref-reachability-filters.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.adoc
similarity index 100%
rename from Documentation/git-bugreport.txt
rename to Documentation/git-bugreport.adoc
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.adoc
similarity index 100%
rename from Documentation/git-bundle.txt
rename to Documentation/git-bundle.adoc
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.adoc
similarity index 100%
rename from Documentation/git-cat-file.txt
rename to Documentation/git-cat-file.adoc
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.adoc
similarity index 100%
rename from Documentation/git-check-attr.txt
rename to Documentation/git-check-attr.adoc
diff --git a/Documentation/git-check-ignore.txt b/Documentation/git-check-ignore.adoc
similarity index 100%
rename from Documentation/git-check-ignore.txt
rename to Documentation/git-check-ignore.adoc
diff --git a/Documentation/git-check-mailmap.txt b/Documentation/git-check-mailmap.adoc
similarity index 100%
rename from Documentation/git-check-mailmap.txt
rename to Documentation/git-check-mailmap.adoc
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.adoc
similarity index 100%
rename from Documentation/git-check-ref-format.txt
rename to Documentation/git-check-ref-format.adoc
diff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.adoc
similarity index 100%
rename from Documentation/git-checkout-index.txt
rename to Documentation/git-checkout-index.adoc
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.adoc
similarity index 99%
rename from Documentation/git-checkout.txt
rename to Documentation/git-checkout.adoc
index bf26655..a66c53a 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.adoc
@@ -612,9 +612,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/checkout.txt[]
+include::config/checkout.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.adoc
similarity index 98%
rename from Documentation/git-cherry-pick.txt
rename to Documentation/git-cherry-pick.adoc
index 81ace90..42b4192 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.adoc
@@ -172,11 +172,11 @@
 	Pass the merge strategy-specific option through to the
 	merge strategy.  See linkgit:git-merge[1] for details.
 
-include::rerere-options.txt[]
+include::rerere-options.adoc[]
 
 SEQUENCER SUBCOMMANDS
 ---------------------
-include::sequencer.txt[]
+include::sequencer.adoc[]
 
 EXAMPLES
 --------
diff --git a/Documentation/git-cherry.txt b/Documentation/git-cherry.adoc
similarity index 100%
rename from Documentation/git-cherry.txt
rename to Documentation/git-cherry.adoc
diff --git a/Documentation/git-citool.txt b/Documentation/git-citool.adoc
similarity index 100%
rename from Documentation/git-citool.txt
rename to Documentation/git-citool.adoc
diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.adoc
similarity index 97%
rename from Documentation/git-clean.txt
rename to Documentation/git-clean.adoc
index fd17165..bed52c2 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.adoc
@@ -140,9 +140,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/clean.txt[]
+include::config/clean.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.adoc
similarity index 92%
rename from Documentation/git-clone.txt
rename to Documentation/git-clone.adoc
index de8d8f5..222d558 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.adoc
@@ -13,7 +13,7 @@
 	  [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
 	  [-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
 	  [--dissociate] [--separate-git-dir <git-dir>]
-	  [--depth <depth>] [--[no-]single-branch] [--no-tags]
+	  [--depth <depth>] [--[no-]single-branch] [--[no-]tags]
 	  [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
 	  [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow]
 	  [--filter=<filter-spec>] [--also-filter-submodules]] [--] <repository>
@@ -221,6 +221,15 @@
 	`--branch` can also take tags and detaches the `HEAD` at that commit
 	in the resulting repository.
 
+`--revision=<rev>`::
+	Create a new repository, and fetch the history leading to the given
+	revision _<rev>_ (and nothing else), without making any remote-tracking
+	branch, and without making any local branch, and detach `HEAD` to
+	_<rev>_. The argument can be a ref name (e.g. `refs/heads/main` or
+	`refs/tags/v1.0`) that peels down to a commit, or a hexadecimal object
+	name.
+	This option is incompatible with `--branch` and `--mirror`.
+
 `-u` _<upload-pack>_::
 `--upload-pack` _<upload-pack>_::
 	When given, and the repository to clone from is accessed
@@ -273,12 +282,15 @@
 	branch when `--single-branch` clone was made, no remote-tracking
 	branch is created.
 
-`--no-tags`::
-	Don't clone any tags, and set
-	`remote.<remote>.tagOpt=--no-tags` in the config, ensuring
-	that future `git pull` and `git fetch` operations won't follow
-	any tags. Subsequent explicit tag fetches will still work,
-	(see linkgit:git-fetch[1]).
+`--[no-]tags`::
+	Control whether or not tags will be cloned. When `--no-tags` is
+	given, the option will be become permanent by setting the
+	`remote.<remote>.tagOpt=--no-tags` configuration. This ensures that
+	future `git pull` and `git fetch` won't follow any tags. Subsequent
+	explicit tag fetches will still work (see linkgit:git-fetch[1]).
++
+By default, tags are cloned and passing `--tags` is thus typically a
+no-op, unless it cancels out a previous `--no-tags`.
 +
 Can be used in conjunction with `--single-branch` to clone and
 maintain a branch with no references other than a single cloned
@@ -321,7 +333,7 @@
 
 Specify the given ref storage format for the repository. The valid values are:
 +
-include::ref-storage-format.txt[]
+include::ref-storage-format.adoc[]
 
 `-j` _<n>_::
 `--jobs` _<n>_::
@@ -348,7 +360,7 @@
 	`--shallow-since`, and `--shallow-exclude`.
 
 :git-clone: 1
-include::urls.txt[]
+include::urls.adoc[]
 
 EXAMPLES
 --------
@@ -396,11 +408,11 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/init.txt[]
+include::config/init.adoc[]
 
-include::config/clone.txt[]
+include::config/clone.adoc[]
 
 
 GIT
diff --git a/Documentation/git-column.txt b/Documentation/git-column.adoc
similarity index 95%
rename from Documentation/git-column.txt
rename to Documentation/git-column.adoc
index 1843164..85fb87c 100644
--- a/Documentation/git-column.txt
+++ b/Documentation/git-column.adoc
@@ -77,9 +77,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/column.txt[]
+include::config/column.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.adoc
similarity index 98%
rename from Documentation/git-commit-graph.txt
rename to Documentation/git-commit-graph.adoc
index 903b168..50b5016 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.adoc
@@ -148,9 +148,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/commitgraph.txt[]
+include::config/commitgraph.adoc[]
 
 
 FILE FORMAT
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.adoc
similarity index 97%
rename from Documentation/git-commit-tree.txt
rename to Documentation/git-commit-tree.adoc
index 2e2c581..6472921 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.adoc
@@ -80,12 +80,12 @@
 entry is not provided via "<" redirection, 'git commit-tree' will just wait
 for one to be entered and terminated with ^D.
 
-include::date-formats.txt[]
+include::date-formats.adoc[]
 
 Discussion
 ----------
 
-include::i18n.txt[]
+include::i18n.adoc[]
 
 FILES
 -----
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.adoc
similarity index 73%
rename from Documentation/git-commit.txt
rename to Documentation/git-commit.adoc
index c822113..dc21902 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.adoc
@@ -7,8 +7,8 @@
 
 SYNOPSIS
 --------
-[verse]
-'git commit' [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
+[synopsis]
+git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]
 	   [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>]
 	   [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
 	   [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
@@ -23,31 +23,31 @@
 the given log message describing the changes. The new commit is a
 direct child of HEAD, usually the tip of the current branch, and the
 branch is updated to point to it (unless no branch is associated with
-the working tree, in which case HEAD is "detached" as described in
+the working tree, in which case `HEAD` is "detached" as described in
 linkgit:git-checkout[1]).
 
 The content to be committed can be specified in several ways:
 
 1. by using linkgit:git-add[1] to incrementally "add" changes to the
-   index before using the 'commit' command (Note: even modified files
+   index before using the `commit` command (Note: even modified files
    must be "added");
 
 2. by using linkgit:git-rm[1] to remove files from the working tree
-   and the index, again before using the 'commit' command;
+   and the index, again before using the `commit` command;
 
-3. by listing files as arguments to the 'commit' command
-   (without --interactive or --patch switch), in which
+3. by listing files as arguments to the `commit` command
+   (without `--interactive` or `--patch` switch), in which
    case the commit will ignore changes staged in the index, and instead
    record the current content of the listed files (which must already
    be known to Git);
 
-4. by using the -a switch with the 'commit' command to automatically
+4. by using the `-a` switch with the `commit` command to automatically
    "add" changes from all known files (i.e. all files that are already
    listed in the index) and to automatically "rm" files in the index
    that have been removed from the working tree, and then perform the
    actual commit;
 
-5. by using the --interactive or --patch switches with the 'commit' command
+5. by using the `--interactive` or `--patch` switches with the `commit` command
    to decide one by one which files or hunks should be part of the commit
    in addition to contents in the index,
    before finalizing the operation. See the ``Interactive Mode'' section of
@@ -58,139 +58,139 @@
 commit by giving the same set of parameters (options and paths).
 
 If you make a commit and then find a mistake immediately after
-that, you can recover from it with 'git reset'.
+that, you can recover from it with `git reset`.
 
 :git-commit: 1
 
 OPTIONS
 -------
--a::
---all::
-	Tell the command to automatically stage files that have
+`-a`::
+`--all`::
+	Automatically stage files that have
 	been modified and deleted, but new files you have not
 	told Git about are not affected.
 
--p::
---patch::
+`-p`::
+`--patch`::
 	Use the interactive patch selection interface to choose
 	which changes to commit. See linkgit:git-add[1] for
 	details.
 
--C <commit>::
---reuse-message=<commit>::
-	Take an existing commit object, and reuse the log message
+`-C <commit>`::
+`--reuse-message=<commit>`::
+	Take an existing _<commit>_ object, and reuse the log message
 	and the authorship information (including the timestamp)
 	when creating the commit.
 
--c <commit>::
---reedit-message=<commit>::
-	Like '-C', but with `-c` the editor is invoked, so that
+`-c <commit>`::
+`--reedit-message=<commit>`::
+	Like `-C`, but with `-c` the editor is invoked, so that
 	the user can further edit the commit message.
 
---fixup=[(amend|reword):]<commit>::
-	Create a new commit which "fixes up" `<commit>` when applied with
+`--fixup=[(amend|reword):]<commit>`::
+	Create a new commit which "fixes up" _<commit>_ when applied with
 	`git rebase --autosquash`. Plain `--fixup=<commit>` creates a
-	"fixup!" commit which changes the content of `<commit>` but leaves
+	"fixup!" commit which changes the content of _<commit>_ but leaves
 	its log message untouched. `--fixup=amend:<commit>` is similar but
 	creates an "amend!" commit which also replaces the log message of
-	`<commit>` with the log message of the "amend!" commit.
+	_<commit>_ with the log message of the "amend!" commit.
 	`--fixup=reword:<commit>` creates an "amend!" commit which
-	replaces the log message of `<commit>` with its own log message
-	but makes no changes to the content of `<commit>`.
+	replaces the log message of _<commit>_ with its own log message
+	but makes no changes to the content of _<commit>_.
 +
-The commit created by plain `--fixup=<commit>` has a subject
-composed of "fixup!" followed by the subject line from <commit>,
+The commit created by plain `--fixup=<commit>` has a title
+composed of "fixup!" followed by the title of _<commit>_,
 and is recognized specially by `git rebase --autosquash`. The `-m`
 option may be used to supplement the log message of the created
 commit, but the additional commentary will be thrown away once the
-"fixup!" commit is squashed into `<commit>` by
+"fixup!" commit is squashed into _<commit>_ by
 `git rebase --autosquash`.
 +
 The commit created by `--fixup=amend:<commit>` is similar but its
-subject is instead prefixed with "amend!". The log message of
-<commit> is copied into the log message of the "amend!" commit and
+title is instead prefixed with "amend!". The log message of
+_<commit>_ is copied into the log message of the "amend!" commit and
 opened in an editor so it can be refined. When `git rebase
---autosquash` squashes the "amend!" commit into `<commit>`, the
-log message of `<commit>` is replaced by the refined log message
+--autosquash` squashes the "amend!" commit into _<commit>_, the
+log message of _<commit>_ is replaced by the refined log message
 from the "amend!" commit. It is an error for the "amend!" commit's
 log message to be empty unless `--allow-empty-message` is
 specified.
 +
 `--fixup=reword:<commit>` is shorthand for `--fixup=amend:<commit>
---only`. It creates an "amend!" commit with only a log message
+ --only`. It creates an "amend!" commit with only a log message
 (ignoring any changes staged in the index). When squashed by `git
-rebase --autosquash`, it replaces the log message of `<commit>`
+rebase --autosquash`, it replaces the log message of _<commit>_
 without making any other changes.
 +
 Neither "fixup!" nor "amend!" commits change authorship of
-`<commit>` when applied by `git rebase --autosquash`.
+_<commit>_ when applied by `git rebase --autosquash`.
 See linkgit:git-rebase[1] for details.
 
---squash=<commit>::
-	Construct a commit message for use with `rebase --autosquash`.
-	The commit message subject line is taken from the specified
+`--squash=<commit>`::
+	Construct a commit message for use with `git rebase --autosquash`.
+	The commit message title is taken from the specified
 	commit with a prefix of "squash! ".  Can be used with additional
 	commit message options (`-m`/`-c`/`-C`/`-F`). See
 	linkgit:git-rebase[1] for details.
 
---reset-author::
-	When used with -C/-c/--amend options, or when committing after a
+`--reset-author`::
+	When used with `-C`/`-c`/`--amend` options, or when committing after a
 	conflicting cherry-pick, declare that the authorship of the
 	resulting commit now belongs to the committer. This also renews
 	the author timestamp.
 
---short::
+`--short`::
 	When doing a dry-run, give the output in the short-format. See
 	linkgit:git-status[1] for details. Implies `--dry-run`.
 
---branch::
+`--branch`::
 	Show the branch and tracking info even in short-format.
 
---porcelain::
+`--porcelain`::
 	When doing a dry-run, give the output in a porcelain-ready
 	format. See linkgit:git-status[1] for details. Implies
 	`--dry-run`.
 
---long::
+`--long`::
 	When doing a dry-run, give the output in the long-format.
 	Implies `--dry-run`.
 
--z::
---null::
+`-z`::
+`--null`::
 	When showing `short` or `porcelain` status output, print the
-	filename verbatim and terminate the entries with NUL, instead of LF.
+	filename verbatim and terminate the entries with _NUL_, instead of _LF_.
 	If no format is given, implies the `--porcelain` output format.
 	Without the `-z` option, filenames with "unusual" characters are
 	quoted as explained for the configuration variable `core.quotePath`
 	(see linkgit:git-config[1]).
 
--F <file>::
---file=<file>::
-	Take the commit message from the given file.  Use '-' to
+`-F <file>`::
+`--file=<file>`::
+	Take the commit message from _<file>_.  Use '-' to
 	read the message from the standard input.
 
---author=<author>::
+`--author=<author>`::
 	Override the commit author. Specify an explicit author using the
-	standard `A U Thor <author@example.com>` format. Otherwise <author>
+	standard `A U Thor <author@example.com>` format. Otherwise _<author>_
 	is assumed to be a pattern and is used to search for an existing
-	commit by that author (i.e. rev-list --all -i --author=<author>);
+	commit by that author (i.e. `git rev-list --all -i --author=<author>`);
 	the commit author is then copied from the first such commit found.
 
---date=<date>::
+`--date=<date>`::
 	Override the author date used in the commit.
 
--m <msg>::
---message=<msg>::
-	Use the given <msg> as the commit message.
+`-m <msg>`::
+`--message=<msg>`::
+	Use _<msg>_ as the commit message.
 	If multiple `-m` options are given, their values are
 	concatenated as separate paragraphs.
 +
 The `-m` option is mutually exclusive with `-c`, `-C`, and `-F`.
 
--t <file>::
---template=<file>::
+`-t <file>`::
+`--template=<file>`::
 	When editing the commit message, start the editor with the
-	contents in the given file.  The `commit.template` configuration
+	contents in _<file>_.  The `commit.template` configuration
 	variable is often used to give this option implicitly to the
 	command.  This mechanism can be used by projects that want to
 	guide participants with some hints on what to write in the message
@@ -198,58 +198,56 @@
 	message, the commit is aborted.  This has no effect when a message
 	is given by other means, e.g. with the `-m` or `-F` options.
 
-include::signoff-option.txt[]
+include::signoff-option.adoc[]
 
---trailer <token>[(=|:)<value>]::
-	Specify a (<token>, <value>) pair that should be applied as a
+`--trailer <token>[(=|:)<value>]`::
+	Specify a (_<token>_, _<value>_) pair that should be applied as a
 	trailer. (e.g. `git commit --trailer "Signed-off-by:C O Mitter \
 	<committer@example.com>" --trailer "Helped-by:C O Mitter \
-	<committer@example.com>"` will add the "Signed-off-by" trailer
-	and the "Helped-by" trailer to the commit message.)
+	<committer@example.com>"` will add the `Signed-off-by` trailer
+	and the `Helped-by` trailer to the commit message.)
 	The `trailer.*` configuration variables
 	(linkgit:git-interpret-trailers[1]) can be used to define if
 	a duplicated trailer is omitted, where in the run of trailers
 	each trailer would appear, and other details.
 
--n::
---[no-]verify::
-	By default, the pre-commit and commit-msg hooks are run.
-	When any of `--no-verify` or `-n` is given, these are bypassed.
+`-n`::
+`--[no-]verify`::
+	Bypass the `pre-commit` and `commit-msg` hooks.
 	See also linkgit:githooks[5].
 
---allow-empty::
+`--allow-empty`::
 	Usually recording a commit that has the exact same tree as its
 	sole parent commit is a mistake, and the command prevents you
 	from making such a commit.  This option bypasses the safety, and
 	is primarily for use by foreign SCM interface scripts.
 
---allow-empty-message::
-       Like --allow-empty this command is primarily for use by foreign
-       SCM interface scripts. It allows you to create a commit with an
-       empty commit message without using plumbing commands like
-       linkgit:git-commit-tree[1].
+`--allow-empty-message`::
+	Create a commit with an empty commit message without using plumbing
+	commands like linkgit:git-commit-tree[1]. Like `--allow-empty`, this
+	command is primarily for use by foreign SCM interface scripts.
 
---cleanup=<mode>::
-	This option determines how the supplied commit message should be
+`--cleanup=<mode>`::
+	Determine how the supplied commit message should be
 	cleaned up before committing.  The '<mode>' can be `strip`,
 	`whitespace`, `verbatim`, `scissors` or `default`.
 +
 --
-strip::
+`strip`::
 	Strip leading and trailing empty lines, trailing whitespace,
 	commentary and collapse consecutive empty lines.
-whitespace::
+`whitespace`::
 	Same as `strip` except #commentary is not removed.
-verbatim::
+`verbatim`::
 	Do not change the message at all.
-scissors::
+`scissors`::
 	Same as `whitespace` except that everything from (and including)
 	the line found below is truncated, if the message is to be edited.
-	"`#`" can be customized with core.commentChar.
+	"`#`" can be customized with `core.commentChar`.
 
 		# ------------------------ >8 ------------------------
 
-default::
+`default`::
 	Same as `strip` if the message is to be edited.
 	Otherwise `whitespace`.
 --
@@ -257,19 +255,18 @@
 The default can be changed by the `commit.cleanup` configuration
 variable (see linkgit:git-config[1]).
 
--e::
---edit::
-	The message taken from file with `-F`, command line with
-	`-m`, and from commit object with `-C` are usually used as
-	the commit log message unmodified. This option lets you
-	further edit the message taken from these sources.
+`-e`::
+`--edit`::
+	Let the user further edit the message taken from _<file>_
+	with `-F <file>`, command line with `-m <message>`, and
+	from _<commit>_ with `-C <commit>`.
 
---no-edit::
+`--no-edit`::
 	Use the selected commit message without launching an editor.
 	For example, `git commit --amend --no-edit` amends a commit
 	without changing its commit message.
 
---amend::
+`--amend`::
 	Replace the tip of the current branch by creating a new
 	commit. The recorded tree is prepared as usual (including
 	the effect of the `-i` and `-o` options and explicit
@@ -295,23 +292,23 @@
 amend a commit that has already been published.  (See the "RECOVERING
 FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].)
 
---no-post-rewrite::
-	Bypass the post-rewrite hook.
+`--no-post-rewrite`::
+	Bypass the `post-rewrite` hook.
 
--i::
---include::
+`-i`::
+`--include`::
 	Before making a commit out of staged contents so far,
 	stage the contents of paths given on the command line
 	as well.  This is usually not what you want unless you
 	are concluding a conflicted merge.
 
--o::
---only::
+`-o`::
+`--only`::
 	Make a commit by taking the updated working tree contents
 	of the paths specified on the
 	command line, disregarding any contents that have been
 	staged for other paths. This is the default mode of operation of
-	'git commit' if any paths are given on the command line,
+	`git commit` if any paths are given on the command line,
 	in which case this option can be omitted.
 	If this option is specified together with `--amend`, then
 	no paths need to be specified, which can be used to amend
@@ -319,48 +316,48 @@
 	already been staged. If used together with `--allow-empty`
 	paths are also not required, and an empty commit will be created.
 
---pathspec-from-file=<file>::
-	Pathspec is passed in `<file>` instead of commandline args. If
-	`<file>` is exactly `-` then standard input is used. Pathspec
-	elements are separated by LF or CR/LF. Pathspec elements can be
+`--pathspec-from-file=<file>`::
+	Pass pathspec in _<file>_ instead of commandline args. If
+	_<file>_ is exactly `-` then standard input is used. Pathspec
+	elements are separated by _LF_ or _CR_/_LF_. Pathspec elements can be
 	quoted as explained for the configuration variable `core.quotePath`
 	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
 	global `--literal-pathspecs`.
 
---pathspec-file-nul::
+`--pathspec-file-nul`::
 	Only meaningful with `--pathspec-from-file`. Pathspec elements are
-	separated with NUL character and all other characters are taken
+	separated with _NUL_ character and all other characters are taken
 	literally (including newlines and quotes).
 
--u[<mode>]::
---untracked-files[=<mode>]::
+`-u[<mode>]`::
+`--untracked-files[=<mode>]`::
 	Show untracked files.
 +
 --
-The mode parameter is optional (defaults to 'all'), and is used to
-specify the handling of untracked files; when -u is not used, the
-default is 'normal', i.e. show untracked files and directories.
+The _<mode>_ parameter is optional (defaults to `all`), and is used to
+specify the handling of untracked files; when `-u` is not used, the
+default is `normal`, i.e. show untracked files and directories.
 
 The possible options are:
 
-	- 'no'     - Show no untracked files
-	- 'normal' - Shows untracked files and directories
-	- 'all'    - Also shows individual files in untracked directories.
+`no`:: Show no untracked files
+`normal`:: Shows untracked files and directories
+`all`:: Also shows individual files in untracked directories.
 
 All usual spellings for Boolean value `true` are taken as `normal`
 and `false` as `no`.
-The default can be changed using the status.showUntrackedFiles
+The default can be changed using the `status.showUntrackedFiles`
 configuration variable documented in linkgit:git-config[1].
 --
 
--v::
---verbose::
-	Show unified diff between the HEAD commit and what
+`-v`::
+`--verbose`::
+	Show unified diff between the `HEAD` commit and what
 	would be committed at the bottom of the commit message
 	template to help the user describe the commit by reminding
 	what changes the commit has.
 	Note that this diff output doesn't have its
-	lines prefixed with '#'. This diff will not be a part
+	lines prefixed with `#`. This diff will not be a part
 	of the commit message. See the `commit.verbose` configuration
 	variable in linkgit:git-config[1].
 +
@@ -368,40 +365,40 @@
 what would be committed and the worktree files, i.e. the unstaged
 changes to tracked files.
 
--q::
---quiet::
+`-q`::
+`--quiet`::
 	Suppress commit summary message.
 
---dry-run::
+`--dry-run`::
 	Do not create a commit, but show a list of paths that are
 	to be committed, paths with local changes that will be left
 	uncommitted and paths that are untracked.
 
---status::
+`--status`::
 	Include the output of linkgit:git-status[1] in the commit
 	message template when using an editor to prepare the commit
 	message.  Defaults to on, but can be used to override
-	configuration variable commit.status.
+	configuration variable `commit.status`.
 
---no-status::
+`--no-status`::
 	Do not include the output of linkgit:git-status[1] in the
 	commit message template when using an editor to prepare the
 	default commit message.
 
--S[<keyid>]::
---gpg-sign[=<keyid>]::
---no-gpg-sign::
-	GPG-sign commits. The `keyid` argument is optional and
+`-S[<key-id>]`::
+`--gpg-sign[=<key-id>]`::
+`--no-gpg-sign`::
+	GPG-sign commits. The _<key-id>_ is optional and
 	defaults to the committer identity; if specified, it must be
 	stuck to the option without a space. `--no-gpg-sign` is useful to
 	countermand both `commit.gpgSign` configuration variable, and
 	earlier `--gpg-sign`.
 
-\--::
+`--`::
 	Do not interpret any more arguments as options.
 
-<pathspec>...::
-	When pathspec is given on the command line, commit the contents of
+`<pathspec>...`::
+	When _<pathspec>_ is given on the command line, commit the contents of
 	the files that match the pathspec without recording the changes
 	already added to the index. The contents of these files are also
 	staged for the next commit on top of what have been staged before.
@@ -412,10 +409,10 @@
 --------
 When recording your own work, the contents of modified files in
 your working tree are temporarily stored to a staging area
-called the "index" with 'git add'.  A file can be
+called the "index" with `git add`.  A file can be
 reverted back, only in the index but not in the working tree,
 to that of the last commit with `git restore --staged <file>`,
-which effectively reverts 'git add' and prevents the changes to
+which effectively reverts `git add` and prevents the changes to
 this file from participating in the next commit.  After building
 the state to be committed incrementally with these commands,
 `git commit` (without any pathname parameter) is used to record what
@@ -443,7 +440,7 @@
 ------------
 
 The command `git commit -a` first looks at your working tree,
-notices that you have modified hello.c and removed goodbye.c,
+notices that you have modified `hello.c` and removed `goodbye.c`,
 and performs necessary `git add` and `git rm` for you.
 
 After staging changes to many files, you can alter the order the
@@ -471,13 +468,13 @@
 this second commit would record the changes to `hello.c` and
 `hello.h` as expected.
 
-After a merge (initiated by 'git merge' or 'git pull') stops
+After a merge (initiated by `git merge` or `git pull`) stops
 because of conflicts, cleanly merged
 paths are already staged to be committed for you, and paths that
 conflicted are left in unmerged state.  You would have to first
-check which paths are conflicting with 'git status'
+check which paths are conflicting with `git status`
 and after fixing them manually in your working tree, you would
-stage the result as usual with 'git add':
+stage the result as usual with `git add`:
 
 ------------
 $ git status | grep unmerged
@@ -507,12 +504,12 @@
 Author and committer information is taken from the following environment
 variables, if set:
 
-	GIT_AUTHOR_NAME
-	GIT_AUTHOR_EMAIL
-	GIT_AUTHOR_DATE
-	GIT_COMMITTER_NAME
-	GIT_COMMITTER_EMAIL
-	GIT_COMMITTER_DATE
+ * `GIT_AUTHOR_NAME`
+ * `GIT_AUTHOR_EMAIL`
+ * `GIT_AUTHOR_DATE`
+ * `GIT_COMMITTER_NAME`
+ * `GIT_COMMITTER_EMAIL`
+ * `GIT_COMMITTER_DATE`
 
 (nb "<", ">" and "\n"s are stripped)
 
@@ -524,7 +521,7 @@
 
 In case (some of) these environment variables are not set, the information
 is taken from the configuration items `user.name` and `user.email`, or, if not
-present, the environment variable EMAIL, or, if that is not set,
+present, the environment variable `EMAIL`, or, if that is not set,
 system user name and the hostname used for outgoing mail (taken
 from `/etc/mailname` and falling back to the fully qualified hostname when
 that file does not exist).
@@ -537,7 +534,7 @@
 the other options are provided for more complex use cases.
 
 :git-commit: 1
-include::date-formats.txt[]
+include::date-formats.adoc[]
 
 DISCUSSION
 ----------
@@ -550,18 +547,18 @@
 For example, linkgit:git-format-patch[1] turns a commit into email, and it uses
 the title on the Subject line and the rest of the commit in the body.
 
-include::i18n.txt[]
+include::i18n.adoc[]
 
 ENVIRONMENT AND CONFIGURATION VARIABLES
 ---------------------------------------
 The editor used to edit the commit log message will be chosen from the
-`GIT_EDITOR` environment variable, the core.editor configuration variable, the
+`GIT_EDITOR` environment variable, the `core.editor` configuration variable, the
 `VISUAL` environment variable, or the `EDITOR` environment variable (in that
 order).  See linkgit:git-var[1] for details.
 
-include::includes/cmd-config-section-rest.txt[]
+include::includes/cmd-config-section-rest.adoc[]
 
-include::config/commit.txt[]
+include::config/commit.adoc[]
 
 HOOKS
 -----
diff --git a/Documentation/git-config.txt b/Documentation/git-config.adoc
similarity index 98%
rename from Documentation/git-config.txt
rename to Documentation/git-config.adoc
index 3e42017..936e0c5 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.adoc
@@ -213,7 +213,9 @@
 +
 Valid `<type>`'s include:
 +
-- 'bool': canonicalize values as either "true" or "false".
+- 'bool': canonicalize values `true`, `yes`,`on`, and positive
+  numbers as "true", and values `false`, `no`, `off` and `0` as
+  "false".
 - 'int': canonicalize values as simple decimal numbers. An optional suffix of
   'k', 'm', or 'g' will cause the value to be multiplied by 1024, 1048576, or
   1073741824 upon input.
@@ -610,7 +612,7 @@
 http.sslverify false
 ------------
 
-include::config.txt[]
+include::config.adoc[]
 
 BUGS
 ----
diff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.adoc
similarity index 100%
rename from Documentation/git-count-objects.txt
rename to Documentation/git-count-objects.adoc
diff --git a/Documentation/git-credential-cache--daemon.txt b/Documentation/git-credential-cache--daemon.adoc
similarity index 100%
rename from Documentation/git-credential-cache--daemon.txt
rename to Documentation/git-credential-cache--daemon.adoc
diff --git a/Documentation/git-credential-cache.txt b/Documentation/git-credential-cache.adoc
similarity index 77%
rename from Documentation/git-credential-cache.txt
rename to Documentation/git-credential-cache.adoc
index 487cc55..54fa7a2 100644
--- a/Documentation/git-credential-cache.txt
+++ b/Documentation/git-credential-cache.adoc
@@ -78,6 +78,23 @@
 $ git config credential.helper 'cache --timeout=3600'
 -------------------------------------------------------
 
+PERSONAL ACCESS TOKENS
+----------------------
+
+Some remotes accept personal access tokens, which are randomly
+generated and hard to memorise. They typically have a lifetime of weeks
+or months.
+
+git-credential-cache is inherently unsuitable for persistent storage of
+personal access tokens. The credential will be forgotten after the cache
+timeout. Even if you configure a long timeout, credentials will be
+forgotten if the daemon dies.
+
+To avoid frequently regenerating personal access tokens, configure a
+credential helper with persistent storage. Alternatively, configure an
+OAuth credential helper to generate credentials automatically. See
+linkgit:gitcredentials[7], sections "Available helpers" and "OAuth".
+
 GIT
 ---
 Part of the linkgit:git[1] suite
diff --git a/Documentation/git-credential-store.txt b/Documentation/git-credential-store.adoc
similarity index 100%
rename from Documentation/git-credential-store.txt
rename to Documentation/git-credential-store.adoc
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.adoc
similarity index 100%
rename from Documentation/git-credential.txt
rename to Documentation/git-credential.adoc
diff --git a/Documentation/git-cvsexportcommit.txt b/Documentation/git-cvsexportcommit.adoc
similarity index 100%
rename from Documentation/git-cvsexportcommit.txt
rename to Documentation/git-cvsexportcommit.adoc
diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.adoc
similarity index 100%
rename from Documentation/git-cvsimport.txt
rename to Documentation/git-cvsimport.adoc
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.adoc
similarity index 100%
rename from Documentation/git-cvsserver.txt
rename to Documentation/git-cvsserver.adoc
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.adoc
similarity index 100%
rename from Documentation/git-daemon.txt
rename to Documentation/git-daemon.adoc
diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.adoc
similarity index 100%
rename from Documentation/git-describe.txt
rename to Documentation/git-describe.adoc
diff --git a/Documentation/git-diagnose.txt b/Documentation/git-diagnose.adoc
similarity index 100%
rename from Documentation/git-diagnose.txt
rename to Documentation/git-diagnose.adoc
diff --git a/Documentation/git-diff-files.txt b/Documentation/git-diff-files.adoc
similarity index 94%
rename from Documentation/git-diff-files.txt
rename to Documentation/git-diff-files.adoc
index bf78e31..2b2358c 100644
--- a/Documentation/git-diff-files.txt
+++ b/Documentation/git-diff-files.adoc
@@ -20,7 +20,7 @@
 
 OPTIONS
 -------
-include::diff-options.txt[]
+include::diff-options.adoc[]
 
 -1 --base::
 -2 --ours::
@@ -45,7 +45,7 @@
 	Remain silent even for nonexistent files
 
 
-include::diff-format.txt[]
+include::diff-format.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-diff-index.txt b/Documentation/git-diff-index.adoc
similarity index 98%
rename from Documentation/git-diff-index.txt
rename to Documentation/git-diff-index.adoc
index 4de1d4c..911446a 100644
--- a/Documentation/git-diff-index.txt
+++ b/Documentation/git-diff-index.adoc
@@ -21,7 +21,7 @@
 
 OPTIONS
 -------
-include::diff-options.txt[]
+include::diff-options.adoc[]
 
 <tree-ish>::
 	The id of a tree object to diff against.
@@ -40,7 +40,7 @@
 	'git diff-index' say that all non-checked-out files are up
 	to date.
 
-include::diff-format.txt[]
+include::diff-format.adoc[]
 
 OPERATING MODES
 ---------------
diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.adoc
similarity index 96%
rename from Documentation/git-diff-tree.txt
rename to Documentation/git-diff-tree.adoc
index 09286a8..f1e3134 100644
--- a/Documentation/git-diff-tree.txt
+++ b/Documentation/git-diff-tree.adoc
@@ -24,7 +24,7 @@
 
 OPTIONS
 -------
-include::diff-options.txt[]
+include::diff-options.adoc[]
 
 <tree-ish>::
 	The id of a tree object.
@@ -84,7 +84,7 @@
 	This flag causes 'git diff-tree --stdin' to also show
 	the commit message before the differences.
 
-include::pretty-options.txt[]
+include::pretty-options.adoc[]
 
 --no-commit-id::
 	'git diff-tree' outputs a line with the commit ID when
@@ -122,9 +122,9 @@
 	if the diff itself is empty.
 
 
-include::pretty-formats.txt[]
+include::pretty-formats.adoc[]
 
-include::diff-format.txt[]
+include::diff-format.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.adoc
similarity index 97%
rename from Documentation/git-diff.txt
rename to Documentation/git-diff.adoc
index e19f31e..dec173a 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.adoc
@@ -123,7 +123,7 @@
 OPTIONS
 -------
 :git-diff: 1
-include::diff-options.txt[]
+include::diff-options.adoc[]
 
 `-1`::
 `--base`::
@@ -154,7 +154,7 @@
 	names and get diff for all files under them).
 
 
-include::diff-format.txt[]
+include::diff-format.adoc[]
 
 EXAMPLES
 --------
@@ -232,10 +232,10 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
 :git-diff: 1
-include::config/diff.txt[]
+include::config/diff.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.adoc
similarity index 97%
rename from Documentation/git-difftool.txt
rename to Documentation/git-difftool.adoc
index a616f8b..d596205 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.adoc
@@ -119,9 +119,9 @@
 'git difftool' falls back to 'git mergetool' config variables when the
 difftool equivalents have not been defined.
 
-include::includes/cmd-config-section-rest.txt[]
+include::includes/cmd-config-section-rest.adoc[]
 
-include::config/difftool.txt[]
+include::config/difftool.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.adoc
similarity index 100%
rename from Documentation/git-fast-export.txt
rename to Documentation/git-fast-export.adoc
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.adoc
similarity index 99%
rename from Documentation/git-fast-import.txt
rename to Documentation/git-fast-import.adoc
index 3d43515..58a2eaa 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.adoc
@@ -1578,9 +1578,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/fastimport.txt[]
+include::config/fastimport.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.adoc
similarity index 100%
rename from Documentation/git-fetch-pack.txt
rename to Documentation/git-fetch-pack.adoc
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.adoc
similarity index 97%
rename from Documentation/git-fetch.txt
rename to Documentation/git-fetch.adoc
index 50900a5..16f5d9d 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.adoc
@@ -44,15 +44,15 @@
 
 OPTIONS
 -------
-include::fetch-options.txt[]
+include::fetch-options.adoc[]
 
-include::pull-fetch-param.txt[]
+include::pull-fetch-param.adoc[]
 
 --stdin::
 	Read refspecs, one per line, from stdin in addition to those provided
 	as arguments. The "tag <name>" format is not supported.
 
-include::urls-remotes.txt[]
+include::urls-remotes.adoc[]
 
 
 CONFIGURED REMOTE-TRACKING BRANCHES[[CRTB]]
@@ -292,14 +292,14 @@
 objects will eventually be removed by git's built-in housekeeping (see
 linkgit:git-gc[1]).
 
-include::transfer-data-leaks.txt[]
+include::transfer-data-leaks.adoc[]
 
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/fetch.txt[]
+include::config/fetch.adoc[]
 
 BUGS
 ----
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.adoc
similarity index 100%
rename from Documentation/git-filter-branch.txt
rename to Documentation/git-filter-branch.adoc
diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.adoc
similarity index 97%
rename from Documentation/git-fmt-merge-msg.txt
rename to Documentation/git-fmt-merge-msg.adoc
index 6f28812..0f33289 100644
--- a/Documentation/git-fmt-merge-msg.txt
+++ b/Documentation/git-fmt-merge-msg.adoc
@@ -55,7 +55,7 @@
 
 CONFIGURATION
 -------------
-include::config/fmt-merge-msg.txt[]
+include::config/fmt-merge-msg.adoc[]
 
 merge.summary::
 	Synonym to `merge.log`; this is deprecated and will be removed in
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.adoc
similarity index 99%
rename from Documentation/git-for-each-ref.txt
rename to Documentation/git-for-each-ref.adoc
index d376440..ffb97e6 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.adoc
@@ -538,7 +538,7 @@
 NOTES
 -----
 
-include::ref-reachability-filters.txt[]
+include::ref-reachability-filters.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-for-each-repo.txt b/Documentation/git-for-each-repo.adoc
similarity index 100%
rename from Documentation/git-for-each-repo.txt
rename to Documentation/git-for-each-repo.adoc
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.adoc
similarity index 99%
rename from Documentation/git-format-patch.txt
rename to Documentation/git-format-patch.adoc
index 5dc7bb4..a8b53db 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.adoc
@@ -105,7 +105,7 @@
 OPTIONS
 -------
 :git-format-patch: 1
-include::diff-options.txt[]
+include::diff-options.adoc[]
 
 -<n>::
 	Prepare patches from the topmost <n> commits.
diff --git a/Documentation/git-fsck-objects.txt b/Documentation/git-fsck-objects.adoc
similarity index 100%
rename from Documentation/git-fsck-objects.txt
rename to Documentation/git-fsck-objects.adoc
diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.adoc
similarity index 97%
rename from Documentation/git-fsck.txt
rename to Documentation/git-fsck.adoc
index 5b82e46..8f32800 100644
--- a/Documentation/git-fsck.txt
+++ b/Documentation/git-fsck.adoc
@@ -107,9 +107,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/fsck.txt[]
+include::config/fsck.adoc[]
 
 DISCUSSION
 ----------
@@ -161,7 +161,7 @@
 error, other than those that are marked as "(FATAL)", can be tweaked
 by setting the corresponding `fsck.<msg-id>` configuration variable.
 
-include::fsck-msgids.txt[]
+include::fsck-msgids.adoc[]
 
 
 Environment Variables
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.adoc
similarity index 97%
rename from Documentation/git-fsmonitor--daemon.txt
rename to Documentation/git-fsmonitor--daemon.adoc
index 8585d19..8fe5241 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.adoc
@@ -97,9 +97,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/fsmonitor--daemon.txt[]
+include::config/fsmonitor--daemon.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.adoc
similarity index 93%
rename from Documentation/git-gc.txt
rename to Documentation/git-gc.adoc
index 370e22f..526ce01 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.adoc
@@ -69,6 +69,13 @@
 	the `--max-cruft-size` option of linkgit:git-repack[1] for
 	more.
 
+--expire-to=<dir>::
+	When packing unreachable objects into a cruft pack, write a cruft
+	pack containing pruned objects (if any) to the directory `<dir>`.
+	This option only has an effect when used together with `--cruft`.
+	See the `--expire-to` option of linkgit:git-repack[1] for
+	more information.
+
 --prune=<date>::
 	Prune loose objects older than date (default is 2 weeks ago,
 	overridable by the config variable `gc.pruneExpire`).
@@ -122,9 +129,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/gc.txt[]
+include::config/gc.adoc[]
 
 NOTES
 -----
diff --git a/Documentation/git-get-tar-commit-id.txt b/Documentation/git-get-tar-commit-id.adoc
similarity index 100%
rename from Documentation/git-get-tar-commit-id.txt
rename to Documentation/git-get-tar-commit-id.adoc
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.adoc
similarity index 98%
rename from Documentation/git-grep.txt
rename to Documentation/git-grep.adoc
index 1e6d7b6..a548585 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.adoc
@@ -351,9 +351,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/grep.txt[]
+include::config/grep.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-gui.txt b/Documentation/git-gui.adoc
similarity index 100%
rename from Documentation/git-gui.txt
rename to Documentation/git-gui.adoc
diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.adoc
similarity index 100%
rename from Documentation/git-hash-object.txt
rename to Documentation/git-hash-object.adoc
diff --git a/Documentation/git-help.txt b/Documentation/git-help.adoc
similarity index 100%
rename from Documentation/git-help.txt
rename to Documentation/git-help.adoc
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.adoc
similarity index 100%
rename from Documentation/git-hook.txt
rename to Documentation/git-hook.adoc
diff --git a/Documentation/git-http-backend.txt b/Documentation/git-http-backend.adoc
similarity index 98%
rename from Documentation/git-http-backend.txt
rename to Documentation/git-http-backend.adoc
index f37ddad..1dea426 100644
--- a/Documentation/git-http-backend.txt
+++ b/Documentation/git-http-backend.adoc
@@ -56,6 +56,10 @@
 	disabled by setting this item to `false`, or enabled for all
 	users, including anonymous users, by setting it to `true`.
 
+http.uploadarchive::
+	This serves 'git archive' clients for remote archive over HTTP/HTTPS
+	protocols. It is disabled by default. It only works in protocol v2.
+
 URL TRANSLATION
 ---------------
 To determine the location of the repository on disk, 'git http-backend'
diff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.adoc
similarity index 100%
rename from Documentation/git-http-fetch.txt
rename to Documentation/git-http-fetch.adoc
diff --git a/Documentation/git-http-push.txt b/Documentation/git-http-push.adoc
similarity index 100%
rename from Documentation/git-http-push.txt
rename to Documentation/git-http-push.adoc
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.adoc
similarity index 97%
rename from Documentation/git-imap-send.txt
rename to Documentation/git-imap-send.adoc
index c8a89d7..26ccf4e 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.adoc
@@ -54,9 +54,9 @@
 To use the tool, `imap.folder` and either `imap.tunnel` or `imap.host` must be set
 to appropriate values.
 
-include::includes/cmd-config-section-rest.txt[]
+include::includes/cmd-config-section-rest.adoc[]
 
-include::config/imap.txt[]
+include::config/imap.adoc[]
 
 EXAMPLES
 --------
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.adoc
similarity index 98%
rename from Documentation/git-index-pack.txt
rename to Documentation/git-index-pack.adoc
index 58dd5b5..270056c 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.adoc
@@ -130,7 +130,7 @@
 +
 This option cannot be used with --stdin.
 +
-include::object-format-disclaimer.txt[]
+include::object-format-disclaimer.adoc[]
 
 --promisor[=<message>]::
 	Before committing the pack-index, create a .promisor file for this
diff --git a/Documentation/git-init-db.txt b/Documentation/git-init-db.adoc
similarity index 100%
rename from Documentation/git-init-db.txt
rename to Documentation/git-init-db.adoc
diff --git a/Documentation/git-init.txt b/Documentation/git-init.adoc
similarity index 97%
rename from Documentation/git-init.txt
rename to Documentation/git-init.adoc
index 315f7f7..a0dffba 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.adoc
@@ -55,12 +55,12 @@
 Specify the given object _<format>_ (hash algorithm) for the repository.  The valid
 values are `sha1` and (if enabled) `sha256`.  `sha1` is the default.
 +
-include::object-format-disclaimer.txt[]
+include::object-format-disclaimer.adoc[]
 
 `--ref-format=<format>`::
 Specify the given ref storage _<format>_ for the repository. The valid values are:
 +
-include::ref-storage-format.txt[]
+include::ref-storage-format.adoc[]
 
 `--template=<template-directory>`::
 Specify the directory from which templates will be used.  (See the "TEMPLATE
@@ -178,11 +178,11 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
 :git-init:
 
-include::config/init.txt[]
+include::config/init.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.adoc
similarity index 100%
rename from Documentation/git-instaweb.txt
rename to Documentation/git-instaweb.adoc
diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.adoc
similarity index 68%
rename from Documentation/git-interpret-trailers.txt
rename to Documentation/git-interpret-trailers.adoc
index d9dfb75..82c8780 100644
--- a/Documentation/git-interpret-trailers.txt
+++ b/Documentation/git-interpret-trailers.adoc
@@ -186,142 +186,9 @@
 CONFIGURATION VARIABLES
 -----------------------
 
-trailer.separators::
-	This option tells which characters are recognized as trailer
-	separators. By default only ':' is recognized as a trailer
-	separator, except that '=' is always accepted on the command
-	line for compatibility with other git commands.
-+
-The first character given by this option will be the default character
-used when another separator is not specified in the config for this
-trailer.
-+
-For example, if the value for this option is "%=$", then only lines
-using the format '<key><sep><value>' with <sep> containing '%', '='
-or '$' and then spaces will be considered trailers. And '%' will be
-the default separator used, so by default trailers will appear like:
-'<key>% <value>' (one percent sign and one space will appear between
-the key and the value).
+include::includes/cmd-config-section-all.adoc[]
 
-trailer.where::
-	This option tells where a new trailer will be added.
-+
-This can be `end`, which is the default, `start`, `after` or `before`.
-+
-If it is `end`, then each new trailer will appear at the end of the
-existing trailers.
-+
-If it is `start`, then each new trailer will appear at the start,
-instead of the end, of the existing trailers.
-+
-If it is `after`, then each new trailer will appear just after the
-last trailer with the same <key>.
-+
-If it is `before`, then each new trailer will appear just before the
-first trailer with the same <key>.
-
-trailer.ifexists::
-	This option makes it possible to choose what action will be
-	performed when there is already at least one trailer with the
-	same <key> in the input.
-+
-The valid values for this option are: `addIfDifferentNeighbor` (this
-is the default), `addIfDifferent`, `add`, `replace` or `doNothing`.
-+
-With `addIfDifferentNeighbor`, a new trailer will be added only if no
-trailer with the same (<key>, <value>) pair is above or below the line
-where the new trailer will be added.
-+
-With `addIfDifferent`, a new trailer will be added only if no trailer
-with the same (<key>, <value>) pair is already in the input.
-+
-With `add`, a new trailer will be added, even if some trailers with
-the same (<key>, <value>) pair are already in the input.
-+
-With `replace`, an existing trailer with the same <key> will be
-deleted and the new trailer will be added. The deleted trailer will be
-the closest one (with the same <key>) to the place where the new one
-will be added.
-+
-With `doNothing`, nothing will be done; that is no new trailer will be
-added if there is already one with the same <key> in the input.
-
-trailer.ifmissing::
-	This option makes it possible to choose what action will be
-	performed when there is not yet any trailer with the same
-	<key> in the input.
-+
-The valid values for this option are: `add` (this is the default) and
-`doNothing`.
-+
-With `add`, a new trailer will be added.
-+
-With `doNothing`, nothing will be done.
-
-trailer.<keyAlias>.key::
-	Defines a <keyAlias> for the <key>. The <keyAlias> must be a
-	prefix (case does not matter) of the <key>. For example, in `git
-	config trailer.ack.key "Acked-by"` the "Acked-by" is the <key> and
-	the "ack" is the <keyAlias>. This configuration allows the shorter
-	`--trailer "ack:..."` invocation on the command line using the "ack"
-	<keyAlias> instead of the longer `--trailer "Acked-by:..."`.
-+
-At the end of the <key>, a separator can appear and then some
-space characters. By default the only valid separator is ':',
-but this can be changed using the `trailer.separators` config
-variable.
-+
-If there is a separator in the key, then it overrides the default
-separator when adding the trailer.
-
-trailer.<keyAlias>.where::
-	This option takes the same values as the 'trailer.where'
-	configuration variable and it overrides what is specified by
-	that option for trailers with the specified <keyAlias>.
-
-trailer.<keyAlias>.ifexists::
-	This option takes the same values as the 'trailer.ifexists'
-	configuration variable and it overrides what is specified by
-	that option for trailers with the specified <keyAlias>.
-
-trailer.<keyAlias>.ifmissing::
-	This option takes the same values as the 'trailer.ifmissing'
-	configuration variable and it overrides what is specified by
-	that option for trailers with the specified <keyAlias>.
-
-trailer.<keyAlias>.command::
-	Deprecated in favor of 'trailer.<keyAlias>.cmd'.
-	This option behaves in the same way as 'trailer.<keyAlias>.cmd', except
-	that it doesn't pass anything as argument to the specified command.
-	Instead the first occurrence of substring $ARG is replaced by the
-	<value> that would be passed as argument.
-+
-Note that $ARG in the user's command is
-only replaced once and that the original way of replacing $ARG is not safe.
-+
-When both 'trailer.<keyAlias>.cmd' and 'trailer.<keyAlias>.command' are given
-for the same <keyAlias>, 'trailer.<keyAlias>.cmd' is used and
-'trailer.<keyAlias>.command' is ignored.
-
-trailer.<keyAlias>.cmd::
-	This option can be used to specify a shell command that will be called
-	once to automatically add a trailer with the specified <keyAlias>, and then
-	called each time a '--trailer <keyAlias>=<value>' argument is specified to
-	modify the <value> of the trailer that this option would produce.
-+
-When the specified command is first called to add a trailer
-with the specified <keyAlias>, the behavior is as if a special
-'--trailer <keyAlias>=<value>' argument was added at the beginning
-of the "git interpret-trailers" command, where <value>
-is taken to be the standard output of the command with any
-leading and trailing whitespace trimmed off.
-+
-If some '--trailer <keyAlias>=<value>' arguments are also passed
-on the command line, the command is called again once for each
-of these arguments with the same <keyAlias>. And the <value> part
-of these arguments, if any, will be passed to the command as its
-first argument. This way the command can produce a <value> computed
-from the <value> passed in the '--trailer <keyAlias>=<value>' argument.
+include::config/trailer.adoc[]
 
 EXAMPLES
 --------
diff --git a/Documentation/git-log.txt b/Documentation/git-log.adoc
similarity index 94%
rename from Documentation/git-log.txt
rename to Documentation/git-log.adoc
index 5796821..ae8a7e2 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.adoc
@@ -16,7 +16,7 @@
 Shows the commit logs.
 
 :git-log: 1
-include::rev-list-description.txt[]
+include::rev-list-description.adoc[]
 
 The command takes options applicable to the linkgit:git-rev-list[1]
 command to control what is shown and how, and options applicable to
@@ -89,7 +89,7 @@
 	Intended to speed up tools that read log messages from `git log`
 	output by allowing them to allocate space in advance.
 
-include::line-range-options.txt[]
+include::line-range-options.adoc[]
 
 <revision-range>::
 	Show only commits in the specified revision range.  When no
@@ -109,9 +109,9 @@
 Paths may need to be prefixed with `--` to separate them from
 options or the revision range, when confusion arises.
 
-include::rev-list-options.txt[]
+include::rev-list-options.adoc[]
 
-include::pretty-formats.txt[]
+include::pretty-formats.adoc[]
 
 DIFF FORMATTING
 ---------------
@@ -128,9 +128,9 @@
 
 :git-log: 1
 :diff-merges-default: `off`
-include::diff-options.txt[]
+include::diff-options.adoc[]
 
-include::diff-generate-patch.txt[]
+include::diff-generate-patch.adoc[]
 
 EXAMPLES
 --------
@@ -192,7 +192,7 @@
 DISCUSSION
 ----------
 
-include::i18n.txt[]
+include::i18n.adoc[]
 
 CONFIGURATION
 -------------
@@ -209,11 +209,11 @@
 	Defaults to the value of `i18n.commitEncoding` if set, and UTF-8
 	otherwise.
 
-include::includes/cmd-config-section-rest.txt[]
+include::includes/cmd-config-section-rest.adoc[]
 
-include::config/log.txt[]
+include::config/log.adoc[]
 
-include::config/notes.txt[]
+include::config/notes.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.adoc
similarity index 100%
rename from Documentation/git-ls-files.txt
rename to Documentation/git-ls-files.adoc
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.adoc
similarity index 100%
rename from Documentation/git-ls-remote.txt
rename to Documentation/git-ls-remote.adoc
diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.adoc
similarity index 100%
rename from Documentation/git-ls-tree.txt
rename to Documentation/git-ls-tree.adoc
diff --git a/Documentation/git-mailinfo.txt b/Documentation/git-mailinfo.adoc
similarity index 97%
rename from Documentation/git-mailinfo.txt
rename to Documentation/git-mailinfo.adoc
index 2806028..3b24c9a 100644
--- a/Documentation/git-mailinfo.txt
+++ b/Documentation/git-mailinfo.adoc
@@ -118,9 +118,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/mailinfo.txt[]
+include::config/mailinfo.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.adoc
similarity index 100%
rename from Documentation/git-mailsplit.txt
rename to Documentation/git-mailsplit.adoc
diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.adoc
similarity index 99%
rename from Documentation/git-maintenance.txt
rename to Documentation/git-maintenance.adoc
index 6e66513..0450d74 100644
--- a/Documentation/git-maintenance.txt
+++ b/Documentation/git-maintenance.adoc
@@ -409,9 +409,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/maintenance.txt[]
+include::config/maintenance.adoc[]
 
 
 GIT
diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.adoc
similarity index 100%
rename from Documentation/git-merge-base.txt
rename to Documentation/git-merge-base.adoc
diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.adoc
similarity index 100%
rename from Documentation/git-merge-file.txt
rename to Documentation/git-merge-file.adoc
diff --git a/Documentation/git-merge-index.txt b/Documentation/git-merge-index.adoc
similarity index 100%
rename from Documentation/git-merge-index.txt
rename to Documentation/git-merge-index.adoc
diff --git a/Documentation/git-merge-one-file.txt b/Documentation/git-merge-one-file.adoc
similarity index 100%
rename from Documentation/git-merge-one-file.txt
rename to Documentation/git-merge-one-file.adoc
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.adoc
similarity index 97%
rename from Documentation/git-merge-tree.txt
rename to Documentation/git-merge-tree.adoc
index 0b6a8a1..cf0578f 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.adoc
@@ -40,11 +40,17 @@
 OPTIONS
 -------
 
+--stdin::
+	Read the commits to merge from the standard input rather than
+	the command-line. See <<INPUT,INPUT FORMAT>> below for more
+	information.  Implies `-z`.
+
 -z::
 	Do not quote filenames in the <Conflicted file info> section,
 	and end each filename with a NUL character rather than
 	newline.  Also begin the messages section with a NUL character
-	instead of a newline.  See <<OUTPUT>> below for more information.
+	instead of a newline.  See <<OUTPUT,OUTPUT>> below for more
+	information.
 
 --name-only::
 	In the Conflicted file info section, instead of writing a list
@@ -116,8 +122,6 @@
 
      0: merge had conflicts
      1: merge was clean
-     <0: something prevented the merge from running (e.g. access to repository
-	 objects denied by filesystem)
 
 [[OIDTLT]]
 OID of toplevel tree
@@ -235,6 +239,7 @@
   * any messages that would have been printed to stdout (the
     <<IM,Informational messages>>)
 
+[[INPUT]]
 INPUT FORMAT
 ------------
 'git merge-tree --stdin' input format is fully text based. Each line
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.adoc
similarity index 98%
rename from Documentation/git-merge.txt
rename to Documentation/git-merge.adoc
index 1ab69f6..64281d6 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.adoc
@@ -65,7 +65,7 @@
 -------
 :git-merge: 1
 
-include::merge-options.txt[]
+include::merge-options.adoc[]
 
 -m <msg>::
 	Set the commit message to be used for the merge commit (in
@@ -91,7 +91,7 @@
 If `--log` is specified, a shortlog of the commits being merged
 will be appended to the specified message.
 
-include::rerere-options.txt[]
+include::rerere-options.adoc[]
 
 --overwrite-ignore::
 --no-overwrite-ignore::
@@ -385,7 +385,7 @@
 release/version name would be acceptable.
 
 
-include::merge-strategies.txt[]
+include::merge-strategies.adoc[]
 
 CONFIGURATION
 -------------
@@ -395,9 +395,9 @@
 	supported options are the same as those of `git merge`, but option
 	values containing whitespace characters are currently not supported.
 
-include::includes/cmd-config-section-rest.txt[]
+include::includes/cmd-config-section-rest.adoc[]
 
-include::config/merge.txt[]
+include::config/merge.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-mergetool--lib.txt b/Documentation/git-mergetool--lib.adoc
similarity index 100%
rename from Documentation/git-mergetool--lib.txt
rename to Documentation/git-mergetool--lib.adoc
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.adoc
similarity index 96%
rename from Documentation/git-mergetool.txt
rename to Documentation/git-mergetool.adoc
index b9e20c5..046c325 100644
--- a/Documentation/git-mergetool.txt
+++ b/Documentation/git-mergetool.adoc
@@ -104,9 +104,9 @@
 -------------
 :git-mergetool: 1
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/mergetool.txt[]
+include::config/mergetool.adoc[]
 
 TEMPORARY FILES
 ---------------
@@ -123,7 +123,7 @@
 
 vimdiff
 ~~~~~~~
-include::mergetools/vimdiff.txt[]
+include::mergetools/vimdiff.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-mktag.txt b/Documentation/git-mktag.adoc
similarity index 100%
rename from Documentation/git-mktag.txt
rename to Documentation/git-mktag.adoc
diff --git a/Documentation/git-mktree.txt b/Documentation/git-mktree.adoc
similarity index 100%
rename from Documentation/git-mktree.txt
rename to Documentation/git-mktree.adoc
diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.adoc
similarity index 100%
rename from Documentation/git-multi-pack-index.txt
rename to Documentation/git-multi-pack-index.adoc
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.adoc
similarity index 100%
rename from Documentation/git-mv.txt
rename to Documentation/git-mv.adoc
diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.adoc
similarity index 100%
rename from Documentation/git-name-rev.txt
rename to Documentation/git-name-rev.adoc
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.adoc
similarity index 72%
rename from Documentation/git-notes.txt
rename to Documentation/git-notes.adoc
index 84022f9..bcfe3da 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.adoc
@@ -7,19 +7,19 @@
 
 SYNOPSIS
 --------
-[verse]
-'git notes' [list [<object>]]
-'git notes' add [-f] [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [-e] [<object>]
-'git notes' copy [-f] ( --stdin | <from-object> [<to-object>] )
-'git notes' append [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [-e] [<object>]
-'git notes' edit [--allow-empty] [<object>] [--[no-]stripspace]
-'git notes' show [<object>]
-'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref>
-'git notes' merge --commit [-v | -q]
-'git notes' merge --abort [-v | -q]
-'git notes' remove [--ignore-missing] [--stdin] [<object>...]
-'git notes' prune [-n] [-v]
-'git notes' get-ref
+[synopsis]
+git notes [list [<object>]]
+git notes add [-f] [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [-e] [<object>]
+git notes copy [-f] ( --stdin | <from-object> [<to-object>] )
+git notes append [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [-e] [<object>]
+git notes edit [--allow-empty] [<object>] [--[no-]stripspace]
+git notes show [<object>]
+git notes merge [-v | -q] [-s <strategy> ] <notes-ref>
+git notes merge --commit [-v | -q]
+git notes merge --abort [-v | -q]
+git notes remove [--ignore-missing] [--stdin] [<object>...]
+git notes prune [-n] [-v]
+git notes get-ref
 
 
 DESCRIPTION
@@ -33,34 +33,34 @@
 quietly created when it is first needed to store a note.
 
 A typical use of notes is to supplement a commit message without
-changing the commit itself. Notes can be shown by 'git log' along with
+changing the commit itself. Notes can be shown by `git log` along with
 the original commit message. To distinguish these notes from the
 message stored in the commit object, the notes are indented like the
-message, after an unindented line saying "Notes (<refname>):" (or
+message, after an unindented line saying "Notes (_<refname>_):" (or
 "Notes:" for `refs/notes/commits`).
 
 Notes can also be added to patches prepared with `git format-patch` by
 using the `--notes` option. Such notes are added as a patch commentary
 after a three dash separator line.
 
-To change which notes are shown by 'git log', see the
-"notes.displayRef" discussion in <<CONFIGURATION>>.
+To change which notes are shown by `git log`, see the
+`notes.displayRef` discussion in <<CONFIGURATION,CONFIGURATION>>.
 
-See the "notes.rewrite.<command>" configuration for a way to carry
+See the `notes.rewrite.<command>` configuration for a way to carry
 notes across commands that rewrite commits.
 
 
 SUBCOMMANDS
 -----------
 
-list::
+`list`::
 	List the notes object for a given object. If no object is
 	given, show a list of all note objects and the objects they
-	annotate (in the format "<note-object> <annotated-object>").
+	annotate (in the format "`<note-object> <annotated-object>`").
 	This is the default subcommand if no subcommand is given.
 
-add::
-	Add notes for a given object (defaults to HEAD). Abort if the
+`add`::
+	Add notes for a given object (defaults to `HEAD`). Abort if the
 	object already has notes (use `-f` to overwrite existing notes).
 	However, if you're using `add` interactively (using an editor
 	to supply the notes contents), then - instead of aborting -
@@ -71,10 +71,10 @@
 	fine-tune the message(s) supplied from `-m` and `-F` options
 	interactively (using an editor) before adding the note.
 
-copy::
+`copy`::
 	Copy the notes for the first object onto the second object (defaults to
-	HEAD). Abort if the second object already has notes, or if the first
-	object has none (use -f to overwrite existing notes to the
+	`HEAD`). Abort if the second object already has notes, or if the first
+	object has none (use `-f` to overwrite existing notes to the
 	second object). This subcommand is equivalent to:
 	`git notes add [-f] -C $(git notes list <from-object>) <to-object>`
 +
@@ -84,27 +84,27 @@
 <from-object> SP <to-object> [ SP <rest> ] LF
 ----------
 +
-on standard input, and copy the notes from each <from-object> to its
-corresponding <to-object>.  (The optional `<rest>` is ignored so that
+on standard input, and copy the notes from each _<from-object>_ to its
+corresponding _<to-object>_.  (The optional _<rest>_ is ignored so that
 the command can read the input given to the `post-rewrite` hook.)
 
-append::
+`append`::
 	Append new message(s) given by `-m` or `-F` options to an
 	existing note, or add them as a new note if one does not
-	exist, for the object (defaults to HEAD).  When appending to
+	exist, for the object (defaults to `HEAD`).  When appending to
 	an existing note, a blank line is added before each new
 	message as an inter-paragraph separator.  The separator can
 	be customized with the `--separator` option.
 	Edit the notes to be appended given by `-m` and `-F` options with
 	`-e` interactively (using an editor) before appending the note.
 
-edit::
-	Edit the notes for a given object (defaults to HEAD).
+`edit`::
+	Edit the notes for a given object (defaults to `HEAD`).
 
-show::
-	Show the notes for a given object (defaults to HEAD).
+`show`::
+	Show the notes for a given object (defaults to `HEAD`).
 
-merge::
+`merge`::
 	Merge the given notes ref into the current notes ref.
 	This will try to merge the changes made by the given
 	notes ref (called "remote") since the merge-base (if
@@ -112,35 +112,35 @@
 +
 If conflicts arise and a strategy for automatically resolving
 conflicting notes (see the "NOTES MERGE STRATEGIES" section) is not given,
-the "manual" resolver is used. This resolver checks out the
+the `manual` resolver is used. This resolver checks out the
 conflicting notes in a special worktree (`.git/NOTES_MERGE_WORKTREE`),
 and instructs the user to manually resolve the conflicts there.
 When done, the user can either finalize the merge with
-'git notes merge --commit', or abort the merge with
-'git notes merge --abort'.
+`git notes merge --commit`, or abort the merge with
+`git notes merge --abort`.
 
-remove::
-	Remove the notes for given objects (defaults to HEAD). When
+`remove`::
+	Remove the notes for given objects (defaults to `HEAD`). When
 	giving zero or one object from the command line, this is
 	equivalent to specifying an empty note message to
 	the `edit` subcommand.
 
-prune::
+`prune`::
 	Remove all notes for non-existing/unreachable objects.
 
-get-ref::
+`get-ref`::
 	Print the current notes ref. This provides an easy way to
 	retrieve the current notes ref (e.g. from scripts).
 
 OPTIONS
 -------
--f::
---force::
+`-f`::
+`--force`::
 	When adding notes to an object that already has notes,
 	overwrite the existing notes (instead of aborting).
 
--m <msg>::
---message=<msg>::
+`-m <msg>`::
+`--message=<msg>`::
 	Use the given note message (instead of prompting).
 	If multiple `-m` options are given, their values
 	are concatenated as separate paragraphs.
@@ -148,95 +148,96 @@
 	single line between paragraphs will be stripped out.
 	If you wish to keep them verbatim, use `--no-stripspace`.
 
--F <file>::
---file=<file>::
-	Take the note message from the given file.  Use '-' to
+`-F <file>`::
+`--file=<file>`::
+	Take the note message from the given file.  Use `-` to
 	read the note message from the standard input.
 	Lines starting with `#` and empty lines other than a
 	single line between paragraphs will be stripped out.
 	If you wish to keep them verbatim, use `--no-stripspace`.
 
--C <object>::
---reuse-message=<object>::
+`-C <object>`::
+`--reuse-message=<object>`::
 	Take the given blob object (for example, another note) as the
 	note message. (Use `git notes copy <object>` instead to
 	copy notes between objects.).  By default, message will be
 	copied verbatim, but if you wish to strip out the lines
 	starting with `#` and empty lines other than a single line
-	between paragraphs, use with`--stripspace` option.
+	between paragraphs, use with `--stripspace` option.
 
--c <object>::
---reedit-message=<object>::
-	Like '-C', but with `-c` the editor is invoked, so that
+`-c <object>`::
+`--reedit-message=<object>`::
+	Like `-C`, but with `-c` the editor is invoked, so that
 	the user can further edit the note message.
 
---allow-empty::
+`--allow-empty`::
 	Allow an empty note object to be stored. The default behavior is
 	to automatically remove empty notes.
 
---[no-]separator, --separator=<paragraph-break>::
+`--[no-]separator`::
+`--separator=<paragraph-break>`::
 	Specify a string used as a custom inter-paragraph separator
 	(a newline is added at the end as needed). If `--no-separator`, no
 	separators will be added between paragraphs.  Defaults to a blank
 	line.
 
---[no-]stripspace::
+`--[no-]stripspace`::
 	Strip leading and trailing whitespace from the note message.
 	Also strip out empty lines other than a single line between
 	paragraphs. Lines starting with `#` will be stripped out
 	in non-editor cases like `-m`, `-F` and `-C`, but not in
 	editor case like `git notes edit`, `-c`, etc.
 
---ref <ref>::
-	Manipulate the notes tree in <ref>.  This overrides
-	`GIT_NOTES_REF` and the "core.notesRef" configuration.  The ref
+`--ref <ref>`::
+	Manipulate the notes tree in _<ref>_.  This overrides
+	`GIT_NOTES_REF` and the `core.notesRef` configuration.  The ref
 	specifies the full refname when it begins with `refs/notes/`; when it
 	begins with `notes/`, `refs/` and otherwise `refs/notes/` is prefixed
 	to form a full name of the ref.
 
---ignore-missing::
+`--ignore-missing`::
 	Do not consider it an error to request removing notes from an
 	object that does not have notes attached to it.
 
---stdin::
+`--stdin`::
 	Also read the object names to remove notes from the standard
 	input (there is no reason you cannot combine this with object
 	names from the command line).
 
--n::
---dry-run::
+`-n`::
+`--dry-run`::
 	Do not remove anything; just report the object names whose notes
 	would be removed.
 
--s <strategy>::
---strategy=<strategy>::
+`-s <strategy>`::
+`--strategy=<strategy>`::
 	When merging notes, resolve notes conflicts using the given
-	strategy. The following strategies are recognized: "manual"
-	(default), "ours", "theirs", "union" and "cat_sort_uniq".
-	This option overrides the "notes.mergeStrategy" configuration setting.
+	strategy. The following strategies are recognized: `manual`
+	(default), `ours`, `theirs`, `union` and `cat_sort_uniq`.
+	This option overrides the `notes.mergeStrategy` configuration setting.
 	See the "NOTES MERGE STRATEGIES" section below for more
 	information on each notes merge strategy.
 
---commit::
-	Finalize an in-progress 'git notes merge'. Use this option
-	when you have resolved the conflicts that 'git notes merge'
-	stored in .git/NOTES_MERGE_WORKTREE. This amends the partial
-	merge commit created by 'git notes merge' (stored in
-	.git/NOTES_MERGE_PARTIAL) by adding the notes in
-	.git/NOTES_MERGE_WORKTREE. The notes ref stored in the
-	.git/NOTES_MERGE_REF symref is updated to the resulting commit.
+`--commit`::
+	Finalize an in-progress `git notes merge`. Use this option
+	when you have resolved the conflicts that `git notes merge`
+	stored in `.git/NOTES_MERGE_WORKTREE`. This amends the partial
+	merge commit created by `git notes merge` (stored in
+	`.git/NOTES_MERGE_PARTIAL`) by adding the notes in
+	`.git/NOTES_MERGE_WORKTREE`. The notes ref stored in the
+	`.git/NOTES_MERGE_REF` symref is updated to the resulting commit.
 
---abort::
-	Abort/reset an in-progress 'git notes merge', i.e. a notes merge
+`--abort`::
+	Abort/reset an in-progress `git notes merge`, i.e. a notes merge
 	with conflicts. This simply removes all files related to the
 	notes merge.
 
--q::
---quiet::
+`-q`::
+`--quiet`::
 	When merging notes, operate quietly.
 
--v::
---verbose::
+`-v`::
+`--verbose`::
 	When merging notes, be more verbose.
 	When pruning notes, report all object names whose notes are
 	removed.
@@ -270,28 +271,28 @@
 NOTES MERGE STRATEGIES
 ----------------------
 
-The default notes merge strategy is "manual", which checks out
+The default notes merge strategy is `manual`, which checks out
 conflicting notes in a special work tree for resolving notes conflicts
 (`.git/NOTES_MERGE_WORKTREE`), and instructs the user to resolve the
 conflicts in that work tree.
 When done, the user can either finalize the merge with
-'git notes merge --commit', or abort the merge with
-'git notes merge --abort'.
+`git notes merge --commit`, or abort the merge with
+`git notes merge --abort`.
 
 Users may select an automated merge strategy from among the following using
-either -s/--strategy option or configuring notes.mergeStrategy accordingly:
+either `-s`/`--strategy` option or configuring `notes.mergeStrategy` accordingly:
 
-"ours" automatically resolves conflicting notes in favor of the local
+`ours` automatically resolves conflicting notes in favor of the local
 version (i.e. the current notes ref).
 
-"theirs" automatically resolves notes conflicts in favor of the remote
+`theirs` automatically resolves notes conflicts in favor of the remote
 version (i.e. the given notes ref being merged into the current notes
 ref).
 
-"union" automatically resolves notes conflicts by concatenating the
+`union` automatically resolves notes conflicts by concatenating the
 local and remote versions.
 
-"cat_sort_uniq" is similar to "union", but in addition to concatenating
+`cat_sort_uniq` is similar to `union`, but in addition to concatenating
 the local and remote versions, this strategy also sorts the resulting
 lines, and removes duplicate lines from the result. This is equivalent
 to applying the "cat | sort | uniq" shell pipeline to the local and
@@ -320,7 +321,7 @@
 
 In principle, a note is a regular Git blob, and any kind of
 (non-)format is accepted.  You can binary-safely create notes from
-arbitrary files using 'git hash-object':
+arbitrary files using `git hash-object`:
 
 ------------
 $ cc *.c
@@ -331,7 +332,7 @@
 (You cannot simply use `git notes --ref=built add -F a.out HEAD`
 because that is not binary-safe.)
 Of course, it doesn't make much sense to display non-text-format notes
-with 'git log', so if you use such notes, you'll probably need to write
+with `git log`, so if you use such notes, you'll probably need to write
 some special-purpose tools to do something useful with them.
 
 
@@ -339,15 +340,15 @@
 CONFIGURATION
 -------------
 
-core.notesRef::
+`core.notesRef`::
 	Notes ref to read and manipulate instead of
 	`refs/notes/commits`.  Must be an unabbreviated ref name.
 	This setting can be overridden through the environment and
 	command line.
 
-include::includes/cmd-config-section-rest.txt[]
+include::includes/cmd-config-section-rest.adoc[]
 
-include::config/notes.txt[]
+include::config/notes.adoc[]
 
 
 ENVIRONMENT
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.adoc
similarity index 100%
rename from Documentation/git-p4.txt
rename to Documentation/git-p4.adoc
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.adoc
similarity index 90%
rename from Documentation/git-pack-objects.txt
rename to Documentation/git-pack-objects.adoc
index e32404c..7f69ae4 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.adoc
@@ -15,7 +15,8 @@
 	[--revs [--unpacked | --all]] [--keep-pack=<pack-name>]
 	[--cruft] [--cruft-expiration=<time>]
 	[--stdout [--filter=<filter-spec>] | <base-name>]
-	[--shallow] [--keep-true-parents] [--[no-]sparse] < <object-list>
+	[--shallow] [--keep-true-parents] [--[no-]sparse]
+	[--name-hash-version=<n>] < <object-list>
 
 
 DESCRIPTION
@@ -345,6 +346,35 @@
 	Restrict delta matches based on "islands". See DELTA ISLANDS
 	below.
 
+--name-hash-version=<n>::
+	While performing delta compression, Git groups objects that may be
+	similar based on heuristics using the path to that object. While
+	grouping objects by an exact path match is good for paths with
+	many versions, there are benefits for finding delta pairs across
+	different full paths. Git collects objects by type and then by a
+	"name hash" of the path and then by size, hoping to group objects
+	that will compress well together.
++
+The default name hash version is `1`, which prioritizes hash locality by
+considering the final bytes of the path as providing the maximum magnitude
+to the hash function. This version excels at distinguishing short paths
+and finding renames across directories. However, the hash function depends
+primarily on the final 16 bytes of the path. If there are many paths in
+the repo that have the same final 16 bytes and differ only by parent
+directory, then this name-hash may lead to too many collisions and cause
+poor results. At the moment, this version is required when writing
+reachability bitmap files with `--write-bitmap-index`.
++
+The name hash version `2` has similar locality features as version `1`,
+except it considers each path component separately and overlays the hashes
+with a shift. This still prioritizes the final bytes of the path, but also
+"salts" the lower bits of the hash using the parent directory names. This
+method allows for some of the locality benefits of version `1` while
+breaking most of the collisions from a similarly-named file appearing in
+many different directories. At the moment, this version is not allowed
+when writing reachability bitmap files with `--write-bitmap-index` and it
+will be automatically changed to version `1`.
+
 
 DELTA ISLANDS
 -------------
diff --git a/Documentation/git-pack-redundant.txt b/Documentation/git-pack-redundant.adoc
similarity index 100%
rename from Documentation/git-pack-redundant.txt
rename to Documentation/git-pack-redundant.adoc
diff --git a/Documentation/git-pack-refs.txt b/Documentation/git-pack-refs.adoc
similarity index 100%
rename from Documentation/git-pack-refs.txt
rename to Documentation/git-pack-refs.adoc
diff --git a/Documentation/git-patch-id.txt b/Documentation/git-patch-id.adoc
similarity index 100%
rename from Documentation/git-patch-id.txt
rename to Documentation/git-patch-id.adoc
diff --git a/Documentation/git-prune-packed.txt b/Documentation/git-prune-packed.adoc
similarity index 100%
rename from Documentation/git-prune-packed.txt
rename to Documentation/git-prune-packed.adoc
diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.adoc
similarity index 100%
rename from Documentation/git-prune.txt
rename to Documentation/git-prune.adoc
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.adoc
similarity index 97%
rename from Documentation/git-pull.txt
rename to Documentation/git-pull.adoc
index b2ae496..3f4ecc4 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.adoc
@@ -102,7 +102,7 @@
 
 :git-pull: 1
 
-include::merge-options.txt[]
+include::merge-options.adoc[]
 
 -r::
 --rebase[=(false|true|merges|interactive)]::
@@ -136,13 +136,13 @@
 Options related to fetching
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-include::fetch-options.txt[]
+include::fetch-options.adoc[]
 
-include::pull-fetch-param.txt[]
+include::pull-fetch-param.adoc[]
 
-include::urls-remotes.txt[]
+include::urls-remotes.adoc[]
 
-include::merge-strategies.txt[]
+include::merge-strategies.adoc[]
 
 DEFAULT BEHAVIOUR
 -----------------
@@ -234,7 +234,7 @@
 would want to start over, you can recover with 'git reset'.
 
 
-include::transfer-data-leaks.txt[]
+include::transfer-data-leaks.adoc[]
 
 BUGS
 ----
diff --git a/Documentation/git-push.txt b/Documentation/git-push.adoc
similarity index 98%
rename from Documentation/git-push.txt
rename to Documentation/git-push.adoc
index 9b7cfbc..d197865 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.adoc
@@ -432,7 +432,7 @@
 --ipv6::
 	Use IPv6 addresses only, ignoring IPv4 addresses.
 
-include::urls-remotes.txt[]
+include::urls-remotes.adoc[]
 
 OUTPUT
 ------
@@ -695,14 +695,14 @@
 and so would be unreachable.  As such, these commits would be removed by
 a `git gc` command on the origin repository.
 
-include::transfer-data-leaks.txt[]
+include::transfer-data-leaks.adoc[]
 
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/push.txt[]
+include::config/push.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-quiltimport.txt b/Documentation/git-quiltimport.adoc
similarity index 100%
rename from Documentation/git-quiltimport.txt
rename to Documentation/git-quiltimport.adoc
diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.adoc
similarity index 100%
rename from Documentation/git-range-diff.txt
rename to Documentation/git-range-diff.adoc
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.adoc
similarity index 100%
rename from Documentation/git-read-tree.txt
rename to Documentation/git-read-tree.adoc
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.adoc
similarity index 98%
rename from Documentation/git-rebase.txt
rename to Documentation/git-rebase.adoc
index b18cdbc..153cb69 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.adoc
@@ -401,7 +401,7 @@
 +
 See also INCOMPATIBLE OPTIONS below.
 
-include::rerere-options.txt[]
+include::rerere-options.adoc[]
 
 -S[<keyid>]::
 --gpg-sign[=<keyid>]::
@@ -599,11 +599,11 @@
 --no-autosquash::
 	Automatically squash commits with specially formatted messages into
 	previous commits being rebased.  If a commit message starts with
-	"squash! ", "fixup! " or "amend! ", the remainder of the subject line
+	"squash! ", "fixup! " or "amend! ", the remainder of the title
 	is taken as a commit specifier, which matches a previous commit if it
-	matches the subject line or the hash of that commit.  If no commit
+	matches the title or the hash of that commit.  If no commit
 	matches fully, matches of the specifier with the start of commit
-	subjects are considered.
+	titles are considered.
 +
 In the rebase todo list, the actions of squash, fixup and amend commits are
 changed from `pick` to `squash`, `fixup` or `fixup -C`, respectively, and they
@@ -613,7 +613,7 @@
 The recommended way to create commits with squash markers is by using the
 `--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of
 linkgit:git-commit[1], which take the target commit as an argument and
-automatically fill in the subject line of the new commit from that.
+automatically fill in the title of the new commit from that.
 +
 Setting configuration variable `rebase.autoSquash` to true enables
 auto-squashing by default for interactive rebase.  The `--no-autosquash`
@@ -825,7 +825,7 @@
 * State directories: The two backends keep their state in different
   directories under `.git/`
 
-include::merge-strategies.txt[]
+include::merge-strategies.adoc[]
 
 NOTES
 -----
@@ -1294,10 +1294,10 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/rebase.txt[]
-include::config/sequencer.txt[]
+include::config/rebase.adoc[]
+include::config/sequencer.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.adoc
similarity index 100%
rename from Documentation/git-receive-pack.txt
rename to Documentation/git-receive-pack.adoc
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.adoc
similarity index 100%
rename from Documentation/git-reflog.txt
rename to Documentation/git-reflog.adoc
diff --git a/Documentation/git-refs.txt b/Documentation/git-refs.adoc
similarity index 84%
rename from Documentation/git-refs.txt
rename to Documentation/git-refs.adoc
index 9829984..4d6dc99 100644
--- a/Documentation/git-refs.txt
+++ b/Documentation/git-refs.adoc
@@ -8,9 +8,9 @@
 
 SYNOPSIS
 --------
-[verse]
-'git refs migrate' --ref-format=<format> [--dry-run]
-'git refs verify' [--strict] [--verbose]
+[synopsis]
+git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]
+git refs verify [--strict] [--verbose]
 
 DESCRIPTION
 -----------
@@ -34,7 +34,7 @@
 --ref-format=<format>::
 	The ref format to migrate the ref store to. Can be one of:
 +
-include::ref-storage-format.txt[]
+include::ref-storage-format.adoc[]
 
 --dry-run::
 	Perform the migration, but do not modify the repository. The migrated
@@ -43,6 +43,11 @@
 	can be used to double check that the migration works as expected before
 	performing the actual migration.
 
+--reflog::
+--no-reflog::
+	Choose between migrating the reflog data to the new backend,
+	and discarding them.  The default is "--reflog", to migrate.
+
 The following options are specific to 'git refs verify':
 
 --strict::
diff --git a/Documentation/git-remote-ext.txt b/Documentation/git-remote-ext.adoc
similarity index 100%
rename from Documentation/git-remote-ext.txt
rename to Documentation/git-remote-ext.adoc
diff --git a/Documentation/git-remote-fd.txt b/Documentation/git-remote-fd.adoc
similarity index 100%
rename from Documentation/git-remote-fd.txt
rename to Documentation/git-remote-fd.adoc
diff --git a/Documentation/git-remote-helpers.txto b/Documentation/git-remote-helpers.adoco
similarity index 100%
rename from Documentation/git-remote-helpers.txto
rename to Documentation/git-remote-helpers.adoco
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.adoc
similarity index 100%
rename from Documentation/git-remote.txt
rename to Documentation/git-remote.adoc
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.adoc
similarity index 96%
rename from Documentation/git-repack.txt
rename to Documentation/git-repack.adoc
index c902512..5852a5c 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.adoc
@@ -9,7 +9,9 @@
 SYNOPSIS
 --------
 [verse]
-'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m] [--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>] [--write-midx]
+'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]
+	[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]
+	[--write-midx] [--name-hash-version=<n>]
 
 DESCRIPTION
 -----------
@@ -249,6 +251,11 @@
 	Write a multi-pack index (see linkgit:git-multi-pack-index[1])
 	containing the non-redundant packs.
 
+--name-hash-version=<n>::
+	Provide this argument to the underlying `git pack-objects` process.
+	See linkgit:git-pack-objects[1] for full details.
+
+
 CONFIGURATION
 -------------
 
diff --git a/Documentation/git-replace.txt b/Documentation/git-replace.adoc
similarity index 100%
rename from Documentation/git-replace.txt
rename to Documentation/git-replace.adoc
diff --git a/Documentation/git-replay.txt b/Documentation/git-replay.adoc
similarity index 98%
rename from Documentation/git-replay.txt
rename to Documentation/git-replay.adoc
index 8f3300c..0b12bf8 100644
--- a/Documentation/git-replay.txt
+++ b/Documentation/git-replay.adoc
@@ -49,7 +49,7 @@
 	to. See "Specifying Ranges" in linkgit:git-rev-parse[1] and the
 	"Commit Limiting" options below.
 
-include::rev-list-options.txt[]
+include::rev-list-options.adoc[]
 
 OUTPUT
 ------
diff --git a/Documentation/git-request-pull.txt b/Documentation/git-request-pull.adoc
similarity index 100%
rename from Documentation/git-request-pull.txt
rename to Documentation/git-request-pull.adoc
diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.adoc
similarity index 100%
rename from Documentation/git-rerere.txt
rename to Documentation/git-rerere.adoc
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.adoc
similarity index 100%
rename from Documentation/git-reset.txt
rename to Documentation/git-reset.adoc
diff --git a/Documentation/git-restore.txt b/Documentation/git-restore.adoc
similarity index 70%
rename from Documentation/git-restore.txt
rename to Documentation/git-restore.adoc
index 975825b..751f01b 100644
--- a/Documentation/git-restore.txt
+++ b/Documentation/git-restore.adoc
@@ -7,10 +7,10 @@
 
 SYNOPSIS
 --------
-[verse]
-'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] [--] <pathspec>...
-'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] --pathspec-from-file=<file> [--pathspec-file-nul]
-'git restore' (-p|--patch) [<options>] [--source=<tree>] [--staged] [--worktree] [--] [<pathspec>...]
+[synopsis]
+git restore [<options>] [--source=<tree>] [--staged] [--worktree] [--] <pathspec>...
+git restore [<options>] [--source=<tree>] [--staged] [--worktree] --pathspec-from-file=<file> [--pathspec-file-nul]
+git restore (-p|--patch) [<options>] [--source=<tree>] [--staged] [--worktree] [--] [<pathspec>...]
 
 DESCRIPTION
 -----------
@@ -32,8 +32,8 @@
 
 OPTIONS
 -------
--s <tree>::
---source=<tree>::
+`-s <tree>`::
+`--source=<tree>`::
 	Restore the working tree files with the content from the given
 	tree. It is common to specify the source tree by naming a
 	commit, branch or tag associated with it.
@@ -41,79 +41,79 @@
 If not specified, the contents are restored from `HEAD` if `--staged` is
 given, otherwise from the index.
 +
-As a special case, you may use `"A...B"` as a shortcut for the
-merge base of `A` and `B` if there is exactly one merge base. You can
-leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
+As a special case, you may use `"<rev-A>...<rev-B>"` as a shortcut for the
+merge base of _<rev-A>_ and _<rev-B>_ if there is exactly one merge base. You can
+leave out at most one of _<rev-A>__ and _<rev-B>_, in which case it defaults to `HEAD`.
 
--p::
---patch::
+`-p`::
+`--patch`::
 	Interactively select hunks in the difference between the
-	restore source and the restore location. See the ``Interactive
-	Mode'' section of linkgit:git-add[1] to learn how to operate
+	restore source and the restore location. See the "Interactive
+	Mode" section of linkgit:git-add[1] to learn how to operate
 	the `--patch` mode.
 +
 Note that `--patch` can accept no pathspec and will prompt to restore
 all modified paths.
 
--W::
---worktree::
--S::
---staged::
+`-W`::
+`--worktree`::
+`-S`::
+`--staged`::
 	Specify the restore location. If neither option is specified,
 	by default the working tree is restored. Specifying `--staged`
 	will only restore the index. Specifying both restores both.
 
--q::
---quiet::
+`-q`::
+`--quiet`::
 	Quiet, suppress feedback messages. Implies `--no-progress`.
 
---progress::
---no-progress::
+`--progress`::
+`--no-progress`::
 	Progress status is reported on the standard error stream
 	by default when it is attached to a terminal, unless `--quiet`
 	is specified. This flag enables progress reporting even if not
 	attached to a terminal, regardless of `--quiet`.
 
---ours::
---theirs::
+`--ours`::
+`--theirs`::
 	When restoring files in the working tree from the index, use
-	stage #2 ('ours') or #3 ('theirs') for unmerged paths.
+	stage #2 (`ours`) or #3 (`theirs`) for unmerged paths.
 	This option cannot be used when checking out paths from a
 	tree-ish (i.e. with the `--source` option).
 +
-Note that during `git rebase` and `git pull --rebase`, 'ours' and
-'theirs' may appear swapped. See the explanation of the same options
+Note that during `git rebase` and `git pull --rebase`, `ours` and
+`theirs` may appear swapped. See the explanation of the same options
 in linkgit:git-checkout[1] for details.
 
--m::
---merge::
+`-m`::
+`--merge`::
 	When restoring files on the working tree from the index,
 	recreate the conflicted merge in the unmerged paths.
 	This option cannot be used when checking out paths from a
 	tree-ish (i.e. with the `--source` option).
 
---conflict=<style>::
+`--conflict=<style>`::
 	The same as `--merge` option above, but changes the way the
 	conflicting hunks are presented, overriding the
 	`merge.conflictStyle` configuration variable.  Possible values
-	are "merge" (default), "diff3", and "zdiff3".
+	are `merge` (default), `diff3`, and `zdiff3`.
 
---ignore-unmerged::
+`--ignore-unmerged`::
 	When restoring files on the working tree from the index, do
 	not abort the operation if there are unmerged entries and
 	neither `--ours`, `--theirs`, `--merge` or `--conflict` is
 	specified. Unmerged paths on the working tree are left alone.
 
---ignore-skip-worktree-bits::
+`--ignore-skip-worktree-bits`::
 	In sparse checkout mode, the default is to only update entries
-	matched by `<pathspec>` and sparse patterns in
-	$GIT_DIR/info/sparse-checkout. This option ignores the sparse
+	matched by _<pathspec>_ and sparse patterns in
+	`$GIT_DIR/info/sparse-checkout`. This option ignores the sparse
 	patterns and unconditionally restores any files in
-	`<pathspec>`.
+	_<pathspec>_.
 
---recurse-submodules::
---no-recurse-submodules::
-	If `<pathspec>` names an active submodule and the restore location
+`--recurse-submodules`::
+`--no-recurse-submodules`::
+	If _<pathspec>_ names an active submodule and the restore location
 	includes the working tree, the submodule will only be updated if
 	this option is given, in which case its working tree will be
 	restored to the commit recorded in the superproject, and any local
@@ -122,30 +122,30 @@
 	not be updated. Just like linkgit:git-checkout[1], this will detach
 	`HEAD` of the submodule.
 
---overlay::
---no-overlay::
-	In overlay mode, the command never removes files when
-	restoring. In no-overlay mode, tracked files that do not
-	appear in the `--source` tree are removed, to make them match
-	`<tree>` exactly. The default is no-overlay mode.
+`--overlay`::
+`--no-overlay`::
+	In overlay mode, never remove files when restoring. In no-overlay mode,
+	remove tracked files that do not appear in the _<tree>_ of
+	`--source=<tree>`, to make them match _<tree>_ exactly. The default
+	is no-overlay mode.
 
---pathspec-from-file=<file>::
-	Pathspec is passed in `<file>` instead of commandline args. If
-	`<file>` is exactly `-` then standard input is used. Pathspec
-	elements are separated by LF or CR/LF. Pathspec elements can be
+`--pathspec-from-file=<file>`::
+	Pathspec is passed in _<file>_ instead of commandline args. If
+	_<file>_ is exactly `-` then standard input is used. Pathspec
+	elements are separated by _LF_ or _CR_/_LF_. Pathspec elements can be
 	quoted as explained for the configuration variable `core.quotePath`
 	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
 	global `--literal-pathspecs`.
 
---pathspec-file-nul::
+`--pathspec-file-nul`::
 	Only meaningful with `--pathspec-from-file`. Pathspec elements are
-	separated with NUL character and all other characters are taken
+	separated with _NUL_ character and all other characters are taken
 	literally (including newlines and quotes).
 
-\--::
+`--`::
 	Do not interpret any more arguments as options.
 
-<pathspec>...::
+`<pathspec>...`::
 	Limits the paths affected by the operation.
 +
 For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
@@ -154,7 +154,7 @@
 --------
 
 The following sequence switches to the `master` branch, reverts the
-`Makefile` to two revisions back, deletes hello.c by mistake, and gets
+`Makefile` to two revisions back, deletes `hello.c` by mistake, and gets
 it back from the index.
 
 ------------
@@ -165,7 +165,7 @@
 ------------
 
 <1> take a file out of another commit
-<2> restore hello.c from the index
+<2> restore `hello.c` from the index
 
 If you want to restore _all_ C source files to match the version in
 the index, you can say
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.adoc
similarity index 96%
rename from Documentation/git-rev-list.txt
rename to Documentation/git-rev-list.adoc
index 2e05c4b..f582491 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.adoc
@@ -15,7 +15,7 @@
 -----------
 
 :git-rev-list: 1
-include::rev-list-description.txt[]
+include::rev-list-description.adoc[]
 
 'rev-list' is an essential Git command, since it
 provides the ability to build and traverse commit ancestry graphs. For
@@ -27,9 +27,9 @@
 -------
 
 :git-rev-list: 1
-include::rev-list-options.txt[]
+include::rev-list-options.adoc[]
 
-include::pretty-formats.txt[]
+include::pretty-formats.adoc[]
 
 EXAMPLES
 --------
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.adoc
similarity index 99%
rename from Documentation/git-rev-parse.txt
rename to Documentation/git-rev-parse.adoc
index dc12d38..cc32b4b 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.adoc
@@ -351,7 +351,7 @@
 	Flags and parameters to be parsed.
 
 
-include::revisions.txt[]
+include::revisions.adoc[]
 
 PARSEOPT
 --------
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.adoc
similarity index 97%
rename from Documentation/git-revert.txt
rename to Documentation/git-revert.adoc
index 568925d..ffba365 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.adoc
@@ -112,7 +112,7 @@
 	Pass the merge strategy-specific option through to the
 	merge strategy.  See linkgit:git-merge[1] for details.
 
-include::rerere-options.txt[]
+include::rerere-options.adoc[]
 
 --reference::
 	Instead of starting the body of the log message with "This
@@ -125,7 +125,7 @@
 
 SEQUENCER SUBCOMMANDS
 ---------------------
-include::sequencer.txt[]
+include::sequencer.adoc[]
 
 EXAMPLES
 --------
@@ -155,9 +155,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/revert.txt[]
+include::config/revert.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.adoc
similarity index 100%
rename from Documentation/git-rm.txt
rename to Documentation/git-rm.adoc
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.adoc
similarity index 99%
rename from Documentation/git-send-email.txt
rename to Documentation/git-send-email.adoc
index bc3ef45..7f223db 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.adoc
@@ -492,9 +492,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/sendemail.txt[]
+include::config/sendemail.adoc[]
 
 EXAMPLES
 --------
diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.adoc
similarity index 100%
rename from Documentation/git-send-pack.txt
rename to Documentation/git-send-pack.adoc
diff --git a/Documentation/git-sh-i18n--envsubst.txt b/Documentation/git-sh-i18n--envsubst.adoc
similarity index 100%
rename from Documentation/git-sh-i18n--envsubst.txt
rename to Documentation/git-sh-i18n--envsubst.adoc
diff --git a/Documentation/git-sh-i18n.txt b/Documentation/git-sh-i18n.adoc
similarity index 100%
rename from Documentation/git-sh-i18n.txt
rename to Documentation/git-sh-i18n.adoc
diff --git a/Documentation/git-sh-setup.txt b/Documentation/git-sh-setup.adoc
similarity index 100%
rename from Documentation/git-sh-setup.txt
rename to Documentation/git-sh-setup.adoc
diff --git a/Documentation/git-shell.txt b/Documentation/git-shell.adoc
similarity index 100%
rename from Documentation/git-shell.txt
rename to Documentation/git-shell.adoc
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.adoc
similarity index 98%
rename from Documentation/git-shortlog.txt
rename to Documentation/git-shortlog.adoc
index 7d0277d..d8ab38d 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.adoc
@@ -114,7 +114,7 @@
 options or the revision range, when confusion arises.
 
 :git-shortlog: 1
-include::rev-list-options.txt[]
+include::rev-list-options.adoc[]
 
 MAPPING AUTHORS
 ---------------
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.adoc
similarity index 98%
rename from Documentation/git-show-branch.txt
rename to Documentation/git-show-branch.adoc
index bc31d8b..7e86d54 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.adoc
@@ -202,9 +202,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/showbranch.txt[]
+include::config/showbranch.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-show-index.txt b/Documentation/git-show-index.adoc
similarity index 92%
rename from Documentation/git-show-index.txt
rename to Documentation/git-show-index.adoc
index e49318a..00b3a90 100644
--- a/Documentation/git-show-index.txt
+++ b/Documentation/git-show-index.adoc
@@ -9,7 +9,7 @@
 SYNOPSIS
 --------
 [verse]
-'git show-index' [--object-format=<hash-algorithm>]
+'git show-index' [--object-format=<hash-algorithm>] < <pack-idx-file>
 
 
 DESCRIPTION
@@ -45,7 +45,7 @@
 	algorithm for the current repository (set by `extensions.objectFormat`), or
 	'sha1' if no value is set or outside a repository..
 +
-include::object-format-disclaimer.txt[]
+include::object-format-disclaimer.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.adoc
similarity index 100%
rename from Documentation/git-show-ref.txt
rename to Documentation/git-show-ref.adoc
diff --git a/Documentation/git-show.txt b/Documentation/git-show.adoc
similarity index 91%
rename from Documentation/git-show.txt
rename to Documentation/git-show.adoc
index 5eb6743..51044c8 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.adoc
@@ -39,10 +39,10 @@
 	For a more complete list of ways to spell object names, see
 	"SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
 
-include::pretty-options.txt[]
+include::pretty-options.adoc[]
 
 
-include::pretty-formats.txt[]
+include::pretty-formats.adoc[]
 
 
 DIFF FORMATTING
@@ -52,9 +52,9 @@
 
 :git-log: 1
 :diff-merges-default: `dense-combined`
-include::diff-options.txt[]
+include::diff-options.adoc[]
 
-include::diff-generate-patch.txt[]
+include::diff-generate-patch.adoc[]
 
 
 EXAMPLES
@@ -83,7 +83,7 @@
 DISCUSSION
 ----------
 
-include::i18n.txt[]
+include::i18n.adoc[]
 
 GIT
 ---
diff --git a/Documentation/git-sparse-checkout.txt b/Documentation/git-sparse-checkout.adoc
similarity index 100%
rename from Documentation/git-sparse-checkout.txt
rename to Documentation/git-sparse-checkout.adoc
diff --git a/Documentation/git-stage.txt b/Documentation/git-stage.adoc
similarity index 100%
rename from Documentation/git-stage.txt
rename to Documentation/git-stage.adoc
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.adoc
similarity index 98%
rename from Documentation/git-stash.txt
rename to Documentation/git-stash.adoc
index 06fb7f1..1a5177f 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.adoc
@@ -388,9 +388,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/stash.txt[]
+include::config/stash.adoc[]
 
 
 SEE ALSO
diff --git a/Documentation/git-status.txt b/Documentation/git-status.adoc
similarity index 100%
rename from Documentation/git-status.txt
rename to Documentation/git-status.adoc
diff --git a/Documentation/git-stripspace.txt b/Documentation/git-stripspace.adoc
similarity index 100%
rename from Documentation/git-stripspace.txt
rename to Documentation/git-stripspace.adoc
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.adoc
similarity index 100%
rename from Documentation/git-submodule.txt
rename to Documentation/git-submodule.adoc
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.adoc
similarity index 100%
rename from Documentation/git-svn.txt
rename to Documentation/git-svn.adoc
diff --git a/Documentation/git-switch.txt b/Documentation/git-switch.adoc
similarity index 98%
rename from Documentation/git-switch.txt
rename to Documentation/git-switch.adoc
index f38e4c8..f55315c 100644
--- a/Documentation/git-switch.txt
+++ b/Documentation/git-switch.adoc
@@ -273,9 +273,9 @@
 CONFIGURATION
 -------------
 
-include::includes/cmd-config-section-all.txt[]
+include::includes/cmd-config-section-all.adoc[]
 
-include::config/checkout.txt[]
+include::config/checkout.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.adoc
similarity index 100%
rename from Documentation/git-symbolic-ref.txt
rename to Documentation/git-symbolic-ref.adoc
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.adoc
similarity index 99%
rename from Documentation/git-tag.txt
rename to Documentation/git-tag.adoc
index 4494729..a4b1c0e 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.adoc
@@ -391,7 +391,7 @@
 $ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1
 ------------
 
-include::date-formats.txt[]
+include::date-formats.adoc[]
 
 FILES
 -----
@@ -406,7 +406,7 @@
 NOTES
 -----
 
-include::ref-reachability-filters.txt[]
+include::ref-reachability-filters.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-tools.txt b/Documentation/git-tools.adoc
similarity index 100%
rename from Documentation/git-tools.txt
rename to Documentation/git-tools.adoc
diff --git a/Documentation/git-unpack-file.txt b/Documentation/git-unpack-file.adoc
similarity index 100%
rename from Documentation/git-unpack-file.txt
rename to Documentation/git-unpack-file.adoc
diff --git a/Documentation/git-unpack-objects.txt b/Documentation/git-unpack-objects.adoc
similarity index 100%
rename from Documentation/git-unpack-objects.txt
rename to Documentation/git-unpack-objects.adoc
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.adoc
similarity index 100%
rename from Documentation/git-update-index.txt
rename to Documentation/git-update-index.adoc
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.adoc
similarity index 100%
rename from Documentation/git-update-ref.txt
rename to Documentation/git-update-ref.adoc
diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.adoc
similarity index 100%
rename from Documentation/git-update-server-info.txt
rename to Documentation/git-update-server-info.adoc
diff --git a/Documentation/git-upload-archive.txt b/Documentation/git-upload-archive.adoc
similarity index 100%
rename from Documentation/git-upload-archive.txt
rename to Documentation/git-upload-archive.adoc
diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.adoc
similarity index 100%
rename from Documentation/git-upload-pack.txt
rename to Documentation/git-upload-pack.adoc
diff --git a/Documentation/git-var.txt b/Documentation/git-var.adoc
similarity index 100%
rename from Documentation/git-var.txt
rename to Documentation/git-var.adoc
diff --git a/Documentation/git-verify-commit.txt b/Documentation/git-verify-commit.adoc
similarity index 100%
rename from Documentation/git-verify-commit.txt
rename to Documentation/git-verify-commit.adoc
diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.adoc
similarity index 100%
rename from Documentation/git-verify-pack.txt
rename to Documentation/git-verify-pack.adoc
diff --git a/Documentation/git-verify-tag.txt b/Documentation/git-verify-tag.adoc
similarity index 100%
rename from Documentation/git-verify-tag.txt
rename to Documentation/git-verify-tag.adoc
diff --git a/Documentation/git-version.txt b/Documentation/git-version.adoc
similarity index 100%
rename from Documentation/git-version.txt
rename to Documentation/git-version.adoc
diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.adoc
similarity index 100%
rename from Documentation/git-web--browse.txt
rename to Documentation/git-web--browse.adoc
diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.adoc
similarity index 100%
rename from Documentation/git-whatchanged.txt
rename to Documentation/git-whatchanged.adoc
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.adoc
similarity index 100%
rename from Documentation/git-worktree.txt
rename to Documentation/git-worktree.adoc
diff --git a/Documentation/git-write-tree.txt b/Documentation/git-write-tree.adoc
similarity index 100%
rename from Documentation/git-write-tree.txt
rename to Documentation/git-write-tree.adoc
diff --git a/Documentation/git.txt b/Documentation/git.adoc
similarity index 97%
rename from Documentation/git.txt
rename to Documentation/git.adoc
index e89a91d..743b7b0 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.adoc
@@ -245,17 +245,17 @@
 Main porcelain commands
 ~~~~~~~~~~~~~~~~~~~~~~~
 
-include::{build_dir}/cmds-mainporcelain.txt[]
+include::{build_dir}/cmds-mainporcelain.adoc[]
 
 Ancillary Commands
 ~~~~~~~~~~~~~~~~~~
 Manipulators:
 
-include::{build_dir}/cmds-ancillarymanipulators.txt[]
+include::{build_dir}/cmds-ancillarymanipulators.adoc[]
 
 Interrogators:
 
-include::{build_dir}/cmds-ancillaryinterrogators.txt[]
+include::{build_dir}/cmds-ancillaryinterrogators.adoc[]
 
 
 Interacting with Others
@@ -264,7 +264,7 @@
 These commands are to interact with foreign SCM and with other
 people via patch over e-mail.
 
-include::{build_dir}/cmds-foreignscminterface.txt[]
+include::{build_dir}/cmds-foreignscminterface.adoc[]
 
 Reset, restore and revert
 ~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -313,13 +313,13 @@
 Manipulation commands
 ~~~~~~~~~~~~~~~~~~~~~
 
-include::{build_dir}/cmds-plumbingmanipulators.txt[]
+include::{build_dir}/cmds-plumbingmanipulators.adoc[]
 
 
 Interrogation commands
 ~~~~~~~~~~~~~~~~~~~~~~
 
-include::{build_dir}/cmds-plumbinginterrogators.txt[]
+include::{build_dir}/cmds-plumbinginterrogators.adoc[]
 
 In general, the interrogate commands do not touch the files in
 the working tree.
@@ -328,12 +328,12 @@
 Syncing repositories
 ~~~~~~~~~~~~~~~~~~~~
 
-include::{build_dir}/cmds-synchingrepositories.txt[]
+include::{build_dir}/cmds-synchingrepositories.adoc[]
 
 The following are helper commands used by the above; end users
 typically do not use them directly.
 
-include::{build_dir}/cmds-synchelpers.txt[]
+include::{build_dir}/cmds-synchelpers.adoc[]
 
 
 Internal helper commands
@@ -342,14 +342,14 @@
 These are internal helper commands used by other commands; end
 users typically do not use them directly.
 
-include::{build_dir}/cmds-purehelpers.txt[]
+include::{build_dir}/cmds-purehelpers.adoc[]
 
 Guides
 ------
 
 The following documentation pages are guides about Git concepts.
 
-include::{build_dir}/cmds-guide.txt[]
+include::{build_dir}/cmds-guide.adoc[]
 
 Repository, command and file interfaces
 ---------------------------------------
@@ -358,7 +358,7 @@
 users are expected to interact with directly. See `--user-formats` in
 linkgit:git-help[1] for more details on the criteria.
 
-include::{build_dir}/cmds-userinterfaces.txt[]
+include::{build_dir}/cmds-userinterfaces.adoc[]
 
 File formats, protocols and other developer interfaces
 ------------------------------------------------------
@@ -367,7 +367,7 @@
 other git developer interfaces. See `--developer-interfaces` in
 linkgit:git-help[1].
 
-include::{build_dir}/cmds-developerinterfaces.txt[]
+include::{build_dir}/cmds-developerinterfaces.adoc[]
 
 Configuration Mechanism
 -----------------------
@@ -472,8 +472,9 @@
 ---------------------
 Various Git commands pay attention to environment variables and change
 their behavior.  The environment variables marked as "Boolean" take
-their values the same way as Boolean valued configuration variables, e.g.
-"true", "yes", "on" and positive numbers are taken as "yes".
+their values the same way as Boolean valued configuration variables, i.e.,
+"true", "yes", "on" and positive numbers are taken as "yes", while "false",
+"no", "off", and "0" are taken as "no".
 
 Here are the variables:
 
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.adoc
similarity index 98%
rename from Documentation/gitattributes.txt
rename to Documentation/gitattributes.adoc
index e615059..a22d1ef 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.adoc
@@ -513,7 +513,7 @@
 `filter.<driver>.process` then Git can process all blobs with a
 single filter invocation for the entire life of a single Git
 command. This is achieved by using the long-running process protocol
-(described in technical/long-running-process-protocol.txt).
+(described in Documentation/technical/long-running-process-protocol.adoc).
 
 When Git encounters the first file that needs to be cleaned or smudged,
 it starts the filter and performs the handshake. In the handshake, the
@@ -701,8 +701,8 @@
 conflicts.
 
 To prevent these unnecessary merge conflicts, Git can be told to run a
-virtual check-out and check-in of all three stages of a file when
-resolving a three-way merge by setting the `merge.renormalize`
+virtual check-out and check-in of all three stages of each file that
+needs a three-way content merge, by setting the `merge.renormalize`
 configuration variable.  This prevents changes caused by check-in
 conversion from causing spurious merge conflicts when a converted file
 is merged with an unconverted file.
@@ -1166,7 +1166,7 @@
 The merge driver can learn the pathname in which the merged result
 will be stored via placeholder `%P`. The conflict labels to be used
 for the common ancestor, local head and other head can be passed by
-using '%S', '%X' and '%Y` respectively.
+using `%S`, `%X` and `%Y` respectively.
 
 `conflict-marker-size`
 ^^^^^^^^^^^^^^^^^^^^^^
@@ -1177,11 +1177,11 @@
 
 For example, this line in `.gitattributes` can be used to tell the merge
 machinery to leave much longer (instead of the usual 7-character-long)
-conflict markers when merging the file `Documentation/git-merge.txt`
+conflict markers when merging the file `Documentation/git-merge.adoc`
 results in a conflict.
 
 ------------------------
-Documentation/git-merge.txt	conflict-marker-size=32
+Documentation/git-merge.adoc	conflict-marker-size=32
 ------------------------
 
 
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.adoc
similarity index 92%
rename from Documentation/gitcli.txt
rename to Documentation/gitcli.adoc
index fcd86d2..04193ec 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.adoc
@@ -161,6 +161,23 @@
 and `--no-color`.
 
 
+Options trump configuration and environment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When there is a configuration variable or an environment variable
+that tweak the behaviour of an aspect of a Git command, and also a
+command line option that tweaks the same, the command line option
+overrides what the configuration and/or environment variable say.
+
+For example, the `user.name` configuration variable is used to
+specify the human-readable name used by the `git commit` command to
+record the author and the committer name in a newly created commit.
+The `GIT_AUTHOR_NAME` environment variable, if set, takes precedence
+when deciding what author name to record.  The `--author=<author>`
+command line option of the `git commit` command, when given, takes
+precedence over these two sources of information.
+
+
 Aggregating short options
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 Commands that support the enhanced option parser allow you to aggregate short
diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.adoc
similarity index 100%
rename from Documentation/gitcore-tutorial.txt
rename to Documentation/gitcore-tutorial.adoc
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.adoc
similarity index 91%
rename from Documentation/gitcredentials.txt
rename to Documentation/gitcredentials.adoc
index 35a7452..3337bb4 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.adoc
@@ -66,18 +66,7 @@
 credential-generating helper might generate credentials for certain servers via
 some API.
 
-To use a helper, you must first select one to use. Git currently
-includes the following helpers:
-
-cache::
-
-	Cache credentials in memory for a short period of time. See
-	linkgit:git-credential-cache[1] for details.
-
-store::
-
-	Store credentials indefinitely on disk. See
-	linkgit:git-credential-store[1] for details.
+To use a helper, you must first select one to use (see below for a list).
 
 You may also have third-party helpers installed; search for
 `credential-*` in the output of `git help -a`, and consult the
@@ -106,6 +95,28 @@
 
 === Available helpers
 
+Git currently includes the following helpers:
+
+cache::
+
+    Cache credentials in memory for a short period of time. See
+    linkgit:git-credential-cache[1] for details.
+
+store::
+
+    Store credentials indefinitely on disk. See
+    linkgit:git-credential-store[1] for details.
+
+Popular helpers with secure persistent storage include:
+
+    - git-credential-libsecret (Linux)
+
+    - git-credential-osxkeychain (macOS)
+
+    - git-credential-wincred (Windows)
+
+    - https://github.com/git-ecosystem/git-credential-manager[Git Credential Manager] (cross platform, included in Git for Windows)
+
 The community maintains a comprehensive list of Git credential helpers at
 https://git-scm.com/doc/credential-helpers.
 
@@ -116,6 +127,12 @@
 host. Subsequent authentication happens in the background. Many popular Git
 hosts support OAuth.
 
+Popular helpers with OAuth support include:
+
+    - https://github.com/git-ecosystem/git-credential-manager[Git Credential Manager] (cross platform, included in Git for Windows)
+
+    - https://github.com/hickford/git-credential-oauth[git-credential-oauth] (cross platform, included in many Linux distributions)
+
 CREDENTIAL CONTEXTS
 -------------------
 
diff --git a/Documentation/gitcvs-migration.txt b/Documentation/gitcvs-migration.adoc
similarity index 100%
rename from Documentation/gitcvs-migration.txt
rename to Documentation/gitcvs-migration.adoc
diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.adoc
similarity index 100%
rename from Documentation/gitdiffcore.txt
rename to Documentation/gitdiffcore.adoc
diff --git a/Documentation/giteveryday.txt b/Documentation/giteveryday.adoc
similarity index 100%
rename from Documentation/giteveryday.txt
rename to Documentation/giteveryday.adoc
diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.adoc
similarity index 100%
rename from Documentation/gitfaq.txt
rename to Documentation/gitfaq.adoc
diff --git a/Documentation/gitformat-bundle.txt b/Documentation/gitformat-bundle.adoc
similarity index 100%
rename from Documentation/gitformat-bundle.txt
rename to Documentation/gitformat-bundle.adoc
diff --git a/Documentation/gitformat-chunk.txt b/Documentation/gitformat-chunk.adoc
similarity index 100%
rename from Documentation/gitformat-chunk.txt
rename to Documentation/gitformat-chunk.adoc
diff --git a/Documentation/gitformat-commit-graph.txt b/Documentation/gitformat-commit-graph.adoc
similarity index 100%
rename from Documentation/gitformat-commit-graph.txt
rename to Documentation/gitformat-commit-graph.adoc
diff --git a/Documentation/gitformat-index.txt b/Documentation/gitformat-index.adoc
similarity index 100%
rename from Documentation/gitformat-index.txt
rename to Documentation/gitformat-index.adoc
diff --git a/Documentation/gitformat-pack.txt b/Documentation/gitformat-pack.adoc
similarity index 100%
rename from Documentation/gitformat-pack.txt
rename to Documentation/gitformat-pack.adoc
diff --git a/Documentation/gitformat-signature.txt b/Documentation/gitformat-signature.adoc
similarity index 100%
rename from Documentation/gitformat-signature.txt
rename to Documentation/gitformat-signature.adoc
diff --git a/Documentation/gitglossary.txt b/Documentation/gitglossary.adoc
similarity index 90%
rename from Documentation/gitglossary.txt
rename to Documentation/gitglossary.adoc
index 571f640..0e85be4 100644
--- a/Documentation/gitglossary.txt
+++ b/Documentation/gitglossary.adoc
@@ -12,7 +12,7 @@
 DESCRIPTION
 -----------
 
-include::glossary-content.txt[]
+include::glossary-content.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/githooks.txt b/Documentation/githooks.adoc
similarity index 100%
rename from Documentation/githooks.txt
rename to Documentation/githooks.adoc
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.adoc
similarity index 100%
rename from Documentation/gitignore.txt
rename to Documentation/gitignore.adoc
diff --git a/Documentation/gitk.txt b/Documentation/gitk.adoc
similarity index 98%
rename from Documentation/gitk.txt
rename to Documentation/gitk.adoc
index 35b3996..58ce40d 100644
--- a/Documentation/gitk.txt
+++ b/Documentation/gitk.adoc
@@ -98,7 +98,7 @@
 	(See "History simplification" in linkgit:git-log[1] for a more
 	detailed explanation.)
 
-include::line-range-options.txt[]
+include::line-range-options.adoc[]
 
 <revision range>::
 
diff --git a/Documentation/gitmailmap.txt b/Documentation/gitmailmap.adoc
similarity index 100%
rename from Documentation/gitmailmap.txt
rename to Documentation/gitmailmap.adoc
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.adoc
similarity index 100%
rename from Documentation/gitmodules.txt
rename to Documentation/gitmodules.adoc
diff --git a/Documentation/gitnamespaces.txt b/Documentation/gitnamespaces.adoc
similarity index 98%
rename from Documentation/gitnamespaces.txt
rename to Documentation/gitnamespaces.adoc
index 1c8d2ec..06f4d37 100644
--- a/Documentation/gitnamespaces.txt
+++ b/Documentation/gitnamespaces.adoc
@@ -61,7 +61,7 @@
 git clone ext::'git --namespace=foo %s /tmp/prefixed.git'
 ----------
 
-include::transfer-data-leaks.txt[]
+include::transfer-data-leaks.adoc[]
 
 GIT
 ---
diff --git a/Documentation/gitpacking.txt b/Documentation/gitpacking.adoc
similarity index 98%
rename from Documentation/gitpacking.txt
rename to Documentation/gitpacking.adoc
index 321154d..a56596e 100644
--- a/Documentation/gitpacking.txt
+++ b/Documentation/gitpacking.adoc
@@ -136,7 +136,7 @@
 
 The exact configuration for pseudo-merges is as follows:
 
-include::config/bitmap-pseudo-merge.txt[]
+include::config/bitmap-pseudo-merge.adoc[]
 
 === Examples
 
diff --git a/Documentation/gitprotocol-capabilities.txt b/Documentation/gitprotocol-capabilities.adoc
similarity index 100%
rename from Documentation/gitprotocol-capabilities.txt
rename to Documentation/gitprotocol-capabilities.adoc
diff --git a/Documentation/gitprotocol-common.txt b/Documentation/gitprotocol-common.adoc
similarity index 100%
rename from Documentation/gitprotocol-common.txt
rename to Documentation/gitprotocol-common.adoc
diff --git a/Documentation/gitprotocol-http.txt b/Documentation/gitprotocol-http.adoc
similarity index 100%
rename from Documentation/gitprotocol-http.txt
rename to Documentation/gitprotocol-http.adoc
diff --git a/Documentation/gitprotocol-pack.txt b/Documentation/gitprotocol-pack.adoc
similarity index 100%
rename from Documentation/gitprotocol-pack.txt
rename to Documentation/gitprotocol-pack.adoc
diff --git a/Documentation/gitprotocol-v2.txt b/Documentation/gitprotocol-v2.adoc
similarity index 91%
rename from Documentation/gitprotocol-v2.txt
rename to Documentation/gitprotocol-v2.adoc
index 1652fef..5598c93 100644
--- a/Documentation/gitprotocol-v2.txt
+++ b/Documentation/gitprotocol-v2.adoc
@@ -184,9 +184,13 @@
 the `agent` capability with a value `Y` (in the form `agent=Y`) in its
 request to the server (but it MUST NOT do so if the server did not
 advertise the agent capability). The `X` and `Y` strings may contain any
-printable ASCII characters except space (i.e., the byte range 32 < x <
-127), and are typically of the form "package/version" (e.g.,
-"git/1.8.3.1"). The agent strings are purely informative for statistics
+printable ASCII characters except space (i.e., the byte range 33 <= x <=
+126), and are typically of the form "package/version-os" (e.g.,
+"git/1.8.3.1-Linux") where `os` is the operating system name (e.g.,
+"Linux"). `X` and `Y` can be configured using the GIT_USER_AGENT
+environment variable and it takes priority. The `os` is
+retrieved using the 'sysname' field of the `uname(2)` system call
+or its equivalent. The agent strings are purely informative for statistics
 and debugging purposes, and MUST NOT be used to programmatically assume
 the presence or absence of particular features.
 
@@ -781,6 +785,60 @@
 save themselves and the server(s) the request(s) needed to inspect the
 headers of that bundle or bundles.
 
+promisor-remote=<pr-infos>
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The server may advertise some promisor remotes it is using or knows
+about to a client which may want to use them as its promisor remotes,
+instead of this repository. In this case <pr-infos> should be of the
+form:
+
+	pr-infos = pr-info | pr-infos ";" pr-info
+
+	pr-info = "name=" pr-name | "name=" pr-name "," "url=" pr-url
+
+where `pr-name` is the urlencoded name of a promisor remote, and
+`pr-url` the urlencoded URL of that promisor remote.
+
+In this case, if the client decides to use one or more promisor
+remotes the server advertised, it can reply with
+"promisor-remote=<pr-names>" where <pr-names> should be of the form:
+
+	pr-names = pr-name | pr-names ";" pr-name
+
+where `pr-name` is the urlencoded name of a promisor remote the server
+advertised and the client accepts.
+
+Note that, everywhere in this document, `pr-name` MUST be a valid
+remote name, and the ';' and ',' characters MUST be encoded if they
+appear in `pr-name` or `pr-url`.
+
+If the server doesn't know any promisor remote that could be good for
+a client to use, or prefers a client not to use any promisor remote it
+uses or knows about, it shouldn't advertise the "promisor-remote"
+capability at all.
+
+In this case, or if the client doesn't want to use any promisor remote
+the server advertised, the client shouldn't advertise the
+"promisor-remote" capability at all in its reply.
+
+The "promisor.advertise" and "promisor.acceptFromServer" configuration
+options can be used on the server and client side to control what they
+advertise or accept respectively. See the documentation of these
+configuration options for more information.
+
+Note that in the future it would be nice if the "promisor-remote"
+protocol capability could be used by the server, when responding to
+`git fetch` or `git clone`, to advertise better-connected remotes that
+the client can use as promisor remotes, instead of this repository, so
+that the client can lazily fetch objects from these other
+better-connected remotes. This would require the server to omit in its
+response the objects available on the better-connected remotes that
+the client has accepted. This hasn't been implemented yet though. So
+for now this "promisor-remote" capability is useful only when the
+server advertises some promisor remotes it already uses to borrow
+objects from.
+
 GIT
 ---
 Part of the linkgit:git[1] suite
diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.adoc
similarity index 100%
rename from Documentation/gitremote-helpers.txt
rename to Documentation/gitremote-helpers.adoc
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.adoc
similarity index 96%
rename from Documentation/gitrepository-layout.txt
rename to Documentation/gitrepository-layout.adoc
index fa8b51d..7421ef9 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.adoc
@@ -152,8 +152,9 @@
 	working directory in multiple working directory setup (see
 	linkgit:git-worktree[1]).
 
+ifndef::with-breaking-changes[]
 branches::
-	A slightly deprecated way to store shorthands to be used
+	A deprecated way to store shorthands to be used
 	to specify a URL to 'git fetch', 'git pull' and 'git push'.
 	A file can be stored as `branches/<name>` and then
 	'name' can be given to these commands in place of
@@ -162,7 +163,9 @@
 	and not likely to be found in modern repositories. This
 	directory is ignored if $GIT_COMMON_DIR is set and
 	"$GIT_COMMON_DIR/branches" will be used instead.
-
++
+Git will stop reading remotes from this directory in Git 3.0.
+endif::with-breaking-changes[]
 
 hooks::
 	Hooks are customization scripts used by various Git
@@ -230,6 +233,7 @@
 	This file stores sparse checkout patterns.
 	See also: linkgit:git-read-tree[1].
 
+ifndef::with-breaking-changes[]
 remotes::
 	Stores shorthands for URL and default refnames for use
 	when interacting with remote repositories via 'git fetch',
@@ -238,6 +242,9 @@
 	and not likely to be found in modern repositories. This
 	directory is ignored if $GIT_COMMON_DIR is set and
 	"$GIT_COMMON_DIR/remotes" will be used instead.
++
+Git will stop reading remotes from this directory in Git 3.0.
+endif::with-breaking-changes[]
 
 logs::
 	Records of changes made to refs are stored in this directory.
@@ -292,7 +299,7 @@
 worktrees/<id>/config.worktree::
 	Working directory specific configuration file.
 
-include::technical/repository-version.txt[]
+include::technical/repository-version.adoc[]
 
 SEE ALSO
 --------
diff --git a/Documentation/gitrevisions.txt b/Documentation/gitrevisions.adoc
similarity index 96%
rename from Documentation/gitrevisions.txt
rename to Documentation/gitrevisions.adoc
index d407b7d..7146117 100644
--- a/Documentation/gitrevisions.txt
+++ b/Documentation/gitrevisions.adoc
@@ -24,7 +24,7 @@
 other objects than commits, e.g. blobs ("files") or trees
 ("directories of files").
 
-include::revisions.txt[]
+include::revisions.adoc[]
 
 
 SEE ALSO
diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.adoc
similarity index 100%
rename from Documentation/gitsubmodules.txt
rename to Documentation/gitsubmodules.adoc
diff --git a/Documentation/gittutorial-2.txt b/Documentation/gittutorial-2.adoc
similarity index 100%
rename from Documentation/gittutorial-2.txt
rename to Documentation/gittutorial-2.adoc
diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.adoc
similarity index 100%
rename from Documentation/gittutorial.txt
rename to Documentation/gittutorial.adoc
diff --git a/Documentation/gitweb.txt b/Documentation/gitweb.adoc
similarity index 100%
rename from Documentation/gitweb.txt
rename to Documentation/gitweb.adoc
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.adoc
similarity index 100%
rename from Documentation/gitweb.conf.txt
rename to Documentation/gitweb.conf.adoc
diff --git a/Documentation/gitworkflows.txt b/Documentation/gitworkflows.adoc
similarity index 100%
rename from Documentation/gitworkflows.txt
rename to Documentation/gitworkflows.adoc
diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.adoc
similarity index 100%
rename from Documentation/glossary-content.txt
rename to Documentation/glossary-content.adoc
diff --git a/Documentation/howto/coordinate-embargoed-releases.txt b/Documentation/howto/coordinate-embargoed-releases.adoc
similarity index 100%
rename from Documentation/howto/coordinate-embargoed-releases.txt
rename to Documentation/howto/coordinate-embargoed-releases.adoc
diff --git a/Documentation/howto/howto-index.sh b/Documentation/howto/howto-index.sh
index eecd123..ace4983 100755
--- a/Documentation/howto/howto-index.sh
+++ b/Documentation/howto/howto-index.sh
@@ -9,9 +9,9 @@
 
 EOF
 
-for txt
+for adoc
 do
-	title=$(expr "$txt" : '.*/\(.*\)\.txt$')
+	title=$(expr "$adoc" : '.*/\(.*\)\.adoc$')
 	from=$(sed -ne '
 	/^$/q
 	/^From:[ 	]/{
@@ -21,7 +21,7 @@
 		s/^/by /
 		p
 	}
-	' "$txt")
+	' "$adoc")
 
 	abstract=$(sed -ne '
 	/^Abstract:[ 	]/{
@@ -39,13 +39,13 @@
 		x
 		p
 		q
-	}' "$txt")
+	}' "$adoc")
 
-	if grep 'Content-type: text/asciidoc' >/dev/null $txt
+	if grep 'Content-type: text/asciidoc' >/dev/null $adoc
 	then
-		file=$(expr "$txt" : '\(.*\)\.txt$').html
+		file=$(expr "$adoc" : '\(.*\)\.adoc$').html
 	else
-		file="$txt"
+		file="$adoc"
 	fi
 
 	echo "* link:howto/$(basename "$file")[$title] $from
diff --git a/Documentation/howto/keep-canonical-history-correct.txt b/Documentation/howto/keep-canonical-history-correct.adoc
similarity index 100%
rename from Documentation/howto/keep-canonical-history-correct.txt
rename to Documentation/howto/keep-canonical-history-correct.adoc
diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.adoc
similarity index 100%
rename from Documentation/howto/maintain-git.txt
rename to Documentation/howto/maintain-git.adoc
diff --git a/Documentation/howto/meson.build b/Documentation/howto/meson.build
index c023c10..8100002 100644
--- a/Documentation/howto/meson.build
+++ b/Documentation/howto/meson.build
@@ -1,20 +1,20 @@
 howto_sources = [
-  'coordinate-embargoed-releases.txt',
-  'keep-canonical-history-correct.txt',
-  'maintain-git.txt',
-  'new-command.txt',
-  'rebase-from-internal-branch.txt',
-  'rebuild-from-update-hook.txt',
-  'recover-corrupted-blob-object.txt',
-  'recover-corrupted-object-harder.txt',
-  'revert-a-faulty-merge.txt',
-  'revert-branch-rebase.txt',
-  'separating-topic-branches.txt',
-  'setup-git-server-over-http.txt',
-  'update-hook-example.txt',
-  'use-git-daemon.txt',
-  'using-merge-subtree.txt',
-  'using-signed-tag-in-pull-request.txt',
+  'coordinate-embargoed-releases.adoc',
+  'keep-canonical-history-correct.adoc',
+  'maintain-git.adoc',
+  'new-command.adoc',
+  'rebase-from-internal-branch.adoc',
+  'rebuild-from-update-hook.adoc',
+  'recover-corrupted-blob-object.adoc',
+  'recover-corrupted-object-harder.adoc',
+  'revert-a-faulty-merge.adoc',
+  'revert-branch-rebase.adoc',
+  'separating-topic-branches.adoc',
+  'setup-git-server-over-http.adoc',
+  'update-hook-example.adoc',
+  'use-git-daemon.adoc',
+  'using-merge-subtree.adoc',
+  'using-signed-tag-in-pull-request.adoc',
 ]
 
 howto_index = custom_target(
@@ -26,7 +26,7 @@
   env: script_environment,
   capture: true,
   input: howto_sources,
-  output: 'howto-index.txt',
+  output: 'howto-index.adoc',
 )
 
 custom_target(
@@ -41,7 +41,7 @@
 foreach howto : howto_sources
   howto_stripped = custom_target(
     command: [
-      find_program('sed'),
+      sed,
       '-e',
       '1,/^$/d',
       '@INPUT@',
diff --git a/Documentation/howto/new-command.txt b/Documentation/howto/new-command.adoc
similarity index 98%
rename from Documentation/howto/new-command.txt
rename to Documentation/howto/new-command.adoc
index 880c511..ac73c98 100644
--- a/Documentation/howto/new-command.txt
+++ b/Documentation/howto/new-command.adoc
@@ -48,7 +48,7 @@
 to find things.
 
 See the CodingGuidelines document for other guidance on what we consider
-good practice in C and shell, and api-builtin.txt for the support
+good practice in C and shell, and builtin.h for the support
 functions available to built-in commands written in C.
 
 What every extension command needs
diff --git a/Documentation/howto/rebase-from-internal-branch.txt b/Documentation/howto/rebase-from-internal-branch.adoc
similarity index 100%
rename from Documentation/howto/rebase-from-internal-branch.txt
rename to Documentation/howto/rebase-from-internal-branch.adoc
diff --git a/Documentation/howto/rebuild-from-update-hook.txt b/Documentation/howto/rebuild-from-update-hook.adoc
similarity index 100%
rename from Documentation/howto/rebuild-from-update-hook.txt
rename to Documentation/howto/rebuild-from-update-hook.adoc
diff --git a/Documentation/howto/recover-corrupted-blob-object.txt b/Documentation/howto/recover-corrupted-blob-object.adoc
similarity index 100%
rename from Documentation/howto/recover-corrupted-blob-object.txt
rename to Documentation/howto/recover-corrupted-blob-object.adoc
diff --git a/Documentation/howto/recover-corrupted-object-harder.txt b/Documentation/howto/recover-corrupted-object-harder.adoc
similarity index 100%
rename from Documentation/howto/recover-corrupted-object-harder.txt
rename to Documentation/howto/recover-corrupted-object-harder.adoc
diff --git a/Documentation/howto/revert-a-faulty-merge.txt b/Documentation/howto/revert-a-faulty-merge.adoc
similarity index 100%
rename from Documentation/howto/revert-a-faulty-merge.txt
rename to Documentation/howto/revert-a-faulty-merge.adoc
diff --git a/Documentation/howto/revert-branch-rebase.txt b/Documentation/howto/revert-branch-rebase.adoc
similarity index 100%
rename from Documentation/howto/revert-branch-rebase.txt
rename to Documentation/howto/revert-branch-rebase.adoc
diff --git a/Documentation/howto/separating-topic-branches.txt b/Documentation/howto/separating-topic-branches.adoc
similarity index 100%
rename from Documentation/howto/separating-topic-branches.txt
rename to Documentation/howto/separating-topic-branches.adoc
diff --git a/Documentation/howto/setup-git-server-over-http.txt b/Documentation/howto/setup-git-server-over-http.adoc
similarity index 100%
rename from Documentation/howto/setup-git-server-over-http.txt
rename to Documentation/howto/setup-git-server-over-http.adoc
diff --git a/Documentation/howto/update-hook-example.txt b/Documentation/howto/update-hook-example.adoc
similarity index 100%
rename from Documentation/howto/update-hook-example.txt
rename to Documentation/howto/update-hook-example.adoc
diff --git a/Documentation/howto/use-git-daemon.txt b/Documentation/howto/use-git-daemon.adoc
similarity index 100%
rename from Documentation/howto/use-git-daemon.txt
rename to Documentation/howto/use-git-daemon.adoc
diff --git a/Documentation/howto/using-merge-subtree.txt b/Documentation/howto/using-merge-subtree.adoc
similarity index 100%
rename from Documentation/howto/using-merge-subtree.txt
rename to Documentation/howto/using-merge-subtree.adoc
diff --git a/Documentation/howto/using-signed-tag-in-pull-request.txt b/Documentation/howto/using-signed-tag-in-pull-request.adoc
similarity index 100%
rename from Documentation/howto/using-signed-tag-in-pull-request.txt
rename to Documentation/howto/using-signed-tag-in-pull-request.adoc
diff --git a/Documentation/i18n.txt b/Documentation/i18n.adoc
similarity index 95%
rename from Documentation/i18n.txt
rename to Documentation/i18n.adoc
index 3a866af..baff780 100644
--- a/Documentation/i18n.txt
+++ b/Documentation/i18n.adoc
@@ -34,7 +34,7 @@
 does not forbid it.  However, there are a few things to keep in
 mind.
 
-. 'git commit' and 'git commit-tree' issue
+. `git commit` and `git commit-tree` issue
   a warning if the commit log message given to it does not look
   like a valid UTF-8 string, unless you explicitly say your
   project uses a legacy encoding.  The way to say this is to
@@ -50,7 +50,7 @@
 help other people who look at them later.  Lack of this header
 implies that the commit log message is encoded in UTF-8.
 
-. 'git log', 'git show', 'git blame' and friends look at the
+. `git log`, `git show`, `git blame` and friends look at the
   `encoding` header of a commit object, and try to re-code the
   log message into UTF-8 unless otherwise specified.  You can
   specify the desired output encoding with
diff --git a/Documentation/includes/cmd-config-section-all.txt b/Documentation/includes/cmd-config-section-all.adoc
similarity index 100%
rename from Documentation/includes/cmd-config-section-all.txt
rename to Documentation/includes/cmd-config-section-all.adoc
diff --git a/Documentation/includes/cmd-config-section-rest.txt b/Documentation/includes/cmd-config-section-rest.adoc
similarity index 100%
rename from Documentation/includes/cmd-config-section-rest.txt
rename to Documentation/includes/cmd-config-section-rest.adoc
diff --git a/Documentation/install-webdoc.sh b/Documentation/install-webdoc.sh
index ed8b4ff..b237b31 100755
--- a/Documentation/install-webdoc.sh
+++ b/Documentation/install-webdoc.sh
@@ -3,10 +3,10 @@
 T="$1"
 
 for h in \
-	*.txt *.html \
-	howto/*.txt howto/*.html \
-	technical/*.txt technical/*.html \
-	RelNotes/*.txt *.css
+	*.adoc *.html \
+	howto/*.adoc howto/*.html \
+	technical/*.adoc technical/*.html \
+	RelNotes/*.adoc *.css
 do
 	if test ! -f "$h"
 	then
@@ -24,13 +24,13 @@
 done
 strip_leading=$(echo "$T/" | sed -e 's|.|.|g')
 for th in \
-	"$T"/*.html "$T"/*.txt \
-	"$T"/howto/*.txt "$T"/howto/*.html \
-	"$T"/technical/*.txt "$T"/technical/*.html
+	"$T"/*.html "$T"/*.adoc \
+	"$T"/howto/*.adoc "$T"/howto/*.html \
+	"$T"/technical/*.adoc "$T"/technical/*.html
 do
 	h=$(expr "$th" : "$strip_leading"'\(.*\)')
 	case "$h" in
-	RelNotes-*.txt | index.html) continue ;;
+	RelNotes-*.adoc | index.html) continue ;;
 	esac
 	test -f "$h" && continue
 	echo >&2 "# rm -f $th"
diff --git a/Documentation/line-range-format.txt b/Documentation/line-range-format.adoc
similarity index 100%
rename from Documentation/line-range-format.txt
rename to Documentation/line-range-format.adoc
diff --git a/Documentation/line-range-options.txt b/Documentation/line-range-options.adoc
similarity index 95%
rename from Documentation/line-range-options.txt
rename to Documentation/line-range-options.adoc
index 8e295a6..f275df3 100644
--- a/Documentation/line-range-options.txt
+++ b/Documentation/line-range-options.adoc
@@ -12,4 +12,4 @@
 	(namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`,
 	`--name-only`, `--name-status`, `--check`) are not currently implemented.
 +
-include::line-range-format.txt[]
+include::line-range-format.adoc[]
diff --git a/Documentation/lint-gitlink.perl b/Documentation/lint-gitlink.perl
index 1c61dd9..aea564d 100755
--- a/Documentation/lint-gitlink.perl
+++ b/Documentation/lint-gitlink.perl
@@ -5,7 +5,7 @@
 
 # Parse arguments, a simple state machine for input like:
 #
-# <file-to-check.txt> <valid-files-to-link-to> --section=1 git.txt git-add.txt [...] --to-lint git-add.txt a-file.txt [...]
+# <file-to-check.adoc> <valid-files-to-link-to> --section=1 git.adoc git-add.adoc [...] --to-lint git-add.adoc a-file.adoc [...]
 my %TXT;
 my %SECTION;
 my $section;
@@ -17,7 +17,7 @@
 		next;
 	}
 
-	my ($name) = $arg =~ /^(.*?)\.txt$/s;
+	my ($name) = $arg =~ /^(.*?)\.adoc$/s;
 	unless (defined $section) {
 		$TXT{$name} = $arg;
 		next;
diff --git a/Documentation/lint-manpages.sh b/Documentation/lint-manpages.sh
index 92cfc0a..a0ea572 100755
--- a/Documentation/lint-manpages.sh
+++ b/Documentation/lint-manpages.sh
@@ -31,7 +31,7 @@
 		git-?*--?* ) continue ;;
 		esac
 
-		if ! test -f "$v.txt"
+		if ! test -f "$v.adoc"
 		then
 			echo "no doc: $v"
 			ret=1
@@ -63,9 +63,9 @@
 		    -e 's/[ 	].*//' \
 		    -e 's/^/listed /' ../command-list.txt
 		make print-man1 |
-		grep '\.txt$' |
+		grep '\.adoc$' |
 		sed -e 's|^|documented |' \
-		    -e 's/\.txt//'
+		    -e 's/\.adoc//'
 	) | (
 		all_commands="$(printf "%s " "$ALL_COMMANDS" "$BUILT_INS" "$EXCLUDED_PROGRAMS" | tr '\n' ' ')"
 		ret=0
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.adoc
similarity index 99%
rename from Documentation/merge-options.txt
rename to Documentation/merge-options.adoc
index 3eaefc4..0022185 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.adoc
@@ -102,7 +102,7 @@
 With --no-log do not list one-line descriptions from the
 actual commits being merged.
 
-include::signoff-option.txt[]
+include::signoff-option.adoc[]
 
 --stat::
 -n::
diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.adoc
similarity index 92%
rename from Documentation/merge-strategies.txt
rename to Documentation/merge-strategies.adoc
index 5fc54ec..93822eb 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.adoc
@@ -22,6 +22,13 @@
 	was written as a replacement for the previous default
 	algorithm, `recursive`.
 +
+In the case where the path is a submodule, if the submodule commit used on
+one side of the merge is a descendant of the submodule commit used on the
+other side of the merge, Git attempts to fast-forward to the
+descendant. Otherwise, Git will treat this case as a conflict, suggesting
+as a resolution a submodule commit that is descendant of the conflicting
+ones, if one exists.
++
 The 'ort' strategy can take the following options:
 
 ours;;
@@ -56,7 +63,7 @@
 
 renormalize;;
 	This runs a virtual check-out and check-in of all three stages
-	of a file when resolving a three-way merge.  This option is
+	of any file which needs a three-way merge.  This option is
 	meant to be used when merging branches with different clean
 	filters or end-of-line normalization rules.  See "Merging
 	branches with differing checkin/checkout attributes" in
@@ -96,6 +103,9 @@
 	the default strategy for resolving two heads from Git v0.99.9k
 	until v2.33.0.
 +
+For a path that is a submodule, the same caution as 'ort' applies to this
+strategy.
++
 The 'recursive' strategy takes the same options as 'ort'.  However,
 there are three additional options that 'ort' ignores (not documented
 above) that are potentially useful with the 'recursive' strategy:
diff --git a/Documentation/mergetools/vimdiff.txt b/Documentation/mergetools/vimdiff.adoc
similarity index 100%
rename from Documentation/mergetools/vimdiff.txt
rename to Documentation/mergetools/vimdiff.adoc
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 2a26fa8..594546d 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -1,214 +1,215 @@
 manpages = {
   # Category 1.
-  'git-add.txt' : 1,
-  'git-am.txt' : 1,
-  'git-annotate.txt' : 1,
-  'git-apply.txt' : 1,
-  'git-archimport.txt' : 1,
-  'git-archive.txt' : 1,
-  'git-bisect.txt' : 1,
-  'git-blame.txt' : 1,
-  'git-branch.txt' : 1,
-  'git-bugreport.txt' : 1,
-  'git-bundle.txt' : 1,
-  'git-cat-file.txt' : 1,
-  'git-check-attr.txt' : 1,
-  'git-check-ignore.txt' : 1,
-  'git-check-mailmap.txt' : 1,
-  'git-checkout-index.txt' : 1,
-  'git-checkout.txt' : 1,
-  'git-check-ref-format.txt' : 1,
-  'git-cherry-pick.txt' : 1,
-  'git-cherry.txt' : 1,
-  'git-citool.txt' : 1,
-  'git-clean.txt' : 1,
-  'git-clone.txt' : 1,
-  'git-column.txt' : 1,
-  'git-commit-graph.txt' : 1,
-  'git-commit-tree.txt' : 1,
-  'git-commit.txt' : 1,
-  'git-config.txt' : 1,
-  'git-count-objects.txt' : 1,
-  'git-credential-cache--daemon.txt' : 1,
-  'git-credential-cache.txt' : 1,
-  'git-credential-store.txt' : 1,
-  'git-credential.txt' : 1,
-  'git-cvsexportcommit.txt' : 1,
-  'git-cvsimport.txt' : 1,
-  'git-cvsserver.txt' : 1,
-  'git-daemon.txt' : 1,
-  'git-describe.txt' : 1,
-  'git-diagnose.txt' : 1,
-  'git-diff-files.txt' : 1,
-  'git-diff-index.txt' : 1,
-  'git-difftool.txt' : 1,
-  'git-diff-tree.txt' : 1,
-  'git-diff.txt' : 1,
-  'git-fast-export.txt' : 1,
-  'git-fast-import.txt' : 1,
-  'git-fetch-pack.txt' : 1,
-  'git-fetch.txt' : 1,
-  'git-filter-branch.txt' : 1,
-  'git-fmt-merge-msg.txt' : 1,
-  'git-for-each-ref.txt' : 1,
-  'git-for-each-repo.txt' : 1,
-  'git-format-patch.txt' : 1,
-  'git-fsck-objects.txt' : 1,
-  'git-fsck.txt' : 1,
-  'git-fsmonitor--daemon.txt' : 1,
-  'git-gc.txt' : 1,
-  'git-get-tar-commit-id.txt' : 1,
-  'git-grep.txt' : 1,
-  'git-gui.txt' : 1,
-  'git-hash-object.txt' : 1,
-  'git-help.txt' : 1,
-  'git-hook.txt' : 1,
-  'git-http-backend.txt' : 1,
-  'git-http-fetch.txt' : 1,
-  'git-http-push.txt' : 1,
-  'git-imap-send.txt' : 1,
-  'git-index-pack.txt' : 1,
-  'git-init-db.txt' : 1,
-  'git-init.txt' : 1,
-  'git-instaweb.txt' : 1,
-  'git-interpret-trailers.txt' : 1,
-  'git-log.txt' : 1,
-  'git-ls-files.txt' : 1,
-  'git-ls-remote.txt' : 1,
-  'git-ls-tree.txt' : 1,
-  'git-mailinfo.txt' : 1,
-  'git-mailsplit.txt' : 1,
-  'git-maintenance.txt' : 1,
-  'git-merge-base.txt' : 1,
-  'git-merge-file.txt' : 1,
-  'git-merge-index.txt' : 1,
-  'git-merge-one-file.txt' : 1,
-  'git-mergetool--lib.txt' : 1,
-  'git-mergetool.txt' : 1,
-  'git-merge-tree.txt' : 1,
-  'git-merge.txt' : 1,
-  'git-mktag.txt' : 1,
-  'git-mktree.txt' : 1,
-  'git-multi-pack-index.txt' : 1,
-  'git-mv.txt' : 1,
-  'git-name-rev.txt' : 1,
-  'git-notes.txt' : 1,
-  'git-p4.txt' : 1,
-  'git-pack-objects.txt' : 1,
-  'git-pack-redundant.txt' : 1,
-  'git-pack-refs.txt' : 1,
-  'git-patch-id.txt' : 1,
-  'git-prune-packed.txt' : 1,
-  'git-prune.txt' : 1,
-  'git-pull.txt' : 1,
-  'git-push.txt' : 1,
-  'git-quiltimport.txt' : 1,
-  'git-range-diff.txt' : 1,
-  'git-read-tree.txt' : 1,
-  'git-rebase.txt' : 1,
-  'git-receive-pack.txt' : 1,
-  'git-reflog.txt' : 1,
-  'git-refs.txt' : 1,
-  'git-remote-ext.txt' : 1,
-  'git-remote-fd.txt' : 1,
-  'git-remote.txt' : 1,
-  'git-repack.txt' : 1,
-  'git-replace.txt' : 1,
-  'git-replay.txt' : 1,
-  'git-request-pull.txt' : 1,
-  'git-rerere.txt' : 1,
-  'git-reset.txt' : 1,
-  'git-restore.txt' : 1,
-  'git-revert.txt' : 1,
-  'git-rev-list.txt' : 1,
-  'git-rev-parse.txt' : 1,
-  'git-rm.txt' : 1,
-  'git-send-email.txt' : 1,
-  'git-send-pack.txt' : 1,
-  'git-shell.txt' : 1,
-  'git-sh-i18n--envsubst.txt' : 1,
-  'git-sh-i18n.txt' : 1,
-  'git-shortlog.txt' : 1,
-  'git-show-branch.txt' : 1,
-  'git-show-index.txt' : 1,
-  'git-show-ref.txt' : 1,
-  'git-show.txt' : 1,
-  'git-sh-setup.txt' : 1,
-  'git-sparse-checkout.txt' : 1,
-  'git-stage.txt' : 1,
-  'git-stash.txt' : 1,
-  'git-status.txt' : 1,
-  'git-stripspace.txt' : 1,
-  'git-submodule.txt' : 1,
-  'git-svn.txt' : 1,
-  'git-switch.txt' : 1,
-  'git-symbolic-ref.txt' : 1,
-  'git-tag.txt' : 1,
-  'git-unpack-file.txt' : 1,
-  'git-unpack-objects.txt' : 1,
-  'git-update-index.txt' : 1,
-  'git-update-ref.txt' : 1,
-  'git-update-server-info.txt' : 1,
-  'git-upload-archive.txt' : 1,
-  'git-upload-pack.txt' : 1,
-  'git-var.txt' : 1,
-  'git-verify-commit.txt' : 1,
-  'git-verify-pack.txt' : 1,
-  'git-verify-tag.txt' : 1,
-  'git-version.txt' : 1,
-  'git-web--browse.txt' : 1,
-  'git-whatchanged.txt' : 1,
-  'git-worktree.txt' : 1,
-  'git-write-tree.txt' : 1,
-  'git.txt' : 1,
-  'gitk.txt' : 1,
-  'gitweb.txt' : 1,
-  'scalar.txt' : 1,
+  'git-add.adoc' : 1,
+  'git-am.adoc' : 1,
+  'git-annotate.adoc' : 1,
+  'git-apply.adoc' : 1,
+  'git-archimport.adoc' : 1,
+  'git-archive.adoc' : 1,
+  'git-backfill.adoc' : 1,
+  'git-bisect.adoc' : 1,
+  'git-blame.adoc' : 1,
+  'git-branch.adoc' : 1,
+  'git-bugreport.adoc' : 1,
+  'git-bundle.adoc' : 1,
+  'git-cat-file.adoc' : 1,
+  'git-check-attr.adoc' : 1,
+  'git-check-ignore.adoc' : 1,
+  'git-check-mailmap.adoc' : 1,
+  'git-checkout-index.adoc' : 1,
+  'git-checkout.adoc' : 1,
+  'git-check-ref-format.adoc' : 1,
+  'git-cherry-pick.adoc' : 1,
+  'git-cherry.adoc' : 1,
+  'git-citool.adoc' : 1,
+  'git-clean.adoc' : 1,
+  'git-clone.adoc' : 1,
+  'git-column.adoc' : 1,
+  'git-commit-graph.adoc' : 1,
+  'git-commit-tree.adoc' : 1,
+  'git-commit.adoc' : 1,
+  'git-config.adoc' : 1,
+  'git-count-objects.adoc' : 1,
+  'git-credential-cache--daemon.adoc' : 1,
+  'git-credential-cache.adoc' : 1,
+  'git-credential-store.adoc' : 1,
+  'git-credential.adoc' : 1,
+  'git-cvsexportcommit.adoc' : 1,
+  'git-cvsimport.adoc' : 1,
+  'git-cvsserver.adoc' : 1,
+  'git-daemon.adoc' : 1,
+  'git-describe.adoc' : 1,
+  'git-diagnose.adoc' : 1,
+  'git-diff-files.adoc' : 1,
+  'git-diff-index.adoc' : 1,
+  'git-difftool.adoc' : 1,
+  'git-diff-tree.adoc' : 1,
+  'git-diff.adoc' : 1,
+  'git-fast-export.adoc' : 1,
+  'git-fast-import.adoc' : 1,
+  'git-fetch-pack.adoc' : 1,
+  'git-fetch.adoc' : 1,
+  'git-filter-branch.adoc' : 1,
+  'git-fmt-merge-msg.adoc' : 1,
+  'git-for-each-ref.adoc' : 1,
+  'git-for-each-repo.adoc' : 1,
+  'git-format-patch.adoc' : 1,
+  'git-fsck-objects.adoc' : 1,
+  'git-fsck.adoc' : 1,
+  'git-fsmonitor--daemon.adoc' : 1,
+  'git-gc.adoc' : 1,
+  'git-get-tar-commit-id.adoc' : 1,
+  'git-grep.adoc' : 1,
+  'git-gui.adoc' : 1,
+  'git-hash-object.adoc' : 1,
+  'git-help.adoc' : 1,
+  'git-hook.adoc' : 1,
+  'git-http-backend.adoc' : 1,
+  'git-http-fetch.adoc' : 1,
+  'git-http-push.adoc' : 1,
+  'git-imap-send.adoc' : 1,
+  'git-index-pack.adoc' : 1,
+  'git-init-db.adoc' : 1,
+  'git-init.adoc' : 1,
+  'git-instaweb.adoc' : 1,
+  'git-interpret-trailers.adoc' : 1,
+  'git-log.adoc' : 1,
+  'git-ls-files.adoc' : 1,
+  'git-ls-remote.adoc' : 1,
+  'git-ls-tree.adoc' : 1,
+  'git-mailinfo.adoc' : 1,
+  'git-mailsplit.adoc' : 1,
+  'git-maintenance.adoc' : 1,
+  'git-merge-base.adoc' : 1,
+  'git-merge-file.adoc' : 1,
+  'git-merge-index.adoc' : 1,
+  'git-merge-one-file.adoc' : 1,
+  'git-mergetool--lib.adoc' : 1,
+  'git-mergetool.adoc' : 1,
+  'git-merge-tree.adoc' : 1,
+  'git-merge.adoc' : 1,
+  'git-mktag.adoc' : 1,
+  'git-mktree.adoc' : 1,
+  'git-multi-pack-index.adoc' : 1,
+  'git-mv.adoc' : 1,
+  'git-name-rev.adoc' : 1,
+  'git-notes.adoc' : 1,
+  'git-p4.adoc' : 1,
+  'git-pack-objects.adoc' : 1,
+  'git-pack-redundant.adoc' : 1,
+  'git-pack-refs.adoc' : 1,
+  'git-patch-id.adoc' : 1,
+  'git-prune-packed.adoc' : 1,
+  'git-prune.adoc' : 1,
+  'git-pull.adoc' : 1,
+  'git-push.adoc' : 1,
+  'git-quiltimport.adoc' : 1,
+  'git-range-diff.adoc' : 1,
+  'git-read-tree.adoc' : 1,
+  'git-rebase.adoc' : 1,
+  'git-receive-pack.adoc' : 1,
+  'git-reflog.adoc' : 1,
+  'git-refs.adoc' : 1,
+  'git-remote-ext.adoc' : 1,
+  'git-remote-fd.adoc' : 1,
+  'git-remote.adoc' : 1,
+  'git-repack.adoc' : 1,
+  'git-replace.adoc' : 1,
+  'git-replay.adoc' : 1,
+  'git-request-pull.adoc' : 1,
+  'git-rerere.adoc' : 1,
+  'git-reset.adoc' : 1,
+  'git-restore.adoc' : 1,
+  'git-revert.adoc' : 1,
+  'git-rev-list.adoc' : 1,
+  'git-rev-parse.adoc' : 1,
+  'git-rm.adoc' : 1,
+  'git-send-email.adoc' : 1,
+  'git-send-pack.adoc' : 1,
+  'git-shell.adoc' : 1,
+  'git-sh-i18n--envsubst.adoc' : 1,
+  'git-sh-i18n.adoc' : 1,
+  'git-shortlog.adoc' : 1,
+  'git-show-branch.adoc' : 1,
+  'git-show-index.adoc' : 1,
+  'git-show-ref.adoc' : 1,
+  'git-show.adoc' : 1,
+  'git-sh-setup.adoc' : 1,
+  'git-sparse-checkout.adoc' : 1,
+  'git-stage.adoc' : 1,
+  'git-stash.adoc' : 1,
+  'git-status.adoc' : 1,
+  'git-stripspace.adoc' : 1,
+  'git-submodule.adoc' : 1,
+  'git-svn.adoc' : 1,
+  'git-switch.adoc' : 1,
+  'git-symbolic-ref.adoc' : 1,
+  'git-tag.adoc' : 1,
+  'git-unpack-file.adoc' : 1,
+  'git-unpack-objects.adoc' : 1,
+  'git-update-index.adoc' : 1,
+  'git-update-ref.adoc' : 1,
+  'git-update-server-info.adoc' : 1,
+  'git-upload-archive.adoc' : 1,
+  'git-upload-pack.adoc' : 1,
+  'git-var.adoc' : 1,
+  'git-verify-commit.adoc' : 1,
+  'git-verify-pack.adoc' : 1,
+  'git-verify-tag.adoc' : 1,
+  'git-version.adoc' : 1,
+  'git-web--browse.adoc' : 1,
+  'git-whatchanged.adoc' : 1,
+  'git-worktree.adoc' : 1,
+  'git-write-tree.adoc' : 1,
+  'git.adoc' : 1,
+  'gitk.adoc' : 1,
+  'gitweb.adoc' : 1,
+  'scalar.adoc' : 1,
 
   # Category 5.
-  'gitattributes.txt' : 5,
-  'gitformat-bundle.txt' : 5,
-  'gitformat-chunk.txt' : 5,
-  'gitformat-commit-graph.txt' : 5,
-  'gitformat-index.txt' : 5,
-  'gitformat-pack.txt' : 5,
-  'gitformat-signature.txt' : 5,
-  'githooks.txt' : 5,
-  'gitignore.txt' : 5,
-  'gitmailmap.txt' : 5,
-  'gitmodules.txt' : 5,
-  'gitprotocol-capabilities.txt' : 5,
-  'gitprotocol-common.txt' : 5,
-  'gitprotocol-http.txt' : 5,
-  'gitprotocol-pack.txt' : 5,
-  'gitprotocol-v2.txt' : 5,
-  'gitrepository-layout.txt' : 5,
-  'gitweb.conf.txt' : 5,
+  'gitattributes.adoc' : 5,
+  'gitformat-bundle.adoc' : 5,
+  'gitformat-chunk.adoc' : 5,
+  'gitformat-commit-graph.adoc' : 5,
+  'gitformat-index.adoc' : 5,
+  'gitformat-pack.adoc' : 5,
+  'gitformat-signature.adoc' : 5,
+  'githooks.adoc' : 5,
+  'gitignore.adoc' : 5,
+  'gitmailmap.adoc' : 5,
+  'gitmodules.adoc' : 5,
+  'gitprotocol-capabilities.adoc' : 5,
+  'gitprotocol-common.adoc' : 5,
+  'gitprotocol-http.adoc' : 5,
+  'gitprotocol-pack.adoc' : 5,
+  'gitprotocol-v2.adoc' : 5,
+  'gitrepository-layout.adoc' : 5,
+  'gitweb.conf.adoc' : 5,
 
   # Category 7.
-  'gitcli.txt' : 7,
-  'gitcore-tutorial.txt' : 7,
-  'gitcredentials.txt' : 7,
-  'gitcvs-migration.txt' : 7,
-  'gitdiffcore.txt' : 7,
-  'giteveryday.txt' : 7,
-  'gitfaq.txt' : 7,
-  'gitglossary.txt' : 7,
-  'gitpacking.txt' : 7,
-  'gitnamespaces.txt' : 7,
-  'gitremote-helpers.txt' : 7,
-  'gitrevisions.txt' : 7,
-  'gitsubmodules.txt' : 7,
-  'gittutorial-2.txt' : 7,
-  'gittutorial.txt' : 7,
-  'gitworkflows.txt' : 7,
+  'gitcli.adoc' : 7,
+  'gitcore-tutorial.adoc' : 7,
+  'gitcredentials.adoc' : 7,
+  'gitcvs-migration.adoc' : 7,
+  'gitdiffcore.adoc' : 7,
+  'giteveryday.adoc' : 7,
+  'gitfaq.adoc' : 7,
+  'gitglossary.adoc' : 7,
+  'gitpacking.adoc' : 7,
+  'gitnamespaces.adoc' : 7,
+  'gitremote-helpers.adoc' : 7,
+  'gitrevisions.adoc' : 7,
+  'gitsubmodules.adoc' : 7,
+  'gittutorial-2.adoc' : 7,
+  'gittutorial.adoc' : 7,
+  'gitworkflows.adoc' : 7,
 }
 
 docs_backend = get_option('docs_backend')
 if docs_backend == 'auto'
-  if find_program('asciidoc', required: false).found()
+  if find_program('asciidoc', dirs: program_path, required: false).found()
     docs_backend = 'asciidoc'
-  elif find_program('asciidoctor', required: false).found()
+  elif find_program('asciidoctor', dirs: program_path, required: false).found()
     docs_backend = 'asciidoctor'
   else
     error('Neither asciidoc nor asciidoctor were found.')
@@ -216,7 +217,7 @@
 endif
 
 if docs_backend == 'asciidoc'
-  asciidoc = find_program('asciidoc', required: true)
+  asciidoc = find_program('asciidoc', dirs: program_path)
   asciidoc_html = 'xhtml11'
   asciidoc_docbook = 'docbook'
   xmlto_extra = [ ]
@@ -245,7 +246,7 @@
     asciidoc_conf,
   ]
 elif docs_backend == 'asciidoctor'
-  asciidoctor = find_program('asciidoctor', required: true)
+  asciidoctor = find_program('asciidoctor', dirs: program_path)
   asciidoc_html = 'xhtml5'
   asciidoc_docbook = 'docbook5'
   xmlto_extra = [
@@ -283,22 +284,25 @@
   ]
 endif
 
-git = find_program('git', required: false)
-xmlto = find_program('xmlto')
+if get_option('breaking_changes')
+   asciidoc_common_options += ['--attribute', 'with-breaking-changes']
+endif
+
+xmlto = find_program('xmlto', dirs: program_path)
 
 cmd_lists = [
-  'cmds-ancillaryinterrogators.txt',
-  'cmds-ancillarymanipulators.txt',
-  'cmds-mainporcelain.txt',
-  'cmds-plumbinginterrogators.txt',
-  'cmds-plumbingmanipulators.txt',
-  'cmds-synchingrepositories.txt',
-  'cmds-synchelpers.txt',
-  'cmds-guide.txt',
-  'cmds-developerinterfaces.txt',
-  'cmds-userinterfaces.txt',
-  'cmds-purehelpers.txt',
-  'cmds-foreignscminterface.txt',
+  'cmds-ancillaryinterrogators.adoc',
+  'cmds-ancillarymanipulators.adoc',
+  'cmds-mainporcelain.adoc',
+  'cmds-plumbinginterrogators.adoc',
+  'cmds-plumbingmanipulators.adoc',
+  'cmds-synchingrepositories.adoc',
+  'cmds-synchelpers.adoc',
+  'cmds-guide.adoc',
+  'cmds-developerinterfaces.adoc',
+  'cmds-userinterfaces.adoc',
+  'cmds-purehelpers.adoc',
+  'cmds-foreignscminterface.adoc',
 ]
 
 documentation_deps += custom_target(
@@ -325,7 +329,7 @@
       'MERGE_TOOLS_DIR=' + meson.project_source_root() / 'mergetools',
     ],
     input: 'generate-mergetool-list.sh',
-    output: 'mergetools-' + mode + '.txt',
+    output: 'mergetools-' + mode + '.adoc',
   )
 endforeach
 
@@ -405,7 +409,7 @@
     pointing_to: 'git.html',
   )
 
-  xsltproc = find_program('xsltproc')
+  xsltproc = find_program('xsltproc', dirs: program_path)
 
   user_manual_xml = custom_target(
     command: asciidoc_common_options + [
@@ -414,7 +418,7 @@
       '--out-file=@OUTPUT@',
       '@INPUT@',
     ],
-    input: 'user-manual.txt',
+    input: 'user-manual.adoc',
     output: 'user-manual.xml',
     depends: documentation_deps,
   )
@@ -436,14 +440,14 @@
   )
 
   articles = [
-    'DecisionMaking.txt',
-    'MyFirstContribution.txt',
-    'MyFirstObjectWalk.txt',
-    'ReviewingGuidelines.txt',
+    'DecisionMaking.adoc',
+    'MyFirstContribution.adoc',
+    'MyFirstObjectWalk.adoc',
+    'ReviewingGuidelines.adoc',
     'SubmittingPatches',
-    'ToolsForGit.txt',
-    'git-bisect-lk2009.txt',
-    'git-tools.txt',
+    'ToolsForGit.adoc',
+    'git-bisect-lk2009.adoc',
+    'git-tools.adoc',
   ]
 
   foreach article : articles
@@ -475,8 +479,8 @@
 # Sanity check that we are not missing any tests present in 't/'. This check
 # only runs once at configure time and is thus best-effort, only. Furthermore,
 # it only verifies man pages for the sake of simplicity.
-configured_manpages = manpages.keys() + [ 'git-bisect-lk2009.txt', 'git-tools.txt' ]
-actual_manpages = run_command(shell, '-c', 'ls git*.txt scalar.txt',
+configured_manpages = manpages.keys() + [ 'git-bisect-lk2009.adoc', 'git-tools.adoc' ]
+actual_manpages = run_command(shell, '-c', 'ls git*.adoc scalar.adoc',
   check: true,
   env: script_environment,
 ).stdout().strip().split('\n')
diff --git a/Documentation/object-format-disclaimer.txt b/Documentation/object-format-disclaimer.adoc
similarity index 100%
rename from Documentation/object-format-disclaimer.txt
rename to Documentation/object-format-disclaimer.adoc
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.adoc
similarity index 98%
rename from Documentation/pretty-formats.txt
rename to Documentation/pretty-formats.adoc
index 8ee940b..07475de 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.adoc
@@ -339,10 +339,10 @@
 decoration format if `--decorate` was not already provided on the command
 line.
 
-The boolean options accept an optional value `[=<bool-value>]`. The values
-`true`, `false`, `on`, `off` etc. are all accepted. See the "boolean"
-sub-section in "EXAMPLES" in linkgit:git-config[1]. If a boolean
-option is given with no value, it's enabled.
+The boolean options accept an optional value `[=<bool-value>]`. The
+values taken by `--type=bool` git-config[1], like `yes` and `off`,
+are all accepted.  Giving a boolean option without `=<value>` is
+equivalent to giving it with `=true`.
 
 If you add a `+` (plus sign) after '%' of a placeholder, a line-feed
 is inserted immediately before the expansion if and only if the
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.adoc
similarity index 100%
rename from Documentation/pretty-options.txt
rename to Documentation/pretty-options.adoc
diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.adoc
similarity index 100%
rename from Documentation/pull-fetch-param.txt
rename to Documentation/pull-fetch-param.adoc
diff --git a/Documentation/ref-reachability-filters.txt b/Documentation/ref-reachability-filters.adoc
similarity index 100%
rename from Documentation/ref-reachability-filters.txt
rename to Documentation/ref-reachability-filters.adoc
diff --git a/Documentation/ref-storage-format.txt b/Documentation/ref-storage-format.adoc
similarity index 100%
rename from Documentation/ref-storage-format.txt
rename to Documentation/ref-storage-format.adoc
diff --git a/Documentation/rerere-options.txt b/Documentation/rerere-options.adoc
similarity index 100%
rename from Documentation/rerere-options.txt
rename to Documentation/rerere-options.adoc
diff --git a/Documentation/rev-list-description.txt b/Documentation/rev-list-description.adoc
similarity index 100%
rename from Documentation/rev-list-description.txt
rename to Documentation/rev-list-description.adoc
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.adoc
similarity index 97%
rename from Documentation/rev-list-options.txt
rename to Documentation/rev-list-options.adoc
index 459e5a0..785c078 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.adoc
@@ -1024,6 +1024,25 @@
 The form '--missing=print' is like 'allow-any', but will also print a
 list of the missing objects.  Object IDs are prefixed with a ``?'' character.
 +
+The form '--missing=print-info' is like 'print', but will also print additional
+information about the missing object inferred from its containing object. The
+information is all printed on the same line with the missing object ID in the
+form: `?<oid> [<token>=<value>]...`. The `<token>=<value>` pairs containing
+additional information are separated from each other by a SP. The value is
+encoded in a token specific fashion, but SP or LF contained in value are always
+expected to be represented in such a way that the resulting encoded value does
+not have either of these two problematic bytes. Each `<token>=<value>` may be
+one of the following:
++
+--
+* The `path=<path>` shows the path of the missing object inferred from a
+  containing object. A path containing SP or special characters is enclosed in
+  double-quotes in the C style as needed.
++
+* The `type=<type>` shows the type of the missing object inferred from a
+  containing object.
+--
++
 If some tips passed to the traversal are missing, they will be
 considered as missing too, and the traversal will ignore them. In case
 we cannot get their Object ID though, an error will be raised.
@@ -1059,7 +1078,7 @@
 linkgit:git-show[1], and linkgit:git-whatchanged[1]
 endif::git-rev-list[]
 
-include::pretty-options.txt[]
+include::pretty-options.adoc[]
 
 --relative-date::
 	Synonym for `--date=relative`.
diff --git a/Documentation/revisions.txt b/Documentation/revisions.adoc
similarity index 100%
rename from Documentation/revisions.txt
rename to Documentation/revisions.adoc
diff --git a/Documentation/scalar.txt b/Documentation/scalar.adoc
similarity index 100%
rename from Documentation/scalar.txt
rename to Documentation/scalar.adoc
diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.adoc
similarity index 100%
rename from Documentation/sequencer.txt
rename to Documentation/sequencer.adoc
diff --git a/Documentation/signoff-option.txt b/Documentation/signoff-option.adoc
similarity index 85%
rename from Documentation/signoff-option.txt
rename to Documentation/signoff-option.adoc
index d98758f..cddfb22 100644
--- a/Documentation/signoff-option.txt
+++ b/Documentation/signoff-option.adoc
@@ -1,8 +1,8 @@
 ifdef::git-commit[]
--s::
+`-s`::
 endif::git-commit[]
---signoff::
---no-signoff::
+`--signoff`::
+`--no-signoff`::
 	Add a `Signed-off-by` trailer by the committer at the end of the commit
 	log message.  The meaning of a signoff depends on the project
 	to which you're committing.  For example, it may certify that
@@ -14,5 +14,5 @@
 	leadership of the project to which you're contributing to
 	understand how the signoffs are used in that project.
 +
-The --no-signoff option can be used to countermand an earlier --signoff
+The `--no-signoff` option can be used to countermand an earlier `--signoff`
 option on the command line.
diff --git a/Documentation/technical/.gitignore b/Documentation/technical/.gitignore
index 8aa891d..3caef14 100644
--- a/Documentation/technical/.gitignore
+++ b/Documentation/technical/.gitignore
@@ -1 +1,2 @@
 api-index.txt
+api-index.adoc
diff --git a/Documentation/technical/api-error-handling.txt b/Documentation/technical/api-error-handling.adoc
similarity index 100%
rename from Documentation/technical/api-error-handling.txt
rename to Documentation/technical/api-error-handling.adoc
diff --git a/Documentation/technical/api-index-skel.txt b/Documentation/technical/api-index-skel.adoc
similarity index 100%
rename from Documentation/technical/api-index-skel.txt
rename to Documentation/technical/api-index-skel.adoc
diff --git a/Documentation/technical/api-index.sh b/Documentation/technical/api-index.sh
index 2964885..dd206b1 100755
--- a/Documentation/technical/api-index.sh
+++ b/Documentation/technical/api-index.sh
@@ -13,18 +13,18 @@
 	cd "$SOURCE_DIR"
 
 	c=////////////////////////////////////////////////////////////////
-	skel=api-index-skel.txt
+	skel=api-index-skel.adoc
 	sed -e '/^\/\/ table of contents begin/q' "$skel"
 	echo "$c"
 
-	ls api-*.txt |
+	ls api-*.adoc |
 	while read filename
 	do
 		case "$filename" in
-		api-index-skel.txt | api-index.txt) continue ;;
+		api-index-skel.adoc | api-index.adoc) continue ;;
 		esac
 		title=$(sed -e 1q "$filename")
-		html=${filename%.txt}.html
+		html=${filename%.adoc}.html
 		echo "* link:$html[$title]"
 	done
 	echo "$c"
diff --git a/Documentation/technical/api-merge.txt b/Documentation/technical/api-merge.adoc
similarity index 100%
rename from Documentation/technical/api-merge.txt
rename to Documentation/technical/api-merge.adoc
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.adoc
similarity index 100%
rename from Documentation/technical/api-parse-options.txt
rename to Documentation/technical/api-parse-options.adoc
diff --git a/Documentation/technical/api-path-walk.adoc b/Documentation/technical/api-path-walk.adoc
new file mode 100644
index 0000000..3e08921
--- /dev/null
+++ b/Documentation/technical/api-path-walk.adoc
@@ -0,0 +1,72 @@
+Path-Walk API
+=============
+
+The path-walk API is used to walk reachable objects, but to visit objects
+in batches based on a common path they appear in, or by type.
+
+For example, all reachable commits are visited in a group. All tags are
+visited in a group. Then, all root trees are visited. At some point, all
+blobs reachable via a path `my/dir/to/A` are visited. When there are
+multiple paths possible to reach the same object, then only one of those
+paths is used to visit the object.
+
+Basics
+------
+
+To use the path-walk API, include `path-walk.h` and call
+`walk_objects_by_path()` with a customized `path_walk_info` struct. The
+struct is used to set all of the options for how the walk should proceed.
+Let's dig into the different options and their use.
+
+`path_fn` and `path_fn_data`::
+	The most important option is the `path_fn` option, which is a
+	function pointer to the callback that can execute logic on the
+	object IDs for objects grouped by type and path. This function
+	also receives a `data` value that corresponds to the
+	`path_fn_data` member, for providing custom data structures to
+	this callback function.
+
+`revs`::
+	To configure the exact details of the reachable set of objects,
+	use the `revs` member and initialize it using the revision
+	machinery in `revision.h`. Initialize `revs` using calls such as
+	`setup_revisions()` or `parse_revision_opt()`. Do not call
+	`prepare_revision_walk()`, as that will be called within
+	`walk_objects_by_path()`.
++
+It is also important that you do not specify the `--objects` flag for the
+`revs` struct. The revision walk should only be used to walk commits, and
+the objects will be walked in a separate way based on those starting
+commits.
+
+`commits`, `blobs`, `trees`, `tags`::
+	By default, these members are enabled and signal that the path-walk
+	API should call the `path_fn` on objects of these types. Specialized
+	applications could disable some options to make it simpler to walk
+	the objects or to have fewer calls to `path_fn`.
++
+While it is possible to walk only commits in this way, consumers would be
+better off using the revision walk API instead.
+
+`prune_all_uninteresting`::
+	By default, all reachable paths are emitted by the path-walk API.
+	This option allows consumers to declare that they are not
+	interested in paths where all included objects are marked with the
+	`UNINTERESTING` flag. This requires using the `boundary` option in
+	the revision walk so that the walk emits commits marked with the
+	`UNINTERESTING` flag.
+
+`pl`::
+	This pattern list pointer allows focusing the path-walk search to
+	a set of patterns, only emitting paths that match the given
+	patterns. See linkgit:gitignore[5] or
+	linkgit:git-sparse-checkout[1] for details about pattern lists.
+	When the pattern list uses cone-mode patterns, then the path-walk
+	API can prune the set of paths it walks to improve performance.
+
+Examples
+--------
+
+See example usages in:
+	`t/helper/test-path-walk.c`,
+	`builtin/backfill.c`
diff --git a/Documentation/technical/api-simple-ipc.txt b/Documentation/technical/api-simple-ipc.adoc
similarity index 98%
rename from Documentation/technical/api-simple-ipc.txt
rename to Documentation/technical/api-simple-ipc.adoc
index c4fb152..972178b 100644
--- a/Documentation/technical/api-simple-ipc.txt
+++ b/Documentation/technical/api-simple-ipc.adoc
@@ -36,7 +36,7 @@
 ---------------------------------
 
 The Simple-IPC mechanism differs from the existing `sub-process.c`
-model (Documentation/technical/long-running-process-protocol.txt) and
+model (Documentation/technical/long-running-process-protocol.adoc) and
 used by applications like Git-LFS.  In the LFS-style sub-process model,
 the helper is started by the foreground process, communication happens
 via a pair of file descriptors bound to the stdin/stdout of the
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.adoc
similarity index 99%
rename from Documentation/technical/api-trace2.txt
rename to Documentation/technical/api-trace2.adoc
index 5817b18..cf493da 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.adoc
@@ -140,7 +140,7 @@
 To enable a target, set the corresponding environment variable or
 system or global config value to one of the following:
 
-include::../trace2-target-values.txt[]
+include::../trace2-target-values.adoc[]
 
 When trace files are written to a target directory, they will be named according
 to the last component of the SID (optionally followed by a counter to avoid
diff --git a/Documentation/technical/bitmap-format.txt b/Documentation/technical/bitmap-format.adoc
similarity index 100%
rename from Documentation/technical/bitmap-format.txt
rename to Documentation/technical/bitmap-format.adoc
diff --git a/Documentation/technical/build-systems.txt b/Documentation/technical/build-systems.adoc
similarity index 100%
rename from Documentation/technical/build-systems.txt
rename to Documentation/technical/build-systems.adoc
diff --git a/Documentation/technical/bundle-uri.txt b/Documentation/technical/bundle-uri.adoc
similarity index 100%
rename from Documentation/technical/bundle-uri.txt
rename to Documentation/technical/bundle-uri.adoc
diff --git a/Documentation/technical/commit-graph.txt b/Documentation/technical/commit-graph.adoc
similarity index 100%
rename from Documentation/technical/commit-graph.txt
rename to Documentation/technical/commit-graph.adoc
diff --git a/Documentation/technical/directory-rename-detection.txt b/Documentation/technical/directory-rename-detection.adoc
similarity index 100%
rename from Documentation/technical/directory-rename-detection.txt
rename to Documentation/technical/directory-rename-detection.adoc
diff --git a/Documentation/technical/hash-function-transition.txt b/Documentation/technical/hash-function-transition.adoc
similarity index 99%
rename from Documentation/technical/hash-function-transition.txt
rename to Documentation/technical/hash-function-transition.adoc
index 7102c7c..f047fd8 100644
--- a/Documentation/technical/hash-function-transition.txt
+++ b/Documentation/technical/hash-function-transition.adoc
@@ -394,7 +394,7 @@
 
 Step 4 is probably necessary for good read-time performance. "git
 pack-objects" on the server optimizes the pack file for good data
-locality (see Documentation/technical/pack-heuristics.txt).
+locality (see Documentation/technical/pack-heuristics.adoc).
 
 Details of this process are likely to change. It will take some
 experimenting to get this to perform well.
diff --git a/Documentation/technical/large-object-promisors.adoc b/Documentation/technical/large-object-promisors.adoc
new file mode 100644
index 0000000..dea8daf
--- /dev/null
+++ b/Documentation/technical/large-object-promisors.adoc
@@ -0,0 +1,656 @@
+Large Object Promisors
+======================
+
+Since Git has been created, users have been complaining about issues
+with storing large files in Git. Some solutions have been created to
+help, but they haven't helped much with some issues.
+
+Git currently supports multiple promisor remotes, which could help
+with some of these remaining issues, but it's very hard to use them to
+help, because a number of important features are missing.
+
+The goal of the effort described in this document is to add these
+important features.
+
+We will call a "Large Object Promisor", or "LOP" in short, a promisor
+remote which is used to store only large blobs and which is separate
+from the main remote that should store the other Git objects and the
+rest of the repos.
+
+By extension, we will also call "Large Object Promisor", or LOP, the
+effort described in this document to add a set of features to make it
+easier to handle large blobs/files in Git by using LOPs.
+
+This effort aims to especially improve things on the server side, and
+especially for large blobs that are already compressed in a binary
+format.
+
+This effort aims to provide an alternative to Git LFS
+(https://git-lfs.com/) and similar tools like git-annex
+(https://git-annex.branchable.com/) for handling large files, even
+though a complete alternative would very likely require other efforts
+especially on the client side, where it would likely help to implement
+a new object representation for large blobs as discussed in:
+
+https://lore.kernel.org/git/xmqqbkdometi.fsf@gitster.g/
+
+0) Non goals
+------------
+
+- We will not discuss those client side improvements here, as they
+  would require changes in different parts of Git than this effort.
++
+So we don't pretend to fully replace Git LFS with only this effort,
+but we nevertheless believe that it can significantly improve the
+current situation on the server side, and that other separate
+efforts could also improve the situation on the client side.
+
+- In the same way, we are not going to discuss all the possible ways
+  to implement a LOP or their underlying object storage, or to
+  optimize how LOP works.
++
+Our opinion is that the simplest solution for now is for LOPs to use
+object storage through a remote helper (see section II.2 below for
+more details) to store their objects. So we consider that this is the
+default implementation. If there are improvements on top of this,
+that's great, but our opinion is that such improvements are not
+necessary for LOPs to already be useful. Such improvements are likely
+a different technical topic, and can be taken care of separately
+anyway.
++
+So in particular we are not going to discuss pluggable ODBs or other
+object database backends that could chunk large blobs, dedup the
+chunks and store them efficiently. Sure, that would be a nice
+improvement to store large blobs on the server side, but we believe
+it can just be a separate effort as it's also not technically very
+related to this effort.
++
+We are also not going to discuss data transfer improvements between
+LOPs and clients or servers. Sure, there might be some easy and very
+effective optimizations there (as we know that objects on LOPs are
+very likely incompressible and not deltifying well), but this can be
+dealt with separately in a separate effort.
+
+In other words, the goal of this document is not to talk about all the
+possible ways to optimize how Git could handle large blobs, but to
+describe how a LOP based solution can already work well and alleviate
+a number of current issues in the context of Git clients and servers
+sharing Git objects.
+
+Even if LOPs are used not very efficiently, they can still be useful
+and worth using in some cases, as we will see in more details
+later in this document:
+
+  - they can make it simpler for clients to use promisor remotes and
+    therefore avoid fetching a lot of large blobs they might not need
+    locally,
+
+  - they can make it significantly cheaper or easier for servers to
+    host a significant part of the current repository content, and
+    even more to host content with larger blobs or more large blobs
+    than currently.
+
+I) Issues with the current situation
+------------------------------------
+
+- Some statistics made on GitLab repos have shown that more than 75%
+  of the disk space is used by blobs that are larger than 1MB and
+  often in a binary format.
+
+- So even if users could use Git LFS or similar tools to store a lot
+  of large blobs out of their repos, it's a fact that in practice they
+  don't do it as much as they probably should.
+
+- On the server side ideally, the server should be able to decide for
+  itself how it stores things. It should not depend on users deciding
+  to use tools like Git LFS on some blobs or not.
+
+- It's much more expensive to store large blobs that don't delta
+  compress well on regular fast seeking drives (like SSDs) than on
+  object storage (like Amazon S3 or GCP Buckets). Using fast drives
+  for regular Git repos makes sense though, as serving regular Git
+  content (blobs containing text or code) needs drives where seeking
+  is fast, but the content is relatively small. On the other hand,
+  object storage for Git LFS blobs makes sense as seeking speed is not
+  as important when dealing with large files, while costs are more
+  important. So the fact that users don't use Git LFS or similar tools
+  for a significant number of large blobs has likely some bad
+  consequences on the cost of repo storage for most Git hosting
+  platforms.
+
+- Having large blobs handled in the same way as other blobs and Git
+  objects in Git repos instead of on object storage also has a cost in
+  increased memory and CPU usage, and therefore decreased performance,
+  when creating packfiles. (This is because Git tries to use delta
+  compression or zlib compression which is unlikely to work well on
+  already compressed binary content.) So it's not just a storage cost
+  increase.
+
+- When a large blob has been committed into a repo, it might not be
+  possible to remove this blob from the repo without rewriting
+  history, even if the user then decides to use Git LFS or a similar
+  tool to handle it.
+
+- In fact Git LFS and similar tools are not very flexible in letting
+  users change their minds about the blobs they should handle or not.
+
+- Even when users are using Git LFS or similar tools, they are often
+  complaining that these tools require significant effort to set up,
+  learn and use correctly.
+
+II) Main features of the "Large Object Promisors" solution
+----------------------------------------------------------
+
+The main features below should give a rough overview of how the
+solution may work. Details about needed elements can be found in
+following sections.
+
+Even if each feature below is very useful for the full solution, it is
+very likely to be also useful on its own in some cases where the full
+solution is not required. However, we'll focus primarily on the big
+picture here.
+
+Also each feature doesn't need to be implemented entirely in Git
+itself. Some could be scripts, hooks or helpers that are not part of
+the Git repo. It would be helpful if those could be shared and
+improved on collaboratively though. So we want to encourage sharing
+them.
+
+1) Large blobs are stored on LOPs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Large blobs should be stored on special promisor remotes that we will
+call "Large Object Promisors" or LOPs. These LOPs should be additional
+remotes dedicated to contain large blobs especially those in binary
+format. They should be used along with main remotes that contain the
+other objects.
+
+Note 1
+++++++
+
+To clarify, a LOP is a normal promisor remote, except that:
+
+- it should store only large blobs,
+
+- it should be separate from the main remote, so that the main remote
+  can focus on serving other objects and the rest of the repos (see
+  feature 4) below) and can use the LOP as a promisor remote for
+  itself.
+
+Note 2
+++++++
+
+Git already makes it possible for a main remote to also be a promisor
+remote storing both regular objects and large blobs for a client that
+clones from it with a filter on blob size. But here we explicitly want
+to avoid that.
+
+Rationale
++++++++++
+
+LOPs aim to be good at handling large blobs while main remotes are
+already good at handling other objects.
+
+Implementation
+++++++++++++++
+
+Git already has support for multiple promisor remotes, see
+link:partial-clone.html#using-many-promisor-remotes[the partial clone documentation].
+
+Also, Git already has support for partial clone using a filter on the
+size of the blobs (with `git clone --filter=blob:limit=<size>`).  Most
+of the other main features below are based on these existing features
+and are about making them easy and efficient to use for the purpose of
+better handling large blobs.
+
+2) LOPs can use object storage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+LOPs can be implemented using object storage, like an Amazon S3 or GCP
+Bucket or MinIO (which is open source under the GNU AGPLv3 license) to
+actually store the large blobs, and can be accessed through a Git
+remote helper (see linkgit:gitremote-helpers[7]) which makes the
+underlying object storage appear like a remote to Git.
+
+Note
+++++
+
+A LOP can be a promisor remote accessed using a remote helper by
+both some clients and the main remote.
+
+Rationale
++++++++++
+
+This looks like the simplest way to create LOPs that can cheaply
+handle many large blobs.
+
+Implementation
+++++++++++++++
+
+Remote helpers are quite easy to write as shell scripts, but it might
+be more efficient and maintainable to write them using other languages
+like Go.
+
+Some already exist under open source licenses, for example:
+
+  - https://github.com/awslabs/git-remote-s3
+  - https://gitlab.com/eric.p.ju/git-remote-gs
+
+Other ways to implement LOPs are certainly possible, but the goal of
+this document is not to discuss how to best implement a LOP or its
+underlying object storage (see the "0) Non goals" section above).
+
+3) LOP object storage can be Git LFS storage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The underlying object storage that a LOP uses could also serve as
+storage for large files handled by Git LFS.
+
+Rationale
++++++++++
+
+This would simplify the server side if it wants to both use a LOP and
+act as a Git LFS server.
+
+4) A main remote can offload to a LOP with a configurable threshold
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+On the server side, a main remote should have a way to offload to a
+LOP all its blobs with a size over a configurable threshold.
+
+Rationale
++++++++++
+
+This makes it easy to set things up and to clean things up. For
+example, an admin could use this to manually convert a repo not using
+LOPs to a repo using a LOP. On a repo already using a LOP but where
+some users would sometimes push large blobs, a cron job could use this
+to regularly make sure the large blobs are moved to the LOP.
+
+Implementation
+++++++++++++++
+
+Using something based on `git repack --filter=...` to separate the
+blobs we want to offload from the other Git objects could be a good
+idea. The missing part is to connect to the LOP, check if the blobs we
+want to offload are already there and if not send them.
+
+5) A main remote should try to remain clean from large blobs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A main remote should try to avoid containing a lot of oversize
+blobs. For that purpose, it should offload as needed to a LOP and it
+should have ways to prevent oversize blobs to be fetched, and also
+perhaps pushed, into it.
+
+Rationale
++++++++++
+
+A main remote containing many oversize blobs would defeat the purpose
+of LOPs.
+
+Implementation
+++++++++++++++
+
+The way to offload to a LOP discussed in 4) above can be used to
+regularly offload oversize blobs. About preventing oversize blobs from
+being fetched into the repo see 6) below. About preventing oversize
+blob pushes, a pre-receive hook could be used.
+
+Also there are different scenarios in which large blobs could get
+fetched into the main remote, for example:
+
+- A client that doesn't implement the "promisor-remote" protocol
+  (described in 6) below) clones from the main remote.
+
+- The main remote gets a request for information about a large blob
+  and is not able to get that information without fetching the blob
+  from the LOP.
+
+It might not be possible to completely prevent all these scenarios
+from happening. So the goal here should be to implement features that
+make the fetching of large blobs less likely. For example adding a
+`remote-object-info` command in the `git cat-file --batch` protocol
+and its variants might make it possible for a main repo to respond to
+some requests about large blobs without fetching them.
+
+6) A protocol negotiation should happen when a client clones
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When a client clones from a main repo, there should be a protocol
+negotiation so that the server can advertise one or more LOPs and so
+that the client and the server can discuss if the client could
+directly use a LOP the server is advertising. If the client and the
+server can agree on that, then the client would be able to get the
+large blobs directly from the LOP and the server would not need to
+fetch those blobs from the LOP to be able to serve the client.
+
+Note
+++++
+
+For fetches instead of clones, a protocol negotiation might not always
+happen, see the "What about fetches?" FAQ entry below for details.
+
+Rationale
++++++++++
+
+Security, configurability and efficiency of setting things up.
+
+Implementation
+++++++++++++++
+
+A "promisor-remote" protocol v2 capability looks like a good way to
+implement this. The way the client and server use this capability
+could be controlled by configuration variables.
+
+Information that the server could send to the client through that
+protocol could be things like: LOP name, LOP URL, filter-spec (for
+example `blob:limit=<size>`) or just size limit that should be used as
+a filter when cloning, token to be used with the LOP, etc.
+
+7) A client can offload to a LOP
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When a client is using a LOP that is also a LOP of its main remote,
+the client should be able to offload some large blobs it has fetched,
+but might not need anymore, to the LOP.
+
+Note
+++++
+
+It might depend on the context if it should be OK or not for clients
+to offload large blobs they have created, instead of fetched, directly
+to the LOP without the main remote checking them in some ways
+(possibly using hooks or other tools).
+
+This should be discussed and refined when we get closer to
+implementing this feature.
+
+Rationale
++++++++++
+
+On the client, the easiest way to deal with unneeded large blobs is to
+offload them.
+
+Implementation
+++++++++++++++
+
+This is very similar to what 4) above is about, except on the client
+side instead of the server side. So a good solution to 4) could likely
+be adapted to work on the client side too.
+
+There might be some security issues here, as there is no negotiation,
+but they might be mitigated if the client can reuse a token it got
+when cloning (see 6) above). Also if the large blobs were fetched from
+a LOP, it is likely, and can easily be confirmed, that the LOP still
+has them, so that they can just be removed from the client.
+
+III) Benefits of using LOPs
+---------------------------
+
+Many benefits are related to the issues discussed in "I) Issues with
+the current situation" above:
+
+- No need to rewrite history when deciding which blobs are worth
+  handling separately than other objects, or when moving or removing
+  the threshold.
+
+- If the protocol between client and server is developed and secured
+  enough, then many details might be setup on the server side only and
+  all the clients could then easily get all the configuration
+  information and use it to set themselves up mostly automatically.
+
+- Storage costs benefits on the server side.
+
+- Reduced memory and CPU needs on main remotes on the server side.
+
+- Reduced storage needs on the client side.
+
+IV) FAQ
+-------
+
+What about using multiple LOPs on the server and client side?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+That could perhaps be useful in some cases, but for now it's more
+likely that in most cases a single LOP will be advertised by the
+server and should be used by the client.
+
+A case where it could be useful for a server to advertise multiple
+LOPs is if a LOP is better for some users while a different LOP is
+better for other users. For example some clients might have a better
+connection to a LOP than others.
+
+In those cases it's the responsibility of the server to have some
+documentation to help clients. It could say for example something like
+"Users in this part of the world might want to pick only LOP A as it
+is likely to be better connected to them, while users in other parts
+of the world should pick only LOP B for the same reason."
+
+When should we trust or not trust the LOPs advertised by the server?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In some contexts, like in corporate setup where the server and all the
+clients are parts of an internal network in a company where admins
+have all the rights on every system, it's OK, and perhaps even a good
+thing, if the clients fully trust the server, as it can help ensure
+that all the clients are on the same page.
+
+There are also contexts in which clients trust a code hosting platform
+serving them some repos, but might not fully trust other users
+managing or contributing to some of these repos. For example, the code
+hosting platform could have hooks in place to check that any object it
+receives doesn't contain malware or otherwise bad content. In this
+case it might be OK for the client to use a main remote and its LOP if
+they are both hosted by the code hosting platform, but not if the LOP
+is hosted elsewhere (where the content is not checked).
+
+In other contexts, a client should just not trust a server.
+
+So there should be different ways to configure how the client should
+behave when a server advertises a LOP to it at clone time.
+
+As the basic elements that a server can advertise about a LOP are a
+LOP name and a LOP URL, the client should base its decision about
+accepting a LOP on these elements.
+
+One simple way to be very strict in the LOP it accepts is for example
+for the client to check that the LOP is already configured on the
+client with the same name and URL as what the server advertises.
+
+In general default and "safe" settings should require that the LOP are
+configured on the client separately from the "promisor-remote"
+protocol and that the client accepts a LOP only when information about
+it from the protocol matches what has been already configured
+separately.
+
+What about LOP names?
+~~~~~~~~~~~~~~~~~~~~~
+
+In some contexts, for example if the clients sometimes fetch from each
+other, it can be a good idea for all the clients to use the same names
+for all the remotes they use, including LOPs.
+
+In other contexts, each client might want to be able to give the name
+it wants to each remote, including each LOP, it interacts with.
+
+So there should be different ways to configure how the client accepts
+or not the LOP name the server advertises.
+
+If a default or "safe" setting is used, then as such a setting should
+require that the LOP be configured separately, then the name would be
+configured separately and there is no risk that the server could
+dictate a name to a client.
+
+Could the main remote be bogged down by old or paranoid clients?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Yes, it could happen if there are too many clients that are either
+unwilling to trust the main remote or that just don't implement the
+"promisor-remote" protocol because they are too old or not fully
+compatible with the 'git' client.
+
+When serving such a client, the main remote has no other choice than
+to first fetch from its LOP, to then be able to provide to the client
+everything it requested. So the main remote, even if it has cleanup
+mechanisms (see section II.4 above), would be burdened at least
+temporarily with the large blobs it had to fetch from its LOP.
+
+Not behaving like this would be breaking backward compatibility, and
+could be seen as segregating clients. For example, it might be
+possible to implement a special mode that allows the server to just
+reject clients that don't implement the "promisor-remote" protocol or
+aren't willing to trust the main remote. This mode might be useful in
+a special context like a corporate environment. There is no plan to
+implement such a mode though, and this should be discussed separately
+later anyway.
+
+A better way to proceed is probably for the main remote to show a
+message telling clients that don't implement the protocol or are
+unwilling to accept the advertised LOP(s) that they would get faster
+clone and fetches by upgrading client software or properly setting
+them up to accept LOP(s).
+
+Waiting for clients to upgrade, monitoring these upgrades and limiting
+the use of LOPs to repos that are not very frequently accessed might
+be other good ways to make sure that some benefits are still reaped
+from LOPs. Over time, as more and more clients upgrade and benefit
+from LOPs, using them in more and more frequently accessed repos will
+become worth it.
+
+Corporate environments, where it might be easier to make sure that all
+the clients are up-to-date and properly configured, could hopefully
+benefit more and earlier from using LOPs.
+
+What about fetches?
+~~~~~~~~~~~~~~~~~~~
+
+There are different kinds of fetches. A regular fetch happens when
+some refs have been updated on the server and the client wants the ref
+updates and possibly the new objects added with them. A "backfill" or
+"lazy" fetch, on the contrary, happens when the client needs to use
+some objects it already knows about but doesn't have because they are
+on a promisor remote.
+
+Regular fetch
++++++++++++++
+
+In a regular fetch, the client will contact the main remote and a
+protocol negotiation will happen between them. It's a good thing that
+a protocol negotiation happens every time, as the configuration on the
+client or the main remote could have changed since the previous
+protocol negotiation. In this case, the new protocol negotiation
+should ensure that the new fetch will happen in a way that satisfies
+the new configuration of both the client and the server.
+
+In most cases though, the configurations on the client and the main
+remote will not have changed between 2 fetches or between the initial
+clone and a subsequent fetch. This means that the result of a new
+protocol negotiation will be the same as the previous result, so the
+new fetch will happen in the same way as the previous clone or fetch,
+using, or not using, the same LOP(s) as last time.
+
+"Backfill" or "lazy" fetch
+++++++++++++++++++++++++++
+
+When there is a backfill fetch, the client doesn't necessarily contact
+the main remote first. It will try to fetch from its promisor remotes
+in the order they appear in the config file, except that a remote
+configured using the `extensions.partialClone` config variable will be
+tried last. See
+link:partial-clone.html#using-many-promisor-remotes[the partial clone documentation].
+
+This is not new with this effort. In fact this is how multiple remotes
+have already been working for around 5 years.
+
+When using LOPs, having the main remote configured using
+`extensions.partialClone`, so it's tried last, makes sense, as missing
+objects should only be large blobs that are on LOPs.
+
+This means that a protocol negotiation will likely not happen as the
+missing objects will be fetched from the LOPs, and then there will be
+nothing left to fetch from the main remote.
+
+To secure that, it could be a good idea for LOPs to require a token
+from the client when it fetches from them. The client could get the
+token when performing a protocol negotiation with the main remote (see
+section II.6 above).
+
+V) Future improvements
+----------------------
+
+It is expected that at the beginning using LOPs will be mostly worth
+it either in a corporate context where the Git version that clients
+use can easily be controlled, or on repos that are infrequently
+accessed. (See the "Could the main remote be bogged down by old or
+paranoid clients?" section in the FAQ above.)
+
+Over time, as more and more clients upgrade to a version that
+implements the "promisor-remote" protocol v2 capability described
+above in section II.6), it will be worth it to use LOPs more widely.
+
+A lot of improvements may also help using LOPs more widely. Some of
+these improvements are part of the scope of this document like the
+following:
+
+  - Implementing a "remote-object-info" command in the
+    `git cat-file --batch` protocol and its variants to allow main
+    remotes to respond to requests about large blobs without fetching
+    them. (Eric Ju has started working on this based on previous work
+    by Calvin Wan.)
+
+  - Creating better cleanup and offload mechanisms for main remotes
+    and clients to prevent accumulation of large blobs.
+
+  - Developing more sophisticated protocol negotiation capabilities
+    between clients and servers for handling LOPs, for example adding
+    a filter-spec (e.g., blob:limit=<size>) or size limit for
+    filtering when cloning, or adding a token for LOP authentication.
+
+  - Improving security measures for LOP access, particularly around
+    token handling and authentication.
+
+  - Developing standardized ways to configure and manage multiple LOPs
+    across different environments. Especially in the case where
+    different LOPs serve the same content to clients in different
+    geographical locations, there is a need for replication or
+    synchronization between LOPs.
+
+Some improvements, including some that have been mentioned in the "0)
+Non Goals" section of this document, are out of the scope of this
+document:
+
+  - Implementing a new object representation for large blobs on the
+    client side.
+
+  - Developing pluggable ODBs or other object database backends that
+    could chunk large blobs, dedup the chunks and store them
+    efficiently.
+
+  - Optimizing data transfer between LOPs and clients/servers,
+    particularly for incompressible and non-deltifying content.
+
+  - Creating improved client side tools for managing large objects
+    more effectively, for example tools for migrating from Git LFS or
+    git-annex, or tools to find which objects could be offloaded and
+    how much disk space could be reclaimed by offloading them.
+
+Some improvements could be seen as part of the scope of this document,
+but might already have their own separate projects from the Git
+project, like:
+
+  - Improving existing remote helpers to access object storage or
+    developing new ones.
+
+  - Improving existing object storage solutions or developing new
+    ones.
+
+Even though all the above improvements may help, this document and the
+LOP effort should try to focus, at least first, on a relatively small
+number of improvements mostly those that are in its current scope.
+
+For example introducing pluggable ODBs and a new object database
+backend is likely a multi-year effort on its own that can happen
+separately in parallel. It has different technical requirements,
+touches other part of the Git code base and should have its own design
+document(s).
diff --git a/Documentation/technical/long-running-process-protocol.txt b/Documentation/technical/long-running-process-protocol.adoc
similarity index 100%
rename from Documentation/technical/long-running-process-protocol.txt
rename to Documentation/technical/long-running-process-protocol.adoc
diff --git a/Documentation/technical/meson.build b/Documentation/technical/meson.build
index 21dfb8b..a13aafc 100644
--- a/Documentation/technical/meson.build
+++ b/Documentation/technical/meson.build
@@ -1,37 +1,37 @@
 api_docs = [
-  'api-error-handling.txt',
-  'api-merge.txt',
-  'api-parse-options.txt',
-  'api-simple-ipc.txt',
-  'api-trace2.txt',
+  'api-error-handling.adoc',
+  'api-merge.adoc',
+  'api-parse-options.adoc',
+  'api-simple-ipc.adoc',
+  'api-trace2.adoc',
 ]
 
 articles = [
-  'bitmap-format.txt',
-  'build-systems.txt',
-  'bundle-uri.txt',
-  'commit-graph.txt',
-  'directory-rename-detection.txt',
-  'hash-function-transition.txt',
-  'long-running-process-protocol.txt',
-  'multi-pack-index.txt',
-  'packfile-uri.txt',
-  'pack-heuristics.txt',
-  'parallel-checkout.txt',
-  'partial-clone.txt',
-  'platform-support.txt',
-  'racy-git.txt',
-  'reftable.txt',
-  'remembering-renames.txt',
-  'repository-version.txt',
-  'rerere.txt',
-  'scalar.txt',
-  'send-pack-pipeline.txt',
-  'shallow.txt',
-  'sparse-checkout.txt',
-  'sparse-index.txt',
-  'trivial-merge.txt',
-  'unit-tests.txt',
+  'bitmap-format.adoc',
+  'build-systems.adoc',
+  'bundle-uri.adoc',
+  'commit-graph.adoc',
+  'directory-rename-detection.adoc',
+  'hash-function-transition.adoc',
+  'long-running-process-protocol.adoc',
+  'multi-pack-index.adoc',
+  'packfile-uri.adoc',
+  'pack-heuristics.adoc',
+  'parallel-checkout.adoc',
+  'partial-clone.adoc',
+  'platform-support.adoc',
+  'racy-git.adoc',
+  'reftable.adoc',
+  'remembering-renames.adoc',
+  'repository-version.adoc',
+  'rerere.adoc',
+  'scalar.adoc',
+  'send-pack-pipeline.adoc',
+  'shallow.adoc',
+  'sparse-checkout.adoc',
+  'sparse-index.adoc',
+  'trivial-merge.adoc',
+  'unit-tests.adoc',
 ]
 
 api_index = custom_target(
@@ -43,7 +43,7 @@
   ],
   env: script_environment,
   input: api_docs,
-  output: 'api-index.txt',
+  output: 'api-index.adoc',
 )
 
 custom_target(
@@ -60,6 +60,7 @@
     command: asciidoc_html_options,
     input: article,
     output: fs.stem(article) + '.html',
+    depends: documentation_deps,
     install: true,
     install_dir: get_option('datadir') / 'doc/git-doc/technical',
   )
diff --git a/Documentation/technical/multi-pack-index.txt b/Documentation/technical/multi-pack-index.adoc
similarity index 100%
rename from Documentation/technical/multi-pack-index.txt
rename to Documentation/technical/multi-pack-index.adoc
diff --git a/Documentation/technical/pack-heuristics.txt b/Documentation/technical/pack-heuristics.adoc
similarity index 100%
rename from Documentation/technical/pack-heuristics.txt
rename to Documentation/technical/pack-heuristics.adoc
diff --git a/Documentation/technical/packfile-uri.txt b/Documentation/technical/packfile-uri.adoc
similarity index 100%
rename from Documentation/technical/packfile-uri.txt
rename to Documentation/technical/packfile-uri.adoc
diff --git a/Documentation/technical/parallel-checkout.txt b/Documentation/technical/parallel-checkout.adoc
similarity index 100%
rename from Documentation/technical/parallel-checkout.txt
rename to Documentation/technical/parallel-checkout.adoc
diff --git a/Documentation/technical/partial-clone.txt b/Documentation/technical/partial-clone.adoc
similarity index 99%
rename from Documentation/technical/partial-clone.txt
rename to Documentation/technical/partial-clone.adoc
index bf5ec5c..e513e39 100644
--- a/Documentation/technical/partial-clone.txt
+++ b/Documentation/technical/partial-clone.adoc
@@ -85,7 +85,7 @@
   server to request filtering during packfile construction.
 +
 There are various filters available to accommodate different situations.
-See "--filter=<filter-spec>" in Documentation/rev-list-options.txt.
+See "--filter=<filter-spec>" in Documentation/rev-list-options.adoc.
 
 - On the server pack-objects applies the requested filter-spec as it
   creates "filtered" packfiles for the client.
diff --git a/Documentation/technical/platform-support.txt b/Documentation/technical/platform-support.adoc
similarity index 100%
rename from Documentation/technical/platform-support.txt
rename to Documentation/technical/platform-support.adoc
diff --git a/Documentation/technical/racy-git.txt b/Documentation/technical/racy-git.adoc
similarity index 100%
rename from Documentation/technical/racy-git.txt
rename to Documentation/technical/racy-git.adoc
diff --git a/Documentation/technical/reftable.txt b/Documentation/technical/reftable.adoc
similarity index 100%
rename from Documentation/technical/reftable.txt
rename to Documentation/technical/reftable.adoc
diff --git a/Documentation/technical/remembering-renames.txt b/Documentation/technical/remembering-renames.adoc
similarity index 100%
rename from Documentation/technical/remembering-renames.txt
rename to Documentation/technical/remembering-renames.adoc
diff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.adoc
similarity index 100%
rename from Documentation/technical/repository-version.txt
rename to Documentation/technical/repository-version.adoc
diff --git a/Documentation/technical/rerere.txt b/Documentation/technical/rerere.adoc
similarity index 100%
rename from Documentation/technical/rerere.txt
rename to Documentation/technical/rerere.adoc
diff --git a/Documentation/technical/scalar.txt b/Documentation/technical/scalar.adoc
similarity index 100%
rename from Documentation/technical/scalar.txt
rename to Documentation/technical/scalar.adoc
diff --git a/Documentation/technical/send-pack-pipeline.txt b/Documentation/technical/send-pack-pipeline.adoc
similarity index 100%
rename from Documentation/technical/send-pack-pipeline.txt
rename to Documentation/technical/send-pack-pipeline.adoc
diff --git a/Documentation/technical/shallow.txt b/Documentation/technical/shallow.adoc
similarity index 100%
rename from Documentation/technical/shallow.txt
rename to Documentation/technical/shallow.adoc
diff --git a/Documentation/technical/sparse-checkout.txt b/Documentation/technical/sparse-checkout.adoc
similarity index 100%
rename from Documentation/technical/sparse-checkout.txt
rename to Documentation/technical/sparse-checkout.adoc
diff --git a/Documentation/technical/sparse-index.txt b/Documentation/technical/sparse-index.adoc
similarity index 100%
rename from Documentation/technical/sparse-index.txt
rename to Documentation/technical/sparse-index.adoc
diff --git a/Documentation/technical/trivial-merge.txt b/Documentation/technical/trivial-merge.adoc
similarity index 100%
rename from Documentation/technical/trivial-merge.txt
rename to Documentation/technical/trivial-merge.adoc
diff --git a/Documentation/technical/unit-tests.txt b/Documentation/technical/unit-tests.adoc
similarity index 100%
rename from Documentation/technical/unit-tests.txt
rename to Documentation/technical/unit-tests.adoc
diff --git a/Documentation/trace2-target-values.txt b/Documentation/trace2-target-values.adoc
similarity index 100%
rename from Documentation/trace2-target-values.txt
rename to Documentation/trace2-target-values.adoc
diff --git a/Documentation/transfer-data-leaks.txt b/Documentation/transfer-data-leaks.adoc
similarity index 100%
rename from Documentation/transfer-data-leaks.txt
rename to Documentation/transfer-data-leaks.adoc
diff --git a/Documentation/urls-remotes.txt b/Documentation/urls-remotes.adoc
similarity index 98%
rename from Documentation/urls-remotes.txt
rename to Documentation/urls-remotes.adoc
index bf17012..9b10151 100644
--- a/Documentation/urls-remotes.txt
+++ b/Documentation/urls-remotes.adoc
@@ -1,4 +1,4 @@
-include::urls.txt[]
+include::urls.adoc[]
 
 REMOTES[[REMOTES]]
 ------------------
diff --git a/Documentation/urls.txt b/Documentation/urls.adoc
similarity index 100%
rename from Documentation/urls.txt
rename to Documentation/urls.adoc
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.adoc
similarity index 99%
rename from Documentation/user-manual.txt
rename to Documentation/user-manual.adoc
index 90a4189..d2b478a 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.adoc
@@ -4354,7 +4354,7 @@
 [[git-explained]]
 === Git explained
 
-include::glossary-content.txt[]
+include::glossary-content.adoc[]
 
 [[git-quick-start]]
 [appendix]
diff --git a/GIT-BUILD-OPTIONS.in b/GIT-BUILD-OPTIONS.in
index edff75a..0a9884e 100644
--- a/GIT-BUILD-OPTIONS.in
+++ b/GIT-BUILD-OPTIONS.in
@@ -9,14 +9,13 @@
 GIT_PERF_MAKE_OPTS=@GIT_PERF_MAKE_OPTS@
 GIT_PERF_REPEAT_COUNT=@GIT_PERF_REPEAT_COUNT@
 GIT_PERF_REPO=@GIT_PERF_REPO@
+GIT_SOURCE_DIR=@GIT_SOURCE_DIR@
 GIT_TEST_CMP=@GIT_TEST_CMP@
 GIT_TEST_CMP_USE_COPIED_CONTEXT=@GIT_TEST_CMP_USE_COPIED_CONTEXT@
 GIT_TEST_GITPERLLIB=@GIT_TEST_GITPERLLIB@
 GIT_TEST_INDEX_VERSION=@GIT_TEST_INDEX_VERSION@
-GIT_TEST_MERGE_TOOLS_DIR=@GIT_TEST_MERGE_TOOLS_DIR@
 GIT_TEST_OPTS=@GIT_TEST_OPTS@
 GIT_TEST_PERL_FATAL_WARNINGS=@GIT_TEST_PERL_FATAL_WARNINGS@
-GIT_TEST_POPATH=@GIT_TEST_POPATH@
 GIT_TEST_TEMPLATE_DIR=@GIT_TEST_TEMPLATE_DIR@
 GIT_TEST_TEXTDOMAINDIR=@GIT_TEST_TEXTDOMAINDIR@
 GIT_TEST_UTF8_LOCALE=@GIT_TEST_UTF8_LOCALE@
@@ -45,4 +44,5 @@
 TEST_SHELL_PATH=@TEST_SHELL_PATH@
 USE_GETTEXT_SCHEME=@USE_GETTEXT_SCHEME@
 USE_LIBPCRE2=@USE_LIBPCRE2@
+WITH_BREAKING_CHANGES=@WITH_BREAKING_CHANGES@
 X=@X@
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index df11f29..3abfe7d 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,25 +1,33 @@
 #!/bin/sh
 
-DEF_VER=v2.48.2
+DEF_VER=v2.49.0
 
 LF='
 '
 
-if test "$#" -ne 3
+if test "$#" -lt 2 || test "$#" -gt 3
 then
-    echo >&2 "USAGE: $0 <SOURCE_DIR> <INPUT> <OUTPUT>"
+    echo >&2 "USAGE: $0 <SOURCE_DIR> (--format=<STRING>|<INPUT>) [<OUTPUT>]"
     exit 1
 fi
 
 SOURCE_DIR="$1"
-INPUT="$2"
-OUTPUT="$3"
 
-if ! test -f "$INPUT"
-then
-	echo >&2 "Input is not a file: $INPUT"
-	exit 1
-fi
+case "$2" in
+--format=*)
+	INPUT="${2#--format=}"
+	;;
+*)
+	if ! test -f "$2"
+	then
+		echo >&2 "Input is not a file: $2"
+		exit 1
+	fi
+	INPUT=$(cat "$2")
+	;;
+esac
+
+OUTPUT="$3"
 
 # Protect us from reading Git version information outside of the Git directory
 # in case it is not a repository itself, but embedded in an unrelated
@@ -39,13 +47,9 @@
 			test -d "${GIT_DIR:-.git}" ||
 			test -f "$SOURCE_DIR"/.git;
 		} &&
-		VN=$(git -C "$SOURCE_DIR" describe --match "v[0-9]*" HEAD 2>/dev/null) &&
+		VN=$(git -C "$SOURCE_DIR" describe --dirty --match="v[0-9]*" 2>/dev/null) &&
 		case "$VN" in
 		*$LF*) (exit 1) ;;
-		v[0-9]*)
-			git -C "$SOURCE_DIR" update-index -q --refresh
-			test -z "$(git -C "$SOURCE_DIR" diff-index --name-only HEAD --)" ||
-			VN="$VN-dirty" ;;
 		esac
 	then
 		VN=$(echo "$VN" | sed -e 's/-/./g');
@@ -78,19 +82,25 @@
 $(echo "$GIT_VERSION" 0 0 0 0 | tr '.a-zA-Z-' ' ')
 EOF
 
-sed -e "s|@GIT_VERSION@|$GIT_VERSION|" \
+REPLACED=$(printf "%s" "$INPUT" | sed -e "s|@GIT_VERSION@|$GIT_VERSION|" \
 	-e "s|@GIT_MAJOR_VERSION@|$GIT_MAJOR_VERSION|" \
 	-e "s|@GIT_MINOR_VERSION@|$GIT_MINOR_VERSION|" \
 	-e "s|@GIT_MICRO_VERSION@|$GIT_MICRO_VERSION|" \
 	-e "s|@GIT_PATCH_LEVEL@|$GIT_PATCH_LEVEL|" \
 	-e "s|@GIT_BUILT_FROM_COMMIT@|$GIT_BUILT_FROM_COMMIT|" \
 	-e "s|@GIT_USER_AGENT@|$GIT_USER_AGENT|" \
-	-e "s|@GIT_DATE@|$GIT_DATE|" \
-	"$INPUT" >"$OUTPUT".$$+
+	-e "s|@GIT_DATE@|$GIT_DATE|"
+)
 
-if ! test -f "$OUTPUT" || ! cmp "$OUTPUT".$$+ "$OUTPUT" >/dev/null
+if test -z "$OUTPUT"
 then
-	mv "$OUTPUT".$$+ "$OUTPUT"
+	printf "%s\n" "$REPLACED"
 else
-	rm "$OUTPUT".$$+
+	printf "%s\n" "$REPLACED" >"$OUTPUT".$$+
+	if ! test -f "$OUTPUT" || ! cmp "$OUTPUT".$$+ "$OUTPUT" >/dev/null
+	then
+		mv "$OUTPUT".$$+ "$OUTPUT"
+	else
+		rm "$OUTPUT".$$+
+	fi
 fi
diff --git a/Makefile b/Makefile
index 97e8385..3868edd 100644
--- a/Makefile
+++ b/Makefile
@@ -183,7 +183,8 @@
 # byte-order mark (BOM) when writing UTF-16 or UTF-32 and always writes in
 # big-endian format.
 #
-# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
+# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound. Define
+# ZLIB_NG if you want to use zlib-ng instead of zlib.
 #
 # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
 # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
@@ -193,7 +194,7 @@
 # Linux, kernel 2.6.11 or newer is required for reliable sub-second file times
 # on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git
 # on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See
-# Documentation/technical/racy-git.txt for details.
+# Documentation/technical/racy-git.adoc for details.
 #
 # Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
 # "st_ctim"
@@ -416,6 +417,9 @@
 # Define LINK_FUZZ_PROGRAMS if you want `make all` to also build the fuzz test
 # programs in oss-fuzz/.
 #
+# Define INCLUDE_LIBGIT_RS if you want `make all` and `make test` to build and
+# test the Rust crates in contrib/libgit-sys and contrib/libgit-rs.
+#
 # === Optional library: libintl ===
 #
 # Define NO_GETTEXT if you don't want Git output to be translated.
@@ -657,6 +661,8 @@
 GCOV = gcov
 STRIP = strip
 SPATCH = spatch
+LD = ld
+OBJCOPY = objcopy
 
 export TCL_PATH TCLTK_PATH
 
@@ -675,6 +681,7 @@
 FUZZ_PROGRAMS =
 GIT_OBJS =
 LIB_OBJS =
+LIBGIT_PUB_OBJS =
 SCALAR_OBJS =
 OBJECTS =
 OTHER_PROGRAMS =
@@ -812,12 +819,14 @@
 TEST_BUILTINS_OBJS += test-match-trees.o
 TEST_BUILTINS_OBJS += test-mergesort.o
 TEST_BUILTINS_OBJS += test-mktemp.o
+TEST_BUILTINS_OBJS += test-name-hash.o
 TEST_BUILTINS_OBJS += test-online-cpus.o
 TEST_BUILTINS_OBJS += test-pack-mtimes.o
 TEST_BUILTINS_OBJS += test-parse-options.o
 TEST_BUILTINS_OBJS += test-parse-pathspec-file.o
 TEST_BUILTINS_OBJS += test-partial-clone.o
 TEST_BUILTINS_OBJS += test-path-utils.o
+TEST_BUILTINS_OBJS += test-path-walk.o
 TEST_BUILTINS_OBJS += test-pcre2-config.o
 TEST_BUILTINS_OBJS += test-pkt-line.o
 TEST_BUILTINS_OBJS += test-proc-receive.o
@@ -981,10 +990,11 @@
 LIB_OBJS += commit-graph.o
 LIB_OBJS += commit-reach.o
 LIB_OBJS += commit.o
+LIB_OBJS += common-exit.o
+LIB_OBJS += common-init.o
 LIB_OBJS += compat/nonblock.o
 LIB_OBJS += compat/obstack.o
 LIB_OBJS += compat/terminal.o
-LIB_OBJS += compat/zlib-uncompress2.o
 LIB_OBJS += config.o
 LIB_OBJS += connect.o
 LIB_OBJS += connected.o
@@ -1094,6 +1104,7 @@
 LIB_OBJS += patch-delta.o
 LIB_OBJS += patch-ids.o
 LIB_OBJS += path.o
+LIB_OBJS += path-walk.o
 LIB_OBJS += pathspec.o
 LIB_OBJS += pkt-line.o
 LIB_OBJS += preload-index.o
@@ -1201,6 +1212,7 @@
 BUILTIN_OBJS += builtin/annotate.o
 BUILTIN_OBJS += builtin/apply.o
 BUILTIN_OBJS += builtin/archive.o
+BUILTIN_OBJS += builtin/backfill.o
 BUILTIN_OBJS += builtin/bisect.o
 BUILTIN_OBJS += builtin/blame.o
 BUILTIN_OBJS += builtin/branch.o
@@ -1271,7 +1283,9 @@
 BUILTIN_OBJS += builtin/name-rev.o
 BUILTIN_OBJS += builtin/notes.o
 BUILTIN_OBJS += builtin/pack-objects.o
+ifndef WITH_BREAKING_CHANGES
 BUILTIN_OBJS += builtin/pack-redundant.o
+endif
 BUILTIN_OBJS += builtin/pack-refs.o
 BUILTIN_OBJS += builtin/patch-id.o
 BUILTIN_OBJS += builtin/prune-packed.o
@@ -1338,20 +1352,24 @@
 THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/%
 
 CLAR_TEST_SUITES += u-ctype
+CLAR_TEST_SUITES += u-example-decorate
+CLAR_TEST_SUITES += u-hash
+CLAR_TEST_SUITES += u-hashmap
+CLAR_TEST_SUITES += u-mem-pool
+CLAR_TEST_SUITES += u-oid-array
+CLAR_TEST_SUITES += u-oidmap
+CLAR_TEST_SUITES += u-oidtree
+CLAR_TEST_SUITES += u-prio-queue
+CLAR_TEST_SUITES += u-reftable-tree
+CLAR_TEST_SUITES += u-strbuf
+CLAR_TEST_SUITES += u-strcmp-offset
 CLAR_TEST_SUITES += u-strvec
 CLAR_TEST_PROG = $(UNIT_TEST_BIN)/unit-tests$(X)
 CLAR_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(CLAR_TEST_SUITES))
 CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/clar/clar.o
 CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o
+CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/lib-oid.o
 
-UNIT_TEST_PROGRAMS += t-example-decorate
-UNIT_TEST_PROGRAMS += t-hash
-UNIT_TEST_PROGRAMS += t-hashmap
-UNIT_TEST_PROGRAMS += t-mem-pool
-UNIT_TEST_PROGRAMS += t-oid-array
-UNIT_TEST_PROGRAMS += t-oidmap
-UNIT_TEST_PROGRAMS += t-oidtree
-UNIT_TEST_PROGRAMS += t-prio-queue
 UNIT_TEST_PROGRAMS += t-reftable-basics
 UNIT_TEST_PROGRAMS += t-reftable-block
 UNIT_TEST_PROGRAMS += t-reftable-merged
@@ -1360,14 +1378,10 @@
 UNIT_TEST_PROGRAMS += t-reftable-readwrite
 UNIT_TEST_PROGRAMS += t-reftable-record
 UNIT_TEST_PROGRAMS += t-reftable-stack
-UNIT_TEST_PROGRAMS += t-reftable-tree
-UNIT_TEST_PROGRAMS += t-strbuf
-UNIT_TEST_PROGRAMS += t-strcmp-offset
 UNIT_TEST_PROGRAMS += t-trailer
 UNIT_TEST_PROGRAMS += t-urlmatch-normalization
 UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
 UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
-UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-oid.o
 UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o
 
 # xdiff and reftable libs may in turn depend on what is in libgit.a
@@ -1395,7 +1409,7 @@
 PTHREAD_CFLAGS =
 
 # For the 'sparse' target
-SPARSE_FLAGS ?= -std=gnu99
+SPARSE_FLAGS ?= -std=gnu99 -D__STDC_NO_VLA__
 SP_EXTRA_FLAGS =
 
 # For informing GIT-BUILD-OPTIONS of the SANITIZE=leak,address targets
@@ -1688,11 +1702,20 @@
 endif
 IMAP_SEND_LDFLAGS += $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
 
-ifdef ZLIB_PATH
-	BASIC_CFLAGS += -I$(ZLIB_PATH)/include
-	EXTLIBS += $(call libpath_template,$(ZLIB_PATH)/$(lib))
+ifdef ZLIB_NG
+	BASIC_CFLAGS += -DHAVE_ZLIB_NG
+        ifdef ZLIB_NG_PATH
+		BASIC_CFLAGS += -I$(ZLIB_NG_PATH)/include
+		EXTLIBS += $(call libpath_template,$(ZLIB_NG_PATH)/$(lib))
+        endif
+	EXTLIBS += -lz-ng
+else
+        ifdef ZLIB_PATH
+		BASIC_CFLAGS += -I$(ZLIB_PATH)/include
+		EXTLIBS += $(call libpath_template,$(ZLIB_PATH)/$(lib))
+        endif
+	EXTLIBS += -lz
 endif
-EXTLIBS += -lz
 
 ifndef NO_OPENSSL
 	OPENSSL_LIBSSL = -lssl
@@ -2234,6 +2257,16 @@
 	COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
 endif
 
+ifdef WITH_BREAKING_CHANGES
+	BASIC_CFLAGS += -DWITH_BREAKING_CHANGES
+endif
+
+ifdef INCLUDE_LIBGIT_RS
+	# Enable symbol hiding in contrib/libgit-sys/libgitpub.a without making
+	# us rebuild the whole tree every time we run a Rust build.
+	BASIC_CFLAGS += -fvisibility=hidden
+endif
+
 ifeq ($(TCLTK_PATH),)
 NO_TCLTK = NoThanks
 endif
@@ -2528,17 +2561,17 @@
 
 config-list.h: generate-configlist.sh
 
-config-list.h: Documentation/*config.txt Documentation/config/*.txt
+config-list.h: Documentation/*config.adoc Documentation/config/*.adoc
 	$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh . $@
 
 command-list.h: generate-cmdlist.sh command-list.txt
 
-command-list.h: $(wildcard Documentation/git*.txt)
+command-list.h: $(wildcard Documentation/git*.adoc)
 	$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh \
 		$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \
 		. $@
 
-hook-list.h: generate-hooklist.sh Documentation/githooks.txt
+hook-list.h: generate-hooklist.sh Documentation/githooks.adoc
 	$(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh . $@
 
 SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):\
@@ -2730,6 +2763,10 @@
 OBJECTS += $(CLAR_TEST_OBJS)
 OBJECTS += $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
 
+ifdef INCLUDE_LIBGIT_RS
+	OBJECTS += contrib/libgit-sys/public_symbol_export.o
+endif
+
 ifndef NO_CURL
 	OBJECTS += http.o http-walker.o remote-curl.o
 endif
@@ -3156,14 +3193,13 @@
 		-e "s|@GIT_PERF_MAKE_OPTS@|\'$(GIT_PERF_MAKE_OPTS)\'|" \
 		-e "s|@GIT_PERF_REPEAT_COUNT@|\'$(GIT_PERF_REPEAT_COUNT)\'|" \
 		-e "s|@GIT_PERF_REPO@|\'$(GIT_PERF_REPO)\'|" \
+		-e "s|@GIT_SOURCE_DIR@|\'$(shell pwd)\'|" \
 		-e "s|@GIT_TEST_CMP@|\'$(GIT_TEST_CMP)\'|" \
 		-e "s|@GIT_TEST_CMP_USE_COPIED_CONTEXT@|\'$(GIT_TEST_CMP_USE_COPIED_CONTEXT)\'|" \
 		-e "s|@GIT_TEST_GITPERLLIB@|\'$(shell pwd)/perl/build/lib\'|" \
 		-e "s|@GIT_TEST_INDEX_VERSION@|\'$(GIT_TEST_INDEX_VERSION)\'|" \
-		-e "s|@GIT_TEST_MERGE_TOOLS_DIR@|\'$(shell pwd)/mergetools\'|" \
 		-e "s|@GIT_TEST_OPTS@|\'$(GIT_TEST_OPTS)\'|" \
 		-e "s|@GIT_TEST_PERL_FATAL_WARNINGS@|\'$(GIT_TEST_PERL_FATAL_WARNINGS)\'|" \
-		-e "s|@GIT_TEST_POPATH@|\'$(shell pwd)/po\'|" \
 		-e "s|@GIT_TEST_TEMPLATE_DIR@|\'$(shell pwd)/templates/blt\'|" \
 		-e "s|@GIT_TEST_TEXTDOMAINDIR@|\'$(shell pwd)/po/build/locale\'|" \
 		-e "s|@GIT_TEST_UTF8_LOCALE@|\'$(GIT_TEST_UTF8_LOCALE)\'|" \
@@ -3192,6 +3228,7 @@
 		-e "s|@TEST_SHELL_PATH@|\'$(TEST_SHELL_PATH_SQ)\'|" \
 		-e "s|@USE_GETTEXT_SCHEME@|\'$(USE_GETTEXT_SCHEME)\'|" \
 		-e "s|@USE_LIBPCRE2@|\'$(USE_LIBPCRE2)\'|" \
+		-e "s|@WITH_BREAKING_CHANGES@|\'$(WITH_BREAKING_CHANGES)\'|" \
 		-e "s|@X@|\'$(X)\'|" \
 		GIT-BUILD-OPTIONS.in >$@+
 	@if grep -q '^[A-Z][A-Z_]*=@.*@$$' $@+; then echo "Unsubstituted build options in $@" >&2 && exit 1; fi
@@ -3724,6 +3761,10 @@
 	$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
 	$(MAKE) -C Documentation/ clean
 	$(RM) Documentation/GIT-EXCLUDED-PROGRAMS
+	$(RM) -r contrib/libgit-sys/target contrib/libgit-rs/target
+	$(RM) contrib/libgit-sys/partial_symbol_export.o
+	$(RM) contrib/libgit-sys/hidden_symbol_export.o
+	$(RM) contrib/libgit-sys/libgitpub.a
 ifndef NO_PERL
 	$(RM) -r perl/build/
 endif
@@ -3885,3 +3926,31 @@
 build-unit-tests: $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG)
 unit-tests: $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG) t/helper/test-tool$X
 	$(MAKE) -C t/ unit-tests
+
+.PHONY: libgit-sys libgit-rs
+libgit-sys libgit-rs:
+	$(QUIET)(\
+		cd contrib/$@ && \
+		cargo build \
+	)
+ifdef INCLUDE_LIBGIT_RS
+all:: libgit-sys libgit-rs
+endif
+
+LIBGIT_PUB_OBJS += contrib/libgit-sys/public_symbol_export.o
+LIBGIT_PUB_OBJS += libgit.a
+LIBGIT_PUB_OBJS += reftable/libreftable.a
+LIBGIT_PUB_OBJS += xdiff/lib.a
+
+LIBGIT_PARTIAL_EXPORT = contrib/libgit-sys/partial_symbol_export.o
+
+LIBGIT_HIDDEN_EXPORT = contrib/libgit-sys/hidden_symbol_export.o
+
+$(LIBGIT_PARTIAL_EXPORT): $(LIBGIT_PUB_OBJS)
+	$(LD) -r $^ -o $@
+
+$(LIBGIT_HIDDEN_EXPORT): $(LIBGIT_PARTIAL_EXPORT)
+	$(OBJCOPY) --localize-hidden $^ $@
+
+contrib/libgit-sys/libgitpub.a: $(LIBGIT_HIDDEN_EXPORT)
+	$(AR) $(ARFLAGS) $@ $^
diff --git a/README.md b/README.md
index 665ce5f..d87bca1 100644
--- a/README.md
+++ b/README.md
@@ -17,15 +17,15 @@
 Many Git online resources are accessible from <https://git-scm.com/>
 including full documentation and Git related tools.
 
-See [Documentation/gittutorial.txt][] to get started, then see
-[Documentation/giteveryday.txt][] for a useful minimum set of commands, and
-`Documentation/git-<commandname>.txt` for documentation of each command.
+See [Documentation/gittutorial.adoc][] to get started, then see
+[Documentation/giteveryday.adoc][] for a useful minimum set of commands, and
+`Documentation/git-<commandname>.adoc` for documentation of each command.
 If git has been correctly installed, then the tutorial can also be
 read with `man gittutorial` or `git help tutorial`, and the
 documentation of each command with `man git-<commandname>` or `git help
 <commandname>`.
 
-CVS users may also want to read [Documentation/gitcvs-migration.txt][]
+CVS users may also want to read [Documentation/gitcvs-migration.adoc][]
 (`man gitcvs-migration` or `git help cvs-migration` if git is
 installed).
 
@@ -66,9 +66,9 @@
  - "goddamn idiotic truckload of sh*t": when it breaks
 
 [INSTALL]: INSTALL
-[Documentation/gittutorial.txt]: Documentation/gittutorial.txt
-[Documentation/giteveryday.txt]: Documentation/giteveryday.txt
-[Documentation/gitcvs-migration.txt]: Documentation/gitcvs-migration.txt
+[Documentation/gittutorial.adoc]: Documentation/gittutorial.adoc
+[Documentation/giteveryday.adoc]: Documentation/giteveryday.adoc
+[Documentation/gitcvs-migration.adoc]: Documentation/gitcvs-migration.adoc
 [Documentation/SubmittingPatches]: Documentation/SubmittingPatches
 [Documentation/CodingGuidelines]: Documentation/CodingGuidelines
 [po/README.md]: po/README.md
diff --git a/RelNotes b/RelNotes
index 87db0ec..ac72bdf 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.48.2.txt
\ No newline at end of file
+Documentation/RelNotes/2.49.0.adoc
\ No newline at end of file
diff --git a/add-interactive.c b/add-interactive.c
index d0f8c10..97ff35b 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -72,14 +71,14 @@ void init_add_i_state(struct add_i_state *s, struct repository *r)
 		s->use_color ? GIT_COLOR_RESET : "", COLOR_MAXLEN);
 
 	FREE_AND_NULL(s->interactive_diff_filter);
-	git_config_get_string("interactive.difffilter",
-			      &s->interactive_diff_filter);
+	repo_config_get_string(r, "interactive.difffilter",
+			       &s->interactive_diff_filter);
 
 	FREE_AND_NULL(s->interactive_diff_algorithm);
-	git_config_get_string("diff.algorithm",
-			      &s->interactive_diff_algorithm);
+	repo_config_get_string(r, "diff.algorithm",
+			       &s->interactive_diff_algorithm);
 
-	git_config_get_bool("interactive.singlekey", &s->use_single_key);
+	repo_config_get_bool(r, "interactive.singlekey", &s->use_single_key);
 	if (s->use_single_key)
 		setbuf(stdin, NULL);
 }
@@ -535,7 +534,7 @@ static int get_modified_files(struct repository *r,
 			      size_t *binary_count)
 {
 	struct object_id head_oid;
-	int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+	int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(r),
 						  "HEAD", RESOLVE_REF_READING,
 						  &head_oid, NULL);
 	struct collection_status s = { 0 };
@@ -560,7 +559,7 @@ static int get_modified_files(struct repository *r,
 		s.skip_unseen = filter && i;
 
 		opt.def = is_initial ?
-			empty_tree_oid_hex(the_repository->hash_algo) : oid_to_hex(&head_oid);
+			empty_tree_oid_hex(r->hash_algo) : oid_to_hex(&head_oid);
 
 		repo_init_revisions(r, &rev, NULL);
 		setup_revisions(0, NULL, &rev, &opt);
@@ -765,7 +764,7 @@ static int run_revert(struct add_i_state *s, const struct pathspec *ps,
 	size_t count, i, j;
 
 	struct object_id oid;
-	int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+	int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(s->r),
 						  "HEAD", RESOLVE_REF_READING,
 						  &oid,
 						  NULL);
@@ -996,7 +995,7 @@ static int run_diff(struct add_i_state *s, const struct pathspec *ps,
 	ssize_t count, i;
 
 	struct object_id oid;
-	int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+	int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(s->r),
 						  "HEAD", RESOLVE_REF_READING,
 						  &oid,
 						  NULL);
diff --git a/add-patch.c b/add-patch.c
index 7b598e1..95c67d8 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -1464,7 +1464,7 @@ static int patch_update_file(struct add_p_state *s,
 		if (file_diff->hunk_nr) {
 			if (rendered_hunk_index != hunk_index) {
 				if (use_pager) {
-					setup_pager();
+					setup_pager(the_repository);
 					sigchain_push(SIGPIPE, SIG_IGN);
 				}
 				render_hunk(s, hunk, 0, colored, &s->buf);
diff --git a/advice.h b/advice.h
index cf2284e..d233cfc 100644
--- a/advice.h
+++ b/advice.h
@@ -7,7 +7,7 @@ struct string_list;
  * To add a new advice, you need to:
  * Define a new advice_type.
  * Add a new entry to advice_setting array.
- * Add the new config variable to Documentation/config/advice.txt.
+ * Add the new config variable to Documentation/config/advice.adoc.
  * Call advise_if_enabled to print your advice.
  */
 enum advice_type {
diff --git a/apply.c b/apply.c
index 4a7b612..f274a37 100644
--- a/apply.c
+++ b/apply.c
@@ -82,7 +82,7 @@ static int parse_whitespace_option(struct apply_state *state, const char *option
 	}
 	/*
 	 * Please update $__git_whitespacelist in git-completion.bash,
-	 * Documentation/git-apply.txt, and Documentation/git-am.txt
+	 * Documentation/git-apply.adoc, and Documentation/git-am.adoc
 	 * when you add new options.
 	 */
 	return error(_("unrecognized whitespace option '%s'"), option);
@@ -1423,7 +1423,10 @@ static int parse_num(const char *line, unsigned long *p)
 
 	if (!isdigit(*line))
 		return 0;
+	errno = 0;
 	*p = strtoul(line, &ptr, 10);
+	if (errno)
+		return 0;
 	return ptr - line;
 }
 
diff --git a/archive-tar.c b/archive-tar.c
index e7b3489..0edf13f 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -473,9 +473,7 @@ static const char internal_gzip_command[] = "git archive gzip";
 static int write_tar_filter_archive(const struct archiver *ar,
 				    struct archiver_args *args)
 {
-#if ZLIB_VERNUM >= 0x1221
 	struct gz_header_s gzhead = { .os = 3 }; /* Unix, for reproducibility */
-#endif
 	struct strbuf cmd = STRBUF_INIT;
 	struct child_process filter = CHILD_PROCESS_INIT;
 	int r;
@@ -486,10 +484,8 @@ static int write_tar_filter_archive(const struct archiver *ar,
 	if (!strcmp(ar->filter_command, internal_gzip_command)) {
 		write_block = tgz_write_block;
 		git_deflate_init_gzip(&gzstream, args->compression_level);
-#if ZLIB_VERNUM >= 0x1221
 		if (deflateSetHeader(&gzstream.z, &gzhead) != Z_OK)
 			BUG("deflateSetHeader() called too late");
-#endif
 		gzstream.next_out = outbuf;
 		gzstream.avail_out = sizeof(outbuf);
 
diff --git a/archive.c b/archive.c
index b9c200c..8be4e7a 100644
--- a/archive.c
+++ b/archive.c
@@ -7,6 +7,7 @@
 #include "convert.h"
 #include "environment.h"
 #include "gettext.h"
+#include "git-zlib.h"
 #include "hex.h"
 #include "object-name.h"
 #include "path.h"
diff --git a/bisect.c b/bisect.c
index 1a9069c..269a98b 100644
--- a/bisect.c
+++ b/bisect.c
@@ -780,10 +780,10 @@ static struct commit *get_commit_reference(struct repository *r,
 }
 
 static struct commit **get_bad_and_good_commits(struct repository *r,
-						int *rev_nr)
+						size_t *rev_nr)
 {
 	struct commit **rev;
-	int i, n = 0;
+	size_t i, n = 0;
 
 	ALLOC_ARRAY(rev, 1 + good_revs.nr);
 	rev[n++] = get_commit_reference(r, current_bad_oid);
@@ -855,7 +855,7 @@ static void handle_skipped_merge_base(const struct object_id *mb)
  * for early success, this will be converted back to 0 in
  * check_good_are_ancestors_of_bad().
  */
-static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int no_checkout)
+static enum bisect_error check_merge_bases(size_t rev_nr, struct commit **rev, int no_checkout)
 {
 	enum bisect_error res = BISECT_OK;
 	struct commit_list *result = NULL;
@@ -887,7 +887,7 @@ static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int
 	return res;
 }
 
-static int check_ancestors(struct repository *r, int rev_nr,
+static int check_ancestors(struct repository *r, size_t rev_nr,
 			   struct commit **rev, const char *prefix)
 {
 	struct strvec rev_argv = STRVEC_INIT;
@@ -922,14 +922,15 @@ static enum bisect_error check_good_are_ancestors_of_bad(struct repository *r,
 {
 	char *filename;
 	struct stat st;
-	int fd, rev_nr;
+	int fd;
+	size_t rev_nr;
 	enum bisect_error res = BISECT_OK;
 	struct commit **rev;
 
 	if (!current_bad_oid)
 		return error(_("a %s revision is needed"), term_bad);
 
-	filename = git_pathdup("BISECT_ANCESTORS_OK");
+	filename = repo_git_path(the_repository, "BISECT_ANCESTORS_OK");
 
 	/* Check if file BISECT_ANCESTORS_OK exists. */
 	if (!stat(filename, &st) && S_ISREG(st.st_mode))
diff --git a/branch.c b/branch.c
index 7771696..91297d5 100644
--- a/branch.c
+++ b/branch.c
@@ -397,7 +397,7 @@ static void prepare_checked_out_branches(void)
 	worktrees = get_worktrees();
 
 	while (worktrees[i]) {
-		char *old;
+		char *old, *wt_gitdir;
 		struct wt_status_state state = { 0 };
 		struct worktree *wt = worktrees[i++];
 		struct string_list update_refs = STRING_LIST_INIT_DUP;
@@ -437,7 +437,8 @@ static void prepare_checked_out_branches(void)
 		}
 		wt_status_state_free_buffers(&state);
 
-		if (!sequencer_get_update_refs_state(get_worktree_git_dir(wt),
+		wt_gitdir = get_worktree_git_dir(wt);
+		if (!sequencer_get_update_refs_state(wt_gitdir,
 						     &update_refs)) {
 			struct string_list_item *item;
 			for_each_string_list_item(item, &update_refs) {
@@ -448,6 +449,8 @@ static void prepare_checked_out_branches(void)
 			}
 			string_list_clear(&update_refs, 1);
 		}
+
+		free(wt_gitdir);
 	}
 
 	free_worktrees(worktrees);
diff --git a/builtin.h b/builtin.h
index f7b166b..993a583 100644
--- a/builtin.h
+++ b/builtin.h
@@ -63,7 +63,7 @@
  *
  * . Add tests to `t/` directory.
  *
- * . Write documentation in `Documentation/git-foo.txt`.
+ * . Write documentation in `Documentation/git-foo.adoc`.
  *
  * . Add an entry for `git-foo` to `command-list.txt`.
  *
@@ -120,6 +120,7 @@ int cmd_am(int argc, const char **argv, const char *prefix, struct repository *r
 int cmd_annotate(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_apply(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_archive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_backfill(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_bisect(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_blame(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_branch(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/am.c b/builtin/am.c
index 1338b60..2921bb8 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -158,7 +158,7 @@ static void am_state_init(struct am_state *state)
 
 	memset(state, 0, sizeof(*state));
 
-	state->dir = git_pathdup("rebase-apply");
+	state->dir = repo_git_path(the_repository, "rebase-apply");
 
 	state->prec = 4;
 
@@ -1211,7 +1211,7 @@ static int parse_mail(struct am_state *state, const char *mail)
 	int ret = 0;
 	struct mailinfo mi;
 
-	setup_mailinfo(&mi);
+	setup_mailinfo(the_repository, &mi);
 
 	if (state->utf8)
 		mi.metainfo_charset = get_commit_output_encoding();
@@ -1786,7 +1786,7 @@ static int do_interactive(struct am_state *state)
 			}
 			strbuf_release(&msg);
 		} else if (*reply == 'v' || *reply == 'V') {
-			const char *pager = git_pager(1);
+			const char *pager = git_pager(the_repository, 1);
 			struct child_process cp = CHILD_PROCESS_INIT;
 
 			if (!pager)
@@ -2246,7 +2246,7 @@ static int show_patch(struct am_state *state, enum resume_type resume_mode)
 	if (len < 0)
 		die_errno(_("failed to read '%s'"), patch_path);
 
-	setup_pager();
+	setup_pager(the_repository);
 	write_in_full(1, sb.buf, sb.len);
 	strbuf_release(&sb);
 	return 0;
@@ -2427,8 +2427,7 @@ int cmd_am(int argc,
 		OPT_END()
 	};
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(usage, options);
+	show_usage_with_options_if_asked(argc, argv, usage, options);
 
 	git_config(git_default_config, NULL);
 
diff --git a/builtin/backfill.c b/builtin/backfill.c
new file mode 100644
index 0000000..33e1ea2
--- /dev/null
+++ b/builtin/backfill.c
@@ -0,0 +1,147 @@
+/* We need this macro to access core_apply_sparse_checkout */
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "git-compat-util.h"
+#include "config.h"
+#include "parse-options.h"
+#include "repository.h"
+#include "commit.h"
+#include "dir.h"
+#include "environment.h"
+#include "hex.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "object.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
+#include "oidset.h"
+#include "promisor-remote.h"
+#include "strmap.h"
+#include "string-list.h"
+#include "revision.h"
+#include "trace2.h"
+#include "progress.h"
+#include "packfile.h"
+#include "path-walk.h"
+
+static const char * const builtin_backfill_usage[] = {
+	N_("git backfill [--min-batch-size=<n>] [--[no-]sparse]"),
+	NULL
+};
+
+struct backfill_context {
+	struct repository *repo;
+	struct oid_array current_batch;
+	size_t min_batch_size;
+	int sparse;
+};
+
+static void backfill_context_clear(struct backfill_context *ctx)
+{
+	oid_array_clear(&ctx->current_batch);
+}
+
+static void download_batch(struct backfill_context *ctx)
+{
+	promisor_remote_get_direct(ctx->repo,
+				   ctx->current_batch.oid,
+				   ctx->current_batch.nr);
+	oid_array_clear(&ctx->current_batch);
+
+	/*
+	 * We likely have a new packfile. Add it to the packed list to
+	 * avoid possible duplicate downloads of the same objects.
+	 */
+	reprepare_packed_git(ctx->repo);
+}
+
+static int fill_missing_blobs(const char *path UNUSED,
+			      struct oid_array *list,
+			      enum object_type type,
+			      void *data)
+{
+	struct backfill_context *ctx = data;
+
+	if (type != OBJ_BLOB)
+		return 0;
+
+	for (size_t i = 0; i < list->nr; i++) {
+		if (!has_object(ctx->repo, &list->oid[i],
+				OBJECT_INFO_FOR_PREFETCH))
+			oid_array_append(&ctx->current_batch, &list->oid[i]);
+	}
+
+	if (ctx->current_batch.nr >= ctx->min_batch_size)
+		download_batch(ctx);
+
+	return 0;
+}
+
+static int do_backfill(struct backfill_context *ctx)
+{
+	struct rev_info revs;
+	struct path_walk_info info = PATH_WALK_INFO_INIT;
+	int ret;
+
+	if (ctx->sparse) {
+		CALLOC_ARRAY(info.pl, 1);
+		if (get_sparse_checkout_patterns(info.pl)) {
+			path_walk_info_clear(&info);
+			return error(_("problem loading sparse-checkout"));
+		}
+	}
+
+	repo_init_revisions(ctx->repo, &revs, "");
+	handle_revision_arg("HEAD", &revs, 0, 0);
+
+	info.blobs = 1;
+	info.tags = info.commits = info.trees = 0;
+
+	info.revs = &revs;
+	info.path_fn = fill_missing_blobs;
+	info.path_fn_data = ctx;
+
+	ret = walk_objects_by_path(&info);
+
+	/* Download the objects that did not fill a batch. */
+	if (!ret)
+		download_batch(ctx);
+
+	path_walk_info_clear(&info);
+	release_revisions(&revs);
+	return ret;
+}
+
+int cmd_backfill(int argc, const char **argv, const char *prefix, struct repository *repo)
+{
+	int result;
+	struct backfill_context ctx = {
+		.repo = repo,
+		.current_batch = OID_ARRAY_INIT,
+		.min_batch_size = 50000,
+		.sparse = 0,
+	};
+	struct option options[] = {
+		OPT_INTEGER(0, "min-batch-size", &ctx.min_batch_size,
+			    N_("Minimum number of objects to request at a time")),
+		OPT_BOOL(0, "sparse", &ctx.sparse,
+			 N_("Restrict the missing objects to the current sparse-checkout")),
+		OPT_END(),
+	};
+
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_backfill_usage, options);
+
+	argc = parse_options(argc, argv, prefix, options, builtin_backfill_usage,
+			     0);
+
+	repo_config(repo, git_default_config, NULL);
+
+	if (ctx.sparse < 0)
+		ctx.sparse = core_apply_sparse_checkout;
+
+	result = do_backfill(&ctx);
+	backfill_context_clear(&ctx);
+	return result;
+}
diff --git a/builtin/blame.c b/builtin/blame.c
index 7555c44..c470654 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1194,14 +1194,16 @@ int cmd_blame(int argc,
 	sb.found_guilty_entry = &found_guilty_entry;
 	sb.found_guilty_entry_data = &pi;
 	if (show_progress)
-		pi.progress = start_delayed_progress(_("Blaming lines"), num_lines);
+		pi.progress = start_delayed_progress(the_repository,
+						     _("Blaming lines"),
+						     num_lines);
 
 	assign_blame(&sb, opt);
 
 	stop_progress(&pi.progress);
 
 	if (!incremental)
-		setup_pager();
+		setup_pager(the_repository);
 	else
 		goto cleanup;
 
diff --git a/builtin/branch.c b/builtin/branch.c
index 6e7b0cf..c150131 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -473,7 +473,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
 	if (verify_ref_format(format))
 		die(_("unable to parse format string"));
 
-	filter_ahead_behind(the_repository, format, &array);
+	filter_ahead_behind(the_repository, &array);
 	ref_array_sort(sorting, &array);
 
 	if (column_active(colopts)) {
@@ -784,8 +784,8 @@ int cmd_branch(int argc,
 	filter.kind = FILTER_REFS_BRANCHES;
 	filter.abbrev = -1;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(builtin_branch_usage, options);
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_branch_usage, options);
 
 	/*
 	 * Try to set sort keys from config. If config does not set any,
@@ -884,7 +884,6 @@ int cmd_branch(int argc,
 		string_list_clear(&output, 0);
 		ref_sorting_release(sorting);
 		ref_filter_clear(&filter);
-		ref_format_clear(&format);
 
 		ret = 0;
 		goto out;
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 7c2df03..66d64bf 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -12,10 +12,10 @@
 #include "diagnose.h"
 #include "object-file.h"
 #include "setup.h"
+#include "version.h"
 
 static void get_system_info(struct strbuf *sys_info)
 {
-	struct utsname uname_info;
 	char *shell = NULL;
 
 	/* get git version from native cmd */
@@ -24,16 +24,7 @@ static void get_system_info(struct strbuf *sys_info)
 
 	/* system call for other version info */
 	strbuf_addstr(sys_info, "uname: ");
-	if (uname(&uname_info))
-		strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"),
-			    strerror(errno),
-			    errno);
-	else
-		strbuf_addf(sys_info, "%s %s %s %s\n",
-			    uname_info.sysname,
-			    uname_info.release,
-			    uname_info.version,
-			    uname_info.machine);
+	get_uname_info(sys_info, 1);
 
 	strbuf_addstr(sys_info, _("compiler info: "));
 	get_compiler_info(sys_info);
@@ -167,7 +158,7 @@ int cmd_bugreport(int argc,
 		strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
 		strbuf_addstr(&zip_path, ".zip");
 
-		if (create_diagnostics_archive(&zip_path, diagnose))
+		if (create_diagnostics_archive(the_repository, &zip_path, diagnose))
 			die_errno(_("unable to create diagnostics archive %s"), zip_path.buf);
 
 		strbuf_release(&zip_path);
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
index df00b5e..be2cebe 100644
--- a/builtin/check-mailmap.c
+++ b/builtin/check-mailmap.c
@@ -35,7 +35,7 @@ static void check_mailmap(struct string_list *mailmap, const char *contact)
 		mail = ident.mail_begin;
 		maillen = ident.mail_end - ident.mail_begin;
 	} else {
-		name = NULL;
+		name = "";
 		namelen = 0;
 		mail = contact;
 		maillen = strlen(contact);
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index cef1ffe..5d80afe 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -64,8 +64,8 @@ int cmd_check_ref_format(int argc,
 
 	BUG_ON_NON_EMPTY_PREFIX(prefix);
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage(builtin_check_ref_format_usage);
+	show_usage_if_asked(argc, argv,
+			    builtin_check_ref_format_usage);
 
 	if (argc == 3 && !strcmp(argv[1], "--branch"))
 		return check_ref_format_branch(argv[2]);
diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c
index b81002a..da9345a 100644
--- a/builtin/checkout--worker.c
+++ b/builtin/checkout--worker.c
@@ -128,9 +128,9 @@ int cmd_checkout__worker(int argc,
 		OPT_END()
 	};
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(checkout_worker_usage,
-				   checkout_worker_options);
+	show_usage_with_options_if_asked(argc, argv,
+					 checkout_worker_usage,
+					 checkout_worker_options);
 
 	git_config(git_default_config, NULL);
 	argc = parse_options(argc, argv, prefix, checkout_worker_options,
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index a815010..e30086c 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -250,9 +250,9 @@ int cmd_checkout_index(int argc,
 		OPT_END()
 	};
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(builtin_checkout_index_usage,
-				   builtin_checkout_index_options);
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_checkout_index_usage,
+					 builtin_checkout_index_options);
 	git_config(git_default_config, NULL);
 	prefix_length = prefix ? strlen(prefix) : 0;
 
diff --git a/builtin/clone.c b/builtin/clone.c
index fd001d8..f14229a 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -56,42 +56,30 @@
  *  - dropping use-separate-remote and no-separate-remote compatibility
  *
  */
-static const char * const builtin_clone_usage[] = {
-	N_("git clone [<options>] [--] <repo> [<dir>]"),
-	NULL
+
+struct clone_opts {
+	int wants_head;
+	int detach;
 };
+#define CLONE_OPTS_INIT { \
+	.wants_head = 1 /* default enabled */ \
+}
 
 static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
 static int option_local = -1, option_no_hardlinks, option_shared;
-static int option_no_tags;
+static int option_tags = 1; /* default enabled */
 static int option_shallow_submodules;
-static int option_reject_shallow = -1;    /* unspecified */
 static int config_reject_shallow = -1;    /* unspecified */
-static int deepen;
-static char *option_template, *option_depth, *option_since;
-static char *option_origin = NULL;
 static char *remote_name = NULL;
 static char *option_branch = NULL;
-static struct string_list option_not = STRING_LIST_INIT_NODUP;
-static const char *real_git_dir;
-static const char *ref_format;
-static const char *option_upload_pack = "git-upload-pack";
 static int option_verbosity;
-static int option_progress = -1;
-static int option_sparse_checkout;
-static enum transport_family family;
-static struct string_list option_config = STRING_LIST_INIT_NODUP;
 static struct string_list option_required_reference = STRING_LIST_INIT_NODUP;
 static struct string_list option_optional_reference = STRING_LIST_INIT_NODUP;
-static int option_dissociate;
 static int max_jobs = -1;
 static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP;
 static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
-static int option_filter_submodules = -1;    /* unspecified */
 static int config_filter_submodules = -1;    /* unspecified */
-static struct string_list server_options = STRING_LIST_INIT_NODUP;
 static int option_remote_submodules;
-static const char *bundle_uri;
 
 static int recurse_submodules_cb(const struct option *opt,
 				 const char *arg, int unset)
@@ -107,78 +95,6 @@ static int recurse_submodules_cb(const struct option *opt,
 	return 0;
 }
 
-static struct option builtin_clone_options[] = {
-	OPT__VERBOSITY(&option_verbosity),
-	OPT_BOOL(0, "progress", &option_progress,
-		 N_("force progress reporting")),
-	OPT_BOOL(0, "reject-shallow", &option_reject_shallow,
-		 N_("don't clone shallow repository")),
-	OPT_BOOL('n', "no-checkout", &option_no_checkout,
-		 N_("don't create a checkout")),
-	OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
-	OPT_HIDDEN_BOOL(0, "naked", &option_bare,
-			N_("create a bare repository")),
-	OPT_BOOL(0, "mirror", &option_mirror,
-		 N_("create a mirror repository (implies --bare)")),
-	OPT_BOOL('l', "local", &option_local,
-		N_("to clone from a local repository")),
-	OPT_BOOL(0, "no-hardlinks", &option_no_hardlinks,
-		    N_("don't use local hardlinks, always copy")),
-	OPT_BOOL('s', "shared", &option_shared,
-		    N_("setup as shared repository")),
-	{ OPTION_CALLBACK, 0, "recurse-submodules", &option_recurse_submodules,
-	  N_("pathspec"), N_("initialize submodules in the clone"),
-	  PARSE_OPT_OPTARG, recurse_submodules_cb, (intptr_t)"." },
-	OPT_ALIAS(0, "recursive", "recurse-submodules"),
-	OPT_INTEGER('j', "jobs", &max_jobs,
-		    N_("number of submodules cloned in parallel")),
-	OPT_STRING(0, "template", &option_template, N_("template-directory"),
-		   N_("directory from which templates will be used")),
-	OPT_STRING_LIST(0, "reference", &option_required_reference, N_("repo"),
-			N_("reference repository")),
-	OPT_STRING_LIST(0, "reference-if-able", &option_optional_reference,
-			N_("repo"), N_("reference repository")),
-	OPT_BOOL(0, "dissociate", &option_dissociate,
-		 N_("use --reference only while cloning")),
-	OPT_STRING('o', "origin", &option_origin, N_("name"),
-		   N_("use <name> instead of 'origin' to track upstream")),
-	OPT_STRING('b', "branch", &option_branch, N_("branch"),
-		   N_("checkout <branch> instead of the remote's HEAD")),
-	OPT_STRING('u', "upload-pack", &option_upload_pack, N_("path"),
-		   N_("path to git-upload-pack on the remote")),
-	OPT_STRING(0, "depth", &option_depth, N_("depth"),
-		    N_("create a shallow clone of that depth")),
-	OPT_STRING(0, "shallow-since", &option_since, N_("time"),
-		    N_("create a shallow clone since a specific time")),
-	OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("ref"),
-			N_("deepen history of shallow clone, excluding ref")),
-	OPT_BOOL(0, "single-branch", &option_single_branch,
-		    N_("clone only one branch, HEAD or --branch")),
-	OPT_BOOL(0, "no-tags", &option_no_tags,
-		 N_("don't clone any tags, and make later fetches not to follow them")),
-	OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules,
-		    N_("any cloned submodules will be shallow")),
-	OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
-		   N_("separate git dir from working tree")),
-	OPT_STRING(0, "ref-format", &ref_format, N_("format"),
-		   N_("specify the reference format to use")),
-	OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
-			N_("set config inside the new repository")),
-	OPT_STRING_LIST(0, "server-option", &server_options,
-			N_("server-specific"), N_("option to transmit")),
-	OPT_IPVERSION(&family),
-	OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
-	OPT_BOOL(0, "also-filter-submodules", &option_filter_submodules,
-		    N_("apply partial clone filters to submodules")),
-	OPT_BOOL(0, "remote-submodules", &option_remote_submodules,
-		    N_("any cloned submodules will use their remote-tracking branch")),
-	OPT_BOOL(0, "sparse", &option_sparse_checkout,
-		    N_("initialize sparse-checkout file to include only files at root")),
-	OPT_STRING(0, "bundle-uri", &bundle_uri,
-		   N_("uri"), N_("a URI for downloading bundles before fetching from origin remote")),
-	OPT_END()
-};
-
 static const char *get_repo_path_1(struct strbuf *path, int *is_bundle)
 {
 	static const char *suffix[] = { "/.git", "", ".git/.git", ".git" };
@@ -521,51 +437,31 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch
 	return ref;
 }
 
-static struct ref *wanted_peer_refs(const struct ref *refs,
-		struct refspec *refspec)
+static struct ref *wanted_peer_refs(struct clone_opts *opts,
+				    const struct ref *refs,
+				    struct refspec *refspec)
 {
-	struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
-	struct ref *local_refs = head;
-	struct ref **tail = head ? &head->next : &local_refs;
-	struct refspec_item tag_refspec;
+	struct ref *local_refs = NULL;
+	struct ref **tail = &local_refs;
+	struct ref *to_free = NULL;
 
-	refspec_item_init(&tag_refspec, TAG_REFSPEC, 0);
-
-	if (option_single_branch) {
-		struct ref *remote_head = NULL;
-
-		if (!option_branch)
-			remote_head = guess_remote_head(head, refs, 0);
-		else {
-			free_one_ref(head);
-			local_refs = head = NULL;
-			tail = &local_refs;
-			remote_head = copy_ref(find_remote_branch(refs, option_branch));
-		}
-
-		if (!remote_head && option_branch)
-			warning(_("Could not find remote branch %s to clone."),
-				option_branch);
-		else {
-			int i;
-			for (i = 0; i < refspec->nr; i++)
-				get_fetch_map(remote_head, &refspec->items[i],
-					      &tail, 0);
-
-			/* if --branch=tag, pull the requested tag explicitly */
-			get_fetch_map(remote_head, &tag_refspec, &tail, 0);
-		}
-		free_refs(remote_head);
-	} else {
-		int i;
-		for (i = 0; i < refspec->nr; i++)
-			get_fetch_map(refs, &refspec->items[i], &tail, 0);
+	if (opts->wants_head) {
+		struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
+		if (head)
+			tail_link_ref(head, &tail);
+		if (option_single_branch)
+			refs = to_free = guess_remote_head(head, refs, 0);
+	} else if (option_single_branch) {
+		local_refs = NULL;
+		tail = &local_refs;
+		refs = to_free = copy_ref(find_remote_branch(refs, option_branch));
 	}
 
-	if (!option_mirror && !option_single_branch && !option_no_tags)
-		get_fetch_map(refs, &tag_refspec, &tail, 0);
+	for (size_t i = 0; i < refspec->nr; i++)
+		get_fetch_map(refs, &refspec->items[i], &tail, 0);
 
-	refspec_item_clear(&tag_refspec);
+	free_one_ref(to_free);
+
 	return local_refs;
 }
 
@@ -654,7 +550,7 @@ static void update_remote_refs(const struct ref *refs,
 
 	if (refs) {
 		write_remote_refs(mapped_refs);
-		if (option_single_branch && !option_no_tags)
+		if (option_single_branch && option_tags)
 			write_followtags(refs, msg);
 	}
 
@@ -670,11 +566,11 @@ static void update_remote_refs(const struct ref *refs,
 	}
 }
 
-static void update_head(const struct ref *our, const struct ref *remote,
+static void update_head(struct clone_opts *opts, const struct ref *our, const struct ref *remote,
 			const char *unborn, const char *msg)
 {
 	const char *head;
-	if (our && skip_prefix(our->name, "refs/heads/", &head)) {
+	if (our && !opts->detach && skip_prefix(our->name, "refs/heads/", &head)) {
 		/* Local default branch link */
 		if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", our->name, NULL) < 0)
 			die(_("unable to update HEAD"));
@@ -685,8 +581,9 @@ static void update_head(const struct ref *our, const struct ref *remote,
 			install_branch_config(0, head, remote_name, our->name);
 		}
 	} else if (our) {
-		struct commit *c = lookup_commit_reference(the_repository,
-							   &our->old_oid);
+		struct commit *c = lookup_commit_or_die(&our->old_oid,
+							our->name);
+
 		/* --branch specifies a non-branch (i.e. tags), detach HEAD */
 		refs_update_ref(get_main_ref_store(the_repository), msg,
 				"HEAD", &c->object.oid, NULL, REF_NO_DEREF,
@@ -938,7 +835,7 @@ static void write_refspec_config(const char *src_ref_prefix,
 
 static void dissociate_from_references(void)
 {
-	char *alternates = git_pathdup("objects/info/alternates");
+	char *alternates = repo_git_path(the_repository, "objects/info/alternates");
 
 	if (!access(alternates, F_OK)) {
 		struct child_process cmd = CHILD_PROCESS_INIT;
@@ -989,10 +886,108 @@ int cmd_clone(int argc,
 	int hash_algo;
 	enum ref_storage_format ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
 	const int do_not_override_repo_unix_permissions = -1;
+	int option_reject_shallow = -1; /* unspecified */
+	int deepen = 0;
+	char *option_template = NULL, *option_depth = NULL, *option_since = NULL;
+	char *option_origin = NULL;
+	struct string_list option_not = STRING_LIST_INIT_NODUP;
+	const char *real_git_dir = NULL;
+	const char *ref_format = NULL;
+	const char *option_upload_pack = "git-upload-pack";
+	int option_progress = -1;
+	int option_sparse_checkout = 0;
+	enum transport_family family = TRANSPORT_FAMILY_ALL;
+	struct string_list option_config = STRING_LIST_INIT_DUP;
+	int option_dissociate = 0;
+	int option_filter_submodules = -1; /* unspecified */
+	struct string_list server_options = STRING_LIST_INIT_NODUP;
+	const char *bundle_uri = NULL;
+	char *option_rev = NULL;
+
+	struct clone_opts opts = CLONE_OPTS_INIT;
 
 	struct transport_ls_refs_options transport_ls_refs_options =
 		TRANSPORT_LS_REFS_OPTIONS_INIT;
 
+	struct option builtin_clone_options[] = {
+		OPT__VERBOSITY(&option_verbosity),
+		OPT_BOOL(0, "progress", &option_progress,
+			 N_("force progress reporting")),
+		OPT_BOOL(0, "reject-shallow", &option_reject_shallow,
+			 N_("don't clone shallow repository")),
+		OPT_BOOL('n', "no-checkout", &option_no_checkout,
+			 N_("don't create a checkout")),
+		OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
+		OPT_HIDDEN_BOOL(0, "naked", &option_bare,
+				N_("create a bare repository")),
+		OPT_BOOL(0, "mirror", &option_mirror,
+			 N_("create a mirror repository (implies --bare)")),
+		OPT_BOOL('l', "local", &option_local,
+			 N_("to clone from a local repository")),
+		OPT_BOOL(0, "no-hardlinks", &option_no_hardlinks,
+			 N_("don't use local hardlinks, always copy")),
+		OPT_BOOL('s', "shared", &option_shared,
+			 N_("setup as shared repository")),
+		{ OPTION_CALLBACK, 0, "recurse-submodules", &option_recurse_submodules,
+		  N_("pathspec"), N_("initialize submodules in the clone"),
+		  PARSE_OPT_OPTARG, recurse_submodules_cb, (intptr_t)"." },
+		OPT_ALIAS(0, "recursive", "recurse-submodules"),
+		OPT_INTEGER('j', "jobs", &max_jobs,
+			    N_("number of submodules cloned in parallel")),
+		OPT_STRING(0, "template", &option_template, N_("template-directory"),
+			   N_("directory from which templates will be used")),
+		OPT_STRING_LIST(0, "reference", &option_required_reference, N_("repo"),
+				N_("reference repository")),
+		OPT_STRING_LIST(0, "reference-if-able", &option_optional_reference,
+				N_("repo"), N_("reference repository")),
+		OPT_BOOL(0, "dissociate", &option_dissociate,
+			 N_("use --reference only while cloning")),
+		OPT_STRING('o', "origin", &option_origin, N_("name"),
+			   N_("use <name> instead of 'origin' to track upstream")),
+		OPT_STRING('b', "branch", &option_branch, N_("branch"),
+			   N_("checkout <branch> instead of the remote's HEAD")),
+		OPT_STRING(0, "revision", &option_rev, N_("rev"),
+			   N_("clone single revision <rev> and check out")),
+		OPT_STRING('u', "upload-pack", &option_upload_pack, N_("path"),
+			   N_("path to git-upload-pack on the remote")),
+		OPT_STRING(0, "depth", &option_depth, N_("depth"),
+			   N_("create a shallow clone of that depth")),
+		OPT_STRING(0, "shallow-since", &option_since, N_("time"),
+			   N_("create a shallow clone since a specific time")),
+		OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("ref"),
+				N_("deepen history of shallow clone, excluding ref")),
+		OPT_BOOL(0, "single-branch", &option_single_branch,
+			 N_("clone only one branch, HEAD or --branch")),
+		OPT_BOOL(0, "tags", &option_tags,
+			 N_("clone tags, and make later fetches not to follow them")),
+		OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules,
+			 N_("any cloned submodules will be shallow")),
+		OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
+			   N_("separate git dir from working tree")),
+		OPT_STRING(0, "ref-format", &ref_format, N_("format"),
+			   N_("specify the reference format to use")),
+		OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
+				N_("set config inside the new repository")),
+		OPT_STRING_LIST(0, "server-option", &server_options,
+				N_("server-specific"), N_("option to transmit")),
+		OPT_IPVERSION(&family),
+		OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+		OPT_BOOL(0, "also-filter-submodules", &option_filter_submodules,
+			 N_("apply partial clone filters to submodules")),
+		OPT_BOOL(0, "remote-submodules", &option_remote_submodules,
+			 N_("any cloned submodules will use their remote-tracking branch")),
+		OPT_BOOL(0, "sparse", &option_sparse_checkout,
+			 N_("initialize sparse-checkout file to include only files at root")),
+		OPT_STRING(0, "bundle-uri", &bundle_uri,
+			   N_("uri"), N_("a URI for downloading bundles before fetching from origin remote")),
+		OPT_END()
+	};
+
+	const char * const builtin_clone_usage[] = {
+		N_("git clone [<options>] [--] <repo> [<dir>]"),
+		NULL
+	};
+
 	packet_trace_identity("clone");
 
 	git_config(git_clone_config, NULL);
@@ -1019,8 +1014,10 @@ int cmd_clone(int argc,
 			die(_("unknown ref storage format '%s'"), ref_format);
 	}
 
-	if (option_mirror)
+	if (option_mirror) {
 		option_bare = 1;
+		option_tags = 0;
+	}
 
 	if (option_bare) {
 		if (real_git_dir)
@@ -1138,8 +1135,8 @@ int cmd_clone(int argc,
 		for_each_string_list_item(item, &option_recurse_submodules) {
 			strbuf_addf(&sb, "submodule.active=%s",
 				    item->string);
-			string_list_append(&option_config,
-					   strbuf_detach(&sb, NULL));
+			string_list_append(&option_config, sb.buf);
+			strbuf_reset(&sb);
 		}
 
 		if (!git_config_get_bool("submodule.stickyRecursiveClone", &val) &&
@@ -1161,6 +1158,8 @@ int cmd_clone(int argc,
 			string_list_append(&option_config,
 				"submodule.alternateErrorStrategy=info");
 		}
+
+		strbuf_release(&sb);
 	}
 
 	/*
@@ -1220,7 +1219,7 @@ int cmd_clone(int argc,
 
 	strbuf_reset(&buf);
 	strbuf_addf(&buf, "%s/refs", git_dir);
-	safe_create_dir(buf.buf, 1);
+	safe_create_dir(the_repository, buf.buf, 1);
 
 	/*
 	 * additional config can be injected with -c, make sure it's included
@@ -1285,7 +1284,7 @@ int cmd_clone(int argc,
 		strbuf_addstr(&branch_top, src_ref_prefix);
 
 		git_config_set("core.bare", "true");
-	} else {
+	} else if (!option_rev) {
 		strbuf_addf(&branch_top, "refs/remotes/%s/", remote_name);
 	}
 
@@ -1293,7 +1292,7 @@ int cmd_clone(int argc,
 	git_config_set(key.buf, repo);
 	strbuf_reset(&key);
 
-	if (option_no_tags) {
+	if (!option_tags) {
 		strbuf_addf(&key, "remote.%s.tagOpt", remote_name);
 		git_config_set(key.buf, "--no-tags");
 		strbuf_reset(&key);
@@ -1304,8 +1303,9 @@ int cmd_clone(int argc,
 
 	remote = remote_get_early(remote_name);
 
-	refspec_appendf(&remote->fetch, "+%s*:%s*", src_ref_prefix,
-			branch_top.buf);
+	if (!option_rev)
+		refspec_appendf(&remote->fetch, "+%s*:%s*", src_ref_prefix,
+				branch_top.buf);
 
 	path = get_repo_path(remote->url.v[0], &is_bundle);
 	is_local = option_local != 0 && path && !is_bundle;
@@ -1348,6 +1348,11 @@ int cmd_clone(int argc,
 
 	transport_set_option(transport, TRANS_OPT_KEEP, "yes");
 
+	die_for_incompatible_opt2(!!option_rev, "--revision",
+				  !!option_branch, "--branch");
+	die_for_incompatible_opt2(!!option_rev, "--revision",
+				  option_mirror, "--mirror");
+
 	if (reject_shallow)
 		transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");
 	if (option_depth)
@@ -1359,9 +1364,13 @@ int cmd_clone(int argc,
 	if (option_not.nr)
 		transport_set_option(transport, TRANS_OPT_DEEPEN_NOT,
 				     (const char *)&option_not);
-	if (option_single_branch)
+	if (option_single_branch) {
 		transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
 
+		if (option_branch)
+			opts.wants_head = 0;
+	}
+
 	if (option_upload_pack)
 		transport_set_option(transport, TRANS_OPT_UPLOADPACK,
 				     option_upload_pack);
@@ -1380,15 +1389,38 @@ int cmd_clone(int argc,
 	if (transport->smart_options && !deepen && !filter_options.choice)
 		transport->smart_options->check_self_contained_and_connected = 1;
 
-	strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+	if (option_rev) {
+		option_tags = 0;
+		option_single_branch = 0;
+		opts.wants_head = 0;
+		opts.detach = 1;
+
+		refspec_append(&remote->fetch, option_rev);
+	}
+
+	if (option_tags || option_branch)
+		/*
+		 * Add tags refspec when user asked for tags (implicitly) or
+		 * specified --branch, whose argument might be a tag.
+		 */
+		refspec_append(&remote->fetch, TAG_REFSPEC);
+
 	refspec_ref_prefixes(&remote->fetch,
 			     &transport_ls_refs_options.ref_prefixes);
 	if (option_branch)
 		expand_ref_prefix(&transport_ls_refs_options.ref_prefixes,
 				  option_branch);
-	if (!option_no_tags)
-		strvec_push(&transport_ls_refs_options.ref_prefixes,
-			    "refs/tags/");
+
+	/*
+	 * As part of transport_get_remote_refs() the server tells us the hash
+	 * algorithm, which we require to initialize the repo. But calling that
+	 * function without any ref prefix, will cause the server to announce
+	 * all known refs. If the argument passed to --revision was a hex oid,
+	 * ref_prefixes will be empty so we fall back to asking about HEAD to
+	 * reduce traffic from the server.
+	 */
+	if (opts.wants_head || transport_ls_refs_options.ref_prefixes.nr == 0)
+		strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
 
 	refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
 
@@ -1465,7 +1497,7 @@ int cmd_clone(int argc,
 	}
 
 	if (refs)
-		mapped_refs = wanted_peer_refs(refs, &remote->fetch);
+		mapped_refs = wanted_peer_refs(&opts, refs, &remote->fetch);
 
 	if (mapped_refs) {
 		/*
@@ -1498,6 +1530,11 @@ int cmd_clone(int argc,
 		if (!our_head_points_at)
 			die(_("Remote branch %s not found in upstream %s"),
 			    option_branch, remote_name);
+	} else if (option_rev) {
+		our_head_points_at = mapped_refs;
+		if (!our_head_points_at)
+			die(_("Remote revision %s not found in upstream %s"),
+			    option_rev, remote_name);
 	} else if (remote_head_points_at) {
 		our_head_points_at = remote_head_points_at;
 	} else if (remote_head) {
@@ -1536,8 +1573,9 @@ int cmd_clone(int argc,
 		free(to_free);
 	}
 
-	write_refspec_config(src_ref_prefix, our_head_points_at,
-			remote_head_points_at, &branch_top);
+	if (!option_rev)
+		write_refspec_config(src_ref_prefix, our_head_points_at,
+				     remote_head_points_at, &branch_top);
 
 	if (filter_options.choice)
 		partial_clone_register(remote_name, &filter_options);
@@ -1553,7 +1591,7 @@ int cmd_clone(int argc,
 			   branch_top.buf, reflog_msg.buf, transport,
 			   !is_local);
 
-	update_head(our_head_points_at, remote_head, unborn_head, reflog_msg.buf);
+	update_head(&opts, our_head_points_at, remote_head, unborn_head, reflog_msg.buf);
 
 	/*
 	 * We want to show progress for recursive submodule clones iff
@@ -1578,6 +1616,10 @@ int cmd_clone(int argc,
 	err = checkout(submodule_progress, filter_submodules,
 		       ref_storage_format);
 
+	string_list_clear(&option_not, 0);
+	string_list_clear(&option_config, 0);
+	string_list_clear(&server_options, 0);
+
 	free(remote_name);
 	strbuf_release(&reflog_msg);
 	strbuf_release(&branch_top);
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index bd70d05..8ca7526 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -305,6 +305,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
 		oidset_init(&commits, 0);
 		if (opts.progress)
 			progress = start_delayed_progress(
+				the_repository,
 				_("Collecting commits from input"), 0);
 
 		while (strbuf_getline(&buf, stdin) != EOF) {
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 2ca1a57..3845760 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -119,8 +119,8 @@ int cmd_commit_tree(int argc,
 
 	git_config(git_default_config, NULL);
 
-	if (argc < 2 || !strcmp(argv[1], "-h"))
-		usage_with_options(commit_tree_usage, options);
+	show_usage_with_options_if_asked(argc, argv,
+					 commit_tree_usage, options);
 
 	argc = parse_options(argc, argv, prefix, options, commit_tree_usage, 0);
 
diff --git a/builtin/commit.c b/builtin/commit.c
index ef5e622..2f45968 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -44,7 +44,7 @@
 #include "trailer.h"
 
 static const char * const builtin_commit_usage[] = {
-	N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+	N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 	   "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>]\n"
 	   "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 	   "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
@@ -352,6 +352,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
 	struct pathspec pathspec;
 	int refresh_flags = REFRESH_QUIET;
 	const char *ret;
+	char *path = NULL;
 
 	if (is_status)
 		refresh_flags |= REFRESH_UNMERGED;
@@ -524,9 +525,9 @@ static const char *prepare_index(const char **argv, const char *prefix,
 	if (write_locked_index(the_repository->index, &index_lock, 0))
 		die(_("unable to write new index file"));
 
-	hold_lock_file_for_update(&false_lock,
-				  git_path("next-index-%"PRIuMAX,
-					   (uintmax_t) getpid()),
+	path = repo_git_path(the_repository, "next-index-%"PRIuMAX,
+			     (uintmax_t) getpid());
+	hold_lock_file_for_update(&false_lock, path,
 				  LOCK_DIE_ON_ERROR);
 
 	create_base_index(current_head);
@@ -542,6 +543,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
 out:
 	string_list_clear(&partial, 0);
 	clear_pathspec(&pathspec);
+	free(path);
 	return ret;
 }
 
@@ -1559,8 +1561,8 @@ struct repository *repo UNUSED)
 		OPT_END(),
 	};
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(builtin_status_usage, builtin_status_options);
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_status_usage, builtin_status_options);
 
 	prepare_repo_settings(the_repository);
 	the_repository->settings.command_requires_full_index = 0;
@@ -1736,8 +1738,8 @@ int cmd_commit(int argc,
 	struct strbuf err = STRBUF_INIT;
 	int ret = 0;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(builtin_commit_usage, builtin_commit_options);
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_commit_usage, builtin_commit_options);
 
 	prepare_repo_settings(the_repository);
 	the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/config.c b/builtin/config.c
index 16e6e30..53a9009 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -775,13 +775,13 @@ static void location_options_init(struct config_location_options *opts,
 		opts->source.file = opts->file_to_free = git_system_config();
 		opts->source.scope = CONFIG_SCOPE_SYSTEM;
 	} else if (opts->use_local_config) {
-		opts->source.file = opts->file_to_free = git_pathdup("config");
+		opts->source.file = opts->file_to_free = repo_git_path(the_repository, "config");
 		opts->source.scope = CONFIG_SCOPE_LOCAL;
 	} else if (opts->use_worktree_config) {
 		struct worktree **worktrees = get_worktrees();
 		if (the_repository->repository_format_worktree_config)
 			opts->source.file = opts->file_to_free =
-				git_pathdup("config.worktree");
+				repo_git_path(the_repository, "config.worktree");
 		else if (worktrees[0] && worktrees[1])
 			die(_("--worktree cannot be used with multiple "
 			      "working trees unless the config\n"
@@ -790,7 +790,7 @@ static void location_options_init(struct config_location_options *opts,
 			      "section in \"git help worktree\" for details"));
 		else
 			opts->source.file = opts->file_to_free =
-				git_pathdup("config");
+				repo_git_path(the_repository, "config");
 		opts->source.scope = CONFIG_SCOPE_LOCAL;
 		free_worktrees(worktrees);
 	} else if (opts->source.file) {
@@ -1087,7 +1087,7 @@ static int show_editor(struct config_location_options *opts)
 	git_config(git_default_config, NULL);
 	config_file = opts->source.file ?
 			xstrdup(opts->source.file) :
-			git_pathdup("config");
+			repo_git_path(the_repository, "config");
 	if (opts->use_global_config) {
 		int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
 		if (fd >= 0) {
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index bc22f5c..e707618 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -142,9 +142,9 @@ static void serve_one_client(FILE *in, FILE *out)
 				fprintf(out, "username=%s\n", e->item.username);
 			if (e->item.password)
 				fprintf(out, "password=%s\n", e->item.password);
-			if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_HELPER) && e->item.authtype)
+			if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_RESPONSE) && e->item.authtype)
 				fprintf(out, "authtype=%s\n", e->item.authtype);
-			if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_HELPER) && e->item.credential)
+			if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_RESPONSE) && e->item.credential)
 				fprintf(out, "credential=%s\n", e->item.credential);
 			if (e->item.password_expiry_utc != TIME_MAX)
 				fprintf(out, "password_expiry_utc=%"PRItime"\n",
diff --git a/builtin/credential.c b/builtin/credential.c
index 14c8c66..2e11b15 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -18,7 +18,8 @@ int cmd_credential(int argc,
 
 	git_config(git_default_config, NULL);
 
-	if (argc != 2 || !strcmp(argv[1], "-h"))
+	show_usage_if_asked(argc, argv, usage_msg);
+	if (argc != 2)
 		usage(usage_msg);
 	op = argv[1];
 
@@ -32,15 +33,15 @@ int cmd_credential(int argc,
 		die("unable to read credential from stdin");
 
 	if (!strcmp(op, "fill")) {
-		credential_fill(&c, 0);
+		credential_fill(the_repository, &c, 0);
 		credential_next_state(&c);
 		credential_write(&c, stdout, CREDENTIAL_OP_RESPONSE);
 	} else if (!strcmp(op, "approve")) {
 		credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER);
-		credential_approve(&c);
+		credential_approve(the_repository, &c);
 	} else if (!strcmp(op, "reject")) {
 		credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER);
-		credential_reject(&c);
+		credential_reject(the_repository, &c);
 	} else {
 		usage(usage_msg);
 	}
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
index 66a22d9..33c39bd 100644
--- a/builtin/diagnose.c
+++ b/builtin/diagnose.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
 #include "abspath.h"
 #include "gettext.h"
@@ -58,7 +60,7 @@ int cmd_diagnose(int argc,
 	}
 
 	/* Prepare diagnostics */
-	if (create_diagnostics_archive(&zip_path, mode))
+	if (create_diagnostics_archive(the_repository, &zip_path, mode))
 		die_errno(_("unable to create diagnostics archive %s"),
 			  zip_path.buf);
 
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 604b04b..99b1749 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -29,8 +29,7 @@ int cmd_diff_files(int argc,
 	int result;
 	unsigned options = 0;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage(diff_files_usage);
+	show_usage_if_asked(argc, argv, diff_files_usage);
 
 	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index ebc8246..81c0bc8 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -26,8 +26,7 @@ int cmd_diff_index(int argc,
 	int i;
 	int result;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage(diff_cache_usage);
+	show_usage_if_asked(argc, argv, diff_cache_usage);
 
 	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 40804e7..e31cc79 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -122,8 +122,7 @@ int cmd_diff_tree(int argc,
 	int read_stdin = 0;
 	int merge_base = 0;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage(diff_tree_usage);
+	show_usage_if_asked(argc, argv, diff_tree_usage);
 
 	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 03a8bb9..41cd000 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -12,8 +12,6 @@
  * Copyright (C) 2016 Johannes Schindelin
  */
 
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "builtin.h"
 
 #include "abspath.h"
@@ -36,18 +34,27 @@
 #include "entry.h"
 #include "setup.h"
 
-static int trust_exit_code;
-
 static const char *const builtin_difftool_usage[] = {
 	N_("git difftool [<options>] [<commit> [<commit>]] [--] [<path>...]"),
 	NULL
 };
 
+struct difftool_options {
+	int has_symlinks;
+	int symlinks;
+	int trust_exit_code;
+};
+
 static int difftool_config(const char *var, const char *value,
 			   const struct config_context *ctx, void *cb)
 {
+	struct difftool_options *dt_options = (struct difftool_options *)cb;
 	if (!strcmp(var, "difftool.trustexitcode")) {
-		trust_exit_code = git_config_bool(var, value);
+		dt_options->trust_exit_code = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "core.symlinks")) {
+		dt_options->has_symlinks = git_config_bool(var, value);
 		return 0;
 	}
 
@@ -63,7 +70,8 @@ static int print_tool_help(void)
 	return run_command(&cmd);
 }
 
-static int parse_index_info(char *p, int *mode1, int *mode2,
+static int parse_index_info(struct repository *repo,
+			    char *p, int *mode1, int *mode2,
 			    struct object_id *oid1, struct object_id *oid2,
 			    char *status)
 {
@@ -75,11 +83,11 @@ static int parse_index_info(char *p, int *mode1, int *mode2,
 	*mode2 = (int)strtol(p + 1, &p, 8);
 	if (*p != ' ')
 		return error("expected ' ', got '%c'", *p);
-	if (parse_oid_hex(++p, oid1, (const char **)&p))
+	if (parse_oid_hex_algop(++p, oid1, (const char **)&p, repo->hash_algo))
 		return error("expected object ID, got '%s'", p);
 	if (*p != ' ')
 		return error("expected ' ', got '%c'", *p);
-	if (parse_oid_hex(++p, oid2, (const char **)&p))
+	if (parse_oid_hex_algop(++p, oid2, (const char **)&p, repo->hash_algo))
 		return error("expected object ID, got '%s'", p);
 	if (*p != ' ')
 		return error("expected ' ', got '%c'", *p);
@@ -106,7 +114,8 @@ static void add_path(struct strbuf *buf, size_t base_len, const char *path)
 /*
  * Determine whether we can simply reuse the file in the worktree.
  */
-static int use_wt_file(const char *workdir, const char *name,
+static int use_wt_file(struct repository *repo,
+		       const char *workdir, const char *name,
 		       struct object_id *oid)
 {
 	struct strbuf buf = STRBUF_INIT;
@@ -121,7 +130,7 @@ static int use_wt_file(const char *workdir, const char *name,
 		int fd = open(buf.buf, O_RDONLY);
 
 		if (fd >= 0 &&
-		    !index_fd(the_repository->index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) {
+		    !index_fd(repo->index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) {
 			if (is_null_oid(oid)) {
 				oidcpy(oid, &wt_oid);
 				use = 1;
@@ -212,13 +221,14 @@ static int path_entry_cmp(const void *cmp_data UNUSED,
 	return strcmp(a->path, key ? key : b->path);
 }
 
-static void changed_files(struct hashmap *result, const char *index_path,
+static void changed_files(struct repository *repo,
+			  struct hashmap *result, const char *index_path,
 			  const char *workdir)
 {
 	struct child_process update_index = CHILD_PROCESS_INIT;
 	struct child_process diff_files = CHILD_PROCESS_INIT;
 	struct strbuf buf = STRBUF_INIT;
-	const char *git_dir = absolute_path(repo_get_git_dir(the_repository));
+	const char *git_dir = absolute_path(repo_get_git_dir(repo));
 	FILE *fp;
 
 	strvec_pushl(&update_index.args,
@@ -291,13 +301,15 @@ static int ensure_leading_directories(char *path)
  * to compare the readlink(2) result as text, even on a filesystem that is
  * capable of doing a symbolic link.
  */
-static char *get_symlink(const struct object_id *oid, const char *path)
+static char *get_symlink(struct repository *repo,
+			 struct difftool_options *dt_options,
+			 const struct object_id *oid, const char *path)
 {
 	char *data;
 	if (is_null_oid(oid)) {
 		/* The symlink is unknown to Git so read from the filesystem */
 		struct strbuf link = STRBUF_INIT;
-		if (has_symlinks) {
+		if (dt_options->has_symlinks) {
 			if (strbuf_readlink(&link, path, strlen(path)))
 				die(_("could not read symlink %s"), path);
 		} else if (strbuf_read_file(&link, path, 128))
@@ -307,8 +319,7 @@ static char *get_symlink(const struct object_id *oid, const char *path)
 	} else {
 		enum object_type type;
 		unsigned long size;
-		data = repo_read_object_file(the_repository, oid, &type,
-					     &size);
+		data = repo_read_object_file(repo, oid, &type, &size);
 		if (!data)
 			die(_("could not read object %s for symlink %s"),
 				oid_to_hex(oid), path);
@@ -355,7 +366,9 @@ static void write_standin_files(struct pair_entry *entry,
 		write_file_in_directory(rdir, rdir_len, entry->path, entry->right);
 }
 
-static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
+static int run_dir_diff(struct repository *repo,
+			struct difftool_options *dt_options,
+			const char *extcmd, const char *prefix,
 			struct child_process *child)
 {
 	struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT;
@@ -375,7 +388,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 = INDEX_STATE_INIT(the_repository);
+	struct index_state wtindex = INDEX_STATE_INIT(repo);
 	struct checkout lstate, rstate;
 	int err = 0;
 	struct child_process cmd = CHILD_PROCESS_INIT;
@@ -383,7 +396,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	struct hashmap tmp_modified = HASHMAP_INIT(path_entry_cmp, NULL);
 	int indices_loaded = 0;
 
-	workdir = repo_get_work_tree(the_repository);
+	workdir = repo_get_work_tree(repo);
 
 	/* Setup temp directories */
 	tmp = getenv("TMPDIR");
@@ -438,8 +451,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 			       "not supported in\n"
 			       "directory diff mode ('-d' and '--dir-diff')."));
 
-		if (parse_index_info(info.buf, &lmode, &rmode, &loid, &roid,
-				     &status))
+		if (parse_index_info(repo, info.buf, &lmode, &rmode, &loid, &roid, &status))
 			break;
 		if (strbuf_getline_nul(&lpath, fp))
 			break;
@@ -469,13 +481,13 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		}
 
 		if (S_ISLNK(lmode)) {
-			char *content = get_symlink(&loid, src_path);
+			char *content = get_symlink(repo, dt_options, &loid, src_path);
 			add_left_or_right(&symlinks2, src_path, content, 0);
 			free(content);
 		}
 
 		if (S_ISLNK(rmode)) {
-			char *content = get_symlink(&roid, dst_path);
+			char *content = get_symlink(repo, dt_options, &roid, dst_path);
 			add_left_or_right(&symlinks2, dst_path, content, 1);
 			free(content);
 		}
@@ -500,7 +512,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 			}
 			hashmap_add(&working_tree_dups, &entry->entry);
 
-			if (!use_wt_file(workdir, dst_path, &roid)) {
+			if (!use_wt_file(repo, workdir, dst_path, &roid)) {
 				if (checkout_path(rmode, &roid, dst_path,
 						  &rstate)) {
 					ret = error("could not write '%s'",
@@ -528,7 +540,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 					goto finish;
 				}
 				add_path(&wtdir, wtdir_len, dst_path);
-				if (symlinks) {
+				if (dt_options->symlinks) {
 					if (symlink(wtdir.buf, rdir.buf)) {
 						ret = error_errno("could not symlink '%s' to '%s'", wtdir.buf, rdir.buf);
 						goto finish;
@@ -614,7 +626,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		if (lstat(rdir.buf, &st))
 			continue;
 
-		if ((symlinks && S_ISLNK(st.st_mode)) || !S_ISREG(st.st_mode))
+		if ((dt_options->symlinks && S_ISLNK(st.st_mode)) || !S_ISREG(st.st_mode))
 			continue;
 
 		if (!indices_loaded) {
@@ -626,9 +638,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 				ret = error("could not write %s", buf.buf);
 				goto finish;
 			}
-			changed_files(&wt_modified, buf.buf, workdir);
+			changed_files(repo, &wt_modified, buf.buf, workdir);
 			strbuf_setlen(&rdir, rdir_len);
-			changed_files(&tmp_modified, buf.buf, rdir.buf);
+			changed_files(repo, &tmp_modified, buf.buf, rdir.buf);
 			add_path(&rdir, rdir_len, name);
 			indices_loaded = 1;
 		}
@@ -702,11 +714,15 @@ static int run_file_diff(int prompt, const char *prefix,
 int cmd_difftool(int argc,
 		 const char **argv,
 		 const char *prefix,
-		 struct repository *repo UNUSED)
+		 struct repository *repo)
 {
-	int use_gui_tool = -1, dir_diff = 0, prompt = -1, symlinks = 0,
-	    tool_help = 0, no_index = 0;
+	int use_gui_tool = -1, dir_diff = 0, prompt = -1, tool_help = 0, no_index = 0;
 	static char *difftool_cmd = NULL, *extcmd = NULL;
+	struct difftool_options dt_options = {
+		.has_symlinks = 1,
+		.symlinks = 1,
+		.trust_exit_code = 0
+	};
 	struct option builtin_difftool_options[] = {
 		OPT_BOOL('g', "gui", &use_gui_tool,
 			 N_("use `diff.guitool` instead of `diff.tool`")),
@@ -717,14 +733,14 @@ int cmd_difftool(int argc,
 			0, PARSE_OPT_NONEG),
 		OPT_SET_INT_F(0, "prompt", &prompt, NULL,
 			1, PARSE_OPT_NONEG | PARSE_OPT_HIDDEN),
-		OPT_BOOL(0, "symlinks", &symlinks,
+		OPT_BOOL(0, "symlinks", &dt_options.symlinks,
 			 N_("use symlinks in dir-diff mode")),
 		OPT_STRING('t', "tool", &difftool_cmd, N_("tool"),
 			   N_("use the specified diff tool")),
 		OPT_BOOL(0, "tool-help", &tool_help,
 			 N_("print a list of diff tools that may be used with "
 			    "`--tool`")),
-		OPT_BOOL(0, "trust-exit-code", &trust_exit_code,
+		OPT_BOOL(0, "trust-exit-code", &dt_options.trust_exit_code,
 			 N_("make 'git-difftool' exit when an invoked diff "
 			    "tool returns a non-zero exit code")),
 		OPT_STRING('x', "extcmd", &extcmd, N_("command"),
@@ -734,8 +750,9 @@ int cmd_difftool(int argc,
 	};
 	struct child_process child = CHILD_PROCESS_INIT;
 
-	git_config(difftool_config, NULL);
-	symlinks = has_symlinks;
+	if (repo)
+		repo_config(repo, difftool_config, &dt_options);
+	dt_options.symlinks = dt_options.has_symlinks;
 
 	argc = parse_options(argc, argv, prefix, builtin_difftool_options,
 			     builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN_OPT |
@@ -749,8 +766,8 @@ int cmd_difftool(int argc,
 
 	if (!no_index){
 		setup_work_tree();
-		setenv(GIT_DIR_ENVIRONMENT, absolute_path(repo_get_git_dir(the_repository)), 1);
-		setenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(repo_get_work_tree(the_repository)), 1);
+		setenv(GIT_DIR_ENVIRONMENT, absolute_path(repo_get_git_dir(repo)), 1);
+		setenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(repo_get_work_tree(repo)), 1);
 	} else if (dir_diff)
 		die(_("options '%s' and '%s' cannot be used together"), "--dir-diff", "--no-index");
 
@@ -783,7 +800,7 @@ int cmd_difftool(int argc,
 	}
 
 	setenv("GIT_DIFFTOOL_TRUST_EXIT_CODE",
-	       trust_exit_code ? "true" : "false", 1);
+	       dt_options.trust_exit_code ? "true" : "false", 1);
 
 	/*
 	 * In directory diff mode, 'git-difftool--helper' is called once
@@ -799,6 +816,6 @@ int cmd_difftool(int argc,
 	strvec_pushv(&child.args, argv);
 
 	if (dir_diff)
-		return run_dir_diff(extcmd, symlinks, prefix, &child);
+		return run_dir_diff(repo, &dt_options, extcmd, prefix, &child);
 	return run_file_diff(prompt, prefix, &child);
 }
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 0f86392..397a6f4 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -328,7 +328,7 @@ static void write_branch_report(FILE *rpt, struct branch *b)
 
 static void write_crash_report(const char *err)
 {
-	char *loc = git_pathdup("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
+	char *loc = repo_git_path(the_repository, "fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
 	FILE *rpt = fopen(loc, "w");
 	struct branch *b;
 	unsigned long lu;
@@ -798,8 +798,8 @@ static const char *create_index(void)
 	if (c != last)
 		die("internal consistency error creating the index");
 
-	tmpfile = write_idx_file(NULL, idx, object_count, &pack_idx_opts,
-				 pack_data->hash);
+	tmpfile = write_idx_file(the_hash_algo, NULL, idx, object_count,
+				 &pack_idx_opts, pack_data->hash);
 	free(idx);
 	return tmpfile;
 }
@@ -878,9 +878,10 @@ static void end_packfile(void)
 
 		close_pack_windows(pack_data);
 		finalize_hashfile(pack_file, cur_pack_oid.hash, FSYNC_COMPONENT_PACK, 0);
-		fixup_pack_header_footer(pack_data->pack_fd, pack_data->hash,
-					 pack_data->pack_name, object_count,
-					 cur_pack_oid.hash, pack_size);
+		fixup_pack_header_footer(the_hash_algo, pack_data->pack_fd,
+					 pack_data->hash, pack_data->pack_name,
+					 object_count, cur_pack_oid.hash,
+					 pack_size);
 
 		if (object_count <= unpack_limit) {
 			if (!loosen_small_pack(pack_data)) {
@@ -953,15 +954,15 @@ static int store_object(
 	unsigned char hdr[96];
 	struct object_id oid;
 	unsigned long hdrlen, deltalen;
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 	git_zstream s;
 
 	hdrlen = format_object_header((char *)hdr, sizeof(hdr), type,
 				      dat->len);
 	the_hash_algo->init_fn(&c);
-	the_hash_algo->update_fn(&c, hdr, hdrlen);
-	the_hash_algo->update_fn(&c, dat->buf, dat->len);
-	the_hash_algo->final_oid_fn(&oid, &c);
+	git_hash_update(&c, hdr, hdrlen);
+	git_hash_update(&c, dat->buf, dat->len);
+	git_hash_final_oid(&oid, &c);
 	if (oidout)
 		oidcpy(oidout, &oid);
 
@@ -1095,7 +1096,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
 	struct object_id oid;
 	unsigned long hdrlen;
 	off_t offset;
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 	git_zstream s;
 	struct hashfile_checkpoint checkpoint;
 	int status = Z_OK;
@@ -1106,14 +1107,14 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
 		|| (pack_size + PACK_SIZE_THRESHOLD + len) < pack_size)
 		cycle_packfile();
 
-	the_hash_algo->unsafe_init_fn(&checkpoint.ctx);
+	hashfile_checkpoint_init(pack_file, &checkpoint);
 	hashfile_checkpoint(pack_file, &checkpoint);
 	offset = checkpoint.offset;
 
 	hdrlen = format_object_header((char *)out_buf, out_sz, OBJ_BLOB, len);
 
 	the_hash_algo->init_fn(&c);
-	the_hash_algo->update_fn(&c, out_buf, hdrlen);
+	git_hash_update(&c, out_buf, hdrlen);
 
 	crc32_begin(pack_file);
 
@@ -1131,7 +1132,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
 			if (!n && feof(stdin))
 				die("EOF in data (%" PRIuMAX " bytes remaining)", len);
 
-			the_hash_algo->update_fn(&c, in_buf, n);
+			git_hash_update(&c, in_buf, n);
 			s.next_in = in_buf;
 			s.avail_in = n;
 			len -= n;
@@ -1157,7 +1158,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
 		}
 	}
 	git_deflate_end(&s);
-	the_hash_algo->final_oid_fn(&oid, &c);
+	git_hash_final_oid(&oid, &c);
 
 	if (oidout)
 		oidcpy(oidout, &oid);
@@ -3279,7 +3280,7 @@ static char* make_fast_import_path(const char *path)
 {
 	if (!relative_marks_paths || is_absolute_path(path))
 		return prefix_filename(global_prefix, path);
-	return git_pathdup("info/fast-import/%s", path);
+	return repo_git_path(the_repository, "info/fast-import/%s", path);
 }
 
 static void option_import_marks(const char *marks,
@@ -3565,8 +3566,7 @@ int cmd_fast_import(int argc,
 {
 	unsigned int i;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage(fast_import_usage);
+	show_usage_if_asked(argc, argv, fast_import_usage);
 
 	reset_pack_idx_option(&pack_idx_opts);
 	git_pack_config();
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index bed2816..d07eec9 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -75,6 +75,8 @@ int cmd_fetch_pack(int argc,
 	list_objects_filter_init(&args.filter_options);
 	args.uploadpack = "git-upload-pack";
 
+	show_usage_if_asked(argc, argv, fetch_pack_usage);
+
 	for (i = 1; i < argc && *argv[i] == '-'; i++) {
 		const char *arg = argv[i];
 
diff --git a/builtin/fetch.c b/builtin/fetch.c
index fe2b26c..95fd001 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1617,13 +1617,13 @@ static void report_set_head(const char *remote, const char *head_name,
 	strbuf_release(&buf_prefix);
 }
 
-static int set_head(const struct ref *remote_refs, int follow_remote_head,
-		const char *no_warn_branch)
+static int set_head(const struct ref *remote_refs, struct remote *remote)
 {
-	int result = 0, create_only, is_bare, was_detached;
+	int result = 0, create_only, baremirror, was_detached;
 	struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
 		      b_local_head = STRBUF_INIT;
-	const char *remote = gtransport->remote->name;
+	int follow_remote_head = remote->follow_remote_head;
+	const char *no_warn_branch = remote->no_warn_branch;
 	char *head_name = NULL;
 	struct ref *ref, *matches;
 	struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
@@ -1655,17 +1655,17 @@ static int set_head(const struct ref *remote_refs, int follow_remote_head,
 
 	if (!head_name)
 		goto cleanup;
-	is_bare = is_bare_repository();
-	create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !is_bare;
-	if (is_bare) {
+	baremirror = is_bare_repository() && remote->mirror;
+	create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !baremirror;
+	if (baremirror) {
 		strbuf_addstr(&b_head, "HEAD");
 		strbuf_addf(&b_remote_head, "refs/heads/%s", head_name);
 	} else {
-		strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote);
-		strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name);
+		strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote->name);
+		strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote->name, head_name);
 	}
 		/* make sure it's valid */
-	if (!is_bare && !refs_ref_exists(refs, b_remote_head.buf)) {
+	if (!baremirror && !refs_ref_exists(refs, b_remote_head.buf)) {
 		result = 1;
 		goto cleanup;
 	}
@@ -1678,7 +1678,7 @@ static int set_head(const struct ref *remote_refs, int follow_remote_head,
 	if (verbosity >= 0 &&
 		follow_remote_head == FOLLOW_REMOTE_WARN &&
 		(!no_warn_branch || strcmp(no_warn_branch, head_name)))
-		report_set_head(remote, head_name, &b_local_head, was_detached);
+		report_set_head(remote->name, head_name, &b_local_head, was_detached);
 
 cleanup:
 	free(head_name);
@@ -1777,7 +1777,9 @@ static int do_fetch(struct transport *transport,
 
 	if (uses_remote_tracking(transport, rs)) {
 		must_list_refs = 1;
-		strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+		if (transport_ls_refs_options.ref_prefixes.nr)
+			strvec_push(&transport_ls_refs_options.ref_prefixes,
+				    "HEAD");
 	}
 
 	if (must_list_refs) {
@@ -1924,8 +1926,7 @@ static int do_fetch(struct transport *transport,
 				  "you need to specify exactly one branch with the --set-upstream option"));
 		}
 	}
-	if (set_head(remote_refs, transport->remote->follow_remote_head,
-		transport->remote->no_warn_branch))
+	if (set_head(remote_refs, transport->remote))
 		;
 		/*
 		 * Way too many cases where this can go wrong
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 715745a..8085ebd 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -108,7 +108,6 @@ int cmd_for_each_ref(int argc,
 	filter_and_format_refs(&filter, flags, sorting, &format);
 
 	ref_filter_clear(&filter);
-	ref_format_clear(&format);
 	ref_sorting_release(sorting);
 	strvec_clear(&vec);
 	return 0;
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 0196c54..eea1d43 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -197,7 +197,8 @@ static int traverse_reachable(void)
 	unsigned int nr = 0;
 	int result = 0;
 	if (show_progress)
-		progress = start_delayed_progress(_("Checking connectivity"), 0);
+		progress = start_delayed_progress(the_repository,
+						  _("Checking connectivity"), 0);
 	while (pending.nr) {
 		result |= traverse_one_object(object_array_pop(&pending));
 		display_progress(progress, ++nr);
@@ -325,7 +326,7 @@ static void check_unreachable_object(struct object *obj)
 				  printable_type(&obj->oid, obj->type),
 				  describe_object(&obj->oid));
 		if (write_lost_and_found) {
-			char *filename = git_pathdup("lost-found/%s/%s",
+			char *filename = repo_git_path(the_repository, "lost-found/%s/%s",
 				obj->type == OBJ_COMMIT ? "commit" : "other",
 				describe_object(&obj->oid));
 			FILE *f;
@@ -703,7 +704,8 @@ static void fsck_object_dir(const char *path)
 		fprintf_ln(stderr, _("Checking object directory"));
 
 	if (show_progress)
-		progress = start_progress(_("Checking object directories"), 256);
+		progress = start_progress(the_repository,
+					  _("Checking object directories"), 256);
 
 	for_each_loose_file_in_objdir(path, fsck_loose, fsck_cruft, fsck_subdir,
 				      &cb_data);
@@ -879,7 +881,8 @@ static int check_pack_rev_indexes(struct repository *r, int show_progress)
 	if (show_progress) {
 		for (struct packed_git *p = get_all_packs(r); p; p = p->next)
 			pack_count++;
-		progress = start_delayed_progress("Verifying reverse pack-indexes", pack_count);
+		progress = start_delayed_progress(the_repository,
+						  "Verifying reverse pack-indexes", pack_count);
 		pack_count = 0;
 	}
 
@@ -989,7 +992,8 @@ int cmd_fsck(int argc,
 					total += p->num_objects;
 				}
 
-				progress = start_progress(_("Checking objects"), total);
+				progress = start_progress(the_repository,
+							  _("Checking objects"), total);
 			}
 			for (p = get_all_packs(the_repository); p;
 			     p = p->next) {
@@ -1053,7 +1057,7 @@ int cmd_fsck(int argc,
 			struct worktree *wt = *p;
 			struct index_state istate =
 				INDEX_STATE_INIT(the_repository);
-			char *path;
+			char *path, *wt_gitdir;
 
 			/*
 			 * Make a copy since the buffer is reusable
@@ -1061,9 +1065,13 @@ int cmd_fsck(int argc,
 			 * while we're examining the index.
 			 */
 			path = xstrdup(worktree_git_path(the_repository, wt, "index"));
-			read_index_from(&istate, path, get_worktree_git_dir(wt));
+			wt_gitdir = get_worktree_git_dir(wt);
+
+			read_index_from(&istate, path, wt_gitdir);
 			fsck_index(&istate, path, wt->is_current);
+
 			discard_index(&istate);
+			free(wt_gitdir);
 			free(path);
 		}
 		free_worktrees(worktrees);
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 029dc64..0820e52 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1598,8 +1598,8 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED
 		OPT_END()
 	};
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(builtin_fsmonitor__daemon_usage, options);
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_fsmonitor__daemon_usage, options);
 
 	die(_("fsmonitor--daemon not supported on this platform"));
 }
diff --git a/builtin/gc.c b/builtin/gc.c
index a9b1c36..99431fd 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -99,9 +99,11 @@ static void process_log_file(void)
 		/* There was some error recorded in the lock file */
 		commit_lock_file(&log_lock);
 	} else {
+		char *path = repo_git_path(the_repository, "gc.log");
 		/* No error, clean up any old gc.log */
-		unlink(git_path("gc.log"));
+		unlink(path);
 		rollback_lock_file(&log_lock);
+		free(path);
 	}
 }
 
@@ -139,6 +141,7 @@ struct gc_config {
 	char *prune_worktrees_expire;
 	char *repack_filter;
 	char *repack_filter_to;
+	char *repack_expire_to;
 	unsigned long big_pack_threshold;
 	unsigned long max_delta_cache_size;
 	/*
@@ -299,8 +302,11 @@ static int too_many_loose_objects(struct gc_config *cfg)
 	int num_loose = 0;
 	int needed = 0;
 	const unsigned hexsz_loose = the_hash_algo->hexsz - 2;
+	char *path;
 
-	dir = opendir(git_path("objects/17"));
+	path = repo_git_path(the_repository, "objects/17");
+	dir = opendir(path);
+	free(path);
 	if (!dir)
 		return 0;
 
@@ -445,7 +451,8 @@ static int keep_one_pack(struct string_list_item *item, void *data UNUSED)
 static void add_repack_all_option(struct gc_config *cfg,
 				  struct string_list *keep_pack)
 {
-	if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now"))
+	if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now")
+		&& !(cfg->cruft_packs && cfg->repack_expire_to))
 		strvec_push(&repack, "-a");
 	else if (cfg->cruft_packs) {
 		strvec_push(&repack, "--cruft");
@@ -454,6 +461,8 @@ static void add_repack_all_option(struct gc_config *cfg,
 		if (cfg->max_cruft_size)
 			strvec_pushf(&repack, "--max-cruft-size=%lu",
 				     cfg->max_cruft_size);
+		if (cfg->repack_expire_to)
+			strvec_pushf(&repack, "--expire-to=%s", cfg->repack_expire_to);
 	} else {
 		strvec_push(&repack, "-A");
 		if (cfg->prune_expire)
@@ -546,7 +555,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
 	if (xgethostname(my_host, sizeof(my_host)))
 		xsnprintf(my_host, sizeof(my_host), "unknown");
 
-	pidfile_path = git_pathdup("gc.pid");
+	pidfile_path = repo_git_path(the_repository, "gc.pid");
 	fd = hold_lock_file_for_update(&lock, pidfile_path,
 				       LOCK_DIE_ON_ERROR);
 	if (!force) {
@@ -607,7 +616,7 @@ static int report_last_gc_error(void)
 	int ret = 0;
 	ssize_t len;
 	struct stat st;
-	char *gc_log_path = git_pathdup("gc.log");
+	char *gc_log_path = repo_git_path(the_repository, "gc.log");
 
 	if (stat(gc_log_path, &st)) {
 		if (errno == ENOENT)
@@ -688,7 +697,6 @@ struct repository *repo UNUSED)
 	const char *prune_expire_sentinel = "sentinel";
 	const char *prune_expire_arg = prune_expire_sentinel;
 	int ret;
-
 	struct option builtin_gc_options[] = {
 		OPT__QUIET(&quiet, N_("suppress progress reporting")),
 		{ OPTION_STRING, 0, "prune", &prune_expire_arg, N_("date"),
@@ -707,11 +715,13 @@ struct repository *repo UNUSED)
 			   PARSE_OPT_NOCOMPLETE),
 		OPT_BOOL(0, "keep-largest-pack", &keep_largest_pack,
 			 N_("repack all other packs except the largest pack")),
+		OPT_STRING(0, "expire-to", &cfg.repack_expire_to, N_("dir"),
+			   N_("pack prefix to store a pack containing pruned objects")),
 		OPT_END()
 	};
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(builtin_gc_usage, builtin_gc_options);
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_gc_usage, builtin_gc_options);
 
 	strvec_pushl(&reflog, "reflog", "expire", "--all", NULL);
 	strvec_pushl(&repack, "repack", "-d", "-l", NULL);
@@ -821,11 +831,12 @@ struct repository *repo UNUSED)
 	}
 
 	if (daemonized) {
-		hold_lock_file_for_update(&log_lock,
-					  git_path("gc.log"),
+		char *path = repo_git_path(the_repository, "gc.log");
+		hold_lock_file_for_update(&log_lock, path,
 					  LOCK_DIE_ON_ERROR);
 		dup2(get_lock_file_fd(&log_lock), 2);
 		atexit(process_log_file_at_exit);
+		free(path);
 	}
 
 	gc_before_repack(&opts, &cfg);
@@ -887,8 +898,11 @@ struct repository *repo UNUSED)
 		warning(_("There are too many unreachable loose objects; "
 			"run 'git prune' to remove them."));
 
-	if (!daemonized)
-		unlink(git_path("gc.log"));
+	if (!daemonized) {
+		char *path = repo_git_path(the_repository, "gc.log");
+		unlink(path);
+		free(path);
+	}
 
 out:
 	gc_config_release(&cfg);
@@ -1909,7 +1923,7 @@ static int get_random_minute(void)
 	if (getenv("GIT_TEST_MAINT_SCHEDULER"))
 		return 13;
 
-	return git_rand() % 60;
+	return git_rand(0) % 60;
 }
 
 static int is_launchctl_available(void)
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
index 6bec0d1..e4cd162 100644
--- a/builtin/get-tar-commit-id.c
+++ b/builtin/get-tar-commit-id.c
@@ -13,7 +13,7 @@ static const char builtin_get_tar_commit_id_usage[] =
 #define HEADERSIZE (2 * RECORDSIZE)
 
 int cmd_get_tar_commit_id(int argc,
-			  const char **argv UNUSED,
+			  const char **argv,
 			  const char *prefix,
 			  struct repository *repo UNUSED)
 {
@@ -27,6 +27,8 @@ int cmd_get_tar_commit_id(int argc,
 
 	BUG_ON_NON_EMPTY_PREFIX(prefix);
 
+	show_usage_if_asked(argc, argv, builtin_get_tar_commit_id_usage);
+
 	if (argc != 1)
 		usage(builtin_get_tar_commit_id_usage);
 
diff --git a/builtin/grep.c b/builtin/grep.c
index d00ee76..d142729 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -1084,7 +1084,7 @@ int cmd_grep(int argc,
 	}
 
 	if (show_in_pager == default_pager)
-		show_in_pager = git_pager(1);
+		show_in_pager = git_pager(the_repository, 1);
 	if (show_in_pager) {
 		opt.color = 0;
 		opt.name_only = 1;
@@ -1246,7 +1246,7 @@ int cmd_grep(int argc,
 	}
 
 	if (!show_in_pager && !opt.status_only)
-		setup_pager();
+		setup_pager(the_repository);
 
 	die_for_incompatible_opt3(!use_index, "--no-index",
 				  untracked, "--untracked",
diff --git a/builtin/help.c b/builtin/help.c
index 0513627..c257079 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -658,7 +658,7 @@ int cmd_help(int argc,
 	case HELP_ACTION_ALL:
 		opt_mode_usage(argc, "--all", help_format);
 		if (verbose) {
-			setup_pager();
+			setup_pager(the_repository);
 			list_all_cmds_help(show_external_commands,
 					   show_aliases);
 			return 0;
@@ -692,7 +692,7 @@ int cmd_help(int argc,
 		return 0;
 	case HELP_ACTION_CONFIG:
 		opt_mode_usage(argc, "--config", help_format);
-		setup_pager();
+		setup_pager(the_repository);
 		list_config_help(SHOW_CONFIG_HUMAN);
 		printf("\n%s\n", _("'git help config' for more information"));
 		return 0;
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 0b62b25..52cc97d 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -151,7 +151,7 @@ static unsigned int input_offset, input_len;
 static off_t consumed_bytes;
 static off_t max_input_size;
 static unsigned deepest_delta;
-static git_hash_ctx input_ctx;
+static struct git_hash_ctx input_ctx;
 static uint32_t input_crc32;
 static int input_fd, output_fd;
 static const char *curr_pack;
@@ -282,7 +282,8 @@ static unsigned check_objects(void)
 	max = get_max_object_index();
 
 	if (verbose)
-		progress = start_delayed_progress(_("Checking objects"), max);
+		progress = start_delayed_progress(the_repository,
+						  _("Checking objects"), max);
 
 	for (i = 0; i < max; i++) {
 		foreign_nr += check_object(get_indexed_object(i));
@@ -300,7 +301,7 @@ static void flush(void)
 	if (input_offset) {
 		if (output_fd >= 0)
 			write_or_die(output_fd, input_buffer, input_offset);
-		the_hash_algo->update_fn(&input_ctx, input_buffer, input_offset);
+		git_hash_update(&input_ctx, input_buffer, input_offset);
 		memmove(input_buffer, input_buffer + input_offset, input_len);
 		input_offset = 0;
 	}
@@ -379,16 +380,18 @@ static const char *open_pack_file(const char *pack_name)
 
 static void parse_pack_header(void)
 {
-	struct pack_header *hdr = fill(sizeof(struct pack_header));
+	unsigned char *hdr = fill(sizeof(struct pack_header));
 
 	/* Header consistency check */
-	if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
+	if (get_be32(hdr) != PACK_SIGNATURE)
 		die(_("pack signature mismatch"));
-	if (!pack_version_ok(hdr->hdr_version))
+	hdr += 4;
+	if (!pack_version_ok_native(get_be32(hdr)))
 		die(_("pack version %"PRIu32" unsupported"),
-			ntohl(hdr->hdr_version));
+		    get_be32(hdr));
+	hdr += 4;
 
-	nr_objects = ntohl(hdr->hdr_entries);
+	nr_objects = get_be32(hdr);
 	use(sizeof(struct pack_header));
 }
 
@@ -472,14 +475,14 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
 	int status;
 	git_zstream stream;
 	void *buf;
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 	char hdr[32];
 	int hdrlen;
 
 	if (!is_delta_type(type)) {
 		hdrlen = format_object_header(hdr, sizeof(hdr), type, size);
 		the_hash_algo->init_fn(&c);
-		the_hash_algo->update_fn(&c, hdr, hdrlen);
+		git_hash_update(&c, hdr, hdrlen);
 	} else
 		oid = NULL;
 	if (type == OBJ_BLOB && size > big_file_threshold)
@@ -499,7 +502,7 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
 		status = git_inflate(&stream, 0);
 		use(input_len - stream.avail_in);
 		if (oid)
-			the_hash_algo->update_fn(&c, last_out, stream.next_out - last_out);
+			git_hash_update(&c, last_out, stream.next_out - last_out);
 		if (buf == fixed_buf) {
 			stream.next_out = buf;
 			stream.avail_out = sizeof(fixed_buf);
@@ -509,7 +512,7 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
 		bad_object(offset, _("inflate returned %d"), status);
 	git_inflate_end(&stream);
 	if (oid)
-		the_hash_algo->final_oid_fn(oid, &c);
+		git_hash_final_oid(oid, &c);
 	return buf == fixed_buf ? NULL : buf;
 }
 
@@ -1245,10 +1248,11 @@ static void parse_pack_objects(unsigned char *hash)
 	struct ofs_delta_entry *ofs_delta = ofs_deltas;
 	struct object_id ref_delta_oid;
 	struct stat st;
-	git_hash_ctx tmp_ctx;
+	struct git_hash_ctx tmp_ctx;
 
 	if (verbose)
 		progress = start_progress(
+				the_repository,
 				progress_title ? progress_title :
 				from_stdin ? _("Receiving objects") : _("Indexing objects"),
 				nr_objects);
@@ -1282,9 +1286,8 @@ static void parse_pack_objects(unsigned char *hash)
 
 	/* Check pack integrity */
 	flush();
-	the_hash_algo->init_fn(&tmp_ctx);
-	the_hash_algo->clone_fn(&tmp_ctx, &input_ctx);
-	the_hash_algo->final_fn(hash, &tmp_ctx);
+	git_hash_clone(&tmp_ctx, &input_ctx);
+	git_hash_final(hash, &tmp_ctx);
 	if (!hasheq(fill(the_hash_algo->rawsz), hash, the_repository->hash_algo))
 		die(_("pack is corrupted (SHA1 mismatch)"));
 	use(the_hash_algo->rawsz);
@@ -1329,7 +1332,8 @@ static void resolve_deltas(struct pack_idx_option *opts)
 	QSORT(ref_deltas, nr_ref_deltas, compare_ref_delta_entry);
 
 	if (verbose || show_resolving_progress)
-		progress = start_progress(_("Resolving deltas"),
+		progress = start_progress(the_repository,
+					  _("Resolving deltas"),
 					  nr_ref_deltas + nr_ofs_deltas);
 
 	nr_dispatched = 0;
@@ -1387,7 +1391,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
 		strbuf_release(&msg);
 		finalize_hashfile(f, tail_hash, FSYNC_COMPONENT_PACK, 0);
 		hashcpy(read_hash, pack_hash, the_repository->hash_algo);
-		fixup_pack_header_footer(output_fd, pack_hash,
+		fixup_pack_header_footer(the_hash_algo, output_fd, pack_hash,
 					 curr_pack, nr_objects,
 					 read_hash, consumed_bytes-the_hash_algo->rawsz);
 		if (!hasheq(read_hash, tail_hash, the_repository->hash_algo))
@@ -1897,8 +1901,7 @@ int cmd_index_pack(int argc,
 	 */
 	fetch_if_missing = 0;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage(index_pack_usage);
+	show_usage_if_asked(argc, argv, index_pack_usage);
 
 	disable_replace_refs();
 	fsck_options.walk = mark_link;
@@ -1954,19 +1957,11 @@ int cmd_index_pack(int argc,
 					warning(_("no threads support, ignoring %s"), arg);
 					nr_threads = 1;
 				}
-			} else if (starts_with(arg, "--pack_header=")) {
-				struct pack_header *hdr;
-				char *c;
-
-				hdr = (struct pack_header *)input_buffer;
-				hdr->hdr_signature = htonl(PACK_SIGNATURE);
-				hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10));
-				if (*c != ',')
-					die(_("bad %s"), arg);
-				hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10));
-				if (*c)
-					die(_("bad %s"), arg);
-				input_len = sizeof(*hdr);
+			} else if (skip_prefix(arg, "--pack_header=", &arg)) {
+				if (parse_pack_header_option(arg,
+							     input_buffer,
+							     &input_len) < 0)
+					die(_("bad --pack_header: %s"), arg);
 			} else if (!strcmp(arg, "-v")) {
 				verbose = 1;
 			} else if (!strcmp(arg, "--progress-title")) {
@@ -2093,11 +2088,12 @@ int cmd_index_pack(int argc,
 	ALLOC_ARRAY(idx_objects, nr_objects);
 	for (i = 0; i < nr_objects; i++)
 		idx_objects[i] = &objects[i].idx;
-	curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_hash);
+	curr_index = write_idx_file(the_hash_algo, index_name, idx_objects,
+				    nr_objects, &opts, pack_hash);
 	if (rev_index)
-		curr_rev_index = write_rev_file(rev_index_name, idx_objects,
-						nr_objects, pack_hash,
-						opts.flags);
+		curr_rev_index = write_rev_file(the_hash_algo, rev_index_name,
+						idx_objects, nr_objects,
+						pack_hash, opts.flags);
 	free(idx_objects);
 
 	if (!verify)
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 096f96b..196dccd 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -132,8 +132,8 @@ int cmd_init_db(int argc,
 				 * and we know shared_repository should always be 0;
 				 * but just in case we play safe.
 				 */
-				saved = get_shared_repository();
-				set_shared_repository(0);
+				saved = repo_settings_get_shared_repository(the_repository);
+				repo_settings_set_shared_repository(the_repository, 0);
 				switch (safe_create_leading_directories_const(argv[0])) {
 				case SCLD_OK:
 				case SCLD_PERMS:
@@ -145,7 +145,7 @@ int cmd_init_db(int argc,
 					die_errno(_("cannot mkdir %s"), argv[0]);
 					break;
 				}
-				set_shared_repository(saved);
+				repo_settings_set_shared_repository(the_repository, saved);
 				if (mkdir(argv[0], 0777) < 0)
 					die_errno(_("cannot mkdir %s"), argv[0]);
 				mkdir_tried = 1;
@@ -175,7 +175,7 @@ int cmd_init_db(int argc,
 	}
 
 	if (init_shared_repository != -1)
-		set_shared_repository(init_shared_repository);
+		repo_settings_set_shared_repository(the_repository, init_shared_repository);
 
 	/*
 	 * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
diff --git a/builtin/log.c b/builtin/log.c
index 75e1b34..04a6ef9 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -6,7 +6,6 @@
  */
 
 #define USE_THE_REPOSITORY_VARIABLE
-#define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "builtin.h"
 #include "abspath.h"
@@ -209,7 +208,6 @@ static void cmd_log_init_defaults(struct rev_info *rev,
 
 static void set_default_decoration_filter(struct decoration_filter *decoration_filter)
 {
-	int i;
 	char *value = NULL;
 	struct string_list *include = decoration_filter->include_ref_pattern;
 	const struct string_list *config_exclude;
@@ -243,7 +241,7 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
 	 * No command-line or config options were given, so
 	 * populate with sensible defaults.
 	 */
-	for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) {
+	for (size_t i = 0; i < ARRAY_SIZE(ref_namespace); i++) {
 		if (!ref_namespace[i].decoration)
 			continue;
 
@@ -369,7 +367,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
 	if (rev->line_level_traverse)
 		line_log_init(rev, line_cb.prefix, &line_cb.args);
 
-	setup_pager();
+	setup_pager(the_repository);
 }
 
 static void cmd_log_init(int argc, const char **argv, const char *prefix,
@@ -717,14 +715,14 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 	unsigned long size;
 	enum object_type type;
 	char *buf = repo_read_object_file(the_repository, oid, &type, &size);
-	int offset = 0;
+	unsigned long offset = 0;
 
 	if (!buf)
 		return error(_("could not read object %s"), oid_to_hex(oid));
 
 	assert(type == OBJ_TAG);
 	while (offset < size && buf[offset] != '\n') {
-		int new_offset = offset + 1;
+		unsigned long new_offset = offset + 1;
 		const char *ident;
 		while (new_offset < size && buf[new_offset++] != '\n')
 			; /* do nothing */
@@ -1316,24 +1314,25 @@ static void print_signature(const char *signature, FILE *file)
 
 static char *find_branch_name(struct rev_info *rev)
 {
-	int i, positive = -1;
 	struct object_id branch_oid;
 	const struct object_id *tip_oid;
 	const char *ref, *v;
 	char *full_ref, *branch = NULL;
+	int interesting_found = 0;
+	size_t idx;
 
-	for (i = 0; i < rev->cmdline.nr; i++) {
+	for (size_t i = 0; i < rev->cmdline.nr; i++) {
 		if (rev->cmdline.rev[i].flags & UNINTERESTING)
 			continue;
-		if (positive < 0)
-			positive = i;
-		else
+		if (interesting_found)
 			return NULL;
+		interesting_found = 1;
+		idx = i;
 	}
-	if (positive < 0)
+	if (!interesting_found)
 		return NULL;
-	ref = rev->cmdline.rev[positive].name;
-	tip_oid = &rev->cmdline.rev[positive].item->oid;
+	ref = rev->cmdline.rev[idx].name;
+	tip_oid = &rev->cmdline.rev[idx].item->oid;
 	if (repo_dwim_ref(the_repository, ref, strlen(ref), &branch_oid,
 			  &full_ref, 0) &&
 	    skip_prefix(full_ref, "refs/heads/", &v) &&
@@ -1746,11 +1745,12 @@ struct base_tree_info {
 
 static struct commit *get_base_commit(const struct format_config *cfg,
 				      struct commit **list,
-				      int total)
+				      size_t total)
 {
 	struct commit *base = NULL;
 	struct commit **rev;
-	int i = 0, rev_nr = 0, auto_select, die_on_failure, ret;
+	int auto_select, die_on_failure, ret;
+	size_t i = 0, rev_nr = 0;
 
 	switch (cfg->auto_base) {
 	case AUTO_BASE_NEVER:
@@ -1885,13 +1885,12 @@ define_commit_slab(commit_base, int);
 static void prepare_bases(struct base_tree_info *bases,
 			  struct commit *base,
 			  struct commit **list,
-			  int total)
+			  size_t total)
 {
 	struct commit *commit;
 	struct rev_info revs;
 	struct diff_options diffopt;
 	struct commit_base commit_base;
-	int i;
 
 	if (!base)
 		return;
@@ -1906,7 +1905,7 @@ static void prepare_bases(struct base_tree_info *bases,
 	repo_init_revisions(the_repository, &revs, NULL);
 	revs.max_parents = 1;
 	revs.topo_order = 1;
-	for (i = 0; i < total; i++) {
+	for (size_t i = 0; i < total; i++) {
 		list[i]->object.flags &= ~UNINTERESTING;
 		add_pending_object(&revs, &list[i]->object, "rev_list");
 		*commit_base_at(&commit_base, list[i]) = 1;
@@ -2007,7 +2006,7 @@ int cmd_format_patch(int argc,
 	struct rev_info rev;
 	char *to_free = NULL;
 	struct setup_revision_opt s_r_opt;
-	int nr = 0, total, i;
+	size_t nr = 0, total, i;
 	int use_stdout = 0;
 	int start_number = -1;
 	int just_numbers = 0;
@@ -2183,7 +2182,7 @@ int cmd_format_patch(int argc,
 		fmt_patch_suffix = cfg.fmt_patch_suffix;
 
 	/* Make sure "0000-$sub.patch" gives non-negative length for $sub */
-	if (cfg.log.fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix))
+	if (cfg.log.fmt_patch_name_max <= cast_size_t_to_int(strlen("0000-") + strlen(fmt_patch_suffix)))
 		cfg.log.fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
 
 	if (cover_from_description_arg)
@@ -2296,7 +2295,7 @@ int cmd_format_patch(int argc,
 		rev.commit_format = CMIT_FMT_MBOXRD;
 
 	if (use_stdout) {
-		setup_pager();
+		setup_pager(the_repository);
 	} else if (!rev.diffopt.close_file) {
 		int saved;
 
@@ -2310,8 +2309,8 @@ int cmd_format_patch(int argc,
 		 * We consider <outdir> as 'outside of gitdir', therefore avoid
 		 * applying adjust_shared_perm in s-c-l-d.
 		 */
-		saved = get_shared_repository();
-		set_shared_repository(0);
+		saved = repo_settings_get_shared_repository(the_repository);
+		repo_settings_set_shared_repository(the_repository, 0);
 		switch (safe_create_leading_directories_const(output_directory)) {
 		case SCLD_OK:
 		case SCLD_EXISTS:
@@ -2320,7 +2319,7 @@ int cmd_format_patch(int argc,
 			die(_("could not create leading directories "
 			      "of '%s'"), output_directory);
 		}
-		set_shared_repository(saved);
+		repo_settings_set_shared_repository(the_repository, saved);
 		if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
 			die_errno(_("could not create directory '%s'"),
 				  output_directory);
@@ -2499,12 +2498,16 @@ int cmd_format_patch(int argc,
 	rev.add_signoff = cfg.do_signoff;
 
 	if (show_progress)
-		progress = start_delayed_progress(_("Generating patches"), total);
-	while (0 <= --nr) {
+		progress = start_delayed_progress(the_repository,
+						  _("Generating patches"), total);
+	for (i = 0; i < nr; i++) {
+		size_t idx = nr - i - 1;
 		int shown;
-		display_progress(progress, total - nr);
-		commit = list[nr];
-		rev.nr = total - nr + (start_number - 1);
+
+		display_progress(progress, total - idx);
+		commit = list[idx];
+		rev.nr = total - idx + (start_number - 1);
+
 		/* Make the second and subsequent mails replies to the first */
 		if (cfg.thread) {
 			/* Have we already had a message ID? */
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 15499cd..a443142 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -644,8 +644,8 @@ int cmd_ls_files(int argc,
 	};
 	int ret = 0;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(ls_files_usage, builtin_ls_files_options);
+	show_usage_with_options_if_asked(argc, argv,
+					 ls_files_usage, builtin_ls_files_options);
 
 	prepare_repo_settings(the_repository);
 	the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index e17dec2..8de7ba7 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -83,7 +83,7 @@ int cmd_mailinfo(int argc,
 		OPT_END()
 	};
 
-	setup_mailinfo(&mi);
+	setup_mailinfo(the_repository, &mi);
 	meta_charset.policy = CHARSET_DEFAULT;
 
 	argc = parse_options(argc, argv, prefix, options, mailinfo_usage, 0);
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 41dd304..264df62 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -284,6 +284,8 @@ int cmd_mailsplit(int argc,
 
 	BUG_ON_NON_EMPTY_PREFIX(prefix);
 
+	show_usage_if_asked(argc, argv, git_mailsplit_usage);
+
 	for (argp = argv+1; *argp; argp++) {
 		const char *arg = *argp;
 
@@ -297,8 +299,6 @@ int cmd_mailsplit(int argc,
 			continue;
 		} else if ( arg[1] == 'f' ) {
 			nr = strtol(arg+2, NULL, 10);
-		} else if ( arg[1] == 'h' ) {
-			usage(git_mailsplit_usage);
 		} else if ( arg[1] == 'b' && !arg[2] ) {
 			allow_bare = 1;
 		} else if (!strcmp(arg, "--keep-cr")) {
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index a20c93b..123c815 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -8,7 +8,7 @@
 #include "parse-options.h"
 #include "commit-reach.h"
 
-static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
+static int show_merge_base(struct commit **rev, size_t rev_nr, int show_all)
 {
 	struct commit_list *result = NULL, *r;
 
@@ -149,7 +149,7 @@ int cmd_merge_base(int argc,
 		   struct repository *repo UNUSED)
 {
 	struct commit **rev;
-	int rev_nr = 0;
+	size_t rev_nr = 0;
 	int show_all = 0;
 	int cmdmode = 0;
 	int ret;
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 342699e..3314fb1 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -75,6 +75,9 @@ static void merge_all(void)
 	}
 }
 
+static const char usage_string[] =
+"git merge-index [-o] [-q] <merge-program> (-a | [--] [<filename>...])";
+
 int cmd_merge_index(int argc,
 		    const char **argv,
 		    const char *prefix UNUSED,
@@ -87,8 +90,10 @@ int cmd_merge_index(int argc,
 	 */
 	signal(SIGCHLD, SIG_DFL);
 
+	show_usage_if_asked(argc, argv, usage_string);
+
 	if (argc < 3)
-		usage("git merge-index [-o] [-q] <merge-program> (-a | [--] [<filename>...])");
+		usage(usage_string);
 
 	repo_read_index(the_repository);
 
diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c
index 3ecd917..97b8a79 100644
--- a/builtin/merge-ours.c
+++ b/builtin/merge-ours.c
@@ -23,8 +23,7 @@ int cmd_merge_ours(int argc,
 		   const char *prefix UNUSED,
 		   struct repository *repo UNUSED)
 {
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage(builtin_merge_ours_usage);
+	show_usage_if_asked(argc, argv, builtin_merge_ours_usage);
 
 	/*
 	 * The contents of the current index becomes the tree we
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 1dd2955..abfc060 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -38,6 +38,12 @@ int cmd_merge_recursive(int argc,
 	if (argv[0] && ends_with(argv[0], "-subtree"))
 		o.subtree_shift = "";
 
+	if (argc == 2 && !strcmp(argv[1], "-h")) {
+		struct strbuf msg = STRBUF_INIT;
+		strbuf_addf(&msg, builtin_merge_recursive_usage, argv[0]);
+		show_usage_if_asked(argc, argv, msg.buf);
+	}
+
 	if (argc < 4)
 		usagef(builtin_merge_recursive_usage, argv[0]);
 
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 9a6c8b4..3ec7127 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -18,6 +18,7 @@
 #include "tree.h"
 #include "config.h"
 #include "strvec.h"
+#include "write-or-die.h"
 
 static int line_termination = '\n';
 
@@ -575,7 +576,7 @@ int cmd_merge_tree(int argc,
 	};
 
 	/* Init merge options */
-	init_ui_merge_options(&o.merge_options, the_repository);
+	init_basic_merge_options(&o.merge_options, the_repository);
 
 	/* Parse arguments */
 	original_argc = argc - 1; /* ignoring argv[0] */
@@ -600,7 +601,6 @@ int cmd_merge_tree(int argc,
 		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, ' ');
@@ -617,15 +617,14 @@ int cmd_merge_tree(int argc,
 			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);
+				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);
+				real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);
 			} else {
 				die(_("malformed input line: '%s'."), buf.buf);
 			}
+			maybe_flush_or_die(stdout, "stdout");
 
-			if (result < 0)
-				die(_("merging cannot continue; got unclean result of %d"), result);
 			strbuf_list_free(split);
 		}
 		strbuf_release(&buf);
diff --git a/builtin/merge.c b/builtin/merge.c
index 5f67007..ba9faf1 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1300,8 +1300,8 @@ int cmd_merge(int argc,
 	void *branch_to_free;
 	int orig_argc = argc;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(builtin_merge_usage, builtin_merge_options);
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_merge_usage, builtin_merge_options);
 
 	prepare_repo_settings(the_repository);
 	the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/notes.c b/builtin/notes.c
index d051abf..ff61ec5 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -197,7 +197,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
 		struct strbuf buf = STRBUF_INIT;
 
 		/* write the template message before editing: */
-		d->edit_path = git_pathdup("NOTES_EDITMSG");
+		d->edit_path = repo_git_path(the_repository, "NOTES_EDITMSG");
 		fd = xopen(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
 
 		if (d->msg_nr)
@@ -979,6 +979,8 @@ static int merge(int argc, const char **argv, const char *prefix,
 	else { /* Merge has unresolved conflicts */
 		struct worktree **worktrees;
 		const struct worktree *wt;
+		char *path;
+
 		/* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
 		refs_update_ref(get_main_ref_store(the_repository), msg.buf,
 				"NOTES_MERGE_PARTIAL", &result_oid, NULL,
@@ -994,10 +996,13 @@ static int merge(int argc, const char **argv, const char *prefix,
 		if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", notes_ref, NULL))
 			die(_("failed to store link to current notes ref (%s)"),
 			    notes_ref);
+
+		path = repo_git_path(the_repository, NOTES_MERGE_WORKTREE);
 		fprintf(stderr, _("Automatic notes merge failed. Fix conflicts in %s "
 				  "and commit the result with 'git notes merge --commit', "
 				  "or abort the merge with 'git notes merge --abort'.\n"),
-			git_path(NOTES_MERGE_WORKTREE));
+			path);
+		free(path);
 	}
 
 	free_notes(t);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 1c3b842..58a9b16 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -269,6 +269,43 @@ struct configured_exclusion {
 static struct oidmap configured_exclusions;
 
 static struct oidset excluded_by_config;
+static int name_hash_version = -1;
+
+/**
+ * Check whether the name_hash_version chosen by user input is appropriate,
+ * and also validate whether it is compatible with other features.
+ */
+static void validate_name_hash_version(void)
+{
+	if (name_hash_version < 1 || name_hash_version > 2)
+		die(_("invalid --name-hash-version option: %d"), name_hash_version);
+	if (write_bitmap_index && name_hash_version != 1) {
+		warning(_("currently, --write-bitmap-index requires --name-hash-version=1"));
+		name_hash_version = 1;
+	}
+}
+
+static inline uint32_t pack_name_hash_fn(const char *name)
+{
+	static int seen_version = -1;
+
+	if (seen_version < 0)
+		seen_version = name_hash_version;
+	else if (seen_version != name_hash_version)
+		BUG("name hash version changed from %d to %d mid-process",
+		    seen_version, name_hash_version);
+
+	switch (name_hash_version) {
+	case 1:
+		return pack_name_hash(name);
+
+	case 2:
+		return pack_name_hash_v2((const unsigned char *)name);
+
+	default:
+		BUG("invalid name-hash version: %d", name_hash_version);
+	}
+}
 
 /*
  * stats
@@ -1264,7 +1301,8 @@ static void write_pack_file(void)
 	struct object_entry **write_order;
 
 	if (progress > pack_to_stdout)
-		progress_state = start_progress(_("Writing objects"), nr_result);
+		progress_state = start_progress(the_repository,
+						_("Writing objects"), nr_result);
 	ALLOC_ARRAY(written_list, to_pack.nr_objects);
 	write_order = compute_write_order();
 
@@ -1318,8 +1356,9 @@ static void write_pack_file(void)
 			 */
 
 			int fd = finalize_hashfile(f, hash, FSYNC_COMPONENT_PACK, 0);
-			fixup_pack_header_footer(fd, hash, pack_tmp_name,
-						 nr_written, hash, offset);
+			fixup_pack_header_footer(the_hash_algo, fd, hash,
+						 pack_tmp_name, nr_written,
+						 hash, offset);
 			close(fd);
 			if (write_bitmap_index) {
 				if (write_bitmap_index != WRITE_BITMAP_QUIET)
@@ -1367,9 +1406,10 @@ static void write_pack_file(void)
 			if (cruft)
 				pack_idx_opts.flags |= WRITE_MTIMES;
 
-			stage_tmp_packfiles(&tmpname, pack_tmp_name,
-					    written_list, nr_written,
-					    &to_pack, &pack_idx_opts, hash,
+			stage_tmp_packfiles(the_hash_algo, &tmpname,
+					    pack_tmp_name, written_list,
+					    nr_written, &to_pack,
+					    &pack_idx_opts, hash,
 					    &idx_tmp_name);
 
 			if (write_bitmap_index) {
@@ -1686,7 +1726,7 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
 		return 0;
 	}
 
-	create_object_entry(oid, type, pack_name_hash(name),
+	create_object_entry(oid, type, pack_name_hash_fn(name),
 			    exclude, name && no_try_delta(name),
 			    found_pack, found_offset);
 	return 1;
@@ -1900,7 +1940,7 @@ static void add_preferred_base_object(const char *name)
 {
 	struct pbase_tree *it;
 	size_t cmplen;
-	unsigned hash = pack_name_hash(name);
+	unsigned hash = pack_name_hash_fn(name);
 
 	if (!num_preferred_base || check_pbase_path(hash))
 		return;
@@ -2400,7 +2440,8 @@ static void get_object_details(void)
 	struct object_entry **sorted_by_offset;
 
 	if (progress)
-		progress_state = start_progress(_("Counting objects"),
+		progress_state = start_progress(the_repository,
+						_("Counting objects"),
 						to_pack.nr_objects);
 
 	CALLOC_ARRAY(sorted_by_offset, to_pack.nr_objects);
@@ -3220,7 +3261,8 @@ static void prepare_pack(int window, int depth)
 		unsigned nr_done = 0;
 
 		if (progress)
-			progress_state = start_progress(_("Compressing objects"),
+			progress_state = start_progress(the_repository,
+							_("Compressing objects"),
 							nr_deltas);
 		QSORT(delta_list, n, type_size_sort);
 		ll_find_deltas(delta_list, n, window+1, depth, &nr_done);
@@ -3410,7 +3452,7 @@ static void show_object_pack_hint(struct object *object, const char *name,
 	 * here using a now in order to perhaps improve the delta selection
 	 * process.
 	 */
-	oe->hash = pack_name_hash(name);
+	oe->hash = pack_name_hash_fn(name);
 	oe->no_try_delta = name && no_try_delta(name);
 
 	stdin_packs_hints_nr++;
@@ -3560,7 +3602,7 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
 	entry = packlist_find(&to_pack, oid);
 	if (entry) {
 		if (name) {
-			entry->hash = pack_name_hash(name);
+			entry->hash = pack_name_hash_fn(name);
 			entry->no_try_delta = no_try_delta(name);
 		}
 	} else {
@@ -3583,7 +3625,7 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
 			return;
 		}
 
-		entry = create_object_entry(oid, type, pack_name_hash(name),
+		entry = create_object_entry(oid, type, pack_name_hash_fn(name),
 					    0, name && no_try_delta(name),
 					    pack, offset);
 	}
@@ -3648,7 +3690,8 @@ static void add_objects_in_unpacked_packs(void);
 static void enumerate_cruft_objects(void)
 {
 	if (progress)
-		progress_state = start_progress(_("Enumerating cruft objects"), 0);
+		progress_state = start_progress(the_repository,
+						_("Enumerating cruft objects"), 0);
 
 	add_objects_in_unpacked_packs();
 	add_unreachable_loose_objects();
@@ -3674,7 +3717,8 @@ static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs
 	revs.ignore_missing_links = 1;
 
 	if (progress)
-		progress_state = start_progress(_("Enumerating cruft objects"), 0);
+		progress_state = start_progress(the_repository,
+						_("Enumerating cruft objects"), 0);
 	ret = add_unseen_recent_objects_to_traversal(&revs, cruft_expiration,
 						     set_cruft_mtime, 1);
 	stop_progress(&progress_state);
@@ -3693,7 +3737,8 @@ static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs
 	if (prepare_revision_walk(&revs))
 		die(_("revision walk setup failed"));
 	if (progress)
-		progress_state = start_progress(_("Traversing cruft objects"), 0);
+		progress_state = start_progress(the_repository,
+						_("Traversing cruft objects"), 0);
 	nr_seen = 0;
 	traverse_commit_list(&revs, show_cruft_commit, show_cruft_object, NULL);
 
@@ -4060,6 +4105,15 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
 	if (!(bitmap_git = prepare_bitmap_walk(revs, 0)))
 		return -1;
 
+	/*
+	 * For now, force the name-hash version to be 1 since that
+	 * is the version implied by the bitmap format. Later, the
+	 * format can include this version explicitly in its format,
+	 * allowing readers to know the version that was used during
+	 * the bitmap write.
+	 */
+	name_hash_version = 1;
+
 	if (pack_options_allow_reuse())
 		reuse_partial_packfile_from_bitmap(bitmap_git,
 						   &reuse_packfiles,
@@ -4435,6 +4489,8 @@ int cmd_pack_objects(int argc,
 		OPT_STRING_LIST(0, "uri-protocol", &uri_protocols,
 				N_("protocol"),
 				N_("exclude any configured uploadpack.blobpackfileuri with this protocol")),
+		OPT_INTEGER(0, "name-hash-version", &name_hash_version,
+			 N_("use the specified name-hash function to group similar objects")),
 		OPT_END(),
 	};
 
@@ -4590,6 +4646,11 @@ int cmd_pack_objects(int argc,
 	if (pack_to_stdout || !rev_list_all)
 		write_bitmap_index = 0;
 
+	if (name_hash_version < 0)
+		name_hash_version = (int)git_env_ulong("GIT_TEST_NAME_HASH_VERSION", 1);
+
+	validate_name_hash_version();
+
 	if (use_delta_islands)
 		strvec_push(&rp, "--topo-order");
 
@@ -4625,7 +4686,8 @@ int cmd_pack_objects(int argc,
 	prepare_packing_data(the_repository, &to_pack);
 
 	if (progress && !cruft)
-		progress_state = start_progress(_("Enumerating objects"), 0);
+		progress_state = start_progress(the_repository,
+						_("Enumerating objects"), 0);
 	if (stdin_packs) {
 		/* avoids adding objects in excluded packs */
 		ignore_packed_keep_in_core = 1;
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index e046575..3febe73 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -595,8 +595,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s
 	struct strbuf idx_name = STRBUF_INIT;
 	char buf[GIT_MAX_HEXSZ + 2]; /* hex hash + \n + \0 */
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage(pack_redundant_usage);
+	show_usage_if_asked(argc, argv, pack_redundant_usage);
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index f540d8d..cdef2ec 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -70,7 +70,7 @@ static size_t get_one_patchid(struct object_id *next_oid, struct object_id *resu
 	int before = -1, after = -1;
 	int diff_is_binary = 0;
 	char pre_oid_str[GIT_MAX_HEXSZ + 1], post_oid_str[GIT_MAX_HEXSZ + 1];
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 
 	the_hash_algo->init_fn(&ctx);
 	oidclr(result, the_repository->hash_algo);
@@ -85,7 +85,7 @@ static size_t get_one_patchid(struct object_id *next_oid, struct object_id *resu
 		    !skip_prefix(line, "From ", &p) &&
 		    starts_with(line, "\\ ") && 12 < strlen(line)) {
 			if (verbatim)
-				the_hash_algo->update_fn(&ctx, line, strlen(line));
+				git_hash_update(&ctx, line, strlen(line));
 			continue;
 		}
 
@@ -104,10 +104,10 @@ static size_t get_one_patchid(struct object_id *next_oid, struct object_id *resu
 			    starts_with(line, "Binary files")) {
 				diff_is_binary = 1;
 				before = 0;
-				the_hash_algo->update_fn(&ctx, pre_oid_str,
-							 strlen(pre_oid_str));
-				the_hash_algo->update_fn(&ctx, post_oid_str,
-							 strlen(post_oid_str));
+				git_hash_update(&ctx, pre_oid_str,
+						strlen(pre_oid_str));
+				git_hash_update(&ctx, post_oid_str,
+						strlen(post_oid_str));
 				if (stable)
 					flush_one_hunk(result, &ctx);
 				continue;
@@ -165,7 +165,7 @@ static size_t get_one_patchid(struct object_id *next_oid, struct object_id *resu
 		/* Add line to hash algo (possibly removing whitespace) */
 		len = verbatim ? strlen(line) : remove_space(line);
 		patchlen += len;
-		the_hash_algo->update_fn(&ctx, line, len);
+		git_hash_update(&ctx, line, len);
 	}
 
 	if (!found_next)
diff --git a/builtin/prune.c b/builtin/prune.c
index aeff9ca..1c357ff 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -64,7 +64,8 @@ static void perform_reachability_traversal(struct rev_info *revs)
 		return;
 
 	if (show_progress)
-		progress = start_delayed_progress(_("Checking connectivity"), 0);
+		progress = start_delayed_progress(the_repository,
+						  _("Checking connectivity"), 0);
 	mark_reachable_objects(revs, 1, expire, progress);
 	stop_progress(&progress);
 	initialized = 1;
diff --git a/builtin/push.c b/builtin/push.c
index 90de374..92d530e 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -78,7 +78,7 @@ static void refspec_append_mapped(struct refspec *refspec, const char *ref,
 			.src = matched->name,
 		};
 
-		if (!query_refspecs(&remote->push, &query) && query.dst) {
+		if (!refspec_find_match(&remote->push, &query) && query.dst) {
 			refspec_appendf(refspec, "%s%s:%s",
 					query.force ? "+" : "",
 					query.src, query.dst);
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 0498fff..d4715ed 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -644,7 +644,7 @@ static int run_am(struct rebase_options *opts)
 		return run_command(&am);
 	}
 
-	rebased_patches = xstrdup(git_path("rebased-patches"));
+	rebased_patches = repo_git_path(the_repository, "rebased-patches");
 	format_patch.out = open(rebased_patches,
 				O_WRONLY | O_CREAT | O_TRUNC, 0666);
 	if (format_patch.out < 0) {
@@ -1223,9 +1223,9 @@ int cmd_rebase(int argc,
 	};
 	int i;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(builtin_rebase_usage,
-				   builtin_rebase_options);
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_rebase_usage,
+					 builtin_rebase_options);
 
 	prepare_repo_settings(the_repository);
 	the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index c2e9103..7b28fc9 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -174,7 +174,7 @@ static int receive_pack_config(const char *var, const char *value,
 		char *path;
 
 		if (git_config_pathname(&path, var, value))
-			return 1;
+			return -1;
 		strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
 			fsck_msg_types.len ? ',' : '=', path);
 		free(path);
@@ -566,14 +566,14 @@ static void hmac_hash(unsigned char *out,
 	unsigned char k_ipad[GIT_MAX_BLKSZ];
 	unsigned char k_opad[GIT_MAX_BLKSZ];
 	int i;
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 
 	/* RFC 2104 2. (1) */
 	memset(key, '\0', GIT_MAX_BLKSZ);
 	if (the_hash_algo->blksz < key_len) {
 		the_hash_algo->init_fn(&ctx);
-		the_hash_algo->update_fn(&ctx, key_in, key_len);
-		the_hash_algo->final_fn(key, &ctx);
+		git_hash_update(&ctx, key_in, key_len);
+		git_hash_final(key, &ctx);
 	} else {
 		memcpy(key, key_in, key_len);
 	}
@@ -586,15 +586,15 @@ static void hmac_hash(unsigned char *out,
 
 	/* RFC 2104 2. (3) & (4) */
 	the_hash_algo->init_fn(&ctx);
-	the_hash_algo->update_fn(&ctx, k_ipad, sizeof(k_ipad));
-	the_hash_algo->update_fn(&ctx, text, text_len);
-	the_hash_algo->final_fn(out, &ctx);
+	git_hash_update(&ctx, k_ipad, sizeof(k_ipad));
+	git_hash_update(&ctx, text, text_len);
+	git_hash_final(out, &ctx);
 
 	/* RFC 2104 2. (6) & (7) */
 	the_hash_algo->init_fn(&ctx);
-	the_hash_algo->update_fn(&ctx, k_opad, sizeof(k_opad));
-	the_hash_algo->update_fn(&ctx, out, the_hash_algo->rawsz);
-	the_hash_algo->final_fn(out, &ctx);
+	git_hash_update(&ctx, k_opad, sizeof(k_opad));
+	git_hash_update(&ctx, out, the_hash_algo->rawsz);
+	git_hash_final(out, &ctx);
 }
 
 static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
@@ -1435,7 +1435,8 @@ static const char *push_to_checkout(unsigned char *hash,
 
 static const char *update_worktree(unsigned char *sha1, const struct worktree *worktree)
 {
-	const char *retval, *git_dir;
+	const char *retval;
+	char *git_dir;
 	struct strvec env = STRVEC_INIT;
 	int invoked_hook;
 
@@ -1453,6 +1454,7 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
 		retval = push_to_deploy(sha1, &env, worktree->path);
 
 	strvec_clear(&env);
+	free(git_dir);
 	return retval;
 }
 
@@ -2239,7 +2241,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
 		strvec_push(&child.args, alt_shallow_file);
 	}
 
-	tmp_objdir = tmp_objdir_create("incoming");
+	tmp_objdir = tmp_objdir_create(the_repository, "incoming");
 	if (!tmp_objdir) {
 		if (err_fd > 0)
 			close(err_fd);
@@ -2304,7 +2306,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
 		if (status)
 			return "index-pack fork failed";
 
-		lockfile = index_pack_lockfile(child.out, NULL);
+		lockfile = index_pack_lockfile(the_repository, child.out, NULL);
 		if (lockfile) {
 			pack_lockfile = register_tempfile(lockfile);
 			free(lockfile);
@@ -2628,7 +2630,7 @@ int cmd_receive_pack(int argc,
 			}
 		}
 		if (auto_update_server_info)
-			update_server_info(0);
+			update_server_info(the_repository, 0);
 		clear_shallow_info(&si);
 	}
 	if (use_sideband)
diff --git a/builtin/refs.c b/builtin/refs.c
index a29f195..44d592a 100644
--- a/builtin/refs.c
+++ b/builtin/refs.c
@@ -8,7 +8,7 @@
 #include "worktree.h"
 
 #define REFS_MIGRATE_USAGE \
-	N_("git refs migrate --ref-format=<format> [--dry-run]")
+	N_("git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]")
 
 #define REFS_VERIFY_USAGE \
 	N_("git refs verify [--strict] [--verbose]")
@@ -30,6 +30,9 @@ static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,
 		OPT_BIT(0, "dry-run", &flags,
 			N_("perform a non-destructive dry-run"),
 			REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN),
+		OPT_BIT(0, "no-reflog", &flags,
+			N_("drop reflogs entirely during the migration"),
+			REPO_MIGRATE_REF_STORAGE_FORMAT_SKIP_REFLOG),
 		OPT_END(),
 	};
 	struct strbuf errbuf = STRBUF_INIT;
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index 33c8ae0..bd2037f 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -202,6 +202,8 @@ int cmd_remote_ext(int argc,
 {
 	BUG_ON_NON_EMPTY_PREFIX(prefix);
 
+	show_usage_if_asked(argc, argv, usage_msg);
+
 	if (argc != 3)
 		usage(usage_msg);
 
diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c
index ae896ed..3990854 100644
--- a/builtin/remote-fd.c
+++ b/builtin/remote-fd.c
@@ -64,6 +64,7 @@ int cmd_remote_fd(int argc,
 
 	BUG_ON_NON_EMPTY_PREFIX(prefix);
 
+	show_usage_if_asked(argc, argv, usage_msg);
 	if (argc != 3)
 		usage(usage_msg);
 
diff --git a/builtin/remote.c b/builtin/remote.c
index 0435963..1b7aad8 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -383,7 +383,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
 				states->remote->fetch.items[i].raw);
 
 	for (ref = fetch_map; ref; ref = ref->next) {
-		if (omit_name_by_refspec(ref->name, &states->remote->fetch))
+		if (refname_matches_negative_refspec_item(ref->name, &states->remote->fetch))
 			string_list_append(&states->skipped, abbrev_branch(ref->name));
 		else if (!ref->peer_ref || !refs_ref_exists(get_main_ref_store(the_repository), ref->peer_ref->name))
 			string_list_append(&states->new_refs, abbrev_branch(ref->name));
@@ -642,10 +642,14 @@ static int migrate_file(struct remote *remote)
 	strbuf_addf(&buf, "remote.%s.fetch", remote->name);
 	for (i = 0; i < remote->fetch.nr; i++)
 		git_config_set_multivar(buf.buf, remote->fetch.items[i].raw, "^$", 0);
+#ifndef WITH_BREAKING_CHANGES
 	if (remote->origin == REMOTE_REMOTES)
-		unlink_or_warn(git_path("remotes/%s", remote->name));
+		unlink_or_warn(repo_git_path_replace(the_repository, &buf,
+						     "remotes/%s", remote->name));
 	else if (remote->origin == REMOTE_BRANCHES)
-		unlink_or_warn(git_path("branches/%s", remote->name));
+		unlink_or_warn(repo_git_path_replace(the_repository, &buf,
+						     "branches/%s", remote->name));
+#endif /* WITH_BREAKING_CHANGES */
 	strbuf_release(&buf);
 
 	return 0;
@@ -820,7 +824,8 @@ static int mv(int argc, const char **argv, const char *prefix,
 		 * Count symrefs twice, since "renaming" them is done by
 		 * deleting and recreating them in two separate passes.
 		 */
-		progress = start_progress(_("Renaming remote references"),
+		progress = start_progress(the_repository,
+					  _("Renaming remote references"),
 					  rename.remote_branches->nr + rename.symrefs_nr);
 	}
 	for (i = 0; i < remote_branches.nr; i++) {
diff --git a/builtin/repack.c b/builtin/repack.c
index 0c6dad7..75e3752 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -41,7 +41,9 @@ static int run_update_server_info = 1;
 static char *packdir, *packtmp_name, *packtmp;
 
 static const char *const git_repack_usage[] = {
-	N_("git repack [<options>]"),
+	N_("git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+	   "[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+	   "[--write-midx] [--name-hash-version=<n>]"),
 	NULL
 };
 
@@ -60,6 +62,7 @@ struct pack_objects_args {
 	int no_reuse_object;
 	int quiet;
 	int local;
+	int name_hash_version;
 	struct list_objects_filter_options filter_options;
 };
 
@@ -308,6 +311,8 @@ static void prepare_pack_objects(struct child_process *cmd,
 		strvec_pushf(&cmd->args, "--no-reuse-delta");
 	if (args->no_reuse_object)
 		strvec_pushf(&cmd->args, "--no-reuse-object");
+	if (args->name_hash_version)
+		strvec_pushf(&cmd->args, "--name-hash-version=%d", args->name_hash_version);
 	if (args->local)
 		strvec_push(&cmd->args,  "--local");
 	if (args->quiet)
@@ -1205,6 +1210,8 @@ int cmd_repack(int argc,
 				N_("pass --no-reuse-delta to git-pack-objects")),
 		OPT_BOOL('F', NULL, &po_args.no_reuse_object,
 				N_("pass --no-reuse-object to git-pack-objects")),
+		OPT_INTEGER(0, "name-hash-version", &po_args.name_hash_version,
+				N_("specify the name hash version to use for grouping similar objects by path")),
 		OPT_NEGBIT('n', NULL, &run_update_server_info,
 				N_("do not run git-update-server-info"), 1),
 		OPT__QUIET(&po_args.quiet, N_("be quiet")),
@@ -1370,9 +1377,12 @@ int cmd_repack(int argc,
 					    "--unpack-unreachable");
 			} else if (keep_unreachable) {
 				strvec_push(&cmd.args, "--keep-unreachable");
-				strvec_push(&cmd.args, "--pack-loose-unreachable");
 			}
 		}
+
+		if (keep_unreachable && delete_redundant &&
+		    !(pack_everything & PACK_CRUFT))
+			strvec_push(&cmd.args, "--pack-loose-unreachable");
 	} else if (geometry.split_factor) {
 		strvec_push(&cmd.args, "--stdin-packs");
 		strvec_push(&cmd.args, "--unpacked");
@@ -1565,7 +1575,7 @@ int cmd_repack(int argc,
 	}
 
 	if (run_update_server_info)
-		update_server_info(0);
+		update_server_info(the_repository, 0);
 
 	if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) {
 		unsigned flags = 0;
diff --git a/builtin/replace.c b/builtin/replace.c
index a4eaadf..15ec092 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -345,7 +345,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
 	}
 	strbuf_release(&ref);
 
-	tmpfile = git_pathdup("REPLACE_EDITOBJ");
+	tmpfile = repo_git_path(the_repository, "REPLACE_EDITOBJ");
 	if (export_object(&old_oid, type, raw, tmpfile)) {
 		free(tmpfile);
 		return -1;
diff --git a/builtin/replay.c b/builtin/replay.c
index 1afc6d1..032c172 100644
--- a/builtin/replay.c
+++ b/builtin/replay.c
@@ -163,9 +163,10 @@ static void determine_replay_mode(struct rev_cmdline_info *cmd_info,
 	get_ref_information(cmd_info, &rinfo);
 	if (!rinfo.positive_refexprs)
 		die(_("need some commits to replay"));
-	if (onto_name && *advance_name)
-		die(_("--onto and --advance are incompatible"));
-	else if (onto_name) {
+
+	die_for_incompatible_opt2(!!onto_name, "--onto",
+				  !!*advance_name, "--advance");
+	if (onto_name) {
 		*onto = peel_committish(onto_name);
 		if (rinfo.positive_refexprs <
 		    strset_get_size(&rinfo.positive_refs))
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 41127e2..1312e79 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -4,9 +4,9 @@
 #include "config.h"
 #include "gettext.h"
 #include "parse-options.h"
-
-#include "string-list.h"
 #include "rerere.h"
+#include "strbuf.h"
+#include "string-list.h"
 #include "xdiff/xdiff.h"
 #include "xdiff-interface.h"
 #include "pathspec.h"
@@ -112,15 +112,18 @@ int cmd_rerere(int argc,
 				merge_rr.items[i].util = NULL;
 		}
 	} else if (!strcmp(argv[0], "diff")) {
+		struct strbuf buf = STRBUF_INIT;
 		if (setup_rerere(the_repository, &merge_rr,
 				 flags | RERERE_READONLY) < 0)
 			return 0;
 		for (size_t i = 0; i < merge_rr.nr; i++) {
 			const char *path = merge_rr.items[i].string;
 			const struct rerere_id *id = merge_rr.items[i].util;
-			if (diff_two(rerere_path(id, "preimage"), path, path, path))
-				die(_("unable to generate diff for '%s'"), rerere_path(id, NULL));
+			if (diff_two(rerere_path(&buf, id, "preimage"), path, path, path))
+				die(_("unable to generate diff for '%s'"), rerere_path(&buf, id, NULL));
 		}
+
+		strbuf_release(&buf);
 	} else
 		usage_with_options(rerere_usage, options);
 
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 3196da7..bb26bee 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -22,7 +22,10 @@
 #include "progress.h"
 #include "reflog-walk.h"
 #include "oidset.h"
+#include "oidmap.h"
 #include "packfile.h"
+#include "quote.h"
+#include "strbuf.h"
 
 static const char rev_list_usage[] =
 "git rev-list [<options>] <commit>... [--] [<path>...]\n"
@@ -73,11 +76,17 @@ static unsigned progress_counter;
 static struct oidset omitted_objects;
 static int arg_print_omitted; /* print objects omitted by filter */
 
-static struct oidset missing_objects;
+struct missing_objects_map_entry {
+	struct oidmap_entry entry;
+	const char *path;
+	unsigned type;
+};
+static struct oidmap missing_objects;
 enum missing_action {
 	MA_ERROR = 0,    /* fail if any missing objects are encountered */
 	MA_ALLOW_ANY,    /* silently allow ALL missing objects */
 	MA_PRINT,        /* print ALL missing objects in special section */
+	MA_PRINT_INFO,   /* same as MA_PRINT but also prints missing object info */
 	MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
 };
 static enum missing_action arg_missing_action;
@@ -101,7 +110,49 @@ static off_t get_object_disk_usage(struct object *obj)
 	return size;
 }
 
-static inline void finish_object__ma(struct object *obj)
+static void add_missing_object_entry(struct object_id *oid, const char *path,
+				     unsigned type)
+{
+	struct missing_objects_map_entry *entry;
+
+	if (oidmap_get(&missing_objects, oid))
+		return;
+
+	CALLOC_ARRAY(entry, 1);
+	entry->entry.oid = *oid;
+	entry->type = type;
+	if (path)
+		entry->path = xstrdup(path);
+	oidmap_put(&missing_objects, entry);
+}
+
+static void print_missing_object(struct missing_objects_map_entry *entry,
+				 int print_missing_info)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	if (!print_missing_info) {
+		printf("?%s\n", oid_to_hex(&entry->entry.oid));
+		return;
+	}
+
+	if (entry->path && *entry->path) {
+		struct strbuf path = STRBUF_INIT;
+
+		strbuf_addstr(&sb, " path=");
+		quote_path(entry->path, NULL, &path, QUOTE_PATH_QUOTE_SP);
+		strbuf_addbuf(&sb, &path);
+
+		strbuf_release(&path);
+	}
+	if (entry->type)
+		strbuf_addf(&sb, " type=%s", type_name(entry->type));
+
+	printf("?%s%s\n", oid_to_hex(&entry->entry.oid), sb.buf);
+	strbuf_release(&sb);
+}
+
+static inline void finish_object__ma(struct object *obj, const char *name)
 {
 	/*
 	 * Whether or not we try to dynamically fetch missing objects
@@ -119,7 +170,8 @@ static inline void finish_object__ma(struct object *obj)
 		return;
 
 	case MA_PRINT:
-		oidset_insert(&missing_objects, &obj->oid);
+	case MA_PRINT_INFO:
+		add_missing_object_entry(&obj->oid, name, obj->type);
 		return;
 
 	case MA_ALLOW_PROMISOR:
@@ -152,7 +204,7 @@ static void show_commit(struct commit *commit, void *data)
 
 	if (revs->do_not_die_on_missing_objects &&
 	    oidset_contains(&revs->missing_commits, &commit->object.oid)) {
-		finish_object__ma(&commit->object);
+		finish_object__ma(&commit->object, NULL);
 		return;
 	}
 
@@ -268,12 +320,11 @@ static void show_commit(struct commit *commit, void *data)
 	finish_commit(commit);
 }
 
-static int finish_object(struct object *obj, const char *name UNUSED,
-			 void *cb_data)
+static int finish_object(struct object *obj, const char *name, void *cb_data)
 {
 	struct rev_list_info *info = cb_data;
 	if (oid_object_info_extended(the_repository, &obj->oid, NULL, 0) < 0) {
-		finish_object__ma(obj);
+		finish_object__ma(obj, name);
 		return 1;
 	}
 	if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
@@ -414,6 +465,12 @@ static inline int parse_missing_action_value(const char *value)
 		return 1;
 	}
 
+	if (!strcmp(value, "print-info")) {
+		arg_missing_action = MA_PRINT_INFO;
+		fetch_if_missing = 0;
+		return 1;
+	}
+
 	if (!strcmp(value, "allow-promisor")) {
 		arg_missing_action = MA_ALLOW_PROMISOR;
 		fetch_if_missing = 0;
@@ -542,8 +599,7 @@ int cmd_rev_list(int argc,
 	const char *show_progress = NULL;
 	int ret = 0;
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage(rev_list_usage);
+	show_usage_if_asked(argc, argv, rev_list_usage);
 
 	git_config(git_default_config, NULL);
 	repo_init_revisions(the_repository, &revs, prefix);
@@ -735,7 +791,8 @@ int cmd_rev_list(int argc,
 		revs.limited = 1;
 
 	if (show_progress)
-		progress = start_delayed_progress(show_progress, 0);
+		progress = start_delayed_progress(the_repository,
+						  show_progress, 0);
 
 	if (use_bitmap_index) {
 		if (!try_bitmap_count(&revs, filter_provided_objects))
@@ -781,10 +838,18 @@ int cmd_rev_list(int argc,
 
 	if (arg_print_omitted)
 		oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
-	if (arg_missing_action == MA_PRINT) {
-		oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE);
+	if (arg_missing_action == MA_PRINT ||
+	    arg_missing_action == MA_PRINT_INFO) {
+		struct oidset_iter iter;
+		struct object_id *oid;
+
+		oidmap_init(&missing_objects, DEFAULT_OIDSET_SIZE);
+		oidset_iter_init(&revs.missing_commits, &iter);
+
 		/* Add missing tips */
-		oidset_insert_from_set(&missing_objects, &revs.missing_commits);
+		while ((oid = oidset_iter_next(&iter)))
+			add_missing_object_entry(oid, NULL, 0);
+
 		oidset_clear(&revs.missing_commits);
 	}
 
@@ -800,13 +865,20 @@ int cmd_rev_list(int argc,
 			printf("~%s\n", oid_to_hex(oid));
 		oidset_clear(&omitted_objects);
 	}
-	if (arg_missing_action == MA_PRINT) {
-		struct oidset_iter iter;
-		struct object_id *oid;
-		oidset_iter_init(&missing_objects, &iter);
-		while ((oid = oidset_iter_next(&iter)))
-			printf("?%s\n", oid_to_hex(oid));
-		oidset_clear(&missing_objects);
+	if (arg_missing_action == MA_PRINT ||
+	    arg_missing_action == MA_PRINT_INFO) {
+		struct missing_objects_map_entry *entry;
+		struct oidmap_iter iter;
+
+		oidmap_iter_init(&missing_objects, &iter);
+
+		while ((entry = oidmap_iter_next(&iter))) {
+			print_missing_object(entry, arg_missing_action ==
+							    MA_PRINT_INFO);
+			free((void *)entry->path);
+		}
+
+		oidmap_free(&missing_objects, true);
 	}
 
 	stop_progress(&progress);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 949747a..490da33 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -713,6 +713,8 @@ int cmd_rev_parse(int argc,
 	int seen_end_of_options = 0;
 	enum format_type format = FORMAT_DEFAULT;
 
+	show_usage_if_asked(argc, argv, builtin_rev_parse_usage);
+
 	if (argc > 1 && !strcmp("--parseopt", argv[1]))
 		return cmd_parseopt(argc - 1, argv + 1, prefix);
 
@@ -787,8 +789,8 @@ int cmd_rev_parse(int argc,
 			if (!strcmp(arg, "--git-path")) {
 				if (!argv[i + 1])
 					die(_("--git-path requires an argument"));
-				strbuf_reset(&buf);
-				print_path(git_path("%s", argv[i + 1]), prefix,
+				print_path(repo_git_path_replace(the_repository, &buf,
+								 "%s", argv[i + 1]), prefix,
 						format,
 						DEFAULT_RELATIVE_IF_SHARED);
 				i++;
@@ -1081,7 +1083,7 @@ int cmd_rev_parse(int argc,
 					die(_("Could not read the index"));
 				if (the_repository->index->split_index) {
 					const struct object_id *oid = &the_repository->index->split_index->base_oid;
-					const char *path = git_path("sharedindex.%s", oid_to_hex(oid));
+					const char *path = repo_git_path_replace(the_repository, &buf, "sharedindex.%s", oid_to_hex(oid));
 					print_path(path, prefix, format, DEFAULT_RELATIVE);
 				}
 				continue;
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 59b626a..8d46100 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -317,7 +317,7 @@ int cmd_send_pack(int argc,
 	set_ref_status_for_push(remote_refs, args.send_mirror,
 		args.force_update);
 
-	ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
+	ret = send_pack(the_repository, &args, fd, conn, remote_refs, &extra_have);
 
 	if (helper_status)
 		print_helper_status(remote_refs);
diff --git a/builtin/show-index.c b/builtin/show-index.c
index 756d632..9d4ecf5 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c
@@ -9,7 +9,7 @@
 #include "parse-options.h"
 
 static const char *const show_index_usage[] = {
-	"git show-index [--object-format=<hash-algorithm>]",
+	"git show-index [--object-format=<hash-algorithm>] < <pack-idx-file>",
 	NULL
 };
 
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f9b970f..c1a8029 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1301,7 +1301,7 @@ static void sync_submodule(const char *path, const char *prefix,
 	remote_key = xstrfmt("remote.%s.url", default_remote);
 	free(default_remote);
 
-	submodule_to_gitdir(&sb, path);
+	submodule_to_gitdir(the_repository, &sb, path);
 	strbuf_addstr(&sb, "/config");
 
 	if (git_config_set_in_file_gently(sb.buf, remote_key, NULL, sub_origin_url))
@@ -1826,7 +1826,7 @@ static int clone_submodule(const struct module_clone_data *clone_data,
 
 	connect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);
 
-	p = git_pathdup_submodule(clone_data_path, "config");
+	p = repo_submodule_path(the_repository, clone_data_path, "config");
 	if (!p)
 		die(_("could not get submodule directory for '%s'"), clone_data_path);
 
diff --git a/builtin/tag.c b/builtin/tag.c
index c4bd145..d3e0943 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -667,7 +667,7 @@ int cmd_tag(int argc,
 	if (create_tag_object) {
 		if (force_sign_annotate && !annotate)
 			opt.sign = 1;
-		path = git_pathdup("TAG_EDITMSG");
+		path = repo_git_path(the_repository, "TAG_EDITMSG");
 		create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
 			   &trailer_args, path);
 	}
@@ -698,7 +698,6 @@ int cmd_tag(int argc,
 cleanup:
 	ref_sorting_release(sorting);
 	ref_filter_clear(&filter);
-	ref_format_clear(&format);
 	strbuf_release(&buf);
 	strbuf_release(&ref);
 	strbuf_release(&reflog_msg);
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 6da2825..fb5fcbc 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -26,6 +26,9 @@ static char *create_temp_file(struct object_id *oid)
 	return path;
 }
 
+static const char usage_msg[] =
+"git unpack-file <blob>";
+
 int cmd_unpack_file(int argc,
 		    const char **argv,
 		    const char *prefix UNUSED,
@@ -33,8 +36,9 @@ int cmd_unpack_file(int argc,
 {
 	struct object_id oid;
 
-	if (argc != 2 || !strcmp(argv[1], "-h"))
-		usage("git unpack-file <blob>");
+	show_usage_if_asked(argc, argv, usage_msg);
+	if (argc != 2)
+		usage(usage_msg);
 	if (repo_get_oid(the_repository, argv[1], &oid))
 		die("Not a valid object name %s", argv[1]);
 
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 2197d6d..8383bcf 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -18,6 +18,7 @@
 #include "progress.h"
 #include "decorate.h"
 #include "fsck.h"
+#include "packfile.h"
 
 static int dry_run, quiet, recover, has_errors, strict;
 static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict]";
@@ -27,7 +28,7 @@ static unsigned char buffer[4096];
 static unsigned int offset, len;
 static off_t consumed_bytes;
 static off_t max_input_size;
-static git_hash_ctx ctx;
+static struct git_hash_ctx ctx;
 static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
 static struct progress *progress;
 
@@ -69,7 +70,7 @@ static void *fill(int min)
 	if (min > sizeof(buffer))
 		die("cannot fill %d bytes", min);
 	if (offset) {
-		the_hash_algo->update_fn(&ctx, buffer, offset);
+		git_hash_update(&ctx, buffer, offset);
 		memmove(buffer, buffer + offset, len);
 		offset = 0;
 	}
@@ -578,19 +579,21 @@ static void unpack_one(unsigned nr)
 static void unpack_all(void)
 {
 	int i;
-	struct pack_header *hdr = fill(sizeof(struct pack_header));
+	unsigned char *hdr = fill(sizeof(struct pack_header));
 
-	nr_objects = ntohl(hdr->hdr_entries);
-
-	if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
+	if (get_be32(hdr) != PACK_SIGNATURE)
 		die("bad pack file");
-	if (!pack_version_ok(hdr->hdr_version))
+	hdr += 4;
+	if (!pack_version_ok_native(get_be32(hdr)))
 		die("unknown pack file version %"PRIu32,
-			ntohl(hdr->hdr_version));
+		    get_be32(hdr));
+	hdr += 4;
+	nr_objects = get_be32(hdr);
 	use(sizeof(struct pack_header));
 
 	if (!quiet)
-		progress = start_progress(_("Unpacking objects"), nr_objects);
+		progress = start_progress(the_repository,
+					  _("Unpacking objects"), nr_objects);
 	CALLOC_ARRAY(obj_list, nr_objects);
 	begin_odb_transaction();
 	for (i = 0; i < nr_objects; i++) {
@@ -611,7 +614,7 @@ int cmd_unpack_objects(int argc,
 {
 	int i;
 	struct object_id oid;
-	git_hash_ctx tmp_ctx;
+	struct git_hash_ctx tmp_ctx;
 
 	disable_replace_refs();
 
@@ -619,6 +622,8 @@ int cmd_unpack_objects(int argc,
 
 	quiet = !isatty(2);
 
+	show_usage_if_asked(argc, argv, unpack_usage);
+
 	for (i = 1 ; i < argc; i++) {
 		const char *arg = argv[i];
 
@@ -644,19 +649,10 @@ int cmd_unpack_objects(int argc,
 				fsck_set_msg_types(&fsck_options, arg);
 				continue;
 			}
-			if (starts_with(arg, "--pack_header=")) {
-				struct pack_header *hdr;
-				char *c;
-
-				hdr = (struct pack_header *)buffer;
-				hdr->hdr_signature = htonl(PACK_SIGNATURE);
-				hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10));
-				if (*c != ',')
-					die("bad %s", arg);
-				hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10));
-				if (*c)
-					die("bad %s", arg);
-				len = sizeof(*hdr);
+			if (skip_prefix(arg, "--pack_header=", &arg)) {
+				if (parse_pack_header_option(arg,
+							     buffer, &len) < 0)
+					die(_("bad --pack_header: %s"), arg);
 				continue;
 			}
 			if (skip_prefix(arg, "--max-input-size=", &arg)) {
@@ -671,10 +667,9 @@ int cmd_unpack_objects(int argc,
 	}
 	the_hash_algo->init_fn(&ctx);
 	unpack_all();
-	the_hash_algo->update_fn(&ctx, buffer, offset);
-	the_hash_algo->init_fn(&tmp_ctx);
-	the_hash_algo->clone_fn(&tmp_ctx, &ctx);
-	the_hash_algo->final_oid_fn(&oid, &tmp_ctx);
+	git_hash_update(&ctx, buffer, offset);
+	git_hash_clone(&tmp_ctx, &ctx);
+	git_hash_final_oid(&oid, &tmp_ctx);
 	if (strict) {
 		write_rest();
 		if (fsck_finish(&fsck_options))
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 74bbad9..b2f6b1a 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -1045,8 +1045,8 @@ int cmd_update_index(int argc,
 		OPT_END()
 	};
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(update_index_usage, options);
+	show_usage_with_options_if_asked(argc, argv,
+					 update_index_usage, options);
 
 	git_config(git_default_config, NULL);
 
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index 6769611..d746729 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -13,7 +12,7 @@ static const char * const update_server_info_usage[] = {
 int cmd_update_server_info(int argc,
 			   const char **argv,
 			   const char *prefix,
-			   struct repository *repo UNUSED)
+			   struct repository *repo)
 {
 	int force = 0;
 	struct option options[] = {
@@ -21,11 +20,12 @@ int cmd_update_server_info(int argc,
 		OPT_END()
 	};
 
-	git_config(git_default_config, NULL);
+	if (repo)
+		repo_config(repo, git_default_config, NULL);
 	argc = parse_options(argc, argv, prefix, options,
 			     update_server_info_usage, 0);
 	if (argc > 0)
 		usage_with_options(update_server_info_usage, options);
 
-	return !!update_server_info(force);
+	return !!update_server_info(repo, force);
 }
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 9e9343f..97d7c95 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -27,7 +27,8 @@ int cmd_upload_archive_writer(int argc,
 	const char *arg_cmd = "argument ";
 	int ret;
 
-	if (argc != 2 || !strcmp(argv[1], "-h"))
+	show_usage_if_asked(argc, argv, upload_archive_usage);
+	if (argc != 2)
 		usage(upload_archive_usage);
 
 	if (!enter_repo(argv[1], 0))
@@ -92,8 +93,7 @@ struct repository *repo UNUSED)
 
 	BUG_ON_NON_EMPTY_PREFIX(prefix);
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage(upload_archive_usage);
+	show_usage_if_asked(argc, argv, upload_archive_usage);
 
 	/*
 	 * Set up sideband subprocess.
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index dd63d6e..c2bbc03 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
 #include "exec-cmd.h"
 #include "gettext.h"
@@ -63,9 +65,9 @@ int cmd_upload_pack(int argc,
 	switch (determine_protocol_version_server()) {
 	case protocol_v2:
 		if (advertise_refs)
-			protocol_v2_advertise_capabilities();
+			protocol_v2_advertise_capabilities(the_repository);
 		else
-			protocol_v2_serve_loop(stateless_rpc);
+			protocol_v2_serve_loop(the_repository, stateless_rpc);
 		break;
 	case protocol_v1:
 		/*
diff --git a/builtin/var.c b/builtin/var.c
index 1449656..ada642a 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -42,7 +42,7 @@ static char *sequence_editor(int ident_flag UNUSED)
 
 static char *pager(int ident_flag UNUSED)
 {
-	const char *pgm = git_pager(1);
+	const char *pgm = git_pager(the_repository, 1);
 
 	if (!pgm)
 		pgm = "cat";
@@ -221,6 +221,7 @@ int cmd_var(int argc,
 	const struct git_var *git_var;
 	char *val;
 
+	show_usage_if_asked(argc, argv, var_usage);
 	if (argc != 2)
 		usage(var_usage);
 
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index a7f2061..f6b9704 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -69,6 +69,5 @@ int cmd_verify_tag(int argc,
 		if (format.format)
 			pretty_print_ref(name, &oid, &format);
 	}
-	ref_format_clear(&format);
 	return had_error;
 }
diff --git a/builtin/worktree.c b/builtin/worktree.c
index c043d4d..48448a8 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -151,7 +151,7 @@ static int delete_git_dir(const char *id)
 	struct strbuf sb = STRBUF_INIT;
 	int ret;
 
-	strbuf_addstr(&sb, git_common_path("worktrees/%s", id));
+	repo_common_path_append(the_repository, &sb, "worktrees/%s", id);
 	ret = remove_dir_recursively(&sb, 0);
 	if (ret < 0 && errno == ENOTDIR)
 		ret = unlink(sb.buf);
@@ -163,7 +163,9 @@ static int delete_git_dir(const char *id)
 
 static void delete_worktrees_dir_if_empty(void)
 {
-	rmdir(git_path("worktrees")); /* ignore failed removal */
+	char *path = repo_git_path(the_repository, "worktrees");
+	rmdir(path); /* ignore failed removal */
+	free(path);
 }
 
 static void prune_worktree(const char *id, const char *reason)
@@ -212,8 +214,13 @@ static void prune_worktrees(void)
 	struct strbuf reason = STRBUF_INIT;
 	struct strbuf main_path = STRBUF_INIT;
 	struct string_list kept = STRING_LIST_INIT_DUP;
-	DIR *dir = opendir(git_path("worktrees"));
+	char *path;
+	DIR *dir;
 	struct dirent *d;
+
+	path = repo_git_path(the_repository, "worktrees");
+	dir = opendir(path);
+	free(path);
 	if (!dir)
 		return;
 	while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
@@ -337,7 +344,7 @@ static void check_candidate_path(const char *path,
 
 static void copy_sparse_checkout(const char *worktree_git_dir)
 {
-	char *from_file = git_pathdup("info/sparse-checkout");
+	char *from_file = repo_git_path(the_repository, "info/sparse-checkout");
 	char *to_file = xstrfmt("%s/info/sparse-checkout", worktree_git_dir);
 
 	if (file_exists(from_file)) {
@@ -353,7 +360,7 @@ static void copy_sparse_checkout(const char *worktree_git_dir)
 
 static void copy_filtered_worktree_config(const char *worktree_git_dir)
 {
-	char *from_file = git_pathdup("config.worktree");
+	char *from_file = repo_git_path(the_repository, "config.worktree");
 	char *to_file = xstrfmt("%s/config.worktree", worktree_git_dir);
 
 	if (file_exists(from_file)) {
@@ -457,7 +464,7 @@ static int add_worktree(const char *path, const char *refname,
 		BUG("How come '%s' becomes empty after sanitization?", sb.buf);
 	strbuf_reset(&sb);
 	name = sb_name.buf;
-	git_path_buf(&sb_repo, "worktrees/%s", name);
+	repo_git_path_replace(the_repository, &sb_repo, "worktrees/%s", name);
 	len = sb_repo.len;
 	if (safe_create_leading_directories_const(sb_repo.buf))
 		die_errno(_("could not create leading directories of '%s'"),
@@ -657,8 +664,9 @@ static int can_use_local_refs(const struct add_opts *opts)
 		if (!opts->quiet) {
 			struct strbuf path = STRBUF_INIT;
 			struct strbuf contents = STRBUF_INIT;
+			char *wt_gitdir = get_worktree_git_dir(NULL);
 
-			strbuf_add_real_path(&path, get_worktree_git_dir(NULL));
+			strbuf_add_real_path(&path, wt_gitdir);
 			strbuf_addstr(&path, "/HEAD");
 			strbuf_read_file(&contents, path.buf, 64);
 			strbuf_stripspace(&contents, NULL);
@@ -670,6 +678,7 @@ static int can_use_local_refs(const struct add_opts *opts)
 				  path.buf, contents.buf);
 			strbuf_release(&path);
 			strbuf_release(&contents);
+			free(wt_gitdir);
 		}
 		return 1;
 	}
@@ -1100,6 +1109,7 @@ static int lock_worktree(int ac, const char **av, const char *prefix,
 		OPT_END()
 	};
 	struct worktree **worktrees, *wt;
+	char *path;
 
 	ac = parse_options(ac, av, prefix, options, git_worktree_lock_usage, 0);
 	if (ac != 1)
@@ -1120,9 +1130,11 @@ static int lock_worktree(int ac, const char **av, const char *prefix,
 		die(_("'%s' is already locked"), av[0]);
 	}
 
-	write_file(git_common_path("worktrees/%s/locked", wt->id),
-		   "%s", reason);
+	path = repo_common_path(the_repository, "worktrees/%s/locked", wt->id);
+	write_file(path, "%s", reason);
+
 	free_worktrees(worktrees);
+	free(path);
 	return 0;
 }
 
@@ -1133,6 +1145,7 @@ static int unlock_worktree(int ac, const char **av, const char *prefix,
 		OPT_END()
 	};
 	struct worktree **worktrees, *wt;
+	char *path;
 	int ret;
 
 	ac = parse_options(ac, av, prefix, options, git_worktree_unlock_usage, 0);
@@ -1147,8 +1160,12 @@ static int unlock_worktree(int ac, const char **av, const char *prefix,
 		die(_("The main working tree cannot be locked or unlocked"));
 	if (!worktree_lock_reason(wt))
 		die(_("'%s' is not locked"), av[0]);
-	ret = unlink_or_warn(git_common_path("worktrees/%s/locked", wt->id));
+
+	path = repo_common_path(the_repository, "worktrees/%s/locked", wt->id);
+	ret = unlink_or_warn(path);
+
 	free_worktrees(worktrees);
+	free(path);
 	return ret;
 }
 
@@ -1157,6 +1174,9 @@ static void validate_no_submodules(const struct worktree *wt)
 	struct index_state istate = INDEX_STATE_INIT(the_repository);
 	struct strbuf path = STRBUF_INIT;
 	int i, found_submodules = 0;
+	char *wt_gitdir;
+
+	wt_gitdir = get_worktree_git_dir(wt);
 
 	if (is_directory(worktree_git_path(the_repository, wt, "modules"))) {
 		/*
@@ -1166,7 +1186,7 @@ static void validate_no_submodules(const struct worktree *wt)
 		 */
 		found_submodules = 1;
 	} else if (read_index_from(&istate, worktree_git_path(the_repository, wt, "index"),
-				   get_worktree_git_dir(wt)) > 0) {
+				   wt_gitdir) > 0) {
 		for (i = 0; i < istate.cache_nr; i++) {
 			struct cache_entry *ce = istate.cache[i];
 			int err;
@@ -1185,6 +1205,7 @@ static void validate_no_submodules(const struct worktree *wt)
 	}
 	discard_index(&istate);
 	strbuf_release(&path);
+	free(wt_gitdir);
 
 	if (found_submodules)
 		die(_("working trees containing submodules cannot be moved or removed"));
diff --git a/bulk-checkin.c b/bulk-checkin.c
index 433070a..20f2da6 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -44,8 +44,9 @@ static void finish_tmp_packfile(struct strbuf *basename,
 {
 	char *idx_tmp_name = NULL;
 
-	stage_tmp_packfiles(basename, pack_tmp_name, written_list, nr_written,
-			    NULL, pack_idx_opts, hash, &idx_tmp_name);
+	stage_tmp_packfiles(the_hash_algo, basename, pack_tmp_name,
+			    written_list, nr_written, NULL, pack_idx_opts, hash,
+			    &idx_tmp_name);
 	rename_tmp_packfile_idx(basename, &idx_tmp_name);
 
 	free(idx_tmp_name);
@@ -70,7 +71,7 @@ static void flush_bulk_checkin_packfile(struct bulk_checkin_packfile *state)
 				  CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
 	} else {
 		int fd = finalize_hashfile(state->f, hash, FSYNC_COMPONENT_PACK, 0);
-		fixup_pack_header_footer(fd, hash, state->pack_tmp_name,
+		fixup_pack_header_footer(the_hash_algo, fd, hash, state->pack_tmp_name,
 					 state->nr_written, hash,
 					 state->offset);
 		close(fd);
@@ -161,7 +162,7 @@ static int already_written(struct bulk_checkin_packfile *state, struct object_id
  * with a new pack.
  */
 static int stream_blob_to_pack(struct bulk_checkin_packfile *state,
-			       git_hash_ctx *ctx, off_t *already_hashed_to,
+			       struct git_hash_ctx *ctx, off_t *already_hashed_to,
 			       int fd, size_t size, const char *path,
 			       unsigned flags)
 {
@@ -194,7 +195,7 @@ static int stream_blob_to_pack(struct bulk_checkin_packfile *state,
 				if (rsize < hsize)
 					hsize = rsize;
 				if (hsize)
-					the_hash_algo->update_fn(ctx, ibuf, hsize);
+					git_hash_update(ctx, ibuf, hsize);
 				*already_hashed_to = offset;
 			}
 			s.next_in = ibuf;
@@ -258,10 +259,10 @@ static int deflate_blob_to_pack(struct bulk_checkin_packfile *state,
 				const char *path, unsigned flags)
 {
 	off_t seekback, already_hashed_to;
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 	unsigned char obuf[16384];
 	unsigned header_len;
-	struct hashfile_checkpoint checkpoint = {0};
+	struct hashfile_checkpoint checkpoint;
 	struct pack_idx_entry *idx = NULL;
 
 	seekback = lseek(fd, 0, SEEK_CUR);
@@ -271,13 +272,16 @@ static int deflate_blob_to_pack(struct bulk_checkin_packfile *state,
 	header_len = format_object_header((char *)obuf, sizeof(obuf),
 					  OBJ_BLOB, size);
 	the_hash_algo->init_fn(&ctx);
-	the_hash_algo->update_fn(&ctx, obuf, header_len);
-	the_hash_algo->unsafe_init_fn(&checkpoint.ctx);
+	git_hash_update(&ctx, obuf, header_len);
 
 	/* Note: idx is non-NULL when we are writing */
-	if ((flags & HASH_WRITE_OBJECT) != 0)
+	if ((flags & HASH_WRITE_OBJECT) != 0) {
 		CALLOC_ARRAY(idx, 1);
 
+		prepare_to_stream(state, flags);
+		hashfile_checkpoint_init(state->f, &checkpoint);
+	}
+
 	already_hashed_to = 0;
 
 	while (1) {
@@ -303,7 +307,7 @@ static int deflate_blob_to_pack(struct bulk_checkin_packfile *state,
 		if (lseek(fd, seekback, SEEK_SET) == (off_t) -1)
 			return error("cannot seek back");
 	}
-	the_hash_algo->final_oid_fn(result_oid, &ctx);
+	git_hash_final_oid(result_oid, &ctx);
 	if (!idx)
 		return 0;
 
@@ -333,7 +337,7 @@ void prepare_loose_object_bulk_checkin(void)
 	if (!odb_transaction_nesting || bulk_fsync_objdir)
 		return;
 
-	bulk_fsync_objdir = tmp_objdir_create("bulk-fsync");
+	bulk_fsync_objdir = tmp_objdir_create(the_repository, "bulk-fsync");
 	if (bulk_fsync_objdir)
 		tmp_objdir_replace_primary_odb(bulk_fsync_objdir, 0);
 }
diff --git a/bundle.c b/bundle.c
index f18f98f..d7ad690 100644
--- a/bundle.c
+++ b/bundle.c
@@ -607,8 +607,10 @@ int unbundle(struct repository *r, struct bundle_header *header,
 	if (!opts)
 		opts = &opts_fallback;
 
-	if (verify_bundle(r, header, opts->flags))
+	if (verify_bundle(r, header, opts->flags)) {
+		close(bundle_fd);
 		return -1;
+	}
 
 	strvec_pushl(&ip.args, "index-pack", "--fix-thin", "--stdin", NULL);
 
diff --git a/bundle.h b/bundle.h
index a80aa8a..d664b2f 100644
--- a/bundle.h
+++ b/bundle.h
@@ -62,6 +62,8 @@ struct unbundle_opts {
  *
  * Before unbundling, this method will call verify_bundle() with 'flags'
  * provided in 'opts'.
+ *
+ * Note that the `bundle_fd` will be closed as part of the operation.
  */
 int unbundle(struct repository *r, struct bundle_header *header,
 	     int bundle_fd, struct strvec *extra_index_pack_args,
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
index d1cb9fa..da19dad 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -24,16 +24,16 @@
 
 case "$distro" in
 alpine-*)
-	apk add --update shadow sudo build-base curl-dev openssl-dev expat-dev gettext \
-		pcre2-dev python3 musl-libintl perl-utils ncurses \
+	apk add --update shadow sudo meson ninja-build gcc libc-dev curl-dev openssl-dev expat-dev gettext \
+		zlib-ng-dev pcre2-dev python3 musl-libintl perl-utils ncurses \
 		apache2 apache2-http2 apache2-proxy apache2-ssl apache2-webdav apr-util-dbd_sqlite3 \
 		bash cvs gnupg perl-cgi perl-dbd-sqlite perl-io-tty >/dev/null
 	;;
 fedora-*|almalinux-*)
 	dnf -yq update >/dev/null &&
-	dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
+	dnf -yq install shadow-utils sudo make gcc findutils diffutils perl python3 gawk gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
 	;;
-ubuntu-*|ubuntu32-*|debian-*)
+ubuntu-*|i386/ubuntu-*|debian-*)
 	# Required so that apt doesn't wait for user input on certain packages.
 	export DEBIAN_FRONTEND=noninteractive
 
@@ -42,7 +42,7 @@
 		SVN='libsvn-perl subversion'
 		LANGUAGES='language-pack-is'
 		;;
-	ubuntu32-*)
+	i386/ubuntu-*)
 		SVN=
 		LANGUAGES='language-pack-is'
 		;;
@@ -58,7 +58,7 @@
 		make libssl-dev libcurl4-openssl-dev libexpat-dev wget sudo default-jre \
 		tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \
 		libemail-valid-perl libio-pty-perl libio-socket-ssl-perl libnet-smtp-ssl-perl libdbd-sqlite3-perl libcgi-pm-perl \
-		libpcre2-dev meson ninja-build pkg-config \
+		libsecret-1-dev libpcre2-dev meson ninja-build pkg-config \
 		${CC_PACKAGE:-${CC:-gcc}} $PYTHON_PACKAGE
 
 	case "$distro" in
@@ -66,16 +66,29 @@
 		mkdir --parents "$CUSTOM_PATH"
 
 		wget --quiet --directory-prefix="$CUSTOM_PATH" \
-			"$P4WHENCE/bin.linux26x86_64/p4d" "$P4WHENCE/bin.linux26x86_64/p4"
-		chmod a+x "$CUSTOM_PATH/p4d" "$CUSTOM_PATH/p4"
+			"$P4WHENCE/bin.linux26x86_64/p4d" \
+			"$P4WHENCE/bin.linux26x86_64/p4" &&
+		chmod a+x "$CUSTOM_PATH/p4d" "$CUSTOM_PATH/p4" || {
+			rm -f "$CUSTOM_PATH/p4"
+			rm -f "$CUSTOM_PATH/p4d"
+			echo >&2 "P4 download (optional) failed"
+		}
 
-		wget --quiet "$LFSWHENCE/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
+		wget --quiet \
+		     "$LFSWHENCE/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz" &&
 		tar -xzf "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz" \
-			-C "$CUSTOM_PATH" --strip-components=1 "git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs"
-		rm "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
+			-C "$CUSTOM_PATH" --strip-components=1 \
+			"git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs" &&
+		rm "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz" || {
+			rm -f "$CUSTOM_PATH/git-lfs"
+			echo >&2 "LFS download (optional) failed"
+		}
 
-		wget --quiet "$JGITWHENCE" --output-document="$CUSTOM_PATH/jgit"
-		chmod a+x "$CUSTOM_PATH/jgit"
+		wget --quiet "$JGITWHENCE" --output-document="$CUSTOM_PATH/jgit" &&
+		chmod a+x "$CUSTOM_PATH/jgit" || {
+			rm -f "$CUSTOM_PATH/jgit"
+			echo >&2 "JGit download (optional) failed"
+		}
 		;;
 	esac
 	;;
@@ -119,7 +132,7 @@
 sparse)
 	sudo apt-get -q update -q
 	sudo apt-get -q -y install libssl-dev libcurl4-openssl-dev \
-		libexpat-dev gettext zlib1g-dev
+		libexpat-dev gettext zlib1g-dev sparse
 	;;
 Documentation)
 	sudo apt-get -q update
diff --git a/ci/lib.sh b/ci/lib.sh
index 8885ee3..f561884 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -206,26 +206,7 @@
 # Clear MAKEFLAGS that may come from the outside world.
 export MAKEFLAGS=
 
-if test -n "$SYSTEM_COLLECTIONURI" || test -n "$SYSTEM_TASKDEFINITIONSURI"
-then
-	CI_TYPE=azure-pipelines
-	# We are running in Azure Pipelines
-	CI_BRANCH="$BUILD_SOURCEBRANCH"
-	CI_COMMIT="$BUILD_SOURCEVERSION"
-	CI_JOB_ID="$BUILD_BUILDID"
-	CI_JOB_NUMBER="$BUILD_BUILDNUMBER"
-	CI_OS_NAME="$(echo "$AGENT_OS" | tr A-Z a-z)"
-	test darwin != "$CI_OS_NAME" || CI_OS_NAME=osx
-	CI_REPO_SLUG="$(expr "$BUILD_REPOSITORY_URI" : '.*/\([^/]*/[^/]*\)$')"
-	CC="${CC:-gcc}"
-
-	# use a subdirectory of the cache dir (because the file share is shared
-	# among *all* phases)
-	cache_dir="$HOME/test-cache/$SYSTEM_PHASENAME"
-
-	GIT_TEST_OPTS="--write-junit-xml"
-	JOBS=10
-elif test true = "$GITHUB_ACTIONS"
+if test true = "$GITHUB_ACTIONS"
 then
 	CI_TYPE=github-actions
 	CI_BRANCH="$GITHUB_REF"
@@ -246,6 +227,8 @@
 
 	GIT_TEST_OPTS="--github-workflow-markup"
 	JOBS=10
+
+	distro=$(echo "$CI_JOB_IMAGE" | tr : -)
 elif test true = "$GITLAB_CI"
 then
 	CI_TYPE=gitlab-ci
@@ -267,7 +250,7 @@
 		CI_OS_NAME=osx
 		JOBS=$(nproc)
 		;;
-	*,alpine:*|*,fedora:*|*,ubuntu:*)
+	*,alpine:*|*,fedora:*|*,ubuntu:*|*,i386/ubuntu:*)
 		CI_OS_NAME=linux
 		JOBS=$(nproc)
 		;;
@@ -329,11 +312,6 @@
 
 case "$distro" in
 ubuntu-*)
-	if test "$jobname" = "linux-gcc-default"
-	then
-		break
-	fi
-
 	# Python 2 is end of life, and Ubuntu 23.04 and newer don't actually
 	# have it anymore. We thus only test with Python 2 on older LTS
 	# releases.
@@ -345,14 +323,7 @@
 	fi
 	MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/$PYTHON_PACKAGE"
 
-	case "$distro" in
-	ubuntu-16.04)
-		# Apache is too old for HTTP/2.
-		;;
-	*)
-		export GIT_TEST_HTTPD=true
-		;;
-	esac
+	export GIT_TEST_HTTPD=true
 
 	# The Linux build installs the defined dependency versions below.
 	# The OS X build installs much more recent versions, whichever
@@ -377,11 +348,11 @@
 linux32)
 	CC=gcc
 	;;
-linux-musl)
-	CC=gcc
-	MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python3 USE_LIBPCRE2=Yes"
-	MAKEFLAGS="$MAKEFLAGS NO_REGEX=Yes ICONV_OMITS_BOM=Yes"
-	MAKEFLAGS="$MAKEFLAGS GIT_TEST_UTF8_LOCALE=C.UTF-8"
+linux-meson)
+	MESONFLAGS="$MESONFLAGS -Dcredential_helpers=libsecret,netrc"
+	;;
+linux-musl-meson)
+	MESONFLAGS="$MESONFLAGS -Dtest_utf8_locale=C.UTF-8"
 	;;
 linux-leaks|linux-reftable-leaks)
 	export SANITIZE=leak
@@ -391,6 +362,9 @@
 	export NO_SVN_TESTS=LetsSaveSomeTime
 	MAKEFLAGS="$MAKEFLAGS NO_PYTHON=YepBecauseP4FlakesTooOften"
 	;;
+osx-meson)
+	MESONFLAGS="$MESONFLAGS -Dcredential_helpers=osxkeychain"
+	;;
 esac
 
 MAKEFLAGS="$MAKEFLAGS CC=${CC:-cc}"
diff --git a/ci/print-test-failures.sh b/ci/print-test-failures.sh
index 655687d..dc910e5 100755
--- a/ci/print-test-failures.sh
+++ b/ci/print-test-failures.sh
@@ -39,11 +39,6 @@
 		test_name="${test_name##*/}"
 		trash_dir="trash directory.$test_name"
 		case "$CI_TYPE" in
-		azure-pipelines)
-			mkdir -p failed-test-artifacts
-			mv "$trash_dir" failed-test-artifacts
-			continue
-			;;
 		github-actions)
 			mkdir -p failed-test-artifacts
 			echo "FAILED_TEST_ARTIFACTS=${TEST_OUTPUT_DIRECTORY:t}/failed-test-artifacts" >>$GITHUB_ENV
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
index 76667a1..1c69846 100755
--- a/ci/run-build-and-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -13,8 +13,9 @@
 run_tests=t
 
 case "$jobname" in
-linux-gcc)
+linux-breaking-changes)
 	export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+	export WITH_BREAKING_CHANGES=YesPlease
 	;;
 linux-TEST-vars)
 	export OPENSSL_SHA1_UNSAFE=YesPlease
@@ -52,8 +53,11 @@
 case "$jobname" in
 *-meson)
 	group "Configure" meson setup build . \
+		--fatal-meson-warnings \
 		--warnlevel 2 --werror \
-		--wrap-mode nofallback
+		--wrap-mode nofallback \
+		-Dfuzzers=true \
+		$MESONFLAGS
 	group "Build" meson compile -C build --
 	if test -n "$run_tests"
 	then
diff --git a/combine-diff.c b/combine-diff.c
index 641bc92..9527f31 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -47,31 +47,20 @@ static struct combine_diff_path *intersect_paths(
 
 	if (!n) {
 		for (i = 0; i < q->nr; i++) {
-			int len;
-			const char *path;
 			if (diff_unmodified_pair(q->queue[i]))
 				continue;
-			path = q->queue[i]->two->path;
-			len = strlen(path);
-			p = xmalloc(combine_diff_path_size(num_parent, len));
-			p->path = (char *) &(p->parent[num_parent]);
-			memcpy(p->path, path, len);
-			p->path[len] = 0;
-			p->next = NULL;
-			memset(p->parent, 0,
-			       sizeof(p->parent[0]) * num_parent);
-
-			oidcpy(&p->oid, &q->queue[i]->two->oid);
-			p->mode = q->queue[i]->two->mode;
+			p = combine_diff_path_new(q->queue[i]->two->path,
+						  strlen(q->queue[i]->two->path),
+						  q->queue[i]->two->mode,
+						  &q->queue[i]->two->oid,
+						  num_parent);
 			oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
 			p->parent[n].mode = q->queue[i]->one->mode;
 			p->parent[n].status = q->queue[i]->status;
 
 			if (combined_all_paths &&
 			    filename_changed(p->parent[n].status)) {
-				strbuf_init(&p->parent[n].path, 0);
-				strbuf_addstr(&p->parent[n].path,
-					      q->queue[i]->one->path);
+				p->parent[n].path = xstrdup(q->queue[i]->one->path);
 			}
 			*tail = p;
 			tail = &p->next;
@@ -92,9 +81,7 @@ static struct combine_diff_path *intersect_paths(
 			/* p->path not in q->queue[]; drop it */
 			*tail = p->next;
 			for (j = 0; j < num_parent; j++)
-				if (combined_all_paths &&
-				    filename_changed(p->parent[j].status))
-					strbuf_release(&p->parent[j].path);
+				free(p->parent[j].path);
 			free(p);
 			continue;
 		}
@@ -110,8 +97,7 @@ static struct combine_diff_path *intersect_paths(
 		p->parent[n].status = q->queue[i]->status;
 		if (combined_all_paths &&
 		    filename_changed(p->parent[n].status))
-			strbuf_addstr(&p->parent[n].path,
-				      q->queue[i]->one->path);
+			p->parent[n].path = xstrdup(q->queue[i]->one->path);
 
 		tail = &p->next;
 		i++;
@@ -996,8 +982,9 @@ static void show_combined_header(struct combine_diff_path *elem,
 
 	if (rev->combined_all_paths) {
 		for (i = 0; i < num_parent; i++) {
-			char *path = filename_changed(elem->parent[i].status)
-				? elem->parent[i].path.buf : elem->path;
+			const char *path = elem->parent[i].path ?
+					   elem->parent[i].path :
+					   elem->path;
 			if (elem->parent[i].status == DIFF_STATUS_ADDED)
 				dump_quoted_path("--- ", "", "/dev/null",
 						 line_prefix, c_meta, c_reset);
@@ -1278,12 +1265,10 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
 
 	for (i = 0; i < num_parent; i++)
 		if (rev->combined_all_paths) {
-			if (filename_changed(p->parent[i].status))
-				write_name_quoted(p->parent[i].path.buf, stdout,
-						  inter_name_termination);
-			else
-				write_name_quoted(p->path, stdout,
-						  inter_name_termination);
+			const char *path = p->parent[i].path ?
+					   p->parent[i].path :
+					   p->path;
+			write_name_quoted(path, stdout, inter_name_termination);
 		}
 	write_name_quoted(p->path, stdout, line_termination);
 }
@@ -1443,22 +1428,19 @@ static struct combine_diff_path *find_paths_multitree(
 {
 	int i, nparent = parents->nr;
 	const struct object_id **parents_oid;
-	struct combine_diff_path paths_head;
+	struct combine_diff_path *paths;
 	struct strbuf base;
 
 	ALLOC_ARRAY(parents_oid, nparent);
 	for (i = 0; i < nparent; i++)
 		parents_oid[i] = &parents->oid[i];
 
-	/* fake list head, so worker can assume it is non-NULL */
-	paths_head.next = NULL;
-
 	strbuf_init(&base, PATH_MAX);
-	diff_tree_paths(&paths_head, oid, parents_oid, nparent, &base, opt);
+	paths = diff_tree_paths(oid, parents_oid, nparent, &base, opt);
 
 	strbuf_release(&base);
 	free(parents_oid);
-	return paths_head.next;
+	return paths;
 }
 
 static int match_objfind(struct combine_diff_path *path,
@@ -1645,9 +1627,7 @@ void diff_tree_combined(const struct object_id *oid,
 		struct combine_diff_path *tmp = paths;
 		paths = paths->next;
 		for (i = 0; i < num_parent; i++)
-			if (rev->combined_all_paths &&
-			    filename_changed(tmp->parent[i].status))
-				strbuf_release(&tmp->parent[i].path);
+			free(tmp->parent[i].path);
 		free(tmp);
 	}
 
@@ -1667,3 +1647,25 @@ void diff_tree_combined_merge(const struct commit *commit,
 	diff_tree_combined(&commit->object.oid, &parents, rev);
 	oid_array_clear(&parents);
 }
+
+struct combine_diff_path *combine_diff_path_new(const char *path,
+						size_t path_len,
+						unsigned int mode,
+						const struct object_id *oid,
+						size_t num_parents)
+{
+	struct combine_diff_path *p;
+	size_t parent_len = st_mult(sizeof(p->parent[0]), num_parents);
+
+	p = xmalloc(st_add4(sizeof(*p), path_len, 1, parent_len));
+	p->path = (char *)&(p->parent[num_parents]);
+	memcpy(p->path, path, path_len);
+	p->path[path_len] = 0;
+	p->next = NULL;
+	p->mode = mode;
+	oidcpy(&p->oid, oid);
+
+	memset(p->parent, 0, parent_len);
+
+	return p;
+}
diff --git a/command-list.txt b/command-list.txt
index e0bb87b..c537114 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -60,6 +60,7 @@
 git-apply                               plumbingmanipulators            complete
 git-archimport                          foreignscminterface
 git-archive                             mainporcelain
+git-backfill                            mainporcelain           history
 git-bisect                              mainporcelain           info
 git-blame                               ancillaryinterrogators          complete
 git-branch                              mainporcelain           history
diff --git a/commit-graph.c b/commit-graph.c
index 0df66e5..1021ccb 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1534,6 +1534,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)
 
 	if (ctx->report_progress)
 		ctx->progress = start_delayed_progress(
+					the_repository,
 					_("Loading known commits in commit graph"),
 					ctx->oids.nr);
 	for (i = 0; i < ctx->oids.nr; i++) {
@@ -1551,6 +1552,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)
 	 */
 	if (ctx->report_progress)
 		ctx->progress = start_delayed_progress(
+					the_repository,
 					_("Expanding reachable commits in commit graph"),
 					0);
 	for (i = 0; i < ctx->oids.nr; i++) {
@@ -1571,6 +1573,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)
 
 	if (ctx->report_progress)
 		ctx->progress = start_delayed_progress(
+					the_repository,
 					_("Clearing commit marks in commit graph"),
 					ctx->oids.nr);
 	for (i = 0; i < ctx->oids.nr; i++) {
@@ -1688,6 +1691,7 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx)
 	if (ctx->report_progress)
 		info.progress = ctx->progress
 			      = start_delayed_progress(
+					the_repository,
 					_("Computing commit graph topological levels"),
 					ctx->commits.nr);
 
@@ -1722,6 +1726,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
 	if (ctx->report_progress)
 		info.progress = ctx->progress
 			      = start_delayed_progress(
+					the_repository,
 					_("Computing commit graph generation numbers"),
 					ctx->commits.nr);
 
@@ -1798,6 +1803,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)
 
 	if (ctx->report_progress)
 		progress = start_delayed_progress(
+			the_repository,
 			_("Computing commit changed paths Bloom filters"),
 			ctx->commits.nr);
 
@@ -1877,6 +1883,7 @@ int write_commit_graph_reachable(struct object_directory *odb,
 	data.commits = &commits;
 	if (flags & COMMIT_GRAPH_WRITE_PROGRESS)
 		data.progress = start_delayed_progress(
+			the_repository,
 			_("Collecting referenced commits"), 0);
 
 	refs_for_each_ref(get_main_ref_store(the_repository), add_ref_to_set,
@@ -1908,7 +1915,8 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
 			       "Finding commits for commit graph in %"PRIuMAX" packs",
 			       pack_indexes->nr),
 			    (uintmax_t)pack_indexes->nr);
-		ctx->progress = start_delayed_progress(progress_title.buf, 0);
+		ctx->progress = start_delayed_progress(the_repository,
+						       progress_title.buf, 0);
 		ctx->progress_done = 0;
 	}
 	for (i = 0; i < pack_indexes->nr; i++) {
@@ -1959,6 +1967,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
 {
 	if (ctx->report_progress)
 		ctx->progress = start_delayed_progress(
+			the_repository,
 			_("Finding commits for commit graph among packed objects"),
 			ctx->approx_nr_objects);
 	for_each_packed_object(ctx->r, add_packed_commits, ctx,
@@ -1977,6 +1986,7 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
 	ctx->num_extra_edges = 0;
 	if (ctx->report_progress)
 		ctx->progress = start_delayed_progress(
+			the_repository,
 			_("Finding extra edges in commit graph"),
 			ctx->oids.nr);
 	oid_array_sort(&ctx->oids);
@@ -2074,7 +2084,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 			return -1;
 		}
 
-		if (adjust_shared_perm(get_tempfile_path(graph_layer))) {
+		if (adjust_shared_perm(the_repository, get_tempfile_path(graph_layer))) {
 			error(_("unable to adjust shared permissions for '%s'"),
 			      get_tempfile_path(graph_layer));
 			return -1;
@@ -2136,6 +2146,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 			       get_num_chunks(cf)),
 			    get_num_chunks(cf));
 		ctx->progress = start_delayed_progress(
+			the_repository,
 			progress_title.buf,
 			st_mult(get_num_chunks(cf), ctx->commits.nr));
 	}
@@ -2348,6 +2359,7 @@ static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx)
 
 	if (ctx->report_progress)
 		ctx->progress = start_delayed_progress(
+					the_repository,
 					_("Scanning merged commits"),
 					ctx->commits.nr);
 
@@ -2392,7 +2404,8 @@ static void merge_commit_graphs(struct write_commit_graph_context *ctx)
 		current_graph_number--;
 
 		if (ctx->report_progress)
-			ctx->progress = start_delayed_progress(_("Merging commit-graph"), 0);
+			ctx->progress = start_delayed_progress(the_repository,
+							       _("Merging commit-graph"), 0);
 
 		merge_commit_graph(ctx, g);
 		stop_progress(&ctx->progress);
@@ -2874,7 +2887,8 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
 		if (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))
 			total += g->num_commits_in_base;
 
-		progress = start_progress(_("Verifying commits in commit graph"),
+		progress = start_progress(the_repository,
+					  _("Verifying commits in commit graph"),
 					  total);
 	}
 
diff --git a/commit-reach.c b/commit-reach.c
index e3edd11..a339e41 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -1,5 +1,4 @@
 #define USE_THE_REPOSITORY_VARIABLE
-#define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
 #include "commit.h"
@@ -42,8 +41,7 @@ static int compare_commits_by_gen(const void *_a, const void *_b)
 
 static int queue_has_nonstale(struct prio_queue *queue)
 {
-	int i;
-	for (i = 0; i < queue->nr; i++) {
+	for (size_t i = 0; i < queue->nr; i++) {
 		struct commit *commit = queue->array[i].data;
 		if (!(commit->object.flags & STALE))
 			return 1;
@@ -213,12 +211,13 @@ int get_octopus_merge_bases(struct commit_list *in, struct commit_list **result)
 }
 
 static int remove_redundant_no_gen(struct repository *r,
-				   struct commit **array, int cnt)
+				   struct commit **array,
+				   size_t cnt, size_t *dedup_cnt)
 {
 	struct commit **work;
 	unsigned char *redundant;
-	int *filled_index;
-	int i, j, filled;
+	size_t *filled_index;
+	size_t i, j, filled;
 
 	CALLOC_ARRAY(work, cnt);
 	redundant = xcalloc(cnt, 1);
@@ -268,20 +267,22 @@ static int remove_redundant_no_gen(struct repository *r,
 	for (i = filled = 0; i < cnt; i++)
 		if (!redundant[i])
 			array[filled++] = work[i];
+	*dedup_cnt = filled;
 	free(work);
 	free(redundant);
 	free(filled_index);
-	return filled;
+	return 0;
 }
 
 static int remove_redundant_with_gen(struct repository *r,
-				     struct commit **array, int cnt)
+				     struct commit **array, size_t cnt,
+				     size_t *dedup_cnt)
 {
-	int i, count_non_stale = 0, count_still_independent = cnt;
+	size_t i, count_non_stale = 0, count_still_independent = cnt;
 	timestamp_t min_generation = GENERATION_NUMBER_INFINITY;
 	struct commit **walk_start, **sorted;
 	size_t walk_start_nr = 0, walk_start_alloc = cnt;
-	int min_gen_pos = 0;
+	size_t min_gen_pos = 0;
 
 	/*
 	 * Sort the input by generation number, ascending. This allows
@@ -327,12 +328,12 @@ static int remove_redundant_with_gen(struct repository *r,
 	 * terminate early. Otherwise, we will do the same amount of work
 	 * as before.
 	 */
-	for (i = walk_start_nr - 1; i >= 0 && count_still_independent > 1; i--) {
+	for (i = walk_start_nr; i && count_still_independent > 1; i--) {
 		/* push the STALE bits up to min generation */
 		struct commit_list *stack = NULL;
 
-		commit_list_insert(walk_start[i], &stack);
-		walk_start[i]->object.flags |= STALE;
+		commit_list_insert(walk_start[i - 1], &stack);
+		walk_start[i - 1]->object.flags |= STALE;
 
 		while (stack) {
 			struct commit_list *parents;
@@ -389,10 +390,12 @@ static int remove_redundant_with_gen(struct repository *r,
 	clear_commit_marks_many(walk_start_nr, walk_start, STALE);
 	free(walk_start);
 
-	return count_non_stale;
+	*dedup_cnt = count_non_stale;
+	return 0;
 }
 
-static int remove_redundant(struct repository *r, struct commit **array, int cnt)
+static int remove_redundant(struct repository *r, struct commit **array,
+			    size_t cnt, size_t *dedup_cnt)
 {
 	/*
 	 * Some commit in the array may be an ancestor of
@@ -402,31 +405,30 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt
 	 * that number.
 	 */
 	if (generation_numbers_enabled(r)) {
-		int i;
-
 		/*
 		 * If we have a single commit with finite generation
 		 * number, then the _with_gen algorithm is preferred.
 		 */
-		for (i = 0; i < cnt; i++) {
+		for (size_t i = 0; i < cnt; i++) {
 			if (commit_graph_generation(array[i]) < GENERATION_NUMBER_INFINITY)
-				return remove_redundant_with_gen(r, array, cnt);
+				return remove_redundant_with_gen(r, array, cnt, dedup_cnt);
 		}
 	}
 
-	return remove_redundant_no_gen(r, array, cnt);
+	return remove_redundant_no_gen(r, array, cnt, dedup_cnt);
 }
 
 static int get_merge_bases_many_0(struct repository *r,
 				  struct commit *one,
-				  int n,
+				  size_t n,
 				  struct commit **twos,
 				  int cleanup,
 				  struct commit_list **result)
 {
 	struct commit_list *list;
 	struct commit **rslt;
-	int cnt, i;
+	size_t cnt, i;
+	int ret;
 
 	if (merge_bases_many(r, one, n, twos, result) < 0)
 		return -1;
@@ -453,8 +455,8 @@ static int get_merge_bases_many_0(struct repository *r,
 	clear_commit_marks(one, all_flags);
 	clear_commit_marks_many(n, twos, all_flags);
 
-	cnt = remove_redundant(r, rslt, cnt);
-	if (cnt < 0) {
+	ret = remove_redundant(r, rslt, cnt, &cnt);
+	if (ret < 0) {
 		free(rslt);
 		return -1;
 	}
@@ -466,7 +468,7 @@ static int get_merge_bases_many_0(struct repository *r,
 
 int repo_get_merge_bases_many(struct repository *r,
 			      struct commit *one,
-			      int n,
+			      size_t n,
 			      struct commit **twos,
 			      struct commit_list **result)
 {
@@ -475,7 +477,7 @@ int repo_get_merge_bases_many(struct repository *r,
 
 int repo_get_merge_bases_many_dirty(struct repository *r,
 				    struct commit *one,
-				    int n,
+				    size_t n,
 				    struct commit **twos,
 				    struct commit_list **result)
 {
@@ -583,7 +585,8 @@ struct commit_list *reduce_heads(struct commit_list *heads)
 	struct commit_list *p;
 	struct commit_list *result = NULL, **tail = &result;
 	struct commit **array;
-	int num_head, i;
+	size_t num_head, i;
+	int ret;
 
 	if (!heads)
 		return NULL;
@@ -604,11 +607,13 @@ struct commit_list *reduce_heads(struct commit_list *heads)
 			p->item->object.flags &= ~STALE;
 		}
 	}
-	num_head = remove_redundant(the_repository, array, num_head);
-	if (num_head < 0) {
+
+	ret = remove_redundant(the_repository, array, num_head, &num_head);
+	if (ret < 0) {
 		free(array);
 		return NULL;
 	}
+
 	for (i = 0; i < num_head; i++)
 		tail = &commit_list_insert(array[i], tail)->next;
 	free(array);
@@ -781,12 +786,12 @@ int commit_contains(struct ref_filter *filter, struct commit *commit,
 int can_all_from_reach_with_flag(struct object_array *from,
 				 unsigned int with_flag,
 				 unsigned int assign_flag,
-				 time_t min_commit_date,
+				 timestamp_t min_commit_date,
 				 timestamp_t min_generation)
 {
 	struct commit **list = NULL;
-	int i;
-	int nr_commits;
+	size_t i;
+	size_t nr_commits;
 	int result = 1;
 
 	ALLOC_ARRAY(list, from->nr);
@@ -884,9 +889,9 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
 		       int cutoff_by_min_date)
 {
 	struct object_array from_objs = OBJECT_ARRAY_INIT;
-	time_t min_commit_date = cutoff_by_min_date ? from->item->date : 0;
 	struct commit_list *from_iter = from, *to_iter = to;
 	int result;
+	timestamp_t min_commit_date = cutoff_by_min_date ? from->item->date : 0;
 	timestamp_t min_generation = GENERATION_NUMBER_INFINITY;
 
 	while (from_iter) {
@@ -938,8 +943,8 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
 	return result;
 }
 
-struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
-					 struct commit **to, int nr_to,
+struct commit_list *get_reachable_subset(struct commit **from, size_t nr_from,
+					 struct commit **to, size_t nr_to,
 					 unsigned int reachable_flag)
 {
 	struct commit **item;
diff --git a/commit-reach.h b/commit-reach.h
index 9a745b7..6012402 100644
--- a/commit-reach.h
+++ b/commit-reach.h
@@ -14,12 +14,12 @@ int repo_get_merge_bases(struct repository *r,
 			 struct commit *rev2,
 			 struct commit_list **result);
 int repo_get_merge_bases_many(struct repository *r,
-			      struct commit *one, int n,
+			      struct commit *one, size_t n,
 			      struct commit **twos,
 			      struct commit_list **result);
 /* To be used only when object flags after this call no longer matter */
 int repo_get_merge_bases_many_dirty(struct repository *r,
-				    struct commit *one, int n,
+				    struct commit *one, size_t n,
 				    struct commit **twos,
 				    struct commit_list **result);
 
@@ -81,7 +81,7 @@ int commit_contains(struct ref_filter *filter, struct commit *commit,
 int can_all_from_reach_with_flag(struct object_array *from,
 				 unsigned int with_flag,
 				 unsigned int assign_flag,
-				 time_t min_commit_date,
+				 timestamp_t min_commit_date,
 				 timestamp_t min_generation);
 int can_all_from_reach(struct commit_list *from, struct commit_list *to,
 		       int commit_date_cutoff);
@@ -95,8 +95,8 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
  * This method uses the PARENT1 and PARENT2 flags during its operation,
  * so be sure these flags are not set before calling the method.
  */
-struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
-					 struct commit **to, int nr_to,
+struct commit_list *get_reachable_subset(struct commit **from, size_t nr_from,
+					 struct commit **to, size_t nr_to,
 					 unsigned int reachable_flag);
 
 struct ahead_behind_count {
diff --git a/commit.c b/commit.c
index a127fe6..6efdb03 100644
--- a/commit.c
+++ b/commit.c
@@ -778,16 +778,16 @@ static void clear_commit_marks_1(struct commit_list **plist,
 	}
 }
 
-void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark)
+void clear_commit_marks_many(size_t nr, struct commit **commit, unsigned int mark)
 {
-	struct commit_list *list = NULL;
+	for (size_t i = 0; i < nr; i++) {
+		struct commit_list *list = NULL;
 
-	while (nr--) {
 		clear_commit_marks_1(&list, *commit, mark);
+		while (list)
+			clear_commit_marks_1(&list, pop_commit(&list), mark);
 		commit++;
 	}
-	while (list)
-		clear_commit_marks_1(&list, pop_commit(&list), mark);
 }
 
 void clear_commit_marks(struct commit *commit, unsigned int mark)
diff --git a/commit.h b/commit.h
index 943e3d7..70c870d 100644
--- a/commit.h
+++ b/commit.h
@@ -210,7 +210,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
 struct commit *pop_commit(struct commit_list **stack);
 
 void clear_commit_marks(struct commit *commit, unsigned int mark);
-void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark);
+void clear_commit_marks_many(size_t nr, struct commit **commit, unsigned int mark);
 
 
 enum rev_sort_order {
diff --git a/common-exit.c b/common-exit.c
new file mode 100644
index 0000000..1aaa538
--- /dev/null
+++ b/common-exit.c
@@ -0,0 +1,26 @@
+#include "git-compat-util.h"
+#include "trace2.h"
+
+static void check_bug_if_BUG(void)
+{
+	if (!bug_called_must_BUG)
+		return;
+	BUG("on exit(): had bug() call(s) in this process without explicit BUG_if_bug()");
+}
+
+/* We wrap exit() to call common_exit() in git-compat-util.h */
+int common_exit(const char *file, int line, int code)
+{
+	/*
+	 * For non-POSIX systems: Take the lowest 8 bits of the "code"
+	 * to e.g. turn -1 into 255. On a POSIX system this is
+	 * redundant, see exit(3) and wait(2), but as it doesn't harm
+	 * anything there we don't need to guard this with an "ifdef".
+	 */
+	code &= 0xff;
+
+	check_bug_if_BUG();
+	trace2_cmd_exit_fl(file, line, code);
+
+	return code;
+}
diff --git a/common-init.c b/common-init.c
new file mode 100644
index 0000000..5cc73f0
--- /dev/null
+++ b/common-init.c
@@ -0,0 +1,63 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "common-init.h"
+#include "exec-cmd.h"
+#include "gettext.h"
+#include "attr.h"
+#include "repository.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "trace2.h"
+
+/*
+ * Many parts of Git have subprograms communicate via pipe, expect the
+ * upstream of a pipe to die with SIGPIPE when the downstream of a
+ * pipe does not need to read all that is written.  Some third-party
+ * programs that ignore or block SIGPIPE for their own reason forget
+ * to restore SIGPIPE handling to the default before spawning Git and
+ * break this carefully orchestrated machinery.
+ *
+ * Restore the way SIGPIPE is handled to default, which is what we
+ * expect.
+ */
+static void restore_sigpipe_to_default(void)
+{
+	sigset_t unblock;
+
+	sigemptyset(&unblock);
+	sigaddset(&unblock, SIGPIPE);
+	sigprocmask(SIG_UNBLOCK, &unblock, NULL);
+	signal(SIGPIPE, SIG_DFL);
+}
+
+void init_git(const char **argv)
+{
+	struct strbuf tmp = STRBUF_INIT;
+
+	trace2_initialize_clock();
+
+	/*
+	 * Always open file descriptors 0/1/2 to avoid clobbering files
+	 * in die().  It also avoids messing up when the pipes are dup'ed
+	 * onto stdin/stdout/stderr in the child processes we spawn.
+	 */
+	sanitize_stdfds();
+	restore_sigpipe_to_default();
+
+	git_resolve_executable_dir(argv[0]);
+
+	setlocale(LC_CTYPE, "");
+	git_setup_gettext();
+
+	initialize_repository(the_repository);
+
+	attr_start();
+
+	trace2_initialize();
+	trace2_cmd_start(argv);
+	trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);
+
+	if (!strbuf_getcwd(&tmp))
+		tmp_original_cwd = strbuf_detach(&tmp, NULL);
+}
diff --git a/common-init.h b/common-init.h
new file mode 100644
index 0000000..3e6db20
--- /dev/null
+++ b/common-init.h
@@ -0,0 +1,6 @@
+#ifndef COMMON_INIT_H
+#define COMMON_INIT_H
+
+void init_git(const char **argv);
+
+#endif /* COMMON_INIT_H */
diff --git a/common-main.c b/common-main.c
index 8e68ac9..6b7ab07 100644
--- a/common-main.c
+++ b/common-main.c
@@ -1,92 +1,13 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
-#include "exec-cmd.h"
-#include "gettext.h"
-#include "attr.h"
-#include "repository.h"
-#include "setup.h"
-#include "strbuf.h"
-#include "trace2.h"
-
-/*
- * Many parts of Git have subprograms communicate via pipe, expect the
- * upstream of a pipe to die with SIGPIPE when the downstream of a
- * pipe does not need to read all that is written.  Some third-party
- * programs that ignore or block SIGPIPE for their own reason forget
- * to restore SIGPIPE handling to the default before spawning Git and
- * break this carefully orchestrated machinery.
- *
- * Restore the way SIGPIPE is handled to default, which is what we
- * expect.
- */
-static void restore_sigpipe_to_default(void)
-{
-	sigset_t unblock;
-
-	sigemptyset(&unblock);
-	sigaddset(&unblock, SIGPIPE);
-	sigprocmask(SIG_UNBLOCK, &unblock, NULL);
-	signal(SIGPIPE, SIG_DFL);
-}
+#include "common-init.h"
 
 int main(int argc, const char **argv)
 {
 	int result;
-	struct strbuf tmp = STRBUF_INIT;
 
-	trace2_initialize_clock();
-
-	/*
-	 * Always open file descriptors 0/1/2 to avoid clobbering files
-	 * in die().  It also avoids messing up when the pipes are dup'ed
-	 * onto stdin/stdout/stderr in the child processes we spawn.
-	 */
-	sanitize_stdfds();
-	restore_sigpipe_to_default();
-
-	git_resolve_executable_dir(argv[0]);
-
-	setlocale(LC_CTYPE, "");
-	git_setup_gettext();
-
-	initialize_repository(the_repository);
-
-	attr_start();
-
-	trace2_initialize();
-	trace2_cmd_start(argv);
-	trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);
-
-	if (!strbuf_getcwd(&tmp))
-		tmp_original_cwd = strbuf_detach(&tmp, NULL);
-
+	init_git(argv);
 	result = cmd_main(argc, argv);
 
 	/* Not exit(3), but a wrapper calling our common_exit() */
 	exit(result);
 }
-
-static void check_bug_if_BUG(void)
-{
-	if (!bug_called_must_BUG)
-		return;
-	BUG("on exit(): had bug() call(s) in this process without explicit BUG_if_bug()");
-}
-
-/* We wrap exit() to call common_exit() in git-compat-util.h */
-int common_exit(const char *file, int line, int code)
-{
-	/*
-	 * For non-POSIX systems: Take the lowest 8 bits of the "code"
-	 * to e.g. turn -1 into 255. On a POSIX system this is
-	 * redundant, see exit(3) and wait(2), but as it doesn't harm
-	 * anything there we don't need to guard this with an "ifdef".
-	 */
-	code &= 0xff;
-
-	check_bug_if_BUG();
-	trace2_cmd_exit_fl(file, line, code);
-
-	return code;
-}
diff --git a/compat/bswap.h b/compat/bswap.h
index 512f6f4..b34054f 100644
--- a/compat/bswap.h
+++ b/compat/bswap.h
@@ -171,23 +171,23 @@ static inline uint64_t get_be64(const void *ptr)
 static inline void put_be32(void *ptr, uint32_t value)
 {
 	unsigned char *p = ptr;
-	p[0] = value >> 24;
-	p[1] = value >> 16;
-	p[2] = value >>  8;
-	p[3] = value >>  0;
+	p[0] = (value >> 24) & 0xff;
+	p[1] = (value >> 16) & 0xff;
+	p[2] = (value >>  8) & 0xff;
+	p[3] = (value >>  0) & 0xff;
 }
 
 static inline void put_be64(void *ptr, uint64_t value)
 {
 	unsigned char *p = ptr;
-	p[0] = value >> 56;
-	p[1] = value >> 48;
-	p[2] = value >> 40;
-	p[3] = value >> 32;
-	p[4] = value >> 24;
-	p[5] = value >> 16;
-	p[6] = value >>  8;
-	p[7] = value >>  0;
+	p[0] = (value >> 56) & 0xff;
+	p[1] = (value >> 48) & 0xff;
+	p[2] = (value >> 40) & 0xff;
+	p[3] = (value >> 32) & 0xff;
+	p[4] = (value >> 24) & 0xff;
+	p[5] = (value >> 16) & 0xff;
+	p[6] = (value >>  8) & 0xff;
+	p[7] = (value >>  0) & 0xff;
 }
 
 #endif /* COMPAT_BSWAP_H */
diff --git a/compat/mingw.c b/compat/mingw.c
index 1d5b211..f524c54 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2278,7 +2278,9 @@ int mingw_rename(const char *pold, const char *pnew)
 
 		old_handle = CreateFileW(wpold, DELETE,
 					 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
-					 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+					 NULL, OPEN_EXISTING,
+					 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+					 NULL);
 		if (old_handle == INVALID_HANDLE_VALUE) {
 			errno = err_win_to_posix(GetLastError());
 			return -1;
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index f7cc7b3..12e38e0 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -50,15 +50,15 @@ void probe_utf8_pathname_composition(void)
 	int output_fd;
 	if (precomposed_unicode != -1)
 		return; /* We found it defined in the global config, respect it */
-	git_path_buf(&path, "%s", auml_nfc);
+	repo_git_path_replace(the_repository, &path, "%s", auml_nfc);
 	output_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600);
 	if (output_fd >= 0) {
 		close(output_fd);
-		git_path_buf(&path, "%s", auml_nfd);
+		repo_git_path_replace(the_repository, &path, "%s", auml_nfd);
 		precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;
 		git_config_set("core.precomposeunicode",
 			       precomposed_unicode ? "true" : "false");
-		git_path_buf(&path, "%s", auml_nfc);
+		repo_git_path_replace(the_repository, &path, "%s", auml_nfc);
 		if (unlink(path.buf))
 			die_errno(_("failed to unlink '%s'"), path.buf);
 	}
diff --git a/compat/zlib-compat.h b/compat/zlib-compat.h
new file mode 100644
index 0000000..0c60e3a
--- /dev/null
+++ b/compat/zlib-compat.h
@@ -0,0 +1,53 @@
+#ifndef COMPAT_ZLIB_H
+#define COMPAT_ZLIB_H
+
+#ifdef HAVE_ZLIB_NG
+# include <zlib-ng.h>
+
+# define z_stream zng_stream
+#define gz_header_s zng_gz_header_s
+
+# define crc32(crc, buf, len) zng_crc32(crc, buf, len)
+
+# define inflate(strm, bits) zng_inflate(strm, bits)
+# define inflateEnd(strm) zng_inflateEnd(strm)
+# define inflateInit(strm) zng_inflateInit(strm)
+# define inflateInit2(strm, bits) zng_inflateInit2(strm, bits)
+# define inflateReset(strm) zng_inflateReset(strm)
+
+# define deflate(strm, flush) zng_deflate(strm, flush)
+# define deflateBound(strm, source_len) zng_deflateBound(strm, source_len)
+# define deflateEnd(strm) zng_deflateEnd(strm)
+# define deflateInit(strm, level) zng_deflateInit(strm, level)
+# define deflateInit2(stream, level, method, window_bits, mem_level, strategy) zng_deflateInit2(stream, level, method, window_bits, mem_level, strategy)
+# define deflateReset(strm) zng_deflateReset(strm)
+# define deflateSetHeader(strm, head) zng_deflateSetHeader(strm, head)
+
+#else
+# include <zlib.h>
+
+# if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
+#  define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
+# endif
+
+/*
+ * zlib only gained support for setting up the gzip header in v1.2.2.1. In
+ * Git we only set the header to make archives reproducible across different
+ * operating systems, so it's fine to simply make this a no-op when using a
+ * zlib version that doesn't support this yet.
+ */
+# if ZLIB_VERNUM < 0x1221
+struct gz_header_s {
+	int os;
+};
+
+static int deflateSetHeader(z_streamp strm, struct gz_header_s *head)
+{
+	(void)(strm);
+	(void)(head);
+	return Z_OK;
+}
+# endif
+#endif /* HAVE_ZLIB_NG */
+
+#endif /* COMPAT_ZLIB_H */
diff --git a/compat/zlib-uncompress2.c b/compat/zlib-uncompress2.c
deleted file mode 100644
index 77a1b08..0000000
--- a/compat/zlib-uncompress2.c
+++ /dev/null
@@ -1,96 +0,0 @@
-#include "git-compat-util.h"
-
-#if ZLIB_VERNUM < 0x1290
-/* taken from zlib's uncompr.c
-
-   commit cacf7f1d4e3d44d871b605da3b647f07d718623f
-   Author: Mark Adler <madler@alumni.caltech.edu>
-   Date:   Sun Jan 15 09:18:46 2017 -0800
-
-       zlib 1.2.11
-
-*/
-
-/*
- * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/* clang-format off */
-
-/* ===========================================================================
-     Decompresses the source buffer into the destination buffer.  *sourceLen is
-   the byte length of the source buffer. Upon entry, *destLen is the total size
-   of the destination buffer, which must be large enough to hold the entire
-   uncompressed data. (The size of the uncompressed data must have been saved
-   previously by the compressor and transmitted to the decompressor by some
-   mechanism outside the scope of this compression library.) Upon exit,
-   *destLen is the size of the decompressed data and *sourceLen is the number
-   of source bytes consumed. Upon return, source + *sourceLen points to the
-   first unused input byte.
-
-     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_BUF_ERROR if there was not enough room in the output buffer, or
-   Z_DATA_ERROR if the input data was corrupted, including if the input data is
-   an incomplete zlib stream.
-*/
-int ZEXPORT uncompress2 (
-    Bytef *dest,
-    uLongf *destLen,
-    const Bytef *source,
-    uLong *sourceLen) {
-    z_stream stream;
-    int err;
-    const uInt max = (uInt)-1;
-    uLong len, left;
-    Byte buf[1];    /* for detection of incomplete stream when *destLen == 0 */
-
-    len = *sourceLen;
-    if (*destLen) {
-	left = *destLen;
-	*destLen = 0;
-    }
-    else {
-	left = 1;
-	dest = buf;
-    }
-
-    stream.next_in = (z_const Bytef *)source;
-    stream.avail_in = 0;
-    stream.zalloc = (alloc_func)0;
-    stream.zfree = (free_func)0;
-    stream.opaque = (voidpf)0;
-
-    err = inflateInit(&stream);
-    if (err != Z_OK) return err;
-
-    stream.next_out = dest;
-    stream.avail_out = 0;
-
-    do {
-	if (stream.avail_out == 0) {
-	    stream.avail_out = left > (uLong)max ? max : (uInt)left;
-	    left -= stream.avail_out;
-	}
-	if (stream.avail_in == 0) {
-	    stream.avail_in = len > (uLong)max ? max : (uInt)len;
-	    len -= stream.avail_in;
-	}
-	err = inflate(&stream, Z_NO_FLUSH);
-    } while (err == Z_OK);
-
-    *sourceLen -= len + stream.avail_in;
-    if (dest != buf)
-	*destLen = stream.total_out;
-    else if (stream.total_out && err == Z_BUF_ERROR)
-	left = 1;
-
-    inflateEnd(&stream);
-    return err == Z_STREAM_END ? Z_OK :
-	   err == Z_NEED_DICT ? Z_DATA_ERROR  :
-	   err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
-	   err;
-}
-#else
-static void *dummy_variable = &dummy_variable;
-#endif
diff --git a/config.c b/config.c
index 4d73507..3dc9c78 100644
--- a/config.c
+++ b/config.c
@@ -19,6 +19,7 @@
 #include "convert.h"
 #include "environment.h"
 #include "gettext.h"
+#include "git-zlib.h"
 #include "ident.h"
 #include "repository.h"
 #include "lockfile.h"
@@ -1436,11 +1437,6 @@ static int git_default_core_config(const char *var, const char *value,
 		return git_config_pathname(&git_attributes_file, var, value);
 	}
 
-	if (!strcmp(var, "core.hookspath")) {
-		FREE_AND_NULL(git_hooks_path);
-		return git_config_pathname(&git_hooks_path, var, value);
-	}
-
 	if (!strcmp(var, "core.bare")) {
 		is_bare_repository_cfg = git_config_bool(var, value);
 		return 0;
@@ -1651,7 +1647,7 @@ static int git_default_core_config(const char *var, const char *value,
 		return 0;
 	}
 
-	/* Add other config variables here and to Documentation/config.txt. */
+	/* Add other config variables here and to Documentation/config.adoc. */
 	return platform_core_config(var, value, ctx, cb);
 }
 
@@ -1662,7 +1658,7 @@ static int git_default_sparse_config(const char *var, const char *value)
 		return 0;
 	}
 
-	/* Add other config variables here and to Documentation/config/sparse.txt. */
+	/* Add other config variables here and to Documentation/config/sparse.adoc. */
 	return 0;
 }
 
@@ -1678,7 +1674,7 @@ static int git_default_i18n_config(const char *var, const char *value)
 		return git_config_string(&git_log_output_encoding, var, value);
 	}
 
-	/* Add other config variables here and to Documentation/config.txt. */
+	/* Add other config variables here and to Documentation/config.adoc. */
 	return 0;
 }
 
@@ -1714,7 +1710,7 @@ static int git_default_branch_config(const char *var, const char *value)
 		return 0;
 	}
 
-	/* Add other config variables here and to Documentation/config.txt. */
+	/* Add other config variables here and to Documentation/config.adoc. */
 	return 0;
 }
 
@@ -1743,7 +1739,7 @@ static int git_default_push_config(const char *var, const char *value)
 		return 0;
 	}
 
-	/* Add other config variables here and to Documentation/config.txt. */
+	/* Add other config variables here and to Documentation/config.adoc. */
 	return 0;
 }
 
@@ -1759,7 +1755,7 @@ static int git_default_mailmap_config(const char *var, const char *value)
 		return git_config_string(&git_mailmap_blob, var, value);
 	}
 
-	/* Add other config variables here and to Documentation/config.txt. */
+	/* Add other config variables here and to Documentation/config.adoc. */
 	return 0;
 }
 
@@ -1772,7 +1768,7 @@ static int git_default_attr_config(const char *var, const char *value)
 
 	/*
 	 * Add other attribute related config variables here and to
-	 * Documentation/config/attr.txt.
+	 * Documentation/config/attr.adoc.
 	 */
 	return 0;
 }
@@ -1830,7 +1826,7 @@ int git_default_config(const char *var, const char *value,
 	if (starts_with(var, "sparse."))
 		return git_default_sparse_config(var, value);
 
-	/* Add other config variables here and to Documentation/config.txt. */
+	/* Add other config variables here and to Documentation/config.adoc. */
 	return 0;
 }
 
diff --git a/connect.c b/connect.c
index 10fad43..3280435 100644
--- a/connect.c
+++ b/connect.c
@@ -1,5 +1,4 @@
 #define USE_THE_REPOSITORY_VARIABLE
-#define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
 #include "config.h"
@@ -23,6 +22,7 @@
 #include "protocol.h"
 #include "alias.h"
 #include "bundle-uri.h"
+#include "promisor-remote.h"
 
 static char *server_capabilities_v1;
 static struct strvec server_capabilities_v2 = STRVEC_INIT;
@@ -77,7 +77,7 @@ static NORETURN void die_initial_contact(int unexpected)
 /* Checks if the server supports the capability 'c' */
 int server_supports_v2(const char *c)
 {
-	int i;
+	size_t i;
 
 	for (i = 0; i < server_capabilities_v2.nr; i++) {
 		const char *out;
@@ -96,7 +96,7 @@ void ensure_server_supports_v2(const char *c)
 
 int server_feature_v2(const char *c, const char **v)
 {
-	int i;
+	size_t i;
 
 	for (i = 0; i < server_capabilities_v2.nr; i++) {
 		const char *out;
@@ -112,7 +112,7 @@ int server_feature_v2(const char *c, const char **v)
 int server_supports_feature(const char *c, const char *feature,
 			    int die_on_error)
 {
-	int i;
+	size_t i;
 
 	for (i = 0; i < server_capabilities_v2.nr; i++) {
 		const char *out;
@@ -232,12 +232,12 @@ static void annotate_refs_with_symref_info(struct ref *ref)
 	string_list_clear(&symref, 0);
 }
 
-static void process_capabilities(struct packet_reader *reader, int *linelen)
+static void process_capabilities(struct packet_reader *reader, size_t *linelen)
 {
 	const char *feat_val;
 	size_t feat_len;
 	const char *line = reader->line;
-	int nul_location = strlen(line);
+	size_t nul_location = strlen(line);
 	if (nul_location == *linelen)
 		return;
 	server_capabilities_v1 = xstrdup(line + nul_location + 1);
@@ -271,14 +271,14 @@ static int process_dummy_ref(const struct packet_reader *reader)
 		!strcmp(name, "capabilities^{}");
 }
 
-static void check_no_capabilities(const char *line, int len)
+static void check_no_capabilities(const char *line, size_t len)
 {
 	if (strlen(line) != len)
 		warning(_("ignoring capabilities after first line '%s'"),
 			line + strlen(line));
 }
 
-static int process_ref(const struct packet_reader *reader, int len,
+static int process_ref(const struct packet_reader *reader, size_t len,
 		       struct ref ***list, unsigned int flags,
 		       struct oid_array *extra_have)
 {
@@ -306,7 +306,7 @@ static int process_ref(const struct packet_reader *reader, int len,
 	return 1;
 }
 
-static int process_shallow(const struct packet_reader *reader, int len,
+static int process_shallow(const struct packet_reader *reader, size_t len,
 			   struct oid_array *shallow_points)
 {
 	const char *line = reader->line;
@@ -341,7 +341,7 @@ struct ref **get_remote_heads(struct packet_reader *reader,
 			      struct oid_array *shallow_points)
 {
 	struct ref **orig_list = list;
-	int len = 0;
+	size_t len = 0;
 	enum get_remote_heads_state state = EXPECTING_FIRST_REF;
 
 	*list = NULL;
@@ -394,7 +394,7 @@ static int process_ref_v2(struct packet_reader *reader, struct ref ***list,
 			  const char **unborn_head_target)
 {
 	int ret = 1;
-	int i = 0;
+	size_t i = 0;
 	struct object_id old_oid;
 	struct ref *ref;
 	struct string_list line_sections = STRING_LIST_INIT_DUP;
@@ -488,6 +488,7 @@ void check_stateless_delimiter(int stateless_rpc,
 static void send_capabilities(int fd_out, struct packet_reader *reader)
 {
 	const char *hash_name;
+	const char *promisor_remote_info;
 
 	if (server_supports_v2("agent"))
 		packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());
@@ -501,6 +502,13 @@ static void send_capabilities(int fd_out, struct packet_reader *reader)
 	} else {
 		reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
 	}
+	if (server_feature_v2("promisor-remote", &promisor_remote_info)) {
+		char *reply = promisor_remote_reply(promisor_remote_info);
+		if (reply) {
+			packet_write_fmt(fd_out, "promisor-remote=%s", reply);
+			free(reply);
+		}
+	}
 }
 
 int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
@@ -552,7 +560,7 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
 			     const struct string_list *server_options,
 			     int stateless_rpc)
 {
-	int i;
+	size_t i;
 	struct strvec *ref_prefixes = transport_options ?
 		&transport_options->ref_prefixes : NULL;
 	const char **unborn_head_target = transport_options ?
@@ -625,7 +633,7 @@ const char *parse_feature_value(const char *feature_list, const char *feature, s
 					*offset = found + len - orig_start;
 				return value;
 			}
-			/* feature with a value (e.g., "agent=git/1.2.3") */
+			/* feature with a value (e.g., "agent=git/1.2.3-Linux") */
 			else if (*value == '=') {
 				size_t end;
 
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 10dc54f..25b495f 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -1001,10 +1001,14 @@
 list(TRANSFORM unit-test_SOURCES REPLACE "\\$\\(UNIT_TEST_DIR\\)/" "${CMAKE_SOURCE_DIR}/t/unit-tests/")
 add_library(unit-test-lib STATIC ${unit-test_SOURCES})
 
+parse_makefile_for_sources(clar-test_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "CLAR_TEST_OBJS")
+list(TRANSFORM clar-test_SOURCES REPLACE "\\$\\(UNIT_TEST_DIR\\)/" "${CMAKE_SOURCE_DIR}/t/unit-tests/")
+add_library(clar-test-lib STATIC ${clar-test_SOURCES})
+
 parse_makefile_for_scripts(unit_test_PROGRAMS "UNIT_TEST_PROGRAMS" "")
 foreach(unit_test ${unit_test_PROGRAMS})
 	add_executable("${unit_test}" "${CMAKE_SOURCE_DIR}/t/unit-tests/${unit_test}.c")
-	target_link_libraries("${unit_test}" unit-test-lib common-main)
+	target_link_libraries("${unit_test}" unit-test-lib clar-test-lib common-main)
 	set_target_properties("${unit_test}"
 		PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
 	if(MSVC)
@@ -1046,13 +1050,13 @@
 	VERBATIM)
 
 add_library(unit-tests-lib ${clar_test_SUITES}
-	"${CMAKE_SOURCE_DIR}/t/unit-tests/clar/clar.c"
 	"${CMAKE_BINARY_DIR}/t/unit-tests/clar-decls.h"
 	"${CMAKE_BINARY_DIR}/t/unit-tests/clar.suite"
 )
+target_include_directories(clar-test-lib PUBLIC "${CMAKE_BINARY_DIR}/t/unit-tests")
 target_include_directories(unit-tests-lib PUBLIC "${CMAKE_BINARY_DIR}/t/unit-tests")
-add_executable(unit-tests "${CMAKE_SOURCE_DIR}/t/unit-tests/unit-test.c")
-target_link_libraries(unit-tests unit-tests-lib common-main)
+add_executable(unit-tests)
+target_link_libraries(unit-tests unit-tests-lib clar-test-lib common-main)
 set_target_properties(unit-tests
 	PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
 if(MSVC)
@@ -1169,14 +1173,13 @@
 string(REPLACE "@GIT_PERF_MAKE_OPTS@" "" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_PERF_REPEAT_COUNT@" "" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_PERF_REPO@" "" git_build_options "${git_build_options}")
+string(REPLACE "@GIT_SOURCE_DIR@" "${CMAKE_SOURCE_DIR}" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_TEST_CMP@" "" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_TEST_CMP_USE_COPIED_CONTEXT@" "" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_TEST_GITPERLLIB@" "'${CMAKE_BINARY_DIR}/perl/build/lib'" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_TEST_INDEX_VERSION@" "" git_build_options "${git_build_options}")
-string(REPLACE "@GIT_TEST_MERGE_TOOLS_DIR@" "'${CMAKE_BINARY_DIR}/mergetools'" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_TEST_OPTS@" "" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_TEST_PERL_FATAL_WARNINGS@" "" git_build_options "${git_build_options}")
-string(REPLACE "@GIT_TEST_POPATH@" "'${CMAKE_BINARY_DIR}/po'" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_TEST_TEMPLATE_DIR@" "'${CMAKE_BINARY_DIR}/templates/blt'" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_TEST_TEXTDOMAINDIR@" "'${CMAKE_BINARY_DIR}/po/build/locale'" git_build_options "${git_build_options}")
 string(REPLACE "@GIT_TEST_UTF8_LOCALE@" "" git_build_options "${git_build_options}")
@@ -1205,6 +1208,7 @@
 string(REPLACE "@TEST_SHELL_PATH@" "'${TEST_SHELL_PATH}'" git_build_options "${git_build_options}")
 string(REPLACE "@USE_GETTEXT_SCHEME@" "" git_build_options "${git_build_options}")
 string(REPLACE "@USE_LIBPCRE2@" "" git_build_options "${git_build_options}")
+string(REPLACE "@WITH_BREAKING_CHANGES@" "" git_build_options "${git_build_options}")
 string(REPLACE "@X@" "${EXE_EXTENSION}" git_build_options "${git_build_options}")
 if(USE_VCPKG)
 	string(APPEND git_build_options "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n")
diff --git a/contrib/coccinelle/meson.build b/contrib/coccinelle/meson.build
new file mode 100644
index 0000000..5d76a7f
--- /dev/null
+++ b/contrib/coccinelle/meson.build
@@ -0,0 +1,89 @@
+spatch = find_program('spatch', required: get_option('coccinelle'))
+if not spatch.found()
+  subdir_done()
+endif
+
+third_party_sources = [
+  ':!contrib',
+  ':!compat/inet_ntop.c',
+  ':!compat/inet_pton.c',
+  ':!compat/nedmalloc',
+  ':!compat/obstack.*',
+  ':!compat/poll',
+  ':!compat/regex',
+  ':!sha1collisiondetection',
+  ':!sha1dc',
+  ':!t/unit-tests/clar',
+  ':!t/unit-tests/clar',
+  ':!t/t[0-9][0-9][0-9][0-9]*',
+]
+
+rules = [
+  'array.cocci',
+  'commit.cocci',
+  'config_fn_ctx.pending.cocci',
+  'equals-null.cocci',
+  'flex_alloc.cocci',
+  'free.cocci',
+  'git_config_number.cocci',
+  'hashmap.cocci',
+  'index-compatibility.cocci',
+  'object_id.cocci',
+  'preincr.cocci',
+  'qsort.cocci',
+  'refs.cocci',
+  'strbuf.cocci',
+  'swap.cocci',
+  'the_repository.cocci',
+  'xcalloc.cocci',
+  'xopen.cocci',
+  'xstrdup_or_null.cocci',
+  'xstrncmpz.cocci',
+]
+
+concatenated_rules = custom_target(
+  command: [
+    'cat', '@INPUT@',
+  ],
+  input: rules,
+  output: 'rules.cocci',
+  capture: true,
+)
+
+sources = [ ]
+foreach source : run_command(git, '-C', meson.project_source_root(), 'ls-files', '--deduplicate', '*.c', third_party_sources, check: true).stdout().split()
+  sources += source
+endforeach
+
+headers = [ ]
+foreach header : run_command(git, '-C', meson.project_source_root(), 'ls-files', '--deduplicate', '*.h', third_party_sources, check: true).stdout().split()
+  headers += meson.project_source_root() / header
+endforeach
+
+patches = [ ]
+foreach source : sources
+  patches += custom_target(
+    command: [
+      spatch,
+      '--all-includes',
+      '--sp-file', concatenated_rules,
+      '--patch', meson.project_source_root(),
+      '@INPUT@',
+    ],
+    input: meson.project_source_root() / source,
+    output: source.underscorify() + '.patch',
+    capture: true,
+    depend_files: headers,
+  )
+endforeach
+
+concatenated_patch = custom_target(
+  command: [
+    'cat', '@INPUT@',
+  ],
+  input: patches,
+  output: 'cocci.patch',
+  capture: true,
+)
+
+alias_target('coccicheck', concatenated_patch)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index b3b6aa3..413911b 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -2737,12 +2737,17 @@
 	__git_config_vars_all="$(git --no-pager help --config)"
 }
 
+__git_indirect()
+{
+	eval printf '%s' "\"\$$1\""
+}
+
 __git_compute_first_level_config_vars_for_section ()
 {
 	local section="$1"
 	__git_compute_config_vars
 	local this_section="__git_first_level_config_vars_for_section_${section}"
-	test -n "${!this_section}" ||
+	test -n "$(__git_indirect "${this_section}")" ||
 	printf -v "__git_first_level_config_vars_for_section_${section}" %s \
 		"$(echo "$__git_config_vars" | awk -F. "/^${section}\.[a-z]/ { print \$2 }")"
 }
@@ -2752,7 +2757,7 @@
 	local section="$1"
 	__git_compute_config_vars_all
 	local this_section="__git_second_level_config_vars_for_section_${section}"
-	test -n "${!this_section}" ||
+	test -n "$(__git_indirect "${this_section}")" ||
 	printf -v "__git_second_level_config_vars_for_section_${section}" %s \
 		"$(echo "$__git_config_vars_all" | awk -F. "/^${section}\.</ { print \$3 }")"
 }
@@ -2907,7 +2912,7 @@
 		local section="${pfx%.*.}"
 		__git_compute_second_level_config_vars_for_section "${section}"
 		local this_section="__git_second_level_config_vars_for_section_${section}"
-		__gitcomp "${!this_section}" "$pfx" "$cur_" "$sfx"
+		__gitcomp "$(__git_indirect "${this_section}")" "$pfx" "$cur_" "$sfx"
 		return
 		;;
 	branch.*)
@@ -2917,7 +2922,7 @@
 		__gitcomp_direct "$(__git_heads "$pfx" "$cur_" ".")"
 		__git_compute_first_level_config_vars_for_section "${section}"
 		local this_section="__git_first_level_config_vars_for_section_${section}"
-		__gitcomp_nl_append "${!this_section}" "$pfx" "$cur_" "${sfx:- }"
+		__gitcomp_nl_append "$(__git_indirect "${this_section}")" "$pfx" "$cur_" "${sfx:- }"
 		return
 		;;
 	pager.*)
@@ -2934,7 +2939,7 @@
 		__gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "."
 		__git_compute_first_level_config_vars_for_section "${section}"
 		local this_section="__git_first_level_config_vars_for_section_${section}"
-		__gitcomp_nl_append "${!this_section}" "$pfx" "$cur_" "${sfx:- }"
+		__gitcomp_nl_append "$(__git_indirect "${this_section}")" "$pfx" "$cur_" "${sfx:- }"
 		return
 		;;
 	submodule.*)
@@ -2944,7 +2949,7 @@
 		__gitcomp_nl "$(__git config -f "$(__git rev-parse --show-toplevel)/.gitmodules" --get-regexp 'submodule.*.path' | awk -F. '{print $2}')" "$pfx" "$cur_" "."
 		__git_compute_first_level_config_vars_for_section "${section}"
 		local this_section="__git_first_level_config_vars_for_section_${section}"
-		__gitcomp_nl_append "${!this_section}" "$pfx" "$cur_" "${sfx:- }"
+		__gitcomp_nl_append "$(__git_indirect "${this_section}")" "$pfx" "$cur_" "${sfx:- }"
 		return
 		;;
 	*.*)
diff --git a/contrib/contacts/Makefile b/contrib/contacts/Makefile
index a2990f0..9c4ca4f 100644
--- a/contrib/contacts/Makefile
+++ b/contrib/contacts/Makefile
@@ -34,7 +34,7 @@
 
 GIT_CONTACTS_DOC := git-contacts.1
 GIT_CONTACTS_XML := git-contacts.xml
-GIT_CONTACTS_TXT := git-contacts.txt
+GIT_CONTACTS_TXT := git-contacts.adoc
 GIT_CONTACTS_HTML := git-contacts.html
 
 doc: $(GIT_CONTACTS_DOC) $(GIT_CONTACTS_HTML)
diff --git a/contrib/contacts/git-contacts.txt b/contrib/contacts/git-contacts.adoc
similarity index 100%
rename from contrib/contacts/git-contacts.txt
rename to contrib/contacts/git-contacts.adoc
diff --git a/contrib/contacts/meson.build b/contrib/contacts/meson.build
new file mode 100644
index 0000000..73d82df
--- /dev/null
+++ b/contrib/contacts/meson.build
@@ -0,0 +1,55 @@
+custom_target(
+  input: 'git-contacts',
+  output: 'git-contacts',
+  command: generate_perl_command,
+  depends: [git_version_file],
+  install: true,
+  install_dir: get_option('libexecdir') / 'git-core',
+)
+
+if get_option('docs').contains('man')
+  contacts_xml = custom_target(
+    command: asciidoc_common_options + [
+      '--backend=' + asciidoc_docbook,
+      '--doctype=manpage',
+      '--out-file=@OUTPUT@',
+      '@INPUT@',
+    ],
+    depends: documentation_deps,
+    input: 'git-contacts.adoc',
+    output: 'git-contacts.xml',
+  )
+
+  custom_target(
+    command: [
+      xmlto,
+      '-m', '@INPUT@',
+      'man',
+      contacts_xml,
+      '-o',
+      meson.current_build_dir(),
+    ] + xmlto_extra,
+    input: [
+      '../../Documentation/manpage-normal.xsl',
+    ],
+    output: 'git-contacts.1',
+    install: true,
+    install_dir: get_option('mandir') / 'man1',
+  )
+endif
+
+if get_option('docs').contains('html')
+  custom_target(
+    command: asciidoc_common_options + [
+      '--backend=' + asciidoc_html,
+      '--doctype=manpage',
+      '--out-file=@OUTPUT@',
+      '@INPUT@',
+    ],
+    depends: documentation_deps,
+    input: 'git-contacts.adoc',
+    output: 'git-contacts.html',
+    install: true,
+    install_dir: get_option('datadir') / 'doc/git-doc',
+  )
+endif
diff --git a/contrib/credential/libsecret/Makefile b/contrib/credential/libsecret/Makefile
index 3e67552..97ce9c9 100644
--- a/contrib/credential/libsecret/Makefile
+++ b/contrib/credential/libsecret/Makefile
@@ -1,3 +1,6 @@
+# The default target of this Makefile is...
+all::
+
 MAIN:=git-credential-libsecret
 all:: $(MAIN)
 
diff --git a/contrib/credential/libsecret/git-credential-libsecret.c b/contrib/credential/libsecret/git-credential-libsecret.c
index 90034d0..941b2af 100644
--- a/contrib/credential/libsecret/git-credential-libsecret.c
+++ b/contrib/credential/libsecret/git-credential-libsecret.c
@@ -59,10 +59,10 @@ static void credential_clear(struct credential *c);
 /* ----------------- Secret Service functions ----------------- */
 
 static const SecretSchema schema = {
-	"org.git.Password",
+	.name = "org.git.Password",
 	/* Ignore schema name during search for backwards compatibility */
-	SECRET_SCHEMA_DONT_MATCH_NAME,
-	{
+	.flags = SECRET_SCHEMA_DONT_MATCH_NAME,
+	.attributes = {
 		/*
 		 * libsecret assumes attribute values are non-confidential and
 		 * unchanging, so we can't include oauth_refresh_token or
@@ -168,7 +168,7 @@ static int keyring_get(struct credential *c)
 				g_free(c->password);
 				c->password = g_strdup("");
 			}
-			for (int i = 1; i < g_strv_length(parts); i++) {
+			for (guint i = 1; i < g_strv_length(parts); i++) {
 				if (g_str_has_prefix(parts[i], "password_expiry_utc=")) {
 					g_free(c->password_expiry_utc);
 					c->password_expiry_utc = g_strdup(&parts[i][20]);
@@ -424,7 +424,7 @@ int main(int argc, char *argv[])
 	struct credential_operation const *try_op = credential_helper_ops;
 	struct credential cred = CREDENTIAL_INIT;
 
-	if (!argv[1]) {
+	if (argc < 2 || !*argv[1]) {
 		usage(argv[0]);
 		exit(EXIT_FAILURE);
 	}
diff --git a/contrib/credential/libsecret/meson.build b/contrib/credential/libsecret/meson.build
new file mode 100644
index 0000000..0137660
--- /dev/null
+++ b/contrib/credential/libsecret/meson.build
@@ -0,0 +1,9 @@
+executable('git-credential-libsecret',
+  sources: 'git-credential-libsecret.c',
+  dependencies: [
+    dependency('glib-2.0'),
+    dependency('libsecret-1'),
+  ],
+  install: true,
+  install_dir: get_option('libexecdir') / 'git-core',
+)
diff --git a/contrib/credential/meson.build b/contrib/credential/meson.build
new file mode 100644
index 0000000..4216296
--- /dev/null
+++ b/contrib/credential/meson.build
@@ -0,0 +1,3 @@
+foreach helper : get_option('credential_helpers')
+  subdir(helper)
+endforeach
diff --git a/contrib/credential/netrc/meson.build b/contrib/credential/netrc/meson.build
new file mode 100644
index 0000000..a990dbb
--- /dev/null
+++ b/contrib/credential/netrc/meson.build
@@ -0,0 +1,20 @@
+credential_netrc = custom_target(
+  input: 'git-credential-netrc.perl',
+  output: 'git-credential-netrc',
+  command: generate_perl_command,
+  depends: [git_version_file],
+  install: true,
+  install_dir: get_option('libexecdir') / 'git-core',
+)
+
+credential_netrc_testenv = test_environment
+credential_netrc_testenv.set('CREDENTIAL_NETRC_PATH', credential_netrc.full_path())
+
+test('t-git-credential-netrc',
+  shell,
+  args: [ meson.current_source_dir() / 't-git-credential-netrc.sh' ],
+  workdir: meson.current_source_dir(),
+  env: credential_netrc_testenv,
+  depends: test_dependencies + bin_wrappers + [credential_netrc],
+  timeout: 0,
+)
diff --git a/contrib/credential/netrc/t-git-credential-netrc.sh b/contrib/credential/netrc/t-git-credential-netrc.sh
index bf27773..1b7b8b3 100755
--- a/contrib/credential/netrc/t-git-credential-netrc.sh
+++ b/contrib/credential/netrc/t-git-credential-netrc.sh
@@ -15,7 +15,7 @@
 
 	export PERL5LIB="$GITPERLLIB"
 	test_expect_success 'git-credential-netrc' '
-		perl "$GIT_BUILD_DIR"/contrib/credential/netrc/test.pl
+		perl "$GIT_SOURCE_DIR"/contrib/credential/netrc/test.pl
 	'
 
 	test_done
diff --git a/contrib/credential/netrc/test.pl b/contrib/credential/netrc/test.pl
index c0fb371..67a0ede 100755
--- a/contrib/credential/netrc/test.pl
+++ b/contrib/credential/netrc/test.pl
@@ -15,10 +15,11 @@
 
 my @global_credential_args = @ARGV;
 my $scriptDir = dirname rel2abs $0;
-my ($netrc, $netrcGpg, $gcNetrc) = map { catfile $scriptDir, $_; }
+my ($netrc, $netrcGpg) = map { catfile $scriptDir, $_; }
                                        qw(test.netrc
-                                          test.netrc.gpg
-                                          git-credential-netrc);
+                                          test.netrc.gpg);
+my $gcNetrc = $ENV{CREDENTIAL_NETRC_PATH} || catfile $scriptDir, qw(git-credential-netrc);
+
 local $ENV{PATH} = join ':'
                       , $scriptDir
                       , $ENV{PATH}
diff --git a/contrib/credential/osxkeychain/Makefile b/contrib/credential/osxkeychain/Makefile
index 238f5f8..0948297 100644
--- a/contrib/credential/osxkeychain/Makefile
+++ b/contrib/credential/osxkeychain/Makefile
@@ -1,3 +1,4 @@
+# The default target of this Makefile is...
 all:: git-credential-osxkeychain
 
 CC = gcc
diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
index 1c8310d..611c979 100644
--- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c
+++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
@@ -422,7 +422,7 @@ int main(int argc, const char **argv)
 	const char *usage =
 		"usage: git credential-osxkeychain <get|store|erase>";
 
-	if (!argv[1])
+	if (argc < 2 || !*argv[1])
 		die("%s", usage);
 
 	if (open(argv[0], O_RDONLY | O_EXLOCK) == -1)
diff --git a/contrib/credential/osxkeychain/meson.build b/contrib/credential/osxkeychain/meson.build
new file mode 100644
index 0000000..3c7677f
--- /dev/null
+++ b/contrib/credential/osxkeychain/meson.build
@@ -0,0 +1,9 @@
+executable('git-credential-osxkeychain',
+  sources: 'git-credential-osxkeychain.c',
+  dependencies: [
+    dependency('CoreFoundation'),
+    dependency('Security'),
+  ],
+  install: true,
+  install_dir: get_option('libexecdir') / 'git-core',
+)
diff --git a/contrib/credential/wincred/Makefile b/contrib/credential/wincred/Makefile
index 6e992c0..5b795fc 100644
--- a/contrib/credential/wincred/Makefile
+++ b/contrib/credential/wincred/Makefile
@@ -1,4 +1,5 @@
-all: git-credential-wincred.exe
+# The default target of this Makefile is...
+all:: git-credential-wincred.exe
 
 -include ../../../config.mak.autogen
 -include ../../../config.mak
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index 3c16b74..5683846 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -12,7 +12,9 @@
 
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
 
+#ifndef _MSC_VER
 __attribute__((format (printf, 1, 2)))
+#endif
 static void die(const char *err, ...)
 {
 	char msg[4096];
diff --git a/contrib/credential/wincred/meson.build b/contrib/credential/wincred/meson.build
new file mode 100644
index 0000000..6de23ca
--- /dev/null
+++ b/contrib/credential/wincred/meson.build
@@ -0,0 +1,5 @@
+executable('git-credential-wincred',
+  sources: 'git-credential-wincred.c',
+  install: true,
+  install_dir: get_option('libexecdir') / 'git-core',
+)
diff --git a/contrib/diff-highlight/Makefile b/contrib/diff-highlight/Makefile
index f2be7cc..33c2ccc 100644
--- a/contrib/diff-highlight/Makefile
+++ b/contrib/diff-highlight/Makefile
@@ -1,4 +1,5 @@
-all: diff-highlight
+# The default target of this Makefile is...
+all:: diff-highlight
 
 PERL_PATH = /usr/bin/perl
 -include ../../config.mak
diff --git a/contrib/diff-highlight/t/Makefile b/contrib/diff-highlight/t/Makefile
index 5ff5275..2a98541 100644
--- a/contrib/diff-highlight/t/Makefile
+++ b/contrib/diff-highlight/t/Makefile
@@ -1,3 +1,6 @@
+# The default target of this Makefile is...
+all::
+
 -include ../../../config.mak.autogen
 -include ../../../config.mak
 
@@ -6,7 +9,7 @@
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
 T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
 
-all: test
+all:: test
 test: $(T)
 
 .PHONY: help clean all test $(T)
diff --git a/contrib/libgit-rs/Cargo.lock b/contrib/libgit-rs/Cargo.lock
new file mode 100644
index 0000000..a30c7c8
--- /dev/null
+++ b/contrib/libgit-rs/Cargo.lock
@@ -0,0 +1,77 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "cc"
+version = "1.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.158"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+
+[[package]]
+name = "libgit"
+version = "0.1.0"
+dependencies = [
+ "autocfg",
+ "libgit-sys",
+]
+
+[[package]]
+name = "libgit-sys"
+version = "0.1.0"
+dependencies = [
+ "autocfg",
+ "libz-sys",
+ "make-cmd",
+]
+
+[[package]]
+name = "libz-sys"
+version = "1.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "make-cmd"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8ca8afbe8af1785e09636acb5a41e08a765f5f0340568716c18a8700ba3c0d3"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
diff --git a/contrib/libgit-rs/Cargo.toml b/contrib/libgit-rs/Cargo.toml
new file mode 100644
index 0000000..c3289e6
--- /dev/null
+++ b/contrib/libgit-rs/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "libgit"
+version = "0.1.0"
+edition = "2021"
+build = "build.rs"
+rust-version = "1.63" # TODO: Once we hit 1.84 or newer, we may want to remove Cargo.lock from
+                      # version control. See https://lore.kernel.org/git/Z47jgK-oMjFRSslr@tapette.crustytoothpaste.net/
+
+
+[lib]
+path = "src/lib.rs"
+
+[dependencies]
+libgit-sys = { version = "0.1.0", path = "../libgit-sys" }
+
+[build-dependencies]
+autocfg = "1.4.0"
diff --git a/contrib/libgit-rs/README.md b/contrib/libgit-rs/README.md
new file mode 100644
index 0000000..ff945e1
--- /dev/null
+++ b/contrib/libgit-rs/README.md
@@ -0,0 +1,13 @@
+# libgit-rs
+
+Proof-of-concept Git bindings for Rust.
+
+```toml
+[dependencies]
+libgit = "0.1.0"
+```
+
+## Rust version requirements
+
+libgit-rs should support Rust versions at least as old as the version included
+in Debian stable (currently 1.63).
diff --git a/contrib/libgit-rs/build.rs b/contrib/libgit-rs/build.rs
new file mode 100644
index 0000000..f8bd01a
--- /dev/null
+++ b/contrib/libgit-rs/build.rs
@@ -0,0 +1,4 @@
+pub fn main() {
+    let ac = autocfg::new();
+    ac.emit_has_path("std::ffi::c_char");
+}
diff --git a/contrib/libgit-rs/src/config.rs b/contrib/libgit-rs/src/config.rs
new file mode 100644
index 0000000..6bf0484
--- /dev/null
+++ b/contrib/libgit-rs/src/config.rs
@@ -0,0 +1,106 @@
+use std::ffi::{c_void, CStr, CString};
+use std::path::Path;
+
+#[cfg(has_std__ffi__c_char)]
+use std::ffi::{c_char, c_int};
+
+#[cfg(not(has_std__ffi__c_char))]
+#[allow(non_camel_case_types)]
+type c_char = i8;
+
+#[cfg(not(has_std__ffi__c_char))]
+#[allow(non_camel_case_types)]
+type c_int = i32;
+
+use libgit_sys::*;
+
+/// A ConfigSet is an in-memory cache for config-like files such as `.gitmodules` or `.gitconfig`.
+/// It does not support all config directives; notably, it will not process `include` or
+/// `includeIf` directives (but it will store them so that callers can choose whether and how to
+/// handle them).
+pub struct ConfigSet(*mut libgit_config_set);
+impl ConfigSet {
+    /// Allocate a new ConfigSet
+    pub fn new() -> Self {
+        unsafe { ConfigSet(libgit_configset_alloc()) }
+    }
+
+    /// Load the given files into the ConfigSet; conflicting directives in later files will
+    /// override those given in earlier files.
+    pub fn add_files(&mut self, files: &[&Path]) {
+        for file in files {
+            let pstr = file.to_str().expect("Invalid UTF-8");
+            let rs = CString::new(pstr).expect("Couldn't convert to CString");
+            unsafe {
+                libgit_configset_add_file(self.0, rs.as_ptr());
+            }
+        }
+    }
+
+    /// Load the value for the given key and attempt to parse it as an i32. Dies with a fatal error
+    /// if the value cannot be parsed. Returns None if the key is not present.
+    pub fn get_int(&mut self, key: &str) -> Option<i32> {
+        let key = CString::new(key).expect("Couldn't convert to CString");
+        let mut val: c_int = 0;
+        unsafe {
+            if libgit_configset_get_int(self.0, key.as_ptr(), &mut val as *mut c_int) != 0 {
+                return None;
+            }
+        }
+
+        Some(val.into())
+    }
+
+    /// Clones the value for the given key. Dies with a fatal error if the value cannot be
+    /// converted to a String. Returns None if the key is not present.
+    pub fn get_string(&mut self, key: &str) -> Option<String> {
+        let key = CString::new(key).expect("Couldn't convert key to CString");
+        let mut val: *mut c_char = std::ptr::null_mut();
+        unsafe {
+            if libgit_configset_get_string(self.0, key.as_ptr(), &mut val as *mut *mut c_char) != 0
+            {
+                return None;
+            }
+            let borrowed_str = CStr::from_ptr(val);
+            let owned_str =
+                String::from(borrowed_str.to_str().expect("Couldn't convert val to str"));
+            free(val as *mut c_void); // Free the xstrdup()ed pointer from the C side
+            Some(owned_str)
+        }
+    }
+}
+
+impl Default for ConfigSet {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl Drop for ConfigSet {
+    fn drop(&mut self) {
+        unsafe {
+            libgit_configset_free(self.0);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn load_configs_via_configset() {
+        let mut cs = ConfigSet::new();
+        cs.add_files(&[
+            Path::new("testdata/config1"),
+            Path::new("testdata/config2"),
+            Path::new("testdata/config3"),
+        ]);
+        // ConfigSet retrieves correct value
+        assert_eq!(cs.get_int("trace2.eventTarget"), Some(1));
+        // ConfigSet respects last config value set
+        assert_eq!(cs.get_int("trace2.eventNesting"), Some(3));
+        // ConfigSet returns None for missing key
+        assert_eq!(cs.get_string("foo.bar"), None);
+    }
+}
diff --git a/contrib/libgit-rs/src/lib.rs b/contrib/libgit-rs/src/lib.rs
new file mode 100644
index 0000000..ef68c36
--- /dev/null
+++ b/contrib/libgit-rs/src/lib.rs
@@ -0,0 +1 @@
+pub mod config;
diff --git a/contrib/libgit-rs/testdata/config1 b/contrib/libgit-rs/testdata/config1
new file mode 100644
index 0000000..4e9a9d2
--- /dev/null
+++ b/contrib/libgit-rs/testdata/config1
@@ -0,0 +1,2 @@
+[trace2]
+	eventNesting = 1
diff --git a/contrib/libgit-rs/testdata/config2 b/contrib/libgit-rs/testdata/config2
new file mode 100644
index 0000000..b8d1eca
--- /dev/null
+++ b/contrib/libgit-rs/testdata/config2
@@ -0,0 +1,2 @@
+[trace2]
+	eventTarget = 1
diff --git a/contrib/libgit-rs/testdata/config3 b/contrib/libgit-rs/testdata/config3
new file mode 100644
index 0000000..ca7b9a7
--- /dev/null
+++ b/contrib/libgit-rs/testdata/config3
@@ -0,0 +1,2 @@
+[trace2]
+	eventNesting = 3
diff --git a/contrib/libgit-sys/Cargo.lock b/contrib/libgit-sys/Cargo.lock
new file mode 100644
index 0000000..427a4c6
--- /dev/null
+++ b/contrib/libgit-sys/Cargo.lock
@@ -0,0 +1,69 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "cc"
+version = "1.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.158"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+
+[[package]]
+name = "libgit-sys"
+version = "0.1.0"
+dependencies = [
+ "autocfg",
+ "libz-sys",
+ "make-cmd",
+]
+
+[[package]]
+name = "libz-sys"
+version = "1.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "make-cmd"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8ca8afbe8af1785e09636acb5a41e08a765f5f0340568716c18a8700ba3c0d3"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
diff --git a/contrib/libgit-sys/Cargo.toml b/contrib/libgit-sys/Cargo.toml
new file mode 100644
index 0000000..e062302
--- /dev/null
+++ b/contrib/libgit-sys/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "libgit-sys"
+version = "0.1.0"
+edition = "2021"
+build = "build.rs"
+links = "gitpub"
+rust-version = "1.63" # TODO: Once we hit 1.84 or newer, we may want to remove Cargo.lock from
+                      # version control. See https://lore.kernel.org/git/Z47jgK-oMjFRSslr@tapette.crustytoothpaste.net/
+description = "Native bindings to a portion of libgit"
+
+[lib]
+path = "src/lib.rs"
+
+[dependencies]
+libz-sys = "1.1.19"
+
+[build-dependencies]
+autocfg = "1.4.0"
+make-cmd = "0.1.0"
diff --git a/contrib/libgit-sys/README.md b/contrib/libgit-sys/README.md
new file mode 100644
index 0000000..c061cfc
--- /dev/null
+++ b/contrib/libgit-sys/README.md
@@ -0,0 +1,4 @@
+# libgit-sys
+
+A small proof-of-concept crate showing how to provide a Rust FFI to Git
+internals.
diff --git a/contrib/libgit-sys/build.rs b/contrib/libgit-sys/build.rs
new file mode 100644
index 0000000..3ffd80a
--- /dev/null
+++ b/contrib/libgit-sys/build.rs
@@ -0,0 +1,35 @@
+use std::env;
+use std::path::PathBuf;
+
+pub fn main() -> std::io::Result<()> {
+    let ac = autocfg::new();
+    ac.emit_has_path("std::ffi::c_char");
+
+    let crate_root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
+    let git_root = crate_root.join("../..");
+    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
+
+    let make_output = make_cmd::gnu_make()
+        .env("DEVELOPER", "1")
+        .env_remove("PROFILE")
+        .current_dir(git_root.clone())
+        .args([
+            "INCLUDE_LIBGIT_RS=YesPlease",
+            "contrib/libgit-sys/libgitpub.a",
+        ])
+        .output()
+        .expect("Make failed to run");
+    if !make_output.status.success() {
+        panic!(
+            "Make failed:\n  stdout = {}\n  stderr = {}\n",
+            String::from_utf8(make_output.stdout).unwrap(),
+            String::from_utf8(make_output.stderr).unwrap()
+        );
+    }
+    std::fs::copy(crate_root.join("libgitpub.a"), dst.join("libgitpub.a"))?;
+    println!("cargo:rustc-link-search=native={}", dst.display());
+    println!("cargo:rustc-link-lib=gitpub");
+    println!("cargo:rerun-if-changed={}", git_root.display());
+
+    Ok(())
+}
diff --git a/contrib/libgit-sys/public_symbol_export.c b/contrib/libgit-sys/public_symbol_export.c
new file mode 100644
index 0000000..dfbb257
--- /dev/null
+++ b/contrib/libgit-sys/public_symbol_export.c
@@ -0,0 +1,59 @@
+/*
+ * Shim to publicly export Git symbols. These must be renamed so that the
+ * original symbols can be hidden. Renaming these with a "libgit_" prefix also
+ * avoids conflicts with other libraries such as libgit2.
+ */
+
+#include "git-compat-util.h"
+#include "config.h"
+#include "contrib/libgit-sys/public_symbol_export.h"
+#include "version.h"
+
+#pragma GCC visibility push(default)
+
+struct libgit_config_set {
+	struct config_set cs;
+};
+
+struct libgit_config_set *libgit_configset_alloc(void)
+{
+	struct libgit_config_set *cs =
+			xmalloc(sizeof(struct libgit_config_set));
+	git_configset_init(&cs->cs);
+	return cs;
+}
+
+void libgit_configset_free(struct libgit_config_set *cs)
+{
+	git_configset_clear(&cs->cs);
+	free(cs);
+}
+
+int libgit_configset_add_file(struct libgit_config_set *cs, const char *filename)
+{
+	return git_configset_add_file(&cs->cs, filename);
+}
+
+int libgit_configset_get_int(struct libgit_config_set *cs, const char *key,
+			     int *dest)
+{
+	return git_configset_get_int(&cs->cs, key, dest);
+}
+
+int libgit_configset_get_string(struct libgit_config_set *cs, const char *key,
+				char **dest)
+{
+	return git_configset_get_string(&cs->cs, key, dest);
+}
+
+const char *libgit_user_agent(void)
+{
+	return git_user_agent();
+}
+
+const char *libgit_user_agent_sanitized(void)
+{
+	return git_user_agent_sanitized();
+}
+
+#pragma GCC visibility pop
diff --git a/contrib/libgit-sys/public_symbol_export.h b/contrib/libgit-sys/public_symbol_export.h
new file mode 100644
index 0000000..701db92
--- /dev/null
+++ b/contrib/libgit-sys/public_symbol_export.h
@@ -0,0 +1,18 @@
+#ifndef PUBLIC_SYMBOL_EXPORT_H
+#define PUBLIC_SYMBOL_EXPORT_H
+
+struct libgit_config_set *libgit_configset_alloc(void);
+
+void libgit_configset_free(struct libgit_config_set *cs);
+
+int libgit_configset_add_file(struct libgit_config_set *cs, const char *filename);
+
+int libgit_configset_get_int(struct libgit_config_set *cs, const char *key, int *dest);
+
+int libgit_configset_get_string(struct libgit_config_set *cs, const char *key, char **dest);
+
+const char *libgit_user_agent(void);
+
+const char *libgit_user_agent_sanitized(void);
+
+#endif /* PUBLIC_SYMBOL_EXPORT_H */
diff --git a/contrib/libgit-sys/src/lib.rs b/contrib/libgit-sys/src/lib.rs
new file mode 100644
index 0000000..4bfc650
--- /dev/null
+++ b/contrib/libgit-sys/src/lib.rs
@@ -0,0 +1,79 @@
+use std::ffi::c_void;
+
+#[cfg(has_std__ffi__c_char)]
+use std::ffi::{c_char, c_int};
+
+#[cfg(not(has_std__ffi__c_char))]
+#[allow(non_camel_case_types)]
+pub type c_char = i8;
+
+#[cfg(not(has_std__ffi__c_char))]
+#[allow(non_camel_case_types)]
+pub type c_int = i32;
+
+extern crate libz_sys;
+
+#[allow(non_camel_case_types)]
+#[repr(C)]
+pub struct libgit_config_set {
+    _data: [u8; 0],
+    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
+}
+
+extern "C" {
+    pub fn free(ptr: *mut c_void);
+
+    pub fn libgit_user_agent() -> *const c_char;
+    pub fn libgit_user_agent_sanitized() -> *const c_char;
+
+    pub fn libgit_configset_alloc() -> *mut libgit_config_set;
+    pub fn libgit_configset_free(cs: *mut libgit_config_set);
+
+    pub fn libgit_configset_add_file(cs: *mut libgit_config_set, filename: *const c_char) -> c_int;
+
+    pub fn libgit_configset_get_int(
+        cs: *mut libgit_config_set,
+        key: *const c_char,
+        int: *mut c_int,
+    ) -> c_int;
+
+    pub fn libgit_configset_get_string(
+        cs: *mut libgit_config_set,
+        key: *const c_char,
+        dest: *mut *mut c_char,
+    ) -> c_int;
+
+}
+
+#[cfg(test)]
+mod tests {
+    use std::ffi::CStr;
+
+    use super::*;
+
+    #[test]
+    fn user_agent_starts_with_git() {
+        let c_str = unsafe { CStr::from_ptr(libgit_user_agent()) };
+        let agent = c_str
+            .to_str()
+            .expect("User agent contains invalid UTF-8 data");
+        assert!(
+            agent.starts_with("git/"),
+            r#"Expected user agent to start with "git/", got: {}"#,
+            agent
+        );
+    }
+
+    #[test]
+    fn sanitized_user_agent_starts_with_git() {
+        let c_str = unsafe { CStr::from_ptr(libgit_user_agent_sanitized()) };
+        let agent = c_str
+            .to_str()
+            .expect("Sanitized user agent contains invalid UTF-8 data");
+        assert!(
+            agent.starts_with("git/"),
+            r#"Expected user agent to start with "git/", got: {}"#,
+            agent
+        );
+    }
+}
diff --git a/contrib/long-running-filter/example.pl b/contrib/long-running-filter/example.pl
index a677569..4b83e4c 100755
--- a/contrib/long-running-filter/example.pl
+++ b/contrib/long-running-filter/example.pl
@@ -1,7 +1,7 @@
 #!/usr/bin/perl
 #
 # Example implementation for the Git filter protocol version 2
-# See Documentation/gitattributes.txt, section "Filter Protocol"
+# See Documentation/gitattributes.adoc, section "Filter Protocol"
 #
 # Please note, this pass-thru filter is a minimal skeleton. No proper
 # error handling was implemented.
diff --git a/contrib/meson.build b/contrib/meson.build
index a7b77b8..a88c5df 100644
--- a/contrib/meson.build
+++ b/contrib/meson.build
@@ -1 +1,6 @@
-subdir('completion')
+foreach feature : get_option('contrib')
+  subdir(feature)
+endforeach
+
+subdir('coccinelle')
+subdir('credential')
diff --git a/contrib/mw-to-git/Makefile b/contrib/mw-to-git/Makefile
index 4e60351..497ac43 100644
--- a/contrib/mw-to-git/Makefile
+++ b/contrib/mw-to-git/Makefile
@@ -12,6 +12,9 @@
 #
 #   make install
 
+# The default target of this Makefile is...
+all::
+
 GIT_MEDIAWIKI_PM=Git/Mediawiki.pm
 SCRIPT_PERL=git-remote-mediawiki.perl
 SCRIPT_PERL+=git-mw.perl
@@ -27,7 +30,7 @@
 DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 INSTLIBDIR_SQ = $(subst ','\'',$(INSTLIBDIR))
 
-all: build
+all:: build
 
 test: all
 	$(MAKE) -C t
diff --git a/contrib/mw-to-git/t/Makefile b/contrib/mw-to-git/t/Makefile
index f422203..6c9f377 100644
--- a/contrib/mw-to-git/t/Makefile
+++ b/contrib/mw-to-git/t/Makefile
@@ -8,7 +8,8 @@
 #
 ## Test git-remote-mediawiki
 
-all: test
+# The default target of this Makefile is...
+all:: test
 
 -include ../../../config.mak.autogen
 -include ../../../config.mak
diff --git a/contrib/persistent-https/Makefile b/contrib/persistent-https/Makefile
index 52b84ba..691737e 100644
--- a/contrib/persistent-https/Makefile
+++ b/contrib/persistent-https/Makefile
@@ -12,10 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# The default target of this Makefile is...
+all::
+
 BUILD_LABEL=$(shell cut -d" " -f3 ../../GIT-VERSION-FILE)
 TAR_OUT=$(shell go env GOOS)_$(shell go env GOARCH).tar.gz
 
-all: git-remote-persistent-https git-remote-persistent-https--proxy \
+all:: git-remote-persistent-https git-remote-persistent-https--proxy \
 	git-remote-persistent-http
 
 git-remote-persistent-https--proxy: git-remote-persistent-https
diff --git a/contrib/subtree/.gitignore b/contrib/subtree/.gitignore
index 0b9381a..6deaf17 100644
--- a/contrib/subtree/.gitignore
+++ b/contrib/subtree/.gitignore
@@ -1,4 +1,6 @@
 *~
+asciidoc.conf
+asciidoctor-extensions.rb
 git-subtree
 git-subtree.1
 git-subtree.html
diff --git a/contrib/subtree/Makefile b/contrib/subtree/Makefile
index 6fa7496..c0c9f21 100644
--- a/contrib/subtree/Makefile
+++ b/contrib/subtree/Makefile
@@ -1,6 +1,7 @@
 # The default target of this Makefile is...
 all::
 
+-include ../../shared.mak
 -include ../../config.mak.autogen
 -include ../../config.mak
 
@@ -13,17 +14,16 @@
 ../../GIT-VERSION-FILE: FORCE
 	$(MAKE) -C ../../ GIT-VERSION-FILE
 
--include ../../GIT-VERSION-FILE
-
 # this should be set to a 'standard' bsd-type install program
 INSTALL  ?= install
 RM       ?= rm -f
 
 ASCIIDOC         = asciidoc
-ASCIIDOC_CONF    = -f ../../Documentation/asciidoc.conf
+ASCIIDOC_CONF    = -f asciidoc.conf
 ASCIIDOC_HTML    = xhtml11
 ASCIIDOC_DOCBOOK = docbook
 ASCIIDOC_EXTRA   =
+ASCIIDOC_DEPS    = asciidoc.conf
 XMLTO            = xmlto
 XMLTO_EXTRA      =
 
@@ -32,8 +32,9 @@
 ASCIIDOC_CONF    =
 ASCIIDOC_HTML    = xhtml5
 ASCIIDOC_DOCBOOK = docbook
-ASCIIDOC_EXTRA  += -I../../Documentation -rasciidoctor-extensions
+ASCIIDOC_EXTRA  += -I. -rasciidoctor-extensions
 ASCIIDOC_EXTRA  += -alitdd='&\#x2d;&\#x2d;'
+ASCIIDOC_DEPS    = asciidoctor-extensions.rb
 XMLTO_EXTRA     += --skip-validation
 endif
 
@@ -49,7 +50,7 @@
 
 GIT_SUBTREE_DOC := git-subtree.1
 GIT_SUBTREE_XML := git-subtree.xml
-GIT_SUBTREE_TXT := git-subtree.txt
+GIT_SUBTREE_TXT := git-subtree.adoc
 GIT_SUBTREE_HTML := git-subtree.html
 GIT_SUBTREE_TEST := ../../git-subtree
 
@@ -82,13 +83,13 @@
 $(GIT_SUBTREE_DOC): $(GIT_SUBTREE_XML)
 	$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $^
 
-$(GIT_SUBTREE_XML): $(GIT_SUBTREE_TXT)
+$(GIT_SUBTREE_XML): $(GIT_SUBTREE_TXT) $(ASCIIDOC_DEPS)
 	$(ASCIIDOC) -b $(ASCIIDOC_DOCBOOK) -d manpage $(ASCIIDOC_CONF) \
-		-agit_version=$(GIT_VERSION) $(ASCIIDOC_EXTRA) $^
+		$(ASCIIDOC_EXTRA) $<
 
-$(GIT_SUBTREE_HTML): $(GIT_SUBTREE_TXT)
+$(GIT_SUBTREE_HTML): $(GIT_SUBTREE_TXT) $(ASCIIDOC_DEPS)
 	$(ASCIIDOC) -b $(ASCIIDOC_HTML) -d manpage $(ASCIIDOC_CONF) \
-		-agit_version=$(GIT_VERSION) $(ASCIIDOC_EXTRA) $^
+		$(ASCIIDOC_EXTRA) $<
 
 $(GIT_SUBTREE_TEST): $(GIT_SUBTREE)
 	cp $< $@
@@ -98,6 +99,12 @@
 
 clean:
 	$(RM) $(GIT_SUBTREE)
+	$(RM) asciidoc.conf asciidoctor-extensions.rb
 	$(RM) *.xml *.html *.1
 
+asciidoc.conf: ../../Documentation/asciidoc.conf.in ../../GIT-VERSION-FILE
+	$(QUIET_GEN)$(call version_gen,"$(shell pwd)/../..",$<,$@)
+asciidoctor-extensions.rb: ../../Documentation/asciidoctor-extensions.rb.in ../../GIT-VERSION-FILE
+	$(QUIET_GEN)$(call version_gen,"$(shell pwd)/../..",$<,$@)
+
 .PHONY: FORCE
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.adoc
similarity index 100%
rename from contrib/subtree/git-subtree.txt
rename to contrib/subtree/git-subtree.adoc
diff --git a/contrib/subtree/meson.build b/contrib/subtree/meson.build
new file mode 100644
index 0000000..9c72b23
--- /dev/null
+++ b/contrib/subtree/meson.build
@@ -0,0 +1,71 @@
+git_subtree = custom_target(
+  input: 'git-subtree.sh',
+  output: 'git-subtree',
+  command: [
+    shell,
+    meson.project_source_root() / 'generate-script.sh',
+    '@INPUT@',
+    '@OUTPUT@',
+    meson.project_build_root() / 'GIT-BUILD-OPTIONS',
+  ],
+  install: true,
+  install_dir: get_option('libexecdir') / 'git-core',
+)
+
+subtree_test_environment = test_environment
+subtree_test_environment.prepend('PATH', meson.current_build_dir())
+
+test('t7900-subtree', shell,
+  args: [ 't7900-subtree.sh' ],
+  env: subtree_test_environment,
+  workdir: meson.current_source_dir() / 't',
+  depends: test_dependencies + bin_wrappers + [ git_subtree ],
+  timeout: 0,
+)
+
+if get_option('docs').contains('man')
+  subtree_xml = custom_target(
+    command: asciidoc_common_options + [
+      '--backend=' + asciidoc_docbook,
+      '--doctype=manpage',
+      '--out-file=@OUTPUT@',
+      '@INPUT@',
+    ],
+    depends: documentation_deps,
+    input: 'git-subtree.adoc',
+    output: 'git-subtree.xml',
+  )
+
+  custom_target(
+    command: [
+      xmlto,
+      '-m', '@INPUT@',
+      'man',
+      subtree_xml,
+      '-o',
+      meson.current_build_dir(),
+    ] + xmlto_extra,
+    input: [
+      '../../Documentation/manpage-normal.xsl',
+    ],
+    output: 'git-subtree.1',
+    install: true,
+    install_dir: get_option('mandir') / 'man1',
+  )
+endif
+
+if get_option('docs').contains('html')
+  custom_target(
+    command: asciidoc_common_options + [
+      '--backend=' + asciidoc_html,
+      '--doctype=manpage',
+      '--out-file=@OUTPUT@',
+      '@INPUT@',
+    ],
+    depends: documentation_deps,
+    input: 'git-subtree.adoc',
+    output: 'git-subtree.html',
+    install: true,
+    install_dir: get_option('datadir') / 'doc/git-doc',
+  )
+endif
diff --git a/contrib/subtree/t/Makefile b/contrib/subtree/t/Makefile
index 093399c..2a85f5e 100644
--- a/contrib/subtree/t/Makefile
+++ b/contrib/subtree/t/Makefile
@@ -3,6 +3,9 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
+# The default target of this Makefile is...
+all::
+
 -include ../../../config.mak.autogen
 -include ../../../config.mak
 
@@ -31,7 +34,7 @@
 TGITWEB = $(sort $(wildcard t95[0-9][0-9]-*.sh))
 THELPERS = $(sort $(filter-out $(T),$(wildcard *.sh)))
 
-all: $(DEFAULT_TEST_TARGET)
+all:: $(DEFAULT_TEST_TARGET)
 
 test: pre-clean $(TEST_LINT)
 	$(MAKE) aggregate-results-and-cleanup
diff --git a/contrib/thunderbird-patch-inline/appp.sh b/contrib/thunderbird-patch-inline/appp.sh
index 1053872..fdcc948 100755
--- a/contrib/thunderbird-patch-inline/appp.sh
+++ b/contrib/thunderbird-patch-inline/appp.sh
@@ -31,7 +31,7 @@
 CMT_MSG=$(sed -e '1,/^$/d' -e '/^---$/,$d' "${PATCH}")
 DIFF=$(sed -e '1,/^---$/d' "${PATCH}")
 
-CCS=$(echo -e "$CMT_MSG\n$HEADERS" | sed -n -e 's/^Cc: \(.*\)$/\1,/gp' \
+CCS=$(printf '%s\n%s\n' "$CMT_MSG" "$HEADERS" | sed -n -e 's/^Cc: \(.*\)$/\1,/gp' \
 	-e 's/^Signed-off-by: \(.*\)/\1,/gp')
 
 echo "$SUBJECT" > $1
diff --git a/copy.c b/copy.c
index d9d2092..b668209 100644
--- a/copy.c
+++ b/copy.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "copy.h"
 #include "path.h"
@@ -57,7 +59,7 @@ int copy_file(const char *dst, const char *src, int mode)
 	if (close(fdo) != 0)
 		return error_errno("%s: close error", dst);
 
-	if (!status && adjust_shared_perm(dst))
+	if (!status && adjust_shared_perm(the_repository, dst))
 		return -1;
 
 	return status;
diff --git a/credential.c b/credential.c
index 6e6e81c..2594c0c 100644
--- a/credential.c
+++ b/credential.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -170,7 +169,7 @@ static int match_partial_url(const char *url, void *cb)
 	return matches;
 }
 
-static void credential_apply_config(struct credential *c)
+static void credential_apply_config(struct repository *r, struct credential *c)
 {
 	char *normalized_url;
 	struct urlmatch_config config = URLMATCH_CONFIG_INIT;
@@ -195,7 +194,7 @@ static void credential_apply_config(struct credential *c)
 	credential_format(c, &url);
 	normalized_url = url_normalize(url.buf, &config.url);
 
-	git_config(urlmatch_config_entry, &config);
+	repo_config(r, urlmatch_config_entry, &config);
 	string_list_clear(&config.vars, 1);
 	free(normalized_url);
 	urlmatch_config_release(&config);
@@ -262,34 +261,34 @@ static char *credential_ask_one(const char *what, struct credential *c,
 	return xstrdup(r);
 }
 
-static int credential_getpass(struct credential *c)
+static int credential_getpass(struct repository *r, struct credential *c)
 {
 	int interactive;
 	char *value;
-	if (!git_config_get_maybe_bool("credential.interactive", &interactive) &&
+	if (!repo_config_get_maybe_bool(r, "credential.interactive", &interactive) &&
 	    !interactive) {
-		trace2_data_intmax("credential", the_repository,
+		trace2_data_intmax("credential", r,
 				   "interactive/skipped", 1);
 		return -1;
 	}
-	if (!git_config_get_string("credential.interactive", &value)) {
+	if (!repo_config_get_string(r, "credential.interactive", &value)) {
 		int same = !strcmp(value, "never");
 		free(value);
 		if (same) {
-			trace2_data_intmax("credential", the_repository,
+			trace2_data_intmax("credential", r,
 					   "interactive/skipped", 1);
 			return -1;
 		}
 	}
 
-	trace2_region_enter("credential", "interactive", the_repository);
+	trace2_region_enter("credential", "interactive", r);
 	if (!c->username)
 		c->username = credential_ask_one("Username", c,
 						 PROMPT_ASKPASS|PROMPT_ECHO);
 	if (!c->password)
 		c->password = credential_ask_one("Password", c,
 						 PROMPT_ASKPASS);
-	trace2_region_leave("credential", "interactive", the_repository);
+	trace2_region_leave("credential", "interactive", r);
 
 	return 0;
 }
@@ -502,7 +501,8 @@ static int credential_do(struct credential *c, const char *helper,
 	return r;
 }
 
-void credential_fill(struct credential *c, int all_capabilities)
+void credential_fill(struct repository *r,
+		     struct credential *c, int all_capabilities)
 {
 	int i;
 
@@ -512,7 +512,7 @@ void credential_fill(struct credential *c, int all_capabilities)
 	credential_next_state(c);
 	c->multistage = 0;
 
-	credential_apply_config(c);
+	credential_apply_config(r, c);
 	if (all_capabilities)
 		credential_set_all_capabilities(c, CREDENTIAL_OP_INITIAL);
 
@@ -539,12 +539,12 @@ void credential_fill(struct credential *c, int all_capabilities)
 			    c->helpers.items[i].string);
 	}
 
-	if (credential_getpass(c) ||
+	if (credential_getpass(r, c) ||
 	    (!c->username && !c->password && !c->credential))
 		die("unable to get password from user");
 }
 
-void credential_approve(struct credential *c)
+void credential_approve(struct repository *r, struct credential *c)
 {
 	int i;
 
@@ -555,20 +555,20 @@ void credential_approve(struct credential *c)
 
 	credential_next_state(c);
 
-	credential_apply_config(c);
+	credential_apply_config(r, c);
 
 	for (i = 0; i < c->helpers.nr; i++)
 		credential_do(c, c->helpers.items[i].string, "store");
 	c->approved = 1;
 }
 
-void credential_reject(struct credential *c)
+void credential_reject(struct repository *r, struct credential *c)
 {
 	int i;
 
 	credential_next_state(c);
 
-	credential_apply_config(c);
+	credential_apply_config(r, c);
 
 	for (i = 0; i < c->helpers.nr; i++)
 		credential_do(c, c->helpers.items[i].string, "erase");
diff --git a/credential.h b/credential.h
index 63fef3e..c78b72d 100644
--- a/credential.h
+++ b/credential.h
@@ -4,6 +4,8 @@
 #include "string-list.h"
 #include "strvec.h"
 
+struct repository;
+
 /**
  * The credentials API provides an abstracted way of gathering
  * authentication credentials from the user.
@@ -65,7 +67,7 @@
  * // Fill in the username and password fields by contacting
  * // helpers and/or asking the user. The function will die if it
  * // fails.
- * credential_fill(&c);
+ * credential_fill(repo, &c);
  *
  * // Otherwise, we have a username and password. Try to use it.
  *
@@ -222,7 +224,8 @@ void credential_clear(struct credential *);
  * If all_capabilities is set, this is an internal user that is prepared
  * to deal with all known capabilities, and we should advertise that fact.
  */
-void credential_fill(struct credential *, int all_capabilities);
+void credential_fill(struct repository *, struct credential *,
+		     int all_capabilities);
 
 /**
  * Inform the credential subsystem that the provided credentials
@@ -231,7 +234,7 @@ void credential_fill(struct credential *, int all_capabilities);
  * that they may store the result to be used again.  Any errors
  * from helpers are ignored.
  */
-void credential_approve(struct credential *);
+void credential_approve(struct repository *, struct credential *);
 
 /**
  * Inform the credential subsystem that the provided credentials
@@ -243,7 +246,7 @@ void credential_approve(struct credential *);
  * for another call to `credential_fill`). Any errors from helpers
  * are ignored.
  */
-void credential_reject(struct credential *);
+void credential_reject(struct repository *, struct credential *);
 
 /**
  * Enable all of the supported credential flags in this credential.
diff --git a/csum-file.c b/csum-file.c
index 5716016..b58c183 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -11,9 +11,10 @@
 #define USE_THE_REPOSITORY_VARIABLE
 
 #include "git-compat-util.h"
-#include "progress.h"
 #include "csum-file.h"
+#include "git-zlib.h"
 #include "hash.h"
+#include "progress.h"
 
 static void verify_buffer_or_die(struct hashfile *f,
 				 const void *buf,
@@ -50,7 +51,7 @@ void hashflush(struct hashfile *f)
 
 	if (offset) {
 		if (!f->skip_hash)
-			the_hash_algo->unsafe_update_fn(&f->ctx, f->buffer, offset);
+			git_hash_update(&f->ctx, f->buffer, offset);
 		flush(f, f->buffer, offset);
 		f->offset = 0;
 	}
@@ -71,14 +72,14 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result,
 	hashflush(f);
 
 	if (f->skip_hash)
-		hashclr(f->buffer, the_repository->hash_algo);
+		hashclr(f->buffer, f->algop);
 	else
-		the_hash_algo->unsafe_final_fn(f->buffer, &f->ctx);
+		git_hash_final(f->buffer, &f->ctx);
 
 	if (result)
-		hashcpy(result, f->buffer, the_repository->hash_algo);
+		hashcpy(result, f->buffer, f->algop);
 	if (flags & CSUM_HASH_IN_STREAM)
-		flush(f, f->buffer, the_hash_algo->rawsz);
+		flush(f, f->buffer, f->algop->rawsz);
 	if (flags & CSUM_FSYNC)
 		fsync_component_or_die(component, f->fd, f->name);
 	if (flags & CSUM_CLOSE) {
@@ -128,7 +129,7 @@ void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
 			 * f->offset is necessarily zero.
 			 */
 			if (!f->skip_hash)
-				the_hash_algo->unsafe_update_fn(&f->ctx, buf, nr);
+				git_hash_update(&f->ctx, buf, nr);
 			flush(f, buf, nr);
 		} else {
 			/*
@@ -174,7 +175,9 @@ static struct hashfile *hashfd_internal(int fd, const char *name,
 	f->name = name;
 	f->do_crc = 0;
 	f->skip_hash = 0;
-	the_hash_algo->unsafe_init_fn(&f->ctx);
+
+	f->algop = unsafe_hash_algo(the_hash_algo);
+	f->algop->init_fn(&f->ctx);
 
 	f->buffer_len = buffer_len;
 	f->buffer = xmalloc(buffer_len);
@@ -204,11 +207,18 @@ struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp
 	return hashfd_internal(fd, name, tp, 8 * 1024);
 }
 
+void hashfile_checkpoint_init(struct hashfile *f,
+			      struct hashfile_checkpoint *checkpoint)
+{
+	memset(checkpoint, 0, sizeof(*checkpoint));
+	f->algop->init_fn(&checkpoint->ctx);
+}
+
 void hashfile_checkpoint(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
 {
 	hashflush(f);
 	checkpoint->offset = f->total;
-	the_hash_algo->unsafe_clone_fn(&checkpoint->ctx, &f->ctx);
+	git_hash_clone(&checkpoint->ctx, &f->ctx);
 }
 
 int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
@@ -219,7 +229,7 @@ int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint
 	    lseek(f->fd, offset, SEEK_SET) != offset)
 		return -1;
 	f->total = offset;
-	the_hash_algo->unsafe_clone_fn(&f->ctx, &checkpoint->ctx);
+	git_hash_clone(&f->ctx, &checkpoint->ctx);
 	f->offset = 0; /* hashflush() was called in checkpoint */
 	return 0;
 }
@@ -239,15 +249,16 @@ uint32_t crc32_end(struct hashfile *f)
 int hashfile_checksum_valid(const unsigned char *data, size_t total_len)
 {
 	unsigned char got[GIT_MAX_RAWSZ];
-	git_hash_ctx ctx;
-	size_t data_len = total_len - the_hash_algo->rawsz;
+	struct git_hash_ctx ctx;
+	const struct git_hash_algo *algop = unsafe_hash_algo(the_hash_algo);
+	size_t data_len = total_len - algop->rawsz;
 
-	if (total_len < the_hash_algo->rawsz)
+	if (total_len < algop->rawsz)
 		return 0; /* say "too short"? */
 
-	the_hash_algo->unsafe_init_fn(&ctx);
-	the_hash_algo->unsafe_update_fn(&ctx, data, data_len);
-	the_hash_algo->unsafe_final_fn(got, &ctx);
+	algop->init_fn(&ctx);
+	git_hash_update(&ctx, data, data_len);
+	git_hash_final(got, &ctx);
 
-	return hasheq(got, data + data_len, the_repository->hash_algo);
+	return hasheq(got, data + data_len, algop);
 }
diff --git a/csum-file.h b/csum-file.h
index 7c73da0..ffccbf0 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -11,7 +11,7 @@ struct hashfile {
 	int fd;
 	int check_fd;
 	unsigned int offset;
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 	off_t total;
 	struct progress *tp;
 	const char *name;
@@ -20,6 +20,7 @@ struct hashfile {
 	size_t buffer_len;
 	unsigned char *buffer;
 	unsigned char *check_buffer;
+	const struct git_hash_algo *algop;
 
 	/**
 	 * If non-zero, skip_hash indicates that we should
@@ -32,9 +33,10 @@ struct hashfile {
 /* Checkpoint */
 struct hashfile_checkpoint {
 	off_t offset;
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 };
 
+void hashfile_checkpoint_init(struct hashfile *, struct hashfile_checkpoint *);
 void hashfile_checkpoint(struct hashfile *, struct hashfile_checkpoint *);
 int hashfile_truncate(struct hashfile *, struct hashfile_checkpoint *);
 
diff --git a/date.c b/date.c
index a1b26a8..17a9507 100644
--- a/date.c
+++ b/date.c
@@ -1244,7 +1244,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
 	}
 
 	for (s = special; s->name; s++) {
-		int len = strlen(s->name);
+		size_t len = strlen(s->name);
 		if (match_string(date, s->name) == len) {
 			s->fn(tm, now, num);
 			*touched = 1;
@@ -1254,7 +1254,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
 
 	if (!*num) {
 		for (i = 1; i < 11; i++) {
-			int len = strlen(number_name[i]);
+			size_t len = strlen(number_name[i]);
 			if (match_string(date, number_name[i]) == len) {
 				*num = i;
 				*touched = 1;
@@ -1270,7 +1270,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
 
 	tl = typelen;
 	while (tl->type) {
-		int len = strlen(tl->type);
+		size_t len = strlen(tl->type);
 		if (match_string(date, tl->type) >= len-1) {
 			update_tm(tm, now, tl->length * *num);
 			*num = 0;
diff --git a/delta-islands.c b/delta-islands.c
index 1c465a6..3aec43f 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -267,7 +267,8 @@ void resolve_tree_islands(struct repository *r,
 	QSORT(todo, nr, tree_depth_compare);
 
 	if (progress)
-		progress_state = start_progress(_("Propagating island marks"), nr);
+		progress_state = start_progress(the_repository,
+						_("Propagating island marks"), nr);
 
 	for (i = 0; i < nr; i++) {
 		struct object_entry *ent = todo[i].entry;
diff --git a/diagnose.c b/diagnose.c
index b11931d..bd485ef 100644
--- a/diagnose.c
+++ b/diagnose.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "diagnose.h"
 #include "compat/disk.h"
@@ -12,6 +10,7 @@
 #include "object-store-ll.h"
 #include "packfile.h"
 #include "parse-options.h"
+#include "repository.h"
 #include "write-or-die.h"
 
 struct archive_dir {
@@ -179,7 +178,9 @@ static int add_directory_to_archiver(struct strvec *archiver_args,
 	return res;
 }
 
-int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode)
+int create_diagnostics_archive(struct repository *r,
+			       struct strbuf *zip_path,
+			       enum diagnose_mode mode)
 {
 	struct strvec archiver_args = STRVEC_INIT;
 	char **argv_copy = NULL;
@@ -218,7 +219,7 @@ int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode)
 	strbuf_addstr(&buf, "Collecting diagnostic info\n\n");
 	get_version_info(&buf, 1);
 
-	strbuf_addf(&buf, "Repository root: %s\n", the_repository->worktree);
+	strbuf_addf(&buf, "Repository root: %s\n", r->worktree);
 	get_disk_info(&buf);
 	write_or_die(stdout_fd, buf.buf, buf.len);
 	strvec_pushf(&archiver_args,
@@ -227,7 +228,7 @@ int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode)
 
 	strbuf_reset(&buf);
 	strbuf_addstr(&buf, "--add-virtual-file=packs-local.txt:");
-	dir_file_stats(the_repository->objects->odb, &buf);
+	dir_file_stats(r->objects->odb, &buf);
 	foreach_alt_odb(dir_file_stats, &buf);
 	strvec_push(&archiver_args, buf.buf);
 
@@ -250,13 +251,13 @@ int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode)
 	}
 
 	strvec_pushl(&archiver_args, "--prefix=",
-		     oid_to_hex(the_hash_algo->empty_tree), "--", NULL);
+		     oid_to_hex(r->hash_algo->empty_tree), "--", NULL);
 
 	/* `write_archive()` modifies the `argv` passed to it. Let it. */
 	argv_copy = xmemdupz(archiver_args.v,
 			     sizeof(char *) * archiver_args.nr);
 	res = write_archive(archiver_args.nr, (const char **)argv_copy, NULL,
-			    the_repository, NULL, 0);
+			    r, NULL, 0);
 	if (res) {
 		error(_("failed to write archive"));
 		goto diagnose_cleanup;
diff --git a/diagnose.h b/diagnose.h
index f525219..f7b38f4 100644
--- a/diagnose.h
+++ b/diagnose.h
@@ -4,6 +4,7 @@
 #include "strbuf.h"
 
 struct option;
+struct repository;
 
 enum diagnose_mode {
 	DIAGNOSE_NONE,
@@ -13,6 +14,8 @@ enum diagnose_mode {
 
 int option_parse_diagnose(const struct option *opt, const char *arg, int unset);
 
-int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode);
+int create_diagnostics_archive(struct repository *r,
+			       struct strbuf *zip_path,
+			       enum diagnose_mode mode);
 
 #endif /* DIAGNOSE_H */
diff --git a/diff-lib.c b/diff-lib.c
index c6d3bc4..353b473 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -153,21 +153,8 @@ void run_diff_files(struct rev_info *revs, unsigned int option)
 			struct diff_filepair *pair;
 			unsigned int wt_mode = 0;
 			int num_compare_stages = 0;
-			size_t path_len;
 			struct stat st;
 
-			path_len = ce_namelen(ce);
-
-			dpath = xmalloc(combine_diff_path_size(5, path_len));
-			dpath->path = (char *) &(dpath->parent[5]);
-
-			dpath->next = NULL;
-			memcpy(dpath->path, ce->name, path_len);
-			dpath->path[path_len] = '\0';
-			oidclr(&dpath->oid, the_repository->hash_algo);
-			memset(&(dpath->parent[0]), 0,
-			       sizeof(struct combine_diff_parent)*5);
-
 			changed = check_removed(ce, &st);
 			if (!changed)
 				wt_mode = ce_mode_from_stat(ce, st.st_mode);
@@ -178,7 +165,14 @@ void run_diff_files(struct rev_info *revs, unsigned int option)
 				}
 				wt_mode = 0;
 			}
-			dpath->mode = wt_mode;
+
+			/*
+			 * Allocate space for two parents, which will come from
+			 * index stages #2 and #3, if present. Below we'll fill
+			 * these from (stage - 2).
+			 */
+			dpath = combine_diff_path_new(ce->name, ce_namelen(ce),
+						      wt_mode, null_oid(), 2);
 
 			while (i < entries) {
 				struct cache_entry *nce = istate->cache[i];
@@ -405,16 +399,10 @@ static int show_modified(struct rev_info *revs,
 	if (revs->combine_merges && !cached &&
 	    (!oideq(oid, &old_entry->oid) || !oideq(&old_entry->oid, &new_entry->oid))) {
 		struct combine_diff_path *p;
-		int pathlen = ce_namelen(new_entry);
 
-		p = xmalloc(combine_diff_path_size(2, pathlen));
-		p->path = (char *) &p->parent[2];
-		p->next = NULL;
-		memcpy(p->path, new_entry->name, pathlen);
-		p->path[pathlen] = 0;
-		p->mode = mode;
-		oidclr(&p->oid, the_repository->hash_algo);
-		memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
+		p = combine_diff_path_new(new_entry->name,
+					  ce_namelen(new_entry),
+					  mode, null_oid(), 2);
 		p->parent[0].status = DIFF_STATUS_MODIFIED;
 		p->parent[0].mode = new_entry->ce_mode;
 		oidcpy(&p->parent[0].oid, &new_entry->oid);
diff --git a/diff.c b/diff.c
index d28b411..c89c15d 100644
--- a/diff.c
+++ b/diff.c
@@ -5493,6 +5493,8 @@ static int diff_opt_pickaxe_regex(const struct option *opt,
 	BUG_ON_OPT_NEG(unset);
 	options->pickaxe = arg;
 	options->pickaxe_opts |= DIFF_PICKAXE_KIND_G;
+	if (arg && !*arg)
+		return error(_("-G requires a non-empty argument"));
 	return 0;
 }
 
@@ -5504,6 +5506,8 @@ static int diff_opt_pickaxe_string(const struct option *opt,
 	BUG_ON_OPT_NEG(unset);
 	options->pickaxe = arg;
 	options->pickaxe_opts |= DIFF_PICKAXE_KIND_S;
+	if (arg && !*arg)
+		return error(_("-S requires a non-empty argument"));
 	return 0;
 }
 
@@ -6392,7 +6396,7 @@ static void diff_summary(struct diff_options *opt, struct diff_filepair *p)
 }
 
 struct patch_id_t {
-	git_hash_ctx *ctx;
+	struct git_hash_ctx *ctx;
 	int patchlen;
 };
 
@@ -6409,13 +6413,13 @@ static int remove_space(char *line, int len)
 	return dst - line;
 }
 
-void flush_one_hunk(struct object_id *result, git_hash_ctx *ctx)
+void flush_one_hunk(struct object_id *result, struct git_hash_ctx *ctx)
 {
 	unsigned char hash[GIT_MAX_RAWSZ];
 	unsigned short carry = 0;
 	int i;
 
-	the_hash_algo->final_fn(hash, ctx);
+	git_hash_final(hash, ctx);
 	the_hash_algo->init_fn(ctx);
 	/* 20-byte sum, with carry */
 	for (i = 0; i < the_hash_algo->rawsz; ++i) {
@@ -6434,22 +6438,22 @@ static int patch_id_consume(void *priv, char *line, unsigned long len)
 		return 0;
 	new_len = remove_space(line, len);
 
-	the_hash_algo->update_fn(data->ctx, line, new_len);
+	git_hash_update(data->ctx, line, new_len);
 	data->patchlen += new_len;
 	return 0;
 }
 
-static void patch_id_add_string(git_hash_ctx *ctx, const char *str)
+static void patch_id_add_string(struct git_hash_ctx *ctx, const char *str)
 {
-	the_hash_algo->update_fn(ctx, str, strlen(str));
+	git_hash_update(ctx, str, strlen(str));
 }
 
-static void patch_id_add_mode(git_hash_ctx *ctx, unsigned mode)
+static void patch_id_add_mode(struct git_hash_ctx *ctx, unsigned mode)
 {
 	/* large enough for 2^32 in octal */
 	char buf[12];
 	int len = xsnprintf(buf, sizeof(buf), "%06o", mode);
-	the_hash_algo->update_fn(ctx, buf, len);
+	git_hash_update(ctx, buf, len);
 }
 
 /* returns 0 upon success, and writes result into oid */
@@ -6457,7 +6461,7 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid
 {
 	struct diff_queue_struct *q = &diff_queued_diff;
 	int i;
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 	struct patch_id_t data;
 
 	the_hash_algo->init_fn(&ctx);
@@ -6493,9 +6497,9 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid
 		len2 = remove_space(p->two->path, strlen(p->two->path));
 		patch_id_add_string(&ctx, "diff--git");
 		patch_id_add_string(&ctx, "a/");
-		the_hash_algo->update_fn(&ctx, p->one->path, len1);
+		git_hash_update(&ctx, p->one->path, len1);
 		patch_id_add_string(&ctx, "b/");
-		the_hash_algo->update_fn(&ctx, p->two->path, len2);
+		git_hash_update(&ctx, p->two->path, len2);
 
 		if (p->one->mode == 0) {
 			patch_id_add_string(&ctx, "newfilemode");
@@ -6514,24 +6518,24 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid
 			/* don't do anything since we're only populating header info */
 		} else if (diff_filespec_is_binary(options->repo, p->one) ||
 		    diff_filespec_is_binary(options->repo, p->two)) {
-			the_hash_algo->update_fn(&ctx, oid_to_hex(&p->one->oid),
+			git_hash_update(&ctx, oid_to_hex(&p->one->oid),
 					the_hash_algo->hexsz);
-			the_hash_algo->update_fn(&ctx, oid_to_hex(&p->two->oid),
+			git_hash_update(&ctx, oid_to_hex(&p->two->oid),
 					the_hash_algo->hexsz);
 		} else {
 			if (p->one->mode == 0) {
 				patch_id_add_string(&ctx, "---/dev/null");
 				patch_id_add_string(&ctx, "+++b/");
-				the_hash_algo->update_fn(&ctx, p->two->path, len2);
+				git_hash_update(&ctx, p->two->path, len2);
 			} else if (p->two->mode == 0) {
 				patch_id_add_string(&ctx, "---a/");
-				the_hash_algo->update_fn(&ctx, p->one->path, len1);
+				git_hash_update(&ctx, p->one->path, len1);
 				patch_id_add_string(&ctx, "+++/dev/null");
 			} else {
 				patch_id_add_string(&ctx, "---a/");
-				the_hash_algo->update_fn(&ctx, p->one->path, len1);
+				git_hash_update(&ctx, p->one->path, len1);
 				patch_id_add_string(&ctx, "+++b/");
-				the_hash_algo->update_fn(&ctx, p->two->path, len2);
+				git_hash_update(&ctx, p->two->path, len2);
 			}
 
 			if (fill_mmfile(options->repo, &mf1, p->one) < 0 ||
@@ -7386,6 +7390,6 @@ void setup_diff_pager(struct diff_options *opt)
 	 * --exit-code" in hooks and other scripts, we do not do so.
 	 */
 	if (!opt->flags.exit_with_status &&
-	    check_pager_config("diff") != 0)
-		setup_pager();
+	    check_pager_config(the_repository, "diff") != 0)
+		setup_pager(the_repository);
 }
diff --git a/diff.h b/diff.h
index 6e6007c..ff0348e 100644
--- a/diff.h
+++ b/diff.h
@@ -333,7 +333,7 @@ struct diff_options {
 	int xdl_opts;
 	int ignore_driver_algorithm;
 
-	/* see Documentation/diff-options.txt */
+	/* see Documentation/diff-options.adoc */
 	char **anchors;
 	size_t anchors_nr, anchors_alloc;
 
@@ -462,7 +462,7 @@ const char *diff_line_prefix(struct diff_options *);
 extern const char mime_boundary_leader[];
 
 struct combine_diff_path *diff_tree_paths(
-	struct combine_diff_path *p, const struct object_id *oid,
+	const struct object_id *oid,
 	const struct object_id **parents_oid, int nparent,
 	struct strbuf *base, struct diff_options *opt);
 void diff_tree_oid(const struct object_id *old_oid,
@@ -480,12 +480,20 @@ struct combine_diff_path {
 		char status;
 		unsigned int mode;
 		struct object_id oid;
-		struct strbuf path;
+		/*
+		 * This per-parent path is filled only when doing a combined
+		 * diff with revs.combined_all_paths set, and only if the path
+		 * differs from the post-image (e.g., a rename or copy).
+		 * Otherwise it is left NULL.
+		 */
+		char *path;
 	} parent[FLEX_ARRAY];
 };
-#define combine_diff_path_size(n, l) \
-	st_add4(sizeof(struct combine_diff_path), (l), 1, \
-		st_mult(sizeof(struct combine_diff_parent), (n)))
+struct combine_diff_path *combine_diff_path_new(const char *path,
+						size_t path_len,
+						unsigned int mode,
+						const struct object_id *oid,
+						size_t num_parents);
 
 void show_combined_diff(struct combine_diff_path *elem, int num_parent,
 			struct rev_info *);
@@ -644,7 +652,7 @@ void run_diff_index(struct rev_info *revs, unsigned int option);
 
 int do_diff_cache(const struct object_id *, struct diff_options *);
 int diff_flush_patch_id(struct diff_options *, struct object_id *, int);
-void flush_one_hunk(struct object_id *result, git_hash_ctx *ctx);
+void flush_one_hunk(struct object_id *result, struct git_hash_ctx *ctx);
 
 int diff_result_code(struct rev_info *);
 
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 10bb032..91b7799 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -1567,6 +1567,7 @@ void diffcore_rename_extended(struct diff_options *options,
 	trace2_region_enter("diff", "inexact renames", options->repo);
 	if (options->show_rename_progress) {
 		progress = start_delayed_progress(
+				the_repository,
 				_("Performing inexact rename detection"),
 				(uint64_t)num_destinations * (uint64_t)num_sources);
 	}
diff --git a/diffcore.h b/diffcore.h
index 2feb325..9c0a0e7 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -107,7 +107,7 @@ struct diff_filepair {
 	struct diff_filespec *one;
 	struct diff_filespec *two;
 	unsigned short int score;
-	char status; /* M C R A D U etc. (see Documentation/diff-format.txt or DIFF_STATUS_* in diff.h) */
+	char status; /* M C R A D U etc. (see Documentation/diff-format.adoc or DIFF_STATUS_* in diff.h) */
 	unsigned broken_pair : 1;
 	unsigned renamed_pair : 1;
 	unsigned is_unmerged : 1;
diff --git a/dir.c b/dir.c
index 5b2181e..cbd82be 100644
--- a/dir.c
+++ b/dir.c
@@ -1093,10 +1093,6 @@ static void invalidate_directory(struct untracked_cache *uc,
 		dir->dirs[i]->recurse = 0;
 }
 
-static int add_patterns_from_buffer(char *buf, size_t size,
-				    const char *base, int baselen,
-				    struct pattern_list *pl);
-
 /* Flags for add_patterns() */
 #define PATTERN_NOFOLLOW (1<<0)
 
@@ -1186,9 +1182,9 @@ static int add_patterns(const char *fname, const char *base, int baselen,
 	return 0;
 }
 
-static int add_patterns_from_buffer(char *buf, size_t size,
-				    const char *base, int baselen,
-				    struct pattern_list *pl)
+int add_patterns_from_buffer(char *buf, size_t size,
+			     const char *base, int baselen,
+			     struct pattern_list *pl)
 {
 	char *orig = buf;
 	int i, lineno = 1;
@@ -3455,7 +3451,7 @@ void setup_standard_excludes(struct dir_struct *dir)
 
 char *get_sparse_checkout_filename(void)
 {
-	return git_pathdup("info/sparse-checkout");
+	return repo_git_path(the_repository, "info/sparse-checkout");
 }
 
 int get_sparse_checkout_patterns(struct pattern_list *pl)
diff --git a/dir.h b/dir.h
index a3a2f00..6cfef5d 100644
--- a/dir.h
+++ b/dir.h
@@ -467,6 +467,9 @@ void add_patterns_from_file(struct dir_struct *, const char *fname);
 int add_patterns_from_blob_to_list(struct object_id *oid,
 				   const char *base, int baselen,
 				   struct pattern_list *pl);
+int add_patterns_from_buffer(char *buf, size_t size,
+			     const char *base, int baselen,
+			     struct pattern_list *pl);
 void parse_path_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen);
 void add_pattern(const char *string, const char *base,
 		 int baselen, struct pattern_list *pl, int srcpos);
diff --git a/editor.c b/editor.c
index 6b9ce81..b79d97b 100644
--- a/editor.c
+++ b/editor.c
@@ -142,10 +142,8 @@ int strbuf_edit_interactively(struct repository *r,
 	struct strbuf sb = STRBUF_INIT;
 	int fd, res = 0;
 
-	if (!is_absolute_path(path)) {
-		strbuf_repo_git_path(&sb, r, "%s", path);
-		path = sb.buf;
-	}
+	if (!is_absolute_path(path))
+		path = repo_git_path_append(r, &sb, "%s", path);
 
 	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
 	if (fd < 0)
diff --git a/entry.c b/entry.c
index 53a1c39..81b321e 100644
--- a/entry.c
+++ b/entry.c
@@ -188,7 +188,9 @@ int finish_delayed_checkout(struct checkout *state, int show_progress)
 
 	dco->state = CE_RETRY;
 	if (show_progress)
-		progress = start_delayed_progress(_("Filtering content"), dco->paths.nr);
+		progress = start_delayed_progress(the_repository,
+						  _("Filtering content"),
+						  dco->paths.nr);
 	while (dco->filters.nr > 0) {
 		for_each_string_list_item(filter, &dco->filters) {
 			struct string_list available_paths = STRING_LIST_INIT_DUP;
diff --git a/environment.c b/environment.c
index 8389a27..9e4c778 100644
--- a/environment.c
+++ b/environment.c
@@ -16,6 +16,7 @@
 #include "convert.h"
 #include "environment.h"
 #include "gettext.h"
+#include "git-zlib.h"
 #include "repository.h"
 #include "config.h"
 #include "refs.h"
@@ -42,7 +43,6 @@ char *git_log_output_encoding;
 char *apply_default_whitespace;
 char *apply_default_ignorewhitespace;
 char *git_attributes_file;
-char *git_hooks_path;
 int zlib_compression_level = Z_BEST_SPEED;
 int pack_compression_level = Z_DEFAULT_COMPRESSION;
 int fsync_object_files = -1;
@@ -207,32 +207,6 @@ const char *get_commit_output_encoding(void)
 	return git_commit_encoding ? git_commit_encoding : "UTF-8";
 }
 
-static int the_shared_repository = PERM_UMASK;
-static int need_shared_repository_from_config = 1;
-
-void set_shared_repository(int value)
-{
-	the_shared_repository = value;
-	need_shared_repository_from_config = 0;
-}
-
-int get_shared_repository(void)
-{
-	if (need_shared_repository_from_config) {
-		const char *var = "core.sharedrepository";
-		const char *value;
-		if (!git_config_get_value(var, &value))
-			the_shared_repository = git_config_perm(var, value);
-		need_shared_repository_from_config = 0;
-	}
-	return the_shared_repository;
-}
-
-void reset_shared_repository(void)
-{
-	need_shared_repository_from_config = 1;
-}
-
 int use_optional_locks(void)
 {
 	return git_env_bool(GIT_OPTIONAL_LOCKS_ENVIRONMENT, 1);
diff --git a/environment.h b/environment.h
index 2f43340..45e690f 100644
--- a/environment.h
+++ b/environment.h
@@ -134,16 +134,6 @@ void setup_git_env(const char *git_dir);
  */
 int have_git_dir(void);
 
-/*
- * Accessors for the core.sharedrepository config which lazy-load the value
- * from the config (if not already set). The "reset" function can be
- * used to unset "set" or cached value, meaning that the value will be loaded
- * fresh from the config file on the next call to get_shared_repository().
- */
-void set_shared_repository(int value);
-int get_shared_repository(void);
-void reset_shared_repository(void);
-
 extern int is_bare_repository_cfg;
 int is_bare_repository(void);
 extern char *git_work_tree_cfg;
@@ -160,7 +150,6 @@ extern int warn_on_object_refname_ambiguity;
 extern char *apply_default_whitespace;
 extern char *apply_default_ignorewhitespace;
 extern char *git_attributes_file;
-extern char *git_hooks_path;
 extern int zlib_compression_level;
 extern int pack_compression_level;
 extern size_t packed_git_window_size;
diff --git a/fetch-pack.c b/fetch-pack.c
index 3a22772..1ed5e11 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -1036,7 +1036,9 @@ static int get_pack(struct fetch_pack_args *args,
 		die(_("fetch-pack: unable to fork off %s"), cmd_name);
 	if (do_keep && (pack_lockfiles || fsck_objects)) {
 		int is_well_formed;
-		char *pack_lockfile = index_pack_lockfile(cmd.out, &is_well_formed);
+		char *pack_lockfile = index_pack_lockfile(the_repository,
+							  cmd.out,
+							  &is_well_formed);
 
 		if (!is_well_formed)
 			die(_("fetch-pack: invalid index-pack output"));
@@ -1867,7 +1869,7 @@ int fetch_pack_fsck_config(const char *var, const char *value,
 		char *path ;
 
 		if (git_config_pathname(&path, var, value))
-			return 0;
+			return -1;
 		strbuf_addf(msg_types, "%cskiplist=%s",
 			msg_types->len ? ',' : '=', path);
 		free(path);
diff --git a/fsck.c b/fsck.c
index 87ce999..9fc4c25 100644
--- a/fsck.c
+++ b/fsck.c
@@ -1353,7 +1353,7 @@ int git_fsck_config(const char *var, const char *value,
 		struct strbuf sb = STRBUF_INIT;
 
 		if (git_config_pathname(&path, var, value))
-			return 1;
+			return -1;
 		strbuf_addf(&sb, "skiplist=%s", path);
 		free(path);
 		fsck_set_msg_types(options, sb.buf);
diff --git a/fsck.h b/fsck.h
index a44c231..a95ae7e 100644
--- a/fsck.h
+++ b/fsck.h
@@ -15,7 +15,7 @@ enum fsck_msg_type {
 };
 
 /*
- * Documentation/fsck-msgids.txt documents these; when
+ * Documentation/fsck-msgids.adoc documents these; when
  * modifying this list in any way, make sure to keep the
  * two in sync.
  */
diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh
index b923a5a..0ed39c4 100755
--- a/generate-cmdlist.sh
+++ b/generate-cmdlist.sh
@@ -76,7 +76,7 @@
 				break
 				;;
 			esac
-		done <"$1/Documentation/$cmd.txt"
+		done <"$1/Documentation/$cmd.adoc"
 
 		printf '\t{ "%s", N_("%s"), 0' "$cmd" "$synopsis"
 		printf " | CAT_%s" $rest
diff --git a/generate-configlist.sh b/generate-configlist.sh
index 5794226..dffdaad 100755
--- a/generate-configlist.sh
+++ b/generate-configlist.sh
@@ -13,7 +13,7 @@
 	cat <<EOF
 static const char *config_name_list[] = {
 EOF
-	grep -h '^[a-zA-Z].*\..*::$' "$SOURCE_DIR"/Documentation/*config.txt "$SOURCE_DIR"/Documentation/config/*.txt |
+	grep -h '^[a-zA-Z].*\..*::$' "$SOURCE_DIR"/Documentation/*config.adoc "$SOURCE_DIR"/Documentation/config/*.adoc |
 	sed '/deprecated/d; s/::$//; s/,  */\n/g' |
 	sort |
 	sed 's/^.*$/	"&",/'
diff --git a/generate-hooklist.sh b/generate-hooklist.sh
index e22068c..e0cdf26 100755
--- a/generate-hooklist.sh
+++ b/generate-hooklist.sh
@@ -22,7 +22,7 @@
 sed -n \
 	-e '/^~~~~*$/ {x; s/^.*$/	"&",/; p;}' \
 	-e 'x' \
-	<"$SOURCE_DIR"/Documentation/githooks.txt |
+	<"$SOURCE_DIR"/Documentation/githooks.adoc |
 	LC_ALL=C sort
 
 cat <<EOF
diff --git a/git-compat-util.h b/git-compat-util.h
index e283c46..e123288 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -701,6 +701,8 @@ int error_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
 void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
 void warning_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
 
+void show_usage_if_asked(int ac, const char **av, const char *err);
+
 #ifndef NO_OPENSSL
 #ifdef APPLE_COMMON_CRYPTO
 #include "compat/apple-common-crypto.h"
@@ -1537,18 +1539,6 @@ int cmd_main(int, const char **);
 int common_exit(const char *file, int line, int code);
 #define exit(code) exit(common_exit(__FILE__, __LINE__, (code)))
 
-#define z_const
-#include <zlib.h>
-
-#if ZLIB_VERNUM < 0x1290
-/*
- * This is uncompress2, which is only available in zlib >= 1.2.9
- * (released as of early 2017). See compat/zlib-uncompress2.c.
- */
-int uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source,
-		uLong *sourceLen);
-#endif
-
 /*
  * This include must come after system headers, since it introduces macros that
  * replace system names.
diff --git a/git-gui/Makefile b/git-gui/Makefile
index 667c39e..6c5a12b 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -1,3 +1,4 @@
+# The default target of this Makefile is...
 all::
 
 # Define V=1 to have a more verbose compile.
diff --git a/git-gui/po/glossary/Makefile b/git-gui/po/glossary/Makefile
index 749aa2e..e656b0d 100644
--- a/git-gui/po/glossary/Makefile
+++ b/git-gui/po/glossary/Makefile
@@ -1,3 +1,6 @@
+# The default target of this Makefile is...
+update-po::
+
 PO_TEMPLATE = git-gui-glossary.pot
 
 ALL_POFILES = $(wildcard *.po)
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 5ad5016..7b44f70 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -694,9 +694,9 @@
 		return result
 
 
-bind = "127.0.0.1"
+bind = "0.0.0.0"
 if "$local" == "true":
-	bind = "0.0.0.0"
+	bind = "127.0.0.1"
 
 # Set our http root directory
 # This is a work around for a missing directory argument in older Python versions
diff --git a/git-submodule.sh b/git-submodule.sh
index 03c5a22..2999b31 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -40,11 +40,11 @@
 require_init=
 files=
 remote=
-nofetch=
+no_fetch=
 rebase=
 merge=
 checkout=
-custom_name=
+name=
 depth=
 progress=
 dissociate=
@@ -52,11 +52,10 @@
 jobs=
 recommend_shallow=
 filter=
-
-isnumber()
-{
-	n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
-}
+all=
+default=
+summary_limit=
+for_status=
 
 #
 # Add a new submodule to the working tree, .gitmodules and the index
@@ -68,31 +67,33 @@
 cmd_add()
 {
 	# parse $args after "submodule ... add".
-	reference_path=
 	while test $# -ne 0
 	do
 		case "$1" in
 		-b | --branch)
 			case "$2" in '') usage ;; esac
-			branch=$2
+			branch="--branch=$2"
 			shift
 			;;
+		-b* | --branch=*)
+			branch="$1"
+			;;
 		-f | --force)
 			force=$1
 			;;
 		-q|--quiet)
-			quiet=1
+			quiet=$1
 			;;
 		--progress)
-			progress=1
+			progress=$1
 			;;
 		--reference)
 			case "$2" in '') usage ;; esac
-			reference_path=$2
+			reference="--reference=$2"
 			shift
 			;;
 		--reference=*)
-			reference_path="${1#--reference=}"
+			reference="$1"
 			;;
 		--ref-format)
 			case "$2" in '') usage ;; esac
@@ -103,20 +104,23 @@
 			ref_format="$1"
 			;;
 		--dissociate)
-			dissociate=1
+			dissociate=$1
 			;;
 		--name)
 			case "$2" in '') usage ;; esac
-			custom_name=$2
+			name="--name=$2"
 			shift
 			;;
+		--name=*)
+			name="$1"
+			;;
 		--depth)
 			case "$2" in '') usage ;; esac
 			depth="--depth=$2"
 			shift
 			;;
 		--depth=*)
-			depth=$1
+			depth="$1"
 			;;
 		--)
 			shift
@@ -138,14 +142,14 @@
 	fi
 
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add \
-		${quiet:+--quiet} \
-		${force:+--force} \
-		${progress:+"--progress"} \
-		${branch:+--branch "$branch"} \
-		${reference_path:+--reference "$reference_path"} \
+		$quiet \
+		$force \
+		$progress \
+		${branch:+"$branch"} \
+		${reference:+"$reference"} \
 		${ref_format:+"$ref_format"} \
-		${dissociate:+--dissociate} \
-		${custom_name:+--name "$custom_name"} \
+		$dissociate \
+		${name:+"$name"} \
 		${depth:+"$depth"} \
 		-- \
 		"$@"
@@ -164,10 +168,10 @@
 	do
 		case "$1" in
 		-q|--quiet)
-			quiet=1
+			quiet=$1
 			;;
 		--recursive)
-			recursive=1
+			recursive=$1
 			;;
 		-*)
 			usage
@@ -180,8 +184,8 @@
 	done
 
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach \
-		${quiet:+--quiet} \
-		${recursive:+--recursive} \
+		$quiet \
+		$recursive \
 		-- \
 		"$@"
 }
@@ -198,7 +202,7 @@
 	do
 		case "$1" in
 		-q|--quiet)
-			quiet=1
+			quiet=$1
 			;;
 		--)
 			shift
@@ -215,7 +219,7 @@
 	done
 
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init \
-		${quiet:+--quiet} \
+		$quiet \
 		-- \
 		"$@"
 }
@@ -226,7 +230,6 @@
 cmd_deinit()
 {
 	# parse $args after "submodule ... deinit".
-	deinit_all=
 	while test $# -ne 0
 	do
 		case "$1" in
@@ -234,10 +237,10 @@
 			force=$1
 			;;
 		-q|--quiet)
-			quiet=1
+			quiet=$1
 			;;
 		--all)
-			deinit_all=t
+			all=$1
 			;;
 		--)
 			shift
@@ -254,9 +257,9 @@
 	done
 
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \
-		${quiet:+--quiet} \
-		${force:+--force} \
-		${deinit_all:+--all} \
+		$quiet \
+		$force \
+		$all \
 		-- \
 		"$@"
 }
@@ -273,31 +276,31 @@
 	do
 		case "$1" in
 		-q|--quiet)
-			quiet=1
+			quiet=$1
 			;;
 		-v|--verbose)
-			quiet=0
+			quiet=
 			;;
 		--progress)
-			progress=1
+			progress=$1
 			;;
 		-i|--init)
-			init=1
+			init=$1
 			;;
 		--require-init)
-			require_init=1
+			require_init=$1
 			;;
 		--remote)
-			remote=1
+			remote=$1
 			;;
 		-N|--no-fetch)
-			nofetch=1
+			no_fetch=$1
 			;;
 		-f|--force)
 			force=$1
 			;;
 		-r|--rebase)
-			rebase=1
+			rebase=$1
 			;;
 		--ref-format)
 			case "$2" in '') usage ;; esac
@@ -316,22 +319,19 @@
 			reference="$1"
 			;;
 		--dissociate)
-			dissociate=1
+			dissociate=$1
 			;;
 		-m|--merge)
-			merge=1
+			merge=$1
 			;;
 		--recursive)
-			recursive=1
+			recursive=$1
 			;;
 		--checkout)
-			checkout=1
+			checkout=$1
 			;;
-		--recommend-shallow)
-			recommend_shallow="--recommend-shallow"
-			;;
-		--no-recommend-shallow)
-			recommend_shallow="--no-recommend-shallow"
+		--recommend-shallow|--no-recommend-shallow)
+			recommend_shallow=$1
 			;;
 		--depth)
 			case "$2" in '') usage ;; esac
@@ -339,21 +339,18 @@
 			shift
 			;;
 		--depth=*)
-			depth=$1
+			depth="$1"
 			;;
 		-j|--jobs)
 			case "$2" in '') usage ;; esac
 			jobs="--jobs=$2"
 			shift
 			;;
-		--jobs=*)
-			jobs=$1
+		-j*|--jobs=*)
+			jobs="$1"
 			;;
-		--single-branch)
-			single_branch="--single-branch"
-			;;
-		--no-single-branch)
-			single_branch="--no-single-branch"
+		--single-branch|--no-single-branch)
+			single_branch=$1
 			;;
 		--filter)
 			case "$2" in '') usage ;; esac
@@ -378,22 +375,21 @@
 	done
 
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update \
-		${quiet:+--quiet} \
-		${force:+--force} \
-		${progress:+"--progress"} \
-		${remote:+--remote} \
-		${recursive:+--recursive} \
-		${init:+--init} \
-		${nofetch:+--no-fetch} \
-		${rebase:+--rebase} \
-		${merge:+--merge} \
-		${checkout:+--checkout} \
+		$quiet \
+		$force \
+		$progress \
+		$remote \
+		$recursive \
+		$init \
+		$no_fetch \
+		$rebase \
+		$merge \
+		$checkout \
 		${ref_format:+"$ref_format"} \
 		${reference:+"$reference"} \
-		${dissociate:+"--dissociate"} \
+		$dissociate \
 		${depth:+"$depth"} \
-		${require_init:+--require-init} \
-		${dissociate:+"--dissociate"} \
+		$require_init \
 		$single_branch \
 		$recommend_shallow \
 		$jobs \
@@ -408,9 +404,7 @@
 # $@ = requested path
 #
 cmd_set_branch() {
-	default=
-	branch=
-
+	# parse $args after "submodule ... set-branch".
 	while test $# -ne 0
 	do
 		case "$1" in
@@ -418,13 +412,16 @@
 			# we don't do anything with this but we need to accept it
 			;;
 		-d|--default)
-			default=1
+			default=$1
 			;;
 		-b|--branch)
 			case "$2" in '') usage ;; esac
-			branch=$2
+			branch="--branch=$2"
 			shift
 			;;
+		-b*|--branch=*)
+			branch="$1"
+			;;
 		--)
 			shift
 			break
@@ -440,9 +437,9 @@
 	done
 
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch \
-		${quiet:+--quiet} \
-		${branch:+--branch "$branch"} \
-		${default:+--default} \
+		$quiet \
+		${branch:+"$branch"} \
+		$default \
 		-- \
 		"$@"
 }
@@ -453,11 +450,12 @@
 # $@ = requested path, requested url
 #
 cmd_set_url() {
+	# parse $args after "submodule ... set-url".
 	while test $# -ne 0
 	do
 		case "$1" in
 		-q|--quiet)
-			quiet=1
+			quiet=$1
 			;;
 		--)
 			shift
@@ -474,7 +472,7 @@
 	done
 
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url \
-		${quiet:+--quiet} \
+		$quiet \
 		-- \
 		"$@"
 }
@@ -488,31 +486,26 @@
 # $@ = [commit (default 'HEAD'),] requested paths (default all)
 #
 cmd_summary() {
-	summary_limit=-1
-	for_status=
-	diff_cmd=diff-index
-
 	# parse $args after "submodule ... summary".
 	while test $# -ne 0
 	do
 		case "$1" in
 		--cached)
-			cached=1
+			cached=$1
 			;;
 		--files)
-			files="$1"
+			files=$1
 			;;
 		--for-status)
-			for_status="$1"
+			for_status=$1
 			;;
 		-n|--summary-limit)
-			summary_limit="$2"
-			isnumber "$summary_limit" || usage
+			case "$2" in '') usage ;; esac
+			summary_limit="--summary-limit=$2"
 			shift
 			;;
-		--summary-limit=*)
-			summary_limit="${1#--summary-limit=}"
-			isnumber "$summary_limit" || usage
+		-n*|--summary-limit=*)
+			summary_limit="$1"
 			;;
 		--)
 			shift
@@ -529,10 +522,10 @@
 	done
 
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary \
-		${files:+--files} \
-		${cached:+--cached} \
-		${for_status:+--for-status} \
-		${summary_limit:+-n $summary_limit} \
+		$files \
+		$cached \
+		$for_status \
+		${summary_limit:+"$summary_limit"} \
 		-- \
 		"$@"
 }
@@ -553,13 +546,13 @@
 	do
 		case "$1" in
 		-q|--quiet)
-			quiet=1
+			quiet=$1
 			;;
 		--cached)
-			cached=1
+			cached=$1
 			;;
 		--recursive)
-			recursive=1
+			recursive=$1
 			;;
 		--)
 			shift
@@ -576,9 +569,9 @@
 	done
 
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status \
-		${quiet:+--quiet} \
-		${cached:+--cached} \
-		${recursive:+--recursive} \
+		$quiet \
+		$cached \
+		$recursive \
 		-- \
 		"$@"
 }
@@ -590,15 +583,16 @@
 #
 cmd_sync()
 {
+	# parse $args after "submodule ... sync".
 	while test $# -ne 0
 	do
 		case "$1" in
 		-q|--quiet)
-			quiet=1
+			quiet=$1
 			shift
 			;;
 		--recursive)
-			recursive=1
+			recursive=$1
 			shift
 			;;
 		--)
@@ -615,8 +609,8 @@
 	done
 
 	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync \
-		${quiet:+--quiet} \
-		${recursive:+--recursive} \
+		$quiet \
+		$recursive \
 		-- \
 		"$@"
 }
@@ -639,10 +633,10 @@
 		command=$1
 		;;
 	-q|--quiet)
-		quiet=1
+		quiet=$1
 		;;
 	--cached)
-		cached=1
+		cached=$1
 		;;
 	--)
 		break
diff --git a/git-zlib.c b/git-zlib.c
index d43bbeb..651dd9e 100644
--- a/git-zlib.c
+++ b/git-zlib.c
@@ -59,7 +59,8 @@ static void zlib_post_call(git_zstream *s)
 
 	s->total_out = s->z.total_out;
 	s->total_in = s->z.total_in;
-	s->next_in = s->z.next_in;
+	/* zlib-ng marks `next_in` as `const`, so we have to cast it away. */
+	s->next_in = (unsigned char *) s->z.next_in;
 	s->next_out = s->z.next_out;
 	s->avail_in -= bytes_consumed;
 	s->avail_out -= bytes_produced;
@@ -147,10 +148,6 @@ int git_inflate(git_zstream *strm, int flush)
 	return status;
 }
 
-#if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
-#define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
-#endif
-
 unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)
 {
 	return deflateBound(&strm->z, size);
diff --git a/git-zlib.h b/git-zlib.h
index d8a670a..1e8d9aa 100644
--- a/git-zlib.h
+++ b/git-zlib.h
@@ -1,6 +1,8 @@
 #ifndef GIT_ZLIB_H
 #define GIT_ZLIB_H
 
+#include "compat/zlib-compat.h"
+
 typedef struct git_zstream {
 	z_stream z;
 	unsigned long avail_in;
diff --git a/git.c b/git.c
index 71d644d..450d6aa 100644
--- a/git.c
+++ b/git.c
@@ -125,7 +125,7 @@ static void commit_pager_choice(void)
 		setenv("GIT_PAGER", "cat", 1);
 		break;
 	case 1:
-		setup_pager();
+		setup_pager(the_repository);
 		break;
 	default:
 		break;
@@ -136,7 +136,7 @@ void setup_auto_pager(const char *cmd, int def)
 {
 	if (use_pager != -1 || pager_in_use())
 		return;
-	use_pager = check_pager_config(cmd);
+	use_pager = check_pager_config(the_repository, cmd);
 	if (use_pager == -1)
 		use_pager = def;
 	commit_pager_choice();
@@ -462,12 +462,12 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct
 	precompose_argv_prefix(argc, argv, NULL);
 	if (use_pager == -1 && run_setup &&
 		!(p->option & DELAY_PAGER_CONFIG))
-		use_pager = check_pager_config(p->cmd);
+		use_pager = check_pager_config(the_repository, p->cmd);
 	if (use_pager == -1 && p->option & USE_PAGER)
 		use_pager = 1;
 	if (run_setup && startup_info->have_repository)
 		/* get_git_dir() may set up repo, avoid that */
-		trace_repo_setup();
+		trace_repo_setup(the_repository);
 	commit_pager_choice();
 
 	if (!help && p->option & NEED_WORK_TREE)
@@ -506,6 +506,7 @@ static struct cmd_struct commands[] = {
 	{ "annotate", cmd_annotate, RUN_SETUP },
 	{ "apply", cmd_apply, RUN_SETUP_GENTLY },
 	{ "archive", cmd_archive, RUN_SETUP_GENTLY },
+	{ "backfill", cmd_backfill, RUN_SETUP },
 	{ "bisect", cmd_bisect, RUN_SETUP },
 	{ "blame", cmd_blame, RUN_SETUP },
 	{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
@@ -587,7 +588,9 @@ static struct cmd_struct commands[] = {
 	{ "name-rev", cmd_name_rev, RUN_SETUP },
 	{ "notes", cmd_notes, RUN_SETUP },
 	{ "pack-objects", cmd_pack_objects, RUN_SETUP },
+#ifndef WITH_BREAKING_CHANGES
 	{ "pack-redundant", cmd_pack_redundant, RUN_SETUP | NO_PARSEOPT },
+#endif
 	{ "pack-refs", cmd_pack_refs, RUN_SETUP },
 	{ "patch-id", cmd_patch_id, RUN_SETUP_GENTLY | NO_PARSEOPT },
 	{ "pickaxe", cmd_blame, RUN_SETUP },
@@ -750,7 +753,7 @@ static void execv_dashed_external(const char **argv)
 	int status;
 
 	if (use_pager == -1 && !is_builtin(argv[0]))
-		use_pager = check_pager_config(argv[0]);
+		use_pager = check_pager_config(the_repository, argv[0]);
 	commit_pager_choice();
 
 	strvec_pushf(&cmd.args, "git-%s", argv[0]);
diff --git a/gitk-git/Makefile b/gitk-git/Makefile
index e1f0aff..3a3c56c 100644
--- a/gitk-git/Makefile
+++ b/gitk-git/Makefile
@@ -8,6 +8,7 @@
 msgsdir    ?= $(gitk_libdir)/msgs
 msgsdir_SQ  = $(subst ','\'',$(msgsdir))
 
+SHELL_PATH ?= /bin/sh
 TCL_PATH ?= tclsh
 TCLTK_PATH ?= wish
 INSTALL ?= install
@@ -64,9 +65,7 @@
 
 gitk-wish: gitk GIT-TCLTK-VARS
 	$(QUIET_GEN)$(RM) $@ $@+ && \
-	sed -e '1,3s|^exec .* "$$0"|exec $(subst |,'\|',$(TCLTK_PATH_SQ)) "$$0"|' <gitk >$@+ && \
-	chmod +x $@+ && \
-	mv -f $@+ $@
+	$(SHELL_PATH) ./generate-tcl.sh "$(TCLTK_PATH_SQ)" "$<" "$@"
 
 $(PO_TEMPLATE): gitk
 	$(XGETTEXT) -kmc -LTcl -o $@ gitk
diff --git a/gitk-git/generate-tcl.sh b/gitk-git/generate-tcl.sh
new file mode 100755
index 0000000..46bba6d
--- /dev/null
+++ b/gitk-git/generate-tcl.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+set -e
+
+WISH=$(echo "$1" | sed 's/|/\\|/g')
+INPUT="$2"
+OUTPUT="$3"
+
+sed -e "1,3s|^exec .* \"\$0\"|exec $WISH \"\$0\"|" "$INPUT" >"$OUTPUT"+
+chmod a+x "$OUTPUT"+
+mv "$OUTPUT"+ "$OUTPUT"
diff --git a/gitk-git/gitk b/gitk-git/gitk
index f4471ad..68341a7 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -9,6 +9,140 @@
 
 package require Tk
 
+######################################################################
+##
+## Enabling platform-specific code paths
+
+proc is_MacOSX {} {
+	if {[tk windowingsystem] eq {aqua}} {
+		return 1
+	}
+	return 0
+}
+
+proc is_Windows {} {
+	if {$::tcl_platform(platform) eq {windows}} {
+		return 1
+	}
+	return 0
+}
+
+set _iscygwin {}
+proc is_Cygwin {} {
+	global _iscygwin
+	if {$_iscygwin eq {}} {
+		if {[string match "CYGWIN_*" $::tcl_platform(os)]} {
+			set _iscygwin 1
+		} else {
+			set _iscygwin 0
+		}
+	}
+	return $_iscygwin
+}
+
+######################################################################
+##
+## PATH lookup
+
+set _search_path {}
+proc _which {what args} {
+	global env _search_exe _search_path
+
+	if {$_search_path eq {}} {
+		if {[is_Cygwin] && [regexp {^(/|\.:)} $env(PATH)]} {
+			set _search_path [split [exec cygpath \
+				--windows \
+				--path \
+				--absolute \
+				$env(PATH)] {;}]
+			set _search_exe .exe
+		} elseif {[is_Windows]} {
+			set gitguidir [file dirname [info script]]
+			regsub -all ";" $gitguidir "\\;" gitguidir
+			set env(PATH) "$gitguidir;$env(PATH)"
+			set _search_path [split $env(PATH) {;}]
+			# Skip empty `PATH` elements
+			set _search_path [lsearch -all -inline -not -exact \
+				$_search_path ""]
+			set _search_exe .exe
+		} else {
+			set _search_path [split $env(PATH) :]
+			set _search_exe {}
+		}
+	}
+
+	if {[is_Windows] && [lsearch -exact $args -script] >= 0} {
+		set suffix {}
+	} else {
+		set suffix $_search_exe
+	}
+
+	foreach p $_search_path {
+		set p [file join $p $what$suffix]
+		if {[file exists $p]} {
+			return [file normalize $p]
+		}
+	}
+	return {}
+}
+
+proc sanitize_command_line {command_line from_index} {
+	set i $from_index
+	while {$i < [llength $command_line]} {
+		set cmd [lindex $command_line $i]
+		if {[file pathtype $cmd] ne "absolute"} {
+			set fullpath [_which $cmd]
+			if {$fullpath eq ""} {
+				throw {NOT-FOUND} "$cmd not found in PATH"
+			}
+			lset command_line $i $fullpath
+		}
+
+		# handle piped commands, e.g. `exec A | B`
+		for {incr i} {$i < [llength $command_line]} {incr i} {
+			if {[lindex $command_line $i] eq "|"} {
+				incr i
+				break
+			}
+		}
+	}
+	return $command_line
+}
+
+# Override `exec` to avoid unsafe PATH lookup
+
+rename exec real_exec
+
+proc exec {args} {
+	# skip options
+	for {set i 0} {$i < [llength $args]} {incr i} {
+		set arg [lindex $args $i]
+		if {$arg eq "--"} {
+			incr i
+			break
+		}
+		if {[string range $arg 0 0] ne "-"} {
+			break
+		}
+	}
+	set args [sanitize_command_line $args $i]
+	uplevel 1 real_exec $args
+}
+
+# Override `open` to avoid unsafe PATH lookup
+
+rename open real_open
+
+proc open {args} {
+	set arg0 [lindex $args 0]
+	if {[string range $arg0 0 0] eq "|"} {
+		set command_line [string trim [string range $arg0 1 end]]
+		lset args 0 "| [sanitize_command_line $command_line 0]"
+	}
+	uplevel 1 real_open $args
+}
+
+# End of safe PATH lookup stuff
 
 # Wrap exec/open to sanitize arguments
 
@@ -2176,7 +2310,7 @@
     global headctxmenu progresscanv progressitem progresscoords statusw
     global fprogitem fprogcoord lastprogupdate progupdatepending
     global rprogitem rprogcoord rownumsel numcommits
-    global have_tk85 use_ttk NS
+    global have_tk85 have_tk86 use_ttk NS
     global git_version
     global worddiff
 
@@ -2674,8 +2808,13 @@
     bind . <Key-Down> "selnextline 1"
     bind . <Shift-Key-Up> "dofind -1 0"
     bind . <Shift-Key-Down> "dofind 1 0"
-    bindkey <Key-Right> "goforw"
-    bindkey <Key-Left> "goback"
+    if {$have_tk86} {
+        bindkey <<NextChar>> "goforw"
+        bindkey <<PrevChar>> "goback"
+    } else {
+        bindkey <Key-Right> "goforw"
+        bindkey <Key-Left> "goback"
+    }
     bind . <Key-Prior> "selnextpage -1"
     bind . <Key-Next> "selnextpage 1"
     bind . <$M1B-Home> "allcanvs yview moveto 0.0"
@@ -7791,7 +7930,7 @@
         if {[string index $fname 0] eq "\""} {
             set fname [lindex $fname 0]
         }
-        set fname [encoding convertfrom $fname]
+        set fname [encoding convertfrom utf-8 $fname]
         lappend treefilelist($id) $fname
     }
     if {![eof $gtf]} {
@@ -8053,7 +8192,7 @@
             if {[string index $file 0] eq "\""} {
                 set file [lindex $file 0]
             }
-            set file [encoding convertfrom $file]
+            set file [encoding convertfrom utf-8 $file]
             if {$file ne [lindex $treediff end]} {
                 lappend treediff $file
                 lappend sublist $file
@@ -8198,7 +8337,7 @@
     global ctext curdiffstart treediffs diffencoding
     global ctext_file_names jump_to_here targetline diffline
 
-    set fname [encoding convertfrom $fname]
+    set fname [encoding convertfrom utf-8 $fname]
     set diffencoding [get_path_encoding $fname]
     set i [lsearch -exact $treediffs($ids) $fname]
     if {$i >= 0} {
@@ -8260,7 +8399,7 @@
 
     if {![string compare -length 5 "diff " $line]} {
         if {![regexp {^diff (--cc|--git) } $line m type]} {
-            set line [encoding convertfrom $line]
+            set line [encoding convertfrom utf-8 $line]
             $ctext insert end "$line\n" hunksep
             continue
         }
@@ -8309,7 +8448,7 @@
         makediffhdr $fname $ids
 
     } elseif {![string compare -length 16 "* Unmerged path " $line]} {
-        set fname [encoding convertfrom [string range $line 16 end]]
+        set fname [encoding convertfrom utf-8 [string range $line 16 end]]
         $ctext insert end "\n"
         set curdiffstart [$ctext index "end - 1c"]
         lappend ctext_file_names $fname
@@ -8362,7 +8501,7 @@
             if {[string index $fname 0] eq "\""} {
                 set fname [lindex $fname 0]
             }
-            set fname [encoding convertfrom $fname]
+            set fname [encoding convertfrom utf-8 $fname]
             set i [lsearch -exact $treediffs($ids) $fname]
             if {$i >= 0} {
                 setinlist difffilestart $i $curdiffstart
@@ -8381,6 +8520,7 @@
             set diffinhdr 0
             return
         }
+        set line [encoding convertfrom utf-8 $line]
         $ctext insert end "$line\n" filesep
 
     } else {
@@ -10133,7 +10273,7 @@
     text $top.list -background $bgcolor -foreground $fgcolor \
         -selectbackground $selectbgcolor -font mainfont \
         -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \
-        -width 30 -height 20 -cursor $maincursor \
+        -width 60 -height 20 -cursor $maincursor \
         -spacing1 1 -spacing3 1 -state disabled
     $top.list tag configure highlight -background $selectbgcolor
     if {![lsearch -exact $bglist $top.list]} {
@@ -12371,7 +12511,7 @@
             foreach row [split $rlist "\n"] {
                 if {[regexp "(.*): $attr: (.*)" $row m path value]} {
                     if {[string index $path 0] eq "\""} {
-                        set path [encoding convertfrom [lindex $path 0]]
+                        set path [encoding convertfrom utf-8 [lindex $path 0]]
                     }
                     set path_attr_cache($attr,$path) $value
                 }
@@ -12401,7 +12541,6 @@
     set gitk_prefix [file dirname [file dirname [file normalize $argv0]]]
     set gitk_libdir [file join $gitk_prefix share gitk lib]
     set gitk_msgsdir [file join $gitk_libdir msgs]
-    unset gitk_prefix
 }
 
 ## Internationalization (i18n) through msgcat and gettext. See
@@ -12703,6 +12842,7 @@
 set nullfile "/dev/null"
 
 set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
+set have_tk86 [expr {[package vcompare $tk_version "8.6"] >= 0}]
 if {![info exists have_ttk]} {
     set have_ttk [llength [info commands ::ttk::style]]
 }
@@ -12767,28 +12907,32 @@
 set worktree [gitworktree]
 setcoords
 makewindow
-catch {
-    image create photo gitlogo      -width 16 -height 16
+if {$::tcl_platform(platform) eq {windows} && [file exists $gitk_prefix/etc/git.ico]} {
+    wm iconbitmap . -default $gitk_prefix/etc/git.ico
+} else {
+    catch {
+        image create photo gitlogo      -width 16 -height 16
 
-    image create photo gitlogominus -width  4 -height  2
-    gitlogominus put #C00000 -to 0 0 4 2
-    gitlogo copy gitlogominus -to  1 5
-    gitlogo copy gitlogominus -to  6 5
-    gitlogo copy gitlogominus -to 11 5
-    image delete gitlogominus
+        image create photo gitlogominus -width  4 -height  2
+        gitlogominus put #C00000 -to 0 0 4 2
+        gitlogo copy gitlogominus -to  1 5
+        gitlogo copy gitlogominus -to  6 5
+        gitlogo copy gitlogominus -to 11 5
+        image delete gitlogominus
 
-    image create photo gitlogoplus  -width  4 -height  4
-    gitlogoplus  put #008000 -to 1 0 3 4
-    gitlogoplus  put #008000 -to 0 1 4 3
-    gitlogo copy gitlogoplus  -to  1 9
-    gitlogo copy gitlogoplus  -to  6 9
-    gitlogo copy gitlogoplus  -to 11 9
-    image delete gitlogoplus
+        image create photo gitlogoplus  -width  4 -height  4
+        gitlogoplus  put #008000 -to 1 0 3 4
+        gitlogoplus  put #008000 -to 0 1 4 3
+        gitlogo copy gitlogoplus  -to  1 9
+        gitlogo copy gitlogoplus  -to  6 9
+        gitlogo copy gitlogoplus  -to 11 9
+        image delete gitlogoplus
 
-    image create photo gitlogo32    -width 32 -height 32
-    gitlogo32 copy gitlogo -zoom 2 2
+        image create photo gitlogo32    -width 32 -height 32
+        gitlogo32 copy gitlogo -zoom 2 2
 
-    wm iconphoto . -default gitlogo gitlogo32
+        wm iconphoto . -default gitlogo gitlogo32
+    }
 }
 # wait for the window to become visible
 if {![winfo viewable .]} {tkwait visibility .}
diff --git a/gitk-git/meson.build b/gitk-git/meson.build
new file mode 100644
index 0000000..ca3c0ce
--- /dev/null
+++ b/gitk-git/meson.build
@@ -0,0 +1,30 @@
+project('gitk')
+
+shell = find_program('sh')
+wish = find_program('wish')
+
+# Verify that dependencies of "generate-tcl.sh" are satisfied.
+foreach dependency : [ 'chmod', 'mv', 'sed' ]
+  find_program(dependency)
+endforeach
+
+custom_target(
+  command: [
+    shell,
+    meson.current_source_dir() / 'generate-tcl.sh',
+    wish.full_path(),
+    '@INPUT@',
+    '@OUTPUT@',
+  ],
+  input: 'gitk',
+  output: 'gitk',
+  depend_files: [
+    'generate-tcl.sh',
+  ],
+  install: true,
+  install_dir: get_option('bindir'),
+)
+
+if find_program('msgfmt').found()
+  subdir('po')
+endif
diff --git a/gitk-git/po/meson.build b/gitk-git/po/meson.build
new file mode 100644
index 0000000..b1ed019
--- /dev/null
+++ b/gitk-git/po/meson.build
@@ -0,0 +1,19 @@
+import('i18n').gettext('gitk',
+  languages: [
+    'bg',
+    'ca',
+    'de',
+    'es',
+    'fr',
+    'hu',
+    'it',
+    'ja',
+    'pt_br',
+    'pt_pt',
+    'ru',
+    'sv',
+    'vi',
+    'zh_cn',
+  ],
+  install: true,
+)
diff --git a/graph.c b/graph.c
index 52205f7..26f6fbf 100644
--- a/graph.c
+++ b/graph.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -351,7 +350,7 @@ struct git_graph *graph_init(struct rev_info *opt)
 
 	if (!column_colors) {
 		char *string;
-		if (git_config_get_string("log.graphcolors", &string)) {
+		if (repo_config_get_string(opt->repo, "log.graphcolors", &string)) {
 			/* not configured -- use default */
 			graph_set_column_colors(column_colors_ansi,
 						column_colors_ansi_max);
diff --git a/hash.h b/hash.h
index 756166c..4367acf 100644
--- a/hash.h
+++ b/hash.h
@@ -234,19 +234,20 @@ enum get_oid_result {
 #endif
 
 /* A suitably aligned type for stack allocations of hash contexts. */
-union git_hash_ctx {
-	git_SHA_CTX sha1;
-	git_SHA_CTX_unsafe sha1_unsafe;
-
-	git_SHA256_CTX sha256;
+struct git_hash_ctx {
+	const struct git_hash_algo *algop;
+	union {
+		git_SHA_CTX sha1;
+		git_SHA_CTX_unsafe sha1_unsafe;
+		git_SHA256_CTX sha256;
+	} state;
 };
-typedef union git_hash_ctx git_hash_ctx;
 
-typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
-typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);
-typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
-typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
-typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx);
+typedef void (*git_hash_init_fn)(struct git_hash_ctx *ctx);
+typedef void (*git_hash_clone_fn)(struct git_hash_ctx *dst, const struct git_hash_ctx *src);
+typedef void (*git_hash_update_fn)(struct git_hash_ctx *ctx, const void *in, size_t len);
+typedef void (*git_hash_final_fn)(unsigned char *hash, struct git_hash_ctx *ctx);
+typedef void (*git_hash_final_oid_fn)(struct object_id *oid, struct git_hash_ctx *ctx);
 
 struct git_hash_algo {
 	/*
@@ -282,21 +283,6 @@ struct git_hash_algo {
 	/* The hash finalization function for object IDs. */
 	git_hash_final_oid_fn final_oid_fn;
 
-	/* The non-cryptographic hash initialization function. */
-	git_hash_init_fn unsafe_init_fn;
-
-	/* The non-cryptographic hash context cloning function. */
-	git_hash_clone_fn unsafe_clone_fn;
-
-	/* The non-cryptographic hash update function. */
-	git_hash_update_fn unsafe_update_fn;
-
-	/* The non-cryptographic hash finalization function. */
-	git_hash_final_fn unsafe_final_fn;
-
-	/* The non-cryptographic hash finalization function. */
-	git_hash_final_oid_fn unsafe_final_oid_fn;
-
 	/* The OID of the empty tree. */
 	const struct object_id *empty_tree;
 
@@ -305,9 +291,32 @@ struct git_hash_algo {
 
 	/* The all-zeros OID. */
 	const struct object_id *null_oid;
+
+	/* The unsafe variant of this hash function, if one exists. */
+	const struct git_hash_algo *unsafe;
 };
 extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];
 
+static inline void git_hash_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src)
+{
+	src->algop->clone_fn(dst, src);
+}
+
+static inline void git_hash_update(struct git_hash_ctx *ctx, const void *in, size_t len)
+{
+	ctx->algop->update_fn(ctx, in, len);
+}
+
+static inline void git_hash_final(unsigned char *hash, struct git_hash_ctx *ctx)
+{
+	ctx->algop->final_fn(hash, ctx);
+}
+
+static inline void git_hash_final_oid(struct object_id *oid, struct git_hash_ctx *ctx)
+{
+	ctx->algop->final_oid_fn(oid, ctx);
+}
+
 /*
  * Return a GIT_HASH_* constant based on the name.  Returns GIT_HASH_UNKNOWN if
  * the name doesn't match a known algorithm.
@@ -320,9 +329,17 @@ int hash_algo_by_length(int len);
 /* Identical, except for a pointer to struct git_hash_algo. */
 static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
 {
-	return p - hash_algos;
+	size_t i;
+	for (i = 0; i < GIT_HASH_NALGOS; i++) {
+		const struct git_hash_algo *algop = &hash_algos[i];
+		if (p == algop)
+			return i;
+	}
+	return GIT_HASH_UNKNOWN;
 }
 
+const struct git_hash_algo *unsafe_hash_algo(const struct git_hash_algo *algop);
+
 const struct object_id *null_oid(void);
 
 static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
diff --git a/help.c b/help.c
index 5483ea8..c54bd99 100644
--- a/help.c
+++ b/help.c
@@ -2,6 +2,7 @@
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
+#include "git-zlib.h"
 #include "config.h"
 #include "builtin.h"
 #include "exec-cmd.h"
@@ -552,10 +553,34 @@ struct help_unknown_cmd_config {
 	struct cmdnames aliases;
 };
 
+#define AUTOCORRECT_SHOW (-4)
 #define AUTOCORRECT_PROMPT (-3)
 #define AUTOCORRECT_NEVER (-2)
 #define AUTOCORRECT_IMMEDIATELY (-1)
 
+static int parse_autocorrect(const char *value)
+{
+	switch (git_parse_maybe_bool_text(value)) {
+		case 1:
+			return AUTOCORRECT_IMMEDIATELY;
+		case 0:
+			return AUTOCORRECT_SHOW;
+		default: /* other random text */
+			break;
+	}
+
+	if (!strcmp(value, "prompt"))
+		return AUTOCORRECT_PROMPT;
+	if (!strcmp(value, "never"))
+		return AUTOCORRECT_NEVER;
+	if (!strcmp(value, "immediate"))
+		return AUTOCORRECT_IMMEDIATELY;
+	if (!strcmp(value, "show"))
+		return AUTOCORRECT_SHOW;
+
+	return 0;
+}
+
 static int git_unknown_cmd_config(const char *var, const char *value,
 				  const struct config_context *ctx,
 				  void *cb)
@@ -564,20 +589,17 @@ static int git_unknown_cmd_config(const char *var, const char *value,
 	const char *p;
 
 	if (!strcmp(var, "help.autocorrect")) {
-		if (!value)
-			return config_error_nonbool(var);
-		if (!strcmp(value, "never")) {
-			cfg->autocorrect = AUTOCORRECT_NEVER;
-		} else if (!strcmp(value, "immediate")) {
-			cfg->autocorrect = AUTOCORRECT_IMMEDIATELY;
-		} else if (!strcmp(value, "prompt")) {
-			cfg->autocorrect = AUTOCORRECT_PROMPT;
-		} else {
-			int v = git_config_int(var, value, ctx->kvi);
-			cfg->autocorrect = (v < 0)
-				? AUTOCORRECT_IMMEDIATELY : v;
+		int v = parse_autocorrect(value);
+
+		if (!v) {
+			v = git_config_int(var, value, ctx->kvi);
+			if (v < 0 || v == 1)
+				v = AUTOCORRECT_IMMEDIATELY;
 		}
+
+		cfg->autocorrect = v;
 	}
+
 	/* Also use aliases for command lookup */
 	if (skip_prefix(var, "alias.", &p))
 		add_cmdname(&cfg->aliases, p, strlen(p));
@@ -695,7 +717,8 @@ char *help_unknown_cmd(const char *cmd)
 		     n++)
 			; /* still counting */
 	}
-	if (cfg.autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {
+	if (cfg.autocorrect && cfg.autocorrect != AUTOCORRECT_SHOW && n == 1 &&
+	    SIMILAR_ENOUGH(best_similarity)) {
 		char *assumed = xstrdup(main_cmds.names[0]->name);
 
 		fprintf_ln(stderr,
@@ -775,7 +798,9 @@ void get_version_info(struct strbuf *buf, int show_build_options)
 #if defined OPENSSL_VERSION_TEXT
 		strbuf_addf(buf, "OpenSSL: %s\n", OPENSSL_VERSION_TEXT);
 #endif
-#if defined ZLIB_VERSION
+#if defined ZLIBNG_VERSION
+		strbuf_addf(buf, "zlib-ng: %s\n", ZLIBNG_VERSION);
+#elif defined ZLIB_VERSION
 		strbuf_addf(buf, "zlib: %s\n", ZLIB_VERSION);
 #endif
 	}
diff --git a/hook.c b/hook.c
index 9ddbdee..b3de104 100644
--- a/hook.c
+++ b/hook.c
@@ -16,8 +16,7 @@ const char *find_hook(struct repository *r, const char *name)
 
 	int found_hook;
 
-	strbuf_reset(&path);
-	strbuf_repo_git_path(&path, r, "hooks/%s", name);
+	repo_git_path_replace(r, &path, "hooks/%s", name);
 	found_hook = access(path.buf, X_OK) >= 0;
 #ifdef STRIP_EXTENSION
 	if (!found_hook) {
diff --git a/http-backend.c b/http-backend.c
index 33cf378..50b2858 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -183,7 +183,7 @@ static void send_strbuf(struct strbuf *hdr,
 static void send_local_file(struct strbuf *hdr, const char *the_type,
 				const char *name)
 {
-	char *p = git_pathdup("%s", name);
+	char *p = repo_git_path(the_repository, "%s", name);
 	size_t buf_alloc = 8192;
 	char *buf = xmalloc(buf_alloc);
 	int fd;
diff --git a/http-push.c b/http-push.c
index 43da1c7..1b030d9 100644
--- a/http-push.c
+++ b/http-push.c
@@ -760,7 +760,7 @@ static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed)
 static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
 {
 	struct remote_lock *lock = (struct remote_lock *)ctx->userData;
-	git_hash_ctx hash_ctx;
+	struct git_hash_ctx hash_ctx;
 	unsigned char lock_token_hash[GIT_MAX_RAWSZ];
 
 	if (tag_closed && ctx->cdata) {
@@ -774,8 +774,8 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
 			lock->token = xstrdup(ctx->cdata);
 
 			the_hash_algo->init_fn(&hash_ctx);
-			the_hash_algo->update_fn(&hash_ctx, lock->token, strlen(lock->token));
-			the_hash_algo->final_fn(lock_token_hash, &hash_ctx);
+			git_hash_update(&hash_ctx, lock->token, strlen(lock->token));
+			git_hash_final(lock_token_hash, &hash_ctx);
 
 			lock->tmpfile_suffix[0] = '_';
 			memcpy(lock->tmpfile_suffix + 1, hash_to_hex(lock_token_hash), the_hash_algo->hexsz);
diff --git a/http.c b/http.c
index c8fc15a..0c9a872 100644
--- a/http.c
+++ b/http.c
@@ -598,8 +598,7 @@ static void init_curl_http_auth(CURL *result)
 {
 	if ((!http_auth.username || !*http_auth.username) &&
 	    (!http_auth.credential || !*http_auth.credential)) {
-		int empty_auth = curl_empty_auth_enabled();
-		if ((empty_auth != -1 && !always_auth_proactively()) || empty_auth == 1) {
+		if (!always_auth_proactively() && curl_empty_auth_enabled()) {
 			curl_easy_setopt(result, CURLOPT_USERPWD, ":");
 			return;
 		} else if (!always_auth_proactively()) {
@@ -609,7 +608,7 @@ static void init_curl_http_auth(CURL *result)
 		}
 	}
 
-	credential_fill(&http_auth, 1);
+	credential_fill(the_repository, &http_auth, 1);
 
 	if (http_auth.password) {
 		if (always_auth_proactively()) {
@@ -652,7 +651,7 @@ static void init_curl_proxy_auth(CURL *result)
 {
 	if (proxy_auth.username) {
 		if (!proxy_auth.password && !proxy_auth.credential)
-			credential_fill(&proxy_auth, 1);
+			credential_fill(the_repository, &proxy_auth, 1);
 		set_proxyauth_name_password(result);
 	}
 
@@ -686,7 +685,7 @@ static int has_cert_password(void)
 		cert_auth.host = xstrdup("");
 		cert_auth.username = xstrdup("");
 		cert_auth.path = xstrdup(ssl_cert);
-		credential_fill(&cert_auth, 0);
+		credential_fill(the_repository, &cert_auth, 0);
 	}
 	return 1;
 }
@@ -700,7 +699,7 @@ static int has_proxy_cert_password(void)
 		proxy_cert_auth.host = xstrdup("");
 		proxy_cert_auth.username = xstrdup("");
 		proxy_cert_auth.path = xstrdup(http_proxy_ssl_cert);
-		credential_fill(&proxy_cert_auth, 0);
+		credential_fill(the_repository, &proxy_cert_auth, 0);
 	}
 	return 1;
 }
@@ -1784,9 +1783,9 @@ static int handle_curl_result(struct slot_results *results)
 			      curl_errorstr, sizeof(curl_errorstr));
 
 	if (results->curl_result == CURLE_OK) {
-		credential_approve(&http_auth);
-		credential_approve(&proxy_auth);
-		credential_approve(&cert_auth);
+		credential_approve(the_repository, &http_auth);
+		credential_approve(the_repository, &proxy_auth);
+		credential_approve(the_repository, &cert_auth);
 		return HTTP_OK;
 	} else if (results->curl_result == CURLE_SSL_CERTPROBLEM) {
 		/*
@@ -1795,7 +1794,7 @@ static int handle_curl_result(struct slot_results *results)
 		 * with the certificate.  So we reject the credential to
 		 * avoid caching or saving a bad password.
 		 */
-		credential_reject(&cert_auth);
+		credential_reject(the_repository, &cert_auth);
 		return HTTP_NOAUTH;
 	} else if (results->curl_result == CURLE_SSL_PINNEDPUBKEYNOTMATCH) {
 		return HTTP_NOMATCHPUBLICKEY;
@@ -1808,7 +1807,7 @@ static int handle_curl_result(struct slot_results *results)
 				credential_clear_secrets(&http_auth);
 				return HTTP_REAUTH;
 			}
-			credential_reject(&http_auth);
+			credential_reject(the_repository, &http_auth);
 			if (always_auth_proactively())
 				http_proactive_auth = PROACTIVE_AUTH_NONE;
 			return HTTP_NOAUTH;
@@ -1822,7 +1821,7 @@ static int handle_curl_result(struct slot_results *results)
 		}
 	} else {
 		if (results->http_connectcode == 407)
-			credential_reject(&proxy_auth);
+			credential_reject(the_repository, &proxy_auth);
 		if (!curl_errorstr[0])
 			strlcpy(curl_errorstr,
 				curl_easy_strerror(results->curl_result),
@@ -2210,7 +2209,7 @@ static int http_request_reauth(const char *url,
 	int ret;
 
 	if (always_auth_proactively())
-		credential_fill(&http_auth, 1);
+		credential_fill(the_repository, &http_auth, 1);
 
 	ret = http_request(url, result, target, options);
 
@@ -2251,7 +2250,7 @@ static int http_request_reauth(const char *url,
 			BUG("Unknown http_request target");
 		}
 
-		credential_fill(&http_auth, 1);
+		credential_fill(the_repository, &http_auth, 1);
 
 		ret = http_request(url, result, target, options);
 	}
@@ -2597,8 +2596,8 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
 		freq->stream.next_out = expn;
 		freq->stream.avail_out = sizeof(expn);
 		freq->zret = git_inflate(&freq->stream, Z_SYNC_FLUSH);
-		the_hash_algo->update_fn(&freq->c, expn,
-					 sizeof(expn) - freq->stream.avail_out);
+		git_hash_update(&freq->c, expn,
+				sizeof(expn) - freq->stream.avail_out);
 	} while (freq->stream.avail_in && freq->zret == Z_OK);
 	return nmemb;
 }
@@ -2763,7 +2762,7 @@ int finish_http_object_request(struct http_object_request *freq)
 		return -1;
 	}
 
-	the_hash_algo->final_oid_fn(&freq->real_oid, &freq->c);
+	git_hash_final_oid(&freq->real_oid, &freq->c);
 	if (freq->zret != Z_STREAM_END) {
 		unlink_or_warn(freq->tmpfile.buf);
 		return -1;
diff --git a/http.h b/http.h
index 46e334c..3620213 100644
--- a/http.h
+++ b/http.h
@@ -228,7 +228,7 @@ struct http_object_request {
 	long http_code;
 	struct object_id oid;
 	struct object_id real_oid;
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 	git_zstream stream;
 	int zret;
 	int rename;
diff --git a/ident.c b/ident.c
index caf41fb..967895d 100644
--- a/ident.c
+++ b/ident.c
@@ -59,7 +59,7 @@ static struct passwd *xgetpwuid_self(int *is_bogus)
 
 static void copy_gecos(const struct passwd *w, struct strbuf *name)
 {
-	char *src;
+	const char *src;
 
 	/* Traditionally GECOS field had office phone numbers etc, separated
 	 * with commas.  Also & stands for capitalized form of the login name.
diff --git a/imap-send.c b/imap-send.c
index 68ab1ae..6c8f84e 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -922,7 +922,7 @@ static void server_fill_credential(struct imap_server_conf *srvc, struct credent
 	cred->username = xstrdup_or_null(srvc->user);
 	cred->password = xstrdup_or_null(srvc->pass);
 
-	credential_fill(cred, 1);
+	credential_fill(the_repository, cred, 1);
 
 	if (!srvc->user)
 		srvc->user = xstrdup(cred->username);
@@ -1123,7 +1123,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
 	} /* !preauth */
 
 	if (cred.username)
-		credential_approve(&cred);
+		credential_approve(the_repository, &cred);
 	credential_clear(&cred);
 
 	/* check the target mailbox exists */
@@ -1150,7 +1150,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
 
 bail:
 	if (cred.username)
-		credential_reject(&cred);
+		credential_reject(the_repository, &cred);
 	credential_clear(&cred);
 
  out:
@@ -1492,9 +1492,9 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,
 
 	if (cred.username) {
 		if (res == CURLE_OK)
-			credential_approve(&cred);
+			credential_approve(the_repository, &cred);
 		else if (res == CURLE_LOGIN_DENIED)
-			credential_reject(&cred);
+			credential_reject(the_repository, &cred);
 	}
 
 	credential_clear(&cred);
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
index 55fab85..7b2108b 100644
--- a/list-objects-filter-options.h
+++ b/list-objects-filter-options.h
@@ -82,7 +82,7 @@ void list_objects_filter_init(struct list_objects_filter_options *filter_options
  *       "filter" SP <arg>
  *
  * The filter keyword will be used by many commands.
- * See Documentation/rev-list-options.txt for allowed values for <arg>.
+ * See Documentation/rev-list-options.adoc for allowed values for <arg>.
  *
  * Capture the given arg as the "filter_spec".  This can be forwarded to
  * subordinate commands when necessary (although it's better to pass it through
diff --git a/log-tree.c b/log-tree.c
index d08eb67..8b184d6 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -1042,7 +1042,7 @@ static int do_remerge_diff(struct rev_info *opt,
 	 * into the alternative object store list as the primary.
 	 */
 	if (opt->remerge_diff && !opt->remerge_objdir) {
-		opt->remerge_objdir = tmp_objdir_create("remerge-diff");
+		opt->remerge_objdir = tmp_objdir_create(the_repository, "remerge-diff");
 		if (!opt->remerge_objdir)
 			return error(_("unable to create temporary object directory"));
 		tmp_objdir_replace_primary_odb(opt->remerge_objdir, 1);
diff --git a/loose.c b/loose.c
index 897ba38..bb602aa 100644
--- a/loose.c
+++ b/loose.c
@@ -75,7 +75,7 @@ static int load_one_loose_object_map(struct repository *repo, struct object_dire
 	insert_loose_map(dir, repo->hash_algo->empty_blob, repo->compat_hash_algo->empty_blob);
 	insert_loose_map(dir, repo->hash_algo->null_oid, repo->compat_hash_algo->null_oid);
 
-	strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
+	repo_common_path_replace(repo, &path, "objects/loose-object-idx");
 	fp = fopen(path.buf, "rb");
 	if (!fp) {
 		strbuf_release(&path);
@@ -133,7 +133,7 @@ int repo_write_loose_object_map(struct repository *repo)
 	if (!should_use_loose_object_map(repo))
 		return 0;
 
-	strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
+	repo_common_path_replace(repo, &path, "objects/loose-object-idx");
 	fd = hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
 	iter = kh_begin(map);
 	if (write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
@@ -174,7 +174,7 @@ static int write_one_object(struct repository *repo, const struct object_id *oid
 	struct stat st;
 	struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
 
-	strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
+	repo_common_path_replace(repo, &path, "objects/loose-object-idx");
 	hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
 
 	fd = open(path.buf, O_WRONLY | O_CREAT | O_APPEND, 0666);
@@ -190,7 +190,7 @@ static int write_one_object(struct repository *repo, const struct object_id *oid
 		goto errout;
 	if (close(fd))
 		goto errout;
-	adjust_shared_perm(path.buf);
+	adjust_shared_perm(repo, path.buf);
 	rollback_lock_file(&lock);
 	strbuf_release(&buf);
 	strbuf_release(&path);
diff --git a/mailinfo.c b/mailinfo.c
index aa263bf..7b001fa 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -1269,7 +1268,7 @@ static int git_mailinfo_config(const char *var, const char *value,
 	return 0;
 }
 
-void setup_mailinfo(struct mailinfo *mi)
+void setup_mailinfo(struct repository *r, struct mailinfo *mi)
 {
 	memset(mi, 0, sizeof(*mi));
 	strbuf_init(&mi->name, 0);
@@ -1281,7 +1280,7 @@ void setup_mailinfo(struct mailinfo *mi)
 	mi->header_stage = 1;
 	mi->use_inbody_headers = 1;
 	mi->content_top = mi->content;
-	git_config(git_mailinfo_config, mi);
+	repo_config(r, git_mailinfo_config, mi);
 }
 
 void clear_mailinfo(struct mailinfo *mi)
diff --git a/mailinfo.h b/mailinfo.h
index f2ffd03..1f20664 100644
--- a/mailinfo.h
+++ b/mailinfo.h
@@ -5,6 +5,8 @@
 
 #define MAX_BOUNDARIES 5
 
+struct repository;
+
 enum quoted_cr_action {
 	quoted_cr_unset = -1,
 	quoted_cr_nowarn,
@@ -49,7 +51,7 @@ struct mailinfo {
 };
 
 int mailinfo_parse_quoted_cr_action(const char *actionstr, int *action);
-void setup_mailinfo(struct mailinfo *);
+void setup_mailinfo(struct repository *r, struct mailinfo *);
 int mailinfo(struct mailinfo *, const char *msg, const char *patch);
 void clear_mailinfo(struct mailinfo *);
 
diff --git a/match-trees.c b/match-trees.c
index a1c8b91..ef14ceb 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -8,6 +7,7 @@
 #include "tree.h"
 #include "tree-walk.h"
 #include "object-store-ll.h"
+#include "repository.h"
 
 static int score_missing(unsigned mode)
 {
@@ -54,14 +54,15 @@ static int score_matches(unsigned mode1, unsigned mode2)
 	return score;
 }
 
-static void *fill_tree_desc_strict(struct tree_desc *desc,
+static void *fill_tree_desc_strict(struct repository *r,
+				   struct tree_desc *desc,
 				   const struct object_id *hash)
 {
 	void *buffer;
 	enum object_type type;
 	unsigned long size;
 
-	buffer = repo_read_object_file(the_repository, hash, &type, &size);
+	buffer = repo_read_object_file(r, hash, &type, &size);
 	if (!buffer)
 		die("unable to read tree (%s)", oid_to_hex(hash));
 	if (type != OBJ_TREE)
@@ -80,12 +81,13 @@ static int base_name_entries_compare(const struct name_entry *a,
 /*
  * Inspect two trees, and give a score that tells how similar they are.
  */
-static int score_trees(const struct object_id *hash1, const struct object_id *hash2)
+static int score_trees(struct repository *r,
+		       const struct object_id *hash1, const struct object_id *hash2)
 {
 	struct tree_desc one;
 	struct tree_desc two;
-	void *one_buf = fill_tree_desc_strict(&one, hash1);
-	void *two_buf = fill_tree_desc_strict(&two, hash2);
+	void *one_buf = fill_tree_desc_strict(r, &one, hash1);
+	void *two_buf = fill_tree_desc_strict(r, &two, hash2);
 	int score = 0;
 
 	for (;;) {
@@ -133,7 +135,8 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
 /*
  * Match one itself and its subtrees with two and pick the best match.
  */
-static void match_trees(const struct object_id *hash1,
+static void match_trees(struct repository *r,
+			const struct object_id *hash1,
 			const struct object_id *hash2,
 			int *best_score,
 			char **best_match,
@@ -141,7 +144,7 @@ static void match_trees(const struct object_id *hash1,
 			int recurse_limit)
 {
 	struct tree_desc one;
-	void *one_buf = fill_tree_desc_strict(&one, hash1);
+	void *one_buf = fill_tree_desc_strict(r, &one, hash1);
 
 	while (one.size) {
 		const char *path;
@@ -152,7 +155,7 @@ static void match_trees(const struct object_id *hash1,
 		elem = tree_entry_extract(&one, &path, &mode);
 		if (!S_ISDIR(mode))
 			goto next;
-		score = score_trees(elem, hash2);
+		score = score_trees(r, elem, hash2);
 		if (*best_score < score) {
 			free(*best_match);
 			*best_match = xstrfmt("%s%s", base, path);
@@ -160,7 +163,7 @@ static void match_trees(const struct object_id *hash1,
 		}
 		if (recurse_limit) {
 			char *newbase = xstrfmt("%s%s/", base, path);
-			match_trees(elem, hash2, best_score, best_match,
+			match_trees(r, elem, hash2, best_score, best_match,
 				    newbase, recurse_limit - 1);
 			free(newbase);
 		}
@@ -175,7 +178,8 @@ static void match_trees(const struct object_id *hash1,
  * A tree "oid1" has a subdirectory at "prefix".  Come up with a tree object by
  * replacing it with another tree "oid2".
  */
-static int splice_tree(const struct object_id *oid1, const char *prefix,
+static int splice_tree(struct repository *r,
+		       const struct object_id *oid1, const char *prefix,
 		       const struct object_id *oid2, struct object_id *result)
 {
 	char *subpath;
@@ -194,7 +198,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
 	if (*subpath)
 		subpath++;
 
-	buf = repo_read_object_file(the_repository, oid1, &type, &sz);
+	buf = repo_read_object_file(r, oid1, &type, &sz);
 	if (!buf)
 		die("cannot read tree %s", oid_to_hex(oid1));
 	init_tree_desc(&desc, oid1, buf, sz);
@@ -232,15 +236,15 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
 		    oid_to_hex(oid1));
 	if (*subpath) {
 		struct object_id tree_oid;
-		oidread(&tree_oid, rewrite_here, the_repository->hash_algo);
-		status = splice_tree(&tree_oid, subpath, oid2, &subtree);
+		oidread(&tree_oid, rewrite_here, r->hash_algo);
+		status = splice_tree(r, &tree_oid, subpath, oid2, &subtree);
 		if (status)
 			return status;
 		rewrite_with = &subtree;
 	} else {
 		rewrite_with = oid2;
 	}
-	hashcpy(rewrite_here, rewrite_with->hash, the_repository->hash_algo);
+	hashcpy(rewrite_here, rewrite_with->hash, r->hash_algo);
 	status = write_object_file(buf, sz, OBJ_TREE, result);
 	free(buf);
 	return status;
@@ -271,7 +275,7 @@ void shift_tree(struct repository *r,
 	if (!depth_limit)
 		depth_limit = 2;
 
-	add_score = del_score = score_trees(hash1, hash2);
+	add_score = del_score = score_trees(r, hash1, hash2);
 	add_prefix = xcalloc(1, 1);
 	del_prefix = xcalloc(1, 1);
 
@@ -279,13 +283,13 @@ void shift_tree(struct repository *r,
 	 * See if one's subtree resembles two; if so we need to prefix
 	 * two with a few fake trees to match the prefix.
 	 */
-	match_trees(hash1, hash2, &add_score, &add_prefix, "", depth_limit);
+	match_trees(r, hash1, hash2, &add_score, &add_prefix, "", depth_limit);
 
 	/*
 	 * See if two's subtree resembles one; if so we need to
 	 * pick only subtree of two.
 	 */
-	match_trees(hash2, hash1, &del_score, &del_prefix, "", depth_limit);
+	match_trees(r, hash2, hash1, &del_score, &del_prefix, "", depth_limit);
 
 	/* Assume we do not have to do any shifting */
 	oidcpy(shifted, hash2);
@@ -306,7 +310,7 @@ void shift_tree(struct repository *r,
 	if (!*add_prefix)
 		goto out;
 
-	splice_tree(hash1, add_prefix, hash2, shifted);
+	splice_tree(r, hash1, add_prefix, hash2, shifted);
 
 out:
 	free(add_prefix);
@@ -340,16 +344,16 @@ void shift_tree_by(struct repository *r,
 
 	if (candidate == 3) {
 		/* Both are plausible -- we need to evaluate the score */
-		int best_score = score_trees(hash1, hash2);
+		int best_score = score_trees(r, hash1, hash2);
 		int score;
 
 		candidate = 0;
-		score = score_trees(&sub1, hash2);
+		score = score_trees(r, &sub1, hash2);
 		if (score > best_score) {
 			candidate = 1;
 			best_score = score;
 		}
-		score = score_trees(&sub2, hash1);
+		score = score_trees(r, &sub2, hash1);
 		if (score > best_score)
 			candidate = 2;
 	}
@@ -365,7 +369,7 @@ void shift_tree_by(struct repository *r,
 		 * shift tree2 down by adding shift_prefix above it
 		 * to match tree1.
 		 */
-		splice_tree(hash1, shift_prefix, hash2, shifted);
+		splice_tree(r, hash1, shift_prefix, hash2, shifted);
 	else
 		/*
 		 * shift tree2 up by removing shift_prefix from it
diff --git a/merge-recursive.c b/merge-recursive.c
index 5dfaf32..884ccf9 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -2758,23 +2758,22 @@ static int process_renames(struct merge_options *opt,
 	const struct rename *sre;
 
 	/*
-	 * FIXME: As string-list.h notes, it's O(n^2) to build a sorted
-	 * string_list one-by-one, but O(n log n) to build it unsorted and
-	 * then sort it.  Note that as we build the list, we do not need to
-	 * check if the existing destination path is already in the list,
-	 * because the structure of diffcore_rename guarantees we won't
-	 * have duplicates.
+	 * Note that as we build the list, we do not need to check if the
+	 * existing destination path is already in the list, because the
+	 * structure of diffcore_rename guarantees we won't have duplicates.
 	 */
 	for (i = 0; i < a_renames->nr; i++) {
 		sre = a_renames->items[i].util;
-		string_list_insert(&a_by_dst, sre->pair->two->path)->util
+		string_list_append(&a_by_dst, sre->pair->two->path)->util
 			= (void *)sre;
 	}
 	for (i = 0; i < b_renames->nr; i++) {
 		sre = b_renames->items[i].util;
-		string_list_insert(&b_by_dst, sre->pair->two->path)->util
+		string_list_append(&b_by_dst, sre->pair->two->path)->util
 			= (void *)sre;
 	}
+	string_list_sort(&a_by_dst);
+	string_list_sort(&b_by_dst);
 
 	for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) {
 		struct string_list *renames1, *renames2Dst;
diff --git a/meson.build b/meson.build
index 0064eb6..efe2871 100644
--- a/meson.build
+++ b/meson.build
@@ -170,36 +170,50 @@
 
 project('git', 'c',
   meson_version: '>=0.61.0',
-  version: 'v2.47.GIT',
+  # The version is only of cosmetic nature, so if we cannot find a shell yet we
+  # simply don't set up a version at all. This may be the case for example on
+  # Windows systems, where we first have to bootstrap the host environment.
+  version: find_program('sh', required: false).found() ? run_command(
+    'GIT-VERSION-GEN', meson.current_source_dir(), '--format=@GIT_VERSION@',
+    capture: true,
+    check: true,
+  ).stdout().strip() : 'unknown',
+  default_options: [
+    # Git requires C99 with GNU extensions, which of course isn't supported by
+    # MSVC. Funny enough, C99 doesn't work with MSVC either, as it has only
+    # learned to define __STDC_VERSION__ with C11 and later. We thus require
+    # GNU C99 and fall back to C11. Meson only learned to handle the fallback
+    # with version 1.3.0, so on older versions we use GNU C99 unconditionally.
+    'c_std=' + (meson.version().version_compare('>=1.3.0') ? 'gnu99,c11' : 'gnu99'),
+  ],
 )
 
 fs = import('fs')
 
 program_path = []
-# Git for Windows provides all the tools we need to build Git.
-if host_machine.system() == 'windows'
-  program_path += [ 'C:/Program Files/Git/bin', 'C:/Program Files/Git/usr/bin' ]
+if get_option('sane_tool_path').length() != 0
+  program_path = get_option('sane_tool_path')
+elif host_machine.system() == 'windows'
+  # Git for Windows provides all the tools we need to build Git.
+  program_path = [ 'C:/Program Files/Git/bin', 'C:/Program Files/Git/usr/bin' ]
 endif
 
 cygpath = find_program('cygpath', dirs: program_path, required: false)
 diff = find_program('diff', dirs: program_path)
+git = find_program('git', dirs: program_path, required: false)
+sed = find_program('sed', dirs: program_path)
 shell = find_program('sh', dirs: program_path)
 tar = find_program('tar', dirs: program_path)
 
-script_environment = environment()
-foreach tool : ['cat', 'cut', 'grep', 'sed', 'sort', 'tr', 'uname']
-  program = find_program(tool, dirs: program_path)
-  script_environment.prepend('PATH', fs.parent(program.full_path()))
+# Sanity-check that programs required for the build exist.
+foreach tool : ['cat', 'cut', 'grep', 'sort', 'tr', 'uname']
+  find_program(tool, dirs: program_path)
 endforeach
 
-git = find_program('git', dirs: program_path, required: false)
-if git.found()
-  script_environment.prepend('PATH', fs.parent(git.full_path()))
-endif
-
-if get_option('sane_tool_path') != ''
-  script_environment.prepend('PATH', get_option('sane_tool_path'))
-endif
+script_environment = environment()
+foreach path : program_path
+  script_environment.prepend('PATH', path)
+endforeach
 
 # The environment used by GIT-VERSION-GEN. Note that we explicitly override
 # environment variables that might be set by the user. This is by design so
@@ -245,10 +259,11 @@
   'commit-graph.c',
   'commit-reach.c',
   'commit.c',
+  'common-exit.c',
+  'common-init.c',
   'compat/nonblock.c',
   'compat/obstack.c',
   'compat/terminal.c',
-  'compat/zlib-uncompress2.c',
   'config.c',
   'connect.c',
   'connected.c',
@@ -358,6 +373,7 @@
   'patch-delta.c',
   'patch-ids.c',
   'path.c',
+  'path-walk.c',
   'pathspec.c',
   'pkt-line.c',
   'preload-index.c',
@@ -462,6 +478,7 @@
   'userdiff.c',
   'utf8.c',
   'varint.c',
+  'version.c',
   'versioncmp.c',
   'walker.c',
   'wildmatch.c',
@@ -480,12 +497,20 @@
   'xdiff/xutils.c',
 ]
 
+libgit_sources += custom_target(
+  input: 'command-list.txt',
+  output: 'command-list.h',
+  command: [shell, meson.current_source_dir() + '/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],
+  env: script_environment,
+)
+
 builtin_sources = [
   'builtin/add.c',
   'builtin/am.c',
   'builtin/annotate.c',
   'builtin/apply.c',
   'builtin/archive.c',
+  'builtin/backfill.c',
   'builtin/bisect.c',
   'builtin/blame.c',
   'builtin/branch.c',
@@ -607,14 +632,7 @@
   'builtin/write-tree.c',
 ]
 
-libgit_sources += custom_target(
-  input: 'command-list.txt',
-  output: 'command-list.h',
-  command: [shell, meson.current_source_dir() + '/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'],
-  env: script_environment,
-)
-
-libgit_sources += custom_target(
+builtin_sources += custom_target(
   output: 'config-list.h',
   command: [
     shell,
@@ -625,8 +643,8 @@
   env: script_environment,
 )
 
-libgit_sources += custom_target(
-  input: 'Documentation/githooks.txt',
+builtin_sources += custom_target(
+  input: 'Documentation/githooks.adoc',
   output: 'hook-list.h',
   command: [
     shell,
@@ -650,12 +668,19 @@
 build_options_config.set('GIT_TEST_INDEX_VERSION', '')
 build_options_config.set('GIT_TEST_OPTS', '')
 build_options_config.set('GIT_TEST_PERL_FATAL_WARNINGS', '')
-build_options_config.set('GIT_TEST_UTF8_LOCALE', '')
+build_options_config.set_quoted('GIT_TEST_UTF8_LOCALE', get_option('test_utf8_locale'))
 build_options_config.set_quoted('LOCALEDIR', fs.as_posix(get_option('prefix') / get_option('localedir')))
 build_options_config.set('GITWEBDIR', fs.as_posix(get_option('prefix') / get_option('datadir') / 'gitweb'))
 
-if get_option('sane_tool_path') != ''
-  build_options_config.set_quoted('BROKEN_PATH_FIX', 's|^\# @BROKEN_PATH_FIX@$|git_broken_path_fix "' + get_option('sane_tool_path') + '"|')
+if get_option('breaking_changes')
+  build_options_config.set('WITH_BREAKING_CHANGES', 'YesPlease')
+else
+  build_options_config.set('WITH_BREAKING_CHANGES', '')
+endif
+
+if get_option('sane_tool_path').length() != 0
+  sane_tool_path = (host_machine.system() == 'windows' ? ';' : ':').join(get_option('sane_tool_path'))
+  build_options_config.set_quoted('BROKEN_PATH_FIX', 's|^\# @BROKEN_PATH_FIX@$|git_broken_path_fix "' + sane_tool_path + '"|')
 else
   build_options_config.set_quoted('BROKEN_PATH_FIX', '/^\# @BROKEN_PATH_FIX@$/d')
 endif
@@ -675,7 +700,6 @@
   '-DETC_GITATTRIBUTES="' + get_option('gitattributes') + '"',
   '-DETC_GITCONFIG="' + get_option('gitconfig') + '"',
   '-DFALLBACK_RUNTIME_PREFIX="' + get_option('prefix') + '"',
-  '-DGIT_EXEC_PATH="' + get_option('prefix') / get_option('libexecdir') / 'git-core"',
   '-DGIT_HOST_CPU="' + host_machine.cpu_family() + '"',
   '-DGIT_HTML_PATH="' + get_option('datadir') / 'doc/git-doc"',
   '-DGIT_INFO_PATH="' + get_option('infodir') + '"',
@@ -708,7 +732,6 @@
     # These are disabled because we have these all over the place.
     '-Wno-empty-body',
     '-Wno-missing-field-initializers',
-    '-Wno-sign-compare',
   ]
     if compiler.has_argument(cflag)
       libgit_c_args += cflag
@@ -749,13 +772,28 @@
 # features. It is optional if you want to neither execute tests nor use any of
 # these optional features.
 perl_required = get_option('perl')
-if get_option('tests') or get_option('gitweb').enabled()
+if get_option('tests') or get_option('gitweb').enabled() or 'netrc' in get_option('credential_helpers')
   perl_required = true
 endif
 
 # Note that we only set NO_PERL if the Perl features were disabled by the user.
 # It may not be set when we have found Perl, but only use it to run tests.
-perl = find_program('perl', version: '>=5.8.1', dirs: program_path, required: perl_required)
+#
+# At the time of writing, executing `perl --version` results in a string
+# similar to the following output:
+#
+#     This is perl 5, version 40, subversion 0 (v5.40.0) built for x86_64-linux-thread-multi
+#
+# Meson picks up the "40" as version number instead of using "v5.40.0"
+# due to the regular expression it uses. This got fixed in Meson 1.7.0,
+# but meanwhile we have to either use `-V:version` instead of `--version`,
+# which we can do starting with Meson 1.5.0 and newer, or we have to
+# match against the minor version.
+if meson.version().version_compare('>=1.5.0')
+  perl = find_program('perl', dirs: program_path, required: perl_required, version: '>=5.26.0', version_argument: '-V:version')
+else
+  perl = find_program('perl', dirs: program_path, required: perl_required, version: '>=26')
+endif
 perl_features_enabled = perl.found() and get_option('perl').allowed()
 if perl_features_enabled
   build_options_config.set('NO_PERL', '')
@@ -778,11 +816,23 @@
   build_options_config.set('NO_PERL_CPAN_FALLBACKS', '')
 endif
 
-zlib = dependency('zlib', default_options: ['default_library=static', 'tests=disabled'])
-if zlib.version().version_compare('<1.2.0')
-  libgit_c_args += '-DNO_DEFLATE_BOUND'
+zlib_backend = get_option('zlib_backend')
+if zlib_backend in ['auto', 'zlib-ng']
+  zlib_ng = dependency('zlib-ng', required: zlib_backend == 'zlib-ng')
+  if zlib_ng.found()
+    zlib_backend = 'zlib-ng'
+    libgit_c_args += '-DHAVE_ZLIB_NG'
+    libgit_dependencies += zlib_ng
+  endif
 endif
-libgit_dependencies += zlib
+if zlib_backend in ['auto', 'zlib']
+  zlib = dependency('zlib', default_options: ['default_library=static', 'tests=disabled'])
+  if zlib.version().version_compare('<1.2.0')
+    libgit_c_args += '-DNO_DEFLATE_BOUND'
+  endif
+  zlib_backend = 'zlib'
+  libgit_dependencies += zlib
+endif
 
 threads = dependency('threads', required: false)
 if threads.found()
@@ -913,7 +963,9 @@
     use_curl_for_imap_send = true
   endif
 
-  libgit_dependencies += curl
+  # Most executables don't have to link against libcurl, but we still need its
+  # include directories so that we can resolve LIBCURL_VERSION in "help.c".
+  libgit_dependencies += curl.partial_dependency(includes: true)
   libgit_c_args += '-DCURL_DISABLE_TYPECHECK'
   build_options_config.set('NO_CURL', '')
 else
@@ -1057,11 +1109,11 @@
   libgit_sources += [
     'compat/mingw.c',
     'compat/winansi.c',
+    'compat/win32/dirent.c',
     'compat/win32/flush.c',
     'compat/win32/path-utils.c',
     'compat/win32/pthread.c',
     'compat/win32/syslog.c',
-    'compat/win32/dirent.c',
     'compat/win32mmap.c',
     'compat/nedmalloc/nedmalloc.c',
   ]
@@ -1325,16 +1377,24 @@
   libgit_c_args += '-DHAVE_DEV_TTY'
 endif
 
+csprng_backend = get_option('csprng_backend')
 https_backend = get_option('https_backend')
+sha1_backend = get_option('sha1_backend')
+sha1_unsafe_backend = get_option('sha1_unsafe_backend')
+sha256_backend = get_option('sha256_backend')
 
-security_framework = dependency('Security', required: https_backend == 'CommonCrypto')
+security_framework = dependency('Security', required: 'CommonCrypto' in [https_backend, sha1_backend, sha1_unsafe_backend])
 core_foundation_framework = dependency('CoreFoundation', required: security_framework.found())
 if https_backend == 'auto' and security_framework.found()
   https_backend = 'CommonCrypto'
 endif
 
-openssl_required = https_backend == 'openssl' or get_option('sha1_backend') == 'openssl' or get_option('sha256_backend') == 'openssl'
-openssl = dependency('openssl', required: openssl_required, default_options: ['default_library=static'])
+openssl_required = 'openssl' in [csprng_backend, https_backend, sha1_backend, sha1_unsafe_backend, sha256_backend]
+openssl = dependency('openssl',
+  required: openssl_required,
+  allow_fallback: openssl_required or https_backend == 'auto',
+  default_options: ['default_library=static'],
+)
 if https_backend == 'auto' and openssl.found()
   https_backend = 'openssl'
 endif
@@ -1348,13 +1408,13 @@
 else
   # We either couldn't find any dependencies with 'auto' or the user requested
   # 'none'. Both cases are benign.
+  https_backend = 'none'
 endif
 
 if https_backend != 'openssl'
   libgit_c_args += '-DNO_OPENSSL'
 endif
 
-sha1_backend = get_option('sha1_backend')
 if sha1_backend == 'sha1dc'
   libgit_c_args += '-DSHA1_DC'
   libgit_c_args += '-DSHA1DC_NO_STANDARD_INCLUDES=1'
@@ -1367,22 +1427,40 @@
     'sha1dc/sha1.c',
     'sha1dc/ubc_check.c',
   ]
-elif sha1_backend == 'common-crypto'
+endif
+if sha1_backend == 'CommonCrypto' or sha1_unsafe_backend == 'CommonCrypto'
+  if sha1_backend == 'CommonCrypto'
+    libgit_c_args += '-DSHA1_APPLE'
+  endif
+  if sha1_unsafe_backend == 'CommonCrypto'
+    libgit_c_args += '-DSHA1_APPLE_UNSAFE'
+  endif
+
   libgit_c_args += '-DCOMMON_DIGEST_FOR_OPENSSL'
-  libgit_c_args += '-DSHA1_APPLE'
   # Apple CommonCrypto requires chunking
   libgit_c_args += '-DSHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L'
-elif sha1_backend == 'openssl'
-  libgit_c_args += '-DSHA1_OPENSSL'
+endif
+if sha1_backend == 'openssl' or sha1_unsafe_backend == 'openssl'
+  if sha1_backend == 'openssl'
+    libgit_c_args += '-DSHA1_OPENSSL'
+  endif
+  if sha1_unsafe_backend == 'openssl'
+    libgit_c_args += '-DSHA1_OPENSSL_UNSAFE'
+  endif
+
   libgit_dependencies += openssl
-elif sha1_backend == 'block'
-  libgit_c_args += '-DSHA1_BLK'
+endif
+if sha1_backend == 'block' or sha1_unsafe_backend == 'block'
+  if sha1_backend == 'block'
+    libgit_c_args += '-DSHA1_BLK'
+  endif
+  if sha1_unsafe_backend == 'block'
+    libgit_c_args += '-DSHA1_BLK_UNSAFE'
+  endif
+
   libgit_sources += 'block-sha1/sha1.c'
-else
-  error('Unhandled SHA1 backend ' + sha1_backend)
 endif
 
-sha256_backend = get_option('sha256_backend')
 if sha256_backend == 'openssl'
   libgit_c_args += '-DSHA256_OPENSSL'
   libgit_dependencies += openssl
@@ -1401,23 +1479,36 @@
   error('Unhandled SHA256 backend ' + sha256_backend)
 endif
 
-if compiler.has_header_symbol('stdlib.h', 'arc4random_buf')
+# Backends are ordered to reflect our preference for more secure and faster
+# ones over the ones that are less so.
+if csprng_backend in ['auto', 'arc4random'] and compiler.has_header_symbol('stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random')
   libgit_c_args += '-DHAVE_ARC4RANDOM'
-elif compiler.has_header_symbol('bsd/stdlib.h', 'arc4random_buf')
+  csprng_backend = 'arc4random'
+elif csprng_backend in ['auto', 'arc4random_bsd'] and compiler.has_header_symbol('bsd/stdlib.h', 'arc4random_buf', required: csprng_backend == 'arc4random_bsd')
   libgit_c_args += '-DHAVE_ARC4RANDOM_BSD'
-elif compiler.has_function('getrandom', prefix: '#include <sys/random.h>')
+  csprng_backend = 'arc4random_bsd'
+elif csprng_backend in ['auto', 'getrandom'] and compiler.has_header_symbol('sys/random.h', 'getrandom', required: csprng_backend == 'getrandom')
   libgit_c_args += '-DHAVE_GETRANDOM'
-elif compiler.has_function('getentropy', prefix: '#include <unistd.h>')
+  csprng_backend = 'getrandom'
+elif csprng_backend in ['auto', 'getentropy'] and compiler.has_header_symbol('unistd.h', 'getentropy', required: csprng_backend == 'getentropy')
   libgit_c_args += '-DHAVE_GETENTROPY'
-elif compiler.has_function('RtlGenRandom', prefix: '#include <windows.h>\n#include <ntsecapi.h>')
+  csprng_backend = 'getentropy'
+elif csprng_backend in ['auto', 'rtlgenrandom'] and compiler.has_header_symbol('ntsecapi.h', 'RtlGenRandom', prefix: '#include <windows.h>', required: csprng_backend == 'rtlgenrandom')
   libgit_c_args += '-DHAVE_RTLGENRANDOM'
-elif openssl.found()
+  csprng_backend = 'rtlgenrandom'
+elif csprng_backend in ['auto', 'openssl'] and openssl.found()
   libgit_c_args += '-DHAVE_OPENSSL_CSPRNG'
+  csprng_backend = 'openssl'
+elif csprng_backend in ['auto', 'urandom']
+  csprng_backend = 'urandom'
+else
+  error('Unsupported CSPRNG backend: ' + csprng_backend)
 endif
 
 if get_option('runtime_prefix')
   libgit_c_args += '-DRUNTIME_PREFIX'
   build_options_config.set('RUNTIME_PREFIX', 'true')
+  git_exec_path = get_option('libexecdir') / 'git-core'
 
   if compiler.has_header('mach-o/dyld.h')
     libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH'
@@ -1454,7 +1545,9 @@
   endif
 else
   build_options_config.set('RUNTIME_PREFIX', 'false')
+  git_exec_path = get_option('prefix') / get_option('libexecdir') / 'git-core'
 endif
+libgit_c_args += '-DGIT_EXEC_PATH="' + git_exec_path + '"'
 
 git_version_file = custom_target(
   command: [
@@ -1485,30 +1578,18 @@
   depends: [git_version_file],
   env: version_gen_environment,
 )
-
-# Build a separate library for "version.c" so that we do not have to rebuild
-# everything when the current Git commit changes.
-libgit_version_library = static_library('git-version',
-  sources: [
-    'version.c',
-    version_def_h,
-  ],
-  c_args: libgit_c_args,
-  dependencies: libgit_dependencies,
-  include_directories: libgit_include_directories,
-)
-
-libgit_library = static_library('git',
-  sources: libgit_sources,
-  c_args: libgit_c_args,
-  link_with: libgit_version_library,
-  dependencies: libgit_dependencies,
-  include_directories: libgit_include_directories,
-)
+libgit_sources += version_def_h
 
 libgit = declare_dependency(
+  link_with: static_library('git',
+    sources: libgit_sources,
+    c_args: libgit_c_args + [
+      '-DGIT_VERSION_H="' + version_def_h.full_path() + '"',
+    ],
+    dependencies: libgit_dependencies,
+    include_directories: libgit_include_directories,
+  ),
   compile_args: libgit_c_args,
-  link_with: libgit_library,
   dependencies: libgit_dependencies,
   include_directories: libgit_include_directories,
 )
@@ -1549,88 +1630,89 @@
     error('Unsupported compiler ' + compiler.get_id())
   endif
 endif
-common_main_library = static_library('common-main',
-  sources: common_main_sources,
-  c_args: libgit_c_args,
-  dependencies: libgit_dependencies,
-  include_directories: libgit_include_directories,
-)
-common_main = declare_dependency(
-  link_with: common_main_library,
+
+libgit_commonmain = declare_dependency(
+  link_with: static_library('common-main',
+    sources: common_main_sources,
+    dependencies: [ libgit ],
+  ),
   link_args: common_main_link_args,
+  dependencies: [ libgit ],
 )
 
 bin_wrappers = [ ]
 test_dependencies = [ ]
 
-git = executable('git',
+git_builtin = executable('git',
   sources: builtin_sources + 'git.c',
-  dependencies: [libgit, common_main],
+  dependencies: [libgit_commonmain],
   install: true,
   install_dir: get_option('libexecdir') / 'git-core',
 )
-bin_wrappers += git
+bin_wrappers += git_builtin
 
 test_dependencies += executable('git-daemon',
   sources: 'daemon.c',
-  dependencies: [libgit, common_main],
+  dependencies: [libgit_commonmain],
   install: true,
   install_dir: get_option('libexecdir') / 'git-core',
 )
 
 test_dependencies += executable('git-sh-i18n--envsubst',
   sources: 'sh-i18n--envsubst.c',
-  dependencies: [libgit, common_main],
+  dependencies: [libgit_commonmain],
   install: true,
   install_dir: get_option('libexecdir') / 'git-core',
 )
 
 bin_wrappers += executable('git-shell',
   sources: 'shell.c',
-  dependencies: [libgit, common_main],
+  dependencies: [libgit_commonmain],
   install: true,
   install_dir: get_option('libexecdir') / 'git-core',
 )
 
 test_dependencies += executable('git-http-backend',
   sources: 'http-backend.c',
-  dependencies: [libgit, common_main],
+  dependencies: [libgit_commonmain],
   install: true,
   install_dir: get_option('libexecdir') / 'git-core',
 )
 
 bin_wrappers += executable('scalar',
   sources: 'scalar.c',
-  dependencies: [libgit, common_main],
+  dependencies: [libgit_commonmain],
   install: true,
   install_dir: get_option('libexecdir') / 'git-core',
 )
 
 if get_option('curl').enabled()
-  curl_sources = [
-    'http.c',
-    'http-walker.c',
-  ]
+  libgit_curl = declare_dependency(
+    sources: [
+      'http.c',
+      'http-walker.c',
+    ],
+    dependencies: [libgit_commonmain, curl],
+  )
 
-  git_remote_http = executable('git-remote-http',
-    sources: curl_sources + 'remote-curl.c',
-    dependencies: [libgit, common_main],
+  test_dependencies += executable('git-remote-http',
+    sources: 'remote-curl.c',
+    dependencies: [libgit_curl],
     install: true,
     install_dir: get_option('libexecdir') / 'git-core',
   )
-  test_dependencies += git_remote_http
 
   test_dependencies += executable('git-http-fetch',
-    sources: curl_sources + 'http-fetch.c',
-    dependencies: [libgit, common_main],
+    sources: 'http-fetch.c',
+    dependencies: [libgit_curl],
     install: true,
     install_dir: get_option('libexecdir') / 'git-core',
   )
 
   if expat.found()
     test_dependencies += executable('git-http-push',
-      sources: curl_sources + 'http-push.c',
-      dependencies: [libgit, common_main],
+      sources: 'http-push.c',
+      dependencies: [libgit_curl],
       install: true,
       install_dir: get_option('libexecdir') / 'git-core',
     )
@@ -1638,8 +1720,8 @@
 
   foreach alias : [ 'git-remote-https', 'git-remote-ftp', 'git-remote-ftps' ]
     test_dependencies += executable(alias,
-      objects: git_remote_http.extract_all_objects(recursive: false),
-      dependencies: [libgit, common_main],
+      sources: 'remote-curl.c',
+      dependencies: [libgit_curl],
     )
 
     install_symlink(alias + executable_suffix,
@@ -1649,22 +1731,17 @@
   endforeach
 endif
 
-imap_send_sources = ['imap-send.c']
-if use_curl_for_imap_send
-  imap_send_sources += curl_sources
-endif
-
 test_dependencies += executable('git-imap-send',
-  sources: imap_send_sources,
-  dependencies: [libgit, common_main],
+  sources: 'imap-send.c',
+  dependencies: [ use_curl_for_imap_send ? libgit_curl : libgit_commonmain ],
   install: true,
   install_dir: get_option('libexecdir') / 'git-core',
 )
 
 foreach alias : [ 'git-receive-pack', 'git-upload-archive', 'git-upload-pack' ]
   bin_wrappers += executable(alias,
-    objects: git.extract_all_objects(recursive: false),
-    dependencies: [libgit, common_main],
+    objects: git_builtin.extract_all_objects(recursive: false),
+    dependencies: [libgit_commonmain],
   )
 
   install_symlink(alias + executable_suffix,
@@ -1857,7 +1934,6 @@
 if intl.found()
   subdir('po')
 endif
-subdir('contrib')
 
 # Gitweb requires Perl, so we disable the auto-feature if Perl was not found.
 # We make sure further up that Perl is required in case the gitweb option is
@@ -1879,17 +1955,22 @@
   subdir('t')
 endif
 
+if get_option('fuzzers')
+  subdir('oss-fuzz')
+endif
+
 subdir('bin-wrappers')
 if get_option('docs') != []
   subdir('Documentation')
 endif
 
+subdir('contrib')
+
 foreach key, value : {
   'DIFF': diff.full_path(),
+  'GIT_SOURCE_DIR': meson.project_source_root(),
   'GIT_TEST_CMP': diff.full_path() + ' -u',
   'GIT_TEST_GITPERLLIB': meson.project_build_root() / 'perl',
-  'GIT_TEST_MERGE_TOOLS_DIR': meson.project_source_root() / 'mergetools',
-  'GIT_TEST_POPATH': meson.project_source_root() / 'po',
   'GIT_TEST_TEMPLATE_DIR': meson.project_build_root() / 'templates',
   'GIT_TEST_TEXTDOMAINDIR': meson.project_build_root() / 'po',
   'PAGER_ENV': get_option('pager_environment'),
@@ -1912,6 +1993,27 @@
   configuration: build_options_config,
 )
 
+# Development environments can be used via `meson devenv -C <builddir>`. This
+# allows you to execute test scripts directly with the built Git version and
+# puts the built version of Git in your PATH.
+devenv = environment()
+devenv.set('GIT_BUILD_DIR', meson.current_build_dir())
+devenv.prepend('PATH', meson.current_build_dir() / 'bin-wrappers')
+meson.add_devenv(devenv)
+
+# Generate the 'version' file in the distribution tarball. This is used via
+# `meson dist -C <builddir>` to populate the source archive with the Git
+# version that the archive is being generated from.
+meson.add_dist_script(
+  shell,
+  '-c',
+  '"$1" "$2" "$3" --format="@GIT_VERSION@" "$MESON_DIST_ROOT/version"',
+  'GIT-VERSION-GEN',
+  shell,
+  meson.current_source_dir() / 'GIT-VERSION-GEN',
+  meson.current_source_dir(),
+)
+
 summary({
   'curl': curl.found(),
   'expat': expat.found(),
@@ -1923,3 +2025,12 @@
   'perl': perl_features_enabled,
   'python': python.found(),
 }, section: 'Auto-detected features')
+
+summary({
+  'csprng': csprng_backend,
+  'https': https_backend,
+  'sha1': sha1_backend,
+  'sha1_unsafe': sha1_unsafe_backend,
+  'sha256': sha256_backend,
+  'zlib': zlib_backend,
+}, section: 'Backends')
diff --git a/meson_options.txt b/meson_options.txt
index f50bb40..78d172a 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -13,8 +13,8 @@
   description: 'Install bundled copies of CPAN modules that serve as a fallback in case the modules are not available on the system.')
 option('runtime_prefix', type: 'boolean', value: false,
   description: 'Resolve ancillary tooling and support files relative to the location of the runtime binary instead of hard-coding them into the binary.')
-option('sane_tool_path', type: 'string', value: '',
-  description: 'A colon-separated list of paths to prepend to PATH if your tools in /usr/bin are broken.')
+option('sane_tool_path', type: 'array', value: [],
+  description: 'An array of paths to pick up tools from in case the normal tools are broken or lacking.')
 
 # Build information compiled into Git and other parts like documentation.
 option('build_date', type: 'string', value: '',
@@ -27,6 +27,10 @@
   description: 'Version string reported by git-version(1) and other tools.')
 
 # Features supported by Git.
+option('contrib', type: 'array', value: [ 'completion' ], choices: [ 'completion', 'contacts', 'subtree' ],
+  description: 'Contributed features to include.')
+option('credential_helpers', type: 'array', value: [ ], choices: [ 'libsecret', 'netrc', 'osxkeychain', 'wincred' ],
+  description: 'Contributed features to include.')
 option('curl', type: 'feature', value: 'enabled',
   description: 'Build helpers used to access remotes with the HTTP transport.')
 option('expat', type: 'feature', value: 'enabled',
@@ -47,14 +51,22 @@
   description: 'Use the system-provided regex library instead of the bundled one.')
 
 # Backends.
+option('csprng_backend', type: 'combo', value: 'auto', choices: ['auto', 'arc4random', 'arc4random_bsd', 'getrandom', 'getentropy', 'rtlgenrandom', 'openssl', 'urandom'],
+  description: 'The backend to use for generating cryptographically-secure pseudo-random numbers.')
 option('https_backend', type: 'combo', value: 'auto', choices: ['auto', 'openssl', 'CommonCrypto', 'none'],
   description: 'The HTTPS backend to use when connecting to remotes.')
-option('sha1_backend', type: 'combo', choices: ['openssl', 'block', 'sha1dc', 'common-crypto'], value: 'sha1dc',
-  description: 'The backend used for hashing objects with the SHA1 object format')
+option('sha1_backend', type: 'combo', choices: ['openssl', 'block', 'sha1dc', 'CommonCrypto'], value: 'sha1dc',
+  description: 'The backend used for hashing objects with the SHA1 object format.')
+option('sha1_unsafe_backend', type: 'combo', choices: ['openssl', 'block', 'CommonCrypto', 'none'], value: 'none',
+  description: 'The backend used for hashing data with the SHA1 object format in case no cryptographic security is needed.')
 option('sha256_backend', type: 'combo', choices: ['openssl', 'nettle', 'gcrypt', 'block'], value: 'block',
-  description: 'The backend used for hashing objects with the SHA256 object format')
+  description: 'The backend used for hashing objects with the SHA256 object format.')
+option('zlib_backend', type: 'combo', choices: ['auto', 'zlib', 'zlib-ng'], value: 'auto',
+  description: 'The backend used for compressing objects and other data.')
 
 # Build tweaks.
+option('breaking_changes', type: 'boolean', value: false,
+  description: 'Enable upcoming breaking changes.')
 option('macos_use_homebrew_gettext', type: 'boolean', value: true,
   description: 'Use gettext from Homebrew instead of the slightly-broken system-provided one.')
 
@@ -89,7 +101,13 @@
   description: 'Which backend to use to generate documentation.')
 
 # Testing.
+option('coccinelle', type: 'feature', value: 'auto',
+  description: 'Provide a coccicheck target that generates a Coccinelle patch.')
 option('tests', type: 'boolean', value: true,
   description: 'Enable building tests. This requires Perl, but is separate from the "perl" option such that you can build tests without Perl features enabled.')
 option('test_output_directory', type: 'string',
   description: 'Path to the directory used to store test outputs')
+option('test_utf8_locale', type: 'string',
+  description: 'Name of a UTF-8 locale used for testing.')
+option('fuzzers', type: 'boolean', value: false,
+  description: 'Enable building fuzzers.')
diff --git a/midx-write.c b/midx-write.c
index 0066594..48d6558 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -658,8 +658,8 @@ static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash,
 	strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex_algop(midx_hash,
 								    ctx->repo->hash_algo));
 
-	tmp_file = write_rev_file_order(NULL, ctx->pack_order, ctx->entries_nr,
-					midx_hash, WRITE_REV);
+	tmp_file = write_rev_file_order(ctx->repo->hash_algo, NULL, ctx->pack_order,
+					ctx->entries_nr, midx_hash, WRITE_REV);
 
 	if (finalize_object_file(tmp_file, buf.buf))
 		die(_("cannot store reverse index file"));
@@ -1131,7 +1131,8 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
 
 	ctx.pack_paths_checked = 0;
 	if (flags & MIDX_PROGRESS)
-		ctx.progress = start_delayed_progress(_("Adding packfiles to multi-pack-index"), 0);
+		ctx.progress = start_delayed_progress(r,
+						      _("Adding packfiles to multi-pack-index"), 0);
 	else
 		ctx.progress = NULL;
 
@@ -1335,7 +1336,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
 			return -1;
 		}
 
-		if (adjust_shared_perm(get_tempfile_path(incr))) {
+		if (adjust_shared_perm(r, get_tempfile_path(incr))) {
 			error(_("unable to adjust shared permissions for '%s'"),
 			      get_tempfile_path(incr));
 			return -1;
@@ -1539,7 +1540,9 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla
 	CALLOC_ARRAY(count, m->num_packs);
 
 	if (flags & MIDX_PROGRESS)
-		progress = start_delayed_progress(_("Counting referenced objects"),
+		progress = start_delayed_progress(
+					  r,
+					  _("Counting referenced objects"),
 					  m->num_objects);
 	for (i = 0; i < m->num_objects; i++) {
 		int pack_int_id = nth_midxed_pack_int_id(m, i);
@@ -1549,7 +1552,9 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla
 	stop_progress(&progress);
 
 	if (flags & MIDX_PROGRESS)
-		progress = start_delayed_progress(_("Finding and deleting unreferenced packfiles"),
+		progress = start_delayed_progress(
+					  r,
+					  _("Finding and deleting unreferenced packfiles"),
 					  m->num_packs);
 	for (i = 0; i < m->num_packs; i++) {
 		char *pack_name;
diff --git a/midx.c b/midx.c
index f8a75ca..d91088e 100644
--- a/midx.c
+++ b/midx.c
@@ -907,7 +907,8 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
 		midx_report(_("incorrect checksum"));
 
 	if (flags & MIDX_PROGRESS)
-		progress = start_delayed_progress(_("Looking for referenced packfiles"),
+		progress = start_delayed_progress(r,
+						  _("Looking for referenced packfiles"),
 						  m->num_packs + m->num_packs_in_base);
 	for (i = 0; i < m->num_packs + m->num_packs_in_base; i++) {
 		if (prepare_midx_pack(r, m, i))
@@ -927,7 +928,8 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
 	}
 
 	if (flags & MIDX_PROGRESS)
-		progress = start_sparse_progress(_("Verifying OID order in multi-pack-index"),
+		progress = start_sparse_progress(r,
+						 _("Verifying OID order in multi-pack-index"),
 						 m->num_objects - 1);
 
 	for (curr = m; curr; curr = curr->base_midx) {
@@ -959,14 +961,17 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
 	}
 
 	if (flags & MIDX_PROGRESS)
-		progress = start_sparse_progress(_("Sorting objects by packfile"),
+		progress = start_sparse_progress(r,
+						 _("Sorting objects by packfile"),
 						 m->num_objects);
 	display_progress(progress, 0); /* TODO: Measure QSORT() progress */
 	QSORT(pairs, m->num_objects, compare_pair_pos_vs_id);
 	stop_progress(&progress);
 
 	if (flags & MIDX_PROGRESS)
-		progress = start_sparse_progress(_("Verifying object offsets"), m->num_objects);
+		progress = start_sparse_progress(r,
+						 _("Verifying object offsets"),
+						 m->num_objects);
 	for (i = 0; i < m->num_objects + m->num_objects_in_base; i++) {
 		struct object_id oid;
 		struct pack_entry e;
diff --git a/notes-merge.c b/notes-merge.c
index 8d701ed..67a4720 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -275,41 +275,45 @@ static void diff_tree_local(struct notes_merge_options *o,
 
 static void check_notes_merge_worktree(struct notes_merge_options *o)
 {
+	struct strbuf buf = STRBUF_INIT;
+
 	if (!o->has_worktree) {
 		/*
 		 * Must establish NOTES_MERGE_WORKTREE.
 		 * Abort if NOTES_MERGE_WORKTREE already exists
 		 */
-		if (file_exists(git_path(NOTES_MERGE_WORKTREE)) &&
-		    !is_empty_dir(git_path(NOTES_MERGE_WORKTREE))) {
+		if (file_exists(repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE)) &&
+		    !is_empty_dir(repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE))) {
 			if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
 				die(_("You have not concluded your previous "
 				    "notes merge (%s exists).\nPlease, use "
 				    "'git notes merge --commit' or 'git notes "
 				    "merge --abort' to commit/abort the "
 				    "previous merge before you start a new "
-				    "notes merge."), git_path("NOTES_MERGE_*"));
+				    "notes merge."), repo_git_path_replace(the_repository, &buf, "NOTES_MERGE_*"));
 			else
 				die(_("You have not concluded your notes merge "
-				    "(%s exists)."), git_path("NOTES_MERGE_*"));
+				    "(%s exists)."), repo_git_path_replace(the_repository, &buf, "NOTES_MERGE_*"));
 		}
 
-		if (safe_create_leading_directories_const(git_path(
+		if (safe_create_leading_directories_const(repo_git_path_replace(the_repository, &buf,
 				NOTES_MERGE_WORKTREE "/.test")))
 			die_errno("unable to create directory %s",
-				  git_path(NOTES_MERGE_WORKTREE));
+				  repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE));
 		o->has_worktree = 1;
-	} else if (!file_exists(git_path(NOTES_MERGE_WORKTREE)))
+	} else if (!file_exists(repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE)))
 		/* NOTES_MERGE_WORKTREE should already be established */
 		die("missing '%s'. This should not happen",
-		    git_path(NOTES_MERGE_WORKTREE));
+		    repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE));
+
+	strbuf_release(&buf);
 }
 
 static void write_buf_to_worktree(const struct object_id *obj,
 				  const char *buf, unsigned long size)
 {
 	int fd;
-	char *path = git_pathdup(NOTES_MERGE_WORKTREE "/%s", oid_to_hex(obj));
+	char *path = repo_git_path(the_repository, NOTES_MERGE_WORKTREE "/%s", oid_to_hex(obj));
 	if (safe_create_leading_directories_const(path))
 		die_errno("unable to create directory for '%s'", path);
 
@@ -695,7 +699,7 @@ int notes_merge_commit(struct notes_merge_options *o,
 	const char *msg = strstr(buffer, "\n\n");
 	int baselen;
 
-	git_path_buf(&path, NOTES_MERGE_WORKTREE);
+	repo_git_path_replace(the_repository, &path, NOTES_MERGE_WORKTREE);
 	if (o->verbosity >= 3)
 		printf("Committing notes in notes merge worktree at %s\n",
 			path.buf);
@@ -757,7 +761,7 @@ int notes_merge_abort(struct notes_merge_options *o)
 	struct strbuf buf = STRBUF_INIT;
 	int ret;
 
-	git_path_buf(&buf, NOTES_MERGE_WORKTREE);
+	repo_git_path_replace(the_repository, &buf, NOTES_MERGE_WORKTREE);
 	if (o->verbosity >= 3)
 		printf("Removing notes merge worktree at %s/*\n", buf.buf);
 	ret = remove_dir_recursively(&buf, REMOVE_DIR_KEEP_TOPLEVEL);
diff --git a/object-file.c b/object-file.c
index 5b792b3..726e41a 100644
--- a/object-file.c
+++ b/object-file.c
@@ -86,84 +86,90 @@ static const struct object_id null_oid_sha256 = {
 	.algo = GIT_HASH_SHA256,
 };
 
-static void git_hash_sha1_init(git_hash_ctx *ctx)
+static void git_hash_sha1_init(struct git_hash_ctx *ctx)
 {
-	git_SHA1_Init(&ctx->sha1);
+	ctx->algop = &hash_algos[GIT_HASH_SHA1];
+	git_SHA1_Init(&ctx->state.sha1);
 }
 
-static void git_hash_sha1_clone(git_hash_ctx *dst, const git_hash_ctx *src)
+static void git_hash_sha1_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src)
 {
-	git_SHA1_Clone(&dst->sha1, &src->sha1);
+	dst->algop = src->algop;
+	git_SHA1_Clone(&dst->state.sha1, &src->state.sha1);
 }
 
-static void git_hash_sha1_update(git_hash_ctx *ctx, const void *data, size_t len)
+static void git_hash_sha1_update(struct git_hash_ctx *ctx, const void *data, size_t len)
 {
-	git_SHA1_Update(&ctx->sha1, data, len);
+	git_SHA1_Update(&ctx->state.sha1, data, len);
 }
 
-static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx)
+static void git_hash_sha1_final(unsigned char *hash, struct git_hash_ctx *ctx)
 {
-	git_SHA1_Final(hash, &ctx->sha1);
+	git_SHA1_Final(hash, &ctx->state.sha1);
 }
 
-static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)
+static void git_hash_sha1_final_oid(struct object_id *oid, struct git_hash_ctx *ctx)
 {
-	git_SHA1_Final(oid->hash, &ctx->sha1);
+	git_SHA1_Final(oid->hash, &ctx->state.sha1);
 	memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);
 	oid->algo = GIT_HASH_SHA1;
 }
 
-static void git_hash_sha1_init_unsafe(git_hash_ctx *ctx)
+static void git_hash_sha1_init_unsafe(struct git_hash_ctx *ctx)
 {
-	git_SHA1_Init_unsafe(&ctx->sha1_unsafe);
+	ctx->algop = unsafe_hash_algo(&hash_algos[GIT_HASH_SHA1]);
+	git_SHA1_Init_unsafe(&ctx->state.sha1_unsafe);
 }
 
-static void git_hash_sha1_clone_unsafe(git_hash_ctx *dst, const git_hash_ctx *src)
+static void git_hash_sha1_clone_unsafe(struct git_hash_ctx *dst, const struct git_hash_ctx *src)
 {
-	git_SHA1_Clone_unsafe(&dst->sha1_unsafe, &src->sha1_unsafe);
+	dst->algop = src->algop;
+	git_SHA1_Clone_unsafe(&dst->state.sha1_unsafe, &src->state.sha1_unsafe);
 }
 
-static void git_hash_sha1_update_unsafe(git_hash_ctx *ctx, const void *data,
+static void git_hash_sha1_update_unsafe(struct git_hash_ctx *ctx, const void *data,
 				      size_t len)
 {
-	git_SHA1_Update_unsafe(&ctx->sha1_unsafe, data, len);
+	git_SHA1_Update_unsafe(&ctx->state.sha1_unsafe, data, len);
 }
 
-static void git_hash_sha1_final_unsafe(unsigned char *hash, git_hash_ctx *ctx)
+static void git_hash_sha1_final_unsafe(unsigned char *hash, struct git_hash_ctx *ctx)
 {
-	git_SHA1_Final_unsafe(hash, &ctx->sha1_unsafe);
+	git_SHA1_Final_unsafe(hash, &ctx->state.sha1_unsafe);
 }
 
-static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, git_hash_ctx *ctx)
+static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, struct git_hash_ctx *ctx)
 {
-	git_SHA1_Final_unsafe(oid->hash, &ctx->sha1_unsafe);
+	git_SHA1_Final_unsafe(oid->hash, &ctx->state.sha1_unsafe);
 	memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);
 	oid->algo = GIT_HASH_SHA1;
 }
 
-static void git_hash_sha256_init(git_hash_ctx *ctx)
+static void git_hash_sha256_init(struct git_hash_ctx *ctx)
 {
-	git_SHA256_Init(&ctx->sha256);
+	ctx->algop = unsafe_hash_algo(&hash_algos[GIT_HASH_SHA256]);
+	git_SHA256_Init(&ctx->state.sha256);
 }
 
-static void git_hash_sha256_clone(git_hash_ctx *dst, const git_hash_ctx *src)
+static void git_hash_sha256_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src)
 {
-	git_SHA256_Clone(&dst->sha256, &src->sha256);
+	dst->algop = src->algop;
+	git_SHA256_Clone(&dst->state.sha256, &src->state.sha256);
 }
 
-static void git_hash_sha256_update(git_hash_ctx *ctx, const void *data, size_t len)
+static void git_hash_sha256_update(struct git_hash_ctx *ctx, const void *data, size_t len)
 {
-	git_SHA256_Update(&ctx->sha256, data, len);
+	git_SHA256_Update(&ctx->state.sha256, data, len);
 }
 
-static void git_hash_sha256_final(unsigned char *hash, git_hash_ctx *ctx)
+static void git_hash_sha256_final(unsigned char *hash, struct git_hash_ctx *ctx)
 {
-	git_SHA256_Final(hash, &ctx->sha256);
+	git_SHA256_Final(hash, &ctx->state.sha256);
 }
 
-static void git_hash_sha256_final_oid(struct object_id *oid, git_hash_ctx *ctx)
+static void git_hash_sha256_final_oid(struct object_id *oid, struct git_hash_ctx *ctx)
 {
-	git_SHA256_Final(oid->hash, &ctx->sha256);
+	git_SHA256_Final(oid->hash, &ctx->state.sha256);
 	/*
 	 * This currently does nothing, so the compiler should optimize it out,
 	 * but keep it in case we extend the hash size again.
@@ -172,18 +178,18 @@ static void git_hash_sha256_final_oid(struct object_id *oid, git_hash_ctx *ctx)
 	oid->algo = GIT_HASH_SHA256;
 }
 
-static void git_hash_unknown_init(git_hash_ctx *ctx UNUSED)
+static void git_hash_unknown_init(struct git_hash_ctx *ctx UNUSED)
 {
 	BUG("trying to init unknown hash");
 }
 
-static void git_hash_unknown_clone(git_hash_ctx *dst UNUSED,
-				   const git_hash_ctx *src UNUSED)
+static void git_hash_unknown_clone(struct git_hash_ctx *dst UNUSED,
+				   const struct git_hash_ctx *src UNUSED)
 {
 	BUG("trying to clone unknown hash");
 }
 
-static void git_hash_unknown_update(git_hash_ctx *ctx UNUSED,
+static void git_hash_unknown_update(struct git_hash_ctx *ctx UNUSED,
 				    const void *data UNUSED,
 				    size_t len UNUSED)
 {
@@ -191,17 +197,33 @@ static void git_hash_unknown_update(git_hash_ctx *ctx UNUSED,
 }
 
 static void git_hash_unknown_final(unsigned char *hash UNUSED,
-				   git_hash_ctx *ctx UNUSED)
+				   struct git_hash_ctx *ctx UNUSED)
 {
 	BUG("trying to finalize unknown hash");
 }
 
 static void git_hash_unknown_final_oid(struct object_id *oid UNUSED,
-				       git_hash_ctx *ctx UNUSED)
+				       struct git_hash_ctx *ctx UNUSED)
 {
 	BUG("trying to finalize unknown hash");
 }
 
+static const struct git_hash_algo sha1_unsafe_algo = {
+	.name = "sha1",
+	.format_id = GIT_SHA1_FORMAT_ID,
+	.rawsz = GIT_SHA1_RAWSZ,
+	.hexsz = GIT_SHA1_HEXSZ,
+	.blksz = GIT_SHA1_BLKSZ,
+	.init_fn = git_hash_sha1_init_unsafe,
+	.clone_fn = git_hash_sha1_clone_unsafe,
+	.update_fn = git_hash_sha1_update_unsafe,
+	.final_fn = git_hash_sha1_final_unsafe,
+	.final_oid_fn = git_hash_sha1_final_oid_unsafe,
+	.empty_tree = &empty_tree_oid,
+	.empty_blob = &empty_blob_oid,
+	.null_oid = &null_oid_sha1,
+};
+
 const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
 	{
 		.name = NULL,
@@ -214,11 +236,6 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
 		.update_fn = git_hash_unknown_update,
 		.final_fn = git_hash_unknown_final,
 		.final_oid_fn = git_hash_unknown_final_oid,
-		.unsafe_init_fn = git_hash_unknown_init,
-		.unsafe_clone_fn = git_hash_unknown_clone,
-		.unsafe_update_fn = git_hash_unknown_update,
-		.unsafe_final_fn = git_hash_unknown_final,
-		.unsafe_final_oid_fn = git_hash_unknown_final_oid,
 		.empty_tree = NULL,
 		.empty_blob = NULL,
 		.null_oid = NULL,
@@ -234,11 +251,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
 		.update_fn = git_hash_sha1_update,
 		.final_fn = git_hash_sha1_final,
 		.final_oid_fn = git_hash_sha1_final_oid,
-		.unsafe_init_fn = git_hash_sha1_init_unsafe,
-		.unsafe_clone_fn = git_hash_sha1_clone_unsafe,
-		.unsafe_update_fn = git_hash_sha1_update_unsafe,
-		.unsafe_final_fn = git_hash_sha1_final_unsafe,
-		.unsafe_final_oid_fn = git_hash_sha1_final_oid_unsafe,
+		.unsafe = &sha1_unsafe_algo,
 		.empty_tree = &empty_tree_oid,
 		.empty_blob = &empty_blob_oid,
 		.null_oid = &null_oid_sha1,
@@ -254,11 +267,6 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
 		.update_fn = git_hash_sha256_update,
 		.final_fn = git_hash_sha256_final,
 		.final_oid_fn = git_hash_sha256_final_oid,
-		.unsafe_init_fn = git_hash_sha256_init,
-		.unsafe_clone_fn = git_hash_sha256_clone,
-		.unsafe_update_fn = git_hash_sha256_update,
-		.unsafe_final_fn = git_hash_sha256_final,
-		.unsafe_final_oid_fn = git_hash_sha256_final_oid,
 		.empty_tree = &empty_tree_oid_sha256,
 		.empty_blob = &empty_blob_oid_sha256,
 		.null_oid = &null_oid_sha256,
@@ -305,6 +313,15 @@ int hash_algo_by_length(int len)
 	return GIT_HASH_UNKNOWN;
 }
 
+const struct git_hash_algo *unsafe_hash_algo(const struct git_hash_algo *algop)
+{
+	/* If we have a faster "unsafe" implementation, use that. */
+	if (algop->unsafe)
+		return algop->unsafe;
+	/* Otherwise use the default one. */
+	return algop;
+}
+
 /*
  * This is meant to hold a *small* number of objects that you would
  * want repo_read_object_file() to be able to return, but yet you do not want
@@ -377,7 +394,7 @@ int mkdir_in_gitdir(const char *path)
 		}
 		strbuf_release(&sb);
 	}
-	return adjust_shared_perm(path);
+	return adjust_shared_perm(the_repository, path);
 }
 
 static enum scld_error safe_create_leading_directories_1(char *path, int share)
@@ -426,7 +443,7 @@ static enum scld_error safe_create_leading_directories_1(char *path, int share)
 				ret = SCLD_VANISHED;
 			else
 				ret = SCLD_FAILED;
-		} else if (share && adjust_shared_perm(path)) {
+		} else if (share && adjust_shared_perm(the_repository, path)) {
 			ret = SCLD_PERMS;
 		}
 		*slash = slash_character;
@@ -465,14 +482,14 @@ int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
 	 * restrictive except to remove write permission.
 	 */
 	int mode = 0444;
-	git_path_buf(temp_filename, "objects/%s", pattern);
+	repo_git_path_replace(the_repository, temp_filename, "objects/%s", pattern);
 	fd = git_mkstemp_mode(temp_filename->buf, mode);
 	if (0 <= fd)
 		return fd;
 
 	/* slow path */
 	/* some mkstemp implementations erase temp_filename on failure */
-	git_path_buf(temp_filename, "objects/%s", pattern);
+	repo_git_path_replace(the_repository, temp_filename, "objects/%s", pattern);
 	safe_create_leading_directories(temp_filename->buf);
 	return xmkstemp_mode(temp_filename->buf, mode);
 }
@@ -706,7 +723,7 @@ static void read_info_alternates(struct repository *r,
 void add_to_alternates_file(const char *reference)
 {
 	struct lock_file lock = LOCK_INIT;
-	char *alts = git_pathdup("objects/info/alternates");
+	char *alts = repo_git_path(the_repository, "objects/info/alternates");
 	FILE *in, *out;
 	int found = 0;
 
@@ -1169,7 +1186,7 @@ int stream_object_signature(struct repository *r, const struct object_id *oid)
 	unsigned long size;
 	enum object_type obj_type;
 	struct git_istream *st;
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 	char hdr[MAX_HEADER_LEN];
 	int hdrlen;
 
@@ -1182,7 +1199,7 @@ int stream_object_signature(struct repository *r, const struct object_id *oid)
 
 	/* Sha1.. */
 	r->hash_algo->init_fn(&c);
-	r->hash_algo->update_fn(&c, hdr, hdrlen);
+	git_hash_update(&c, hdr, hdrlen);
 	for (;;) {
 		char buf[1024 * 16];
 		ssize_t readlen = read_istream(st, buf, sizeof(buf));
@@ -1193,9 +1210,9 @@ int stream_object_signature(struct repository *r, const struct object_id *oid)
 		}
 		if (!readlen)
 			break;
-		r->hash_algo->update_fn(&c, buf, readlen);
+		git_hash_update(&c, buf, readlen);
 	}
-	r->hash_algo->final_oid_fn(&real_oid, &c);
+	git_hash_final_oid(&real_oid, &c);
 	close_istream(st);
 	return !oideq(oid, &real_oid) ? -1 : 0;
 }
@@ -1934,15 +1951,15 @@ void *read_object_with_reference(struct repository *r,
 	}
 }
 
-static void hash_object_body(const struct git_hash_algo *algo, git_hash_ctx *c,
+static void hash_object_body(const struct git_hash_algo *algo, struct git_hash_ctx *c,
 			     const void *buf, unsigned long len,
 			     struct object_id *oid,
 			     char *hdr, int *hdrlen)
 {
 	algo->init_fn(c);
-	algo->update_fn(c, hdr, *hdrlen);
-	algo->update_fn(c, buf, len);
-	algo->final_oid_fn(oid, c);
+	git_hash_update(c, hdr, *hdrlen);
+	git_hash_update(c, buf, len);
+	git_hash_final_oid(oid, c);
 }
 
 static void write_object_file_prepare(const struct git_hash_algo *algo,
@@ -1950,7 +1967,7 @@ static void write_object_file_prepare(const struct git_hash_algo *algo,
 				      enum object_type type, struct object_id *oid,
 				      char *hdr, int *hdrlen)
 {
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 
 	/* Generate the header */
 	*hdrlen = format_object_header(hdr, *hdrlen, type, len);
@@ -1964,60 +1981,65 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo
 				      const char *type, struct object_id *oid,
 				      char *hdr, int *hdrlen)
 {
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 
 	*hdrlen = format_object_header_literally(hdr, *hdrlen, type, len);
 	hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen);
 }
 
-static int check_collision(const char *filename_a, const char *filename_b)
+#define CHECK_COLLISION_DEST_VANISHED -2
+
+static int check_collision(const char *source, const char *dest)
 {
-	char buf_a[4096], buf_b[4096];
-	int fd_a = -1, fd_b = -1;
+	char buf_source[4096], buf_dest[4096];
+	int fd_source = -1, fd_dest = -1;
 	int ret = 0;
 
-	fd_a = open(filename_a, O_RDONLY);
-	if (fd_a < 0) {
-		ret = error_errno(_("unable to open %s"), filename_a);
+	fd_source = open(source, O_RDONLY);
+	if (fd_source < 0) {
+		ret = error_errno(_("unable to open %s"), source);
 		goto out;
 	}
 
-	fd_b = open(filename_b, O_RDONLY);
-	if (fd_b < 0) {
-		ret = error_errno(_("unable to open %s"), filename_b);
+	fd_dest = open(dest, O_RDONLY);
+	if (fd_dest < 0) {
+		if (errno != ENOENT)
+			ret = error_errno(_("unable to open %s"), dest);
+		else
+			ret = CHECK_COLLISION_DEST_VANISHED;
 		goto out;
 	}
 
 	while (1) {
 		ssize_t sz_a, sz_b;
 
-		sz_a = read_in_full(fd_a, buf_a, sizeof(buf_a));
+		sz_a = read_in_full(fd_source, buf_source, sizeof(buf_source));
 		if (sz_a < 0) {
-			ret = error_errno(_("unable to read %s"), filename_a);
+			ret = error_errno(_("unable to read %s"), source);
 			goto out;
 		}
 
-		sz_b = read_in_full(fd_b, buf_b, sizeof(buf_b));
+		sz_b = read_in_full(fd_dest, buf_dest, sizeof(buf_dest));
 		if (sz_b < 0) {
-			ret = error_errno(_("unable to read %s"), filename_b);
+			ret = error_errno(_("unable to read %s"), dest);
 			goto out;
 		}
 
-		if (sz_a != sz_b || memcmp(buf_a, buf_b, sz_a)) {
+		if (sz_a != sz_b || memcmp(buf_source, buf_dest, sz_a)) {
 			ret = error(_("files '%s' and '%s' differ in contents"),
-				    filename_a, filename_b);
+				    source, dest);
 			goto out;
 		}
 
-		if (sz_a < sizeof(buf_a))
+		if (sz_a < sizeof(buf_source))
 			break;
 	}
 
 out:
-	if (fd_a > -1)
-		close(fd_a);
-	if (fd_b > -1)
-		close(fd_b);
+	if (fd_source > -1)
+		close(fd_source);
+	if (fd_dest > -1)
+		close(fd_dest);
 	return ret;
 }
 
@@ -2032,8 +2054,11 @@ int finalize_object_file(const char *tmpfile, const char *filename)
 int finalize_object_file_flags(const char *tmpfile, const char *filename,
 			       enum finalize_object_file_flags flags)
 {
-	struct stat st;
-	int ret = 0;
+	unsigned retries = 0;
+	int ret;
+
+retry:
+	ret = 0;
 
 	if (object_creation_mode == OBJECT_CREATION_USES_RENAMES)
 		goto try_rename;
@@ -2054,6 +2079,8 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename,
 	 * left to unlink.
 	 */
 	if (ret && ret != EEXIST) {
+		struct stat st;
+
 	try_rename:
 		if (!stat(filename, &st))
 			ret = EEXIST;
@@ -2069,14 +2096,22 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename,
 			errno = saved_errno;
 			return error_errno(_("unable to write file %s"), filename);
 		}
-		if (!(flags & FOF_SKIP_COLLISION_CHECK) &&
-		    check_collision(tmpfile, filename))
+		if (!(flags & FOF_SKIP_COLLISION_CHECK)) {
+			ret = check_collision(tmpfile, filename);
+			if (ret == CHECK_COLLISION_DEST_VANISHED) {
+				if (retries++ > 5)
+					return error(_("unable to write repeatedly vanishing file %s"),
+						     filename);
+				goto retry;
+			}
+			else if (ret)
 				return -1;
+		}
 		unlink_or_warn(tmpfile);
 	}
 
 out:
-	if (adjust_shared_perm(filename))
+	if (adjust_shared_perm(the_repository, filename))
 		return error(_("unable to set permission to '%s'"), filename);
 	return 0;
 }
@@ -2152,7 +2187,7 @@ static int create_tmpfile(struct strbuf *tmp, const char *filename)
 		strbuf_add(tmp, filename, dirlen - 1);
 		if (mkdir(tmp->buf, 0777) && errno != EEXIST)
 			return -1;
-		if (adjust_shared_perm(tmp->buf))
+		if (adjust_shared_perm(the_repository, tmp->buf))
 			return -1;
 
 		/* Try again */
@@ -2177,7 +2212,7 @@ static int start_loose_object_common(struct strbuf *tmp_file,
 				     const char *filename, unsigned flags,
 				     git_zstream *stream,
 				     unsigned char *buf, size_t buflen,
-				     git_hash_ctx *c, git_hash_ctx *compat_c,
+				     struct git_hash_ctx *c, struct git_hash_ctx *compat_c,
 				     char *hdr, int hdrlen)
 {
 	struct repository *repo = the_repository;
@@ -2211,9 +2246,9 @@ static int start_loose_object_common(struct strbuf *tmp_file,
 	stream->avail_in = hdrlen;
 	while (git_deflate(stream, 0) == Z_OK)
 		; /* nothing */
-	algo->update_fn(c, hdr, hdrlen);
+	git_hash_update(c, hdr, hdrlen);
 	if (compat && compat_c)
-		compat->update_fn(compat_c, hdr, hdrlen);
+		git_hash_update(compat_c, hdr, hdrlen);
 
 	return fd;
 }
@@ -2222,21 +2257,20 @@ static int start_loose_object_common(struct strbuf *tmp_file,
  * Common steps for the inner git_deflate() loop for writing loose
  * objects. Returns what git_deflate() returns.
  */
-static int write_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
+static int write_loose_object_common(struct git_hash_ctx *c, struct git_hash_ctx *compat_c,
 				     git_zstream *stream, const int flush,
 				     unsigned char *in0, const int fd,
 				     unsigned char *compressed,
 				     const size_t compressed_len)
 {
 	struct repository *repo = the_repository;
-	const struct git_hash_algo *algo = repo->hash_algo;
 	const struct git_hash_algo *compat = repo->compat_hash_algo;
 	int ret;
 
 	ret = git_deflate(stream, flush ? Z_FINISH : 0);
-	algo->update_fn(c, in0, stream->next_in - in0);
+	git_hash_update(c, in0, stream->next_in - in0);
 	if (compat && compat_c)
-		compat->update_fn(compat_c, in0, stream->next_in - in0);
+		git_hash_update(compat_c, in0, stream->next_in - in0);
 	if (write_in_full(fd, compressed, stream->next_out - compressed) < 0)
 		die_errno(_("unable to write loose object file"));
 	stream->next_out = compressed;
@@ -2251,21 +2285,20 @@ static int write_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
  * - End the compression of zlib stream.
  * - Get the calculated oid to "oid".
  */
-static int end_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
+static int end_loose_object_common(struct git_hash_ctx *c, struct git_hash_ctx *compat_c,
 				   git_zstream *stream, struct object_id *oid,
 				   struct object_id *compat_oid)
 {
 	struct repository *repo = the_repository;
-	const struct git_hash_algo *algo = repo->hash_algo;
 	const struct git_hash_algo *compat = repo->compat_hash_algo;
 	int ret;
 
 	ret = git_deflate_end_gently(stream);
 	if (ret != Z_OK)
 		return ret;
-	algo->final_oid_fn(oid, c);
+	git_hash_final_oid(oid, c);
 	if (compat && compat_c)
-		compat->final_oid_fn(compat_oid, compat_c);
+		git_hash_final_oid(compat_oid, compat_c);
 
 	return Z_OK;
 }
@@ -2277,7 +2310,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
 	int fd, ret;
 	unsigned char compressed[4096];
 	git_zstream stream;
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 	struct object_id parano_oid;
 	static struct strbuf tmp_file = STRBUF_INIT;
 	static struct strbuf filename = STRBUF_INIT;
@@ -2357,7 +2390,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
 	int fd, ret, err = 0, flush = 0;
 	unsigned char compressed[4096];
 	git_zstream stream;
-	git_hash_ctx c, compat_c;
+	struct git_hash_ctx c, compat_c;
 	struct strbuf tmp_file = STRBUF_INIT;
 	struct strbuf filename = STRBUF_INIT;
 	int dirlen;
@@ -3017,14 +3050,14 @@ static int check_stream_oid(git_zstream *stream,
 			    const char *path,
 			    const struct object_id *expected_oid)
 {
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 	struct object_id real_oid;
 	unsigned char buf[4096];
 	unsigned long total_read;
 	int status = Z_OK;
 
 	the_hash_algo->init_fn(&c);
-	the_hash_algo->update_fn(&c, hdr, stream->total_out);
+	git_hash_update(&c, hdr, stream->total_out);
 
 	/*
 	 * We already read some bytes into hdr, but the ones up to the NUL
@@ -3044,7 +3077,7 @@ static int check_stream_oid(git_zstream *stream,
 		if (size - total_read < stream->avail_out)
 			stream->avail_out = size - total_read;
 		status = git_inflate(stream, Z_FINISH);
-		the_hash_algo->update_fn(&c, buf, stream->next_out - buf);
+		git_hash_update(&c, buf, stream->next_out - buf);
 		total_read += stream->next_out - buf;
 	}
 	git_inflate_end(stream);
@@ -3059,7 +3092,7 @@ static int check_stream_oid(git_zstream *stream,
 		return -1;
 	}
 
-	the_hash_algo->final_oid_fn(&real_oid, &c);
+	git_hash_final_oid(&real_oid, &c);
 	if (!oideq(expected_oid, &real_oid)) {
 		error(_("hash mismatch for %s (expected %s)"), path,
 		      oid_to_hex(expected_oid));
diff --git a/object-name.c b/object-name.c
index 88d1313..76749fb 100644
--- a/object-name.c
+++ b/object-name.c
@@ -1272,6 +1272,58 @@ static int peel_onion(struct repository *r, const char *name, int len,
 	return 0;
 }
 
+/*
+ * Documentation/revisions.adoc says:
+ *    '<describeOutput>', e.g. 'v1.7.4.2-679-g3bee7fb'::
+ *      Output from `git describe`; i.e. a closest tag, optionally
+ *      followed by a dash and a number of commits, followed by a dash, a
+ *      'g', and an abbreviated object name.
+ *
+ * which means that the stuff before '-g${HASH}' needs to be a valid
+ * refname, a dash, and a non-negative integer.  This function verifies
+ * that.
+ *
+ * In particular, we do not want to treat
+ *   branchname:path/to/file/named/i-gaffed
+ * as a request for commit affed.
+ *
+ * More generally, we should probably not treat
+ *   'refs/heads/./../.../ ~^:/?*[////\\\&}/busted.lock-g050e0ef6ead'
+ * as a request for object 050e0ef6ead either.
+ *
+ * We are called with name[len] == '-' and name[len+1] == 'g', i.e.
+ * we are verifying ${REFNAME}-{INTEGER} part of the name.
+ */
+static int ref_and_count_parts_valid(const char *name, int len)
+{
+	struct strbuf sb;
+	const char *cp;
+	int flags = REFNAME_ALLOW_ONELEVEL;
+	int ret = 1;
+
+	/* Ensure we have at least one digit */
+	if (!isxdigit(name[len-1]))
+		return 0;
+
+	/* Skip over digits backwards until we get to the dash */
+	for (cp = name + len - 2; name < cp; cp--) {
+		if (*cp == '-')
+			break;
+		if (!isxdigit(*cp))
+			return 0;
+	}
+	/* Ensure we found the leading dash */
+	if (*cp != '-')
+		return 0;
+
+	len = cp - name;
+	strbuf_init(&sb, len);
+	strbuf_add(&sb, name, len);
+	ret = !check_refname_format(sb.buf, flags);
+	strbuf_release(&sb);
+	return ret;
+}
+
 static int get_describe_name(struct repository *r,
 			     const char *name, int len,
 			     struct object_id *oid)
@@ -1285,7 +1337,8 @@ static int get_describe_name(struct repository *r,
 			/* We must be looking at g in "SOMETHING-g"
 			 * for it to be describe output.
 			 */
-			if (ch == 'g' && cp[-1] == '-') {
+			if (ch == 'g' && cp[-1] == '-' &&
+			    ref_and_count_parts_valid(name, cp - 1 - name)) {
 				cp++;
 				len -= cp - name;
 				return get_short_oid(r,
@@ -2052,12 +2105,14 @@ static enum get_oid_result get_oid_with_context_1(struct repository *repo,
 		return -1;
 	}
 	for (cp = name, bracket_depth = 0; *cp; cp++) {
-		if (*cp == '{')
+		if (strchr("@^", *cp) && cp[1] == '{') {
+			cp++;
 			bracket_depth++;
-		else if (bracket_depth && *cp == '}')
+		} else if (bracket_depth && *cp == '}') {
 			bracket_depth--;
-		else if (!bracket_depth && *cp == ':')
+		} else if (!bracket_depth && *cp == ':') {
 			break;
+		}
 	}
 	if (*cp == ':') {
 		struct object_id tree_oid;
diff --git a/oss-fuzz/fuzz-parse-attr-line.c b/oss-fuzz/fuzz-parse-attr-line.c
index e0e4bc6..3151985 100644
--- a/oss-fuzz/fuzz-parse-attr-line.c
+++ b/oss-fuzz/fuzz-parse-attr-line.c
@@ -24,7 +24,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 	res = parse_attr_line(buf, "dummy", 0, 0);
 
 	if (res) {
-		int j;
+		size_t j;
 		for (j = 0; j < res->num_attr; j++) {
 			const char *setto = res->state[j].setto;
 			if (ATTR_TRUE(setto) || ATTR_FALSE(setto) ||
diff --git a/oss-fuzz/meson.build b/oss-fuzz/meson.build
new file mode 100644
index 0000000..878afd8
--- /dev/null
+++ b/oss-fuzz/meson.build
@@ -0,0 +1,20 @@
+fuzz_programs = [
+  'fuzz-commit-graph.c',
+  'fuzz-config.c',
+  'fuzz-credential-from-url-gently.c',
+  'fuzz-date.c',
+  'fuzz-pack-headers.c',
+  'fuzz-pack-idx.c',
+  'fuzz-parse-attr-line.c',
+  'fuzz-url-decode-mem.c',
+]
+
+foreach fuzz_program : fuzz_programs
+  executable(fs.stem(fuzz_program),
+    sources: [
+      'dummy-cmd-main.c',
+      fuzz_program,
+    ],
+    dependencies: [libgit_commonmain],
+  )
+endforeach
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
index 4f8be53..34e86d4 100644
--- a/pack-bitmap-write.c
+++ b/pack-bitmap-write.c
@@ -590,7 +590,8 @@ int bitmap_writer_build(struct bitmap_writer *writer)
 	int closed = 1; /* until proven otherwise */
 
 	if (writer->show_progress)
-		writer->progress = start_progress("Building bitmaps",
+		writer->progress = start_progress(the_repository,
+						  "Building bitmaps",
 						  writer->selected_nr);
 	trace2_region_enter("pack-bitmap-write", "building_bitmaps_total",
 			    the_repository);
@@ -710,7 +711,8 @@ void bitmap_writer_select_commits(struct bitmap_writer *writer,
 	}
 
 	if (writer->show_progress)
-		writer->progress = start_progress("Selecting bitmap commits", 0);
+		writer->progress = start_progress(the_repository,
+						  "Selecting bitmap commits", 0);
 
 	for (;;) {
 		struct commit *chosen = NULL;
@@ -1070,7 +1072,7 @@ void bitmap_writer_finish(struct bitmap_writer *writer,
 	finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,
 			  CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
 
-	if (adjust_shared_perm(tmp_file.buf))
+	if (adjust_shared_perm(the_repository, tmp_file.buf))
 		die_errno("unable to make temporary bitmap file readable");
 
 	if (rename(tmp_file.buf, filename))
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 60b5da9..6406953 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -2573,7 +2573,9 @@ void test_bitmap_walk(struct rev_info *revs)
 	tdata.trees = ewah_to_bitmap(bitmap_git->trees);
 	tdata.blobs = ewah_to_bitmap(bitmap_git->blobs);
 	tdata.tags = ewah_to_bitmap(bitmap_git->tags);
-	tdata.prg = start_progress("Verifying bitmap entries", result_popcnt);
+	tdata.prg = start_progress(revs->repo,
+				   "Verifying bitmap entries",
+				   result_popcnt);
 	tdata.seen = 0;
 
 	traverse_commit_list(revs, &test_show_commit, &test_show_object, &tdata);
diff --git a/pack-check.c b/pack-check.c
index 8d9f6da..d0aeb5e 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -58,7 +58,7 @@ static int verify_packfile(struct repository *r,
 {
 	off_t index_size = p->index_size;
 	const unsigned char *index_base = p->index_data;
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 	unsigned char hash[GIT_MAX_RAWSZ], *pack_sig;
 	off_t offset = 0, pack_sig_ofs = 0;
 	uint32_t nr_objects, i;
@@ -77,9 +77,9 @@ static int verify_packfile(struct repository *r,
 			pack_sig_ofs = p->pack_size - r->hash_algo->rawsz;
 		if (offset > pack_sig_ofs)
 			remaining -= (unsigned int)(offset - pack_sig_ofs);
-		r->hash_algo->update_fn(&ctx, in, remaining);
+		git_hash_update(&ctx, in, remaining);
 	} while (offset < pack_sig_ofs);
-	r->hash_algo->final_fn(hash, &ctx);
+	git_hash_final(hash, &ctx);
 	pack_sig = use_pack(p, w_curs, pack_sig_ofs, NULL);
 	if (!hasheq(hash, pack_sig, the_repository->hash_algo))
 		err = error("%s pack checksum mismatch",
diff --git a/pack-objects.h b/pack-objects.h
index 3f6f504..d73e384 100644
--- a/pack-objects.h
+++ b/pack-objects.h
@@ -208,6 +208,34 @@ static inline uint32_t pack_name_hash(const char *name)
 	return hash;
 }
 
+static inline uint32_t pack_name_hash_v2(const unsigned char *name)
+{
+	uint32_t hash = 0, base = 0, c;
+
+	if (!name)
+		return 0;
+
+	while ((c = *name++)) {
+		if (isspace(c))
+			continue;
+		if (c == '/') {
+			base = (base >> 6) ^ hash;
+			hash = 0;
+		} else {
+			/*
+			 * 'c' is only a single byte. Reverse it and move
+			 * it to the top of the hash, moving the rest to
+			 * less-significant bits.
+			 */
+			c = (c & 0xF0) >> 4 | (c & 0x0F) << 4;
+			c = (c & 0xCC) >> 2 | (c & 0x33) << 2;
+			c = (c & 0xAA) >> 1 | (c & 0x55) << 1;
+			hash = (hash >> 2) + (c << 24);
+		}
+	}
+	return (base >> 6) ^ hash;
+}
+
 static inline enum object_type oe_type(const struct object_entry *e)
 {
 	return e->type_valid ? e->type_ : OBJ_BAD;
diff --git a/pack-write.c b/pack-write.c
index 98a8c0e..823e40b 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -56,7 +56,8 @@ static int need_large_offset(off_t offset, const struct pack_idx_option *opts)
  * The *sha1 contains the pack content SHA1 hash.
  * The objects array passed in will be sorted by SHA1 on exit.
  */
-const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects,
+const char *write_idx_file(const struct git_hash_algo *hash_algo,
+			   const char *index_name, struct pack_idx_entry **objects,
 			   int nr_objects, const struct pack_idx_option *opts,
 			   const unsigned char *sha1)
 {
@@ -130,7 +131,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
 		struct pack_idx_entry *obj = *list++;
 		if (index_version < 2)
 			hashwrite_be32(f, obj->offset);
-		hashwrite(f, obj->oid.hash, the_hash_algo->rawsz);
+		hashwrite(f, obj->oid.hash, hash_algo->rawsz);
 		if ((opts->flags & WRITE_IDX_STRICT) &&
 		    (i && oideq(&list[-2]->oid, &obj->oid)))
 			die("The same object %s appears twice in the pack",
@@ -172,7 +173,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
 		}
 	}
 
-	hashwrite(f, sha1, the_hash_algo->rawsz);
+	hashwrite(f, sha1, hash_algo->rawsz);
 	finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,
 			  CSUM_HASH_IN_STREAM | CSUM_CLOSE |
 			  ((opts->flags & WRITE_IDX_VERIFY) ? 0 : CSUM_FSYNC));
@@ -193,11 +194,12 @@ static int pack_order_cmp(const void *va, const void *vb, void *ctx)
 	return 0;
 }
 
-static void write_rev_header(struct hashfile *f)
+static void write_rev_header(const struct git_hash_algo *hash_algo,
+			     struct hashfile *f)
 {
 	hashwrite_be32(f, RIDX_SIGNATURE);
 	hashwrite_be32(f, RIDX_VERSION);
-	hashwrite_be32(f, oid_version(the_hash_algo));
+	hashwrite_be32(f, oid_version(hash_algo));
 }
 
 static void write_rev_index_positions(struct hashfile *f,
@@ -209,12 +211,14 @@ static void write_rev_index_positions(struct hashfile *f,
 		hashwrite_be32(f, pack_order[i]);
 }
 
-static void write_rev_trailer(struct hashfile *f, const unsigned char *hash)
+static void write_rev_trailer(const struct git_hash_algo *hash_algo,
+			      struct hashfile *f, const unsigned char *hash)
 {
-	hashwrite(f, hash, the_hash_algo->rawsz);
+	hashwrite(f, hash, hash_algo->rawsz);
 }
 
-char *write_rev_file(const char *rev_name,
+char *write_rev_file(const struct git_hash_algo *hash_algo,
+		     const char *rev_name,
 		     struct pack_idx_entry **objects,
 		     uint32_t nr_objects,
 		     const unsigned char *hash,
@@ -232,15 +236,16 @@ char *write_rev_file(const char *rev_name,
 		pack_order[i] = i;
 	QSORT_S(pack_order, nr_objects, pack_order_cmp, objects);
 
-	ret = write_rev_file_order(rev_name, pack_order, nr_objects, hash,
-				   flags);
+	ret = write_rev_file_order(hash_algo, rev_name, pack_order, nr_objects,
+				   hash, flags);
 
 	free(pack_order);
 
 	return ret;
 }
 
-char *write_rev_file_order(const char *rev_name,
+char *write_rev_file_order(const struct git_hash_algo *hash_algo,
+			   const char *rev_name,
 			   uint32_t *pack_order,
 			   uint32_t nr_objects,
 			   const unsigned char *hash,
@@ -279,12 +284,12 @@ char *write_rev_file_order(const char *rev_name,
 		return NULL;
 	}
 
-	write_rev_header(f);
+	write_rev_header(hash_algo, f);
 
 	write_rev_index_positions(f, pack_order, nr_objects);
-	write_rev_trailer(f, hash);
+	write_rev_trailer(hash_algo, f, hash);
 
-	if (adjust_shared_perm(path) < 0)
+	if (adjust_shared_perm(the_repository, path) < 0)
 		die(_("failed to make %s readable"), path);
 
 	finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,
@@ -294,11 +299,12 @@ char *write_rev_file_order(const char *rev_name,
 	return path;
 }
 
-static void write_mtimes_header(struct hashfile *f)
+static void write_mtimes_header(const struct git_hash_algo *hash_algo,
+				struct hashfile *f)
 {
 	hashwrite_be32(f, MTIMES_SIGNATURE);
 	hashwrite_be32(f, MTIMES_VERSION);
-	hashwrite_be32(f, oid_version(the_hash_algo));
+	hashwrite_be32(f, oid_version(hash_algo));
 }
 
 /*
@@ -318,12 +324,14 @@ static void write_mtimes_objects(struct hashfile *f,
 	}
 }
 
-static void write_mtimes_trailer(struct hashfile *f, const unsigned char *hash)
+static void write_mtimes_trailer(const struct git_hash_algo *hash_algo,
+				 struct hashfile *f, const unsigned char *hash)
 {
-	hashwrite(f, hash, the_hash_algo->rawsz);
+	hashwrite(f, hash, hash_algo->rawsz);
 }
 
-static char *write_mtimes_file(struct packing_data *to_pack,
+static char *write_mtimes_file(const struct git_hash_algo *hash_algo,
+			       struct packing_data *to_pack,
 			       struct pack_idx_entry **objects,
 			       uint32_t nr_objects,
 			       const unsigned char *hash)
@@ -340,11 +348,11 @@ static char *write_mtimes_file(struct packing_data *to_pack,
 	mtimes_name = strbuf_detach(&tmp_file, NULL);
 	f = hashfd(fd, mtimes_name);
 
-	write_mtimes_header(f);
+	write_mtimes_header(hash_algo, f);
 	write_mtimes_objects(f, to_pack, objects, nr_objects);
-	write_mtimes_trailer(f, hash);
+	write_mtimes_trailer(hash_algo, f, hash);
 
-	if (adjust_shared_perm(mtimes_name) < 0)
+	if (adjust_shared_perm(the_repository, mtimes_name) < 0)
 		die(_("failed to make %s readable"), mtimes_name);
 
 	finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,
@@ -380,7 +388,8 @@ off_t write_pack_header(struct hashfile *f, uint32_t nr_entries)
  * partial_pack_sha1 can refer to the same buffer if the caller is not
  * interested in the resulting SHA1 of pack data above partial_pack_offset.
  */
-void fixup_pack_header_footer(int pack_fd,
+void fixup_pack_header_footer(const struct git_hash_algo *hash_algo,
+			 int pack_fd,
 			 unsigned char *new_pack_hash,
 			 const char *pack_name,
 			 uint32_t object_count,
@@ -388,13 +397,13 @@ void fixup_pack_header_footer(int pack_fd,
 			 off_t partial_pack_offset)
 {
 	int aligned_sz, buf_sz = 8 * 1024;
-	git_hash_ctx old_hash_ctx, new_hash_ctx;
+	struct git_hash_ctx old_hash_ctx, new_hash_ctx;
 	struct pack_header hdr;
 	char *buf;
 	ssize_t read_result;
 
-	the_hash_algo->init_fn(&old_hash_ctx);
-	the_hash_algo->init_fn(&new_hash_ctx);
+	hash_algo->init_fn(&old_hash_ctx);
+	hash_algo->init_fn(&new_hash_ctx);
 
 	if (lseek(pack_fd, 0, SEEK_SET) != 0)
 		die_errno("Failed seeking to start of '%s'", pack_name);
@@ -406,9 +415,9 @@ void fixup_pack_header_footer(int pack_fd,
 			  pack_name);
 	if (lseek(pack_fd, 0, SEEK_SET) != 0)
 		die_errno("Failed seeking to start of '%s'", pack_name);
-	the_hash_algo->update_fn(&old_hash_ctx, &hdr, sizeof(hdr));
+	git_hash_update(&old_hash_ctx, &hdr, sizeof(hdr));
 	hdr.hdr_entries = htonl(object_count);
-	the_hash_algo->update_fn(&new_hash_ctx, &hdr, sizeof(hdr));
+	git_hash_update(&new_hash_ctx, &hdr, sizeof(hdr));
 	write_or_die(pack_fd, &hdr, sizeof(hdr));
 	partial_pack_offset -= sizeof(hdr);
 
@@ -423,7 +432,7 @@ void fixup_pack_header_footer(int pack_fd,
 			break;
 		if (n < 0)
 			die_errno("Failed to checksum '%s'", pack_name);
-		the_hash_algo->update_fn(&new_hash_ctx, buf, n);
+		git_hash_update(&new_hash_ctx, buf, n);
 
 		aligned_sz -= n;
 		if (!aligned_sz)
@@ -432,13 +441,13 @@ void fixup_pack_header_footer(int pack_fd,
 		if (!partial_pack_hash)
 			continue;
 
-		the_hash_algo->update_fn(&old_hash_ctx, buf, n);
+		git_hash_update(&old_hash_ctx, buf, n);
 		partial_pack_offset -= n;
 		if (partial_pack_offset == 0) {
 			unsigned char hash[GIT_MAX_RAWSZ];
-			the_hash_algo->final_fn(hash, &old_hash_ctx);
+			git_hash_final(hash, &old_hash_ctx);
 			if (!hasheq(hash, partial_pack_hash,
-				    the_repository->hash_algo))
+				    hash_algo))
 				die("Unexpected checksum for %s "
 				    "(disk corruption?)", pack_name);
 			/*
@@ -446,7 +455,7 @@ void fixup_pack_header_footer(int pack_fd,
 			 * pack, which also means making partial_pack_offset
 			 * big enough not to matter anymore.
 			 */
-			the_hash_algo->init_fn(&old_hash_ctx);
+			hash_algo->init_fn(&old_hash_ctx);
 			partial_pack_offset = ~partial_pack_offset;
 			partial_pack_offset -= MSB(partial_pack_offset, 1);
 		}
@@ -454,16 +463,16 @@ void fixup_pack_header_footer(int pack_fd,
 	free(buf);
 
 	if (partial_pack_hash)
-		the_hash_algo->final_fn(partial_pack_hash, &old_hash_ctx);
-	the_hash_algo->final_fn(new_pack_hash, &new_hash_ctx);
-	write_or_die(pack_fd, new_pack_hash, the_hash_algo->rawsz);
+		git_hash_final(partial_pack_hash, &old_hash_ctx);
+	git_hash_final(new_pack_hash, &new_hash_ctx);
+	write_or_die(pack_fd, new_pack_hash, hash_algo->rawsz);
 	fsync_component_or_die(FSYNC_COMPONENT_PACK, pack_fd, pack_name);
 }
 
-char *index_pack_lockfile(int ip_out, int *is_well_formed)
+char *index_pack_lockfile(struct repository *r, int ip_out, int *is_well_formed)
 {
 	char packname[GIT_MAX_HEXSZ + 6];
-	const int len = the_hash_algo->hexsz + 6;
+	const int len = r->hash_algo->hexsz + 6;
 
 	/*
 	 * The first thing we expect from index-pack's output
@@ -480,7 +489,7 @@ char *index_pack_lockfile(int ip_out, int *is_well_formed)
 		packname[len-1] = 0;
 		if (skip_prefix(packname, "keep\t", &name))
 			return xstrfmt("%s/pack/pack-%s.keep",
-				       repo_get_object_directory(the_repository), name);
+				       repo_get_object_directory(r), name);
 		return NULL;
 	}
 	if (is_well_formed)
@@ -546,7 +555,8 @@ void rename_tmp_packfile_idx(struct strbuf *name_buffer,
 	rename_tmp_packfile(name_buffer, *idx_tmp_name, "idx");
 }
 
-void stage_tmp_packfiles(struct strbuf *name_buffer,
+void stage_tmp_packfiles(const struct git_hash_algo *hash_algo,
+			 struct strbuf *name_buffer,
 			 const char *pack_tmp_name,
 			 struct pack_idx_entry **written_list,
 			 uint32_t nr_written,
@@ -558,20 +568,20 @@ void stage_tmp_packfiles(struct strbuf *name_buffer,
 	char *rev_tmp_name = NULL;
 	char *mtimes_tmp_name = NULL;
 
-	if (adjust_shared_perm(pack_tmp_name))
+	if (adjust_shared_perm(the_repository, pack_tmp_name))
 		die_errno("unable to make temporary pack file readable");
 
-	*idx_tmp_name = (char *)write_idx_file(NULL, written_list, nr_written,
-					       pack_idx_opts, hash);
-	if (adjust_shared_perm(*idx_tmp_name))
+	*idx_tmp_name = (char *)write_idx_file(hash_algo, NULL, written_list,
+					       nr_written, pack_idx_opts, hash);
+	if (adjust_shared_perm(the_repository, *idx_tmp_name))
 		die_errno("unable to make temporary index file readable");
 
-	rev_tmp_name = write_rev_file(NULL, written_list, nr_written, hash,
-				      pack_idx_opts->flags);
+	rev_tmp_name = write_rev_file(hash_algo, NULL, written_list, nr_written,
+				      hash, pack_idx_opts->flags);
 
 	if (pack_idx_opts->flags & WRITE_MTIMES) {
-		mtimes_tmp_name = write_mtimes_file(to_pack, written_list,
-						    nr_written,
+		mtimes_tmp_name = write_mtimes_file(hash_algo, to_pack,
+						    written_list, nr_written,
 						    hash);
 	}
 
diff --git a/pack.h b/pack.h
index a8da040..9f1194a 100644
--- a/pack.h
+++ b/pack.h
@@ -13,7 +13,8 @@ struct repository;
  */
 #define PACK_SIGNATURE 0x5041434b	/* "PACK" */
 #define PACK_VERSION 2
-#define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3))
+#define pack_version_ok(v) pack_version_ok_native(ntohl(v))
+#define pack_version_ok_native(v) ((v) == 2 || (v) == 3)
 struct pack_header {
 	uint32_t hdr_signature;
 	uint32_t hdr_version;
@@ -86,20 +87,37 @@ struct progress;
 /* Note, the data argument could be NULL if object type is blob */
 typedef int (*verify_fn)(const struct object_id *, enum object_type, unsigned long, void*, int*);
 
-const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, const unsigned char *sha1);
+const char *write_idx_file(const struct git_hash_algo *hash_algo,
+			   const char *index_name,
+			   struct pack_idx_entry **objects,
+			   int nr_objects,
+			   const struct pack_idx_option *,
+			   const unsigned char *sha1);
 int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
 int verify_pack_index(struct packed_git *);
 int verify_pack(struct repository *, struct packed_git *, verify_fn fn, struct progress *, uint32_t);
 off_t write_pack_header(struct hashfile *f, uint32_t);
-void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
-char *index_pack_lockfile(int fd, int *is_well_formed);
+void fixup_pack_header_footer(const struct git_hash_algo *, int,
+			      unsigned char *, const char *, uint32_t,
+			      unsigned char *, off_t);
+char *index_pack_lockfile(struct repository *r, int fd, int *is_well_formed);
 
 struct ref;
 
 void write_promisor_file(const char *promisor_name, struct ref **sought, int nr_sought);
 
-char *write_rev_file(const char *rev_name, struct pack_idx_entry **objects, uint32_t nr_objects, const unsigned char *hash, unsigned flags);
-char *write_rev_file_order(const char *rev_name, uint32_t *pack_order, uint32_t nr_objects, const unsigned char *hash, unsigned flags);
+char *write_rev_file(const struct git_hash_algo *hash_algo,
+		     const char *rev_name,
+		     struct pack_idx_entry **objects,
+		     uint32_t nr_objects,
+		     const unsigned char *hash,
+		     unsigned flags);
+char *write_rev_file_order(const struct git_hash_algo *hash_algo,
+			   const char *rev_name,
+			   uint32_t *pack_order,
+			   uint32_t nr_objects,
+			   const unsigned char *hash,
+			   unsigned flags);
 
 /*
  * The "hdr" output buffer should be at least this big, which will handle sizes
@@ -117,7 +135,8 @@ int read_pack_header(int fd, struct pack_header *);
 struct packing_data;
 
 struct hashfile *create_tmp_packfile(char **pack_tmp_name);
-void stage_tmp_packfiles(struct strbuf *name_buffer,
+void stage_tmp_packfiles(const struct git_hash_algo *hash_algo,
+			 struct strbuf *name_buffer,
 			 const char *pack_tmp_name,
 			 struct pack_idx_entry **written_list,
 			 uint32_t nr_written,
diff --git a/packfile.c b/packfile.c
index cc7ab64..2d80d80 100644
--- a/packfile.c
+++ b/packfile.c
@@ -2315,3 +2315,23 @@ int is_promisor_object(struct repository *r, const struct object_id *oid)
 	}
 	return oidset_contains(&promisor_objects, oid);
 }
+
+int parse_pack_header_option(const char *in, unsigned char *out, unsigned int *len)
+{
+	unsigned char *hdr;
+	char *c;
+
+	hdr = out;
+	put_be32(hdr, PACK_SIGNATURE);
+	hdr += 4;
+	put_be32(hdr, strtoul(in, &c, 10));
+	hdr += 4;
+	if (*c != ',')
+		return -1;
+	put_be32(hdr, strtoul(c + 1, &c, 10));
+	hdr += 4;
+	if (*c)
+		return -1;
+	*len = hdr - out;
+	return 0;
+}
diff --git a/packfile.h b/packfile.h
index 58104fa..00ada7a 100644
--- a/packfile.h
+++ b/packfile.h
@@ -216,4 +216,10 @@ int is_promisor_object(struct repository *r, const struct object_id *oid);
 int load_idx(const char *path, const unsigned int hashsz, void *idx_map,
 	     size_t idx_size, struct packed_git *p);
 
+/*
+ * Parse a --pack_header option as accepted by index-pack and unpack-objects,
+ * turning it into the matching bytes we'd find in a pack.
+ */
+int parse_pack_header_option(const char *in, unsigned char *out, unsigned int *len);
+
 #endif
diff --git a/pager.c b/pager.c
index 40b664f..5531fff 100644
--- a/pager.c
+++ b/pager.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "config.h"
 #include "editor.h"
@@ -84,7 +82,7 @@ static int core_pager_config(const char *var, const char *value,
 	return 0;
 }
 
-const char *git_pager(int stdout_is_tty)
+const char *git_pager(struct repository *r, int stdout_is_tty)
 {
 	const char *pager;
 
@@ -94,7 +92,7 @@ const char *git_pager(int stdout_is_tty)
 	pager = getenv("GIT_PAGER");
 	if (!pager) {
 		if (!pager_program)
-			read_early_config(the_repository,
+			read_early_config(r,
 					  core_pager_config, NULL);
 		pager = pager_program;
 	}
@@ -143,10 +141,10 @@ void prepare_pager_args(struct child_process *pager_process, const char *pager)
 	pager_process->trace2_child_class = "pager";
 }
 
-void setup_pager(void)
+void setup_pager(struct repository *r)
 {
 	static int once = 0;
-	const char *pager = git_pager(isatty(1));
+	const char *pager = git_pager(r, isatty(1));
 
 	if (!pager)
 		return;
@@ -293,7 +291,7 @@ static int pager_command_config(const char *var, const char *value,
 }
 
 /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
-int check_pager_config(const char *cmd)
+int check_pager_config(struct repository *r, const char *cmd)
 {
 	struct pager_command_config_data data;
 
@@ -301,7 +299,7 @@ int check_pager_config(const char *cmd)
 	data.want = -1;
 	data.value = NULL;
 
-	read_early_config(the_repository, pager_command_config, &data);
+	read_early_config(r, pager_command_config, &data);
 
 	if (data.value)
 		pager_program = data.value;
diff --git a/pager.h b/pager.h
index 103ecac..d070be6 100644
--- a/pager.h
+++ b/pager.h
@@ -2,15 +2,16 @@
 #define PAGER_H
 
 struct child_process;
+struct repository;
 
-const char *git_pager(int stdout_is_tty);
-void setup_pager(void);
+const char *git_pager(struct repository *r, int stdout_is_tty);
+void setup_pager(struct repository *r);
 void wait_for_pager(void);
 int pager_in_use(void);
 int term_columns(void);
 void term_clear_line(void);
 int decimal_width(uintmax_t);
-int check_pager_config(const char *cmd);
+int check_pager_config(struct repository *r, const char *cmd);
 void prepare_pager_args(struct child_process *, const char *pager);
 
 extern int pager_use_color;
diff --git a/parse-options.c b/parse-options.c
index 33bfba0..35fbb3b 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -1076,11 +1076,48 @@ static int usage_argh(const struct option *opts, FILE *outfile)
 		!opts->argh || !!strpbrk(opts->argh, "()<>[]|");
 	if (opts->flags & PARSE_OPT_OPTARG)
 		if (opts->long_name)
-			s = literal ? "[=%s]" : "[=<%s>]";
+			/*
+			 * TRANSLATORS: The "<%s>" part of this string
+			 * stands for an optional value given to a command
+			 * line option in the long form, and "<>" is there
+			 * as a convention to signal that it is a
+			 * placeholder (i.e. the user should substitute it
+			 * with the real value).  If your language uses a
+			 * different convention, you can change "<%s>" part
+			 * to match yours, e.g. it might use "|%s|" instead,
+			 * or if the alphabet is different enough it may use
+			 * "%s" without any placeholder signal.  Most
+			 * translations leave this message as is.
+			 */
+			s = literal ? "[=%s]" : _("[=<%s>]");
 		else
-			s = literal ? "[%s]" : "[<%s>]";
+			/*
+			 * TRANSLATORS: The "<%s>" part of this string
+			 * stands for an optional value given to a command
+			 * line option in the short form, and "<>" is there
+			 * as a convention to signal that it is a
+			 * placeholder (i.e. the user should substitute it
+			 * with the real value).  If your language uses a
+			 * different convention, you can change "<%s>" part
+			 * to match yours, e.g. it might use "|%s|" instead,
+			 * or if the alphabet is different enough it may use
+			 * "%s" without any placeholder signal.  Most
+			 * translations leave this message as is.
+			 */
+			s = literal ? "[%s]" : _("[<%s>]");
 	else
-		s = literal ? " %s" : " <%s>";
+		/*
+		 * TRANSLATORS: The "<%s>" part of this string stands for a
+		 * value given to a command line option, and "<>" is there
+		 * as a convention to signal that it is a placeholder
+		 * (i.e. the user should substitute it with the real value).
+		 * If your language uses a different convention, you can
+		 * change "<%s>" part to match yours, e.g. it might use
+		 * "|%s|" instead, or if the alphabet is different enough it
+		 * may use "%s" without any placeholder signal.  Most
+		 * translations leave this message as is.
+		 */
+		s = literal ? " %s" : _(" <%s>");
 	return utf8_fprintf(outfile, s, opts->argh ? _(opts->argh) : _("..."));
 }
 
@@ -1282,6 +1319,16 @@ void NORETURN usage_with_options(const char * const *usagestr,
 	exit(129);
 }
 
+void show_usage_with_options_if_asked(int ac, const char **av,
+				      const char * const *usagestr,
+				      const struct option *opts)
+{
+	if (ac == 2 && !strcmp(av[1], "-h")) {
+		usage_with_options_internal(NULL, usagestr, opts, 0, 0);
+		exit(129);
+	}
+}
+
 void NORETURN usage_msg_opt(const char *msg,
 		   const char * const *usagestr,
 		   const struct option *options)
diff --git a/parse-options.h b/parse-options.h
index d01361c..997ffbe 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -6,7 +6,7 @@
 struct repository;
 
 /**
- * Refer to Documentation/technical/api-parse-options.txt for the API doc.
+ * Refer to Documentation/technical/api-parse-options.adoc for the API doc.
  */
 
 enum parse_opt_type {
@@ -402,6 +402,10 @@ int parse_options(int argc, const char **argv, const char *prefix,
 NORETURN void usage_with_options(const char * const *usagestr,
 				 const struct option *options);
 
+void show_usage_with_options_if_asked(int ac, const char **av,
+				      const char * const *usage,
+				      const struct option *options);
+
 NORETURN void usage_msg_opt(const char *msg,
 			    const char * const *usagestr,
 			    const struct option *options);
@@ -432,6 +436,15 @@ static inline void die_for_incompatible_opt3(int opt1, const char *opt1_name,
 				  0, "");
 }
 
+static inline void die_for_incompatible_opt2(int opt1, const char *opt1_name,
+					     int opt2, const char *opt2_name)
+{
+	die_for_incompatible_opt4(opt1, opt1_name,
+				  opt2, opt2_name,
+				  0, "",
+				  0, "");
+}
+
 /*
  * Use these assertions for callbacks that expect to be called with NONEG and
  * NOARG respectively, and do not otherwise handle the "unset" and "arg"
diff --git a/path-walk.c b/path-walk.c
new file mode 100644
index 0000000..341bdd2
--- /dev/null
+++ b/path-walk.c
@@ -0,0 +1,609 @@
+/*
+ * path-walk.c: implementation for path-based walks of the object graph.
+ */
+#include "git-compat-util.h"
+#include "path-walk.h"
+#include "blob.h"
+#include "commit.h"
+#include "dir.h"
+#include "hashmap.h"
+#include "hex.h"
+#include "list-objects.h"
+#include "object.h"
+#include "oid-array.h"
+#include "prio-queue.h"
+#include "repository.h"
+#include "revision.h"
+#include "string-list.h"
+#include "strmap.h"
+#include "tag.h"
+#include "trace2.h"
+#include "tree.h"
+#include "tree-walk.h"
+
+static const char *root_path = "";
+
+struct type_and_oid_list {
+	enum object_type type;
+	struct oid_array oids;
+	int maybe_interesting;
+};
+
+#define TYPE_AND_OID_LIST_INIT { \
+	.type = OBJ_NONE, 	 \
+	.oids = OID_ARRAY_INIT	 \
+}
+
+struct path_walk_context {
+	/**
+	 * Repeats of data in 'struct path_walk_info' for
+	 * access with fewer characters.
+	 */
+	struct repository *repo;
+	struct rev_info *revs;
+	struct path_walk_info *info;
+
+	/**
+	 * Map a path to a 'struct type_and_oid_list'
+	 * containing the objects discovered at that
+	 * path.
+	 */
+	struct strmap paths_to_lists;
+
+	/**
+	 * Store the current list of paths in a priority queue,
+	 * using object type as a sorting mechanism, mostly to
+	 * make sure blobs are popped off the stack first. No
+	 * other sort is made, so within each object type it acts
+	 * like a stack and performs a DFS within the trees.
+	 *
+	 * Use path_stack_pushed to indicate whether a path
+	 * was previously added to path_stack.
+	 */
+	struct prio_queue path_stack;
+	struct strset path_stack_pushed;
+};
+
+static int compare_by_type(const void *one, const void *two, void *cb_data)
+{
+	struct type_and_oid_list *list1, *list2;
+	const char *str1 = one;
+	const char *str2 = two;
+	struct path_walk_context *ctx = cb_data;
+
+	list1 = strmap_get(&ctx->paths_to_lists, str1);
+	list2 = strmap_get(&ctx->paths_to_lists, str2);
+
+	/*
+	 * If object types are equal, then use path comparison.
+	 */
+	if (!list1 || !list2 || list1->type == list2->type)
+		return strcmp(str1, str2);
+
+	/* Prefer tags to be popped off first. */
+	if (list1->type == OBJ_TAG)
+		return -1;
+	if (list2->type == OBJ_TAG)
+		return 1;
+
+	/* Prefer blobs to be popped off second. */
+	if (list1->type == OBJ_BLOB)
+		return -1;
+	if (list2->type == OBJ_BLOB)
+		return 1;
+
+	return 0;
+}
+
+static void push_to_stack(struct path_walk_context *ctx,
+			  const char *path)
+{
+	if (strset_contains(&ctx->path_stack_pushed, path))
+		return;
+
+	strset_add(&ctx->path_stack_pushed, path);
+	prio_queue_put(&ctx->path_stack, xstrdup(path));
+}
+
+static int add_tree_entries(struct path_walk_context *ctx,
+			    const char *base_path,
+			    struct object_id *oid)
+{
+	struct tree_desc desc;
+	struct name_entry entry;
+	struct strbuf path = STRBUF_INIT;
+	size_t base_len;
+	struct tree *tree = lookup_tree(ctx->repo, oid);
+
+	if (!tree) {
+		error(_("failed to walk children of tree %s: not found"),
+		      oid_to_hex(oid));
+		return -1;
+	} else if (parse_tree_gently(tree, 1)) {
+		error("bad tree object %s", oid_to_hex(oid));
+		return -1;
+	}
+
+	strbuf_addstr(&path, base_path);
+	base_len = path.len;
+
+	init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
+	while (tree_entry(&desc, &entry)) {
+		struct type_and_oid_list *list;
+		struct object *o;
+		/* Not actually true, but we will ignore submodules later. */
+		enum object_type type = S_ISDIR(entry.mode) ? OBJ_TREE : OBJ_BLOB;
+
+		/* Skip submodules. */
+		if (S_ISGITLINK(entry.mode))
+			continue;
+
+		/* If the caller doesn't want blobs, then don't bother. */
+		if (!ctx->info->blobs && type == OBJ_BLOB)
+			continue;
+
+		if (type == OBJ_TREE) {
+			struct tree *child = lookup_tree(ctx->repo, &entry.oid);
+			o = child ? &child->object : NULL;
+		} else if (type == OBJ_BLOB) {
+			struct blob *child = lookup_blob(ctx->repo, &entry.oid);
+			o = child ? &child->object : NULL;
+		} else {
+			BUG("invalid type for tree entry: %d", type);
+		}
+
+		if (!o) {
+			error(_("failed to find object %s"),
+			      oid_to_hex(&o->oid));
+			return -1;
+		}
+
+		/* Skip this object if already seen. */
+		if (o->flags & SEEN)
+			continue;
+		o->flags |= SEEN;
+
+		strbuf_setlen(&path, base_len);
+		strbuf_add(&path, entry.path, entry.pathlen);
+
+		/*
+		 * Trees will end with "/" for concatenation and distinction
+		 * from blobs at the same path.
+		 */
+		if (type == OBJ_TREE)
+			strbuf_addch(&path, '/');
+
+		if (ctx->info->pl) {
+			int dtype;
+			enum pattern_match_result match;
+			match = path_matches_pattern_list(path.buf, path.len,
+							  path.buf + base_len, &dtype,
+							  ctx->info->pl,
+							  ctx->repo->index);
+
+			if (ctx->info->pl->use_cone_patterns &&
+			    match == NOT_MATCHED)
+				continue;
+			else if (!ctx->info->pl->use_cone_patterns &&
+				 type == OBJ_BLOB &&
+				 match != MATCHED)
+				continue;
+		}
+
+		if (!(list = strmap_get(&ctx->paths_to_lists, path.buf))) {
+			CALLOC_ARRAY(list, 1);
+			list->type = type;
+			strmap_put(&ctx->paths_to_lists, path.buf, list);
+		}
+		push_to_stack(ctx, path.buf);
+
+		if (!(o->flags & UNINTERESTING))
+			list->maybe_interesting = 1;
+
+		oid_array_append(&list->oids, &entry.oid);
+	}
+
+	free_tree_buffer(tree);
+	strbuf_release(&path);
+	return 0;
+}
+
+/*
+ * For each path in paths_to_explore, walk the trees another level
+ * and add any found blobs to the batch (but only if they exist and
+ * haven't been added yet).
+ */
+static int walk_path(struct path_walk_context *ctx,
+		     const char *path)
+{
+	struct type_and_oid_list *list;
+	int ret = 0;
+
+	list = strmap_get(&ctx->paths_to_lists, path);
+
+	if (!list)
+		BUG("provided path '%s' that had no associated list", path);
+
+	if (!list->oids.nr)
+		return 0;
+
+	if (ctx->info->prune_all_uninteresting) {
+		/*
+		 * This is true if all objects were UNINTERESTING
+		 * when added to the list.
+		 */
+		if (!list->maybe_interesting)
+			return 0;
+
+		/*
+		 * But it's still possible that the objects were set
+		 * as UNINTERESTING after being added. Do a quick check.
+		 */
+		list->maybe_interesting = 0;
+		for (size_t i = 0;
+		     !list->maybe_interesting && i < list->oids.nr;
+		     i++) {
+			if (list->type == OBJ_TREE) {
+				struct tree *t = lookup_tree(ctx->repo,
+							     &list->oids.oid[i]);
+				if (t && !(t->object.flags & UNINTERESTING))
+					list->maybe_interesting = 1;
+			} else if (list->type == OBJ_BLOB) {
+				struct blob *b = lookup_blob(ctx->repo,
+							     &list->oids.oid[i]);
+				if (b && !(b->object.flags & UNINTERESTING))
+					list->maybe_interesting = 1;
+			} else {
+				/* Tags are always interesting if visited. */
+				list->maybe_interesting = 1;
+			}
+		}
+
+		/* We have confirmed that all objects are UNINTERESTING. */
+		if (!list->maybe_interesting)
+			return 0;
+	}
+
+	/* Evaluate function pointer on this data, if requested. */
+	if ((list->type == OBJ_TREE && ctx->info->trees) ||
+	    (list->type == OBJ_BLOB && ctx->info->blobs) ||
+	    (list->type == OBJ_TAG && ctx->info->tags))
+		ret = ctx->info->path_fn(path, &list->oids, list->type,
+					ctx->info->path_fn_data);
+
+	/* Expand data for children. */
+	if (list->type == OBJ_TREE) {
+		for (size_t i = 0; i < list->oids.nr; i++) {
+			ret |= add_tree_entries(ctx,
+					    path,
+					    &list->oids.oid[i]);
+		}
+	}
+
+	oid_array_clear(&list->oids);
+	strmap_remove(&ctx->paths_to_lists, path, 1);
+	return ret;
+}
+
+static void clear_paths_to_lists(struct strmap *map)
+{
+	struct hashmap_iter iter;
+	struct strmap_entry *e;
+
+	hashmap_for_each_entry(&map->map, &iter, e, ent) {
+		struct type_and_oid_list *list = e->value;
+		oid_array_clear(&list->oids);
+	}
+	strmap_clear(map, 1);
+	strmap_init(map);
+}
+
+static struct repository *edge_repo;
+static struct type_and_oid_list *edge_tree_list;
+
+static void show_edge(struct commit *commit)
+{
+	struct tree *t = repo_get_commit_tree(edge_repo, commit);
+
+	if (!t)
+		return;
+
+	if (commit->object.flags & UNINTERESTING)
+		t->object.flags |= UNINTERESTING;
+
+	if (t->object.flags & SEEN)
+		return;
+	t->object.flags |= SEEN;
+
+	oid_array_append(&edge_tree_list->oids, &t->object.oid);
+}
+
+static int setup_pending_objects(struct path_walk_info *info,
+				 struct path_walk_context *ctx)
+{
+	struct type_and_oid_list *tags = NULL;
+	struct type_and_oid_list *tagged_blobs = NULL;
+	struct type_and_oid_list *root_tree_list = NULL;
+
+	if (info->tags)
+		CALLOC_ARRAY(tags, 1);
+	if (info->blobs)
+		CALLOC_ARRAY(tagged_blobs, 1);
+	if (info->trees)
+		root_tree_list = strmap_get(&ctx->paths_to_lists, root_path);
+
+	/*
+	 * Pending objects include:
+	 * * Commits at branch tips.
+	 * * Annotated tags at tag tips.
+	 * * Any kind of object at lightweight tag tips.
+	 * * Trees and blobs in the index (with an associated path).
+	 */
+	for (size_t i = 0; i < info->revs->pending.nr; i++) {
+		struct object_array_entry *pending = info->revs->pending.objects + i;
+		struct object *obj = pending->item;
+
+		/* Commits will be picked up by revision walk. */
+		if (obj->type == OBJ_COMMIT)
+			continue;
+
+		/* Navigate annotated tag object chains. */
+		while (obj->type == OBJ_TAG) {
+			struct tag *tag = lookup_tag(info->revs->repo, &obj->oid);
+			if (!tag) {
+				error(_("failed to find tag %s"),
+				      oid_to_hex(&obj->oid));
+				return -1;
+			}
+			if (tag->object.flags & SEEN)
+				break;
+			tag->object.flags |= SEEN;
+
+			if (tags)
+				oid_array_append(&tags->oids, &obj->oid);
+			obj = tag->tagged;
+		}
+
+		if (obj->type == OBJ_TAG)
+			continue;
+
+		/* We are now at a non-tag object. */
+		if (obj->flags & SEEN)
+			continue;
+		obj->flags |= SEEN;
+
+		switch (obj->type) {
+		case OBJ_TREE:
+			if (!info->trees)
+				continue;
+			if (pending->path) {
+				struct type_and_oid_list *list;
+				char *path = *pending->path ? xstrfmt("%s/", pending->path)
+							    : xstrdup("");
+				if (!(list = strmap_get(&ctx->paths_to_lists, path))) {
+					CALLOC_ARRAY(list, 1);
+					list->type = OBJ_TREE;
+					strmap_put(&ctx->paths_to_lists, path, list);
+				}
+				oid_array_append(&list->oids, &obj->oid);
+				free(path);
+			} else {
+				/* assume a root tree, such as a lightweight tag. */
+				oid_array_append(&root_tree_list->oids, &obj->oid);
+			}
+			break;
+
+		case OBJ_BLOB:
+			if (!info->blobs)
+				continue;
+			if (pending->path) {
+				struct type_and_oid_list *list;
+				char *path = pending->path;
+				if (!(list = strmap_get(&ctx->paths_to_lists, path))) {
+					CALLOC_ARRAY(list, 1);
+					list->type = OBJ_BLOB;
+					strmap_put(&ctx->paths_to_lists, path, list);
+				}
+				oid_array_append(&list->oids, &obj->oid);
+			} else {
+				/* assume a root tree, such as a lightweight tag. */
+				oid_array_append(&tagged_blobs->oids, &obj->oid);
+			}
+			break;
+
+		case OBJ_COMMIT:
+			/* Make sure it is in the object walk */
+			if (obj != pending->item)
+				add_pending_object(info->revs, obj, "");
+			break;
+
+		default:
+			BUG("should not see any other type here");
+		}
+	}
+
+	/*
+	 * Add tag objects and tagged blobs if they exist.
+	 */
+	if (tagged_blobs) {
+		if (tagged_blobs->oids.nr) {
+			const char *tagged_blob_path = "/tagged-blobs";
+			tagged_blobs->type = OBJ_BLOB;
+			tagged_blobs->maybe_interesting = 1;
+			strmap_put(&ctx->paths_to_lists, tagged_blob_path, tagged_blobs);
+			push_to_stack(ctx, tagged_blob_path);
+		} else {
+			oid_array_clear(&tagged_blobs->oids);
+			free(tagged_blobs);
+		}
+	}
+	if (tags) {
+		if (tags->oids.nr) {
+			const char *tag_path = "/tags";
+			tags->type = OBJ_TAG;
+			tags->maybe_interesting = 1;
+			strmap_put(&ctx->paths_to_lists, tag_path, tags);
+			push_to_stack(ctx, tag_path);
+		} else {
+			oid_array_clear(&tags->oids);
+			free(tags);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Given the configuration of 'info', walk the commits based on 'info->revs' and
+ * call 'info->path_fn' on each discovered path.
+ *
+ * Returns nonzero on an error.
+ */
+int walk_objects_by_path(struct path_walk_info *info)
+{
+	int ret;
+	size_t commits_nr = 0, paths_nr = 0;
+	struct commit *c;
+	struct type_and_oid_list *root_tree_list;
+	struct type_and_oid_list *commit_list;
+	struct path_walk_context ctx = {
+		.repo = info->revs->repo,
+		.revs = info->revs,
+		.info = info,
+		.path_stack = {
+			.compare = compare_by_type,
+			.cb_data = &ctx
+		},
+		.path_stack_pushed = STRSET_INIT,
+		.paths_to_lists = STRMAP_INIT
+	};
+
+	trace2_region_enter("path-walk", "commit-walk", info->revs->repo);
+
+	CALLOC_ARRAY(commit_list, 1);
+	commit_list->type = OBJ_COMMIT;
+
+	if (info->tags)
+		info->revs->tag_objects = 1;
+
+	/* Insert a single list for the root tree into the paths. */
+	CALLOC_ARRAY(root_tree_list, 1);
+	root_tree_list->type = OBJ_TREE;
+	root_tree_list->maybe_interesting = 1;
+	strmap_put(&ctx.paths_to_lists, root_path, root_tree_list);
+	push_to_stack(&ctx, root_path);
+
+	/*
+	 * Set these values before preparing the walk to catch
+	 * lightweight tags pointing to non-commits and indexed objects.
+	 */
+	info->revs->blob_objects = info->blobs;
+	info->revs->tree_objects = info->trees;
+
+	if (prepare_revision_walk(info->revs))
+		die(_("failed to setup revision walk"));
+
+	/* Walk trees to mark them as UNINTERESTING. */
+	edge_repo = info->revs->repo;
+	edge_tree_list = root_tree_list;
+	mark_edges_uninteresting(info->revs, show_edge,
+				 info->prune_all_uninteresting);
+	edge_repo = NULL;
+	edge_tree_list = NULL;
+
+	info->revs->blob_objects = info->revs->tree_objects = 0;
+
+	trace2_region_enter("path-walk", "pending-walk", info->revs->repo);
+	ret = setup_pending_objects(info, &ctx);
+	trace2_region_leave("path-walk", "pending-walk", info->revs->repo);
+
+	if (ret)
+		return ret;
+
+	while ((c = get_revision(info->revs))) {
+		struct object_id *oid;
+		struct tree *t;
+		commits_nr++;
+
+		if (info->commits)
+			oid_array_append(&commit_list->oids,
+					 &c->object.oid);
+
+		/* If we only care about commits, then skip trees. */
+		if (!info->trees && !info->blobs)
+			continue;
+
+		oid = get_commit_tree_oid(c);
+		t = lookup_tree(info->revs->repo, oid);
+
+		if (!t) {
+			error("could not find tree %s", oid_to_hex(oid));
+			return -1;
+		}
+
+		if (t->object.flags & SEEN)
+			continue;
+		t->object.flags |= SEEN;
+		oid_array_append(&root_tree_list->oids, oid);
+	}
+
+	trace2_data_intmax("path-walk", ctx.repo, "commits", commits_nr);
+	trace2_region_leave("path-walk", "commit-walk", info->revs->repo);
+
+	/* Track all commits. */
+	if (info->commits && commit_list->oids.nr)
+		ret = info->path_fn("", &commit_list->oids, OBJ_COMMIT,
+				    info->path_fn_data);
+	oid_array_clear(&commit_list->oids);
+	free(commit_list);
+
+	trace2_region_enter("path-walk", "path-walk", info->revs->repo);
+	while (!ret && ctx.path_stack.nr) {
+		char *path = prio_queue_get(&ctx.path_stack);
+		paths_nr++;
+
+		ret = walk_path(&ctx, path);
+
+		free(path);
+	}
+
+	/* Are there paths remaining? Likely they are from indexed objects. */
+	if (!strmap_empty(&ctx.paths_to_lists)) {
+		struct hashmap_iter iter;
+		struct strmap_entry *entry;
+
+		strmap_for_each_entry(&ctx.paths_to_lists, &iter, entry)
+			push_to_stack(&ctx, entry->key);
+
+		while (!ret && ctx.path_stack.nr) {
+			char *path = prio_queue_get(&ctx.path_stack);
+			paths_nr++;
+
+			ret = walk_path(&ctx, path);
+
+			free(path);
+		}
+	}
+
+	trace2_data_intmax("path-walk", ctx.repo, "paths", paths_nr);
+	trace2_region_leave("path-walk", "path-walk", info->revs->repo);
+
+	clear_paths_to_lists(&ctx.paths_to_lists);
+	strset_clear(&ctx.path_stack_pushed);
+	clear_prio_queue(&ctx.path_stack);
+	return ret;
+}
+
+void path_walk_info_init(struct path_walk_info *info)
+{
+	struct path_walk_info empty = PATH_WALK_INFO_INIT;
+	memcpy(info, &empty, sizeof(empty));
+}
+
+void path_walk_info_clear(struct path_walk_info *info)
+{
+	if (info->pl) {
+		clear_pattern_list(info->pl);
+		free(info->pl);
+	}
+}
diff --git a/path-walk.h b/path-walk.h
new file mode 100644
index 0000000..473ee9d
--- /dev/null
+++ b/path-walk.h
@@ -0,0 +1,80 @@
+/*
+ * path-walk.h : Methods and structures for walking the object graph in batches
+ * by the paths that can reach those objects.
+ */
+#include "object.h" /* Required for 'enum object_type'. */
+
+struct rev_info;
+struct oid_array;
+struct pattern_list;
+
+/**
+ * The type of a function pointer for the method that is called on a list of
+ * objects reachable at a given path.
+ */
+typedef int (*path_fn)(const char *path,
+		       struct oid_array *oids,
+		       enum object_type type,
+		       void *data);
+
+struct path_walk_info {
+	/**
+	 * revs provides the definitions for the commit walk, including
+	 * which commits are UNINTERESTING or not. This structure is
+	 * expected to be owned by the caller.
+	 */
+	struct rev_info *revs;
+
+	/**
+	 * The caller wishes to execute custom logic on objects reachable at a
+	 * given path. Every reachable object will be visited exactly once, and
+	 * the first path to see an object wins. This may not be a stable choice.
+	 */
+	path_fn path_fn;
+	void *path_fn_data;
+
+	/**
+	 * Initialize which object types the path_fn should be called on. This
+	 * could also limit the walk to skip blobs if not set.
+	 */
+	int commits;
+	int trees;
+	int blobs;
+	int tags;
+
+	/**
+	 * When 'prune_all_uninteresting' is set and a path has all objects
+	 * marked as UNINTERESTING, then the path-walk will not visit those
+	 * objects. It will not call path_fn on those objects and will not
+	 * walk the children of such trees.
+	 */
+	int prune_all_uninteresting;
+
+	/**
+	 * Specify a sparse-checkout definition to match our paths to. Do not
+	 * walk outside of this sparse definition. If the patterns are in
+	 * cone mode, then the search may prune directories that are outside
+	 * of the cone. If not in cone mode, then all tree paths will be
+	 * explored but the path_fn will only be called when the path matches
+	 * the sparse-checkout patterns.
+	 */
+	struct pattern_list *pl;
+};
+
+#define PATH_WALK_INFO_INIT {   \
+	.blobs = 1,		\
+	.trees = 1,		\
+	.commits = 1,		\
+	.tags = 1,		\
+}
+
+void path_walk_info_init(struct path_walk_info *info);
+void path_walk_info_clear(struct path_walk_info *info);
+
+/**
+ * Given the configuration of 'info', walk the commits based on 'info->revs' and
+ * call 'info->path_fn' on each discovered path.
+ *
+ * Returns nonzero on an error.
+ */
+int walk_objects_by_path(struct path_walk_info *info);
diff --git a/path.c b/path.c
index 07964f5..910756c 100644
--- a/path.c
+++ b/path.c
@@ -2,8 +2,6 @@
  * Utilities for paths and pathnames
  */
 
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "abspath.h"
 #include "environment.h"
@@ -30,7 +28,7 @@ static int get_st_mode_bits(const char *path, int *mode)
 	return 0;
 }
 
-struct strbuf *get_pathname(void)
+static struct strbuf *get_pathname(void)
 {
 	static struct strbuf pathname_array[4] = {
 		STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
@@ -387,10 +385,11 @@ void report_linked_checkout_garbage(struct repository *r)
 	strbuf_release(&sb);
 }
 
-static void adjust_git_path(const struct repository *repo,
+static void adjust_git_path(struct repository *repo,
 			    struct strbuf *buf, int git_dir_len)
 {
 	const char *base = buf->buf + git_dir_len;
+
 	if (is_dir_file(base, "info", "grafts"))
 		strbuf_splice(buf, 0, buf->len,
 			      repo->graft_file, strlen(repo->graft_file));
@@ -399,8 +398,8 @@ static void adjust_git_path(const struct repository *repo,
 			      repo->index_file, strlen(repo->index_file));
 	else if (dir_prefix(base, "objects"))
 		replace_dir(buf, git_dir_len + 7, repo->objects->odb->path);
-	else if (git_hooks_path && dir_prefix(base, "hooks"))
-		replace_dir(buf, git_dir_len + 5, git_hooks_path);
+	else if (repo_settings_get_hooks_path(repo) && dir_prefix(base, "hooks"))
+		replace_dir(buf, git_dir_len + 5, repo_settings_get_hooks_path(repo));
 	else if (repo->different_commondir)
 		update_common_dir(buf, git_dir_len, repo->commondir);
 }
@@ -414,12 +413,12 @@ static void strbuf_worktree_gitdir(struct strbuf *buf,
 	else if (!wt->id)
 		strbuf_addstr(buf, repo->commondir);
 	else
-		strbuf_git_common_path(buf, repo, "worktrees/%s", wt->id);
+		repo_common_path_append(repo, buf, "worktrees/%s", wt->id);
 }
 
-void repo_git_pathv(const struct repository *repo,
-		    const struct worktree *wt, struct strbuf *buf,
-		    const char *fmt, va_list args)
+static void repo_git_pathv(struct repository *repo,
+			   const struct worktree *wt, struct strbuf *buf,
+			   const char *fmt, va_list args)
 {
 	int gitdir_len;
 	strbuf_worktree_gitdir(buf, repo, wt);
@@ -432,7 +431,7 @@ void repo_git_pathv(const struct repository *repo,
 	strbuf_cleanup_path(buf);
 }
 
-char *repo_git_path(const struct repository *repo,
+char *repo_git_path(struct repository *repo,
 		    const char *fmt, ...)
 {
 	struct strbuf path = STRBUF_INIT;
@@ -443,14 +442,27 @@ char *repo_git_path(const struct repository *repo,
 	return strbuf_detach(&path, NULL);
 }
 
-void strbuf_repo_git_path(struct strbuf *sb,
-			  const struct repository *repo,
-			  const char *fmt, ...)
+const char *repo_git_path_append(struct repository *repo,
+				 struct strbuf *sb,
+				 const char *fmt, ...)
 {
 	va_list args;
 	va_start(args, fmt);
 	repo_git_pathv(repo, NULL, sb, fmt, args);
 	va_end(args);
+	return sb->buf;
+}
+
+const char *repo_git_path_replace(struct repository *repo,
+				  struct strbuf *sb,
+				  const char *fmt, ...)
+{
+	va_list args;
+	strbuf_reset(sb);
+	va_start(args, fmt);
+	repo_git_pathv(repo, NULL, sb, fmt, args);
+	va_end(args);
+	return sb->buf;
 }
 
 char *mkpathdup(const char *fmt, ...)
@@ -506,9 +518,6 @@ char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)
 	struct strbuf path = STRBUF_INIT;
 	va_list args;
 
-	if (!repo->worktree)
-		return NULL;
-
 	va_start(args, fmt);
 	do_worktree_path(repo, &path, fmt, args);
 	va_end(args);
@@ -516,29 +525,49 @@ char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)
 	return strbuf_detach(&path, NULL);
 }
 
-void strbuf_repo_worktree_path(struct strbuf *sb,
-			       const struct repository *repo,
-			       const char *fmt, ...)
+const char *repo_worktree_path_append(const struct repository *repo,
+				      struct strbuf *sb,
+				      const char *fmt, ...)
 {
 	va_list args;
 
 	if (!repo->worktree)
-		return;
+		return NULL;
 
 	va_start(args, fmt);
 	do_worktree_path(repo, sb, fmt, args);
 	va_end(args);
+
+	return sb->buf;
+}
+
+const char *repo_worktree_path_replace(const struct repository *repo,
+				       struct strbuf *sb,
+				       const char *fmt, ...)
+{
+	va_list args;
+
+	strbuf_reset(sb);
+	if (!repo->worktree)
+		return NULL;
+
+	va_start(args, fmt);
+	do_worktree_path(repo, sb, fmt, args);
+	va_end(args);
+
+	return sb->buf;
 }
 
 /* Returns 0 on success, negative on failure. */
-static int do_submodule_path(struct strbuf *buf, const char *path,
+static int do_submodule_path(struct repository *repo,
+			     struct strbuf *buf, const char *path,
 			     const char *fmt, va_list args)
 {
 	struct strbuf git_submodule_common_dir = STRBUF_INIT;
 	struct strbuf git_submodule_dir = STRBUF_INIT;
 	int ret;
 
-	ret = submodule_to_gitdir(&git_submodule_dir, path);
+	ret = submodule_to_gitdir(repo, &git_submodule_dir, path);
 	if (ret)
 		goto cleanup;
 
@@ -557,13 +586,14 @@ static int do_submodule_path(struct strbuf *buf, const char *path,
 	return ret;
 }
 
-char *git_pathdup_submodule(const char *path, const char *fmt, ...)
+char *repo_submodule_path(struct repository *repo,
+			  const char *path, const char *fmt, ...)
 {
 	int err;
 	va_list args;
 	struct strbuf buf = STRBUF_INIT;
 	va_start(args, fmt);
-	err = do_submodule_path(&buf, path, fmt, args);
+	err = do_submodule_path(repo, &buf, path, fmt, args);
 	va_end(args);
 	if (err) {
 		strbuf_release(&buf);
@@ -572,22 +602,41 @@ char *git_pathdup_submodule(const char *path, const char *fmt, ...)
 	return strbuf_detach(&buf, NULL);
 }
 
-int strbuf_git_path_submodule(struct strbuf *buf, const char *path,
-			      const char *fmt, ...)
+const char *repo_submodule_path_append(struct repository *repo,
+				       struct strbuf *buf,
+				       const char *path,
+				       const char *fmt, ...)
 {
 	int err;
 	va_list args;
 	va_start(args, fmt);
-	err = do_submodule_path(buf, path, fmt, args);
+	err = do_submodule_path(repo, buf, path, fmt, args);
 	va_end(args);
-
-	return err;
+	if (err)
+		return NULL;
+	return buf->buf;
 }
 
-void repo_common_pathv(const struct repository *repo,
-		       struct strbuf *sb,
-		       const char *fmt,
-		       va_list args)
+const char *repo_submodule_path_replace(struct repository *repo,
+					struct strbuf *buf,
+					const char *path,
+					const char *fmt, ...)
+{
+	int err;
+	va_list args;
+	strbuf_reset(buf);
+	va_start(args, fmt);
+	err = do_submodule_path(repo, buf, path, fmt, args);
+	va_end(args);
+	if (err)
+		return NULL;
+	return buf->buf;
+}
+
+static void repo_common_pathv(const struct repository *repo,
+			      struct strbuf *sb,
+			      const char *fmt,
+			      va_list args)
 {
 	strbuf_addstr(sb, repo->commondir);
 	if (sb->len && !is_dir_sep(sb->buf[sb->len - 1]))
@@ -596,14 +645,38 @@ void repo_common_pathv(const struct repository *repo,
 	strbuf_cleanup_path(sb);
 }
 
-void strbuf_git_common_path(struct strbuf *sb,
-			    const struct repository *repo,
-			    const char *fmt, ...)
+char *repo_common_path(const struct repository *repo,
+		       const char *fmt, ...)
+{
+	struct strbuf sb = STRBUF_INIT;
+	va_list args;
+	va_start(args, fmt);
+	repo_common_pathv(repo, &sb, fmt, args);
+	va_end(args);
+	return strbuf_detach(&sb, NULL);
+}
+
+const char *repo_common_path_append(const struct repository *repo,
+				    struct strbuf *sb,
+				    const char *fmt, ...)
 {
 	va_list args;
 	va_start(args, fmt);
 	repo_common_pathv(repo, sb, fmt, args);
 	va_end(args);
+	return sb->buf;
+}
+
+const char *repo_common_path_replace(const struct repository *repo,
+				     struct strbuf *sb,
+				     const char *fmt, ...)
+{
+	va_list args;
+	strbuf_reset(sb);
+	va_start(args, fmt);
+	repo_common_pathv(repo, sb, fmt, args);
+	va_end(args);
+	return sb->buf;
 }
 
 static struct passwd *getpw_str(const char *username, size_t len)
@@ -765,21 +838,22 @@ const char *enter_repo(const char *path, unsigned flags)
 	return NULL;
 }
 
-int calc_shared_perm(int mode)
+int calc_shared_perm(struct repository *repo,
+		     int mode)
 {
 	int tweak;
 
-	if (get_shared_repository() < 0)
-		tweak = -get_shared_repository();
+	if (repo_settings_get_shared_repository(repo) < 0)
+		tweak = -repo_settings_get_shared_repository(repo);
 	else
-		tweak = get_shared_repository();
+		tweak = repo_settings_get_shared_repository(repo);
 
 	if (!(mode & S_IWUSR))
 		tweak &= ~0222;
 	if (mode & S_IXUSR)
 		/* Copy read bits to execute bits */
 		tweak |= (tweak & 0444) >> 2;
-	if (get_shared_repository() < 0)
+	if (repo_settings_get_shared_repository(repo) < 0)
 		mode = (mode & ~0777) | tweak;
 	else
 		mode |= tweak;
@@ -787,17 +861,17 @@ int calc_shared_perm(int mode)
 	return mode;
 }
 
-
-int adjust_shared_perm(const char *path)
+int adjust_shared_perm(struct repository *repo,
+		       const char *path)
 {
 	int old_mode, new_mode;
 
-	if (!get_shared_repository())
+	if (!repo_settings_get_shared_repository(repo))
 		return 0;
 	if (get_st_mode_bits(path, &old_mode) < 0)
 		return -1;
 
-	new_mode = calc_shared_perm(old_mode);
+	new_mode = calc_shared_perm(repo, old_mode);
 	if (S_ISDIR(old_mode)) {
 		/* Copy read bits to execute bits */
 		new_mode |= (new_mode & 0444) >> 2;
@@ -816,7 +890,7 @@ int adjust_shared_perm(const char *path)
 	return 0;
 }
 
-void safe_create_dir(const char *dir, int share)
+void safe_create_dir(struct repository *repo, const char *dir, int share)
 {
 	if (mkdir(dir, 0777) < 0) {
 		if (errno != EEXIST) {
@@ -824,7 +898,7 @@ void safe_create_dir(const char *dir, int share)
 			exit(1);
 		}
 	}
-	else if (share && adjust_shared_perm(dir))
+	else if (share && adjust_shared_perm(repo, dir))
 		die(_("Could not make %s writable by group"), dir);
 }
 
diff --git a/path.h b/path.h
index 5f6c85e..65fe968 100644
--- a/path.h
+++ b/path.h
@@ -25,22 +25,20 @@ char *mkpathdup(const char *fmt, ...)
 	__attribute__((format (printf, 1, 2)));
 
 /*
- * The `strbuf_git_common_path` family of functions will construct a path into a
+ * The `repo_common_path` family of functions will construct a path into a
  * repository's common git directory, which is shared by all worktrees.
  */
-
-/*
- * Constructs a path into the common git directory of repository `repo` and
- * append it in the provided buffer `sb`.
- */
-void strbuf_git_common_path(struct strbuf *sb,
-			    const struct repository *repo,
-			    const char *fmt, ...)
+char *repo_common_path(const struct repository *repo,
+		       const char *fmt, ...)
+	__attribute__((format (printf, 2, 3)));
+const char *repo_common_path_append(const struct repository *repo,
+				    struct strbuf *sb,
+				    const char *fmt, ...)
 	__attribute__((format (printf, 3, 4)));
-void repo_common_pathv(const struct repository *repo,
-		       struct strbuf *buf,
-		       const char *fmt,
-		       va_list args);
+const char *repo_common_path_replace(const struct repository *repo,
+				     struct strbuf *sb,
+				     const char *fmt, ...)
+	__attribute__((format (printf, 3, 4)));
 
 /*
  * The `repo_git_path` family of functions will construct a path into a repository's
@@ -54,29 +52,16 @@ void repo_common_pathv(const struct repository *repo,
  * For an exhaustive list of the adjustments made look at `common_list` and
  * `adjust_git_path` in path.c.
  */
-
-/*
- * Return a path into the git directory of repository `repo`.
- */
-char *repo_git_path(const struct repository *repo,
+char *repo_git_path(struct repository *repo,
 		    const char *fmt, ...)
 	__attribute__((format (printf, 2, 3)));
-
-/*
- * Print a path into the git directory of repository `repo` into the provided
- * buffer.
- */
-void repo_git_pathv(const struct repository *repo,
-		    const struct worktree *wt, struct strbuf *buf,
-		    const char *fmt, va_list args);
-
-/*
- * Construct a path into the git directory of repository `repo` and append it
- * to the provided buffer `sb`.
- */
-void strbuf_repo_git_path(struct strbuf *sb,
-			  const struct repository *repo,
-			  const char *fmt, ...)
+const char *repo_git_path_append(struct repository *repo,
+				 struct strbuf *sb,
+				 const char *fmt, ...)
+	__attribute__((format (printf, 3, 4)));
+const char *repo_git_path_replace(struct repository *repo,
+				  struct strbuf *sb,
+				  const char *fmt, ...)
 	__attribute__((format (printf, 3, 4)));
 
 /*
@@ -90,41 +75,45 @@ const char *worktree_git_path(struct repository *r,
 	__attribute__((format (printf, 3, 4)));
 
 /*
- * Return a path into the worktree of repository `repo`.
+ * The `repo_worktree_path` family of functions will construct a path into a
+ * repository's worktree.
  *
- * If the repository doesn't have a worktree NULL is returned.
+ * Returns a `NULL` pointer in case the repository has no worktree.
  */
 char *repo_worktree_path(const struct repository *repo,
 				const char *fmt, ...)
 	__attribute__((format (printf, 2, 3)));
-
-/*
- * Construct a path into the worktree of repository `repo` and append it
- * to the provided buffer `sb`.
- *
- * If the repository doesn't have a worktree nothing will be appended to `sb`.
- */
-void strbuf_repo_worktree_path(struct strbuf *sb,
-				      const struct repository *repo,
+const char *repo_worktree_path_append(const struct repository *repo,
+				      struct strbuf *sb,
 				      const char *fmt, ...)
 	__attribute__((format (printf, 3, 4)));
-
-/*
- * Return a path into a submodule's git directory located at `path`.  `path`
- * must only reference a submodule of the main repository (the_repository).
- */
-char *git_pathdup_submodule(const char *path, const char *fmt, ...)
-	__attribute__((format (printf, 2, 3)));
-
-/*
- * Construct a path into a submodule's git directory located at `path` and
- * append it to the provided buffer `sb`.  `path` must only reference a
- * submodule of the main repository (the_repository).
- */
-int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
-				     const char *fmt, ...)
+const char *repo_worktree_path_replace(const struct repository *repo,
+				       struct strbuf *sb,
+				       const char *fmt, ...)
 	__attribute__((format (printf, 3, 4)));
 
+/*
+ * The `repo_submodule_path` family of functions will construct a path into a
+ * submodule's git directory located at `path`. `path` must be a submodule path
+ * as found in the index and must be part of the given repository.
+ *
+ * Returns a `NULL` pointer in case the submodule cannot be found.
+ */
+char *repo_submodule_path(struct repository *repo,
+			  const char *path,
+			  const char *fmt, ...)
+	__attribute__((format (printf, 3, 4)));
+const char *repo_submodule_path_append(struct repository *repo,
+				       struct strbuf *sb,
+				       const char *path,
+				       const char *fmt, ...)
+	__attribute__((format (printf, 4, 5)));
+const char *repo_submodule_path_replace(struct repository *repo,
+					struct strbuf *sb,
+					const char *path,
+					const char *fmt, ...)
+	__attribute__((format (printf, 4, 5)));
+
 void report_linked_checkout_garbage(struct repository *r);
 
 /*
@@ -152,8 +141,8 @@ const char *git_path_shallow(struct repository *r);
 
 int ends_with_path_components(const char *path, const char *components);
 
-int calc_shared_perm(int mode);
-int adjust_shared_perm(const char *path);
+int calc_shared_perm(struct repository *repo, int mode);
+int adjust_shared_perm(struct repository *repo, const char *path);
 
 char *interpolate_path(const char *path, int real_home);
 
@@ -230,101 +219,21 @@ char *xdg_cache_home(const char *filename);
  * directories under $GIT_DIR.  Don't use it for working tree
  * directories.
  */
-void safe_create_dir(const char *dir, int share);
-
-/*
- * Do not use this function. It is only exported to other subsystems until we
- * can get rid of the below block of functions that implicitly rely on
- * `the_repository`.
- */
-struct strbuf *get_pathname(void);
+void safe_create_dir(struct repository *repo, const char *dir, int share);
 
 # ifdef USE_THE_REPOSITORY_VARIABLE
 #  include "strbuf.h"
 #  include "repository.h"
 
-/*
- * Return a statically allocated path into the main repository's
- * (the_repository) common git directory.
- */
-__attribute__((format (printf, 1, 2)))
-static inline const char *git_common_path(const char *fmt, ...)
-{
-	struct strbuf *pathname = get_pathname();
-	va_list args;
-	va_start(args, fmt);
-	repo_common_pathv(the_repository, pathname, fmt, args);
-	va_end(args);
-	return pathname->buf;
-}
-
-/*
- * Construct a path into the main repository's (the_repository) git directory
- * and place it in the provided buffer `buf`, the contents of the buffer will
- * be overridden.
- */
-__attribute__((format (printf, 2, 3)))
-static inline char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
-{
-	va_list args;
-	strbuf_reset(buf);
-	va_start(args, fmt);
-	repo_git_pathv(the_repository, NULL, buf, fmt, args);
-	va_end(args);
-	return buf->buf;
-}
-
-/*
- * Construct a path into the main repository's (the_repository) git directory
- * and append it to the provided buffer `sb`.
- */
-__attribute__((format (printf, 2, 3)))
-static inline void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
-{
-	va_list args;
-	va_start(args, fmt);
-	repo_git_pathv(the_repository, NULL, sb, fmt, args);
-	va_end(args);
-}
-
-/*
- * Return a statically allocated path into the main repository's
- * (the_repository) git directory.
- */
-__attribute__((format (printf, 1, 2)))
-static inline const char *git_path(const char *fmt, ...)
-{
-	struct strbuf *pathname = get_pathname();
-	va_list args;
-	va_start(args, fmt);
-	repo_git_pathv(the_repository, NULL, pathname, fmt, args);
-	va_end(args);
-	return pathname->buf;
-}
-
 #define GIT_PATH_FUNC(func, filename) \
 	const char *func(void) \
 	{ \
 		static char *ret; \
 		if (!ret) \
-			ret = git_pathdup(filename); \
+			ret = repo_git_path(the_repository, filename); \
 		return ret; \
 	}
 
-/*
- * Return a path into the main repository's (the_repository) git directory.
- */
-__attribute__((format (printf, 1, 2)))
-static inline char *git_pathdup(const char *fmt, ...)
-{
-	struct strbuf path = STRBUF_INIT;
-	va_list args;
-	va_start(args, fmt);
-	repo_git_pathv(the_repository, NULL, &path, fmt, args);
-	va_end(args);
-	return strbuf_detach(&path, NULL);
-}
-
 # endif /* USE_THE_REPOSITORY_VARIABLE */
 
 #endif /* PATH_H */
diff --git a/po/bg.po b/po/bg.po
index 2fc6c2b..37d127f 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, 2023, 2024 Alexander Shopov <ash@kambanaria.org>.
+# Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025 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, 2023, 2024.
+# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025.
 # ========================
 # DICTIONARY TO MERGE IN GIT GUI
 # ------------------------
@@ -233,6 +233,7 @@
 # cache-tree кеша на обектите-дървета
 # acquire lock придобивам ключалка
 # detached отделѐн, несвързан
+# revision walk обхождане на версиите
 #
 # ------------------------
 # „$var“ - може да не сработва за shell има gettext и eval_gettext - проверка - намират се лесно по „$
@@ -261,8 +262,8 @@
 msgstr ""
 "Project-Id-Version: git 2.48\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-12-27 22:37+0100\n"
-"PO-Revision-Date: 2024-12-27 22:40+0100\n"
+"POT-Creation-Date: 2025-03-05 22:57+0000\n"
+"PO-Revision-Date: 2025-03-06 09:15+0100\n"
 "Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
 "Language-Team: Bulgarian <dict@fsa-bg.org>\n"
 "Language: bg\n"
@@ -2655,6 +2656,18 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: очакваше се изчистване на буферите чрез „flush“"
 
+msgid "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+msgstr "git backfill [--min-batch-size=БРОЙ] [--[no-]sparse]"
+
+msgid "problem loading sparse-checkout"
+msgstr "проблем при зареждане на частично хранилище"
+
+msgid "Minimum number of objects to request at a time"
+msgstr "Минимален БРОЙ обекти заявявани наведнъж"
+
+msgid "Restrict the missing objects to the current sparse-checkout"
+msgstr "Ограничаване на липсващите обекти до текущото частично хранилище"
+
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
 "checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
@@ -3434,10 +3447,6 @@
 msgid "git version:\n"
 msgstr "версия на git:\n"
 
-#, c-format
-msgid "uname() failed with error '%s' (%d)\n"
-msgstr "грешка при изпълнението на „uname()“ — „%s“ (%d)\n"
-
 msgid "compiler info: "
 msgstr "компилатор: "
 
@@ -4466,130 +4475,6 @@
 "Настройката „clean.requireForce“ е зададена, което изисква опцията „-f“.  "
 "Няма да се извърши изчистване"
 
-msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [ОПЦИЯ…] [--] ХРАНИЛИЩЕ [ДИРЕКТОРИЯ]"
-
-msgid "don't clone shallow repository"
-msgstr "без клониране на плитко хранилище"
-
-msgid "don't create a checkout"
-msgstr "без създаване на работно дърво"
-
-msgid "create a bare repository"
-msgstr "създаване на голо хранилище"
-
-msgid "create a mirror repository (implies --bare)"
-msgstr ""
-"създаване на хранилище-огледало (включва опцията „--bare“ за голо хранилище)"
-
-msgid "to clone from a local repository"
-msgstr "клониране от локално хранилище"
-
-msgid "don't use local hardlinks, always copy"
-msgstr "без твърди връзки, файловете винаги да се копират"
-
-msgid "setup as shared repository"
-msgstr "настройване за споделено хранилище"
-
-msgid "pathspec"
-msgstr "път"
-
-msgid "initialize submodules in the clone"
-msgstr "инициализиране на подмодулите при това клониране"
-
-msgid "number of submodules cloned in parallel"
-msgstr "брой подмодули, клонирани паралелно"
-
-msgid "template-directory"
-msgstr "директория с шаблони"
-
-msgid "directory from which templates will be used"
-msgstr "директория, която съдържа шаблоните, които да се ползват"
-
-msgid "reference repository"
-msgstr "еталонно хранилище"
-
-msgid "use --reference only while cloning"
-msgstr "опцията „--reference“ може да се използва само при клониране"
-
-msgid "name"
-msgstr "ИМЕ"
-
-msgid "use <name> instead of 'origin' to track upstream"
-msgstr "използване на това ИМЕ вместо „origin“ при проследяване на клони"
-
-msgid "checkout <branch> instead of the remote's HEAD"
-msgstr "изтегляне на този КЛОН, а не соченият от отдалечения указател „HEAD“"
-
-msgid "path to git-upload-pack on the remote"
-msgstr "път към командата „git-upload-pack“ на отдалеченото хранилище"
-
-msgid "depth"
-msgstr "ДЪЛБОЧИНА"
-
-msgid "create a shallow clone of that depth"
-msgstr "плитко клониране до тази ДЪЛБОЧИНА"
-
-msgid "create a shallow clone since a specific time"
-msgstr "плитко клониране до момент във времето"
-
-msgid "ref"
-msgstr "УКАЗ"
-
-msgid "deepen history of shallow clone, excluding ref"
-msgstr "задълбочаване на историята на плитко хранилище до изключващ указател"
-
-msgid "clone only one branch, HEAD or --branch"
-msgstr ""
-"клониране само на един клон — или сочения от отдалечения „HEAD“, или изрично "
-"зададения с „--branch“"
-
-msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr ""
-"без клониране на етикети, като последващите доставяния няма да ги следят"
-
-msgid "any cloned submodules will be shallow"
-msgstr "всички клонирани подмодули ще са плитки"
-
-msgid "gitdir"
-msgstr "СЛУЖЕБНА_ДИРЕКТОРИЯ"
-
-msgid "separate git dir from working tree"
-msgstr "отделна СЛУЖЕБНА_ДИРЕКТОРИЯ за git извън работното дърво"
-
-msgid "specify the reference format to use"
-msgstr "указване на форма̀та за указател"
-
-msgid "key=value"
-msgstr "КЛЮЧ=СТОЙНОСТ"
-
-msgid "set config inside the new repository"
-msgstr "задаване на настройките на новото хранилище"
-
-msgid "server-specific"
-msgstr "специфични за сървъра"
-
-msgid "option to transmit"
-msgstr "опция за пренос"
-
-msgid "apply partial clone filters to submodules"
-msgstr "прилагане на филтрите за непълно хранилище към подмодулите"
-
-msgid "any cloned submodules will use their remote-tracking branch"
-msgstr "всички клонирани подмодули ще ползват следящите си клони"
-
-msgid "initialize sparse-checkout file to include only files at root"
-msgstr ""
-"инициализиране на файла за частично изтегляне („.git/info/sparse-checkout“) "
-"да съдържа само файловете в основната директория"
-
-msgid "uri"
-msgstr "АДРЕС"
-
-msgid "a URI for downloading bundles before fetching from origin remote"
-msgstr ""
-"АДРЕС за доставяне на пратки на git преди доставяне от отдалеченото хранилище"
-
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr ""
@@ -4656,12 +4541,6 @@
 "\n"
 "    git restore --source=HEAD :/\n"
 
-#, c-format
-msgid "Could not find remote branch %s to clone."
-msgstr ""
-"Клонът „%s“ от отдалеченото хранилище, което клонирате,\n"
-"и който следва да бъде изтеглен, не съществува."
-
 msgid "remote did not send all necessary objects"
 msgstr "отдалеченото хранилище не изпрати всички необходими обекти."
 
@@ -4689,6 +4568,132 @@
 msgid "cannot unlink temporary alternates file"
 msgstr "временният файл за алтернативни обекти не може да бъде изтрит"
 
+msgid "don't clone shallow repository"
+msgstr "без клониране на плитко хранилище"
+
+msgid "don't create a checkout"
+msgstr "без създаване на работно дърво"
+
+msgid "create a bare repository"
+msgstr "създаване на голо хранилище"
+
+msgid "create a mirror repository (implies --bare)"
+msgstr ""
+"създаване на хранилище-огледало (включва опцията „--bare“ за голо хранилище)"
+
+msgid "to clone from a local repository"
+msgstr "клониране от локално хранилище"
+
+msgid "don't use local hardlinks, always copy"
+msgstr "без твърди връзки, файловете винаги да се копират"
+
+msgid "setup as shared repository"
+msgstr "настройване за споделено хранилище"
+
+msgid "pathspec"
+msgstr "път"
+
+msgid "initialize submodules in the clone"
+msgstr "инициализиране на подмодулите при това клониране"
+
+msgid "number of submodules cloned in parallel"
+msgstr "брой подмодули, клонирани паралелно"
+
+msgid "template-directory"
+msgstr "директория с шаблони"
+
+msgid "directory from which templates will be used"
+msgstr "директория, която съдържа шаблоните, които да се ползват"
+
+msgid "reference repository"
+msgstr "еталонно хранилище"
+
+msgid "use --reference only while cloning"
+msgstr "опцията „--reference“ може да се използва само при клониране"
+
+msgid "name"
+msgstr "ИМЕ"
+
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "използване на това ИМЕ вместо „origin“ при проследяване на клони"
+
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "изтегляне на този КЛОН, а не соченият от отдалечения указател „HEAD“"
+
+msgid "clone single revision <rev> and check out"
+msgstr "клониране на единствена ВЕРСИЯ и изтегляне в работната директория"
+
+msgid "path to git-upload-pack on the remote"
+msgstr "път към командата „git-upload-pack“ на отдалеченото хранилище"
+
+msgid "depth"
+msgstr "ДЪЛБОЧИНА"
+
+msgid "create a shallow clone of that depth"
+msgstr "плитко клониране до тази ДЪЛБОЧИНА"
+
+msgid "create a shallow clone since a specific time"
+msgstr "плитко клониране до момент във времето"
+
+msgid "ref"
+msgstr "УКАЗ"
+
+msgid "deepen history of shallow clone, excluding ref"
+msgstr "задълбочаване на историята на плитко хранилище до изключващ указател"
+
+msgid "clone only one branch, HEAD or --branch"
+msgstr ""
+"клониране само на един клон — или сочения от отдалечения „HEAD“, или изрично "
+"зададения с „--branch“"
+
+msgid "clone tags, and make later fetches not to follow them"
+msgstr "клониране на етикети, като последващите доставяния няма да ги следят"
+
+msgid "any cloned submodules will be shallow"
+msgstr "всички клонирани подмодули ще са плитки"
+
+msgid "gitdir"
+msgstr "СЛУЖЕБНА_ДИРЕКТОРИЯ"
+
+msgid "separate git dir from working tree"
+msgstr "отделна СЛУЖЕБНА_ДИРЕКТОРИЯ за git извън работното дърво"
+
+msgid "specify the reference format to use"
+msgstr "указване на форма̀та за указател"
+
+msgid "key=value"
+msgstr "КЛЮЧ=СТОЙНОСТ"
+
+msgid "set config inside the new repository"
+msgstr "задаване на настройките на новото хранилище"
+
+msgid "server-specific"
+msgstr "специфични за сървъра"
+
+msgid "option to transmit"
+msgstr "опция за пренос"
+
+msgid "apply partial clone filters to submodules"
+msgstr "прилагане на филтрите за непълно хранилище към подмодулите"
+
+msgid "any cloned submodules will use their remote-tracking branch"
+msgstr "всички клонирани подмодули ще ползват следящите си клони"
+
+msgid "initialize sparse-checkout file to include only files at root"
+msgstr ""
+"инициализиране на файла за частично изтегляне („.git/info/sparse-checkout“) "
+"да съдържа само файловете в основната директория"
+
+msgid "uri"
+msgstr "АДРЕС"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr ""
+"АДРЕС за доставяне на пратки на git преди доставяне от отдалеченото хранилище"
+
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [ОПЦИЯ…] [--] ХРАНИЛИЩЕ [ДИРЕКТОРИЯ]"
+
 msgid "Too many arguments."
 msgstr "Прекалено много аргументи."
 
@@ -4796,6 +4801,10 @@
 msgid "Remote branch %s not found in upstream %s"
 msgstr "Отдалеченият клон „%s“ липсва в клонираното хранилище „%s“"
 
+#, c-format
+msgid "Remote revision %s not found in upstream %s"
+msgstr "Отдалечената версия „%s“ липсва в клонираното хранилище „%s“"
+
 msgid "You appear to have cloned an empty repository."
 msgstr "Изглежда клонирахте празно хранилище."
 
@@ -4975,7 +4984,7 @@
 msgstr "git commit-tree: не може да се прочете"
 
 msgid ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -4985,7 +4994,7 @@
 "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
 "           [--] [<pathspec>...]"
 msgstr ""
-"git commit [-a|--interactive|--patch] [-s] [-v] [-u РЕЖИМ] [--amend]\n"
+"git commit [-a|--interactive|--patch] [-s] [-v] [-u[РЕЖИМ]] [--amend]\n"
 "           [--dry-run] [(-c|-C|--squash) ПОДАВАНЕ |--fixup [(amend|"
 "reword):]ПОДАВАНЕ]\n"
 "           [-F ФАЙЛ|-m СЪОБЩЕНИЕ] [--reset-author] [--allow-empty]\n"
@@ -6424,8 +6433,8 @@
 "Run 'git remote set-head %s %s' to follow the change, or set\n"
 "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
 "if you do not want to see this message. Specifically running\n"
-"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
-"until the remote changes HEAD to something else."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"will disable the warning until the remote changes HEAD to something else."
 msgstr ""
 "Изпълнете\n"
 "\n"
@@ -6435,7 +6444,7 @@
 "„remote.%s.followRemoteHEAD, ако не искате тези съобщения.\n"
 "Изпълнението на\n"
 "\n"
-"    git config set remote.%s.followRemoteHEAD %s\n"
+"    git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s\n"
 "\n"
 "ще изключи предупреждението, докато отдалеченият указател HEAD не\n"
 "започне да сочи нещо друго."
@@ -7124,6 +7133,9 @@
 msgid "repack all other packs except the largest pack"
 msgstr "препакетиране на всичко без най-големия пакет"
 
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "префикс на имената на пакетите за окастрени обекти"
+
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
 msgstr "неразпозната стойност на „gc.logExpiry“ %s"
@@ -7944,6 +7956,10 @@
 msgstr "Процесът не може да се върне към предишната работна директория"
 
 #, c-format
+msgid "bad --pack_header: %s"
+msgstr "неправилна стойност за „--pack_header“: „%s“"
+
+#, c-format
 msgid "bad %s"
 msgstr "неправилна стойност „%s“"
 
@@ -8835,10 +8851,6 @@
 msgid "malformed input line: '%s'."
 msgstr "входен ред с неправилен формат: „%s“."
 
-#, c-format
-msgid "merging cannot continue; got unclean result of %d"
-msgstr "сливането не може да продължи — %d-тото завърши с грешка"
-
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [ОПЦИЯ…] [ПОДАВАНЕ…]"
 
@@ -9685,6 +9697,13 @@
 "СПИСЪК_С_ОБЕКТИ]"
 
 #, c-format
+msgid "invalid --name-hash-version option: %d"
+msgstr "неправилна опция „--name-hash-version“: %d"
+
+msgid "currently, --write-bitmap-index requires --name-hash-version=1"
+msgstr "текущо опцията „--write-bitmap-index“ изисква „--name-hash-version=1“"
+
+#, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
@@ -10025,6 +10044,11 @@
 msgid "exclude any configured uploadpack.blobpackfileuri with this protocol"
 msgstr "без ползване на настройки „uploadpack.blobpackfileuri“ с този протокол"
 
+msgid "use the specified name-hash function to group similar objects"
+msgstr ""
+"използване на указаната функция за контролни суми за групиране на подобните "
+"обекти"
+
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
 msgstr "веригата с разлики е прекалено дълбока — %d, ще се ползва %d"
@@ -11304,8 +11328,8 @@
 msgid "invalid ref format: %s"
 msgstr "неправилен формат на указател: %s"
 
-msgid "git refs migrate --ref-format=<format> [--dry-run]"
-msgstr "git refs migrate --ref-format=ФОРМАТ [--dry-run]"
+msgid "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
+msgstr "git refs migrate --ref-format=ФОРМАТ [--no-reflog] [--dry-run]"
 
 msgid "git refs verify [--strict] [--verbose]"
 msgstr "git refs verify [--strict] [--verbose]"
@@ -11316,6 +11340,9 @@
 msgid "perform a non-destructive dry-run"
 msgstr "пробно изпълнение — без промяна на данни"
 
+msgid "drop reflogs entirely during the migration"
+msgstr "журналът на указателите да се изтрие изцяло по време на миграцията"
+
 msgid "missing --ref-format=<format>"
 msgstr "липсва опцията --ref-format=ФОРМАТ"
 
@@ -11786,8 +11813,14 @@
 msgid "be verbose; must be placed before a subcommand"
 msgstr "повече подробности.  Поставя се пред подкоманда"
 
-msgid "git repack [<options>]"
-msgstr "git repack [ОПЦИЯ…]"
+msgid ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
+msgstr ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=БРОЙ] [--depth=БРОЙ] [--threads=БРОЙ] [--keep-pack=ИМЕ_НА_ПАКЕТ]\n"
+"[--write-midx] [--name-hash-version=БРОЙ]"
 
 msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
@@ -11875,6 +11908,11 @@
 msgstr ""
 "подаване на опцията „--no-reuse-object“ на командата „git-pack-objects“"
 
+msgid ""
+"specify the name hash version to use for grouping similar objects by path"
+msgstr ""
+"укажете функция за контролни суми за групиране на подобните обекти по път"
+
 msgid "do not run git-update-server-info"
 msgstr "без изпълнение на командата „git-update-server-info“"
 
@@ -11927,9 +11965,6 @@
 msgid "write a multi-pack index of the resulting packs"
 msgstr "запазване на многопакетен индекс за създадените пакети"
 
-msgid "pack prefix to store a pack containing pruned objects"
-msgstr "префикс на имената на пакетите за окастрени обекти"
-
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr "префикс на имената на пакетите за филтрирани обекти"
 
@@ -12146,9 +12181,6 @@
 msgid "need some commits to replay"
 msgstr "необходимо е да има подавания за прилагане отново"
 
-msgid "--onto and --advance are incompatible"
-msgstr "опциите „--onto“ и „--advance“ са несъвместими"
-
 msgid "all positive revisions given must be references"
 msgstr "всички зададени положителни версии трябва да са указатели"
 
@@ -14852,6 +14884,9 @@
 msgid "Create an archive of files from a named tree"
 msgstr "Създаване на архив с файловете от именовано дърво"
 
+msgid "Download missing objects in a partial clone"
+msgstr "Изтегляне на липсващите обекти в частично хранилище"
+
 msgid "Use binary search to find the commit that introduced a bug"
 msgstr "Двоично търсене на промяната, която е причинила грешка"
 
@@ -16852,6 +16887,12 @@
 msgid "invalid regex given to -I: '%s'"
 msgstr "неправилен регулярен израз подаден към „-I“: „%s“"
 
+msgid "-G requires a non-empty argument"
+msgstr "опцията „-G“ изисква аргумент"
+
+msgid "-S requires a non-empty argument"
+msgstr "опцията „-S“ изисква аргумент"
+
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr "неразпознат параметър към опцията „--submodule“: „%s“"
@@ -19123,6 +19164,10 @@
 msgstr "файлът „%s“ не може да бъде записан"
 
 #, c-format
+msgid "unable to write repeatedly vanishing file %s"
+msgstr "смаляващият се файл „%s“ не може да бъде записван"
+
+#, c-format
 msgid "unable to set permission to '%s'"
 msgstr "права̀та за достъп до „%s“ не може да бъдат зададени"
 
@@ -19722,6 +19767,52 @@
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "непозната стойност извън „ascii“ в низа: „%s“"
 
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the long form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[=<%s>]"
+msgstr "[=%s]"
+
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the short form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[<%s>]"
+msgstr "[%s]"
+
+#. TRANSLATORS: The "<%s>" part of this string stands for a
+#. value given to a command line option, and "<>" is there
+#. as a convention to signal that it is a placeholder
+#. (i.e. the user should substitute it with the real value).
+#. If your language uses a different convention, you can
+#. change "<%s>" part to match yours, e.g. it might use
+#. "|%s|" instead, or if the alphabet is different enough it
+#. may use "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid " <%s>"
+msgstr " %s"
+
 msgid "..."
 msgstr "…"
 
@@ -19809,6 +19900,21 @@
 msgstr "„%s“ не може да бъде анализиран"
 
 #, c-format
+msgid "failed to walk children of tree %s: not found"
+msgstr "неуспешно обхождане на дъщерните елементи на дървото „%s“: то липсва"
+
+#, c-format
+msgid "failed to find object %s"
+msgstr "обектът „%s“ липсва"
+
+#, c-format
+msgid "failed to find tag %s"
+msgstr "етикетът „%s“ липсва"
+
+msgid "failed to setup revision walk"
+msgstr "неуспешно настройване на обхождането на версиите"
+
+#, c-format
 msgid "Could not make %s writable by group"
 msgstr "Не може да се дадат права̀ за запис в директорията „%s“ на групата"
 
@@ -19957,6 +20063,22 @@
 msgid "could not fetch %s from promisor remote"
 msgstr "„%s“ не може да се достави от гарантиращото хранилище"
 
+#, c-format
+msgid "known remote named '%s' but with url '%s' instead of '%s'"
+msgstr "има хранилище с име „%s“, но адресът му сочи към „%s“, а не към „%s“"
+
+#, c-format
+msgid "unknown '%s' value for '%s' config option"
+msgstr "непозната стойност „%s“ за настройката „%s“"
+
+#, c-format
+msgid "unknown element '%s' from remote info"
+msgstr "непознат елемент „%s“ в информацията за отдалеченото хранилище"
+
+#, c-format
+msgid "accepted promisor remote '%s' not found"
+msgstr "липсва приетото вече хранилище-гарант „%s“"
+
 msgid "object-info: expected flush after arguments"
 msgstr "object-info: след аргументите се очаква изчистване на буферите"
 
@@ -20803,6 +20925,14 @@
 msgstr "неправилен указател: „%s“"
 
 #, c-format
+msgid "pattern '%s' has no '*'"
+msgstr "шаблонът „%s“ не съдържа „*“"
+
+#, c-format
+msgid "replacement '%s' has no '*'"
+msgstr "заместителят „%s“ не съдържа „*“"
+
+#, c-format
 msgid "invalid quoting in push-option value: '%s'"
 msgstr ""
 "неправилно екраниране или цитиране в стойността към опция за изтласкване: "
@@ -20930,6 +21060,28 @@
 msgstr "remote-curl: непозната команда „%s“ от git"
 
 #, c-format
+msgid ""
+"reading remote from \"%s/%s\", which is nominated for removal.\n"
+"\n"
+"If you still use the \"remotes/\" directory it is recommended to\n"
+"migrate to config-based remotes:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"If you cannot, please let us know why you still need to use it by\n"
+"sending an e-mail to <git@vger.kernel.org>."
+msgstr ""
+"изчитането на отдалеченото хранилище от „%s/%s“ предстои да бъде "
+"премахнато.\n"
+"Ако все още ползвате директорията „remotes/“, препоръчваме да я мигрирате\n"
+"към следящи директории на база настройки чрез командата:\n"
+"\n"
+"    git remote rename %s %s\n"
+"\n"
+"Ако не може поради някаква причина, молим да ни известите за нея с\n"
+"е-писмо до пощенския списък: <git@vger.kernel.org>."
+
+#, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
 msgstr ""
 "съкращението за отдалечено хранилище не може за започва със знака „/“: %s"
@@ -20965,14 +21117,6 @@
 msgstr "„%s“ следи както „%s“, така и „%s“"
 
 #, c-format
-msgid "key '%s' of pattern had no '*'"
-msgstr "ключ „%s“ на шаблона не съдържа „*“"
-
-#, c-format
-msgid "value '%s' of pattern has no '*'"
-msgstr "стойност „%s“ на шаблона не съдържа „*“"
-
-#, c-format
 msgid "src refspec %s does not match any"
 msgstr "указателят на версия-източник „%s“ не съвпада с никой обект"
 
@@ -22945,6 +23089,28 @@
 "какъв брой записи в кеша на обектите-дървета да се отбележат като невалидни "
 "(стандартно е 0)"
 
+msgid "test-tool path-walk <options> -- <revision-options>"
+msgstr "test-tool path-walk ОПЦИЯ… -- ОПЦИЯ_ЗА_ВЕРСИИ…"
+
+msgid "toggle inclusion of blob objects"
+msgstr "превключване на поместването на обекти-BLOB"
+
+msgid "toggle inclusion of commit objects"
+msgstr "превключване на поместването на обекти-подавания"
+
+msgid "toggle inclusion of tag objects"
+msgstr "превключване на поместването на обекти-етикети"
+
+msgid "toggle inclusion of tree objects"
+msgstr "превключване на поместването на обекти-дърво"
+
+msgid "toggle pruning of uninteresting paths"
+msgstr ""
+"превключване на окастрянето на пътищата, които не представляват интерес"
+
+msgid "read a pattern list over stdin"
+msgstr "изчитане на списък с шаблони от стандартния вход"
+
 #, c-format
 msgid "commit %s is not marked reachable"
 msgstr "подаването „%s“ не е отбелязано като достижимо"
@@ -23581,6 +23747,10 @@
 msgid "warning: "
 msgstr "предупреждение: "
 
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "грешка при изпълнението на „uname()“ — „%s“ (%d)\n"
+
 msgid "Fetching objects"
 msgstr "Доставяне на обектите"
 
diff --git a/po/de.po b/po/de.po
index addd591..4d9c46f 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: 2024-12-20 17:44+0100\n"
-"PO-Revision-Date: 2024-12-27 16:43+0100\n"
+"POT-Creation-Date: 2025-03-06 18:29+0100\n"
+"PO-Revision-Date: 2025-03-07 17:28+0100\n"
 "Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
 "Language-Team: German\n"
 "Language: de\n"
@@ -2400,6 +2400,18 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: erwartete eine Spülung (flush)"
 
+msgid "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+msgstr "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+
+msgid "problem loading sparse-checkout"
+msgstr "Problem beim Laden von sparse-checkout"
+
+msgid "Minimum number of objects to request at a time"
+msgstr "Mindestanzahl der gleichzeitig anzufordernden Objekte"
+
+msgid "Restrict the missing objects to the current sparse-checkout"
+msgstr "fehlenden Objekte im aktuellen sparse-checkout beschränken"
+
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
 "checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
@@ -3167,10 +3179,6 @@
 msgid "git version:\n"
 msgstr "git Version:\n"
 
-#, c-format
-msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() ist fehlgeschlagen mit Fehler '%s' (%d)\n"
-
 msgid "compiler info: "
 msgstr "Compiler Info: "
 
@@ -4201,131 +4209,6 @@
 "clean.requireForce ist 'true' und -f ist nicht angegeben: clean wird "
 "verweigert"
 
-msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<Optionen>] [--] <Repository> [<Verzeichnis>]"
-
-msgid "don't clone shallow repository"
-msgstr "Repository mit unvollständiger Historie nicht klonen"
-
-msgid "don't create a checkout"
-msgstr "kein Auschecken"
-
-msgid "create a bare repository"
-msgstr "ein Bare-Repository erstellen"
-
-msgid "create a mirror repository (implies --bare)"
-msgstr "ein Spiegel-Repository erstellen (impliziert --bare)"
-
-msgid "to clone from a local repository"
-msgstr "von einem lokalen Repository klonen"
-
-msgid "don't use local hardlinks, always copy"
-msgstr "lokal keine harten Verweise verwenden, immer Kopien"
-
-msgid "setup as shared repository"
-msgstr "als verteiltes Repository einrichten"
-
-msgid "pathspec"
-msgstr "Pfadspezifikation"
-
-msgid "initialize submodules in the clone"
-msgstr "Submodule im Klon initialisieren"
-
-msgid "number of submodules cloned in parallel"
-msgstr "Anzahl der parallel zu klonenden Submodule"
-
-msgid "template-directory"
-msgstr "Vorlagenverzeichnis"
-
-msgid "directory from which templates will be used"
-msgstr "Verzeichnis, von welchem die Vorlagen verwendet werden"
-
-msgid "reference repository"
-msgstr "Repository referenzieren"
-
-msgid "use --reference only while cloning"
-msgstr "--reference nur während des Klonens benutzen"
-
-msgid "name"
-msgstr "Name"
-
-msgid "use <name> instead of 'origin' to track upstream"
-msgstr "<Name> statt 'origin' für Upstream-Repository verwenden"
-
-msgid "checkout <branch> instead of the remote's HEAD"
-msgstr "<Branch> auschecken, anstatt HEAD des Remote-Repositories"
-
-msgid "path to git-upload-pack on the remote"
-msgstr "Pfad zu \"git-upload-pack\" auf der Gegenseite"
-
-msgid "depth"
-msgstr "Tiefe"
-
-msgid "create a shallow clone of that depth"
-msgstr ""
-"einen Klon mit unvollständiger Historie (shallow) in dieser Tiefe erstellen"
-
-msgid "create a shallow clone since a specific time"
-msgstr ""
-"einen Klon mit unvollständiger Historie (shallow) seit einer bestimmten "
-"Zeit\n"
-"erstellen"
-
-msgid "ref"
-msgstr "Referenz"
-
-msgid "deepen history of shallow clone, excluding ref"
-msgstr "Historie eines flachen Klons vertiefen, Referenz exkludiert"
-
-msgid "clone only one branch, HEAD or --branch"
-msgstr "nur einen Branch klonen, HEAD oder --branch"
-
-msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr "keine Tags klonen, und auch bei späteren Abrufen nicht beachten"
-
-msgid "any cloned submodules will be shallow"
-msgstr "jedes geklonte Submodul mit unvollständiger Historie (shallow)"
-
-msgid "gitdir"
-msgstr ".git-Verzeichnis"
-
-msgid "separate git dir from working tree"
-msgstr "Git-Verzeichnis vom Arbeitsverzeichnis separieren"
-
-msgid "specify the reference format to use"
-msgstr "das zu verwendende Referenzformat angeben"
-
-msgid "key=value"
-msgstr "Schlüssel=Wert"
-
-msgid "set config inside the new repository"
-msgstr "Konfiguration innerhalb des neuen Repositories setzen"
-
-msgid "server-specific"
-msgstr "serverspezifisch"
-
-msgid "option to transmit"
-msgstr "Option übertragen"
-
-msgid "apply partial clone filters to submodules"
-msgstr "partielle Klonfilter auf Submodule anwenden"
-
-msgid "any cloned submodules will use their remote-tracking branch"
-msgstr "jedes geklonte Submodul nutzt seinen Remote-Tracking-Branch"
-
-msgid "initialize sparse-checkout file to include only files at root"
-msgstr ""
-"Initialisiere Datei für partiellen Checkout, um nur Dateien im\n"
-"Root-Verzeichnis einzubeziehen"
-
-msgid "uri"
-msgstr "uri"
-
-msgid "a URI for downloading bundles before fetching from origin remote"
-msgstr ""
-"eine URI für das Herunterladen von Bundles vor dem Abruf\n"
-"aus dem ursprünglichen Remote-Repository"
-
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info: Konnte Alternative für '%s' nicht hinzufügen: %s\n"
@@ -4389,10 +4272,6 @@
 "Sie können mit 'git status' prüfen, was ausgecheckt worden ist\n"
 "und das Auschecken mit 'git restore --source=HEAD :/' erneut versuchen.\n"
 
-#, c-format
-msgid "Could not find remote branch %s to clone."
-msgstr "Konnte zu klonenden Remote-Branch %s nicht finden."
-
 msgid "remote did not send all necessary objects"
 msgstr "Remote-Repository hat nicht alle erforderlichen Objekte gesendet"
 
@@ -4420,6 +4299,134 @@
 msgid "cannot unlink temporary alternates file"
 msgstr "Kann temporäre \"alternates\"-Datei nicht entfernen"
 
+msgid "don't clone shallow repository"
+msgstr "Repository mit unvollständiger Historie nicht klonen"
+
+msgid "don't create a checkout"
+msgstr "kein Auschecken"
+
+msgid "create a bare repository"
+msgstr "ein Bare-Repository erstellen"
+
+msgid "create a mirror repository (implies --bare)"
+msgstr "ein Spiegel-Repository erstellen (impliziert --bare)"
+
+msgid "to clone from a local repository"
+msgstr "von einem lokalen Repository klonen"
+
+msgid "don't use local hardlinks, always copy"
+msgstr "lokal keine harten Verweise verwenden, immer Kopien"
+
+msgid "setup as shared repository"
+msgstr "als verteiltes Repository einrichten"
+
+msgid "pathspec"
+msgstr "Pfadspezifikation"
+
+msgid "initialize submodules in the clone"
+msgstr "Submodule im Klon initialisieren"
+
+msgid "number of submodules cloned in parallel"
+msgstr "Anzahl der parallel zu klonenden Submodule"
+
+msgid "template-directory"
+msgstr "Vorlagenverzeichnis"
+
+msgid "directory from which templates will be used"
+msgstr "Verzeichnis, von welchem die Vorlagen verwendet werden"
+
+msgid "reference repository"
+msgstr "Repository referenzieren"
+
+msgid "use --reference only while cloning"
+msgstr "--reference nur während des Klonens benutzen"
+
+msgid "name"
+msgstr "Name"
+
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "<Name> statt 'origin' für Upstream-Repository verwenden"
+
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "<Branch> auschecken, anstatt HEAD des Remote-Repositories"
+
+msgid "clone single revision <rev> and check out"
+msgstr "einzelnen Commit <Commit> klonen und auschecken"
+
+msgid "path to git-upload-pack on the remote"
+msgstr "Pfad zu \"git-upload-pack\" auf der Gegenseite"
+
+msgid "depth"
+msgstr "Tiefe"
+
+msgid "create a shallow clone of that depth"
+msgstr ""
+"einen Klon mit unvollständiger Historie (shallow) in dieser Tiefe erstellen"
+
+msgid "create a shallow clone since a specific time"
+msgstr ""
+"einen Klon mit unvollständiger Historie (shallow) seit einer bestimmten "
+"Zeit\n"
+"erstellen"
+
+msgid "ref"
+msgstr "Referenz"
+
+msgid "deepen history of shallow clone, excluding ref"
+msgstr "Historie eines flachen Klons vertiefen, Referenz exkludiert"
+
+msgid "clone only one branch, HEAD or --branch"
+msgstr "nur einen Branch klonen, HEAD oder --branch"
+
+msgid "clone tags, and make later fetches not to follow them"
+msgstr "Tags klonen und dafür sorgen, dass spätere Abrufe ihnen nicht folgen"
+
+msgid "any cloned submodules will be shallow"
+msgstr "jedes geklonte Submodul mit unvollständiger Historie (shallow)"
+
+msgid "gitdir"
+msgstr ".git-Verzeichnis"
+
+msgid "separate git dir from working tree"
+msgstr "Git-Verzeichnis vom Arbeitsverzeichnis separieren"
+
+msgid "specify the reference format to use"
+msgstr "das zu verwendende Referenzformat angeben"
+
+msgid "key=value"
+msgstr "Schlüssel=Wert"
+
+msgid "set config inside the new repository"
+msgstr "Konfiguration innerhalb des neuen Repositories setzen"
+
+msgid "server-specific"
+msgstr "serverspezifisch"
+
+msgid "option to transmit"
+msgstr "Option übertragen"
+
+msgid "apply partial clone filters to submodules"
+msgstr "partielle Klonfilter auf Submodule anwenden"
+
+msgid "any cloned submodules will use their remote-tracking branch"
+msgstr "jedes geklonte Submodul nutzt seinen Remote-Tracking-Branch"
+
+msgid "initialize sparse-checkout file to include only files at root"
+msgstr ""
+"Initialisiere Datei für partiellen Checkout, um nur Dateien im\n"
+"Root-Verzeichnis einzubeziehen"
+
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr ""
+"eine URI für das Herunterladen von Bundles vor dem Abruf\n"
+"aus dem ursprünglichen Remote-Repository"
+
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [<Optionen>] [--] <Repository> [<Verzeichnis>]"
+
 msgid "Too many arguments."
 msgstr "Zu viele Argumente."
 
@@ -4531,6 +4538,10 @@
 msgid "Remote branch %s not found in upstream %s"
 msgstr "Remote-Branch %s nicht im Upstream-Repository %s gefunden"
 
+#, c-format
+msgid "Remote revision %s not found in upstream %s"
+msgstr "Remote-Commit %s nicht im Upstream-Repository %s gefunden"
+
 msgid "You appear to have cloned an empty repository."
 msgstr "Sie scheinen ein leeres Repository geklont zu haben."
 
@@ -4710,7 +4721,7 @@
 msgstr "git commit-tree: Fehler beim Lesen"
 
 msgid ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -4720,14 +4731,14 @@
 "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
 "           [--] [<pathspec>...]"
 msgstr ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<Modus>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<Modus>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <Commit> | --fixup [(amend|"
 "reword):]<Commit>]\n"
 "           [-F <Datei> | -m <Nachricht>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<Autor>]\n"
 "           [--date=<Datum>] [--cleanup=<Modus>] [--[no-]status]\n"
 "           [-i | -o] [--pathspec-from-file=<Datei> [--pathspec-file-nul]]\n"
-"           [(--trailer <Token>[(=|:)<Wert>])...] [-S[<Key-Id>]]\n"
+"           [(--trailer <Token>[(=|:)<Wert>])...] [-S[<Key-ID>>]]\n"
 "           [--] [<Pfadspezifikation>...]"
 
 msgid "git status [<options>] [--] [<pathspec>...]"
@@ -6139,14 +6150,15 @@
 "Run 'git remote set-head %s %s' to follow the change, or set\n"
 "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
 "if you do not want to see this message. Specifically running\n"
-"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
-"until the remote changes HEAD to something else."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"will disable the warning until the remote changes HEAD to something else."
 msgstr ""
 "Führen Sie 'git remote set-head %s %s' aus, um der Änderung zu folgen,\n"
 "oder setzen Sie die Konfiguration 'remote.%s.followRemoteHEAD' auf einen\n"
-"anderen Wert, wenn Sie diese Meldung nicht sehen wollen. Konkret wird diese\n"
-"Warnung mit 'git config set remote.%s.followRemoteHEAD %s' deaktiviert\n"
-"bis die Gegenstelle HEAD in etwas anderes ändert."
+"anderen Wert wenn Sie diese Meldung nicht sehen wollen. Speziell der Befehl\n"
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"wird die Warnung deaktivieren, bis das Remote-Repository HEAD in etwas\n"
+"anderes ändert."
 
 msgid "multiple branches detected, incompatible with --set-upstream"
 msgstr "mehrere Branches erkannt, inkompatibel mit --set-upstream"
@@ -6842,6 +6854,9 @@
 msgid "repack all other packs except the largest pack"
 msgstr "alle anderen Pakete, außer das größte Paket, neu packen"
 
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "pack-Präfix zum Speichern eines Pakets mit gelöschten Objekten"
+
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
 msgstr "Fehler beim Parsen des Wertes '%s' von gc.logExpiry"
@@ -7659,6 +7674,10 @@
 msgstr "Kann nicht zurück zum Arbeitsverzeichnis wechseln"
 
 #, c-format
+msgid "bad --pack_header: %s"
+msgstr "ungültiger --pack_header: %s"
+
+#, c-format
 msgid "bad %s"
 msgstr "%s ist ungültig"
 
@@ -8537,11 +8556,6 @@
 msgid "malformed input line: '%s'."
 msgstr "Fehlerhafte Eingabezeile: '%s'."
 
-#, c-format
-msgid "merging cannot continue; got unclean result of %d"
-msgstr ""
-"Merge kann nicht fortgesetzt werden; unsauberes Ergebnis von %d erhalten"
-
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<Optionen>] [<Commit>...]"
 
@@ -9382,6 +9396,13 @@
 "<Objektliste>]"
 
 #, c-format
+msgid "invalid --name-hash-version option: %d"
+msgstr "ungültige Option für --name-hash-version: %d"
+
+msgid "currently, --write-bitmap-index requires --name-hash-version=1"
+msgstr "derzeit erfordert --write-bitmap-index --name-hash-version=1"
+
+#, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
@@ -9718,6 +9739,11 @@
 "jegliche konfigurierte uploadpack.blobpackfileuri für dieses Protkoll "
 "ausschließen"
 
+msgid "use the specified name-hash function to group similar objects"
+msgstr ""
+"die angegebene Name-Hash-Funktion verwenden, um ähnliche Objekte zu "
+"gruppieren"
+
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
 msgstr "Tiefe für Verkettung von Unterschieden %d ist zu tief, erzwinge %d"
@@ -11006,8 +11032,8 @@
 msgid "invalid ref format: %s"
 msgstr "Ungültiges Format für Referenzen: %s"
 
-msgid "git refs migrate --ref-format=<format> [--dry-run]"
-msgstr "git refs migrate --ref-format=<Format> [--dry-run]"
+msgid "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
+msgstr "git refs migrate --ref-format=<Format> [--no-reflog] [--dry-run]"
 
 msgid "git refs verify [--strict] [--verbose]"
 msgstr "git refs verify [--strict] [--verbose]"
@@ -11018,6 +11044,9 @@
 msgid "perform a non-destructive dry-run"
 msgstr "einen zerstörungsfreien Trockenlauf durchführen"
 
+msgid "drop reflogs entirely during the migration"
+msgstr "Reflogs während der Migration vollständig zu löschen"
+
 msgid "missing --ref-format=<format>"
 msgstr "fehlendes --ref-format=<Format>"
 
@@ -11488,8 +11517,14 @@
 msgid "be verbose; must be placed before a subcommand"
 msgstr "erweiterte Ausgaben; muss vor einem Unterbefehl angegeben werden"
 
-msgid "git repack [<options>]"
-msgstr "git repack [<Optionen>]"
+msgid ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
+msgstr ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<Paketname>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
 
 msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
@@ -11568,6 +11603,12 @@
 msgid "pass --no-reuse-object to git-pack-objects"
 msgstr "--no-reuse-object an git-pack-objects übergeben"
 
+msgid ""
+"specify the name hash version to use for grouping similar objects by path"
+msgstr ""
+"die Version des Hash-Namens angeben, die für die Gruppierung ähnlicher "
+"Objekte nach Pfad verwendet werden soll"
+
 msgid "do not run git-update-server-info"
 msgstr "git-update-server-info nicht ausführen"
 
@@ -11619,9 +11660,6 @@
 msgid "write a multi-pack index of the resulting packs"
 msgstr "ein Multi-Pack-Index des resultierenden Pakets schreiben"
 
-msgid "pack prefix to store a pack containing pruned objects"
-msgstr "pack-Präfix zum Speichern eines Pakets mit gelöschten Objekten"
-
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr "Paketpräfix, um ein Paket mit herausgefilterten Objekten zu speichern"
 
@@ -11839,9 +11877,6 @@
 msgid "need some commits to replay"
 msgstr "zum erneuten Abspielen werden Commits benötigt"
 
-msgid "--onto and --advance are incompatible"
-msgstr "--onto und --advance sind inkompatibel"
-
 msgid "all positive revisions given must be references"
 msgstr "alle angegebenen positiven Commits müssen Referenzen sein"
 
@@ -14571,6 +14606,9 @@
 msgid "Create an archive of files from a named tree"
 msgstr "Dateiarchiv von angegebenem Verzeichnis erstellen"
 
+msgid "Download missing objects in a partial clone"
+msgstr "fehlender Objekte in einem partiellen Klon herunterladen"
+
 msgid "Use binary search to find the commit that introduced a bug"
 msgstr ""
 "Binärsuche verwenden, um den Commit zu finden, der einen Fehler verursacht "
@@ -16543,6 +16581,12 @@
 msgid "invalid regex given to -I: '%s'"
 msgstr "ungültiger regulärer Ausdruck für -I gegeben: '%s'"
 
+msgid "-G requires a non-empty argument"
+msgstr "-G erfordert ein nicht leeres Argument"
+
+msgid "-S requires a non-empty argument"
+msgstr "-S erfordert ein nicht leeres Argument"
+
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr "Fehler beim Parsen des --submodule Optionsparameters: '%s'"
@@ -18782,6 +18826,10 @@
 msgstr "Konnte Datei %s nicht schreiben."
 
 #, c-format
+msgid "unable to write repeatedly vanishing file %s"
+msgstr "konnte nicht in eine wiederholt verschwindende Datei %s schreiben"
+
+#, c-format
 msgid "unable to set permission to '%s'"
 msgstr "Konnte Zugriffsberechtigung auf '%s' nicht setzen."
 
@@ -19355,6 +19403,52 @@
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "Unbekannte nicht-Ascii Option in String: `%s'"
 
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the long form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[=<%s>]"
+msgstr "[=<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the short form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[<%s>]"
+msgstr "[<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string stands for a
+#. value given to a command line option, and "<>" is there
+#. as a convention to signal that it is a placeholder
+#. (i.e. the user should substitute it with the real value).
+#. If your language uses a different convention, you can
+#. change "<%s>" part to match yours, e.g. it might use
+#. "|%s|" instead, or if the alphabet is different enough it
+#. may use "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid " <%s>"
+msgstr " <%s>"
+
 msgid "..."
 msgstr "..."
 
@@ -19442,6 +19536,21 @@
 msgstr "Fehler beim Parsen von %s."
 
 #, c-format
+msgid "failed to walk children of tree %s: not found"
+msgstr "Fehlen beim Durchlaufen der Kinder von Baum %s: nicht gefunden"
+
+#, c-format
+msgid "failed to find object %s"
+msgstr "Objekt nicht gefunden: %s"
+
+#, c-format
+msgid "failed to find tag %s"
+msgstr "Tag nicht gefunden: %s"
+
+msgid "failed to setup revision walk"
+msgstr "Einrichtung des Revisionsgangs fehlgeschlagen"
+
+#, c-format
 msgid "Could not make %s writable by group"
 msgstr "Konnte Gruppenschreibrecht für %s nicht setzen."
 
@@ -19591,6 +19700,25 @@
 msgid "could not fetch %s from promisor remote"
 msgstr "konnte %s nicht von Promisor-Remote abrufen"
 
+#, c-format
+msgid "known remote named '%s' but with url '%s' instead of '%s'"
+msgstr ""
+"bekanntes Remote-Repository mit dem Namen '%s', aber mit der URL '%s' statt "
+"'%s'"
+
+#, c-format
+msgid "unknown '%s' value for '%s' config option"
+msgstr "unbekannter '%s'-Wert für '%s'-Konfigurationsoption"
+
+#, c-format
+msgid "unknown element '%s' from remote info"
+msgstr "unbekanntes Element '%s' aus Information aus Remote-Repository"
+
+#, c-format
+msgid "accepted promisor remote '%s' not found"
+msgstr ""
+"akzeptiertes partiell geklontes \"Remote-Repository '%s' nicht gefunden"
+
 msgid "object-info: expected flush after arguments"
 msgstr "object-info: erwartete Flush nach Argumenten"
 
@@ -20428,6 +20556,14 @@
 msgstr "ungültige Refspec '%s'"
 
 #, c-format
+msgid "pattern '%s' has no '*'"
+msgstr "Muster '%s' hat keinen '*'"
+
+#, c-format
+msgid "replacement '%s' has no '*'"
+msgstr "Ersetzung '%s' hat keinen '*'"
+
+#, c-format
 msgid "invalid quoting in push-option value: '%s'"
 msgstr "Ungültiges Quoting beim \"push-option\"-Wert: '%s'"
 
@@ -20550,6 +20686,28 @@
 msgstr "remote-curl: Unbekannter Befehl '%s' von Git"
 
 #, c-format
+msgid ""
+"reading remote from \"%s/%s\", which is nominated for removal.\n"
+"\n"
+"If you still use the \"remotes/\" directory it is recommended to\n"
+"migrate to config-based remotes:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"If you cannot, please let us know why you still need to use it by\n"
+"sending an e-mail to <git@vger.kernel.org>."
+msgstr ""
+"Lese von Remote-Repository \"%s/%s\", das zum Entfernen vorgeschlagen wird.\n"
+"\n"
+"Wenn Sie noch das Verzeichnis \"remotes/\" verwenden, wird empfohlen\n"
+"auf konfigurationsbasierte Remote-Repositories umzusteigen:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"Wenn dies nicht möglich ist, teilen Sie uns bitte mit, warum Sie das noch\n"
+"verwenden müssen, indem Sie eine E-Mail an <git@vger.kernel.org> senden."
+
+#, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
 msgstr ""
 "Kürzel für Remote-Repository in der Konfiguration kann nicht mit '/' "
@@ -20586,14 +20744,6 @@
 msgstr "%s folgt sowohl %s als auch %s"
 
 #, c-format
-msgid "key '%s' of pattern had no '*'"
-msgstr "Schlüssel '%s' des Musters hatte kein '*'."
-
-#, c-format
-msgid "value '%s' of pattern has no '*'"
-msgstr "Wert '%s' des Musters hat kein '*'."
-
-#, c-format
 msgid "src refspec %s does not match any"
 msgstr "Src-Refspec %s entspricht keiner Referenz."
 
@@ -22519,6 +22669,27 @@
 "Anzahl der Einträge im Cache-Verzeichnis, die ungültig gemacht werden sollen "
 "(Standardwert 0)"
 
+msgid "test-tool path-walk <options> -- <revision-options>"
+msgstr "test-tool path-walk <Optionen> -- <Commit-Optionen>"
+
+msgid "toggle inclusion of blob objects"
+msgstr "Einbeziehung von Blob-Objekten umschalten"
+
+msgid "toggle inclusion of commit objects"
+msgstr "Einbeziehung von Commit-Objekten umschalten"
+
+msgid "toggle inclusion of tag objects"
+msgstr "Einbeziehung von Tag-Objekten umschalten"
+
+msgid "toggle inclusion of tree objects"
+msgstr "Einbeziehung von Tree-Objekten umschalten"
+
+msgid "toggle pruning of uninteresting paths"
+msgstr "Auslassen von uninteressanten Pfaden umschalten"
+
+msgid "read a pattern list over stdin"
+msgstr "Liste von Mustern von der Standard-Eingabe lesen"
+
 #, c-format
 msgid "commit %s is not marked reachable"
 msgstr "Commit %s ist nicht als erreichbar gekennzeichnet."
@@ -23168,6 +23339,10 @@
 msgid "warning: "
 msgstr "Warnung: "
 
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "uname() ist fehlgeschlagen mit Fehler '%s' (%d)\n"
+
 msgid "Fetching objects"
 msgstr "Anfordern der Objekte"
 
@@ -24190,7 +24365,3 @@
 #, perl-format
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Wollen Sie %s wirklich versenden? [y|N]: "
-
-#, c-format
-#~ msgid "preferred pack (%s) is invalid"
-#~ msgstr "bevorzugtes Paket (%s) ist ungültig"
diff --git a/po/fr.po b/po/fr.po
index 64a75ae..8e33390 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -87,8 +87,8 @@
 msgstr ""
 "Project-Id-Version: git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-12-23 18:57+0000\n"
-"PO-Revision-Date: 2024-12-29 18:26+0100\n"
+"POT-Creation-Date: 2025-03-05 22:57+0000\n"
+"PO-Revision-Date: 2025-03-06 16:46+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"
@@ -2452,6 +2452,18 @@
 msgid "git archive: expected a flush"
 msgstr "git archive : vidage attendu"
 
+msgid "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+msgstr "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+
+msgid "problem loading sparse-checkout"
+msgstr "problème lors du chargement de l'extraction clairsemée"
+
+msgid "Minimum number of objects to request at a time"
+msgstr "Nombre minimum d'objets à demander à chaque fois"
+
+msgid "Restrict the missing objects to the current sparse-checkout"
+msgstr "Restreindre les objets manquants à l'extraction clairsemée actuelle"
+
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
 "checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
@@ -3217,10 +3229,6 @@
 msgid "git version:\n"
 msgstr "version git ::\n"
 
-#, c-format
-msgid "uname() failed with error '%s' (%d)\n"
-msgstr "échec de uname() avec l'erreur '%s' (%d)\n"
-
 msgid "compiler info: "
 msgstr "info compilateur : "
 
@@ -4243,130 +4251,6 @@
 msgstr ""
 "clean.requireForce positionné est true et -f non fourni ; refus de nettoyer"
 
-msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<options>] [--] <dépôt> [<répertoire>]"
-
-msgid "don't clone shallow repository"
-msgstr "ne pas cloner un dépôt superficiel"
-
-msgid "don't create a checkout"
-msgstr "ne pas créer d'extraction"
-
-msgid "create a bare repository"
-msgstr "créer un dépôt nu"
-
-msgid "create a mirror repository (implies --bare)"
-msgstr "créer un dépôt miroir (implique --bare)"
-
-msgid "to clone from a local repository"
-msgstr "pour cloner depuis un dépôt local"
-
-msgid "don't use local hardlinks, always copy"
-msgstr "ne pas utiliser de liens durs locaux, toujours copier"
-
-msgid "setup as shared repository"
-msgstr "régler comme dépôt partagé"
-
-msgid "pathspec"
-msgstr "spécificateur de chemin"
-
-msgid "initialize submodules in the clone"
-msgstr "initialiser les sous-modules dans le clone"
-
-msgid "number of submodules cloned in parallel"
-msgstr "nombre de sous-modules clonés en parallèle"
-
-msgid "template-directory"
-msgstr "répertoire-modèle"
-
-msgid "directory from which templates will be used"
-msgstr "répertoire depuis lequel les modèles vont être utilisés"
-
-msgid "reference repository"
-msgstr "dépôt de référence"
-
-msgid "use --reference only while cloning"
-msgstr "utiliser seulement --reference pour cloner"
-
-msgid "name"
-msgstr "nom"
-
-msgid "use <name> instead of 'origin' to track upstream"
-msgstr "utiliser <nom> au lieu de 'origin' pour suivre la branche amont"
-
-msgid "checkout <branch> instead of the remote's HEAD"
-msgstr "extraire <branche> au lieu de la HEAD du répertoire distant"
-
-msgid "path to git-upload-pack on the remote"
-msgstr "chemin vers git-upload-pack sur le serveur distant"
-
-msgid "depth"
-msgstr "profondeur"
-
-msgid "create a shallow clone of that depth"
-msgstr "créer un clone superficiel de cette profondeur"
-
-msgid "create a shallow clone since a specific time"
-msgstr "créer un clone superficiel depuis une date spécifique"
-
-msgid "ref"
-msgstr "ref"
-
-msgid "deepen history of shallow clone, excluding ref"
-msgstr "approfondit l'historique d'un clone superficiel en excluant une ref"
-
-msgid "clone only one branch, HEAD or --branch"
-msgstr "cloner seulement une branche, HEAD ou --branch"
-
-msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr ""
-"ne pas cloner les tags et indiquer aux récupérations futures de ne pas le "
-"faire"
-
-msgid "any cloned submodules will be shallow"
-msgstr "tous les sous-modules clonés seront superficiels"
-
-msgid "gitdir"
-msgstr "gitdir"
-
-msgid "separate git dir from working tree"
-msgstr "séparer le répertoire git de la copie de travail"
-
-msgid "specify the reference format to use"
-msgstr "spécifier le format de réference à utiliser"
-
-msgid "key=value"
-msgstr "clé=valeur"
-
-msgid "set config inside the new repository"
-msgstr "régler la configuration dans le nouveau dépôt"
-
-msgid "server-specific"
-msgstr "spécifique au serveur"
-
-msgid "option to transmit"
-msgstr "option à transmettre"
-
-msgid "apply partial clone filters to submodules"
-msgstr "appliquer les filtres de clone partiel aux sous-modules"
-
-msgid "any cloned submodules will use their remote-tracking branch"
-msgstr ""
-"tous les sous-modules clonés utiliseront leur branche de suivi à distance"
-
-msgid "initialize sparse-checkout file to include only files at root"
-msgstr ""
-"initialiser le fichier d'extraction clairsemée pour n'inclure que les "
-"fichiers à la racine"
-
-msgid "uri"
-msgstr "uri"
-
-msgid "a URI for downloading bundles before fetching from origin remote"
-msgstr ""
-"un URI pour télécharger des paquets avant de récupérer depuis le distant "
-"d'origine"
-
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info : impossible d'ajouter une alternative pour '%s' : %s\n"
@@ -4428,10 +4312,6 @@
 "Vous pouvez inspecter ce qui a été extrait avec 'git status'\n"
 "et réessayer avec 'git restore --source=HEAD :/'\n"
 
-#, c-format
-msgid "Could not find remote branch %s to clone."
-msgstr "Impossible de trouver la branche distante '%s' à cloner."
-
 msgid "remote did not send all necessary objects"
 msgstr "le serveur distant n'a pas envoyé tous les objets nécessaires"
 
@@ -4459,6 +4339,132 @@
 msgid "cannot unlink temporary alternates file"
 msgstr "impossible de délier le fichier temporaire alternates"
 
+msgid "don't clone shallow repository"
+msgstr "ne pas cloner un dépôt superficiel"
+
+msgid "don't create a checkout"
+msgstr "ne pas créer d'extraction"
+
+msgid "create a bare repository"
+msgstr "créer un dépôt nu"
+
+msgid "create a mirror repository (implies --bare)"
+msgstr "créer un dépôt miroir (implique --bare)"
+
+msgid "to clone from a local repository"
+msgstr "pour cloner depuis un dépôt local"
+
+msgid "don't use local hardlinks, always copy"
+msgstr "ne pas utiliser de liens durs locaux, toujours copier"
+
+msgid "setup as shared repository"
+msgstr "régler comme dépôt partagé"
+
+msgid "pathspec"
+msgstr "spécificateur de chemin"
+
+msgid "initialize submodules in the clone"
+msgstr "initialiser les sous-modules dans le clone"
+
+msgid "number of submodules cloned in parallel"
+msgstr "nombre de sous-modules clonés en parallèle"
+
+msgid "template-directory"
+msgstr "répertoire-modèle"
+
+msgid "directory from which templates will be used"
+msgstr "répertoire depuis lequel les modèles vont être utilisés"
+
+msgid "reference repository"
+msgstr "dépôt de référence"
+
+msgid "use --reference only while cloning"
+msgstr "utiliser seulement --reference pour cloner"
+
+msgid "name"
+msgstr "nom"
+
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "utiliser <nom> au lieu de 'origin' pour suivre la branche amont"
+
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "extraire <branche> au lieu de la HEAD du répertoire distant"
+
+msgid "clone single revision <rev> and check out"
+msgstr "cloner la révision unique <rév> et l'extraire"
+
+msgid "path to git-upload-pack on the remote"
+msgstr "chemin vers git-upload-pack sur le serveur distant"
+
+msgid "depth"
+msgstr "profondeur"
+
+msgid "create a shallow clone of that depth"
+msgstr "créer un clone superficiel de cette profondeur"
+
+msgid "create a shallow clone since a specific time"
+msgstr "créer un clone superficiel depuis une date spécifique"
+
+msgid "ref"
+msgstr "ref"
+
+msgid "deepen history of shallow clone, excluding ref"
+msgstr "approfondit l'historique d'un clone superficiel en excluant une ref"
+
+msgid "clone only one branch, HEAD or --branch"
+msgstr "cloner seulement une branche, HEAD ou --branch"
+
+msgid "clone tags, and make later fetches not to follow them"
+msgstr ""
+"cloner les tags et indiquer aux récupérations futures de ne pas le faire"
+
+msgid "any cloned submodules will be shallow"
+msgstr "tous les sous-modules clonés seront superficiels"
+
+msgid "gitdir"
+msgstr "gitdir"
+
+msgid "separate git dir from working tree"
+msgstr "séparer le répertoire git de la copie de travail"
+
+msgid "specify the reference format to use"
+msgstr "spécifier le format de réference à utiliser"
+
+msgid "key=value"
+msgstr "clé=valeur"
+
+msgid "set config inside the new repository"
+msgstr "régler la configuration dans le nouveau dépôt"
+
+msgid "server-specific"
+msgstr "spécifique au serveur"
+
+msgid "option to transmit"
+msgstr "option à transmettre"
+
+msgid "apply partial clone filters to submodules"
+msgstr "appliquer les filtres de clone partiel aux sous-modules"
+
+msgid "any cloned submodules will use their remote-tracking branch"
+msgstr ""
+"tous les sous-modules clonés utiliseront leur branche de suivi à distance"
+
+msgid "initialize sparse-checkout file to include only files at root"
+msgstr ""
+"initialiser le fichier d'extraction clairsemée pour n'inclure que les "
+"fichiers à la racine"
+
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr ""
+"un URI pour télécharger des paquets avant de récupérer depuis le distant "
+"d'origine"
+
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [<options>] [--] <dépôt> [<répertoire>]"
+
 msgid "Too many arguments."
 msgstr "Trop d'arguments."
 
@@ -4563,6 +4569,10 @@
 msgid "Remote branch %s not found in upstream %s"
 msgstr "La branche distante %s n'a pas été trouvée dans le dépôt amont %s"
 
+#, c-format
+msgid "Remote revision %s not found in upstream %s"
+msgstr "La révision distante %s n'a pas été trouvée dans le dépôt amont %s"
+
 msgid "You appear to have cloned an empty repository."
 msgstr "Vous semblez avoir cloné un dépôt vide."
 
@@ -4737,7 +4747,7 @@
 msgstr "git commit-tree : échec de la lecture"
 
 msgid ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -4747,14 +4757,14 @@
 "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
 "           [--] [<pathspec>...]"
 msgstr ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
-"reword):]<commit>)]\n"
+"reword):]<commit>]\n"
 "           [-F <fichier> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<auteur>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
 "           [-i | -o] [--pathspec-from-file=<fichier> [--pathspec-file-nul]]\n"
-"           [(--trailer <symbole>[(=|:)<valeur>])...] [-S[<id-clé>]]\n"
+"           [(--trailer <jeton>[(=|:)<valeur>])...] [-S[<id-clé>]]\n"
 "           [--] [<spéc-de-chemin>...]"
 
 msgid "git status [<options>] [--] [<pathspec>...]"
@@ -6168,13 +6178,14 @@
 "Run 'git remote set-head %s %s' to follow the change, or set\n"
 "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
 "if you do not want to see this message. Specifically running\n"
-"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
-"until the remote changes HEAD to something else."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"will disable the warning until the remote changes HEAD to something else."
 msgstr ""
 "Lancez 'git remote set-head %s %s' pour suivre la modification, ou\n"
 "réglez l'option de configuration 'remote.%s.followRemoteHEAD' à une\n"
 "valeur différente si vous ne souhaitez pas voir ce message. Lancer\n"
-"spécifiquement 'git config set remote.%s.followRemoteHEAD %s'\n"
+"spécifiquement 'git config set remote.%s.followRemoteHEAD warn-if-not-branch-"
+"%s'\n"
 "va désactiver l'alerte jusqu'à ce que le distant change HEAD."
 
 msgid "multiple branches detected, incompatible with --set-upstream"
@@ -6860,6 +6871,9 @@
 msgid "repack all other packs except the largest pack"
 msgstr "recompacter tous les autres paquets excepté le plus gros paquet"
 
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "préfixe de paquet pour stocker un paquet contenant les objets élagués"
+
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
 msgstr "impossible d'analyser gc.logExpiry %s"
@@ -7674,6 +7688,10 @@
 msgstr "Impossible de revenir au répertoire de travail courant"
 
 #, c-format
+msgid "bad --pack_header: %s"
+msgstr "mauvais --pack_header : %s"
+
+#, c-format
 msgid "bad %s"
 msgstr "mauvais %s"
 
@@ -8561,10 +8579,6 @@
 msgid "malformed input line: '%s'."
 msgstr "ligne en entrée malformée : '%s'."
 
-#, c-format
-msgid "merging cannot continue; got unclean result of %d"
-msgstr "la fusion ne peut pas continuer ; résultat non propre retourné %d"
-
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<options>] [<commit>...]"
 
@@ -9398,6 +9412,13 @@
 "objets>]"
 
 #, c-format
+msgid "invalid --name-hash-version option: %d"
+msgstr "option --name-hash-version invalide : %d"
+
+msgid "currently, --write-bitmap-index requires --name-hash-version=1"
+msgstr "actuellement, --write-bitmap-index nécessite --name-hash-version=1"
+
+#, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
@@ -9730,6 +9751,11 @@
 msgid "exclude any configured uploadpack.blobpackfileuri with this protocol"
 msgstr "exclure tout uploadpack.blobpackfileuri configuré avec ce protocole"
 
+msgid "use the specified name-hash function to group similar objects"
+msgstr ""
+"utiliser la fonction d'empreinte de nom spécifiée pour grouper les objets "
+"similaires"
+
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
 msgstr "la profondeur %d de chaîne de delta est trop grande, forcée à %d"
@@ -10992,8 +11018,8 @@
 msgid "invalid ref format: %s"
 msgstr "format de référence invalide : %s"
 
-msgid "git refs migrate --ref-format=<format> [--dry-run]"
-msgstr "git refs migrate --ref-format=<format> [--dry-run]"
+msgid "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
+msgstr "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
 
 msgid "git refs verify [--strict] [--verbose]"
 msgstr "git refs verify [--strict] [--verbose]"
@@ -11004,6 +11030,9 @@
 msgid "perform a non-destructive dry-run"
 msgstr "faire l'action en mode simulé non destructif"
 
+msgid "drop reflogs entirely during the migration"
+msgstr "abandonner complètement le reflog pendant la migration"
+
 msgid "missing --ref-format=<format>"
 msgstr "--ref-format=<format> manquant"
 
@@ -11475,8 +11504,14 @@
 msgid "be verbose; must be placed before a subcommand"
 msgstr "être verbeux : doit être placé avant une sous-commande"
 
-msgid "git repack [<options>]"
-msgstr "git repack [<options>]"
+msgid ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
+msgstr ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<nom-de-paquet>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
 
 msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
@@ -11557,6 +11592,12 @@
 msgid "pass --no-reuse-object to git-pack-objects"
 msgstr "passer --no-reuse-object à git-pack-objects"
 
+msgid ""
+"specify the name hash version to use for grouping similar objects by path"
+msgstr ""
+"spécifier la verison d'empreinte de nom à utiliser pour grouper les objets "
+"similaires par chemin"
+
 msgid "do not run git-update-server-info"
 msgstr "ne pas lancer git-update-server-info"
 
@@ -11606,9 +11647,6 @@
 msgid "write a multi-pack index of the resulting packs"
 msgstr "écrire un index de multi-paquet des paquets résultants"
 
-msgid "pack prefix to store a pack containing pruned objects"
-msgstr "préfixe de paquet pour stocker un paquet contenant les objets élagués"
-
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr "préfixe de paquet pour stocker un paquet contenant les objets filtrés"
 
@@ -11825,9 +11863,6 @@
 msgid "need some commits to replay"
 msgstr "commits requis pour pouvoir rejouer"
 
-msgid "--onto and --advance are incompatible"
-msgstr "--onto et --advance sont incompatibles"
-
 msgid "all positive revisions given must be references"
 msgstr "toutes les révisions positives fournies doivent être des références"
 
@@ -14539,6 +14574,9 @@
 msgid "Create an archive of files from a named tree"
 msgstr "Créer une archive des fichiers depuis un arbre nommé"
 
+msgid "Download missing objects in a partial clone"
+msgstr "Télécharger les objets manquants dans un clone partiel"
+
 msgid "Use binary search to find the commit that introduced a bug"
 msgstr "Trouver par recherche binaire la modification qui a introduit un bogue"
 
@@ -16531,6 +16569,12 @@
 msgid "invalid regex given to -I: '%s'"
 msgstr "regex invalide fournie à -I : '%s'"
 
+msgid "-G requires a non-empty argument"
+msgstr "-G exige un argument non vide"
+
+msgid "-S requires a non-empty argument"
+msgstr "-S exige un argument non vide"
+
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr "échec de l'analyse du paramètre de l'option --submodule : '%s'"
@@ -18767,6 +18811,10 @@
 msgstr "impossible d'écrire le fichier %s"
 
 #, c-format
+msgid "unable to write repeatedly vanishing file %s"
+msgstr "impossible d'écrire le fichier %s qui disparaît répétitivement"
+
+#, c-format
 msgid "unable to set permission to '%s'"
 msgstr "impossible de régler les droits de '%s'"
 
@@ -19338,6 +19386,52 @@
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "option non-ascii inconnue dans la chaîne : '%s'"
 
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the long form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[=<%s>]"
+msgstr "[=<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the short form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[<%s>]"
+msgstr "[<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string stands for a
+#. value given to a command line option, and "<>" is there
+#. as a convention to signal that it is a placeholder
+#. (i.e. the user should substitute it with the real value).
+#. If your language uses a different convention, you can
+#. change "<%s>" part to match yours, e.g. it might use
+#. "|%s|" instead, or if the alphabet is different enough it
+#. may use "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid " <%s>"
+msgstr " <%s>"
+
 msgid "..."
 msgstr "..."
 
@@ -19425,6 +19519,21 @@
 msgstr "échec de l'analyse de %s"
 
 #, c-format
+msgid "failed to walk children of tree %s: not found"
+msgstr "échec de parcours des enfants de l'arbre %s : non trouvé"
+
+#, c-format
+msgid "failed to find object %s"
+msgstr "échec de la recherche de l'objet %s"
+
+#, c-format
+msgid "failed to find tag %s"
+msgstr "impossible de trouver l'étiquette %s"
+
+msgid "failed to setup revision walk"
+msgstr "impossible définir un parcours de révisions"
+
+#, c-format
 msgid "Could not make %s writable by group"
 msgstr "Impossible de rendre %s inscriptible pour le groupe"
 
@@ -19581,6 +19690,22 @@
 msgid "could not fetch %s from promisor remote"
 msgstr "impossible de récupérer %s depuis le distant de prometteur"
 
+#, c-format
+msgid "known remote named '%s' but with url '%s' instead of '%s'"
+msgstr "distant connu nommé '%s' mais avec l'url '%s' au lieu de '%s'"
+
+#, c-format
+msgid "unknown '%s' value for '%s' config option"
+msgstr "valeur inconnue '%s' pour l'option de config '%s'"
+
+#, c-format
+msgid "unknown element '%s' from remote info"
+msgstr "élément inconnu '%s' pour l'info de distant"
+
+#, c-format
+msgid "accepted promisor remote '%s' not found"
+msgstr "distant accpté de prometteur '%s' non trouvé"
+
 msgid "object-info: expected flush after arguments"
 msgstr "object-info : vidage attendu après les arguments"
 
@@ -20418,6 +20543,14 @@
 msgstr "spécificateur de réference invalide : '%s'"
 
 #, c-format
+msgid "pattern '%s' has no '*'"
+msgstr "la valeur '%s' du motif n'a pas de '*'"
+
+#, c-format
+msgid "replacement '%s' has no '*'"
+msgstr "le remplacement '%s' n'a pas de '*'"
+
+#, c-format
 msgid "invalid quoting in push-option value: '%s'"
 msgstr "citation invalide dans la valeur push-option : '%s'"
 
@@ -20539,6 +20672,28 @@
 msgstr "remote-curl : commande inconnue '%s' depuis git"
 
 #, c-format
+msgid ""
+"reading remote from \"%s/%s\", which is nominated for removal.\n"
+"\n"
+"If you still use the \"remotes/\" directory it is recommended to\n"
+"migrate to config-based remotes:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"If you cannot, please let us know why you still need to use it by\n"
+"sending an e-mail to <git@vger.kernel.org>."
+msgstr ""
+"lecture depuis \"%s/%s\", dont la suppression est programmée.\n"
+"\n"
+"Si vous utilisez encore le répertoire \"remotes\", il est recommandé de\n"
+"migrer vers une gestion à base de configuration :\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"S'il vous est impossible de migrer, veuillez nous avertir par\n"
+"un courriel à <git@vger.kernel.org>."
+
+#, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
 msgstr ""
 "un raccourci de configuration de distant ne peut pas commencer par '/' : %s"
@@ -20574,14 +20729,6 @@
 msgstr "%s suit à la fois %s et %s"
 
 #, c-format
-msgid "key '%s' of pattern had no '*'"
-msgstr "la clé '%s' du modèle n'a pas de '*'"
-
-#, c-format
-msgid "value '%s' of pattern has no '*'"
-msgstr "la valeur '%s' du modèle n'a pas de '*'"
-
-#, c-format
 msgid "src refspec %s does not match any"
 msgstr ""
 "le spécificateur de référence source %s ne correspond à aucune référence"
@@ -22505,6 +22652,27 @@
 msgid "number of entries in the cache tree to invalidate (default 0)"
 msgstr "nombre d'entrées dans l'arbre de cache à invalider (par défaut, 0)"
 
+msgid "test-tool path-walk <options> -- <revision-options>"
+msgstr "test-tool path-walk <options> -- <options-de-révision>"
+
+msgid "toggle inclusion of blob objects"
+msgstr "activer l'inclusion des objets blob"
+
+msgid "toggle inclusion of commit objects"
+msgstr "activer l'inclusion des objets commit"
+
+msgid "toggle inclusion of tag objects"
+msgstr "activer l'inclusion des objets étiquette"
+
+msgid "toggle inclusion of tree objects"
+msgstr "activer l'inclusion des objets arbre"
+
+msgid "toggle pruning of uninteresting paths"
+msgstr "activer l'élagage des chemins inintéressants"
+
+msgid "read a pattern list over stdin"
+msgstr "lire les motifs depuis stdin"
+
 #, c-format
 msgid "commit %s is not marked reachable"
 msgstr "le commit %s n'est pas marqué joignable"
@@ -23151,6 +23319,10 @@
 msgid "warning: "
 msgstr "avertissement : "
 
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "échec de uname() avec l'erreur '%s' (%d)\n"
+
 msgid "Fetching objects"
 msgstr "Récupération des objets"
 
@@ -24128,5 +24300,23 @@
 msgstr "Souhaitez-vous réellement envoyer %s ?[y|N] : "
 
 #, c-format
+#~ msgid "Could not find remote branch %s to clone."
+#~ msgstr "Impossible de trouver la branche distante '%s' à cloner."
+
+#, c-format
+#~ msgid "merging cannot continue; got unclean result of %d"
+#~ msgstr "la fusion ne peut pas continuer ; résultat non propre retourné %d"
+
+#~ msgid "git repack [<options>]"
+#~ msgstr "git repack [<options>]"
+
+#~ msgid "--onto and --advance are incompatible"
+#~ msgstr "--onto et --advance sont incompatibles"
+
+#, c-format
+#~ msgid "key '%s' of pattern had no '*'"
+#~ msgstr "la clé '%s' du modèle n'a pas de '*'"
+
+#, c-format
 #~ msgid "preferred pack (%s) is invalid"
 #~ msgstr "le paquet préféré (%s) est invalide"
diff --git a/po/id.po b/po/id.po
index 3965c9e..7d32c51 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: 2024-12-23 18:57+0000\n"
-"PO-Revision-Date: 2025-01-06 15:50+0700\n"
+"POT-Creation-Date: 2025-03-05 22:57+0000\n"
+"PO-Revision-Date: 2025-03-09 17:44+0700\n"
 "Last-Translator: Bagas Sanjaya <bagasdotme@gmail.com>\n"
 "Language-Team: Indonesian\n"
 "Language: id\n"
@@ -2890,6 +2890,22 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: sebuah bilasan diharapkan"
 
+#: builtin/backfill.c
+msgid "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+msgstr "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+
+#: builtin/backfill.c
+msgid "problem loading sparse-checkout"
+msgstr "galat memuat sparse-checkout"
+
+#: builtin/backfill.c
+msgid "Minimum number of objects to request at a time"
+msgstr "Jumlah objek minum yang diminta pada suatu waktu"
+
+#: builtin/backfill.c
+msgid "Restrict the missing objects to the current sparse-checkout"
+msgstr "Batasi objek yang hilang ke sparse-checkout saat ini"
+
 #: builtin/bisect.c
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
@@ -3312,7 +3328,7 @@
 msgid "ignore whitespace differences"
 msgstr "abaikan perbedaan spasi putih"
 
-#: builtin/blame.c builtin/log.c
+#: builtin/blame.c builtin/clone.c builtin/log.c
 msgid "rev"
 msgstr "revisi"
 
@@ -3829,11 +3845,6 @@
 msgstr "versi git:\n"
 
 #: builtin/bugreport.c
-#, c-format
-msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() gagal dengan kesalahan '%s' (%d)\n"
-
-#: builtin/bugreport.c
 msgid "compiler info: "
 msgstr "info pengompilasi: "
 
@@ -5090,167 +5101,6 @@
 msgstr "clean.requireForce 'true' dan -f tidak diberikan: menolak membersihkan"
 
 #: builtin/clone.c
-msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<opsi>] [--] <repo> [<direktori>]"
-
-#: builtin/clone.c
-msgid "don't clone shallow repository"
-msgstr "jangan kloning repositori dangkal"
-
-#: builtin/clone.c
-msgid "don't create a checkout"
-msgstr "jangan buat checkout"
-
-#: builtin/clone.c builtin/init-db.c
-msgid "create a bare repository"
-msgstr "buat repositori bare"
-
-#: builtin/clone.c
-msgid "create a mirror repository (implies --bare)"
-msgstr "buat repositori cermin (mengimplikasikan --bare)"
-
-#: builtin/clone.c
-msgid "to clone from a local repository"
-msgstr "kloning dari repositori lokal"
-
-#: builtin/clone.c
-msgid "don't use local hardlinks, always copy"
-msgstr "jangan gunakan tautan keras lokal, selalu salin"
-
-#: builtin/clone.c
-msgid "setup as shared repository"
-msgstr "siapkan sebagai repositori berbagi"
-
-#: builtin/clone.c
-msgid "pathspec"
-msgstr "spek jalur"
-
-#: builtin/clone.c
-msgid "initialize submodules in the clone"
-msgstr "inisialisasi submodul dalam klon"
-
-#: builtin/clone.c
-msgid "number of submodules cloned in parallel"
-msgstr "jumlah submodul yang diklon secara paralel"
-
-#: builtin/clone.c builtin/init-db.c
-msgid "template-directory"
-msgstr "direktori templat"
-
-#: builtin/clone.c builtin/init-db.c
-msgid "directory from which templates will be used"
-msgstr "direktori dimana templat akan digunakan"
-
-#: builtin/clone.c builtin/submodule--helper.c
-msgid "reference repository"
-msgstr "repositori rujukan"
-
-#: builtin/clone.c builtin/submodule--helper.c
-msgid "use --reference only while cloning"
-msgstr "gunakan --reference hanya pada saat kloning"
-
-#: builtin/clone.c builtin/column.c builtin/fmt-merge-msg.c builtin/init-db.c
-#: builtin/merge-file.c builtin/merge.c builtin/pack-objects.c builtin/repack.c
-#: builtin/submodule--helper.c t/helper/test-simple-ipc.c
-msgid "name"
-msgstr "nama"
-
-#: builtin/clone.c
-msgid "use <name> instead of 'origin' to track upstream"
-msgstr "gunakan <nama> daripada 'origin' untuk lacak hulu"
-
-#: builtin/clone.c
-msgid "checkout <branch> instead of the remote's HEAD"
-msgstr "checkout <cabang> daripada HEAD remote"
-
-#: builtin/clone.c
-msgid "path to git-upload-pack on the remote"
-msgstr "jalur ke git-upload-pack pada remote"
-
-#: builtin/clone.c builtin/fetch.c builtin/pull.c
-msgid "depth"
-msgstr "kedalaman"
-
-#: builtin/clone.c
-msgid "create a shallow clone of that depth"
-msgstr "buat klon dangkal sedalam kedalaman tersebut"
-
-#: builtin/clone.c
-msgid "create a shallow clone since a specific time"
-msgstr "buat klon dangkal sejak waktu yang disebutkan"
-
-#: builtin/clone.c builtin/fetch.c builtin/pull.c
-msgid "ref"
-msgstr "referensi"
-
-#: builtin/clone.c builtin/fetch.c builtin/pull.c
-msgid "deepen history of shallow clone, excluding ref"
-msgstr "perdalam riwayat klon dangkal, kecualikan referensi"
-
-#: builtin/clone.c builtin/submodule--helper.c
-msgid "clone only one branch, HEAD or --branch"
-msgstr "klon hanya satu cabang, HEAD atau --branch"
-
-#: builtin/clone.c
-msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr "jangan klon tag apapun, dan buat pengambilan nanti tidak mengikutinya"
-
-#: builtin/clone.c
-msgid "any cloned submodules will be shallow"
-msgstr "submodul yang diklon akan dangkal"
-
-#: builtin/clone.c builtin/init-db.c
-msgid "gitdir"
-msgstr "direktori git"
-
-#: builtin/clone.c builtin/init-db.c
-msgid "separate git dir from working tree"
-msgstr "pisahkan direktori git dari pohon kerja"
-
-#: builtin/clone.c builtin/init-db.c builtin/submodule--helper.c
-msgid "specify the reference format to use"
-msgstr "sebutkan format referensi untuk digunakan"
-
-#: builtin/clone.c
-msgid "key=value"
-msgstr "kunci=nilai"
-
-#: builtin/clone.c
-msgid "set config inside the new repository"
-msgstr "setel konfigurasi di dalam repositori baru"
-
-#: builtin/clone.c builtin/fetch.c builtin/ls-remote.c builtin/pull.c
-#: builtin/push.c builtin/send-pack.c
-msgid "server-specific"
-msgstr "spesifik ke server"
-
-#: builtin/clone.c builtin/fetch.c builtin/ls-remote.c builtin/pull.c
-#: builtin/push.c builtin/send-pack.c
-msgid "option to transmit"
-msgstr "opsi untuk transmisi"
-
-#: builtin/clone.c
-msgid "apply partial clone filters to submodules"
-msgstr "terapkan saringan kloning parsial ke submodul"
-
-#: builtin/clone.c
-msgid "any cloned submodules will use their remote-tracking branch"
-msgstr "submodul yang diklon akan menggunakan cabang yang melacak remotenya"
-
-#: builtin/clone.c
-msgid "initialize sparse-checkout file to include only files at root"
-msgstr ""
-"inisialisasi berkas checkout tipis agar memasukkan hanya berkas pada akar"
-
-#: builtin/clone.c
-msgid "uri"
-msgstr "URI"
-
-#: builtin/clone.c
-msgid "a URI for downloading bundles before fetching from origin remote"
-msgstr "sebuah URI untuk mengunduh bundel sebelum mengambil dari remote asal"
-
-#: builtin/clone.c
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info: Tidak dapat menambahkan alternatif untuk '%s': %s\n"
@@ -5325,11 +5175,6 @@
 "Anda dapat periksa apa yang dicheckout dengan 'git status'\n"
 "dan coba lagi dengan 'git restore --source=HEAD :/'\n"
 
-#: builtin/clone.c
-#, c-format
-msgid "Could not find remote branch %s to clone."
-msgstr "Tidak dapat menemukan cabang remote %s untuk diklon."
-
 #: builtin/clone.c fetch-pack.c
 msgid "remote did not send all necessary objects"
 msgstr "remote tidak mengirim semua objek yang dibutuhkan"
@@ -5364,6 +5209,171 @@
 msgstr "tidak dapat batal-taut berkas alternatif sementara"
 
 #: builtin/clone.c
+msgid "don't clone shallow repository"
+msgstr "jangan kloning repositori dangkal"
+
+#: builtin/clone.c
+msgid "don't create a checkout"
+msgstr "jangan buat checkout"
+
+#: builtin/clone.c builtin/init-db.c
+msgid "create a bare repository"
+msgstr "buat repositori bare"
+
+#: builtin/clone.c
+msgid "create a mirror repository (implies --bare)"
+msgstr "buat repositori cermin (mengimplikasikan --bare)"
+
+#: builtin/clone.c
+msgid "to clone from a local repository"
+msgstr "kloning dari repositori lokal"
+
+#: builtin/clone.c
+msgid "don't use local hardlinks, always copy"
+msgstr "jangan gunakan tautan keras lokal, selalu salin"
+
+#: builtin/clone.c
+msgid "setup as shared repository"
+msgstr "siapkan sebagai repositori berbagi"
+
+#: builtin/clone.c
+msgid "pathspec"
+msgstr "spek jalur"
+
+#: builtin/clone.c
+msgid "initialize submodules in the clone"
+msgstr "inisialisasi submodul dalam klon"
+
+#: builtin/clone.c
+msgid "number of submodules cloned in parallel"
+msgstr "jumlah submodul yang diklon secara paralel"
+
+#: builtin/clone.c builtin/init-db.c
+msgid "template-directory"
+msgstr "direktori templat"
+
+#: builtin/clone.c builtin/init-db.c
+msgid "directory from which templates will be used"
+msgstr "direktori dimana templat akan digunakan"
+
+#: builtin/clone.c builtin/submodule--helper.c
+msgid "reference repository"
+msgstr "repositori rujukan"
+
+#: builtin/clone.c builtin/submodule--helper.c
+msgid "use --reference only while cloning"
+msgstr "gunakan --reference hanya pada saat kloning"
+
+#: builtin/clone.c builtin/column.c builtin/fmt-merge-msg.c builtin/init-db.c
+#: builtin/merge-file.c builtin/merge.c builtin/pack-objects.c builtin/repack.c
+#: builtin/submodule--helper.c t/helper/test-simple-ipc.c
+msgid "name"
+msgstr "nama"
+
+#: builtin/clone.c
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "gunakan <nama> daripada 'origin' untuk lacak hulu"
+
+#: builtin/clone.c
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "checkout <cabang> daripada HEAD remote"
+
+#: builtin/clone.c
+msgid "clone single revision <rev> and check out"
+msgstr "klon satu revisi <revisi> dan check out"
+
+#: builtin/clone.c
+msgid "path to git-upload-pack on the remote"
+msgstr "jalur ke git-upload-pack pada remote"
+
+#: builtin/clone.c builtin/fetch.c builtin/pull.c
+msgid "depth"
+msgstr "kedalaman"
+
+#: builtin/clone.c
+msgid "create a shallow clone of that depth"
+msgstr "buat klon dangkal sedalam kedalaman tersebut"
+
+#: builtin/clone.c
+msgid "create a shallow clone since a specific time"
+msgstr "buat klon dangkal sejak waktu yang disebutkan"
+
+#: builtin/clone.c builtin/fetch.c builtin/pull.c
+msgid "ref"
+msgstr "referensi"
+
+#: builtin/clone.c builtin/fetch.c builtin/pull.c
+msgid "deepen history of shallow clone, excluding ref"
+msgstr "perdalam riwayat klon dangkal, kecualikan referensi"
+
+#: builtin/clone.c builtin/submodule--helper.c
+msgid "clone only one branch, HEAD or --branch"
+msgstr "klon hanya satu cabang, HEAD atau --branch"
+
+#: builtin/clone.c
+msgid "clone tags, and make later fetches not to follow them"
+msgstr "klon tag dan jangan ikuti mereka pada pengambilan berikutnya"
+
+#: builtin/clone.c
+msgid "any cloned submodules will be shallow"
+msgstr "submodul yang diklon akan dangkal"
+
+#: builtin/clone.c builtin/init-db.c
+msgid "gitdir"
+msgstr "direktori git"
+
+#: builtin/clone.c builtin/init-db.c
+msgid "separate git dir from working tree"
+msgstr "pisahkan direktori git dari pohon kerja"
+
+#: builtin/clone.c builtin/init-db.c builtin/submodule--helper.c
+msgid "specify the reference format to use"
+msgstr "sebutkan format referensi untuk digunakan"
+
+#: builtin/clone.c
+msgid "key=value"
+msgstr "kunci=nilai"
+
+#: builtin/clone.c
+msgid "set config inside the new repository"
+msgstr "setel konfigurasi di dalam repositori baru"
+
+#: builtin/clone.c builtin/fetch.c builtin/ls-remote.c builtin/pull.c
+#: builtin/push.c builtin/send-pack.c
+msgid "server-specific"
+msgstr "spesifik ke server"
+
+#: builtin/clone.c builtin/fetch.c builtin/ls-remote.c builtin/pull.c
+#: builtin/push.c builtin/send-pack.c
+msgid "option to transmit"
+msgstr "opsi untuk transmisi"
+
+#: builtin/clone.c
+msgid "apply partial clone filters to submodules"
+msgstr "terapkan saringan kloning parsial ke submodul"
+
+#: builtin/clone.c
+msgid "any cloned submodules will use their remote-tracking branch"
+msgstr "submodul yang diklon akan menggunakan cabang yang melacak remotenya"
+
+#: builtin/clone.c
+msgid "initialize sparse-checkout file to include only files at root"
+msgstr ""
+"inisialisasi berkas checkout tipis agar memasukkan hanya berkas pada akar"
+
+#: builtin/clone.c
+msgid "uri"
+msgstr "URI"
+
+#: builtin/clone.c
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "sebuah URI untuk mengunduh bundel sebelum mengambil dari remote asal"
+
+#: builtin/clone.c
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [<opsi>] [--] <repo> [<direktori>]"
+
+#: builtin/clone.c
 msgid "Too many arguments."
 msgstr "Terlalu banyak argumen."
 
@@ -5492,6 +5502,11 @@
 msgstr "Cabang remote %s tidak ditemukan di hulu %s"
 
 #: builtin/clone.c
+#, c-format
+msgid "Remote revision %s not found in upstream %s"
+msgstr "Revisi remote %s tidak ditemukan di hulu %s"
+
+#: builtin/clone.c
 msgid "You appear to have cloned an empty repository."
 msgstr "Anda tampaknya mengklon repositori kosong."
 
@@ -5555,7 +5570,8 @@
 "[no-]progress]\n"
 "                       <opsi pemisahan>"
 
-#: builtin/commit-graph.c builtin/fetch.c builtin/log.c builtin/repack.c
+#: builtin/commit-graph.c builtin/fetch.c builtin/gc.c builtin/log.c
+#: builtin/repack.c
 msgid "dir"
 msgstr "direktori"
 
@@ -5715,7 +5731,7 @@
 
 #: builtin/commit.c
 msgid ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -5725,7 +5741,7 @@
 "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
 "           [--] [<pathspec>...]"
 msgstr ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <komit> | --fixup [(amend|"
 "reword):]<komit>]\n"
 "           [-F <berkas> | -m <pesan>] [--reset-author] [--allow-empty]\n"
@@ -7472,14 +7488,14 @@
 "Run 'git remote set-head %s %s' to follow the change, or set\n"
 "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
 "if you do not want to see this message. Specifically running\n"
-"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
-"until the remote changes HEAD to something else."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"will disable the warning until the remote changes HEAD to something else."
 msgstr ""
 "Jalankan 'git remote set-head %s %s' untuk mengikuti perubahan, atau setel\n"
 "opsi konfigurasi 'remote.%s.followRemoteHEAD' ke nilai yang berbeda jika\n"
-"Anda tidak ingin melihat pesan ini lagi. Secara rinci menjalakan\n"
-"'git config set remote.%s followRemoteHEAD %s' akan mematikan peringatan\n"
-"ini sampai remote mengubah HEAD ke yang lain."
+"Anda tidak ingin melihat pesan ini lagi. Secara rinci menjalankan\n"
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s' akan\n"
+"mematikan peringatan ini sampai remote mengubah HEAD ke yang lain."
 
 #: builtin/fetch.c
 msgid "multiple branches detected, incompatible with --set-upstream"
@@ -8341,6 +8357,10 @@
 msgid "repack all other packs except the largest pack"
 msgstr "pak ulang semua pak yang lain kecuali pak terbesar"
 
+#: builtin/gc.c builtin/repack.c
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "awalan pak untuk menyimpan pak berisi objek terpangkas"
+
 #: builtin/gc.c
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
@@ -9353,6 +9373,11 @@
 msgid "Cannot come back to cwd"
 msgstr "tidak dapat kembali ke direktori kerja saat ini"
 
+#: builtin/index-pack.c builtin/unpack-objects.c
+#, c-format
+msgid "bad --pack_header: %s"
+msgstr "--pack_header jelek: %s"
+
 #: builtin/index-pack.c
 #, c-format
 msgid "bad %s"
@@ -10476,11 +10501,6 @@
 msgid "malformed input line: '%s'."
 msgstr "baris masukan jelek: '%s'."
 
-#: builtin/merge-tree.c
-#, c-format
-msgid "merging cannot continue; got unclean result of %d"
-msgstr "penggabungan tidak dapat berlanjut; dapat hasil kotor dari %d"
-
 #: builtin/merge.c
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<opsi>] [<komit>...]"
@@ -11524,6 +11544,15 @@
 
 #: builtin/pack-objects.c
 #, c-format
+msgid "invalid --name-hash-version option: %d"
+msgstr "opsi --name-hash-version tidak valid: %d"
+
+#: builtin/pack-objects.c
+msgid "currently, --write-bitmap-index requires --name-hash-version=1"
+msgstr "saat ini, --write-bitmap-index memerlukan --name-hash-version=1"
+
+#: builtin/pack-objects.c
+#, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
@@ -11935,6 +11964,12 @@
 "protokol ini"
 
 #: builtin/pack-objects.c
+msgid "use the specified name-hash function to group similar objects"
+msgstr ""
+"gunakan fungsi nama-hash yang dirincikan untuk mengelompokan objek yang "
+"serupa"
+
+#: builtin/pack-objects.c
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
 msgstr "kedalaman rantai delta %d terlalu dalam, memaksakan %d"
@@ -13428,8 +13463,8 @@
 msgstr "format referensi tidak valid: %s"
 
 #: builtin/refs.c
-msgid "git refs migrate --ref-format=<format> [--dry-run]"
-msgstr "git refs migrate --ref-format=<format> [--dry-run]"
+msgid "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
+msgstr "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
 
 #: builtin/refs.c
 msgid "git refs verify [--strict] [--verbose]"
@@ -13444,6 +13479,10 @@
 msgstr "lakukan uji coba non desktruktif"
 
 #: builtin/refs.c
+msgid "drop reflogs entirely during the migration"
+msgstr "buang keseluruhan log referensi selama migrasi"
+
+#: builtin/refs.c
 msgid "missing --ref-format=<format>"
 msgstr "--ref-format=<format> hilang"
 
@@ -14024,8 +14063,14 @@
 msgstr "jadi lebih bertele-tele; harus ditempatkan sebelum subperintah"
 
 #: builtin/repack.c
-msgid "git repack [<options>]"
-msgstr "git repack [<opsi>]"
+msgid ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
+msgstr ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<nama pak>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
 
 #: builtin/repack.c
 msgid ""
@@ -14119,6 +14164,13 @@
 msgstr "lewatkan --no-reuse-object ke git-pack-objects"
 
 #: builtin/repack.c
+msgid ""
+"specify the name hash version to use for grouping similar objects by path"
+msgstr ""
+"tentukan versi nama hash yang digunakan untuk mengelompokan objek yang "
+"serupa berdasarkan jalur"
+
+#: builtin/repack.c
 msgid "do not run git-update-server-info"
 msgstr "jangan jalankan git-update-server-info"
 
@@ -14185,10 +14237,6 @@
 msgstr "tulis indeks multipak dari pak yang dihasilkan"
 
 #: builtin/repack.c
-msgid "pack prefix to store a pack containing pruned objects"
-msgstr "awalan pak untuk menyimpan pak berisi objek terpangkas"
-
-#: builtin/repack.c
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr "awalan pak untuk menyimpan pak berisi objek tersaring"
 
@@ -14463,10 +14511,6 @@
 msgstr "butuh beberapa komit untuk dimainkan ulang"
 
 #: builtin/replay.c
-msgid "--onto and --advance are incompatible"
-msgstr "--onto dan --advance tidak kompatibel"
-
-#: builtin/replay.c
 msgid "all positive revisions given must be references"
 msgstr "semua revisi positif yang diberikan haruslah referensi"
 
@@ -17768,6 +17812,10 @@
 msgstr "Buat arsip berkas dari pohon bernama"
 
 #: command-list.h
+msgid "Download missing objects in a partial clone"
+msgstr "Unduh objek yang hilang dalam klon parsial"
+
+#: command-list.h
 msgid "Use binary search to find the commit that introduced a bug"
 msgstr "Gunakan pencarian biner untuk mencari komit yang memasukkan bug"
 
@@ -20191,6 +20239,14 @@
 msgstr "regex tidak valid diberikan ke -I: '%s'"
 
 #: diff.c
+msgid "-G requires a non-empty argument"
+msgstr "-G butuh sebuah argumen bukan kosong"
+
+#: diff.c
+msgid "-S requires a non-empty argument"
+msgstr "-S butuh sebuah argumen bukan kosong"
+
+#: diff.c
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr "gagal menguraikan parameter opsi --submodule: '%s'"
@@ -22888,6 +22944,11 @@
 
 #: object-file.c
 #, c-format
+msgid "unable to write repeatedly vanishing file %s"
+msgstr "tidak dapat menulis berkas yang menghilang %s terus-menerus"
+
+#: object-file.c
+#, c-format
 msgid "unable to set permission to '%s'"
 msgstr "tidak dapat menyetel perizinan ke '%s'"
 
@@ -23579,6 +23640,55 @@
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "opsi non-ascii di dalam untai tidak dikenal: `%s'"
 
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the long form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#: parse-options.c
+#, c-format
+msgid "[=<%s>]"
+msgstr "[=<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the short form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#: parse-options.c
+#, c-format
+msgid "[<%s>]"
+msgstr "[<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string stands for a
+#. value given to a command line option, and "<>" is there
+#. as a convention to signal that it is a placeholder
+#. (i.e. the user should substitute it with the real value).
+#. If your language uses a different convention, you can
+#. change "<%s>" part to match yours, e.g. it might use
+#. "|%s|" instead, or if the alphabet is different enough it
+#. may use "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#: parse-options.c
+#, c-format
+msgid " <%s>"
+msgstr " <%s>"
+
 #: parse-options.c
 msgid "..."
 msgstr "..."
@@ -23682,6 +23792,25 @@
 msgid "failed to parse %s"
 msgstr "gagal menguraikan %s"
 
+#: path-walk.c
+#, c-format
+msgid "failed to walk children of tree %s: not found"
+msgstr "gagal berjalan anak pohon %s: tidak ditemukan"
+
+#: path-walk.c
+#, c-format
+msgid "failed to find object %s"
+msgstr "gagal menemukan objek %s"
+
+#: path-walk.c
+#, c-format
+msgid "failed to find tag %s"
+msgstr "gagal menemukan tag %s"
+
+#: path-walk.c
+msgid "failed to setup revision walk"
+msgstr "gagal men-setup jalan revisi"
+
 #: path.c
 #, c-format
 msgid "Could not make %s writable by group"
@@ -23868,6 +23997,26 @@
 msgid "could not fetch %s from promisor remote"
 msgstr "tidak dapat mengambil %s dari remote penjanji"
 
+#: promisor-remote.c
+#, c-format
+msgid "known remote named '%s' but with url '%s' instead of '%s'"
+msgstr "remote yang terkenal bernama '%s' tapi dengan url '%s' daripada '%s'"
+
+#: promisor-remote.c
+#, c-format
+msgid "unknown '%s' value for '%s' config option"
+msgstr "nilai '%s' tidak dikenal untuk opsi konfigurasi '%s'"
+
+#: promisor-remote.c
+#, c-format
+msgid "unknown element '%s' from remote info"
+msgstr "elemen '%s' dari info remote tidak dikenal"
+
+#: promisor-remote.c
+#, c-format
+msgid "accepted promisor remote '%s' not found"
+msgstr "remote penjanji yang diterima '%s' tidak ditemukan"
+
 #: protocol-caps.c
 msgid "object-info: expected flush after arguments"
 msgstr "object-info: bilasan diharapkan setelah argumen"
@@ -24870,6 +25019,16 @@
 msgid "invalid refspec '%s'"
 msgstr "spek referensi tidak valid '%s'"
 
+#: refspec.c
+#, c-format
+msgid "pattern '%s' has no '*'"
+msgstr "pola '%s' tidak mempunyai '*'"
+
+#: refspec.c
+#, c-format
+msgid "replacement '%s' has no '*'"
+msgstr "pengganti '%s' tidak mempunyai '*'"
+
 #: remote-curl.c
 #, c-format
 msgid "invalid quoting in push-option value: '%s'"
@@ -25025,6 +25184,28 @@
 
 #: remote.c
 #, c-format
+msgid ""
+"reading remote from \"%s/%s\", which is nominated for removal.\n"
+"\n"
+"If you still use the \"remotes/\" directory it is recommended to\n"
+"migrate to config-based remotes:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"If you cannot, please let us know why you still need to use it by\n"
+"sending an e-mail to <git@vger.kernel.org>."
+msgstr ""
+"membaca remote dari \"%s/%s\", yang dinominasikan untuk dihapus.\n"
+"\n"
+"Jika Anda masih menggunakan direktori \"remotes/\" disarankan untuk\n"
+"migrasi ke remote berdasarkan konfigurasi:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"Jika tidak, mohon beri tahu kami mengapa Anda masih menggunakannya dengan\n"
+"mengirimkan surel ke <git@vger.kernel.org>."
+
+#: remote.c
+#, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
 msgstr "pintasan konfigurasi remote tidak dapat diawali dengan '/': %s"
 
@@ -25068,16 +25249,6 @@
 
 #: remote.c
 #, c-format
-msgid "key '%s' of pattern had no '*'"
-msgstr "kunci '%s' dari pola tidak ada '*'"
-
-#: remote.c
-#, c-format
-msgid "value '%s' of pattern has no '*'"
-msgstr "nilai '%s' dari pola tidak ada '*'"
-
-#: remote.c
-#, c-format
 msgid "src refspec %s does not match any"
 msgstr "spek referensi sumber %s tidak cocok dengan apapun"
 
@@ -27389,6 +27560,34 @@
 msgid "number of entries in the cache tree to invalidate (default 0)"
 msgstr "jumlah entri di dalam pohon tembolok untuk dinirvalidasi (asali 0)"
 
+#: t/helper/test-path-walk.c
+msgid "test-tool path-walk <options> -- <revision-options>"
+msgstr "test-tool path-walk <opsi> -- <opsi revisi>"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of blob objects"
+msgstr "sertakan objek blob"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of commit objects"
+msgstr "sertakan objek komit"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of tag objects"
+msgstr "sertakan objek tag"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of tree objects"
+msgstr "sertakan objek pohon"
+
+#: t/helper/test-path-walk.c
+msgid "toggle pruning of uninteresting paths"
+msgstr "pangkas jalur yang tidak menarik"
+
+#: t/helper/test-path-walk.c
+msgid "read a pattern list over stdin"
+msgstr "baca daftar pola dari masukan standar"
+
 #: t/helper/test-reach.c
 #, c-format
 msgid "commit %s is not marked reachable"
@@ -28148,6 +28347,11 @@
 msgid "warning: "
 msgstr "peringatan: "
 
+#: version.c
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "uname() gagal dengan kesalahan '%s' (%d)\n"
+
 #: walker.c
 msgid "Fetching objects"
 msgstr "Mengambil objek"
diff --git a/po/it.po b/po/it.po
index c315608..20fd8bb 100644
--- a/po/it.po
+++ b/po/it.po
@@ -17602,7 +17602,7 @@
 
 #: builtin/mv.c:185
 msgid "bad source"
-msgstr "sourgente errata"
+msgstr "sorgente errata"
 
 #: builtin/mv.c:188
 msgid "can not move directory into itself"
diff --git a/po/ko.po b/po/ko.po
index 5d190e5..7a6847f 100644
--- a/po/ko.po
+++ b/po/ko.po
@@ -7,6 +7,7 @@
 #  Changwoo Ryu <cwryu@debian.org>, 2015-2018.
 #  Sihyeon Jang <uneedsihyeon@gmail.com>, 2018.
 #  Gwan-gyeong Mun <elongbug@gmail.com>, 2018.
+#  Seoyeon Kwon <syeon0204@gmail.com>, 2025.
 #
 # - 작업자는 위 Contributors 목록에 추가해 주세요.
 # - 번역하면서 80컬럼을 넘어가지 않도록 해 주세요.
@@ -7666,7 +7667,7 @@
 "    git commit --allow-empty\n"
 "\n"
 msgstr ""
-"이전 커맷 빼오기가 비어 있습니다. 아마도 충돌 해결 과정에서 그렇게 됐을\n"
+"이전 커밋 빼오기가 비어 있습니다. 아마도 충돌 해결 과정에서 그렇게 됐을\n"
 "것입니다. 그래도 커밋하려면 다음과 같이 하십시오:\n"
 "\n"
 "    git commit --allow-empty\n"
diff --git a/po/sv.po b/po/sv.po
index 5377b3e..42c357e 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -1,14 +1,14 @@
 # Swedish translations for Git.
-# Copyright (C) 2010-2024 Peter Krefting <peter@softwolves.pp.se>
+# Copyright (C) 2010-2025 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-2024.
+# Peter Krefting <peter@softwolves.pp.se>, 2010-2025.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.48.0\n"
+"Project-Id-Version: git 2.49.0\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-12-30 11:57+0100\n"
-"PO-Revision-Date: 2024-12-30 12:03+0100\n"
+"POT-Creation-Date: 2025-03-10 17:45+0100\n"
+"PO-Revision-Date: 2025-03-10 17:48+0100\n"
 "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
 "Language-Team: Svenska <tp-sv@listor.tp-sv.se>\n"
 "Language: sv\n"
@@ -1477,7 +1477,7 @@
 "Use '\\!' for literal leading exclamation."
 msgstr ""
 "Negativa mönster ignoreras i git-attribut\n"
-"Använd '\\!' för att inleda med ett utropstecken."
+"Använd ”\\!” för att inleda med ett utropstecken."
 
 #, c-format
 msgid "cannot fstat gitattributes file '%s'"
@@ -2060,7 +2060,7 @@
 "It does not apply to blobs recorded in its index."
 msgstr ""
 "Har du handredigerat din patch?\n"
-"Den kan inte tillämpas på blobbar som antecknats i dess index."
+"Den kan inte tillämpas på blob:ar som antecknats i dess index."
 
 msgid "Falling back to patching base and 3-way merge..."
 msgstr ""
@@ -2316,6 +2316,18 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: förväntade en tömning (flush)"
 
+msgid "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+msgstr "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+
+msgid "problem loading sparse-checkout"
+msgstr "problem med att läsa filen sparse-checkout"
+
+msgid "Minimum number of objects to request at a time"
+msgstr "Minsta antal objekt att be om varje gång"
+
+msgid "Restrict the missing objects to the current sparse-checkout"
+msgstr "Begränsa saknade objekt till befintlig ”sparse-checkout”"
+
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
 "checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
@@ -2921,7 +2933,7 @@
 msgstr "ta bort gren (även om inte helt sammanslagen)"
 
 msgid "move/rename a branch and its reflog"
-msgstr "flytta/ta bort en gren och dess reflogg"
+msgstr "flytta/ta bort en gren och dess referenslogg"
 
 msgid "move/rename a branch, even if target exists"
 msgstr "flytta/ta bort en gren, även om målet finns"
@@ -2930,7 +2942,7 @@
 msgstr "skriv inte ut ett nyradstecken efter tomma formaterade referenser"
 
 msgid "copy a branch and its reflog"
-msgstr "kopiera en gren och dess reflogg"
+msgstr "kopiera en gren och dess referenslogg"
 
 msgid "copy a branch, even if target exists"
 msgstr "kopiera en gren, även om målet finns"
@@ -2942,7 +2954,7 @@
 msgstr "visa namn på aktuell gren"
 
 msgid "create the branch's reflog"
-msgstr "skapa grenens reflogg"
+msgstr "skapa grenens referenslogg"
 
 msgid "edit the description for the branch"
 msgstr "redigera beskrivning för grenen"
@@ -3055,10 +3067,6 @@
 msgid "git version:\n"
 msgstr "git version:\n"
 
-#, c-format
-msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() misslyckades med felet ”%s” (%d)\n"
-
 msgid "compiler info: "
 msgstr "kompilatorinfo:"
 
@@ -3095,7 +3103,7 @@
 "You can delete any lines you don't wish to share.\n"
 msgstr ""
 "Tack för att du skriver en buggraport för Git!\n"
-"Om du svarar på följande frågor är det lättare för oss att första "
+"Om du svarar på följande frågor är det lättare för oss att förstå "
 "problemet.\n"
 "Skriv gärna på engelska\n"
 "\n"
@@ -3332,11 +3340,11 @@
 msgstr "blob|träd"
 
 msgid "use a <path> for (--textconv | --filters); Not with 'batch'"
-msgstr "använd en <sökväg> för (--textconv | --filters): Inte med 'batch'"
+msgstr "använd en <sökväg> för (--textconv | --filters): Inte med ”batch”"
 
 #, c-format
 msgid "'%s=<%s>' needs '%s' or '%s'"
-msgstr "'%s=<%s>' behöver '%s' eller '%s'"
+msgstr "”%s=<%s>” behöver ”%s” eller ”%s”"
 
 msgid "path|tree-ish"
 msgstr "sökväg|träd-igt"
@@ -3368,13 +3376,13 @@
 "git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
 "<pathname>..."
 msgstr ""
-"git check-attr [--source <träd:igt>] [-a | --all | <attr>...] [--] "
+"git check-attr [--source <träd-igt>] [-a | --all | <attr>...] [--] "
 "<sökväg>..."
 
 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>...]"
+"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"
@@ -3887,7 +3895,7 @@
 msgstr "skapa/nollställ och checka ut en gren"
 
 msgid "create reflog for new branch"
-msgstr "skapa reflogg för ny gren"
+msgstr "skapa referenslogg för ny gren"
 
 msgid "second guess 'git checkout <no-such-branch>' (default)"
 msgstr "förutspå ”git checkout <gren-saknas>” (förval)"
@@ -4062,123 +4070,6 @@
 msgid "clean.requireForce is true and -f not given: refusing to clean"
 msgstr "clean.requireForce är true och -f angavs inte: vägrar städa"
 
-msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<flaggor>] [--] <arkiv> [<kat>]"
-
-msgid "don't clone shallow repository"
-msgstr "klona inte grunt arkiv"
-
-msgid "don't create a checkout"
-msgstr "skapa inte någon utcheckning"
-
-msgid "create a bare repository"
-msgstr "skapa ett naket (”bare”) arkiv"
-
-msgid "create a mirror repository (implies --bare)"
-msgstr "skapa ett spegelarkiv (implicerar --bare)"
-
-msgid "to clone from a local repository"
-msgstr "för att klona från ett lokalt arkiv"
-
-msgid "don't use local hardlinks, always copy"
-msgstr "skapa inte lokala hårda länkar, kopiera alltid"
-
-msgid "setup as shared repository"
-msgstr "skapa som ett delat arkiv"
-
-msgid "pathspec"
-msgstr "sökvägsangivelse"
-
-msgid "initialize submodules in the clone"
-msgstr "initiera undermoduler i klonen"
-
-msgid "number of submodules cloned in parallel"
-msgstr "antal undermoduler som klonas parallellt"
-
-msgid "template-directory"
-msgstr "mallkatalog"
-
-msgid "directory from which templates will be used"
-msgstr "katalog att använda mallar från"
-
-msgid "reference repository"
-msgstr "referensarkiv"
-
-msgid "use --reference only while cloning"
-msgstr "använd --reference endast under kloningen"
-
-msgid "name"
-msgstr "namn"
-
-msgid "use <name> instead of 'origin' to track upstream"
-msgstr "använd <namn> istället för ”origin” för att spåra uppströms"
-
-msgid "checkout <branch> instead of the remote's HEAD"
-msgstr "checka ut <gren> istället för fjärrens HEAD"
-
-msgid "path to git-upload-pack on the remote"
-msgstr "sökväg till git-upload-pack på fjärren"
-
-msgid "depth"
-msgstr "djup"
-
-msgid "create a shallow clone of that depth"
-msgstr "skapa en grund klon på detta djup"
-
-msgid "create a shallow clone since a specific time"
-msgstr "skapa en grund klon från en angiven tidpunkt"
-
-msgid "ref"
-msgstr "ref"
-
-msgid "deepen history of shallow clone, excluding ref"
-msgstr "fördjupa historik för grund klon, exkludera ref"
-
-msgid "clone only one branch, HEAD or --branch"
-msgstr "klona endast en gren, HEAD eller --branch"
-
-msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr "klona inga taggar och gör att senare hämtningar inte följer dem"
-
-msgid "any cloned submodules will be shallow"
-msgstr "klonade undermoduler kommer vara grunda"
-
-msgid "gitdir"
-msgstr "gitkat"
-
-msgid "separate git dir from working tree"
-msgstr "separera gitkatalogen från arbetskatalogen"
-
-msgid "specify the reference format to use"
-msgstr "använd referensformatet som ska användas"
-
-msgid "key=value"
-msgstr "nyckel=värde"
-
-msgid "set config inside the new repository"
-msgstr "ställ in konfiguration i det nya arkivet"
-
-msgid "server-specific"
-msgstr "serverspecifik"
-
-msgid "option to transmit"
-msgstr "flagga att sända"
-
-msgid "apply partial clone filters to submodules"
-msgstr "tillämpa delvisa klonfilter på undermoduler"
-
-msgid "any cloned submodules will use their remote-tracking branch"
-msgstr "klonade undermoduler kommer använda sin fjärrspårningsgren"
-
-msgid "initialize sparse-checkout file to include only files at root"
-msgstr "initiera sparse-checkout-filen till att bara ta med filer i roten"
-
-msgid "uri"
-msgstr "uri"
-
-msgid "a URI for downloading bundles before fetching from origin remote"
-msgstr "en URI för att hämta buntar innan de hämtas från ursprungsfjärr"
-
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info: Kan inte skapa suppleant för ”%s”: %s\n"
@@ -4240,10 +4131,6 @@
 "Du kan inspektera det som checkades ut med ”git status”\n"
 "och försöka med ”git restore --source=HEAD :/”\n"
 
-#, c-format
-msgid "Could not find remote branch %s to clone."
-msgstr "Kunde inte hitta fjärrgrenen %s för att klona."
-
 msgid "remote did not send all necessary objects"
 msgstr "fjärren sände inte alla nödvändiga objekt"
 
@@ -4269,6 +4156,126 @@
 msgid "cannot unlink temporary alternates file"
 msgstr "kunde inte ta bort temporär ”alternates”-fil"
 
+msgid "don't clone shallow repository"
+msgstr "klona inte grunt arkiv"
+
+msgid "don't create a checkout"
+msgstr "skapa inte någon utcheckning"
+
+msgid "create a bare repository"
+msgstr "skapa ett naket (”bare”) arkiv"
+
+msgid "create a mirror repository (implies --bare)"
+msgstr "skapa ett spegelarkiv (implicerar --bare)"
+
+msgid "to clone from a local repository"
+msgstr "för att klona från ett lokalt arkiv"
+
+msgid "don't use local hardlinks, always copy"
+msgstr "skapa inte lokala hårda länkar, kopiera alltid"
+
+msgid "setup as shared repository"
+msgstr "skapa som ett delat arkiv"
+
+msgid "pathspec"
+msgstr "sökvägsangivelse"
+
+msgid "initialize submodules in the clone"
+msgstr "initiera undermoduler i klonen"
+
+msgid "number of submodules cloned in parallel"
+msgstr "antal undermoduler som klonas parallellt"
+
+msgid "template-directory"
+msgstr "mallkatalog"
+
+msgid "directory from which templates will be used"
+msgstr "katalog att använda mallar från"
+
+msgid "reference repository"
+msgstr "referensarkiv"
+
+msgid "use --reference only while cloning"
+msgstr "använd --reference endast under kloningen"
+
+msgid "name"
+msgstr "namn"
+
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "använd <namn> istället för ”origin” för att spåra uppströms"
+
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "checka ut <gren> istället för fjärrens HEAD"
+
+msgid "clone single revision <rev> and check out"
+msgstr "klona ensam revision <rev> och checka ut"
+
+msgid "path to git-upload-pack on the remote"
+msgstr "sökväg till git-upload-pack på fjärren"
+
+msgid "depth"
+msgstr "djup"
+
+msgid "create a shallow clone of that depth"
+msgstr "skapa en grund klon på detta djup"
+
+msgid "create a shallow clone since a specific time"
+msgstr "skapa en grund klon från en angiven tidpunkt"
+
+msgid "ref"
+msgstr "ref"
+
+msgid "deepen history of shallow clone, excluding ref"
+msgstr "fördjupa historik för grund klon, exkludera ref"
+
+msgid "clone only one branch, HEAD or --branch"
+msgstr "klona endast en gren, HEAD eller --branch"
+
+msgid "clone tags, and make later fetches not to follow them"
+msgstr "klona taggar och gör att senare hämtningar inte följer dem"
+
+msgid "any cloned submodules will be shallow"
+msgstr "klonade undermoduler kommer vara grunda"
+
+msgid "gitdir"
+msgstr "gitkat"
+
+msgid "separate git dir from working tree"
+msgstr "separera gitkatalogen från arbetskatalogen"
+
+msgid "specify the reference format to use"
+msgstr "använd referensformatet som ska användas"
+
+msgid "key=value"
+msgstr "nyckel=värde"
+
+msgid "set config inside the new repository"
+msgstr "ställ in konfiguration i det nya arkivet"
+
+msgid "server-specific"
+msgstr "serverspecifik"
+
+msgid "option to transmit"
+msgstr "flagga att sända"
+
+msgid "apply partial clone filters to submodules"
+msgstr "tillämpa delvisa klonfilter på undermoduler"
+
+msgid "any cloned submodules will use their remote-tracking branch"
+msgstr "klonade undermoduler kommer använda sin fjärrspårningsgren"
+
+msgid "initialize sparse-checkout file to include only files at root"
+msgstr "initiera sparse-checkout-filen till att bara ta med filer i roten"
+
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "en URI för att hämta buntar innan de hämtas från ursprungsfjärr"
+
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [<flaggor>] [--] <arkiv> [<kat>]"
+
 msgid "Too many arguments."
 msgstr "För många argument."
 
@@ -4367,6 +4374,10 @@
 msgid "Remote branch %s not found in upstream %s"
 msgstr "Fjärrgrenen %s hittades inte i uppströmsarkivet %s"
 
+#, c-format
+msgid "Remote revision %s not found in upstream %s"
+msgstr "Fjärr-revisionen %s hittades inte i uppströmsarkivet %s"
+
 msgid "You appear to have cloned an empty repository."
 msgstr "Du verkar ha klonat ett tomt arkiv."
 
@@ -4540,7 +4551,7 @@
 msgstr "git commit-tree: misslyckades läsa"
 
 msgid ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -4550,7 +4561,7 @@
 "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
 "           [--] [<pathspec>...]"
 msgstr ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<läge>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<läge>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <incheckning> | --fixup [(amend|"
 "reword):]<incheckning>]\n"
 "           [-F <fil> | -m <medd>] [--reset-author] [--allow-empty]\n"
@@ -4791,7 +4802,7 @@
 #, c-format
 msgid "--author '%s' is not 'Name <email>' and matches no existing author"
 msgstr ""
-"--author '%s' är inte 'Namn <epost>' och motsvarar ingen befintlig författare"
+"--author ”%s” är inte ”Namn <epost>” och motsvarar ingen befintlig författare"
 
 #, c-format
 msgid "Invalid ignored mode '%s'"
@@ -5202,7 +5213,7 @@
 msgstr "skriva till standard in stöds inte"
 
 msgid "writing config blobs is not supported"
-msgstr "skriva konfigurations-blobbar stöds inte"
+msgstr "skriva konfigurations-blob:ar stöds inte"
 
 #, c-format
 msgid ""
@@ -5239,7 +5250,7 @@
 "section in \"git help worktree\" for details"
 msgstr ""
 "--worktree kan inte användas med flera arbetskataloger om inte\n"
-"konfigurationsutöknignen worktreeConfig har aktiverats. Läsa stycket\n"
+"konfigurationsutökningen worktreeConfig har aktiverats. Läsa stycket\n"
 "”KONFIGURATIONSFIL” i ”git help worktree” för detaljer"
 
 msgid "Other"
@@ -5325,7 +5336,7 @@
 msgstr "redigering av standard in stöds ej"
 
 msgid "editing blobs is not supported"
-msgstr "redigering av blobbar stöds ej"
+msgstr "redigering av blob:ar stöds ej"
 
 #, c-format
 msgid "cannot create configuration file %s"
@@ -5601,7 +5612,7 @@
 
 #, c-format
 msgid "more than two blobs given: '%s'"
-msgstr "mer än två blobbar angavs: ”%s”"
+msgstr "mer än två blob:ar angavs: ”%s”"
 
 #, c-format
 msgid "unhandled object '%s' given."
@@ -5760,7 +5771,7 @@
 msgstr "referera föräldrar som inte finns i fast-export-ström med objekt-id"
 
 msgid "show original object ids of blobs/commits"
-msgstr "visa ursprungliga objekt-id för blobbar/incheckningar"
+msgstr "visa ursprungliga objekt-id för blob:ar/incheckningar"
 
 msgid "label tags with mark ids"
 msgstr "märk taggar med märke-id"
@@ -5931,14 +5942,14 @@
 "Run 'git remote set-head %s %s' to follow the change, or set\n"
 "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
 "if you do not want to see this message. Specifically running\n"
-"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
-"until the remote changes HEAD to something else."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"will disable the warning until the remote changes HEAD to something else."
 msgstr ""
 "Kör ”git remote set-head %s %s” för att följa ändringen, eller sätt\n"
 "konfigurationsflaggan ”remote %s.followRemoteHEAD” till ett annat värde\n"
 "om du inte vill se det här meddelandet. Du kan specifikt inaktivera\n"
 "varningen till fjärren ändrar HEAD till något annat genom att köra\n"
-"”git config set remote %s.followRemoteHEAD %s”."
+"”git config set remote %s.followRemoteHEAD warn-if-not-branch-%s”."
 
 msgid "multiple branches detected, incompatible with --set-upstream"
 msgstr "flera grenar upptäcktes, inkompatibelt med --set-upstream"
@@ -6328,11 +6339,11 @@
 
 #, c-format
 msgid "%s: invalid reflog entry %s"
-msgstr "%s: ogiltig reflog-post %s"
+msgstr "%s: ogiltig referensloggpost %s"
 
 #, c-format
 msgid "Checking reflog %s->%s"
-msgstr "Kontrollerar reflog %s→%s"
+msgstr "Kontrollerar referenslogg %s→%s"
 
 #, c-format
 msgid "%s: invalid sha1 pointer %s"
@@ -6441,7 +6452,7 @@
 msgstr "gör indexobjekt till huvudnoder"
 
 msgid "make reflogs head nodes (default)"
-msgstr "gör refloggar till huvudnoder (standard)"
+msgstr "gör referensloggar till huvudnoder (standard)"
 
 msgid "also consider packs and alternate objects"
 msgstr "ta även hänsyn till paket och supplerande objekt"
@@ -6502,11 +6513,11 @@
 
 #, c-format
 msgid "fsmonitor: cookie_result '%d' != SEEN"
-msgstr "fsmonitor: cookie_result '%d' != SEEN"
+msgstr "fsmonitor: cookie_result ”%d” != SEEN"
 
 #, c-format
 msgid "could not start IPC thread pool on '%s'"
-msgstr "kunde inte starta IPC-trådpol på ”%s”"
+msgstr "kunde inte starta IPC-trådpool på ”%s”"
 
 msgid "could not start fsmonitor listener thread"
 msgstr "kunde inte starta fsmonitor-lyssnartråd"
@@ -6618,6 +6629,9 @@
 msgid "repack all other packs except the largest pack"
 msgstr "packa om alla paket förutom det största paketet"
 
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "paketprefix att lagra ett paket som innehåller bortrensade objekt"
+
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
 msgstr "misslyckades tolka värdet %s för gc.logExpiry"
@@ -7176,7 +7190,7 @@
 msgid ""
 "the '--no-[external-commands|aliases]' options can only be used with '--all'"
 msgstr ""
-"flaggorna '--no-[external-commands|aliases]' kan endast användas med ”--all”"
+"flaggorna ”--no-[external-commands|aliases]” kan endast användas med ”--all”"
 
 #, c-format
 msgid "usage: %s%s"
@@ -7407,6 +7421,10 @@
 msgstr "Kan inte gå tillbaka till arbetskatalogen (cwd)"
 
 #, c-format
+msgid "bad --pack_header: %s"
+msgstr "felaktig --pack_header: %s"
+
+#, c-format
 msgid "bad %s"
 msgstr "felaktig %s"
 
@@ -7977,7 +7995,7 @@
 msgstr "undertryck dublettposter"
 
 msgid "show sparse directories in the presence of a sparse index"
-msgstr "visa glesa kataloger när et glest index existerar"
+msgstr "visa glesa kataloger när ett glest index existerar"
 
 msgid ""
 "--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
@@ -8261,10 +8279,6 @@
 msgid "malformed input line: '%s'."
 msgstr "felaktig indatarad: ”%s”."
 
-#, c-format
-msgid "merging cannot continue; got unclean result of %d"
-msgstr "sammanslagning kan inte fortsätta; fick inte rent resultat från %d"
-
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<flaggor>] [<incheckning>...]"
 
@@ -8969,7 +8983,7 @@
 msgstr "misslyckades ta bort arbetskatalogen för ”git notes merge”"
 
 msgid "failed to read ref NOTES_MERGE_PARTIAL"
-msgstr "misslyckades läsa references NOTES_MERGE_PARTIAL"
+msgstr "misslyckades läsa referensen NOTES_MERGE_PARTIAL"
 
 msgid "could not find commit from NOTES_MERGE_PARTIAL."
 msgstr "kunde inte hitta incheckning från NOTES_MERGE_PARTIAL."
@@ -9081,6 +9095,13 @@
 "git pack-objects [<flaggor>] <basnamn> [< <reflista> | < <objektlista>]"
 
 #, c-format
+msgid "invalid --name-hash-version option: %d"
+msgstr "ogiltig flagga för --name-hash-version: %d"
+
+msgid "currently, --write-bitmap-index requires --name-hash-version=1"
+msgstr "--write-bitmap-index kräver för närvarande, --name-hash-version=1"
+
+#, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
@@ -9190,14 +9211,14 @@
 "value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
 "hash> <uri>' (got '%s')"
 msgstr ""
-"värdet på uploadpack.blobpackfileuri måste vara på formen '<objekt-hash> "
-"<paket-hash> <uri>' (fick '%s')"
+"värdet på uploadpack.blobpackfileuri måste vara på formen ”<objekt-hash> "
+"<paket-hash> <uri>” (fick ”%s”)"
 
 #, c-format
 msgid ""
 "object already configured in another uploadpack.blobpackfileuri (got '%s')"
 msgstr ""
-"objektet redan konfigurerat i et annat uploadpack.blobpackfileuri (fick '%s)"
+"objektet redan konfigurerat i ett annat uploadpack.blobpackfileuri (fick ”%s”"
 
 #, c-format
 msgid "could not get type of object %s in pack %s"
@@ -9401,6 +9422,10 @@
 msgstr ""
 "uteslut redan konfigurerade uploadpack.blobpackfileuri med detta protokoll"
 
+msgid "use the specified name-hash function to group similar objects"
+msgstr ""
+"använd den angivna namn-hash-funktionen för att gruppera liknande objekt"
+
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
 msgstr "deltakedjedjupet %d är för djupt, påtvingar %d"
@@ -10189,7 +10214,7 @@
 "Ange vilken gren du vill ombasera mot.\n"
 "Se git-rebase(1) för detaljer.\n"
 "\n"
-"    git rebase '<gren>'\n"
+"    git rebase ”<gren>”\n"
 "\n"
 
 #, c-format
@@ -10603,7 +10628,8 @@
 msgstr "hantera referensloggar för alla referenser"
 
 msgid "limits processing to reflogs from the current worktree only"
-msgstr "begränsar hantering av referensloggar till endast aktuell arbetskatalog"
+msgstr ""
+"begränsar hantering av referensloggar till endast aktuell arbetskatalog"
 
 #, c-format
 msgid "Marking reachable objects..."
@@ -10620,8 +10646,8 @@
 msgid "invalid ref format: %s"
 msgstr "felaktigt referensformat: %s"
 
-msgid "git refs migrate --ref-format=<format> [--dry-run]"
-msgstr "git refs migrate --ref-format=<format> [--dry-run]"
+msgid "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
+msgstr "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
 
 msgid "git refs verify [--strict] [--verbose]"
 msgstr "git refs verify [--strict] [--verbose]"
@@ -10632,6 +10658,9 @@
 msgid "perform a non-destructive dry-run"
 msgstr "utför ett icke-destruktiv testkörning"
 
+msgid "drop reflogs entirely during the migration"
+msgstr "kasta referensloggar helt under migreringen"
+
 msgid "missing --ref-format=<format>"
 msgstr "saknad --ref-format=<format>"
 
@@ -11091,8 +11120,14 @@
 msgid "be verbose; must be placed before a subcommand"
 msgstr "var pratsam; måste skrivas före ett underkommando"
 
-msgid "git repack [<options>]"
-msgstr "git repack [<flaggor>]"
+msgid ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
+msgstr ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<paket-namn>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
 
 msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
@@ -11166,6 +11201,12 @@
 msgid "pass --no-reuse-object to git-pack-objects"
 msgstr "sänd --no-reuse-object till git-pack-objects"
 
+msgid ""
+"specify the name hash version to use for grouping similar objects by path"
+msgstr ""
+"ange den namnhash-version som ska användas för att gruppera liknande objekt "
+"efter sökväg"
+
 msgid "do not run git-update-server-info"
 msgstr "kör inte git-update-server-info"
 
@@ -11214,9 +11255,6 @@
 msgid "write a multi-pack index of the resulting packs"
 msgstr "skriv ett flerpaketsindex för de skapade paketen"
 
-msgid "pack prefix to store a pack containing pruned objects"
-msgstr "paketprefix att lagra ett paket som innehåller bortrensade objekt"
-
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr "paketprefix att lagra ett paket som innehåller utfiltrerade objekt"
 
@@ -11433,9 +11471,6 @@
 msgid "need some commits to replay"
 msgstr "behöver några incheckningar för omspelning"
 
-msgid "--onto and --advance are incompatible"
-msgstr "--onto och --advance kan inte kombineras"
-
 msgid "all positive revisions given must be references"
 msgstr "alla positiva revisioner som anges måste vara referenser"
 
@@ -12020,7 +12055,7 @@
 msgstr "<n>[,<bas>]"
 
 msgid "show <n> most recent ref-log entries starting at base"
-msgstr "visa <n> nyaste refloggposter med början på bas"
+msgstr "visa <n> nyaste referensloggposter med början på bas"
 
 msgid "no branches given, and HEAD is not valid"
 msgstr "inga grenar angavs, och HEAD är inte giltigt"
@@ -12134,7 +12169,7 @@
 "directory '%s' contains untracked files, but is not in the sparse-checkout "
 "cone"
 msgstr ""
-"katalogen ”%s” innehåller ospårade filer, men är inte i området som ages i "
+"katalogen ”%s” innehåller ospårade filer, men är inte i området som anges i "
 "”sparse-checkout”"
 
 #, c-format
@@ -12726,7 +12761,7 @@
 
 #, c-format
 msgid "could not get submodule directory for '%s'"
-msgstr "kunde inte få tag i undermodulkatalog för ”%s”"
+msgstr "kunde inte få tag i undermodulskatalog för ”%s”"
 
 msgid "alternative anchor for relative paths"
 msgstr "alternativa ankare för relativa sökvägar"
@@ -12830,8 +12865,8 @@
 "Fetched in submodule path '%s', but it did not contain %s. Direct fetching "
 "of that commit failed."
 msgstr ""
-"Hämtade i undermodulssökvägen ”%s”, men den innehöll inte %s. Direkt "
-"hämtning av incheckningen misslyckades."
+"Hämtade i undermodulsökvägen ”%s”, men den innehöll inte %s. Direkt hämtning "
+"av incheckningen misslyckades."
 
 #, c-format
 msgid "could not initialize submodule at path '%s'"
@@ -13199,7 +13234,7 @@
 msgstr "ersätt taggen om den finns"
 
 msgid "create a reflog"
-msgstr "skapa en reflog"
+msgstr "skapa en referenslogg"
 
 msgid "Tag listing options"
 msgstr "Alternativ för listning av taggar"
@@ -13924,7 +13959,7 @@
 
 #, c-format
 msgid "'%s' does not look like a v2 or v3 bundle file"
-msgstr "'%s' ser inte ut som en v2- eller v3-bunt-fil"
+msgstr "”%s” ser inte ut som en v2- eller v3-bunt-fil"
 
 #, c-format
 msgid "unrecognized header: %s%s (%d)"
@@ -14058,6 +14093,9 @@
 msgid "Create an archive of files from a named tree"
 msgstr "Skapa ett arkiv över filer från ett namngivet träd"
 
+msgid "Download missing objects in a partial clone"
+msgstr "Hämta saknade objekt i en delvis kloning"
+
 msgid "Use binary search to find the commit that introduced a bug"
 msgstr "Använd binärsökning för att hitta ändringen som introducerade ett fel"
 
@@ -14164,7 +14202,7 @@
 msgstr "Jämför en träd med arbetskatalogen eller indexet"
 
 msgid "Compares the content and mode of blobs found via two tree objects"
-msgstr "Visar innehåll och läge för blobbar som hittats via två trädobjekt"
+msgstr "Visar innehåll och läge för blob:ar som hittats via två trädobjekt"
 
 msgid "Show changes using common diff tools"
 msgstr "Visa ändringar med vanliga diff-verktyg"
@@ -14996,19 +15034,19 @@
 
 #, c-format
 msgid "opendir('%s') failed"
-msgstr "opendir('%s') misslyckades"
+msgstr "opendir(”%s”) misslyckades"
 
 #, c-format
 msgid "lstat('%s') failed"
-msgstr "lstat('%s') misslyckades"
+msgstr "lstat(”%s”) misslyckades"
 
 #, c-format
 msgid "strbuf_readlink('%s') failed"
-msgstr "strbuf_readlink('%s') misslyckades"
+msgstr "strbuf_readlink(”%s”) misslyckades"
 
 #, c-format
 msgid "closedir('%s') failed"
-msgstr "closedir('%s') misslyckades"
+msgstr "closedir(”%s”) misslyckades"
 
 #, c-format
 msgid "[GLE %ld] unable to open for read '%ls'"
@@ -15335,7 +15373,7 @@
 
 #, c-format
 msgid "unable to resolve config blob '%s'"
-msgstr "kan inte slå upp konfigurerings-blobben ”%s”"
+msgstr "kan inte slå upp konfigurerings-blob:en ”%s”"
 
 msgid "unable to parse command-line config"
 msgstr "kan inte tolka kommandoradskonfiguration"
@@ -15968,6 +16006,12 @@
 msgid "invalid regex given to -I: '%s'"
 msgstr "ogiltigt reguljärt uttryck angavs för -I: ”%s”"
 
+msgid "-G requires a non-empty argument"
+msgstr "-G kräver ett icke-tomt argument"
+
+msgid "-S requires a non-empty argument"
+msgstr "-S kräver ett icke-tomt argument"
+
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr "misslyckades tolka argument till flaggan --submodule: ”%s”"
@@ -16080,7 +16124,7 @@
 "do not munge pathnames and use NULs as output field terminators in --raw or "
 "--numstat"
 msgstr ""
-"skriv inte om sökvägsnamn och använd NUL-tecken som fältseparerare i --raw "
+"skriv inte om sökvägsnamn och använd NUL-tecken som fältavdelare i --raw "
 "eller --numstat"
 
 msgid "<prefix>"
@@ -16495,7 +16539,7 @@
 msgstr "har redan %s (%s)"
 
 msgid "fetch-pack: unable to fork off sideband demultiplexer"
-msgstr "fetch-patch: kan inte grena (fork) av sidbandsmultiplexare"
+msgstr "fetch-patch: kan inte grena (fork) av sidbands-avmultiplexare"
 
 msgid "protocol error: bad pack header"
 msgstr "protokollfel: felaktigt packhuvud"
@@ -16689,7 +16733,7 @@
 "”git help -a” och ”git help -g” visar tillgängliga underkommandon och\n"
 "några konceptvägledningar. Se ”git help <kommando>” eller ”git help\n"
 "<koncept>” för att läsa mer om specifika underkommandon och koncept.\n"
-"See ”git help git” för en översikt över systemet."
+"Se ”git help git” för en översikt över systemet."
 
 #, c-format
 msgid "unsupported command listing type '%s'"
@@ -17020,7 +17064,7 @@
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
 msgstr ""
-"argumentet till --packfile måste vara ett giltigt hashvärde (fick '%s')"
+"argumentet till --packfile måste vara ett giltigt hashvärde (fick ”%s”)"
 
 #, c-format
 msgid "negative value for http.postBuffer; defaulting to %d"
@@ -17056,7 +17100,7 @@
 "  asked for: %s\n"
 "   redirect: %s"
 msgstr ""
-"kan inte uppdatera urlbas från omdirigerin:\n"
+"kan inte uppdatera urlbas från omdirigering:\n"
 "        bad om: %s\n"
 "  omdirigering: %s"
 
@@ -17914,7 +17958,7 @@
 msgstr "multi-pack-index innehåller 64-bitars offset, men off_t är för liten"
 
 msgid "multi-pack-index large offset out of bounds"
-msgstr "stort offset för mult-pack-index utanför gränsen"
+msgstr "stort offset för multi-pack-index utanför gränsen"
 
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr "multi-pack-indexfilen finns, men kunde inte tolkas"
@@ -17985,7 +18029,7 @@
 
 #, c-format
 msgid "Bad notes.rewriteMode value: '%s'"
-msgstr "Felaktigt värde för notes.rewriteMode: '%s'"
+msgstr "Felaktigt värde för notes.rewriteMode: ”%s”"
 
 #, c-format
 msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
@@ -18135,6 +18179,10 @@
 msgstr "kan inte skriva filen %s"
 
 #, c-format
+msgid "unable to write repeatedly vanishing file %s"
+msgstr "kan inte skriva till filen %s som hela tiden försvinner"
+
+#, c-format
 msgid "unable to set permission to '%s'"
 msgstr "kan inte sätta behörigheten till ”%s”"
 
@@ -18538,7 +18586,8 @@
 
 #, c-format
 msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
-msgstr "pseudosammanslagningsindex utanför intervallet (%<PRIu32> ≥ %<PRIuMAX>)"
+msgstr ""
+"pseudosammanslagningsindex utanför intervallet (%<PRIu32> ≥ %<PRIuMAX>)"
 
 #, c-format
 msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
@@ -18694,6 +18743,52 @@
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "okänd icke-ascii-flagga i strängen: ”%s”"
 
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the long form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[=<%s>]"
+msgstr "[=<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the short form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[<%s>]"
+msgstr "[<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string stands for a
+#. value given to a command line option, and "<>" is there
+#. as a convention to signal that it is a placeholder
+#. (i.e. the user should substitute it with the real value).
+#. If your language uses a different convention, you can
+#. change "<%s>" part to match yours, e.g. it might use
+#. "|%s|" instead, or if the alphabet is different enough it
+#. may use "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid " <%s>"
+msgstr " <%s>"
+
 msgid "..."
 msgstr "..."
 
@@ -18779,6 +18874,21 @@
 msgstr "misslyckades tolka %s"
 
 #, c-format
+msgid "failed to walk children of tree %s: not found"
+msgstr "misslyckades traversera löven i trädet %s: hittades inte"
+
+#, c-format
+msgid "failed to find object %s"
+msgstr "misslyckades hitta objektet %s"
+
+#, c-format
+msgid "failed to find tag %s"
+msgstr "misslyckades hitta taggen %s"
+
+msgid "failed to setup revision walk"
+msgstr "misslyckades starta revisionstraversering"
+
+#, c-format
 msgid "Could not make %s writable by group"
 msgstr "Kunde inte göra %s skrivbar för gruppen"
 
@@ -18923,6 +19033,22 @@
 msgid "could not fetch %s from promisor remote"
 msgstr "kunde inte hämta %s från kontraktsfjärr"
 
+#, c-format
+msgid "known remote named '%s' but with url '%s' instead of '%s'"
+msgstr "känd fjärr som heter ”%s” med med url:en ”%s” istället för ”%s”"
+
+#, c-format
+msgid "unknown '%s' value for '%s' config option"
+msgstr "okänt värde ”%s” för inställningen ”%s”"
+
+#, c-format
+msgid "unknown element '%s' from remote info"
+msgstr "okänt värde ”%s” från fjärrinformation"
+
+#, c-format
+msgid "accepted promisor remote '%s' not found"
+msgstr "godkänd kontraktsfjärr ”%s” hittades inte"
+
 msgid "object-info: expected flush after arguments"
 msgstr "object-info: förväntade ”flush” efter argument"
 
@@ -19248,7 +19374,7 @@
 "        enrads, om inget incheckningsmeddelande angavs); använd\n"
 "        -c <incheckning> för att skriva om meddelandet.\n"
 "u, update-ref <ref> = spåra en platshållare för <ref> att uppdatera\n"
-"                      till denna position bland nya inchecknngar.\n"
+"                      till denna position bland nya incheckningar.\n"
 "                      <ref> uppdateras i slutet av ombaseringen.\n"
 "\n"
 "Du kan byta ordning på raderna; de utförs uppifrån och ned.\n"
@@ -19616,7 +19742,7 @@
 msgstr "vägrar uppdatera referens med trasigt namn ”%s”"
 
 msgid "refusing to force and skip creation of reflog"
-msgstr "vägrar att tvinga och hoppa över skapande av reflogg"
+msgstr "vägrar att tvinga och hoppa över skapande av referenslogg"
 
 #, c-format
 msgid "update_ref failed for ref '%s': %s"
@@ -19749,6 +19875,14 @@
 msgstr "felaktig referensspecifikation: ”%s”"
 
 #, c-format
+msgid "pattern '%s' has no '*'"
+msgstr "mönstret ”%s” innehåller ingen ”*”"
+
+#, c-format
+msgid "replacement '%s' has no '*'"
+msgstr "ersättningen ”%s” innehåller ingen ”*”"
+
+#, c-format
 msgid "invalid quoting in push-option value: '%s'"
 msgstr "felaktig citering på värde för push-option: ”%s”"
 
@@ -19867,6 +20001,28 @@
 msgstr "remote-curl: okänt kommando ”%s” från git"
 
 #, c-format
+msgid ""
+"reading remote from \"%s/%s\", which is nominated for removal.\n"
+"\n"
+"If you still use the \"remotes/\" directory it is recommended to\n"
+"migrate to config-based remotes:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"If you cannot, please let us know why you still need to use it by\n"
+"sending an e-mail to <git@vger.kernel.org>."
+msgstr ""
+"läser fjärren från ”%s/%s”, som har nominerats för borttagning.\n"
+"\n"
+"Om du fortfarande använder ”remotes/”-katalogen rekommenderas du\n"
+"migrera till konfigurationsbaserade fjärrar:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"Om du inte kan det, berätta för oss varför du fortfarande behöver\n"
+"använda det på e-post till <git@vger.kernel.org>."
+
+#, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
 msgstr "konfigurerad kortform för fjärr kan inte börja med ”/”: %s"
 
@@ -19901,14 +20057,6 @@
 msgstr "%s spårar både %s och %s"
 
 #, c-format
-msgid "key '%s' of pattern had no '*'"
-msgstr "nyckeln ”%s” i mönstret innehåller ingen ”*”"
-
-#, c-format
-msgid "value '%s' of pattern has no '*'"
-msgstr "värdet ”%s” i mönstret innehåller ingen ”*”"
-
-#, c-format
 msgid "src refspec %s does not match any"
 msgstr "käll-referensspecifikationen %s motsvarar ingen"
 
@@ -21798,6 +21946,27 @@
 msgid "number of entries in the cache tree to invalidate (default 0)"
 msgstr "antal poster i cacheträdet att ogiltigförklara (förval är 0)"
 
+msgid "test-tool path-walk <options> -- <revision-options>"
+msgstr "test-tool path-walk <flaggor> -- <revision-flaggor>"
+
+msgid "toggle inclusion of blob objects"
+msgstr "växla om blob-objekt ska vara med eller inte"
+
+msgid "toggle inclusion of commit objects"
+msgstr "växla om incheckningsobjekt ska vara med eller inte"
+
+msgid "toggle inclusion of tag objects"
+msgstr "växla om taggobjekt ska vara med eller inte"
+
+msgid "toggle inclusion of tree objects"
+msgstr "växla om trädobjekt ska vara med eller inte"
+
+msgid "toggle pruning of uninteresting paths"
+msgstr "växla bortrensning av ointressanta sökvägar"
+
+msgid "read a pattern list over stdin"
+msgstr "läs en mönsterlista från standard in"
+
 #, c-format
 msgid "commit %s is not marked reachable"
 msgstr "incheckning %s är inte märkt nåbar"
@@ -22431,6 +22600,10 @@
 msgid "warning: "
 msgstr "varning: "
 
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "uname() misslyckades med felet ”%s” (%d)\n"
+
 msgid "Fetching objects"
 msgstr "Hämtar objekt"
 
@@ -23265,7 +23438,7 @@
 
 #, perl-format
 msgid "Server does not support STARTTLS! %s"
-msgstr "Servern stöder inte SMARTTLS! %s"
+msgstr "Servern stöder inte STARTTLS! %s"
 
 #, perl-format
 msgid "STARTTLS failed! %s"
diff --git a/po/tr.po b/po/tr.po
index 1bc4345..4ed91cb 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -96,8 +96,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: 2024-12-23 18:57+0000\n"
-"PO-Revision-Date: 2025-01-01 15:00+0300\n"
+"POT-Creation-Date: 2025-03-11 15:01+0300\n"
+"PO-Revision-Date: 2025-03-11 15:00+0300\n"
 "Last-Translator: Emir SARI <emir_sari@icloud.com>\n"
 "Language-Team: Turkish (https://github.com/bitigchi/git-po/)\n"
 "Language: tr\n"
@@ -2408,6 +2408,18 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: Floş bekleniyordu"
 
+msgid "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+msgstr "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+
+msgid "problem loading sparse-checkout"
+msgstr "aralıklı çıkış yüklenirken sorun"
+
+msgid "Minimum number of objects to request at a time"
+msgstr "Bir kerede istenecek en çok nesne sayısı"
+
+msgid "Restrict the missing objects to the current sparse-checkout"
+msgstr "Eksik nesneleri geçerli aralıklı çıkışa sınırla"
+
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
 "checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
@@ -3149,10 +3161,6 @@
 msgid "git version:\n"
 msgstr "git sürümü:\n"
 
-#, c-format
-msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() '%s' hatasını verip çıktı (%d)\n"
-
 msgid "compiler info: "
 msgstr "derleyici bilgisi: "
 
@@ -4158,125 +4166,6 @@
 "clean.requireForce 'true' olarak ayarlı ve -f verilmedi; temizlik "
 "reddediliyor"
 
-msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<seçenekler>] [--] <depo> [<dizin>]"
-
-msgid "don't clone shallow repository"
-msgstr "sığ depoyu klonlama"
-
-msgid "don't create a checkout"
-msgstr "çıkış yapma!"
-
-msgid "create a bare repository"
-msgstr "çıplak bir depo oluştur"
-
-msgid "create a mirror repository (implies --bare)"
-msgstr "bir yansı depo oluştur (--bare ima eder)"
-
-msgid "to clone from a local repository"
-msgstr "bir yerel depodan klonla"
-
-msgid "don't use local hardlinks, always copy"
-msgstr "yerel sabit bağları kullanma, her zaman kopyala"
-
-msgid "setup as shared repository"
-msgstr "paylaşılan depo ayarla"
-
-msgid "pathspec"
-msgstr "yol belirteci"
-
-msgid "initialize submodules in the clone"
-msgstr "klon içerisindeki altmodülleri ilklendir"
-
-msgid "number of submodules cloned in parallel"
-msgstr "paralelde klonlanan altmodüllerin sayısı"
-
-msgid "template-directory"
-msgstr "şablon dizini"
-
-msgid "directory from which templates will be used"
-msgstr "şablonların kullanılacağı dizin"
-
-msgid "reference repository"
-msgstr "başvuru deposu"
-
-msgid "use --reference only while cloning"
-msgstr "--reference'ı yalnızca klonlarken kullan"
-
-msgid "name"
-msgstr "ad"
-
-msgid "use <name> instead of 'origin' to track upstream"
-msgstr "üstkaynağı izlemek için 'origin' yerine <ad> kullan"
-
-msgid "checkout <branch> instead of the remote's HEAD"
-msgstr "uzak konumun HEAD'i yerine <dal>'ı çıkış yap"
-
-msgid "path to git-upload-pack on the remote"
-msgstr "uzak konumdaki git-upload-pack'e olan yol"
-
-msgid "depth"
-msgstr "derinlik"
-
-msgid "create a shallow clone of that depth"
-msgstr "verilen derinlikte sığ bir depo oluştur"
-
-msgid "create a shallow clone since a specific time"
-msgstr "verilen zamandan sonrasını içeren bir sığ depo oluştur"
-
-msgid "ref"
-msgstr "başvuru"
-
-msgid "deepen history of shallow clone, excluding ref"
-msgstr "başvuru hariç tutarak sığ klonun geçmişini derinleştir"
-
-msgid "clone only one branch, HEAD or --branch"
-msgstr "yalnızca bir dal klonla, HEAD veya --branch"
-
-msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr "etiket klonlama ve sonraki getirmeler de onları izlemesin"
-
-msgid "any cloned submodules will be shallow"
-msgstr "klonlanan altmodüller sığ olacak"
-
-msgid "gitdir"
-msgstr "git dizini"
-
-msgid "separate git dir from working tree"
-msgstr "git dizinini çalışma ağacından ayır"
-
-msgid "specify the reference format to use"
-msgstr "kullanılacak başvuru biçimini belirt"
-
-msgid "key=value"
-msgstr "anahtar=değer"
-
-msgid "set config inside the new repository"
-msgstr "yapılandırmayı yeni deponun içinde ayarla"
-
-msgid "server-specific"
-msgstr "sunucuya özel"
-
-msgid "option to transmit"
-msgstr "iletme seçeneği"
-
-msgid "apply partial clone filters to submodules"
-msgstr "altmodüllere kısımsal klon süzgeçlerini uygula"
-
-msgid "any cloned submodules will use their remote-tracking branch"
-msgstr "klonlanan herhangi bir altmodül kendi uzak izleme dallarını kullanacak"
-
-msgid "initialize sparse-checkout file to include only files at root"
-msgstr ""
-"sparse-checkout dosyasını yalnızca kökteki dosyaları içerecek biçimde "
-"ilklendir"
-
-msgid "uri"
-msgstr "uri"
-
-msgid "a URI for downloading bundles before fetching from origin remote"
-msgstr "uzak konum kökeninden getirmeden önce demetleri indirmek için bir URI"
-
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info: '%s' için alternatif eklenemedi: %s\n"
@@ -4338,10 +4227,6 @@
 "Neyin çıkış yapılıp yapılmadığını 'git status' ile inceleyebilir\n"
 "ve 'git restore --source=HEAD' ile yeniden deneyebilirsiniz.\n"
 
-#, c-format
-msgid "Could not find remote branch %s to clone."
-msgstr "Klonlanacak %s uzak dal bulunamadı."
-
 msgid "remote did not send all necessary objects"
 msgstr "uzak konum gereken tüm nesneleri göndermedi"
 
@@ -4367,6 +4252,128 @@
 msgid "cannot unlink temporary alternates file"
 msgstr "geçici alternatifler dosyasının bağlantısı kesilemiyor"
 
+msgid "don't clone shallow repository"
+msgstr "sığ depoyu klonlama"
+
+msgid "don't create a checkout"
+msgstr "çıkış yapma!"
+
+msgid "create a bare repository"
+msgstr "çıplak bir depo oluştur"
+
+msgid "create a mirror repository (implies --bare)"
+msgstr "bir yansı depo oluştur (--bare ima eder)"
+
+msgid "to clone from a local repository"
+msgstr "bir yerel depodan klonla"
+
+msgid "don't use local hardlinks, always copy"
+msgstr "yerel sabit bağları kullanma, her zaman kopyala"
+
+msgid "setup as shared repository"
+msgstr "paylaşılan depo ayarla"
+
+msgid "pathspec"
+msgstr "yol belirteci"
+
+msgid "initialize submodules in the clone"
+msgstr "klon içerisindeki altmodülleri ilklendir"
+
+msgid "number of submodules cloned in parallel"
+msgstr "paralelde klonlanan altmodüllerin sayısı"
+
+msgid "template-directory"
+msgstr "şablon dizini"
+
+msgid "directory from which templates will be used"
+msgstr "şablonların kullanılacağı dizin"
+
+msgid "reference repository"
+msgstr "başvuru deposu"
+
+msgid "use --reference only while cloning"
+msgstr "--reference'ı yalnızca klonlarken kullan"
+
+msgid "name"
+msgstr "ad"
+
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "üstkaynağı izlemek için 'origin' yerine <ad> kullan"
+
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "uzak konumun HEAD'i yerine <dal>'ı çıkış yap"
+
+msgid "clone single revision <rev> and check out"
+msgstr "tek revizyonlu <rev>'i klonla ve çıkış yap"
+
+msgid "path to git-upload-pack on the remote"
+msgstr "uzak konumdaki git-upload-pack'e olan yol"
+
+msgid "depth"
+msgstr "derinlik"
+
+msgid "create a shallow clone of that depth"
+msgstr "verilen derinlikte sığ bir depo oluştur"
+
+msgid "create a shallow clone since a specific time"
+msgstr "verilen zamandan sonrasını içeren bir sığ depo oluştur"
+
+msgid "ref"
+msgstr "başvuru"
+
+msgid "deepen history of shallow clone, excluding ref"
+msgstr "başvuru hariç tutarak sığ klonun geçmişini derinleştir"
+
+msgid "clone only one branch, HEAD or --branch"
+msgstr "yalnızca bir dal klonla, HEAD veya --branch"
+
+msgid "clone tags, and make later fetches not to follow them"
+msgstr "etiketleri klonla ve sonraki getirmelerin onları izlememesini sağla"
+
+msgid "any cloned submodules will be shallow"
+msgstr "klonlanan altmodüller sığ olacak"
+
+msgid "gitdir"
+msgstr "git dizini"
+
+msgid "separate git dir from working tree"
+msgstr "git dizinini çalışma ağacından ayır"
+
+msgid "specify the reference format to use"
+msgstr "kullanılacak başvuru biçimini belirt"
+
+msgid "key=value"
+msgstr "anahtar=değer"
+
+msgid "set config inside the new repository"
+msgstr "yapılandırmayı yeni deponun içinde ayarla"
+
+msgid "server-specific"
+msgstr "sunucuya özel"
+
+msgid "option to transmit"
+msgstr "iletme seçeneği"
+
+msgid "apply partial clone filters to submodules"
+msgstr "altmodüllere kısımsal klon süzgeçlerini uygula"
+
+msgid "any cloned submodules will use their remote-tracking branch"
+msgstr "klonlanan herhangi bir altmodül kendi uzak izleme dallarını kullanacak"
+
+msgid "initialize sparse-checkout file to include only files at root"
+msgstr ""
+"sparse-checkout dosyasını yalnızca kökteki dosyaları içerecek biçimde "
+"ilklendir"
+
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "uzak konum kökeninden getirmeden önce demetleri indirmek için bir URI"
+
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [<seçenekler>] [--] <depo> [<dizin>]"
+
 msgid "Too many arguments."
 msgstr "Çok fazla argüman."
 
@@ -4465,6 +4472,10 @@
 msgid "Remote branch %s not found in upstream %s"
 msgstr "%s uzak dalı %s üstkaynağında bulunamadı"
 
+#, c-format
+msgid "Remote revision %s not found in upstream %s"
+msgstr "%s uzak revizyonu, %s üstkaynağında bulunamadı"
+
 msgid "You appear to have cloned an empty repository."
 msgstr "Boş bir depoyu klonlamış görünüyorsunuz."
 
@@ -4641,7 +4652,7 @@
 msgstr "git commit-tree: okunamadı"
 
 msgid ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -4651,11 +4662,11 @@
 "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
 "           [--] [<pathspec>...]"
 msgstr ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<kip>] [--amend]\n"
-"           [--dry-run] [(-c | -C | --squash) <işleme> | --fixup\n"
-"           [(amend|reword):]<işleme>]           [-F <dosya> | -m <ileti>] [--"
-"reset-author] [--allow-empty]\n"
-"           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<kip>]] [--amend]\n"
+"           [--dry-run] [(-c | -C | --squash) <işleme> |\n"
+"           --fixup [(amend|reword):]<işleme>]\n"
+"           [-F <dosya> | -m <ileti>] [--reset-author] [--allow-empty]\n"
+"           [--allow-empty-message] [--no-verify] [-e] [--author=<yazar>]\n"
 "           [--date=<tarih>] [--cleanup=<kip>] [--[no-]status]\n"
 "           [-i | -o] [--pathspec-from-file=<dosya> [--pathspec-file-nul]]\n"
 "           [(--trailer <jeton>[(=|:)<değer>])...] [-S[<anahtar-kimliği>]]\n"
@@ -6044,15 +6055,15 @@
 "Run 'git remote set-head %s %s' to follow the change, or set\n"
 "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
 "if you do not want to see this message. Specifically running\n"
-"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
-"until the remote changes HEAD to something else."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"will disable the warning until the remote changes HEAD to something else."
 msgstr ""
 "Değişikliği izlemek için 'git remote set-head %s %s' yapın veya\n"
 "'remote.%s.followRemoteHEAD' yapılandırma seçeneğini başka bir\n"
 "değere ayarlayın (bu iletiyi görmek istemiyorsanız). Özellikle\n"
-"'git config set remote.%s.followRemoteHEAD %s' komutunu çalıştırmak\n"
-"uyarıyı HEAD'e veya başka bir şeye uzaktan değişiklik olana dek\n"
-"devre dışı bırakır."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"komutunu çalıştırmak, uyarıyı HEAD'e veya başka bir şeye uzaktan\n"
+"değişiklik olana dek devre dışı bırakır."
 
 msgid "multiple branches detected, incompatible with --set-upstream"
 msgstr "birden çok dal algılandı, --set-upstream ile uyumsuz"
@@ -6729,6 +6740,9 @@
 msgid "repack all other packs except the largest pack"
 msgstr "en büyük paket dışındaki diğer tüm paketleri yeniden paketle"
 
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "budanan nesneler içeren paketi depolamak için paket öneki"
+
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
 msgstr "gc.logExpiry değeri %s ayrıştırılamadı"
@@ -7526,6 +7540,10 @@
 msgstr "Geçerli çalışma dizinine geri gelinemiyor"
 
 #, c-format
+msgid "bad --pack_header: %s"
+msgstr "hatalı --pack_header: %s"
+
+#, c-format
 msgid "bad %s"
 msgstr "hatalı %s"
 
@@ -8384,10 +8402,6 @@
 msgid "malformed input line: '%s'."
 msgstr "hatalı oluşturulmuş girdi satırı: '%s'."
 
-#, c-format
-msgid "merging cannot continue; got unclean result of %d"
-msgstr "birleştirme sürdürülemiyor; %d için temiz olmayan sonuçlar alındı"
-
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<seçenekler>] [<işleme>...]"
 
@@ -9202,6 +9216,13 @@
 "listesi>]"
 
 #, c-format
+msgid "invalid --name-hash-version option: %d"
+msgstr "geçersiz --name-hash-version seçeneği: %d"
+
+msgid "currently, --write-bitmap-index requires --name-hash-version=1"
+msgstr "şu anda --write-bitmap-index, --name-hash-version=1 gerektiriyor"
+
+#, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
@@ -9526,6 +9547,9 @@
 "bu protokol ile herhangi bir yapılandırılmış uploadpack.blobpackfileuri "
 "ögesini hariç tut"
 
+msgid "use the specified name-hash function to group similar objects"
+msgstr "benzer nesneleri gruplamak için belirtilen name-hash işlevini kullan"
+
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
 msgstr "delta zincir derinliği %d çok derin, %d zorlanıyor"
@@ -10756,8 +10780,8 @@
 msgid "invalid ref format: %s"
 msgstr "geçersiz başvuru biçimi: %s"
 
-msgid "git refs migrate --ref-format=<format> [--dry-run]"
-msgstr "git refs migrate --ref-format=<biçim> [--dry-run]"
+msgid "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
+msgstr "git refs migrate --ref-format=<biçim> [--no-reflog] [--dry-run]"
 
 msgid "git refs verify [--strict] [--verbose]"
 msgstr "git refs verify [--strict] [--verbose]"
@@ -10768,6 +10792,9 @@
 msgid "perform a non-destructive dry-run"
 msgstr "yıkıcı olmayan bir deneme gerçekleştir"
 
+msgid "drop reflogs entirely during the migration"
+msgstr "göç sırasında başvuru günlüklerini tümüyle bırak"
+
 msgid "missing --ref-format=<format>"
 msgstr "--ref-format=<biçim> eksik"
 
@@ -11234,8 +11261,14 @@
 msgid "be verbose; must be placed before a subcommand"
 msgstr "ayrıntılı anlat; bir altkomuttan önce yerleştirilmelidir"
 
-msgid "git repack [<options>]"
-msgstr "git repack [<seçenekler>]"
+msgid ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
+msgstr ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<paket-adı>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
 
 msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
@@ -11309,6 +11342,11 @@
 msgid "pass --no-reuse-object to git-pack-objects"
 msgstr "'git-pack-objects'e --no-reuse-object geçir"
 
+msgid ""
+"specify the name hash version to use for grouping similar objects by path"
+msgstr ""
+"benzer nesneleri yola göre gruplamada kullanılacak name-hash sürümünü belirt"
+
 msgid "do not run git-update-server-info"
 msgstr "'git-update-server-info' çalıştırma"
 
@@ -11357,9 +11395,6 @@
 msgid "write a multi-pack index of the resulting packs"
 msgstr "ortaya çıkan paketlerin bir çoklu paket indeksini yaz"
 
-msgid "pack prefix to store a pack containing pruned objects"
-msgstr "budanan nesneler içeren paketi depolamak için paket öneki"
-
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr "süzülen nesneler içeren paketi depolamak için paket öneki"
 
@@ -11576,9 +11611,6 @@
 msgid "need some commits to replay"
 msgstr "yeniden oynatmak için birkaç işleme gerekli"
 
-msgid "--onto and --advance are incompatible"
-msgstr "--onto ve --advance birbiriyle uyumsuz"
-
 msgid "all positive revisions given must be references"
 msgstr "verilen tüm pozitif revizyonlar, başvuru olmalı"
 
@@ -14200,6 +14232,9 @@
 msgid "Create an archive of files from a named tree"
 msgstr "Ad verilmiş ağaçtan bir dosyalar arşivi oluştur"
 
+msgid "Download missing objects in a partial clone"
+msgstr "Eksik nesneleri kısımsal bir klonda indir"
+
 msgid "Use binary search to find the commit that introduced a bug"
 msgstr "Hatalara neden olan işlemeyi bulmada ikili arama kullan"
 
@@ -16111,6 +16146,12 @@
 msgid "invalid regex given to -I: '%s'"
 msgstr "-I'ya geçersiz düzenli ifade verildi: '%s'"
 
+msgid "-G requires a non-empty argument"
+msgstr "-G, boş olmayan bir argüman gerektiriyor"
+
+msgid "-S requires a non-empty argument"
+msgstr "-S, boş olmayan bir argüman gerektiriyor"
+
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr "--submodule seçenek parametresi ayrıştırılamadı: '%s'"
@@ -18290,6 +18331,10 @@
 msgstr "%s dosyası yazılamıyor"
 
 #, c-format
+msgid "unable to write repeatedly vanishing file %s"
+msgstr "sürekli olarak kaybolan %s dosyası yazılamıyor"
+
+#, c-format
 msgid "unable to set permission to '%s'"
 msgstr "'%s' ögesine izin ayarlanamıyor"
 
@@ -18851,6 +18896,52 @@
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "dizi içinde bilinmeyen ascii dışı seçenek: '%s'"
 
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the long form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[=<%s>]"
+msgstr "[=<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the short form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[<%s>]"
+msgstr "[<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string stands for a
+#. value given to a command line option, and "<>" is there
+#. as a convention to signal that it is a placeholder
+#. (i.e. the user should substitute it with the real value).
+#. If your language uses a different convention, you can
+#. change "<%s>" part to match yours, e.g. it might use
+#. "|%s|" instead, or if the alphabet is different enough it
+#. may use "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid " <%s>"
+msgstr " <%s>"
+
 msgid "..."
 msgstr "..."
 
@@ -18937,6 +19028,21 @@
 msgstr "%s ayrıştırılamadı"
 
 #, c-format
+msgid "failed to walk children of tree %s: not found"
+msgstr "%s ağacının alt ögeleri yürütülemedi: bulunamadı"
+
+#, c-format
+msgid "failed to find object %s"
+msgstr "%s nesnesi bulunamadı"
+
+#, c-format
+msgid "failed to find tag %s"
+msgstr "%s etiketi bulunamadı"
+
+msgid "failed to setup revision walk"
+msgstr "revizyon yürüyüşü ayarlanamadı"
+
+#, c-format
 msgid "Could not make %s writable by group"
 msgstr "%s grup ile yazılabilir yapılamadı"
 
@@ -19079,6 +19185,22 @@
 msgid "could not fetch %s from promisor remote"
 msgstr "vaatçi uzak konumundan %s getirilemedi"
 
+#, c-format
+msgid "known remote named '%s' but with url '%s' instead of '%s'"
+msgstr "bilinen uzak konum adı '%s'; ancak url'si '%s'; '%s' olmalı"
+
+#, c-format
+msgid "unknown '%s' value for '%s' config option"
+msgstr "'%s' yapılandırma seçeneği için bilinmeyen değer: '%s'"
+
+#, c-format
+msgid "unknown element '%s' from remote info"
+msgstr "uzak bilgiden bilinmeyen öge '%s'"
+
+#, c-format
+msgid "accepted promisor remote '%s' not found"
+msgstr "kabul edilmiş vaatçi uzak konum '%s' bulunamadı"
+
 msgid "object-info: expected flush after arguments"
 msgstr "object-info: argümanlardan sonra floş bekleniyordu"
 
@@ -19902,6 +20024,14 @@
 msgstr "geçersiz başvuru belirteci '%s'"
 
 #, c-format
+msgid "pattern '%s' has no '*'"
+msgstr "'%s' dizgisinde '*' yok"
+
+#, c-format
+msgid "replacement '%s' has no '*'"
+msgstr "'%s' yedeğinde '*' yok"
+
+#, c-format
 msgid "invalid quoting in push-option value: '%s'"
 msgstr "push-option değerinde geçersiz tırnak içine alım: '%s'"
 
@@ -20021,6 +20151,31 @@
 msgstr "remote-curl: git'ten bilinmeyen komut '%s'"
 
 #, c-format
+msgid ""
+"reading remote from \"%s/%s\", which is nominated for removal.\n"
+"\n"
+"If you still use the \"remotes/\" directory it is recommended to\n"
+"migrate to config-based remotes:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"If you cannot, please let us know why you still need to use it by\n"
+"sending an e-mail to <git@vger.kernel.org>."
+msgstr ""
+"Kaldırma için aday gösterilmiş \"%s/%s\" konumundan\n"
+"uzak konum okunuyor.\n"
+"\n"
+"Eğer hâlâ \"remotes\" dizinini kullanıyorsanız\n"
+"yapılandırma tabanlı uzak konumlara geçiş yapmanız\n"
+"önerilir:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"Eğer geçiş yapamıyorsanız bunu neden kullandığınıza\n"
+"dair bir iletiyi <git@vger.kernel.org> adresine\n"
+"gönderin."
+
+#, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
 msgstr "uzak konum yapılandırma stenografisi '/' ile başlayamaz: %s"
 
@@ -20055,14 +20210,6 @@
 msgstr "%s hem %s hem %s ögelerini izler"
 
 #, c-format
-msgid "key '%s' of pattern had no '*'"
-msgstr "dizginin '%s' anahtarında '*' yoktu"
-
-#, c-format
-msgid "value '%s' of pattern has no '*'"
-msgstr "dizginin '%s' değerinde '*' yok"
-
-#, c-format
 msgid "src refspec %s does not match any"
 msgstr "kaynak başvuru belirteci %s başka hiçbir şeyle eşleşmiyor"
 
@@ -21948,6 +22095,27 @@
 msgid "number of entries in the cache tree to invalidate (default 0)"
 msgstr "önbellek ağacındaki geçersizleştirilecek girdi sayısı (öntanımlı 0)"
 
+msgid "test-tool path-walk <options> -- <revision-options>"
+msgstr "test-tool path-walk <seçenekler> -- <revizyon-seçenekleri>"
+
+msgid "toggle inclusion of blob objects"
+msgstr "ikili nesnelerin içerilmesini aç/kapat"
+
+msgid "toggle inclusion of commit objects"
+msgstr "işleme nesnelerinin içerilmesini aç/kapat"
+
+msgid "toggle inclusion of tag objects"
+msgstr "etiket nesnelerinin içerilmesini aç/kapat"
+
+msgid "toggle inclusion of tree objects"
+msgstr "ağaç nesnelerinin içerilmesini aç/kapat"
+
+msgid "toggle pruning of uninteresting paths"
+msgstr "ilgisiz yolların budanmasını aç/kapat"
+
+msgid "read a pattern list over stdin"
+msgstr "stdin'den bir dizgi listesi oku"
+
 #, c-format
 msgid "commit %s is not marked reachable"
 msgstr "%s işlemesi ulaşılabilir olarak imlenmedi"
@@ -22575,6 +22743,10 @@
 msgid "warning: "
 msgstr "uyarı: "
 
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "uname() '%s' hatasını verip çıktı (%d)\n"
+
 msgid "Fetching objects"
 msgstr "Nesneler getiriliyor"
 
diff --git a/po/uk.po b/po/uk.po
index 5f68f36..39c2228 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -8,8 +8,8 @@
 msgstr ""
 "Project-Id-Version: Git v2.46\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2025-01-04 19:26-0800\n"
-"PO-Revision-Date: 2025-01-03 14:17-0800\n"
+"POT-Creation-Date: 2025-03-09 15:40-0700\n"
+"PO-Revision-Date: 2025-03-09 16:53-0700\n"
 "Last-Translator: Kateryna Golovanova <kate@kgthreads.com>\n"
 "Language-Team: Ukrainian <https://github.com/arkid15r/git-uk-l10n/>\n"
 "Language: uk\n"
@@ -1433,7 +1433,7 @@
 msgstr "записати архів до цього файлу"
 
 msgid "read .gitattributes in working directory"
-msgstr "прочитати .gitattributes робочої директорії"
+msgstr "читати .gitattributes робочої директорії"
 
 msgid "report archived files on stderr"
 msgstr "звітувати про заархівовані файли в stderr"
@@ -2357,6 +2357,18 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: очікувалось flush"
 
+msgid "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+msgstr "git backfill [--min-batch-size=<н>] [--[no-]sparse]"
+
+msgid "problem loading sparse-checkout"
+msgstr "проблема із завантаженням розрідженого переходу"
+
+msgid "Minimum number of objects to request at a time"
+msgstr "Мінімальна кількість обʼєктів для запиту за один раз"
+
+msgid "Restrict the missing objects to the current sparse-checkout"
+msgstr "Обмежити відсутні обʼєкти поточним розрідженим переходом"
+
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
 "checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
@@ -3117,15 +3129,11 @@
 msgid "git version:\n"
 msgstr "версія git:\n"
 
-#, c-format
-msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() завершився невдало з помилкою \"%s\" (%d)\n"
-
 msgid "compiler info: "
 msgstr "інформація щодо компілятора: "
 
 msgid "libc info: "
-msgstr "информація щодо libc: "
+msgstr "інформація щодо libc: "
 
 msgid "not run from a git repository - no hooks to show\n"
 msgstr "запущено не з git сховища - немає гачків для показу\n"
@@ -3448,7 +3456,7 @@
 msgstr "використовувати .gitattributes тільки з індексу"
 
 msgid "read file names from stdin"
-msgstr "зчитувати назви файлів з stdin"
+msgstr "читати назви файлів з stdin"
 
 msgid "terminate input and output records by a NUL character"
 msgstr "завершувати вхідні та вихідні записи символом NUL"
@@ -3493,13 +3501,13 @@
 msgstr "також читати контакти з stdin"
 
 msgid "read additional mailmap entries from file"
-msgstr "зчитувати додаткові записи mailmap з файлу"
+msgstr "читати додаткові записи mailmap з файлу"
 
 msgid "blob"
 msgstr "blob"
 
 msgid "read additional mailmap entries from blob"
-msgstr "зчитувати додаткові записи mailmap з blob"
+msgstr "читати додаткові записи mailmap з blob"
 
 msgid "no contacts specified"
 msgstr "контакти не вказані"
@@ -3538,10 +3546,10 @@
 msgstr "оновити статистичну інформацію в індексному файлі"
 
 msgid "read list of paths from the standard input"
-msgstr "зчитати список шляхів зі стандартного вводу"
+msgstr "читати список шляхів зі стандартного вводу"
 
 msgid "write the content to temporary files"
-msgstr "записати вміст у тимчасові файли"
+msgstr "записати вміст до тимчасових файлів"
 
 msgid "copy out the files from named stage"
 msgstr "скопіювати файли з іменованої стадії"
@@ -4146,11 +4154,94 @@
 msgstr ""
 "clean.requireForce встановлено у true і -f не задано: відмовлено в прибиранні"
 
-msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<опції>] [--] <сховище> [<директорія>]"
+#, c-format
+msgid "info: Could not add alternate for '%s': %s\n"
+msgstr "інфо: Не вдалося додати запозичений обʼєкт для \"%s\": %s\n"
+
+#, c-format
+msgid "failed to stat '%s'"
+msgstr "не вдалося виконати stat \"%s\""
+
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr "%s існує і не є директорією"
+
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "\"%s\" є символьним посиланням, відмовлено в клонуванні з --local"
+
+#, c-format
+msgid "failed to start iterator over '%s'"
+msgstr "не вдалося запустити ітератор для \"%s\""
+
+#, c-format
+msgid "symlink '%s' exists, refusing to clone with --local"
+msgstr "символьне посилання \"%s\" існує, відмовлено в клонуванні з --local"
+
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "не вдалося видалити \"%s\""
+
+#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "неможливо перевірити жорстке посилання \"%s\""
+
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "жорстке посилання відрізняється від джерела в \"%s\""
+
+#, c-format
+msgid "failed to create link '%s'"
+msgstr "не вдалося створити посилання \"%s\""
+
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr "не вдалося скопіювати файл у \"%s\""
+
+#, c-format
+msgid "failed to iterate over '%s'"
+msgstr "не вдалося здійснити перебір для \"%s\""
+
+#, c-format
+msgid "done.\n"
+msgstr "готово.\n"
+
+msgid ""
+"Clone succeeded, but checkout failed.\n"
+"You can inspect what was checked out with 'git status'\n"
+"and retry with 'git restore --source=HEAD :/'\n"
+msgstr ""
+"Клонування пройшло успішно, але не вдалося перейти на гілку.\n"
+"Ви можете перевірити, що було додано за допомогою 'git status'\n"
+"і повторити спробу за допомогою \"git restore --source=HEAD :/\"\n"
+
+msgid "remote did not send all necessary objects"
+msgstr "віддалене сховище не надіслало всі необхідні обʼєкти"
+
+#, c-format
+msgid "unable to update %s"
+msgstr "не вдалося оновити %s"
+
+msgid "failed to initialize sparse-checkout"
+msgstr "не вдалося ініціалізувати розріджений перехід"
+
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
+msgstr "віддалений HEAD вказує на неіснуюче посилання, неможливо перейти"
+
+msgid "unable to checkout working tree"
+msgstr "не вдалося завантажити стан робочої директорії"
+
+msgid "unable to write parameters to config file"
+msgstr "не вдалося записати параметри до конфігураційного файлу"
+
+msgid "cannot repack to clean up"
+msgstr "неможливо перепакувати для очищення"
+
+msgid "cannot unlink temporary alternates file"
+msgstr "неможливо видалити тимчасовий файл запозичених обʼєктів"
 
 msgid "don't clone shallow repository"
-msgstr "не клонувати неглибоке сховище"
+msgstr "не клонувати поверхневе сховище"
 
 msgid "don't create a checkout"
 msgstr "не переходити на гілку"
@@ -4202,6 +4293,9 @@
 msgid "checkout <branch> instead of the remote's HEAD"
 msgstr "перейти до <гілки> замість HEAD віддаленого сховища"
 
+msgid "clone single revision <rev> and check out"
+msgstr "клонувати одну ревізію <rev> і перейти на неї"
+
 msgid "path to git-upload-pack on the remote"
 msgstr "шлях до git-upload-pack на віддаленому сервері"
 
@@ -4223,9 +4317,8 @@
 msgid "clone only one branch, HEAD or --branch"
 msgstr "клонувати лише одну гілку, HEAD або --branch"
 
-msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr ""
-"не клонувати жодних тегів і не слідувати за ними під час отримувань пізніше"
+msgid "clone tags, and make later fetches not to follow them"
+msgstr "клонувати теги і більше не слідкувати за ними"
 
 msgid "any cloned submodules will be shallow"
 msgstr "будь-які клоновані підмодулі будуть неглибокими"
@@ -4269,95 +4362,8 @@
 msgid "a URI for downloading bundles before fetching from origin remote"
 msgstr "URI для завантаження пакунків перед отриманням з віддаленого джерела"
 
-#, c-format
-msgid "info: Could not add alternate for '%s': %s\n"
-msgstr "инфо: Не вдалося додати запозичений обʼєкт для \"%s\": %s\n"
-
-#, c-format
-msgid "failed to stat '%s'"
-msgstr "не вдалося виконати stat \"%s\""
-
-#, c-format
-msgid "%s exists and is not a directory"
-msgstr "%s існує і не є директорією"
-
-#, c-format
-msgid "'%s' is a symlink, refusing to clone with --local"
-msgstr "\"%s\" є символьним посиланням, відмовлено в клонуванні з --local"
-
-#, c-format
-msgid "failed to start iterator over '%s'"
-msgstr "не вдалося запустити перебір для \"%s\""
-
-#, c-format
-msgid "symlink '%s' exists, refusing to clone with --local"
-msgstr "символьне посилання \"%s\" існує, не можу клонувати з --local"
-
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "не вдалося видалити \"%s\""
-
-#, c-format
-msgid "hardlink cannot be checked at '%s'"
-msgstr "неможливо перевірити жорстке посилання \"%s\""
-
-#, c-format
-msgid "hardlink different from source at '%s'"
-msgstr "жорстке посилання відрізняється від джерела в \"%s\""
-
-#, c-format
-msgid "failed to create link '%s'"
-msgstr "не вдалося створити посилання \"%s\""
-
-#, c-format
-msgid "failed to copy file to '%s'"
-msgstr "не вдалося скопіювати файл у \"%s\""
-
-#, c-format
-msgid "failed to iterate over '%s'"
-msgstr "не вдалося перебрати \"%s\""
-
-#, c-format
-msgid "done.\n"
-msgstr "готово.\n"
-
-msgid ""
-"Clone succeeded, but checkout failed.\n"
-"You can inspect what was checked out with 'git status'\n"
-"and retry with 'git restore --source=HEAD :/'\n"
-msgstr ""
-"Клонування пройшло успішно, але не вдалося перейти на гілку.\n"
-"Ви можете перевірити, що було додано за допомогою 'git status'\n"
-"і повторити спробу за допомогою 'git restore --source=HEAD :/'\n"
-
-#, c-format
-msgid "Could not find remote branch %s to clone."
-msgstr "Не вдалося знайти віддалену гілку %s для клонування."
-
-msgid "remote did not send all necessary objects"
-msgstr "віддалене сховище не надіслало всі необхідні обʼєкти"
-
-#, c-format
-msgid "unable to update %s"
-msgstr "не вдалося оновити %s"
-
-msgid "failed to initialize sparse-checkout"
-msgstr "не вдалося ініціалізувати розріджений перехід"
-
-msgid "remote HEAD refers to nonexistent ref, unable to checkout"
-msgstr "віддалений HEAD посилається на неіснуючого рефа, неможливо перейти"
-
-msgid "unable to checkout working tree"
-msgstr "не вдалося завантажити стан робочої директорії"
-
-msgid "unable to write parameters to config file"
-msgstr "не вдалося записати параметри до конфігураційного файлу"
-
-msgid "cannot repack to clean up"
-msgstr "неможливо перепакувати, щоб очистити"
-
-msgid "cannot unlink temporary alternates file"
-msgstr "неможливо видалити тимчасовий файл запозичених обʼєктів"
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [<опції>] [--] <сховище> [<директорія>]"
 
 msgid "Too many arguments."
 msgstr "Забагато аргументів."
@@ -4463,6 +4469,10 @@
 msgid "Remote branch %s not found in upstream %s"
 msgstr "Віддалену гілку %s не знайдено у першоджерельному сховищі %s"
 
+#, c-format
+msgid "Remote revision %s not found in upstream %s"
+msgstr "Віддалена ревізія %s не знайдена у першоджерельному сховищі %s"
+
 msgid "You appear to have cloned an empty repository."
 msgstr "Здається, ви клонували порожнє сховище."
 
@@ -4639,7 +4649,7 @@
 msgstr "git commit-tree: не вдалося прочитати"
 
 msgid ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -4649,7 +4659,7 @@
 "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
 "           [--] [<pathspec>...]"
 msgstr ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<режим>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<режим>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <коміт> | --fixup [(amend|"
 "reword):]<коміт>]\n"
 "           [-F <файл> | -m <допис>] [--reset-author] [--allow-empty]\n"
@@ -5214,7 +5224,7 @@
 msgstr "blob-id"
 
 msgid "read config from given blob object"
-msgstr "прочитати конфігурацію з наданого blob-обʼєкту"
+msgstr "читати конфігурацію з наданого blob-обʼєкту"
 
 msgid "Type"
 msgstr "Тип"
@@ -6050,15 +6060,15 @@
 "Run 'git remote set-head %s %s' to follow the change, or set\n"
 "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
 "if you do not want to see this message. Specifically running\n"
-"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
-"until the remote changes HEAD to something else."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"will disable the warning until the remote changes HEAD to something else."
 msgstr ""
 "Запустіть \"git remote set-head %s %s\", щоб відстежити зміни, або "
 "встановіть\n"
 "\"remote.%s.followRemoteHEAD\" параметр конфігурації на інше значення\n"
-"якщо ви не хочете бачити це повідомлення. Зокрема, виконання команди\n"
-"\"git config set remote.%s.followRemoteHEAD %s\" вимкне попередження\n"
-"доки віддалений сервер не змінить HEAD на щось інше."
+"якщо ви не хочете бачити це повідомлення. Зокрема, виконання\n"
+"\"git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s\"\n"
+"вимкне попередження, доки віддалене призначення не змінить HEAD на щось інше."
 
 msgid "multiple branches detected, incompatible with --set-upstream"
 msgstr "виявлено кілька гілок, несумісних з --set-upstream"
@@ -6740,6 +6750,9 @@
 msgid "repack all other packs except the largest pack"
 msgstr "перепакувати всі пакунки, крім найбільшого"
 
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "префікс для зберігання пакунка з обрізаними обʼєктами"
+
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
 msgstr "не вдалося розібрати gc.logExpiry значення %s"
@@ -7120,7 +7133,7 @@
 msgstr "показати навколишню функцію"
 
 msgid "read patterns from file"
-msgstr "зчитувати шаблони з файлу"
+msgstr "читати шаблони з файлу"
 
 msgid "match <pattern>"
 msgstr "зіставляти <шаблон>"
@@ -7196,7 +7209,7 @@
 msgstr "записати об’єкт до бази даних об’єктів"
 
 msgid "read the object from stdin"
-msgstr "прочитати об’єкт з stdin"
+msgstr "читати об’єкт з stdin"
 
 msgid "store file as is without filters"
 msgstr "зберегти файл як є без фільтрів"
@@ -7548,6 +7561,10 @@
 msgstr "Неможливо повернутися до поточної робочої директорії"
 
 #, c-format
+msgid "bad --pack_header: %s"
+msgstr "невірний --pack_header: %s"
+
+#, c-format
 msgid "bad %s"
 msgstr "невірний %s"
 
@@ -8420,10 +8437,6 @@
 msgid "malformed input line: '%s'."
 msgstr "невірно сформований рядок вводу: \"%s\"."
 
-#, c-format
-msgid "merging cannot continue; got unclean result of %d"
-msgstr "неможливо продовжити злиття; отримано брудний результат для %d"
-
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<опції>] [<коміт>...]"
 
@@ -9094,7 +9107,7 @@
 msgstr "Видалення нотатки для обʼєкта %s\n"
 
 msgid "read objects from stdin"
-msgstr "зчитати обʼєкти з stdin"
+msgstr "читати обʼєкти з stdin"
 
 msgid "load rewriting config for <command> (implies --stdin)"
 msgstr ""
@@ -9216,7 +9229,7 @@
 msgstr "спроба видалити неіснуючу нотатку не є помилкою"
 
 msgid "read object names from the standard input"
-msgstr "зчитати імена обʼєктів зі стандартного вводу"
+msgstr "читати імена обʼєктів зі стандартного вводу"
 
 msgid "do not remove, show only"
 msgstr "не видаляти, тільки показувати"
@@ -9246,6 +9259,13 @@
 "обʼєктів>]"
 
 #, c-format
+msgid "invalid --name-hash-version option: %d"
+msgstr "неприпустима --name-hash-version опція: %d"
+
+msgid "currently, --write-bitmap-index requires --name-hash-version=1"
+msgstr "наразі --write-bitmap-index потребує --name-hash-version=1"
+
+#, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
@@ -9481,7 +9501,7 @@
 msgstr "не створювати вивід порожнього пакунка"
 
 msgid "read revision arguments from standard input"
-msgstr "зчитувати аргументи ревізії зі стандартного вводу"
+msgstr "читати аргументи ревізії зі стандартного вводу"
 
 msgid "limit the objects to those that are not yet packed"
 msgstr "обмежувати обʼєкти тільки тими, які ще не запаковані"
@@ -9570,6 +9590,10 @@
 msgid "exclude any configured uploadpack.blobpackfileuri with this protocol"
 msgstr "вилучити всі налаштовані uploadpack.blobpackfileuri з цим протоколом"
 
+msgid "use the specified name-hash function to group similar objects"
+msgstr ""
+"використовувати вказану name-hash функцію для групування схожих обʼєктів"
+
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
 msgstr "глибина дельта ланцюжка %d занадто глибока, примусове %d"
@@ -10826,8 +10850,8 @@
 msgid "invalid ref format: %s"
 msgstr "неприпустимий формат посилання: %s"
 
-msgid "git refs migrate --ref-format=<format> [--dry-run]"
-msgstr "git refs migrate --ref-format=<формат> [--dry-run]"
+msgid "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
+msgstr "git refs migrate --ref-format=<формат> [--no-reflog] [--dry-run]"
 
 msgid "git refs verify [--strict] [--verbose]"
 msgstr "git refs verify [--strict] [--verbose]"
@@ -10838,6 +10862,9 @@
 msgid "perform a non-destructive dry-run"
 msgstr "виконати неруйнівний пробний запуск"
 
+msgid "drop reflogs entirely during the migration"
+msgstr "повністю видалити журнал посилань під час міграції"
+
 msgid "missing --ref-format=<format>"
 msgstr "відсутній --ref-format=<формат>"
 
@@ -11312,8 +11339,14 @@
 msgid "be verbose; must be placed before a subcommand"
 msgstr "розгорнутий вивід; має стояти перед підкомандою"
 
-msgid "git repack [<options>]"
-msgstr "git repack [<опції>]"
+msgid ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
+msgstr ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<н>] [--depth=<н>] [--threads=<н>] [--keep-pack=<назва-пакунка>]\n"
+"[--write-midx] [--name-hash-version=<н>]"
 
 msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
@@ -11388,6 +11421,10 @@
 msgid "pass --no-reuse-object to git-pack-objects"
 msgstr "передати --no-reuse-object до git-pack-objects"
 
+msgid ""
+"specify the name hash version to use for grouping similar objects by path"
+msgstr "вказати версію назви хешу для групування схожих обʼєктів за шляхом"
+
 msgid "do not run git-update-server-info"
 msgstr "не запускати git-update-server-info"
 
@@ -11437,9 +11474,6 @@
 msgid "write a multi-pack index of the resulting packs"
 msgstr "записати multi-pack-index результуючих пакунків"
 
-msgid "pack prefix to store a pack containing pruned objects"
-msgstr "префікс для зберігання пакунка з обрізаними обʼєктами"
-
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr "префікс для зберігання пакунка з відфільтрованими  обʼєктами"
 
@@ -11656,9 +11690,6 @@
 msgid "need some commits to replay"
 msgstr "потрібні деякі коміти для відтворення"
 
-msgid "--onto and --advance are incompatible"
-msgstr "--onto та --advance несумісні"
-
 msgid "all positive revisions given must be references"
 msgstr "всі надані позитивні ревізії мають бути посиланнями"
 
@@ -12135,7 +12166,7 @@
 msgstr "використовувати протокол RPC без збереження стану"
 
 msgid "read refs from stdin"
-msgstr "прочитати посилання з stdin"
+msgstr "читати посилання з stdin"
 
 msgid "print status from remote helper"
 msgstr "вивести статус з віддаленого помічника"
@@ -13623,7 +13654,7 @@
 msgstr "з --stdin: вхідні рядки завершуються нульовими байтами"
 
 msgid "read list of paths to be updated from standard input"
-msgstr "прочитати список шляхів для оновлення зі стандартного вводу"
+msgstr "читати список шляхів для оновлення зі стандартного вводу"
 
 msgid "add entries from standard input to the index"
 msgstr "додати записи зі стандартного вводу до індексу"
@@ -14335,8 +14366,11 @@
 msgid "Create an archive of files from a named tree"
 msgstr "Створити архів файлів з названого дерева"
 
+msgid "Download missing objects in a partial clone"
+msgstr "Завантажити відсутні обʼєкти у частковому клонуванні"
+
 msgid "Use binary search to find the commit that introduced a bug"
-msgstr "Використати бінарний пошук, щоб знайти коміт, який вніс помилку"
+msgstr "Використати бінарний пошук, щоб знайти коміт, який ввів помилку"
 
 msgid "Show what revision and author last modified each line of a file"
 msgstr "Показати, яка ревізія та автор востаннє змінювали кожен рядок файлу"
@@ -15728,7 +15762,7 @@
 
 #, c-format
 msgid "protocol error: expected shallow sha-1, got '%s'"
-msgstr "помилка протоколу: очікувалось неглибоке sha-1, отримано \"%s\""
+msgstr "помилка протоколу: очікувалось поверхневе sha-1, отримано \"%s\""
 
 msgid "repository on the other end cannot be shallow"
 msgstr "сховище на іншому кінці не може бути неглибоким"
@@ -16256,6 +16290,12 @@
 msgid "invalid regex given to -I: '%s'"
 msgstr "неприпустимий regex, переданий до -I: \"%s\""
 
+msgid "-G requires a non-empty argument"
+msgstr "-G потребує непорожнього аргументу"
+
+msgid "-S requires a non-empty argument"
+msgstr "-S потребує непорожнього аргументу"
+
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr "не вдалося розібрати параметр опції --submodule: \"%s\""
@@ -17247,7 +17287,7 @@
 
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
-msgstr "git: \"%s\" не є командою git. Дивітья git --help."
+msgstr "git: \"%s\" не є командою git. Дивіться git --help."
 
 msgid "Uh oh. Your system reports no Git commands at all."
 msgstr "Ой-ой. Ваша система повідомляє про повну відсутність Git команд."
@@ -18448,6 +18488,10 @@
 msgstr "не вдалося записати файл %s"
 
 #, c-format
+msgid "unable to write repeatedly vanishing file %s"
+msgstr "не вдалося записати файл %s, який постійно зникає"
+
+#, c-format
 msgid "unable to set permission to '%s'"
 msgstr "не вдалося встановити дозволи для \"%s\""
 
@@ -19020,6 +19064,52 @@
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "невідомий non-ascii параметр у рядку: \"%s\""
 
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the long form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[=<%s>]"
+msgstr "[=<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the short form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[<%s>]"
+msgstr "[<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string stands for a
+#. value given to a command line option, and "<>" is there
+#. as a convention to signal that it is a placeholder
+#. (i.e. the user should substitute it with the real value).
+#. If your language uses a different convention, you can
+#. change "<%s>" part to match yours, e.g. it might use
+#. "|%s|" instead, or if the alphabet is different enough it
+#. may use "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid " <%s>"
+msgstr " <%s>"
+
 msgid "..."
 msgstr "..."
 
@@ -19107,6 +19197,21 @@
 msgstr "не вдалося розібрати %s"
 
 #, c-format
+msgid "failed to walk children of tree %s: not found"
+msgstr "не вдалося пройти дочірні елементи дерева %s: не знайдено"
+
+#, c-format
+msgid "failed to find object %s"
+msgstr "не вдалося знайти обʼєкт %s"
+
+#, c-format
+msgid "failed to find tag %s"
+msgstr "не вдалося знайти тег %s"
+
+msgid "failed to setup revision walk"
+msgstr "не вдалося налаштувати проходження по ревізіям"
+
+#, c-format
 msgid "Could not make %s writable by group"
 msgstr "Не вдалося зробити %s доступним для запису групою"
 
@@ -19255,6 +19360,22 @@
 msgid "could not fetch %s from promisor remote"
 msgstr "не вдалося отримати %s з віддаленого promisor"
 
+#, c-format
+msgid "known remote named '%s' but with url '%s' instead of '%s'"
+msgstr "відоме віддалене сховище з імʼям \"%s\" має URL \"%s\" замість \"%s\""
+
+#, c-format
+msgid "unknown '%s' value for '%s' config option"
+msgstr "невідоме значення \"%s\" для параметра конфігурації \"%s\""
+
+#, c-format
+msgid "unknown element '%s' from remote info"
+msgstr "невідомий елемент \"%s\" з віддаленої інформації"
+
+#, c-format
+msgid "accepted promisor remote '%s' not found"
+msgstr "прийнятий віддалений promisor \"%s\" не знайдено"
+
 msgid "object-info: expected flush after arguments"
 msgstr "object-info: очікувався flush після аргументів"
 
@@ -20084,6 +20205,14 @@
 msgstr "неприпустимий визначник посилання \"%s\""
 
 #, c-format
+msgid "pattern '%s' has no '*'"
+msgstr "шаблон \"%s\" не має \"*\""
+
+#, c-format
+msgid "replacement '%s' has no '*'"
+msgstr "заміна \"%s\" не має \"*\""
+
+#, c-format
 msgid "invalid quoting in push-option value: '%s'"
 msgstr "неприпустимі лапки у значенні push-опції: \"%s\""
 
@@ -20132,7 +20261,7 @@
 
 msgid "unable to rewind rpc post data - try increasing http.postBuffer"
 msgstr ""
-"не вдалося перемотати  вперед rpc post дані - спробуйте збільшити "
+"не вдалося перемотати вперед rpc post дані - спробуйте збільшити "
 "http.postBuffer"
 
 #, c-format
@@ -20207,8 +20336,31 @@
 msgstr "remote-curl: невідома команда \"%s\" з git"
 
 #, c-format
+msgid ""
+"reading remote from \"%s/%s\", which is nominated for removal.\n"
+"\n"
+"If you still use the \"remotes/\" directory it is recommended to\n"
+"migrate to config-based remotes:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"If you cannot, please let us know why you still need to use it by\n"
+"sending an e-mail to <git@vger.kernel.org>."
+msgstr ""
+"читання віддаленого призначення з \"%s/%s\", який номіновано на вилучення.\n"
+"\n"
+"Якщо ви все ще використовуєте директорію \"remotes/\", рекомендується\n"
+"перейти віддалені призначення на основі конфігурації:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"Якщо ви не можете цього зробити, будь ласка, дайте нам знати, чому ви все ще "
+"використовуєте її\n"
+"надіславши листа на адресу <git@vger.kernel.org>."
+
+#, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
-msgstr "скорочення віддаленої конфігураціі не може починатися з \"/\": %s"
+msgstr "скорочене ім'я віддаленої конфігураціі не може починатися з \"/\": %s"
 
 msgid "more than one receivepack given, using the first"
 msgstr "надано більше одного пакунка для отримання, використано перший"
@@ -20241,14 +20393,6 @@
 msgstr "%s відстежує як %s, так і %s"
 
 #, c-format
-msgid "key '%s' of pattern had no '*'"
-msgstr "ключ \"%s\" шаблону не містив '*'"
-
-#, c-format
-msgid "value '%s' of pattern has no '*'"
-msgstr "значення \"%s\" шаблону не містить '*'"
-
-#, c-format
 msgid "src refspec %s does not match any"
 msgstr "визначник посилання джерела %s не збігається з жодним"
 
@@ -22179,6 +22323,27 @@
 msgstr ""
 "кількість записів у дереві кешу, які потрібно анулювати (за замовчуванням 0)"
 
+msgid "test-tool path-walk <options> -- <revision-options>"
+msgstr "test-tool path-walk <опції> -- <опції-ревізії>."
+
+msgid "toggle inclusion of blob objects"
+msgstr "перемикач включення обʼєктів blob"
+
+msgid "toggle inclusion of commit objects"
+msgstr "перемикач включення обʼєктів коміту"
+
+msgid "toggle inclusion of tag objects"
+msgstr "перемикач включення обʼєктів тегів"
+
+msgid "toggle inclusion of tree objects"
+msgstr "перемикач включення обʼєктів дерева"
+
+msgid "toggle pruning of uninteresting paths"
+msgstr "перемикач обрізання нецікавих шляхів"
+
+msgid "read a pattern list over stdin"
+msgstr "читати список шаблонів через stdin"
+
 #, c-format
 msgid "commit %s is not marked reachable"
 msgstr "коміт %s не позначений як досяжний"
@@ -22819,6 +22984,10 @@
 msgid "warning: "
 msgstr "попередження: "
 
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "uname() завершився невдало з помилкою \"%s\" (%d)\n"
+
 msgid "Fetching objects"
 msgstr "Отримання обʼєктів"
 
diff --git a/po/vi.po b/po/vi.po
index 80a5f19..803a68e 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -11,7 +11,7 @@
 # Vũ Tiến Hưng <newcomerminecraft@gmail.com>, 2024-2025.
 # ---
 # BẢNG THUẬT NGỮ / TERMINOLOGY
-# Updated: 2024-07-26, git 2.46
+# Updated: 2025-03-06, git 2.49
 #
 # Ghi chú:
 #  - Bảng thuật ngữ này chưa hoàn thiện.
@@ -59,15 +59,17 @@
 # | (v.) rebase                       | cải tổ                       |
 # | (v.) squash                       | squash                       |
 # | (v.) amend                        | tu bổ                        |
+# | (n.) revision                     | cải biên                     |
+# | (n.) repo/repository              | kho chứa                     |
 # | | |
 # | ... TODO ...                      |                              |
 # +------------------------------------------------------------------+
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.48\n"
+"Project-Id-Version: git 2.49\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-12-23 18:57+0000\n"
-"PO-Revision-Date: 2025-01-05 01:20+0700\n"
+"POT-Creation-Date: 2025-03-05 22:57+0000\n"
+"PO-Revision-Date: 2025-03-06 08:20+0700\n"
 "Last-Translator: Vũ Tiến Hưng <newcomerminecraft@gmail.com>\n"
 "Language-Team: Vietnamese <https://github.com/Nekosha/git-po>\n"
 "Language: vi\n"
@@ -1601,7 +1603,7 @@
 "git bisect cannot work properly in this case.\n"
 "Maybe you mistook %s and %s revs?\n"
 msgstr ""
-"Một số điểm xét duyệt %s không phải tổ tiên của điểm xét duyệt %s.\n"
+"Một số lần cải biên %s không phải tổ tiên của lần cải biên %s.\n"
 "git bisect không thể làm việc đúng trong trường hợp này.\n"
 "Liệu có phải bạn nhầm lẫn các điểm %s và %s không?\n"
 
@@ -1621,7 +1623,7 @@
 
 #, c-format
 msgid "a %s revision is needed"
-msgstr "cần một điểm xét duyệt %s"
+msgstr "cần lần cải biên %s"
 
 #, c-format
 msgid "could not create file '%s'"
@@ -1661,7 +1663,7 @@
 #, c-format
 msgid "Bisecting: %d revision left to test after this %s\n"
 msgid_plural "Bisecting: %d revisions left to test after this %s\n"
-msgstr[0] "Bisecting: còn %d điểm xét duyệt để kiểm tra %s\n"
+msgstr[0] "Bisecting: còn %d lần cải biên để kiểm tra %s\n"
 
 msgid "--contents and --reverse do not blend well."
 msgstr "tùy chọn --contents và --reverse không nên đi với nhau."
@@ -1671,7 +1673,7 @@
 "cùng sử dụng --reverse và --first-parent cần chỉ định lần chuyển giao cuối"
 
 msgid "revision walk setup failed"
-msgstr "cài đặt việc di chuyển qua các điểm xét duyệt gặp lỗi"
+msgstr "cài đặt việc duyệt qua các lần cải biên gặp lỗi"
 
 msgid ""
 "--reverse --first-parent together require range along first-parent chain"
@@ -2371,6 +2373,18 @@
 msgid "git archive: expected a flush"
 msgstr "git archive: cần flush dữ liệu"
 
+msgid "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+msgstr "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+
+msgid "problem loading sparse-checkout"
+msgstr "không thể tải checkout thưa"
+
+msgid "Minimum number of objects to request at a time"
+msgstr "Số đối tượng tối thiểu mỗi lần yêu cầu"
+
+msgid "Restrict the missing objects to the current sparse-checkout"
+msgstr "Chỉ lấy về đối tượng còn thiếu trong checkout thưa hiện tại"
+
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
 "checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
@@ -2441,7 +2455,7 @@
 
 #, c-format
 msgid "couldn't get the oid of the rev '%s'"
-msgstr "không thể lấy oid của điểm xét duyệt '%s'"
+msgstr "không thể lấy oid của lần cải biên '%s'"
 
 #, c-format
 msgid "couldn't open the file '%s'"
@@ -2466,7 +2480,7 @@
 "You can use \"git bisect %s\" and \"git bisect %s\" for that."
 msgstr ""
 "Bạn cần bắt đầu bằng lệnh \"git bisect start\".\n"
-"Bạn sau đó cần phải chỉ cho tôi ít nhất một điểm xét duyệt %s và một %s.\n"
+"Bạn sau đó cần phải chỉ cho tôi ít nhất một lần cải biên %s và một %s.\n"
 "Bạn có thể sử dụng \"git bisect %s\" và \"git bisect %s\" cho chúng."
 
 #, c-format
@@ -2526,7 +2540,7 @@
 
 #, c-format
 msgid "'%s' does not appear to be a valid revision"
-msgstr "'%s' không có vẻ như là một điểm xét duyệt hợp lệ"
+msgstr "'%s' không có vẻ như là một lần cải biên hợp lệ"
 
 msgid "bad HEAD - I need a HEAD"
 msgstr "sai HEAD - Tôi cần một HEAD"
@@ -2587,11 +2601,11 @@
 
 #, c-format
 msgid "unable to verify %s on good revision"
-msgstr "không thể xác nhận '%s' trên điểm xét duyệt tốt"
+msgstr "không thể xác nhận '%s' trên lần cải biên tốt"
 
 #, c-format
 msgid "bogus exit code %d for good revision"
-msgstr "mã trả về %d bất thường cho điểm xét duyệt tốt"
+msgstr "mã trả về %d bất thường cho lần cải biên tốt"
 
 #, c-format
 msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
@@ -2658,7 +2672,7 @@
 
 #, c-format
 msgid "cannot find revision %s to ignore"
-msgstr "không thể tìm thấy điểm xét duyệt %s để bỏ qua"
+msgstr "không thể tìm thấy lần cải biên %s để bỏ qua"
 
 msgid "show blame entries as we find them, incrementally"
 msgstr "hiển thị các mục 'blame' theo thời gian, tăng dần"
@@ -2717,7 +2731,7 @@
 msgstr "bỏ qua <rev> khi blame"
 
 msgid "ignore revisions from <file>"
-msgstr "bỏ qua các điểm xét duyệt từ <tập tin>"
+msgstr "bỏ qua các lần cải biên từ <tập tin>"
 
 msgid "color redundant metadata from previous line differently"
 msgstr "tô màu khác cho siêu dữ liệu dư thừa từ dòng trước"
@@ -2730,7 +2744,7 @@
 
 msgid "use revisions from <file> instead of calling git-rev-list"
 msgstr ""
-"sử dụng các điểm xét duyệt (revision) từ <tập tin> thay vì gọi git-rev-list"
+"sử dụng các lần cải biên (revision) từ <tập tin> thay vì gọi git-rev-list"
 
 msgid "use <file>'s contents as the final image"
 msgstr "sử dụng nội dung của <tập tin> như là ảnh cuối cùng"
@@ -3114,10 +3128,6 @@
 msgid "git version:\n"
 msgstr "phiên bản git:\n"
 
-#, c-format
-msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() gặp lỗi '%s' (%d)\n"
-
 msgid "compiler info: "
 msgstr "thông tin trình biên dịch: "
 
@@ -3710,7 +3720,7 @@
 "\n"
 
 msgid "internal error in revision walk"
-msgstr "lỗi nội bộ trong khi di chuyển qua các điểm xét duyệt"
+msgstr "lỗi nội bộ trong khi di chuyển qua các lần cải biên"
 
 msgid "Previous HEAD position was"
 msgstr "Vị trí trước kia của HEAD là"
@@ -4116,125 +4126,6 @@
 "clean.requireForce được đặt thành true và không có tuỳ chọn -f; từ chối dọn "
 "dẹp"
 
-msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<các tùy chọn>] [--] <kho> [<t.mục>]"
-
-msgid "don't clone shallow repository"
-msgstr "đừng nhân bản từ kho nông"
-
-msgid "don't create a checkout"
-msgstr "không tạo một checkout"
-
-msgid "create a bare repository"
-msgstr "tạo kho bare"
-
-msgid "create a mirror repository (implies --bare)"
-msgstr "tạo kho bản sao (ngầm chỉ định --bare)"
-
-msgid "to clone from a local repository"
-msgstr "để nhân bản từ kho nội bộ"
-
-msgid "don't use local hardlinks, always copy"
-msgstr "không sử dụng liên kết cứng nội bộ, luôn sao chép"
-
-msgid "setup as shared repository"
-msgstr "cài đặt đây là kho chia sẻ"
-
-msgid "pathspec"
-msgstr "đặc-tả-đường-dẫn"
-
-msgid "initialize submodules in the clone"
-msgstr "khởi tạo mô-đun-con trong bản sao"
-
-msgid "number of submodules cloned in parallel"
-msgstr "số lượng mô-đun-con được nhân bản đồng thời"
-
-msgid "template-directory"
-msgstr "thư-mục-mẫu"
-
-msgid "directory from which templates will be used"
-msgstr "thư mục mà tại đó các mẫu sẽ được dùng"
-
-msgid "reference repository"
-msgstr "kho tham chiếu"
-
-msgid "use --reference only while cloning"
-msgstr "chỉ dùng --reference khi nhân bản"
-
-msgid "name"
-msgstr "tên"
-
-msgid "use <name> instead of 'origin' to track upstream"
-msgstr "dùng <tên> thay cho 'origin' để theo dõi thượng nguồn"
-
-msgid "checkout <branch> instead of the remote's HEAD"
-msgstr "checkout <nhánh> thay cho HEAD của máy chủ"
-
-msgid "path to git-upload-pack on the remote"
-msgstr "đường dẫn đến git-upload-pack trên máy chủ"
-
-msgid "depth"
-msgstr "độ-sâu"
-
-msgid "create a shallow clone of that depth"
-msgstr "tạo bản sao không đầy đủ cho mức sâu đã cho"
-
-msgid "create a shallow clone since a specific time"
-msgstr "tạo bản sao không đầy đủ từ thời điểm đã cho"
-
-msgid "ref"
-msgstr "ref"
-
-msgid "deepen history of shallow clone, excluding ref"
-msgstr "làm sâu hơn lịch sử của bản sao shallow, loại trừ tham chiếu"
-
-msgid "clone only one branch, HEAD or --branch"
-msgstr "chỉ nhân bản một nhánh, HEAD hoặc --branch"
-
-msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr ""
-"đứng có nhân bản bất kỳ nhánh nào, và làm cho những lần lấy về sau không "
-"theo chúng nữa"
-
-msgid "any cloned submodules will be shallow"
-msgstr "mọi mô-đun-con nhân bản sẽ là shallow (nông)"
-
-msgid "gitdir"
-msgstr "gitdir"
-
-msgid "separate git dir from working tree"
-msgstr "không dùng chung thư mục dành riêng cho git và thư mục làm việc"
-
-msgid "specify the reference format to use"
-msgstr "dùng định dạng tham chiếu nào cho các lần chuyển giao"
-
-msgid "key=value"
-msgstr "khóa=giá_trị"
-
-msgid "set config inside the new repository"
-msgstr "đặt cấu hình bên trong một kho chứa mới"
-
-msgid "server-specific"
-msgstr "đặc-tả-máy-phục-vụ"
-
-msgid "option to transmit"
-msgstr "tùy chọn để chuyển giao"
-
-msgid "apply partial clone filters to submodules"
-msgstr "áp dụng các bộ lọc nhân bản một phần cho mô-đun-con"
-
-msgid "any cloned submodules will use their remote-tracking branch"
-msgstr "mọi mô-đun-con được nhân bản sẽ dùng nhánh theo dõi máy chủ của chúng"
-
-msgid "initialize sparse-checkout file to include only files at root"
-msgstr "khởi tạo tập tin sparse-checkout để bao gồm chỉ các tập tin ở gốc"
-
-msgid "uri"
-msgstr "uri"
-
-msgid "a URI for downloading bundles before fetching from origin remote"
-msgstr "URI để tải xuống bundle trước khi lấy về từ máy chủ origin"
-
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "thông tin: không thể thêm thay thế cho '%s': %s\n"
@@ -4296,10 +4187,6 @@
 "Kiểm tra xem cái gì đã được checkout bằng lệnh 'git status'\n"
 "và thử lại với lệnh 'git restore --source=HEAD :/'\n"
 
-#, c-format
-msgid "Could not find remote branch %s to clone."
-msgstr "Không tìm thấy nhánh máy chủ %s để nhân bản (clone)."
-
 msgid "remote did not send all necessary objects"
 msgstr "máy chủ đã không gửi tất cả các đối tượng cần thiết"
 
@@ -4325,6 +4212,126 @@
 msgid "cannot unlink temporary alternates file"
 msgstr "không thể bỏ liên kết tập tin thay thế tạm thời"
 
+msgid "don't clone shallow repository"
+msgstr "đừng nhân bản từ kho nông"
+
+msgid "don't create a checkout"
+msgstr "không tạo một checkout"
+
+msgid "create a bare repository"
+msgstr "tạo kho bare"
+
+msgid "create a mirror repository (implies --bare)"
+msgstr "tạo kho bản sao (ngầm chỉ định --bare)"
+
+msgid "to clone from a local repository"
+msgstr "để nhân bản từ kho nội bộ"
+
+msgid "don't use local hardlinks, always copy"
+msgstr "không sử dụng liên kết cứng nội bộ, luôn sao chép"
+
+msgid "setup as shared repository"
+msgstr "cài đặt đây là kho chia sẻ"
+
+msgid "pathspec"
+msgstr "đặc-tả-đường-dẫn"
+
+msgid "initialize submodules in the clone"
+msgstr "khởi tạo mô-đun-con trong bản sao"
+
+msgid "number of submodules cloned in parallel"
+msgstr "số lượng mô-đun-con được nhân bản đồng thời"
+
+msgid "template-directory"
+msgstr "thư-mục-mẫu"
+
+msgid "directory from which templates will be used"
+msgstr "thư mục mà tại đó các mẫu sẽ được dùng"
+
+msgid "reference repository"
+msgstr "kho tham chiếu"
+
+msgid "use --reference only while cloning"
+msgstr "chỉ dùng --reference khi nhân bản"
+
+msgid "name"
+msgstr "tên"
+
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "dùng <tên> thay cho 'origin' để theo dõi thượng nguồn"
+
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr "checkout <nhánh> thay cho HEAD của máy chủ"
+
+msgid "clone single revision <rev> and check out"
+msgstr "nhân bản chỉ lần cải biên <rev> and check out"
+
+msgid "path to git-upload-pack on the remote"
+msgstr "đường dẫn đến git-upload-pack trên máy chủ"
+
+msgid "depth"
+msgstr "độ-sâu"
+
+msgid "create a shallow clone of that depth"
+msgstr "tạo bản sao không đầy đủ cho mức sâu đã cho"
+
+msgid "create a shallow clone since a specific time"
+msgstr "tạo bản sao không đầy đủ từ thời điểm đã cho"
+
+msgid "ref"
+msgstr "ref"
+
+msgid "deepen history of shallow clone, excluding ref"
+msgstr "làm sâu hơn lịch sử của bản sao shallow, loại trừ tham chiếu"
+
+msgid "clone only one branch, HEAD or --branch"
+msgstr "chỉ nhân bản một nhánh, HEAD hoặc --branch"
+
+msgid "clone tags, and make later fetches not to follow them"
+msgstr "nhân bản thẻ, và làm cho những lần lấy về sau không theo chúng nữa"
+
+msgid "any cloned submodules will be shallow"
+msgstr "mọi mô-đun-con nhân bản sẽ là shallow (nông)"
+
+msgid "gitdir"
+msgstr "gitdir"
+
+msgid "separate git dir from working tree"
+msgstr "không dùng chung thư mục dành riêng cho git và thư mục làm việc"
+
+msgid "specify the reference format to use"
+msgstr "dùng định dạng tham chiếu nào cho các lần chuyển giao"
+
+msgid "key=value"
+msgstr "khóa=giá_trị"
+
+msgid "set config inside the new repository"
+msgstr "đặt cấu hình bên trong một kho chứa mới"
+
+msgid "server-specific"
+msgstr "đặc-tả-máy-phục-vụ"
+
+msgid "option to transmit"
+msgstr "tùy chọn để chuyển giao"
+
+msgid "apply partial clone filters to submodules"
+msgstr "áp dụng các bộ lọc nhân bản một phần cho mô-đun-con"
+
+msgid "any cloned submodules will use their remote-tracking branch"
+msgstr "mọi mô-đun-con được nhân bản sẽ dùng nhánh theo dõi máy chủ của chúng"
+
+msgid "initialize sparse-checkout file to include only files at root"
+msgstr "khởi tạo tập tin sparse-checkout để bao gồm chỉ các tập tin ở gốc"
+
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "URI để tải xuống bundle trước khi lấy về từ máy chủ origin"
+
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [<các tùy chọn>] [--] <kho> [<t.mục>]"
+
 msgid "Too many arguments."
 msgstr "Quá nhiều đối số."
 
@@ -4430,6 +4437,10 @@
 msgid "Remote branch %s not found in upstream %s"
 msgstr "Nhánh máy chủ %s không tìm thấy trong thượng nguồn %s"
 
+#, c-format
+msgid "Remote revision %s not found in upstream %s"
+msgstr "Lần cải biên %s không tìm thấy trong thượng nguồn %s"
+
 msgid "You appear to have cloned an empty repository."
 msgstr "Bạn hình như là đã nhân bản một kho trống rỗng."
 
@@ -4605,7 +4616,7 @@
 msgstr "git commit-tree: gặp lỗi khi đọc"
 
 msgid ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -5576,7 +5587,7 @@
 
 #, c-format
 msgid "traversed %lu commits\n"
-msgstr "đã xuyên %lu qua lần chuyển giao\n"
+msgstr "đã chạy qua %lu lần chuyển giao\n"
 
 #, c-format
 msgid "found %i tags; gave up search at %s\n"
@@ -6021,8 +6032,8 @@
 "Run 'git remote set-head %s %s' to follow the change, or set\n"
 "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
 "if you do not want to see this message. Specifically running\n"
-"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
-"until the remote changes HEAD to something else."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"will disable the warning until the remote changes HEAD to something else."
 msgstr ""
 "Chạy 'git remote set-head %s %s' để làm theo thay đổi, hoặc đặt tuỳ chọn\n"
 "'remote.%s.followRemoteHEAD' sang giá trị khác nếu bạn không muốn thấy\n"
@@ -6073,7 +6084,7 @@
 "remote name from which new revisions should be fetched"
 msgstr ""
 "chưa chỉ ra kho chứa máy chủ; xin hãy chỉ định hoặc là URL hoặc\n"
-"tên máy chủ từ cái mà những điểm xét duyệt mới có thể được fetch (lấy về)"
+"tên máy chủ từ cái mà những lần cải biên mới có thể được fetch (lấy về)"
 
 msgid "you need to specify a tag name"
 msgstr "bạn cần chỉ định một tên thẻ"
@@ -6167,7 +6178,7 @@
 msgstr "chỉ ra refmap cần lấy về"
 
 msgid "revision"
-msgstr "điểm xét duyệt"
+msgstr "lần cải biên"
 
 msgid "report that we have only objects reachable from this object"
 msgstr "báo rằng ta chỉ có các đối tượng tiếp cận được từ đối tượng này"
@@ -6705,6 +6716,9 @@
 msgid "repack all other packs except the largest pack"
 msgstr "đóng gói lại tất cả các gói khác ngoại trừ gói lớn nhất"
 
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "tiền tố của gói để lưu gói gồm những đối tượng đã loại bỏ"
+
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
 msgstr "gặp lỗi khi đọc giá trị gc.logExpiry %s"
@@ -7113,7 +7127,7 @@
 
 #, c-format
 msgid "unable to resolve revision: %s"
-msgstr "không thể phân giải điểm xét duyệt: %s"
+msgstr "không thể phân giải lần cải biên: %s"
 
 msgid "--untracked not supported with --recurse-submodules"
 msgstr "tùy chọn --untracked không được hỗ trợ với --recurse-submodules"
@@ -7491,6 +7505,10 @@
 msgstr "Không thể quay lại thư mục hiện hành"
 
 #, c-format
+msgid "bad --pack_header: %s"
+msgstr "--pack_header sai: %s"
+
+#, c-format
 msgid "bad %s"
 msgstr "%s sai"
 
@@ -7758,10 +7776,10 @@
 msgstr "gặp lỗi khi tìm gốc hòa trộn chính xác"
 
 msgid "base commit should be the ancestor of revision list"
-msgstr "lần chuyển giao nền không là tổ tiên của danh sách điểm xét duyệt"
+msgstr "lần chuyển giao nền không là tổ tiên của danh sách lần cải biên"
 
 msgid "base commit shouldn't be in revision list"
-msgstr "lần chuyển giao nền không được trong danh sách điểm xét duyệt"
+msgstr "lần chuyển giao nền không được trong danh sách lần cải biên"
 
 msgid "cannot get patch id"
 msgstr "không thể lấy mã bản vá"
@@ -8356,10 +8374,6 @@
 msgid "malformed input line: '%s'."
 msgstr "dòng đầu vào sai quy cách: '%s'."
 
-#, c-format
-msgid "merging cannot continue; got unclean result of %d"
-msgstr "không thể tiếp tục hoà trộn; kết quả không hoàn toàn %d"
-
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<các tùy chọn>] [<commit>...]"
 
@@ -9187,6 +9201,13 @@
 "sách-đối-tượng>]"
 
 #, c-format
+msgid "invalid --name-hash-version option: %d"
+msgstr "tùy chọn --name-hash-version không hợp lệ: %d"
+
+msgid "currently, --write-bitmap-index requires --name-hash-version=1"
+msgstr "--write-bitmap-index hiện cần --name-hash-version=1"
+
+#, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
@@ -9363,7 +9384,7 @@
 
 #, c-format
 msgid "bad revision '%s'"
-msgstr "điểm xem xét sai '%s'"
+msgstr "lần cải biên sai '%s'"
 
 msgid "unable to add recent objects"
 msgstr "không thể thêm các đối tượng mới dùng"
@@ -9509,6 +9530,9 @@
 msgid "exclude any configured uploadpack.blobpackfileuri with this protocol"
 msgstr "loại trừ bất kỳ cấu hình uploadpack.blobpackfileuri với giao thức này"
 
+msgid "use the specified name-hash function to group similar objects"
+msgstr "dùng hàm băm này để nhóm các đối tượng giống nhau"
+
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
 msgstr "mức delta chain %d là quá sâu, buộc dùng %d"
@@ -10261,7 +10285,7 @@
 msgstr ""
 "\n"
 "git gặp phải một lỗi trong khi đang chuẩn bị các bản vá để diễn lại\n"
-"những điểm xét duyệt này:\n"
+"những lần cải biên này:\n"
 "\n"
 "    %s\n"
 "\n"
@@ -10750,8 +10774,8 @@
 msgid "invalid ref format: %s"
 msgstr "định dạng tham chiếu không hợp lệ: %s"
 
-msgid "git refs migrate --ref-format=<format> [--dry-run]"
-msgstr "git refs migrate --ref-format=<định dạng> [--dry-run]"
+msgid "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
+msgstr "git refs migrate --ref-format=<định dạng> [--no-reflog] [--dry-run]"
 
 msgid "git refs verify [--strict] [--verbose]"
 msgstr "git refs verify [--strict] [--verbose]"
@@ -10762,6 +10786,9 @@
 msgid "perform a non-destructive dry-run"
 msgstr "chạy thử mà không thay đổi gì"
 
+msgid "drop reflogs entirely during the migration"
+msgstr "bỏ reflog khi chuyển đổi"
+
 msgid "missing --ref-format=<format>"
 msgstr "thiếu --ref-format=<định dạng>"
 
@@ -11216,8 +11243,14 @@
 msgid "be verbose; must be placed before a subcommand"
 msgstr "chi tiết; phải được đặt trước một lệnh-con"
 
-msgid "git repack [<options>]"
-msgstr "git repack [<các tùy chọn>]"
+msgid ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
+msgstr ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<tên-pack>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
 
 msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
@@ -11293,6 +11326,10 @@
 msgid "pass --no-reuse-object to git-pack-objects"
 msgstr "chuyển --no-reuse-object cho git-pack-objects"
 
+msgid ""
+"specify the name hash version to use for grouping similar objects by path"
+msgstr "phiên bản hàm băm để nhóm đối tượng giống nhau theo đường dẫn"
+
 msgid "do not run git-update-server-info"
 msgstr "không chạy git-update-server-info"
 
@@ -11341,9 +11378,6 @@
 msgid "write a multi-pack index of the resulting packs"
 msgstr "ghi chỉ mục 'multi-pack' của các gói kết quả"
 
-msgid "pack prefix to store a pack containing pruned objects"
-msgstr "tiền tố của gói để lưu gói gồm những đối tượng đã loại bỏ"
-
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr "tiền tố của gói để lưu gói gồm những đối tượng đã lọc bỏ"
 
@@ -11560,11 +11594,8 @@
 msgid "need some commits to replay"
 msgstr "cần các chuyển giao để phát lại"
 
-msgid "--onto and --advance are incompatible"
-msgstr "--onto và --advance xung khắc"
-
 msgid "all positive revisions given must be references"
-msgstr "mọi điểm xét duyệt cộng thêm phải là tên tham chiếu"
+msgstr "mọi lần cải biên cộng thêm phải là tên tham chiếu"
 
 msgid "argument to --advance must be a reference"
 msgstr "tham số cho --advance phải là tham chiếu"
@@ -11610,11 +11641,11 @@
 "some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
 "will be forced"
 msgstr ""
-"một số tuỳ chọn duyệt qua điểm xét duyệt sẽ bị bỏ qua do bit '%s' trong "
+"một số tuỳ chọn duyệt qua lần cải biên sẽ bị bỏ qua do bit '%s' trong "
 "'struct rev_info' bị ép bật/tắt"
 
 msgid "error preparing revisions"
-msgstr "gặp lỗi khi chuẩn bị các điểm xét duyệt"
+msgstr "gặp lỗi khi chuẩn bị các lần cải biên"
 
 msgid "replaying down to root commit is not supported yet!"
 msgstr "chưa hỗ trợ phát lại đến lần chuyển giao gốc!"
@@ -11709,7 +11740,7 @@
 
 #, c-format
 msgid "Failed to resolve '%s' as a valid revision."
-msgstr "Gặp lỗi khi phân giải '%s' thành điểm xét duyệt hợp lệ."
+msgstr "Gặp lỗi khi phân giải '%s' thành lần cải biên hợp lệ."
 
 #, c-format
 msgid "Failed to resolve '%s' as a valid tree."
@@ -11742,7 +11773,7 @@
 
 #, c-format
 msgid "Could not reset index file to revision '%s'."
-msgstr "Không thể đặt lại (reset) chỉ mục thành điểm xét duyệt '%s'."
+msgstr "Không thể đặt lại (reset) chỉ mục thành lần cải biên '%s'."
 
 msgid "Could not write new index file."
 msgstr "Không thể ghi tập tin chỉ mục mới."
@@ -11784,7 +11815,7 @@
 msgstr "thiếu opt-spec trước các tuỳ chọn"
 
 msgid "Needed a single revision"
-msgstr "Cần một điểm xét duyệt đơn"
+msgstr "Cần một lần cải biên đơn"
 
 msgid ""
 "git rev-parse --parseopt [<options>] -- [<args>...]\n"
@@ -12160,7 +12191,7 @@
 #, c-format
 msgid "cannot handle more than %d rev."
 msgid_plural "cannot handle more than %d revs."
-msgstr[0] "không thể xử lý nhiều hơn %d điểm xét duyệt."
+msgstr[0] "không thể xử lý nhiều hơn %d lần cải biên."
 
 #, c-format
 msgid "'%s' is not a valid ref."
@@ -12438,7 +12469,7 @@
 
 #, c-format
 msgid "Too many revisions specified:%s"
-msgstr "Chỉ ra quá nhiều điểm xét duyệt: %s"
+msgstr "Chỉ ra quá nhiều lần cải biên: %s"
 
 msgid "No stash entries found."
 msgstr "Không tìm thấy các mục tạm cất (stash) nào."
@@ -12742,7 +12773,7 @@
 "dẫn>]"
 
 msgid "could not fetch a revision for HEAD"
-msgstr "không thể lấy về một điểm xem xét cho HEAD"
+msgstr "không thể lấy về một lần cải biên cho HEAD"
 
 #, c-format
 msgid "Synchronizing submodule url for '%s'\n"
@@ -12977,8 +13008,7 @@
 
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
-msgstr ""
-"Không tìm thấy điểm xét duyệt hiện hành trong đường dẫn mô-đun-con '%s'"
+msgstr "Không tìm thấy lần cải biên hiện hành trong đường dẫn mô-đun-con '%s'"
 
 #, c-format
 msgid "Unable to fetch in submodule path '%s'"
@@ -12986,7 +13016,7 @@
 
 #, c-format
 msgid "Unable to find %s revision in submodule path '%s'"
-msgstr "Không tìm thấy điểm xét duyệt %s trong đường dẫn mô-đun-con '%s'"
+msgstr "Không tìm thấy lần cải biên %s trong đường dẫn mô-đun-con '%s'"
 
 #, c-format
 msgid "Failed to recurse into submodule path '%s'"
@@ -13017,8 +13047,7 @@
 msgstr "dùng chiến lược hòa trộn 'rebase'"
 
 msgid "create a shallow clone truncated to the specified number of revisions"
-msgstr ""
-"tạo một bản sao nông được cắt ngắn thành số lượng điểm xét duyệt đã cho"
+msgstr "tạo một bản sao nông được cắt ngắn thành số lượng lần cải biên đã cho"
 
 msgid "parallel jobs"
 msgstr "công việc đồng thời"
@@ -14190,6 +14219,9 @@
 msgid "Create an archive of files from a named tree"
 msgstr "Tạo một kho nén các tập tin từ cây làm việc có tên"
 
+msgid "Download missing objects in a partial clone"
+msgstr "Tải về các đối tượng còn thiếu khi nhân bản một phần"
+
 msgid "Use binary search to find the commit that introduced a bug"
 msgstr "Tìm kiếm dạng nhị phân để tìm ra lần chuyển giao nào đưa ra lỗi"
 
@@ -14727,7 +14759,7 @@
 msgstr "Bố cục kho Git"
 
 msgid "Specifying revisions and ranges for Git"
-msgstr "Chỉ định điểm xét duyệt và vùng cho Git"
+msgstr "Chỉ định lần cải biên và vùng cho Git"
 
 msgid "Mounting one repository inside another"
 msgstr "Gắn một kho chứa vào trong một cái khác"
@@ -15482,7 +15514,7 @@
 
 #, c-format
 msgid "unable to resolve config blob '%s'"
-msgstr "không thể phân giải điểm xét duyệt '%s'"
+msgstr "không thể phân giải lần cải biên '%s'"
 
 msgid "unable to parse command-line config"
 msgstr "không thể đọc cấu hình dòng lệnh"
@@ -16106,6 +16138,12 @@
 msgid "invalid regex given to -I: '%s'"
 msgstr "đưa cho -I biểu thức chính quy không hợp lệ: '%s'"
 
+msgid "-G requires a non-empty argument"
+msgstr "-G cần một tham số"
+
+msgid "-S requires a non-empty argument"
+msgstr "-S cần một tham số"
+
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr "gặp lỗi khi đọc đối số tùy chọn --submodule: '%s'"
@@ -18275,6 +18313,10 @@
 msgstr "không thể ghi tập tin %s"
 
 #, c-format
+msgid "unable to write repeatedly vanishing file %s"
+msgstr "không thể ghi vào tập tin biến mất liên tục %s"
+
+#, c-format
 msgid "unable to set permission to '%s'"
 msgstr "không thể đặt quyền thành '%s'"
 
@@ -18735,7 +18777,7 @@
 
 #, c-format
 msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
-msgstr "vị trí mục xét duyệt không hợp lệ %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr "vị trí mục cải biên không hợp lệ %<PRIu64>: %<PRIu32> != %<PRIu32>"
 
 msgid "multi-pack-index reverse-index chunk is the wrong size"
 msgstr "chunk chỉ mục ngược của chỉ mục đa gói có kích thước sai"
@@ -18833,6 +18875,52 @@
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "không hiểu tùy chọn non-ascii trong chuỗi: '%s'"
 
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the long form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[=<%s>]"
+msgstr "[=<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the short form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid "[<%s>]"
+msgstr "[<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string stands for a
+#. value given to a command line option, and "<>" is there
+#. as a convention to signal that it is a placeholder
+#. (i.e. the user should substitute it with the real value).
+#. If your language uses a different convention, you can
+#. change "<%s>" part to match yours, e.g. it might use
+#. "|%s|" instead, or if the alphabet is different enough it
+#. may use "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#, c-format
+msgid " <%s>"
+msgstr " <%s>"
+
 msgid "..."
 msgstr "..."
 
@@ -18920,6 +19008,21 @@
 msgstr "gặp lỗi khi đọc cú pháp %s"
 
 #, c-format
+msgid "failed to walk children of tree %s: not found"
+msgstr "gặp lỗi khi duyệt nhánh của cây %s: không tìm thấy"
+
+#, c-format
+msgid "failed to find object %s"
+msgstr "gặp lỗi khi tìm đối tượng '%s'."
+
+#, c-format
+msgid "failed to find tag %s"
+msgstr "gặp lỗi khi tìm thẻ %s"
+
+msgid "failed to setup revision walk"
+msgstr "gặp lỗi khi thiết lập duyệt lần cải biên"
+
+#, c-format
 msgid "Could not make %s writable by group"
 msgstr "Không thể làm %s được ghi bởi nhóm"
 
@@ -19063,6 +19166,22 @@
 msgid "could not fetch %s from promisor remote"
 msgstr "không thể tải %s từ máy chủ promisor"
 
+#, c-format
+msgid "known remote named '%s' but with url '%s' instead of '%s'"
+msgstr "có máy chủ '%s' nhưng với url '%s' thay vì '%s'"
+
+#, c-format
+msgid "unknown '%s' value for '%s' config option"
+msgstr "không hiểu giá trị '%s' cho cho cấu hình '%s'"
+
+#, c-format
+msgid "unknown element '%s' from remote info"
+msgstr "không hiểu phần '%s' từ thông tin máy chủ"
+
+#, c-format
+msgid "accepted promisor remote '%s' not found"
+msgstr "không tìm thấy accepted promisor remote '%s'"
+
 msgid "object-info: expected flush after arguments"
 msgstr "object-info: cần đẩy dữ liệu lên đĩa sau các tham số"
 
@@ -19750,7 +19869,7 @@
 msgstr "từ chối cập nhật tham chiếu với tên sai '%s'"
 
 msgid "refusing to force and skip creation of reflog"
-msgstr "từ chối bỏ qua việc tạo log tham chiếu"
+msgstr "từ chối bỏ qua việc tạo reflog"
 
 #, c-format
 msgid "update_ref failed for ref '%s': %s"
@@ -19884,6 +20003,14 @@
 msgstr "refspec không hợp lệ '%s'"
 
 #, c-format
+msgid "pattern '%s' has no '*'"
+msgstr "giá trị '%s' không có '*'"
+
+#, c-format
+msgid "replacement '%s' has no '*'"
+msgstr "thay thế '%s' không có '*'"
+
+#, c-format
 msgid "invalid quoting in push-option value: '%s'"
 msgstr "sai trích dẫn trong giá trị push-option :'%s'"
 
@@ -20003,6 +20130,27 @@
 msgstr "remote-curl: không hiểu lệnh '%s' từ git"
 
 #, c-format
+msgid ""
+"reading remote from \"%s/%s\", which is nominated for removal.\n"
+"\n"
+"If you still use the \"remotes/\" directory it is recommended to\n"
+"migrate to config-based remotes:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"If you cannot, please let us know why you still need to use it by\n"
+"sending an e-mail to <git@vger.kernel.org>."
+msgstr ""
+"đang đọc máy chủ từ \"%s/%s\", đã được đề cử để loại bỏ.\n"
+"Nếu bạn vẫn còn sử dụng thư mục \"remotes\", chúng tôi khuyên bạn\n"
+"hãy chuyển đổi sang sử dụng máy chủ qua tập tin cấu hình:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"Nếu bạn không thể đổi, hãy cho chúng tôi biết tại sao bạn cần nó\n"
+"bằng cách gửi e-mail đến <git@vger.kernel.org>."
+
+#, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
 msgstr "cấu hình viết tắt máy chủ không thể bắt đầu bằng '/': %s"
 
@@ -20037,14 +20185,6 @@
 msgstr "%s theo dõi cả %s và %s"
 
 #, c-format
-msgid "key '%s' of pattern had no '*'"
-msgstr "khóa '%s' của mẫu k có '*'"
-
-#, c-format
-msgid "value '%s' of pattern has no '*'"
-msgstr "giá trị '%s' của mẫu k có '*'"
-
-#, c-format
 msgid "src refspec %s does not match any"
 msgstr "refspec (đặc tả tham chiếu) nguồn %s không khớp bất kỳ cái gì"
 
@@ -20317,7 +20457,7 @@
 msgstr "cập nhật chỉ mục với phân giải xung đột dùng lại nếu được"
 
 msgid "could not determine HEAD revision"
-msgstr "không thể dò tìm điểm xét duyệt HEAD"
+msgstr "không thể dò tìm lần cải biên HEAD"
 
 #, c-format
 msgid "failed to find tree of %s"
@@ -21456,10 +21596,10 @@
 "Use '--' to separate paths from revisions, like this:\n"
 "'git <command> [<revision>...] -- [<file>...]'"
 msgstr ""
-"tham số chưa rõ ràng '%s': chưa biết điểm xét duyệt hay đường dẫn không "
-"trong cây làm việc.\n"
-"Dùng '--' để ngăn cách các đường dẫn khỏi điểm xét duyệt, như thế này:\n"
-"'git <lệnh> [<điểm xét duyệt>...] -- [<tập tin>...]'"
+"tham số chưa rõ ràng '%s': chưa biết lần cải biên hay đường dẫn không trong "
+"cây làm việc.\n"
+"Dùng '--' để ngăn cách các đường dẫn khỏi lần cải biên, như thế này:\n"
+"'git <lệnh> [<lần cải biên>...] -- [<tập tin>...]'"
 
 #, c-format
 msgid "option '%s' must come before non-option arguments"
@@ -21471,9 +21611,9 @@
 "Use '--' to separate paths from revisions, like this:\n"
 "'git <command> [<revision>...] -- [<file>...]'"
 msgstr ""
-"tham số chưa rõ ràng '%s': cả điểm xem xét và tên tập tin.\n"
-"Dùng '--' để ngăn cách các đường dẫn khỏi điểm xem xét, như thế này:\n"
-"'git <lệnh> [<điểm xem xét>...] -- [<tập tin>...]'"
+"tham số chưa rõ ràng '%s': cả lần cải biên và tên tập tin.\n"
+"Dùng '--' để ngăn cách các đường dẫn khỏi lần cải biên, như thế này:\n"
+"'git <lệnh> [<lần cải biên>...] -- [<tập tin>...]'"
 
 msgid "unable to set up work tree using invalid config"
 msgstr "không thể thiết lập thư mục làm việc với cấu hình không hợp lệ"
@@ -21935,6 +22075,27 @@
 msgid "number of entries in the cache tree to invalidate (default 0)"
 msgstr "số mục cần huỷ trong câu nhớ tạm (mặc định 0)"
 
+msgid "test-tool path-walk <options> -- <revision-options>"
+msgstr "test-tool path-walk <tuỳ chọn> -- <tuỳ chọn cải biên>"
+
+msgid "toggle inclusion of blob objects"
+msgstr "bao gồm các đối tượng blob"
+
+msgid "toggle inclusion of commit objects"
+msgstr "bao gồm các đối tượng chuyển giao"
+
+msgid "toggle inclusion of tag objects"
+msgstr "bao gồm các đối tượng thẻ"
+
+msgid "toggle inclusion of tree objects"
+msgstr "bao gồm các đối tượng cây"
+
+msgid "toggle pruning of uninteresting paths"
+msgstr "lược bỏ những đường dẫn ít ý nghĩa"
+
+msgid "read a pattern list over stdin"
+msgstr "đọc các mẫu từ stdin"
+
 #, c-format
 msgid "commit %s is not marked reachable"
 msgstr "lần chuyển giao %s chưa được đánh dấu là tiếp cận được"
@@ -22579,6 +22740,10 @@
 msgid "warning: "
 msgstr "cảnh báo: "
 
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "uname() gặp lỗi '%s' (%d)\n"
+
 msgid "Fetching objects"
 msgstr "Đang lấy về các đối tượng"
 
@@ -23536,3 +23701,21 @@
 #, perl-format
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Bạn có thực sự muốn gửi %s? [y|N](có/KHÔNG): "
+
+#, c-format
+#~ msgid "Could not find remote branch %s to clone."
+#~ msgstr "Không tìm thấy nhánh máy chủ %s để nhân bản (clone)."
+
+#, c-format
+#~ msgid "merging cannot continue; got unclean result of %d"
+#~ msgstr "không thể tiếp tục hoà trộn; kết quả không hoàn toàn %d"
+
+#~ msgid "git repack [<options>]"
+#~ msgstr "git repack [<các tùy chọn>]"
+
+#~ msgid "--onto and --advance are incompatible"
+#~ msgstr "--onto và --advance xung khắc"
+
+#, c-format
+#~ msgid "key '%s' of pattern had no '*'"
+#~ msgstr "khóa '%s' của mẫu k có '*'"
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 12a0fb5..5cde401 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -93,6 +93,7 @@
 #   pack index                       |  包索引
 #   packfile                         |  包文件
 #   parent                           |  父提交
+#   partial clone                    |  部分克隆
 #   patch                            |  补丁
 #   pathspec                         |  路径规格
 #   pattern                          |  模式
@@ -154,8 +155,8 @@
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2025-01-02 20:43+0800\n"
-"PO-Revision-Date: 2025-01-05 19:01+0800\n"
+"POT-Creation-Date: 2025-03-09 20:34+0800\n"
+"PO-Revision-Date: 2025-03-12 14:47+0800\n"
 "Last-Translator: Teng Long <dyroneteng@gmail.com>\n"
 "Language-Team: GitHub <https://github.com/dyrone/git/>\n"
 "Language: zh_CN\n"
@@ -2962,6 +2963,22 @@
 msgid "git archive: expected a flush"
 msgstr "git archive:应有一个 flush 包"
 
+#: builtin/backfill.c
+msgid "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+msgstr "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+
+#: builtin/backfill.c
+msgid "problem loading sparse-checkout"
+msgstr "加载稀疏检出时出现问题"
+
+#: builtin/backfill.c
+msgid "Minimum number of objects to request at a time"
+msgstr "单次请求的最少对象数量"
+
+#: builtin/backfill.c
+msgid "Restrict the missing objects to the current sparse-checkout"
+msgstr "将缺少的对象限制在当前的稀疏检出中"
+
 #: builtin/bisect.c
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
@@ -3381,7 +3398,7 @@
 msgid "ignore whitespace differences"
 msgstr "忽略空白差异"
 
-#: builtin/blame.c builtin/log.c
+#: builtin/blame.c builtin/clone.c builtin/log.c
 msgid "rev"
 msgstr "版本"
 
@@ -3803,8 +3820,8 @@
 
 #: builtin/branch.c
 msgid ""
-"branch with --recurse-submodules can only be used if submodule."
-"propagateBranches is enabled"
+"branch with --recurse-submodules can only be used if "
+"submodule.propagateBranches is enabled"
 msgstr ""
 "带有 --recurse-submodules 的分支只能在 submodule.propagateBranches 启用时使用"
 
@@ -3892,11 +3909,6 @@
 msgstr "git 版本:\n"
 
 #: builtin/bugreport.c
-#, c-format
-msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() 失败,错误为 '%s'(%d)\n"
-
-#: builtin/bugreport.c
 msgid "compiler info: "
 msgstr "编译器信息:"
 
@@ -5134,8 +5146,112 @@
 msgstr "clean.requireForce 设置为 true 且未提供 -f 选项:拒绝执行清理动作"
 
 #: builtin/clone.c
-msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<选项>] [--] <仓库> [<路径>]"
+#, c-format
+msgid "info: Could not add alternate for '%s': %s\n"
+msgstr "info: 不能为 '%s' 添加一个备用:%s\n"
+
+#: builtin/clone.c builtin/diff.c builtin/rm.c grep.c setup.c
+#, c-format
+msgid "failed to stat '%s'"
+msgstr "无法对 '%s' 调用 stat"
+
+#: builtin/clone.c
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr "%s 存在且不是一个目录"
+
+#: builtin/clone.c
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "'%s' 为符号链接,拒绝用 --local 克隆"
+
+#: builtin/clone.c
+#, c-format
+msgid "failed to start iterator over '%s'"
+msgstr "无法在 '%s' 上启动迭代器"
+
+#: builtin/clone.c
+#, c-format
+msgid "symlink '%s' exists, refusing to clone with --local"
+msgstr "符号链接 '%s' 存在,拒绝用 --local 克隆"
+
+#: builtin/clone.c compat/precompose_utf8.c
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "无法删除 '%s'"
+
+#: builtin/clone.c
+#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "无法检查 '%s' 处的硬链接"
+
+#: builtin/clone.c
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "硬链接与 '%s' 处的来源不同"
+
+#: builtin/clone.c
+#, c-format
+msgid "failed to create link '%s'"
+msgstr "无法创建链接 '%s'"
+
+#: builtin/clone.c
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr "无法拷贝文件至 '%s'"
+
+#: builtin/clone.c refs/files-backend.c
+#, c-format
+msgid "failed to iterate over '%s'"
+msgstr "无法在 '%s' 上迭代"
+
+#: builtin/clone.c
+#, c-format
+msgid "done.\n"
+msgstr "完成。\n"
+
+#: builtin/clone.c
+msgid ""
+"Clone succeeded, but checkout failed.\n"
+"You can inspect what was checked out with 'git status'\n"
+"and retry with 'git restore --source=HEAD :/'\n"
+msgstr ""
+"克隆成功,但是检出失败。\n"
+"您可以通过 'git status' 检查哪些已被检出,然后使用命令\n"
+"'git restore --source=HEAD :/' 重试\n"
+
+#: builtin/clone.c fetch-pack.c
+msgid "remote did not send all necessary objects"
+msgstr "远程没有发送所有必需的对象"
+
+#: builtin/clone.c
+#, c-format
+msgid "unable to update %s"
+msgstr "不能更新 %s"
+
+#: builtin/clone.c
+msgid "failed to initialize sparse-checkout"
+msgstr "无法初始化稀疏检出"
+
+#: builtin/clone.c
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
+msgstr "远程 HEAD 指向一个不存在的引用,无法检出"
+
+#: builtin/clone.c
+msgid "unable to checkout working tree"
+msgstr "不能检出工作区"
+
+#: builtin/clone.c
+msgid "unable to write parameters to config file"
+msgstr "无法将参数写入配置文件"
+
+#: builtin/clone.c
+msgid "cannot repack to clean up"
+msgstr "无法执行 repack 来清理"
+
+#: builtin/clone.c
+msgid "cannot unlink temporary alternates file"
+msgstr "无法删除临时的备用文件"
 
 #: builtin/clone.c
 msgid "don't clone shallow repository"
@@ -5208,6 +5324,10 @@
 msgstr "检出 <分支> 而不是远程 HEAD"
 
 #: builtin/clone.c
+msgid "clone single revision <rev> and check out"
+msgstr "克隆单个版本 <版本> 并检出"
+
+#: builtin/clone.c
 msgid "path to git-upload-pack on the remote"
 msgstr "远程 git-upload-pack 路径"
 
@@ -5236,8 +5356,8 @@
 msgstr "只克隆一个分支、HEAD 或 --branch"
 
 #: builtin/clone.c
-msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr "不要克隆任何标签,并且后续获取操作也不下载它们"
+msgid "clone tags, and make later fetches not to follow them"
+msgstr "克隆标签,并在后续获取时不跟随它们"
 
 #: builtin/clone.c
 msgid "any cloned submodules will be shallow"
@@ -5294,117 +5414,8 @@
 msgstr "用于在从 origin 远程获取之前下载归档包的 URI"
 
 #: builtin/clone.c
-#, c-format
-msgid "info: Could not add alternate for '%s': %s\n"
-msgstr "info: 不能为 '%s' 添加一个备用:%s\n"
-
-#: builtin/clone.c builtin/diff.c builtin/rm.c grep.c setup.c
-#, c-format
-msgid "failed to stat '%s'"
-msgstr "无法对 '%s' 调用 stat"
-
-#: builtin/clone.c
-#, c-format
-msgid "%s exists and is not a directory"
-msgstr "%s 存在且不是一个目录"
-
-#: builtin/clone.c
-#, c-format
-msgid "'%s' is a symlink, refusing to clone with --local"
-msgstr "'%s' 为符号链接,拒绝用 --local 克隆"
-
-#: builtin/clone.c
-#, c-format
-msgid "failed to start iterator over '%s'"
-msgstr "无法在 '%s' 上启动迭代器"
-
-#: builtin/clone.c
-#, c-format
-msgid "symlink '%s' exists, refusing to clone with --local"
-msgstr "符号链接 '%s' 存在,拒绝用 --local 克隆"
-
-#: builtin/clone.c compat/precompose_utf8.c
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "无法删除 '%s'"
-
-#: builtin/clone.c
-#, c-format
-msgid "hardlink cannot be checked at '%s'"
-msgstr "无法检查 '%s' 处的硬链接"
-
-#: builtin/clone.c
-#, c-format
-msgid "hardlink different from source at '%s'"
-msgstr "硬链接与 '%s' 处的源不同"
-
-#: builtin/clone.c
-#, c-format
-msgid "failed to create link '%s'"
-msgstr "无法创建链接 '%s'"
-
-#: builtin/clone.c
-#, c-format
-msgid "failed to copy file to '%s'"
-msgstr "无法拷贝文件至 '%s'"
-
-#: builtin/clone.c refs/files-backend.c
-#, c-format
-msgid "failed to iterate over '%s'"
-msgstr "无法在 '%s' 上迭代"
-
-#: builtin/clone.c
-#, c-format
-msgid "done.\n"
-msgstr "完成。\n"
-
-#: builtin/clone.c
-msgid ""
-"Clone succeeded, but checkout failed.\n"
-"You can inspect what was checked out with 'git status'\n"
-"and retry with 'git restore --source=HEAD :/'\n"
-msgstr ""
-"克隆成功,但是检出失败。\n"
-"您可以通过 'git status' 检查哪些已被检出,然后使用命令\n"
-"'git restore --source=HEAD :/' 重试\n"
-
-#: builtin/clone.c
-#, c-format
-msgid "Could not find remote branch %s to clone."
-msgstr "不能发现要克隆的远程分支 %s。"
-
-#: builtin/clone.c fetch-pack.c
-msgid "remote did not send all necessary objects"
-msgstr "远程没有发送所有必需的对象"
-
-#: builtin/clone.c
-#, c-format
-msgid "unable to update %s"
-msgstr "不能更新 %s"
-
-#: builtin/clone.c
-msgid "failed to initialize sparse-checkout"
-msgstr "无法初始化稀疏检出"
-
-#: builtin/clone.c
-msgid "remote HEAD refers to nonexistent ref, unable to checkout"
-msgstr "远程 HEAD 指向一个不存在的引用,无法检出"
-
-#: builtin/clone.c
-msgid "unable to checkout working tree"
-msgstr "不能检出工作区"
-
-#: builtin/clone.c
-msgid "unable to write parameters to config file"
-msgstr "无法将参数写入配置文件"
-
-#: builtin/clone.c
-msgid "cannot repack to clean up"
-msgstr "无法执行 repack 来清理"
-
-#: builtin/clone.c
-msgid "cannot unlink temporary alternates file"
-msgstr "无法删除临时的 alternates 文件"
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [<选项>] [--] <仓库> [<目录>]"
 
 #: builtin/clone.c
 msgid "Too many arguments."
@@ -5531,6 +5542,11 @@
 msgstr "远程分支 %s 在上游 %s 未发现"
 
 #: builtin/clone.c
+#, c-format
+msgid "Remote revision %s not found in upstream %s"
+msgstr "在上游 %2$s 未发现远程版本 %1$s"
+
+#: builtin/clone.c
 msgid "You appear to have cloned an empty repository."
 msgstr "您似乎克隆了一个空仓库。"
 
@@ -5593,7 +5609,8 @@
 "[no-]progress]\n"
 "                       <切分选项>"
 
-#: builtin/commit-graph.c builtin/fetch.c builtin/log.c builtin/repack.c
+#: builtin/commit-graph.c builtin/fetch.c builtin/gc.c builtin/log.c
+#: builtin/repack.c
 msgid "dir"
 msgstr "目录"
 
@@ -5751,7 +5768,7 @@
 
 #: builtin/commit.c
 msgid ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -5761,7 +5778,7 @@
 "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
 "           [--] [<pathspec>...]"
 msgstr ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<模式>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<模式>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <提交> | --fixup [(amend|"
 "reword):]<提交>]\n"
 "           [-F <文件> | -m <消息>] [--reset-author] [--allow-empty]\n"
@@ -7473,14 +7490,13 @@
 "Run 'git remote set-head %s %s' to follow the change, or set\n"
 "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
 "if you do not want to see this message. Specifically running\n"
-"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
-"until the remote changes HEAD to something else."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"will disable the warning until the remote changes HEAD to something else."
 msgstr ""
-"运行 'git remote set-head %s %s' 以跟随更改,或者\n"
-"如果您不想看到此消息,则将'remote.%s.followRemoteHEAD' 配置选项设置为不同的"
-"值。\n"
-"特别地,运行 'git config set remote.%s.followRemoteHEAD %s' 将禁用警告,直到"
-"远程将 HEAD 更改为其他内容。\""
+"运行 'git remote set-head %s %s' 同步变更,或通过配置选项\n"
+"'remote.%s.followRemoteHEAD' 设置为其他值以屏蔽此提示。具体可通过\n"
+"运行命令 'git config remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"以禁用该警告,直到远程将 HEAD 更改为其他内容。"
 
 #: builtin/fetch.c
 msgid "multiple branches detected, incompatible with --set-upstream"
@@ -7721,8 +7737,8 @@
 
 #: builtin/fetch.c
 msgid ""
-"--filter can only be used with the remote configured in extensions."
-"partialclone"
+"--filter can only be used with the remote configured in "
+"extensions.partialclone"
 msgstr "只可以将 --filter 用于在 extensions.partialclone 中配置的远程仓库"
 
 #: builtin/fetch.c
@@ -8328,6 +8344,10 @@
 msgid "repack all other packs except the largest pack"
 msgstr "除了最大的包之外,对所有其它包文件重新打包"
 
+#: builtin/gc.c builtin/repack.c
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "用于存储修剪对象的包前缀"
+
 #: builtin/gc.c
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
@@ -9327,6 +9347,11 @@
 msgid "Cannot come back to cwd"
 msgstr "无法返回当前工作目录"
 
+#: builtin/index-pack.c builtin/unpack-objects.c
+#, c-format
+msgid "bad --pack_header: %s"
+msgstr "错误的 --pack_header:%s"
+
 #: builtin/index-pack.c
 #, c-format
 msgid "bad %s"
@@ -10432,11 +10457,6 @@
 msgid "malformed input line: '%s'."
 msgstr "格式错误的输入行:'%s'。"
 
-#: builtin/merge-tree.c
-#, c-format
-msgid "merging cannot continue; got unclean result of %d"
-msgstr "合并无法继续;得到不干净的结果 %d"
-
 #: builtin/merge.c
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<选项>] [<提交>...]"
@@ -11454,6 +11474,15 @@
 
 #: builtin/pack-objects.c
 #, c-format
+msgid "invalid --name-hash-version option: %d"
+msgstr "无效的 --name-hash-version 选项:%d"
+
+#: builtin/pack-objects.c
+msgid "currently, --write-bitmap-index requires --name-hash-version=1"
+msgstr "当前,--write-bitmap-index 要求 --name-hash-version=1"
+
+#: builtin/pack-objects.c
+#, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
@@ -11857,7 +11886,11 @@
 
 #: builtin/pack-objects.c
 msgid "exclude any configured uploadpack.blobpackfileuri with this protocol"
-msgstr "使用此协议排除任何已配置的 uploadpack.blobpackfileuri"
+msgstr "排除掉采用该协议的 uploadpack.blobpackfileuri 配置项"
+
+#: builtin/pack-objects.c
+msgid "use the specified name-hash function to group similar objects"
+msgstr "使用指定的名称哈希函数对相似的对象进行分组"
 
 #: builtin/pack-objects.c
 #, c-format
@@ -12284,8 +12317,8 @@
 "upstream, see 'push.autoSetupRemote' in 'git help config'.\n"
 msgstr ""
 "\n"
-"为了让没有追踪上游的分支自动配置,参见 'git help config' 中的 push."
-"autoSetupRemote。\n"
+"为了让没有追踪上游的分支自动配置,参见 'git help config' 中的 "
+"push.autoSetupRemote。\n"
 
 #: builtin/push.c
 #, c-format
@@ -13294,8 +13327,8 @@
 msgstr "无效的引用格式:%s"
 
 #: builtin/refs.c
-msgid "git refs migrate --ref-format=<format> [--dry-run]"
-msgstr "git refs migrate --ref-format=<格式> [--dry-run]"
+msgid "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
+msgstr "git refs migrate --ref-format=<格式> [--no-reflog] [--dry-run]"
 
 #: builtin/refs.c
 msgid "git refs verify [--strict] [--verbose]"
@@ -13310,6 +13343,10 @@
 msgstr "进行非破坏性的试运行(dry-run)"
 
 #: builtin/refs.c
+msgid "drop reflogs entirely during the migration"
+msgstr "在迁移期间丢弃引用日志"
+
+#: builtin/refs.c
 msgid "missing --ref-format=<format>"
 msgstr "缺少 --ref-format=<格式>"
 
@@ -13881,8 +13918,14 @@
 msgstr "冗长输出;必须置于子命令之前"
 
 #: builtin/repack.c
-msgid "git repack [<options>]"
-msgstr "git repack [<选项>]"
+msgid ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
+msgstr ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<包名>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
 
 #: builtin/repack.c
 msgid ""
@@ -13975,6 +14018,11 @@
 msgstr "向 git-pack-objects 传递参数 --no-reuse-object"
 
 #: builtin/repack.c
+msgid ""
+"specify the name hash version to use for grouping similar objects by path"
+msgstr "指定要使用的名称哈希算法,以实现按照路径对相似对象分组"
+
+#: builtin/repack.c
 msgid "do not run git-update-server-info"
 msgstr "不运行 git-update-server-info"
 
@@ -14039,10 +14087,6 @@
 msgstr "写入结果包的多包索引"
 
 #: builtin/repack.c
-msgid "pack prefix to store a pack containing pruned objects"
-msgstr "储存被清除的对象的包的前缀"
-
-#: builtin/repack.c
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr "储存被过滤的对象的包的前缀"
 
@@ -14315,10 +14359,6 @@
 msgstr "需要一些提交来重放"
 
 #: builtin/replay.c
-msgid "--onto and --advance are incompatible"
-msgstr "--onto 和 --advance 不兼容"
-
-#: builtin/replay.c
 msgid "all positive revisions given must be references"
 msgstr "提供的所有正向版本必须为引用"
 
@@ -17546,6 +17586,10 @@
 msgstr "基于一个指定的树创建文件存档"
 
 #: command-list.h
+msgid "Download missing objects in a partial clone"
+msgstr "下载部分克隆中缺失的对象"
+
+#: command-list.h
 msgid "Use binary search to find the commit that introduced a bug"
 msgstr "通过二分查找定位引入 bug 的提交"
 
@@ -18927,8 +18971,8 @@
 "remote URLs cannot be configured in file directly or indirectly included by "
 "includeIf.hasconfig:remote.*.url"
 msgstr ""
-"远程 URL 不能在文件中配置,不管直接地还是通过 includeIf.hasconfig:remote.*."
-"url 间接地包含。"
+"远程 URL 不能在文件中配置,不管直接地还是通过 "
+"includeIf.hasconfig:remote.*.url 间接地包含。"
 
 #: config.c
 #, c-format
@@ -19926,6 +19970,14 @@
 msgstr "选项 -I 的正则表达式无效:'%s'"
 
 #: diff.c
+msgid "-G requires a non-empty argument"
+msgstr "-G 需要一个非空参数"
+
+#: diff.c
+msgid "-S requires a non-empty argument"
+msgstr "-S 需要一个非空参数"
+
+#: diff.c
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr "无法解析 --submodule 选项的参数:'%s'"
@@ -22430,7 +22482,7 @@
 
 #: object-file.c
 msgid "unable to move new alternates file into place"
-msgstr "无法将新的替代文件移动到位"
+msgstr "无法将新的备用文件移动到位"
 
 #: object-file.c
 #, c-format
@@ -22553,6 +22605,11 @@
 
 #: object-file.c
 #, c-format
+msgid "unable to write repeatedly vanishing file %s"
+msgstr "无法写入反复消失的文件 %s"
+
+#: object-file.c
+#, c-format
 msgid "unable to set permission to '%s'"
 msgstr "无法为 '%s' 设置权限"
 
@@ -23233,6 +23290,55 @@
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "字符串中未知的非 ascii 字符选项:`%s'"
 
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the long form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#: parse-options.c
+#, c-format
+msgid "[=<%s>]"
+msgstr "[=<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the short form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#: parse-options.c
+#, c-format
+msgid "[<%s>]"
+msgstr "[<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string stands for a
+#. value given to a command line option, and "<>" is there
+#. as a convention to signal that it is a placeholder
+#. (i.e. the user should substitute it with the real value).
+#. If your language uses a different convention, you can
+#. change "<%s>" part to match yours, e.g. it might use
+#. "|%s|" instead, or if the alphabet is different enough it
+#. may use "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#: parse-options.c
+#, c-format
+msgid " <%s>"
+msgstr " <%s>"
+
 #: parse-options.c
 msgid "..."
 msgstr "..."
@@ -23336,6 +23442,25 @@
 msgid "failed to parse %s"
 msgstr "无法解析 %s"
 
+#: path-walk.c
+#, c-format
+msgid "failed to walk children of tree %s: not found"
+msgstr "无法遍历树 %s 的子节点:未找到"
+
+#: path-walk.c
+#, c-format
+msgid "failed to find object %s"
+msgstr "无法找到对象 %s"
+
+#: path-walk.c
+#, c-format
+msgid "failed to find tag %s"
+msgstr "无法找到标签 %s"
+
+#: path-walk.c
+msgid "failed to setup revision walk"
+msgstr "无法设置版本遍历"
+
 #: path.c
 #, c-format
 msgid "Could not make %s writable by group"
@@ -23517,6 +23642,26 @@
 msgid "could not fetch %s from promisor remote"
 msgstr "无法从承诺者远程获取 %s"
 
+#: promisor-remote.c
+#, c-format
+msgid "known remote named '%s' but with url '%s' instead of '%s'"
+msgstr "已知远程名称为 '%s',但 url 为 '%s' 而不是 '%s'"
+
+#: promisor-remote.c
+#, c-format
+msgid "unknown '%s' value for '%s' config option"
+msgstr "配置项 '%2$s' 为未知的取值 '%1$s'"
+
+#: promisor-remote.c
+#, c-format
+msgid "unknown element '%s' from remote info"
+msgstr "远程信息中的未知元素 '%s'"
+
+#: promisor-remote.c
+#, c-format
+msgid "accepted promisor remote '%s' not found"
+msgstr "未找到已接受的承诺者远程 '%s'"
+
 #: protocol-caps.c
 msgid "object-info: expected flush after arguments"
 msgstr "object-info:在参数之后应有一个 flush"
@@ -24484,6 +24629,16 @@
 msgid "invalid refspec '%s'"
 msgstr "无效的引用规格:'%s'"
 
+#: refspec.c
+#, c-format
+msgid "pattern '%s' has no '*'"
+msgstr "模式 '%s' 没有 '*'"
+
+#: refspec.c
+#, c-format
+msgid "replacement '%s' has no '*'"
+msgstr "替换 '%s' 没有 '*'"
+
 #: remote-curl.c
 #, c-format
 msgid "invalid quoting in push-option value: '%s'"
@@ -24637,6 +24792,28 @@
 
 #: remote.c
 #, c-format
+msgid ""
+"reading remote from \"%s/%s\", which is nominated for removal.\n"
+"\n"
+"If you still use the \"remotes/\" directory it is recommended to\n"
+"migrate to config-based remotes:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"If you cannot, please let us know why you still need to use it by\n"
+"sending an e-mail to <git@vger.kernel.org>."
+msgstr ""
+"正在从 \"%s/%s\" 读取远程内容,该内容被提名删除。\n"
+"\n"
+"如果你仍然在使用 \"remotes/\" 目录,建议迁移为基于配置远程的方式:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"如果你无法迁移,请发送电子邮件至 <git@vger.kernel.org> 告知我们你\n"
+"仍然需要使用它的原因。"
+
+#: remote.c
+#, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
 msgstr "配置的远程短名称不能以 '/' 开始:%s"
 
@@ -24680,16 +24857,6 @@
 
 #: remote.c
 #, c-format
-msgid "key '%s' of pattern had no '*'"
-msgstr "模式的键 '%s' 没有 '*'"
-
-#: remote.c
-#, c-format
-msgid "value '%s' of pattern has no '*'"
-msgstr "模式的值 '%s' 没有 '*'"
-
-#: remote.c
-#, c-format
 msgid "src refspec %s does not match any"
 msgstr "源引用规格 %s 没有匹配"
 
@@ -26956,6 +27123,34 @@
 msgid "number of entries in the cache tree to invalidate (default 0)"
 msgstr "缓存树中无效化的条目数量(默认 0)"
 
+#: t/helper/test-path-walk.c
+msgid "test-tool path-walk <options> -- <revision-options>"
+msgstr "test-tool path-walk <选项> -- <版本选项>"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of blob objects"
+msgstr "切换是否包含数据对象"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of commit objects"
+msgstr "切换是否包含提交对象"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of tag objects"
+msgstr "切换是否包含标签对象"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of tree objects"
+msgstr "切换是否包含树对象"
+
+#: t/helper/test-path-walk.c
+msgid "toggle pruning of uninteresting paths"
+msgstr "切换对无趣路径的修剪"
+
+#: t/helper/test-path-walk.c
+msgid "read a pattern list over stdin"
+msgstr "从标准输入读取模式列表"
+
 #: t/helper/test-reach.c
 #, c-format
 msgid "commit %s is not marked reachable"
@@ -27703,6 +27898,11 @@
 msgid "warning: "
 msgstr "警告:"
 
+#: version.c
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "uname() 失败,错误为 '%s'(%d)\n"
+
 #: walker.c
 msgid "Fetching objects"
 msgstr "正在获取对象"
diff --git a/po/zh_TW.po b/po/zh_TW.po
index a61f544..aa74d65 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -30,8 +30,8 @@
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-12-28 13:16+0800\n"
-"PO-Revision-Date: 2024-12-28 13:23+0800\n"
+"POT-Creation-Date: 2025-03-09 10:39+0800\n"
+"PO-Revision-Date: 2025-03-09 10:52+0800\n"
 "Last-Translator: Yi-Jyun Pan <pan93412@gmail.com>\n"
 "Language-Team: Chinese (Traditional) <http://weblate.slat.org/projects/git-"
 "po/git-cli/zh_Hant/>\n"
@@ -2841,6 +2841,22 @@
 msgid "git archive: expected a flush"
 msgstr "git archive:預期收到 flush 封包"
 
+#: builtin/backfill.c
+msgid "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+msgstr "git backfill [--min-batch-size=<n>] [--[no-]sparse]"
+
+#: builtin/backfill.c
+msgid "problem loading sparse-checkout"
+msgstr "載入稀疏簽出時發生問題"
+
+#: builtin/backfill.c
+msgid "Minimum number of objects to request at a time"
+msgstr "一次請求的最小物件數量"
+
+#: builtin/backfill.c
+msgid "Restrict the missing objects to the current sparse-checkout"
+msgstr "將缺少的物件限制於目前的稀疏簽出"
+
 #: builtin/bisect.c
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
@@ -2872,22 +2888,22 @@
 #: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
-msgstr "無法以「%2$s」模式開啟「%1$s」檔案"
+msgstr "無法以「%2$s」模式開啟檔案「%1$s」"
 
 #: builtin/bisect.c
 #, c-format
 msgid "could not write to file '%s'"
-msgstr "無法寫入「%s」檔案"
+msgstr "無法寫入檔案「%s」"
 
 #: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' for reading"
-msgstr "無法開啟「%s」檔案進行讀取"
+msgstr "無法開啟檔案「%s」來讀取"
 
 #: builtin/bisect.c
 #, c-format
 msgid "'%s' is not a valid term"
-msgstr "「%s」不是有效術語"
+msgstr "「%s」不是有效的術語"
 
 #: builtin/bisect.c
 #, c-format
@@ -2917,7 +2933,7 @@
 #, c-format
 msgid ""
 "could not check out original HEAD '%s'. Try 'git bisect reset <commit>'."
-msgstr "無法簽出原始 HEAD「%s」。請嘗試「git bisect reset <commit>」。"
+msgstr "無法簽出原本的 HEAD「%s」。請嘗試「git bisect reset <commit>」。"
 
 #: builtin/bisect.c
 #, c-format
@@ -2937,7 +2953,7 @@
 #: builtin/bisect.c
 #, c-format
 msgid "Invalid command: you're currently in a %s/%s bisect"
-msgstr "命令無效:您目前正處於二分搜尋 %s/%s 的狀態"
+msgstr "命令無效:您正處於二分搜尋 %s/%s 的狀態"
 
 #: builtin/bisect.c
 #, c-format
@@ -3263,7 +3279,7 @@
 msgid "ignore whitespace differences"
 msgstr "忽略空白差異"
 
-#: builtin/blame.c builtin/log.c
+#: builtin/blame.c builtin/clone.c builtin/log.c
 msgid "rev"
 msgstr "rev"
 
@@ -3776,11 +3792,6 @@
 msgstr "git 版本:\n"
 
 #: builtin/bugreport.c
-#, c-format
-msgid "uname() failed with error '%s' (%d)\n"
-msgstr "uname() 失敗,錯誤:「%s」(%d)\n"
-
-#: builtin/bugreport.c
 msgid "compiler info: "
 msgstr "編譯器資訊: "
 
@@ -5010,8 +5021,112 @@
 msgstr "clean.requireForce 是 true 且未給定 -f 選項:拒絕清理"
 
 #: builtin/clone.c
-msgid "git clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<options>] [--] <repo> [<dir>]"
+#, c-format
+msgid "info: Could not add alternate for '%s': %s\n"
+msgstr "info: 不能為「%s」新增一個備用:%s\n"
+
+#: builtin/clone.c builtin/diff.c builtin/rm.c grep.c setup.c
+#, c-format
+msgid "failed to stat '%s'"
+msgstr "對「%s」呼叫 stat 失敗"
+
+#: builtin/clone.c
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr "%s 存在且不是目錄"
+
+#: builtin/clone.c
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr "「%s」是符號連結,故不能使用 --local 複製"
+
+#: builtin/clone.c
+#, c-format
+msgid "failed to start iterator over '%s'"
+msgstr "無法在「%s」上啟動迭代器"
+
+#: builtin/clone.c
+#, c-format
+msgid "symlink '%s' exists, refusing to clone with --local"
+msgstr "符號連結「%s」已存在,拒絕使用 --local 複製"
+
+#: builtin/clone.c compat/precompose_utf8.c
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "無法刪除「%s」"
+
+#: builtin/clone.c
+#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "無法檢查位於「%s」的硬連結"
+
+#: builtin/clone.c
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "硬連結與位於「%s」的來源不同"
+
+#: builtin/clone.c
+#, c-format
+msgid "failed to create link '%s'"
+msgstr "建立連結「%s」失敗"
+
+#: builtin/clone.c
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr "複製檔案至「%s」失敗"
+
+#: builtin/clone.c refs/files-backend.c
+#, c-format
+msgid "failed to iterate over '%s'"
+msgstr "無法在「%s」上迭代"
+
+#: builtin/clone.c
+#, c-format
+msgid "done.\n"
+msgstr "完成。\n"
+
+#: builtin/clone.c
+msgid ""
+"Clone succeeded, but checkout failed.\n"
+"You can inspect what was checked out with 'git status'\n"
+"and retry with 'git restore --source=HEAD :/'\n"
+msgstr ""
+"複製成功,但是簽出失敗。\n"
+"您可以透過「git status」檢查哪些已被簽出,然後使用指令\n"
+"「git restore --source=HEAD :/」重試\n"
+
+#: builtin/clone.c fetch-pack.c
+msgid "remote did not send all necessary objects"
+msgstr "遠端沒有傳送所有必需的物件"
+
+#: builtin/clone.c
+#, c-format
+msgid "unable to update %s"
+msgstr "不能更新 %s"
+
+#: builtin/clone.c
+msgid "failed to initialize sparse-checkout"
+msgstr "無法初始化稀疏簽出"
+
+#: builtin/clone.c
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
+msgstr "遠端 HEAD 指向不存在的引用,無法簽出"
+
+#: builtin/clone.c
+msgid "unable to checkout working tree"
+msgstr "不能簽出工作區"
+
+#: builtin/clone.c
+msgid "unable to write parameters to config file"
+msgstr "無法將參數寫入組態檔案"
+
+#: builtin/clone.c
+msgid "cannot repack to clean up"
+msgstr "無法執行 repack 來清理"
+
+#: builtin/clone.c
+msgid "cannot unlink temporary alternates file"
+msgstr "無法刪除暫存 alternates 檔案"
 
 #: builtin/clone.c
 msgid "don't clone shallow repository"
@@ -5084,6 +5199,10 @@
 msgstr "簽出 <branch> 而不是遠端 HEAD"
 
 #: builtin/clone.c
+msgid "clone single revision <rev> and check out"
+msgstr "複製單個修訂版 <rev> 並簽出"
+
+#: builtin/clone.c
 msgid "path to git-upload-pack on the remote"
 msgstr "遠端 git-upload-pack 路徑"
 
@@ -5112,8 +5231,8 @@
 msgstr "只複製一個分支、HEAD 或 --branch"
 
 #: builtin/clone.c
-msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr "不要複製任何標籤,之後取得也不要追蹤這些標籤"
+msgid "clone tags, and make later fetches not to follow them"
+msgstr "複製標籤,並使後續抓取不要追蹤這些標籤"
 
 #: builtin/clone.c
 msgid "any cloned submodules will be shallow"
@@ -5170,117 +5289,8 @@
 msgstr "在從 origin 遠端抓取前,用來下載套件包的 URI"
 
 #: builtin/clone.c
-#, c-format
-msgid "info: Could not add alternate for '%s': %s\n"
-msgstr "info: 不能為 '%s' 新增一個備用:%s\n"
-
-#: builtin/clone.c builtin/diff.c builtin/rm.c grep.c setup.c
-#, c-format
-msgid "failed to stat '%s'"
-msgstr "對 '%s' 呼叫 stat 失敗"
-
-#: builtin/clone.c
-#, c-format
-msgid "%s exists and is not a directory"
-msgstr "%s 存在且不是一個目錄"
-
-#: builtin/clone.c
-#, c-format
-msgid "'%s' is a symlink, refusing to clone with --local"
-msgstr "「%s」是個符號連結,故不能使用 --local 複製"
-
-#: builtin/clone.c
-#, c-format
-msgid "failed to start iterator over '%s'"
-msgstr "無法在 '%s' 上啟動疊代器"
-
-#: builtin/clone.c
-#, c-format
-msgid "symlink '%s' exists, refusing to clone with --local"
-msgstr "「%s」符號連結已存在,拒絕使用 --local 複製"
-
-#: builtin/clone.c compat/precompose_utf8.c
-#, c-format
-msgid "failed to unlink '%s'"
-msgstr "無法刪除「%s」"
-
-#: builtin/clone.c
-#, c-format
-msgid "hardlink cannot be checked at '%s'"
-msgstr "無法檢查位於「%s」的硬連結"
-
-#: builtin/clone.c
-#, c-format
-msgid "hardlink different from source at '%s'"
-msgstr "硬連結與位於 '%s' 的來源不同"
-
-#: builtin/clone.c
-#, c-format
-msgid "failed to create link '%s'"
-msgstr "建立連結 '%s' 失敗"
-
-#: builtin/clone.c
-#, c-format
-msgid "failed to copy file to '%s'"
-msgstr "複製檔案至 '%s' 失敗"
-
-#: builtin/clone.c refs/files-backend.c
-#, c-format
-msgid "failed to iterate over '%s'"
-msgstr "無法在 '%s' 上疊代"
-
-#: builtin/clone.c
-#, c-format
-msgid "done.\n"
-msgstr "完成。\n"
-
-#: builtin/clone.c
-msgid ""
-"Clone succeeded, but checkout failed.\n"
-"You can inspect what was checked out with 'git status'\n"
-"and retry with 'git restore --source=HEAD :/'\n"
-msgstr ""
-"複製成功,但是簽出失敗。\n"
-"您可以透過 'git status' 檢查哪些已被簽出,然後使用指令\n"
-"'git restore --source=HEAD :/' 重試\n"
-
-#: builtin/clone.c
-#, c-format
-msgid "Could not find remote branch %s to clone."
-msgstr "找不到要複製的遠端分支 %s。"
-
-#: builtin/clone.c fetch-pack.c
-msgid "remote did not send all necessary objects"
-msgstr "遠端沒有傳送所有必需的物件"
-
-#: builtin/clone.c
-#, c-format
-msgid "unable to update %s"
-msgstr "不能更新 %s"
-
-#: builtin/clone.c
-msgid "failed to initialize sparse-checkout"
-msgstr "無法初始化稀疏簽出"
-
-#: builtin/clone.c
-msgid "remote HEAD refers to nonexistent ref, unable to checkout"
-msgstr "遠端 HEAD 指向一個不存在的引用,無法簽出"
-
-#: builtin/clone.c
-msgid "unable to checkout working tree"
-msgstr "不能簽出工作區"
-
-#: builtin/clone.c
-msgid "unable to write parameters to config file"
-msgstr "無法將參數寫入設定檔案"
-
-#: builtin/clone.c
-msgid "cannot repack to clean up"
-msgstr "無法執行 repack 來清理"
-
-#: builtin/clone.c
-msgid "cannot unlink temporary alternates file"
-msgstr "無法刪除暫存 alternates 檔案"
+msgid "git clone [<options>] [--] <repo> [<dir>]"
+msgstr "git clone [<options>] [--] <repo> [<dir>]"
 
 #: builtin/clone.c
 msgid "Too many arguments."
@@ -5404,7 +5414,12 @@
 #: builtin/clone.c
 #, c-format
 msgid "Remote branch %s not found in upstream %s"
-msgstr "遠端分支 %s 在上游 %s 未發現"
+msgstr "上游 %2$s 上找不到遠端分支 %1$s"
+
+#: builtin/clone.c
+#, c-format
+msgid "Remote revision %s not found in upstream %s"
+msgstr "上游 %2$s 上找不到遠端修訂版 %1$s"
 
 #: builtin/clone.c
 msgid "You appear to have cloned an empty repository."
@@ -5469,7 +5484,8 @@
 "[no-]progress]\n"
 "                       <split-options>"
 
-#: builtin/commit-graph.c builtin/fetch.c builtin/log.c builtin/repack.c
+#: builtin/commit-graph.c builtin/fetch.c builtin/gc.c builtin/log.c
+#: builtin/repack.c
 msgid "dir"
 msgstr "目錄"
 
@@ -5626,8 +5642,19 @@
 msgstr "git commit-tree:讀取失敗"
 
 #: builtin/commit.c
+#| msgid ""
+#| "git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+#| "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
+#| "reword):]<commit>]\n"
+#| "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
+#| "           [--allow-empty-message] [--no-verify] [-e] [--"
+#| "author=<author>]\n"
+#| "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
+#| "           [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
+#| "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
+#| "           [--] [<pathspec>...]"
 msgid ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -5637,7 +5664,7 @@
 "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
 "           [--] [<pathspec>...]"
 msgstr ""
-"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
 "reword):]<commit>]\n"
 "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
@@ -7358,14 +7385,14 @@
 "Run 'git remote set-head %s %s' to follow the change, or set\n"
 "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
 "if you do not want to see this message. Specifically running\n"
-"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n"
-"until the remote changes HEAD to something else."
+"'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+"will disable the warning until the remote changes HEAD to something else."
 msgstr ""
-"執行「git remote set-head %s %s」以追蹤這個變更,或者\n"
-"如果您不想看到這則訊息,請將「remote.%s.followRemoteHEAD」\n"
-"組態選項設定成不同的值。更具體些來說,執行\n"
-"「git config set remote.%s.followRemoteHEAD %s」會停用這個警告,\n"
-"直到遠端將 HEAD 變更為其他內容。"
+"執行「git remote set-head %s %s」來跟進此差異,或者\n"
+"如果您不想看到這則訊息,請將「remote.%s.followRemoteHEAD」組態選項\n"
+"設定成別的值。更具體些來說,執行\n"
+"「git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s」\n"
+"會停用這個警告,直到遠端將 HEAD 改為指向其他東西。"
 
 #: builtin/fetch.c
 msgid "multiple branches detected, incompatible with --set-upstream"
@@ -8216,6 +8243,10 @@
 msgid "repack all other packs except the largest pack"
 msgstr "除了最大的包之外,對所有其它包重新打包"
 
+#: builtin/gc.c builtin/repack.c
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr "將前綴打包並儲存為包含已剪除物件的包"
+
 #: builtin/gc.c
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
@@ -9209,6 +9240,11 @@
 msgid "Cannot come back to cwd"
 msgstr "無法返回目前工作目錄"
 
+#: builtin/index-pack.c builtin/unpack-objects.c
+#, c-format
+msgid "bad --pack_header: %s"
+msgstr "無效的 --pack_header:%s"
+
 #: builtin/index-pack.c
 #, c-format
 msgid "bad %s"
@@ -10311,11 +10347,6 @@
 msgid "malformed input line: '%s'."
 msgstr "格式錯誤的輸入行:'%s'。"
 
-#: builtin/merge-tree.c
-#, c-format
-msgid "merging cannot continue; got unclean result of %d"
-msgstr "無法繼續合併:從 %d 收到的結果不乾淨"
-
 #: builtin/merge.c
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<選項>] [<提交>...]"
@@ -11334,6 +11365,15 @@
 
 #: builtin/pack-objects.c
 #, c-format
+msgid "invalid --name-hash-version option: %d"
+msgstr "無效的 --name-hash-version 選項:%d"
+
+#: builtin/pack-objects.c
+msgid "currently, --write-bitmap-index requires --name-hash-version=1"
+msgstr "目前 --write-bitmap-index 需要指定 --name-hash-version=1"
+
+#: builtin/pack-objects.c
+#, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
@@ -11468,8 +11508,8 @@
 "value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
 "hash> <uri>' (got '%s')"
 msgstr ""
-"uploadpack.blobpackfileuri 的值格式必須為 '<object-hash> <pack-hash> "
-"<uri>' (收到 '%s')"
+"uploadpack.blobpackfileuri 的值格式必須為「<object-hash> <pack-hash> <uri>」"
+"(收到「%s」)"
 
 #: builtin/pack-objects.c
 #, c-format
@@ -11740,6 +11780,10 @@
 msgstr "排除任何設定過,使用此通訊協定的 uploadpack.blobpackfileuri"
 
 #: builtin/pack-objects.c
+msgid "use the specified name-hash function to group similar objects"
+msgstr "使用指定的名稱雜湊函式來為相似物件分組"
+
+#: builtin/pack-objects.c
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
 msgstr "增量鏈深度 %d 太深了,強制為 %d"
@@ -13178,8 +13222,9 @@
 msgstr "無效的引用格式:%s"
 
 #: builtin/refs.c
-msgid "git refs migrate --ref-format=<format> [--dry-run]"
-msgstr "git refs migrate --ref-format=<格式> [--dry-run]"
+#| msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgid "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
+msgstr "git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]"
 
 #: builtin/refs.c
 msgid "git refs verify [--strict] [--verbose]"
@@ -13194,6 +13239,10 @@
 msgstr "進行非破壞性的試執行"
 
 #: builtin/refs.c
+msgid "drop reflogs entirely during the migration"
+msgstr "在遷移過程中完全拋棄 reflog"
+
+#: builtin/refs.c
 msgid "missing --ref-format=<format>"
 msgstr "缺少 --ref-format=<格式>"
 
@@ -13764,8 +13813,14 @@
 msgstr "詳細輸出;必須置於子指令之前"
 
 #: builtin/repack.c
-msgid "git repack [<options>]"
-msgstr "git repack [<選項>]"
+msgid ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
+msgstr ""
+"git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
+"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
+"[--write-midx] [--name-hash-version=<n>]"
 
 #: builtin/repack.c
 msgid ""
@@ -13858,6 +13913,11 @@
 msgstr "向 git-pack-objects 傳遞參數 --no-reuse-object"
 
 #: builtin/repack.c
+msgid ""
+"specify the name hash version to use for grouping similar objects by path"
+msgstr "指定要用來以路徑為相似物件分組的名稱雜湊版本"
+
+#: builtin/repack.c
 msgid "do not run git-update-server-info"
 msgstr "不執行 git-update-server-info"
 
@@ -13922,10 +13982,6 @@
 msgstr "寫入結果包的多包索引"
 
 #: builtin/repack.c
-msgid "pack prefix to store a pack containing pruned objects"
-msgstr "封裝前綴,儲存為包含過時物件的套件包"
-
-#: builtin/repack.c
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr "將前綴進行包裝,儲存為包含已過濾物件的封裝"
 
@@ -14198,10 +14254,6 @@
 msgstr "需要一些提交才能重放"
 
 #: builtin/replay.c
-msgid "--onto and --advance are incompatible"
-msgstr "--onto 和 --advance 不相容"
-
-#: builtin/replay.c
 msgid "all positive revisions given must be references"
 msgstr "提供的所有正向修訂集必須為引用"
 
@@ -17424,6 +17476,10 @@
 msgstr "基於命名過的樹建立檔案封存"
 
 #: command-list.h
+msgid "Download missing objects in a partial clone"
+msgstr "在部分複製中下載缺少的物件"
+
+#: command-list.h
 msgid "Use binary search to find the commit that introduced a bug"
 msgstr "透過二分搜尋定位引入 bug 的提交"
 
@@ -18378,8 +18434,8 @@
 #: commit-graph.c
 #, c-format
 msgid ""
-"attempting to write a commit-graph, but 'commitGraph."
-"changedPathsVersion' (%d) is not supported"
+"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' "
+"(%d) is not supported"
 msgstr "嘗試寫入提交圖,但不支援「commitGraph.changedPathsVersion」(%d)"
 
 #: commit-graph.c
@@ -19791,6 +19847,14 @@
 msgstr "傳入 -I 的常規表示式無效:「%s」"
 
 #: diff.c
+msgid "-G requires a non-empty argument"
+msgstr "-G 需要非空白引數"
+
+#: diff.c
+msgid "-S requires a non-empty argument"
+msgstr "-S 需要非空白引數"
+
+#: diff.c
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr "無法解析 --submodule 選項的參數:'%s'"
@@ -22419,6 +22483,11 @@
 
 #: object-file.c
 #, c-format
+msgid "unable to write repeatedly vanishing file %s"
+msgstr "無法寫入重複消失的檔案 %s"
+
+#: object-file.c
+#, c-format
 msgid "unable to set permission to '%s'"
 msgstr "無法為 '%s' 設定權限"
 
@@ -23100,6 +23169,55 @@
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "字串中未知的非 ascii 字元選項:`%s'"
 
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the long form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#: parse-options.c
+#, c-format
+msgid "[=<%s>]"
+msgstr "[=<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string
+#. stands for an optional value given to a command
+#. line option in the short form, and "<>" is there
+#. as a convention to signal that it is a
+#. placeholder (i.e. the user should substitute it
+#. with the real value).  If your language uses a
+#. different convention, you can change "<%s>" part
+#. to match yours, e.g. it might use "|%s|" instead,
+#. or if the alphabet is different enough it may use
+#. "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#: parse-options.c
+#, c-format
+msgid "[<%s>]"
+msgstr "[<%s>]"
+
+#. TRANSLATORS: The "<%s>" part of this string stands for a
+#. value given to a command line option, and "<>" is there
+#. as a convention to signal that it is a placeholder
+#. (i.e. the user should substitute it with the real value).
+#. If your language uses a different convention, you can
+#. change "<%s>" part to match yours, e.g. it might use
+#. "|%s|" instead, or if the alphabet is different enough it
+#. may use "%s" without any placeholder signal.  Most
+#. translations leave this message as is.
+#.
+#: parse-options.c
+#, c-format
+msgid " <%s>"
+msgstr " <%s>"
+
 #: parse-options.c
 msgid "..."
 msgstr "..."
@@ -23203,6 +23321,25 @@
 msgid "failed to parse %s"
 msgstr "解析 %s 失敗"
 
+#: path-walk.c
+#, c-format
+msgid "failed to walk children of tree %s: not found"
+msgstr "無法走訪樹 %s 的子代:找不到"
+
+#: path-walk.c
+#, c-format
+msgid "failed to find object %s"
+msgstr "找不到物件 %s"
+
+#: path-walk.c
+#, c-format
+msgid "failed to find tag %s"
+msgstr "找不到標籤 %s"
+
+#: path-walk.c
+msgid "failed to setup revision walk"
+msgstr "無法設置修訂版走訪"
+
 #: path.c
 #, c-format
 msgid "Could not make %s writable by group"
@@ -23384,6 +23521,26 @@
 msgid "could not fetch %s from promisor remote"
 msgstr "無法從承諾者遠端抓取 %s"
 
+#: promisor-remote.c
+#, c-format
+msgid "known remote named '%s' but with url '%s' instead of '%s'"
+msgstr "已知有遠端名為「%s」,但其 URL 為「%s」而非「%s」"
+
+#: promisor-remote.c
+#, c-format
+msgid "unknown '%s' value for '%s' config option"
+msgstr "「%2$s」組態選項的值「%1$s」未知"
+
+#: promisor-remote.c
+#, c-format
+msgid "unknown element '%s' from remote info"
+msgstr "遠端資訊的元素「%s」未知"
+
+#: promisor-remote.c
+#, c-format
+msgid "accepted promisor remote '%s' not found"
+msgstr "找不到接受的承諾者遠端「%s」"
+
 #: protocol-caps.c
 msgid "object-info: expected flush after arguments"
 msgstr "object-info:引數後預期要有 flush"
@@ -24351,6 +24508,16 @@
 msgid "invalid refspec '%s'"
 msgstr "無效的引用規格:「%s」"
 
+#: refspec.c
+#, c-format
+msgid "pattern '%s' has no '*'"
+msgstr "符合模式「%s」中沒有「*」"
+
+#: refspec.c
+#, c-format
+msgid "replacement '%s' has no '*'"
+msgstr "取代文字「%s」中沒有「*」"
+
 #: remote-curl.c
 #, c-format
 msgid "invalid quoting in push-option value: '%s'"
@@ -24504,6 +24671,28 @@
 
 #: remote.c
 #, c-format
+msgid ""
+"reading remote from \"%s/%s\", which is nominated for removal.\n"
+"\n"
+"If you still use the \"remotes/\" directory it is recommended to\n"
+"migrate to config-based remotes:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"If you cannot, please let us know why you still need to use it by\n"
+"sending an e-mail to <git@vger.kernel.org>."
+msgstr ""
+"正在自「%s/%s」讀取遠端,該路徑已被標記為即將移除。\n"
+"\n"
+"如果您仍在使用「remotes/」目錄,建議您遷移至基於組態的遠端:\n"
+"\n"
+"\tgit remote rename %s %s\n"
+"\n"
+"如果您無法遷移,請告訴我們您為何仍需使用此功能,\n"
+"請寄信至 <git@vger.kernel.org>。"
+
+#: remote.c
+#, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
 msgstr "設定的遠端短名稱不能以 '/' 開始:%s"
 
@@ -24547,16 +24736,6 @@
 
 #: remote.c
 #, c-format
-msgid "key '%s' of pattern had no '*'"
-msgstr "模式的鍵 '%s' 沒有 '*'"
-
-#: remote.c
-#, c-format
-msgid "value '%s' of pattern has no '*'"
-msgstr "模式的值 '%s' 沒有 '*'"
-
-#: remote.c
-#, c-format
 msgid "src refspec %s does not match any"
 msgstr "來源引用規格 %s 沒有符合項目"
 
@@ -26824,6 +27003,34 @@
 msgid "number of entries in the cache tree to invalidate (default 0)"
 msgstr "在快取樹狀物件中,要使失效的項目數量(預設值為 0)"
 
+#: t/helper/test-path-walk.c
+msgid "test-tool path-walk <options> -- <revision-options>"
+msgstr "test-tool path-walk <options> -- <revision-options>"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of blob objects"
+msgstr "切換是否包含資料物件"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of commit objects"
+msgstr "切換是否包含提交物件"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of tag objects"
+msgstr "切換是否包含標籤物件"
+
+#: t/helper/test-path-walk.c
+msgid "toggle inclusion of tree objects"
+msgstr "切換是否包含樹狀物件"
+
+#: t/helper/test-path-walk.c
+msgid "toggle pruning of uninteresting paths"
+msgstr "切換是否剪除不重要路徑"
+
+#: t/helper/test-path-walk.c
+msgid "read a pattern list over stdin"
+msgstr "從標準輸入讀取模式清單"
+
 #: t/helper/test-reach.c
 #, c-format
 msgid "commit %s is not marked reachable"
@@ -27571,6 +27778,11 @@
 msgid "warning: "
 msgstr "警告: "
 
+#: version.c
+#, c-format
+msgid "uname() failed with error '%s' (%d)\n"
+msgstr "uname() 失敗,錯誤:「%s」(%d)\n"
+
 #: walker.c
 msgid "Fetching objects"
 msgstr "正在抓取物件"
@@ -28758,6 +28970,24 @@
 msgstr "您真的要傳送 %s?[y|N]: "
 
 #, c-format
+#~ msgid "Could not find remote branch %s to clone."
+#~ msgstr "找不到要複製的遠端分支 %s。"
+
+#, c-format
+#~ msgid "merging cannot continue; got unclean result of %d"
+#~ msgstr "無法繼續合併:從 %d 收到的結果不乾淨"
+
+#~ msgid "git repack [<options>]"
+#~ msgstr "git repack [<選項>]"
+
+#~ msgid "--onto and --advance are incompatible"
+#~ msgstr "--onto 和 --advance 不相容"
+
+#, c-format
+#~ msgid "key '%s' of pattern had no '*'"
+#~ msgstr "模式的鍵 '%s' 沒有 '*'"
+
+#, c-format
 #~ msgid "preferred pack (%s) is invalid"
 #~ msgstr "偏好的封包 (%s) 無效"
 
diff --git a/preload-index.c b/preload-index.c
index ab94d6f..40ab2ab 100644
--- a/preload-index.c
+++ b/preload-index.c
@@ -132,7 +132,9 @@ void preload_index(struct index_state *index,
 
 	memset(&pd, 0, sizeof(pd));
 	if (refresh_flags & REFRESH_PROGRESS && isatty(2)) {
-		pd.progress = start_delayed_progress(_("Refreshing index"), index->cache_nr);
+		pd.progress = start_delayed_progress(the_repository,
+						     _("Refreshing index"),
+						     index->cache_nr);
 		pthread_mutex_init(&pd.mutex, NULL);
 	}
 
diff --git a/prio-queue.h b/prio-queue.h
index 36f3706..38d0326 100644
--- a/prio-queue.h
+++ b/prio-queue.h
@@ -22,13 +22,13 @@
 typedef int (*prio_queue_compare_fn)(const void *one, const void *two, void *cb_data);
 
 struct prio_queue_entry {
-	unsigned ctr;
+	size_t ctr;
 	void *data;
 };
 
 struct prio_queue {
 	prio_queue_compare_fn compare;
-	unsigned insertion_ctr;
+	size_t insertion_ctr;
 	void *cb_data;
 	size_t alloc, nr;
 	struct prio_queue_entry *array;
diff --git a/progress.c b/progress.c
index a8fdfce..8d5ae70 100644
--- a/progress.c
+++ b/progress.c
@@ -9,7 +9,6 @@
  */
 
 #define GIT_TEST_PROGRESS_ONLY
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -37,6 +36,7 @@ struct throughput {
 };
 
 struct progress {
+	struct repository *repo;
 	const char *title;
 	uint64_t last_value;
 	uint64_t total;
@@ -254,10 +254,12 @@ void display_progress(struct progress *progress, uint64_t n)
 		display(progress, n, NULL);
 }
 
-static struct progress *start_progress_delay(const char *title, uint64_t total,
+static struct progress *start_progress_delay(struct repository *r,
+					     const char *title, uint64_t total,
 					     unsigned delay, unsigned sparse)
 {
 	struct progress *progress = xmalloc(sizeof(*progress));
+	progress->repo = r;
 	progress->title = title;
 	progress->total = total;
 	progress->last_value = -1;
@@ -270,7 +272,7 @@ static struct progress *start_progress_delay(const char *title, uint64_t total,
 	progress->title_len = utf8_strwidth(title);
 	progress->split = 0;
 	set_progress_signal();
-	trace2_region_enter("progress", title, the_repository);
+	trace2_region_enter("progress", title, r);
 	return progress;
 }
 
@@ -284,14 +286,16 @@ static int get_default_delay(void)
 	return delay_in_secs;
 }
 
-struct progress *start_delayed_progress(const char *title, uint64_t total)
+struct progress *start_delayed_progress(struct repository *r,
+					const char *title, uint64_t total)
 {
-	return start_progress_delay(title, total, get_default_delay(), 0);
+	return start_progress_delay(r, title, total, get_default_delay(), 0);
 }
 
-struct progress *start_progress(const char *title, uint64_t total)
+struct progress *start_progress(struct repository *r,
+				const char *title, uint64_t total)
 {
-	return start_progress_delay(title, total, 0, 0);
+	return start_progress_delay(r, title, total, 0, 0);
 }
 
 /*
@@ -303,15 +307,17 @@ struct progress *start_progress(const char *title, uint64_t total)
  * When "sparse" is set, stop_progress() will automatically force the done
  * message to show 100%.
  */
-struct progress *start_sparse_progress(const char *title, uint64_t total)
+struct progress *start_sparse_progress(struct repository *r,
+				       const char *title, uint64_t total)
 {
-	return start_progress_delay(title, total, 0, 1);
+	return start_progress_delay(r, title, total, 0, 1);
 }
 
-struct progress *start_delayed_sparse_progress(const char *title,
+struct progress *start_delayed_sparse_progress(struct repository *r,
+					       const char *title,
 					       uint64_t total)
 {
-	return start_progress_delay(title, total, get_default_delay(), 1);
+	return start_progress_delay(r, title, total, get_default_delay(), 1);
 }
 
 static void finish_if_sparse(struct progress *progress)
@@ -341,14 +347,14 @@ static void force_last_update(struct progress *progress, const char *msg)
 
 static void log_trace2(struct progress *progress)
 {
-	trace2_data_intmax("progress", the_repository, "total_objects",
+	trace2_data_intmax("progress", progress->repo, "total_objects",
 			   progress->total);
 
 	if (progress->throughput)
-		trace2_data_intmax("progress", the_repository, "total_bytes",
+		trace2_data_intmax("progress", progress->repo, "total_bytes",
 				   progress->throughput->curr_total);
 
-	trace2_region_leave("progress", progress->title, the_repository);
+	trace2_region_leave("progress", progress->title, progress->repo);
 }
 
 void stop_progress_msg(struct progress **p_progress, const char *msg)
diff --git a/progress.h b/progress.h
index 3a94563..ed068c7 100644
--- a/progress.h
+++ b/progress.h
@@ -3,6 +3,7 @@
 #include "gettext.h"
 
 struct progress;
+struct repository;
 
 #ifdef GIT_TEST_PROGRESS_ONLY
 
@@ -14,10 +15,14 @@ void progress_test_force_update(void);
 
 void display_throughput(struct progress *progress, uint64_t total);
 void display_progress(struct progress *progress, uint64_t n);
-struct progress *start_progress(const char *title, uint64_t total);
-struct progress *start_sparse_progress(const char *title, uint64_t total);
-struct progress *start_delayed_progress(const char *title, uint64_t total);
-struct progress *start_delayed_sparse_progress(const char *title,
+struct progress *start_progress(struct repository *r,
+				const char *title, uint64_t total);
+struct progress *start_sparse_progress(struct repository *r,
+				       const char *title, uint64_t total);
+struct progress *start_delayed_progress(struct repository *r,
+					const char *title, uint64_t total);
+struct progress *start_delayed_sparse_progress(struct repository *r,
+					       const char *title,
 					       uint64_t total);
 void stop_progress_msg(struct progress **p_progress, const char *msg);
 static inline void stop_progress(struct progress **p_progress)
diff --git a/promisor-remote.c b/promisor-remote.c
index c714f4f..6a0a613 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -11,6 +11,8 @@
 #include "strvec.h"
 #include "packfile.h"
 #include "environment.h"
+#include "url.h"
+#include "version.h"
 
 struct promisor_remote_config {
 	struct promisor_remote *promisors;
@@ -221,6 +223,18 @@ int repo_has_promisor_remote(struct repository *r)
 	return !!repo_promisor_remote_find(r, NULL);
 }
 
+int repo_has_accepted_promisor_remote(struct repository *r)
+{
+	struct promisor_remote *p;
+
+	promisor_remote_init(r);
+
+	for (p = r->promisor_remote_config->promisors; p; p = p->next)
+		if (p->accepted)
+			return 1;
+	return 0;
+}
+
 static int remove_fetched_oids(struct repository *repo,
 			       struct object_id **oids,
 			       int oid_nr, int to_free)
@@ -292,3 +306,231 @@ void promisor_remote_get_direct(struct repository *repo,
 	if (to_free)
 		free(remaining_oids);
 }
+
+static int allow_unsanitized(char ch)
+{
+	if (ch == ',' || ch == ';' || ch == '%')
+		return 0;
+	return ch > 32 && ch < 127;
+}
+
+static void promisor_info_vecs(struct repository *repo,
+			       struct strvec *names,
+			       struct strvec *urls)
+{
+	struct promisor_remote *r;
+
+	promisor_remote_init(repo);
+
+	for (r = repo->promisor_remote_config->promisors; r; r = r->next) {
+		char *url;
+		char *url_key = xstrfmt("remote.%s.url", r->name);
+
+		strvec_push(names, r->name);
+		strvec_push(urls, git_config_get_string(url_key, &url) ? NULL : url);
+
+		free(url);
+		free(url_key);
+	}
+}
+
+char *promisor_remote_info(struct repository *repo)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int advertise_promisors = 0;
+	struct strvec names = STRVEC_INIT;
+	struct strvec urls = STRVEC_INIT;
+
+	git_config_get_bool("promisor.advertise", &advertise_promisors);
+
+	if (!advertise_promisors)
+		return NULL;
+
+	promisor_info_vecs(repo, &names, &urls);
+
+	if (!names.nr)
+		return NULL;
+
+	for (size_t i = 0; i < names.nr; i++) {
+		if (i)
+			strbuf_addch(&sb, ';');
+		strbuf_addstr(&sb, "name=");
+		strbuf_addstr_urlencode(&sb, names.v[i], allow_unsanitized);
+		if (urls.v[i]) {
+			strbuf_addstr(&sb, ",url=");
+			strbuf_addstr_urlencode(&sb, urls.v[i], allow_unsanitized);
+		}
+	}
+
+	strvec_clear(&names);
+	strvec_clear(&urls);
+
+	return strbuf_detach(&sb, NULL);
+}
+
+/*
+ * Find first index of 'nicks' where there is 'nick'. 'nick' is
+ * compared case insensitively to the strings in 'nicks'. If not found
+ * 'nicks->nr' is returned.
+ */
+static size_t remote_nick_find(struct strvec *nicks, const char *nick)
+{
+	for (size_t i = 0; i < nicks->nr; i++)
+		if (!strcasecmp(nicks->v[i], nick))
+			return i;
+	return nicks->nr;
+}
+
+enum accept_promisor {
+	ACCEPT_NONE = 0,
+	ACCEPT_KNOWN_URL,
+	ACCEPT_KNOWN_NAME,
+	ACCEPT_ALL
+};
+
+static int should_accept_remote(enum accept_promisor accept,
+				const char *remote_name, const char *remote_url,
+				struct strvec *names, struct strvec *urls)
+{
+	size_t i;
+
+	if (accept == ACCEPT_ALL)
+		return 1;
+
+	i = remote_nick_find(names, remote_name);
+
+	if (i >= names->nr)
+		/* We don't know about that remote */
+		return 0;
+
+	if (accept == ACCEPT_KNOWN_NAME)
+		return 1;
+
+	if (accept != ACCEPT_KNOWN_URL)
+		BUG("Unhandled 'enum accept_promisor' value '%d'", accept);
+
+	if (!strcmp(urls->v[i], remote_url))
+		return 1;
+
+	warning(_("known remote named '%s' but with url '%s' instead of '%s'"),
+		remote_name, urls->v[i], remote_url);
+
+	return 0;
+}
+
+static void filter_promisor_remote(struct repository *repo,
+				   struct strvec *accepted,
+				   const char *info)
+{
+	struct strbuf **remotes;
+	const char *accept_str;
+	enum accept_promisor accept = ACCEPT_NONE;
+	struct strvec names = STRVEC_INIT;
+	struct strvec urls = STRVEC_INIT;
+
+	if (!git_config_get_string_tmp("promisor.acceptfromserver", &accept_str)) {
+		if (!*accept_str || !strcasecmp("None", accept_str))
+			accept = ACCEPT_NONE;
+		else if (!strcasecmp("KnownUrl", accept_str))
+			accept = ACCEPT_KNOWN_URL;
+		else if (!strcasecmp("KnownName", accept_str))
+			accept = ACCEPT_KNOWN_NAME;
+		else if (!strcasecmp("All", accept_str))
+			accept = ACCEPT_ALL;
+		else
+			warning(_("unknown '%s' value for '%s' config option"),
+				accept_str, "promisor.acceptfromserver");
+	}
+
+	if (accept == ACCEPT_NONE)
+		return;
+
+	if (accept != ACCEPT_ALL)
+		promisor_info_vecs(repo, &names, &urls);
+
+	/* Parse remote info received */
+
+	remotes = strbuf_split_str(info, ';', 0);
+
+	for (size_t i = 0; remotes[i]; i++) {
+		struct strbuf **elems;
+		const char *remote_name = NULL;
+		const char *remote_url = NULL;
+		char *decoded_name = NULL;
+		char *decoded_url = NULL;
+
+		strbuf_strip_suffix(remotes[i], ";");
+		elems = strbuf_split(remotes[i], ',');
+
+		for (size_t j = 0; elems[j]; j++) {
+			int res;
+			strbuf_strip_suffix(elems[j], ",");
+			res = skip_prefix(elems[j]->buf, "name=", &remote_name) ||
+				skip_prefix(elems[j]->buf, "url=", &remote_url);
+			if (!res)
+				warning(_("unknown element '%s' from remote info"),
+					elems[j]->buf);
+		}
+
+		if (remote_name)
+			decoded_name = url_percent_decode(remote_name);
+		if (remote_url)
+			decoded_url = url_percent_decode(remote_url);
+
+		if (decoded_name && should_accept_remote(accept, decoded_name, decoded_url, &names, &urls))
+			strvec_push(accepted, decoded_name);
+
+		strbuf_list_free(elems);
+		free(decoded_name);
+		free(decoded_url);
+	}
+
+	strvec_clear(&names);
+	strvec_clear(&urls);
+	strbuf_list_free(remotes);
+}
+
+char *promisor_remote_reply(const char *info)
+{
+	struct strvec accepted = STRVEC_INIT;
+	struct strbuf reply = STRBUF_INIT;
+
+	filter_promisor_remote(the_repository, &accepted, info);
+
+	if (!accepted.nr)
+		return NULL;
+
+	for (size_t i = 0; i < accepted.nr; i++) {
+		if (i)
+			strbuf_addch(&reply, ';');
+		strbuf_addstr_urlencode(&reply, accepted.v[i], allow_unsanitized);
+	}
+
+	strvec_clear(&accepted);
+
+	return strbuf_detach(&reply, NULL);
+}
+
+void mark_promisor_remotes_as_accepted(struct repository *r, const char *remotes)
+{
+	struct strbuf **accepted_remotes = strbuf_split_str(remotes, ';', 0);
+
+	for (size_t i = 0; accepted_remotes[i]; i++) {
+		struct promisor_remote *p;
+		char *decoded_remote;
+
+		strbuf_strip_suffix(accepted_remotes[i], ";");
+		decoded_remote = url_percent_decode(accepted_remotes[i]->buf);
+
+		p = repo_promisor_remote_find(r, decoded_remote);
+		if (p)
+			p->accepted = 1;
+		else
+			warning(_("accepted promisor remote '%s' not found"),
+				decoded_remote);
+
+		free(decoded_remote);
+	}
+
+	strbuf_list_free(accepted_remotes);
+}
diff --git a/promisor-remote.h b/promisor-remote.h
index 88cb599..263d331 100644
--- a/promisor-remote.h
+++ b/promisor-remote.h
@@ -9,11 +9,13 @@ struct object_id;
  * Promisor remote linked list
  *
  * Information in its fields come from remote.XXX config entries or
- * from extensions.partialclone.
+ * from extensions.partialclone, except for 'accepted' which comes
+ * from protocol v2 capabilities exchange.
  */
 struct promisor_remote {
 	struct promisor_remote *next;
 	char *partial_clone_filter;
+	unsigned int accepted : 1;
 	const char name[FLEX_ARRAY];
 };
 
@@ -32,4 +34,37 @@ void promisor_remote_get_direct(struct repository *repo,
 				const struct object_id *oids,
 				int oid_nr);
 
+/*
+ * Prepare a "promisor-remote" advertisement by a server.
+ * Check the value of "promisor.advertise" and maybe the configured
+ * promisor remotes, if any, to prepare information to send in an
+ * advertisement.
+ * Return value is NULL if no promisor remote advertisement should be
+ * made. Otherwise it contains the names and urls of the advertised
+ * promisor remotes separated by ';'. See gitprotocol-v2(5).
+ */
+char *promisor_remote_info(struct repository *repo);
+
+/*
+ * Prepare a reply to a "promisor-remote" advertisement from a server.
+ * Check the value of "promisor.acceptfromserver" and maybe the
+ * configured promisor remotes, if any, to prepare the reply.
+ * Return value is NULL if no promisor remote from the server
+ * is accepted. Otherwise it contains the names of the accepted promisor
+ * remotes separated by ';'. See gitprotocol-v2(5).
+ */
+char *promisor_remote_reply(const char *info);
+
+/*
+ * Set the 'accepted' flag for some promisor remotes. Useful on the
+ * server side when some promisor remotes have been accepted by the
+ * client.
+ */
+void mark_promisor_remotes_as_accepted(struct repository *repo, const char *remotes);
+
+/*
+ * Has any promisor remote been accepted by the client?
+ */
+int repo_has_accepted_promisor_remote(struct repository *r);
+
 #endif /* PROMISOR_REMOTE_H */
diff --git a/prune-packed.c b/prune-packed.c
index d1c65ab..7dad2fc 100644
--- a/prune-packed.c
+++ b/prune-packed.c
@@ -37,7 +37,8 @@ static int prune_object(const struct object_id *oid, const char *path,
 void prune_packed_objects(int opts)
 {
 	if (opts & PRUNE_PACKED_VERBOSE)
-		progress = start_delayed_progress(_("Removing duplicate objects"), 256);
+		progress = start_delayed_progress(the_repository,
+						  _("Removing duplicate objects"), 256);
 
 	for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
 				      prune_object, NULL, prune_subdir, &opts);
diff --git a/pseudo-merge.c b/pseudo-merge.c
index 971f54c..893b763 100644
--- a/pseudo-merge.c
+++ b/pseudo-merge.c
@@ -459,7 +459,8 @@ void select_pseudo_merges(struct bitmap_writer *writer)
 		return;
 
 	if (writer->show_progress)
-		progress = start_progress("Selecting pseudo-merge commits",
+		progress = start_progress(the_repository,
+					  "Selecting pseudo-merge commits",
 					  writer->pseudo_merge_groups.nr);
 
 	refs_for_each_ref(get_main_ref_store(the_repository),
diff --git a/pseudo-merge.h b/pseudo-merge.h
index 29df8a3..c9fbe9d 100644
--- a/pseudo-merge.h
+++ b/pseudo-merge.h
@@ -101,7 +101,7 @@ void select_pseudo_merges(struct bitmap_writer *writer);
 
 /*
  * Represents a serialized view of a file containing pseudo-merge(s)
- * (see Documentation/technical/bitmap-format.txt for a specification
+ * (see Documentation/technical/bitmap-format.adoc for a specification
  * of the format).
  */
 struct pseudo_merge_map {
diff --git a/reachable.c b/reachable.c
index ecf7ccf..9ee04c8 100644
--- a/reachable.c
+++ b/reachable.c
@@ -65,8 +65,10 @@ static void add_rebase_files(struct rev_info *revs)
 	struct worktree **worktrees = get_worktrees();
 
 	for (struct worktree **wt = worktrees; *wt; wt++) {
+		char *wt_gitdir = get_worktree_git_dir(*wt);
+
 		strbuf_reset(&buf);
-		strbuf_addstr(&buf, get_worktree_git_dir(*wt));
+		strbuf_addstr(&buf, wt_gitdir);
 		strbuf_complete(&buf, '/');
 		len = buf.len;
 		for (size_t i = 0; i < ARRAY_SIZE(path); i++) {
@@ -74,6 +76,8 @@ static void add_rebase_files(struct rev_info *revs)
 			strbuf_addstr(&buf, path[i]);
 			add_one_file(buf.buf, revs);
 		}
+
+		free(wt_gitdir);
 	}
 	strbuf_release(&buf);
 	free_worktrees(worktrees);
diff --git a/read-cache.c b/read-cache.c
index 15d7983..e678c13 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1523,7 +1523,8 @@ int refresh_index(struct index_state *istate, unsigned int flags,
 	int t2_sum_scan = 0;
 
 	if (flags & REFRESH_PROGRESS && isatty(2))
-		progress = start_delayed_progress(_("Refresh index"),
+		progress = start_delayed_progress(the_repository,
+						  _("Refresh index"),
 						  istate->cache_nr);
 
 	trace_performance_enter();
@@ -1716,7 +1717,7 @@ int verify_ce_order;
 
 static int verify_hdr(const struct cache_header *hdr, unsigned long size)
 {
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 	unsigned char hash[GIT_MAX_RAWSZ];
 	int hdr_version;
 	unsigned char *start, *end;
@@ -1738,8 +1739,8 @@ static int verify_hdr(const struct cache_header *hdr, unsigned long size)
 		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);
+	git_hash_update(&c, hdr, size - the_hash_algo->rawsz);
+	git_hash_final(hash, &c);
 	if (!hasheq(hash, start, the_repository->hash_algo))
 		return error(_("bad index file sha1 signature"));
 	return 0;
@@ -1753,7 +1754,7 @@ static int read_index_extension(struct index_state *istate,
 		istate->cache_tree = cache_tree_read(data, sz);
 		break;
 	case CACHE_EXT_RESOLVE_UNDO:
-		istate->resolve_undo = resolve_undo_read(data, sz);
+		istate->resolve_undo = resolve_undo_read(data, sz, the_hash_algo);
 		break;
 	case CACHE_EXT_LINK:
 		if (read_link_extension(istate, data, sz))
@@ -2001,7 +2002,7 @@ static struct index_entry_offset_table *read_ieot_extension(const char *mmap, si
 static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot);
 
 static size_t read_eoie_extension(const char *mmap, size_t mmap_size);
-static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset);
+static void write_eoie_extension(struct strbuf *sb, struct git_hash_ctx *eoie_context, size_t offset);
 
 struct load_index_extensions
 {
@@ -2565,7 +2566,7 @@ int repo_index_has_changes(struct repository *repo,
 }
 
 static int write_index_ext_header(struct hashfile *f,
-				  git_hash_ctx *eoie_f,
+				  struct git_hash_ctx *eoie_f,
 				  unsigned int ext,
 				  unsigned int sz)
 {
@@ -2575,8 +2576,8 @@ static int write_index_ext_header(struct hashfile *f,
 	if (eoie_f) {
 		ext = htonl(ext);
 		sz = htonl(sz);
-		the_hash_algo->update_fn(eoie_f, &ext, sizeof(ext));
-		the_hash_algo->update_fn(eoie_f, &sz, sizeof(sz));
+		git_hash_update(eoie_f, &ext, sizeof(ext));
+		git_hash_update(eoie_f, &sz, sizeof(sz));
 	}
 	return 0;
 }
@@ -2830,7 +2831,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 {
 	uint64_t start = getnanotime();
 	struct hashfile *f;
-	git_hash_ctx *eoie_c = NULL;
+	struct git_hash_ctx *eoie_c = NULL;
 	struct cache_header hdr;
 	int i, err = 0, removed, extended, hdr_version;
 	struct cache_entry **cache = istate->cache;
@@ -3032,7 +3033,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 	    istate->resolve_undo) {
 		strbuf_reset(&sb);
 
-		resolve_undo_write(&sb, istate->resolve_undo);
+		resolve_undo_write(&sb, istate->resolve_undo, the_hash_algo);
 		err = write_index_ext_header(f, eoie_c, CACHE_EXT_RESOLVE_UNDO,
 					     sb.len) < 0;
 		hashwrite(f, sb.buf, sb.len);
@@ -3250,15 +3251,18 @@ static int clean_shared_index_files(const char *current_hex)
 
 	while ((de = readdir(dir)) != NULL) {
 		const char *sha1_hex;
-		const char *shared_index_path;
+		char *shared_index_path;
 		if (!skip_prefix(de->d_name, "sharedindex.", &sha1_hex))
 			continue;
 		if (!strcmp(sha1_hex, current_hex))
 			continue;
-		shared_index_path = git_path("%s", de->d_name);
+
+		shared_index_path = repo_git_path(the_repository, "%s", de->d_name);
 		if (should_delete_shared_index(shared_index_path) > 0 &&
 		    unlink(shared_index_path))
 			warning_errno(_("unable to unlink: %s"), shared_index_path);
+
+		free(shared_index_path);
 	}
 	closedir(dir);
 
@@ -3270,6 +3274,7 @@ static int write_shared_index(struct index_state *istate,
 {
 	struct split_index *si = istate->split_index;
 	int ret, was_full = !istate->sparse_index;
+	char *path;
 
 	move_cache_to_base_index(istate);
 	convert_to_sparse(istate, 0);
@@ -3285,18 +3290,20 @@ static int write_shared_index(struct index_state *istate,
 
 	if (ret)
 		return ret;
-	ret = adjust_shared_perm(get_tempfile_path(*temp));
+	ret = adjust_shared_perm(the_repository, get_tempfile_path(*temp));
 	if (ret) {
 		error(_("cannot fix permission bits on '%s'"), get_tempfile_path(*temp));
 		return ret;
 	}
-	ret = rename_tempfile(temp,
-			      git_path("sharedindex.%s", oid_to_hex(&si->base->oid)));
+
+	path = repo_git_path(the_repository, "sharedindex.%s", oid_to_hex(&si->base->oid));
+	ret = rename_tempfile(temp, path);
 	if (!ret) {
 		oidcpy(&si->base_oid, &si->base->oid);
 		clean_shared_index_files(oid_to_hex(&si->base->oid));
 	}
 
+	free(path);
 	return ret;
 }
 
@@ -3377,9 +3384,12 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
 	if (new_shared_index) {
 		struct tempfile *temp;
 		int saved_errno;
+		char *path;
 
 		/* Same initial permissions as the main .git/index file */
-		temp = mks_tempfile_sm(git_path("sharedindex_XXXXXX"), 0, 0666);
+		path = repo_git_path(the_repository, "sharedindex_XXXXXX");
+		temp = mks_tempfile_sm(path, 0, 0666);
+		free(path);
 		if (!temp) {
 			ret = do_write_locked_index(istate, lock, flags,
 						    ~WRITE_SPLIT_INDEX_EXTENSION);
@@ -3400,9 +3410,10 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
 
 	/* Freshen the shared index only if the split-index was written */
 	if (!ret && !new_shared_index && !is_null_oid(&si->base_oid)) {
-		const char *shared_index = git_path("sharedindex.%s",
-						    oid_to_hex(&si->base_oid));
+		char *shared_index = repo_git_path(the_repository, "sharedindex.%s",
+						   oid_to_hex(&si->base_oid));
 		freshen_shared_index(shared_index, 1);
+		free(shared_index);
 	}
 
 out:
@@ -3578,7 +3589,7 @@ static size_t read_eoie_extension(const char *mmap, size_t mmap_size)
 	uint32_t extsize;
 	size_t offset, src_offset;
 	unsigned char hash[GIT_MAX_RAWSZ];
-	git_hash_ctx c;
+	struct git_hash_ctx c;
 
 	/* ensure we have an index big enough to contain an EOIE extension */
 	if (mmap_size < sizeof(struct cache_header) + EOIE_SIZE_WITH_HEADER + the_hash_algo->rawsz)
@@ -3633,12 +3644,12 @@ static size_t read_eoie_extension(const char *mmap, size_t mmap_size)
 		if (src_offset + 8 + extsize < src_offset)
 			return 0;
 
-		the_hash_algo->update_fn(&c, mmap + src_offset, 8);
+		git_hash_update(&c, mmap + src_offset, 8);
 
 		src_offset += 8;
 		src_offset += extsize;
 	}
-	the_hash_algo->final_fn(hash, &c);
+	git_hash_final(hash, &c);
 	if (!hasheq(hash, (const unsigned char *)index, the_repository->hash_algo))
 		return 0;
 
@@ -3649,7 +3660,7 @@ static size_t read_eoie_extension(const char *mmap, size_t mmap_size)
 	return offset;
 }
 
-static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset)
+static void write_eoie_extension(struct strbuf *sb, struct git_hash_ctx *eoie_context, size_t offset)
 {
 	uint32_t buffer;
 	unsigned char hash[GIT_MAX_RAWSZ];
@@ -3659,7 +3670,7 @@ static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context,
 	strbuf_add(sb, &buffer, sizeof(uint32_t));
 
 	/* hash */
-	the_hash_algo->final_fn(hash, eoie_context);
+	git_hash_final(hash, eoie_context);
 	strbuf_add(sb, hash, the_hash_algo->rawsz);
 }
 
diff --git a/ref-filter.c b/ref-filter.c
index 2305469..6da8d4c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -235,6 +235,10 @@ static struct used_atom {
 			enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
 			       S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
 		} signature;
+		struct {
+			char *name;
+			struct commit *commit;
+		} base;
 		struct strvec describe_args;
 		struct refname_atom refname;
 		char *head;
@@ -891,35 +895,30 @@ static int rest_atom_parser(struct ref_format *format UNUSED,
 	return 0;
 }
 
-static int ahead_behind_atom_parser(struct ref_format *format,
-				    struct used_atom *atom UNUSED,
+static int ahead_behind_atom_parser(struct ref_format *format UNUSED,
+				    struct used_atom *atom,
 				    const char *arg, struct strbuf *err)
 {
-	struct string_list_item *item;
-
 	if (!arg)
 		return strbuf_addf_ret(err, -1, _("expected format: %%(ahead-behind:<committish>)"));
 
-	item = string_list_append(&format->bases, arg);
-	item->util = lookup_commit_reference_by_name(arg);
-	if (!item->util)
+	atom->u.base.commit = lookup_commit_reference_by_name(arg);
+	if (!atom->u.base.commit)
 		die("failed to find '%s'", arg);
 
 	return 0;
 }
 
-static int is_base_atom_parser(struct ref_format *format,
-			       struct used_atom *atom UNUSED,
+static int is_base_atom_parser(struct ref_format *format UNUSED,
+			       struct used_atom *atom,
 			       const char *arg, struct strbuf *err)
 {
-	struct string_list_item *item;
-
 	if (!arg)
 		return strbuf_addf_ret(err, -1, _("expected format: %%(is-base:<committish>)"));
 
-	item = string_list_append(&format->is_base_tips, arg);
-	item->util = lookup_commit_reference_by_name(arg);
-	if (!item->util)
+	atom->u.base.name = xstrdup(arg);
+	atom->u.base.commit = lookup_commit_reference_by_name(arg);
+	if (!atom->u.base.commit)
 		die("failed to find '%s'", arg);
 
 	return 0;
@@ -3009,6 +3008,8 @@ void ref_array_clear(struct ref_array *array)
 			free(atom->u.head);
 		else if (atom->atom_type == ATOM_DESCRIBE)
 			strvec_clear(&atom->u.describe_args);
+		else if (atom->atom_type == ATOM_ISBASE)
+			free(atom->u.base.name);
 		else if (atom->atom_type == ATOM_TRAILERS ||
 			 (atom->atom_type == ATOM_CONTENTS &&
 			  atom->u.contents.option == C_TRAILERS)) {
@@ -3041,7 +3042,7 @@ static void reach_filter(struct ref_array *array,
 			 struct commit_list **check_reachable,
 			 int include_reached)
 {
-	int i, old_nr;
+	size_t i, old_nr;
 	struct commit **to_clear;
 
 	if (!*check_reachable)
@@ -3084,22 +3085,30 @@ static void reach_filter(struct ref_array *array,
 }
 
 void filter_ahead_behind(struct repository *r,
-			 struct ref_format *format,
 			 struct ref_array *array)
 {
 	struct commit **commits;
-	size_t commits_nr = format->bases.nr + array->nr;
+	size_t bases_nr, commits_nr;
 
-	if (!format->bases.nr || !array->nr)
+	if (!array->nr)
 		return;
 
-	ALLOC_ARRAY(commits, commits_nr);
-	for (size_t i = 0; i < format->bases.nr; i++)
-		commits[i] = format->bases.items[i].util;
+	for (size_t i = bases_nr = 0; i < used_atom_cnt; i++) {
+		if (used_atom[i].atom_type == ATOM_AHEADBEHIND)
+			bases_nr++;
+	}
+	if (!bases_nr)
+		return;
 
-	ALLOC_ARRAY(array->counts, st_mult(format->bases.nr, array->nr));
+	ALLOC_ARRAY(commits, st_add(bases_nr, array->nr));
+	for (size_t i = 0, j = 0; i < used_atom_cnt; i++) {
+		if (used_atom[i].atom_type == ATOM_AHEADBEHIND)
+			commits[j++] = used_atom[i].u.base.commit;
+	}
 
-	commits_nr = format->bases.nr;
+	ALLOC_ARRAY(array->counts, st_mult(bases_nr, array->nr));
+
+	commits_nr = bases_nr;
 	array->counts_nr = 0;
 	for (size_t i = 0; i < array->nr; i++) {
 		const char *name = array->items[i]->refname;
@@ -3108,8 +3117,8 @@ void filter_ahead_behind(struct repository *r,
 		if (!commits[commits_nr])
 			continue;
 
-		CALLOC_ARRAY(array->items[i]->counts, format->bases.nr);
-		for (size_t j = 0; j < format->bases.nr; j++) {
+		CALLOC_ARRAY(array->items[i]->counts, bases_nr);
+		for (size_t j = 0; j < bases_nr; j++) {
 			struct ahead_behind_count *count;
 			count = &array->counts[array->counts_nr++];
 			count->tip_index = commits_nr;
@@ -3125,14 +3134,20 @@ void filter_ahead_behind(struct repository *r,
 }
 
 void filter_is_base(struct repository *r,
-		    struct ref_format *format,
 		    struct ref_array *array)
 {
 	struct commit **bases;
-	size_t bases_nr = 0;
+	size_t bases_nr = 0, is_base_nr;
 	struct ref_array_item **back_index;
 
-	if (!format->is_base_tips.nr || !array->nr)
+	if (!array->nr)
+		return;
+
+	for (size_t i = is_base_nr = 0; i < used_atom_cnt; i++) {
+		if (used_atom[i].atom_type == ATOM_ISBASE)
+			is_base_nr++;
+	}
+	if (!is_base_nr)
 		return;
 
 	CALLOC_ARRAY(back_index, array->nr);
@@ -3142,7 +3157,7 @@ void filter_is_base(struct repository *r,
 		const char *name = array->items[i]->refname;
 		struct commit *c = lookup_commit_reference_by_name_gently(name, 1);
 
-		CALLOC_ARRAY(array->items[i]->is_base, format->is_base_tips.nr);
+		CALLOC_ARRAY(array->items[i]->is_base, is_base_nr);
 
 		if (!c)
 			continue;
@@ -3152,15 +3167,20 @@ void filter_is_base(struct repository *r,
 		bases_nr++;
 	}
 
-	for (size_t i = 0; i < format->is_base_tips.nr; i++) {
-		struct commit *tip = format->is_base_tips.items[i].util;
-		int base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);
+	for (size_t i = 0, j = 0; i < used_atom_cnt; i++) {
+		struct commit *tip;
+		int base_index;
 
+		if (used_atom[i].atom_type != ATOM_ISBASE)
+			continue;
+
+		tip = used_atom[i].u.base.commit;
+		base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);
 		if (base_index < 0)
 			continue;
 
 		/* Store the string for use in output later. */
-		back_index[base_index]->is_base[i] = xstrdup(format->is_base_tips.items[i].string);
+		back_index[base_index]->is_base[j++] = xstrdup(used_atom[i].u.base.name);
 	}
 
 	free(back_index);
@@ -3252,8 +3272,7 @@ struct ref_sorting {
 };
 
 static inline int can_do_iterative_format(struct ref_filter *filter,
-					  struct ref_sorting *sorting,
-					  struct ref_format *format)
+					  struct ref_sorting *sorting)
 {
 	/*
 	 * Reference backends sort patterns lexicographically by refname, so if
@@ -3277,17 +3296,20 @@ static inline int can_do_iterative_format(struct ref_filter *filter,
 	 * - filtering on reachability
 	 * - including ahead-behind information in the formatted output
 	 */
-	return !(filter->reachable_from ||
-		 filter->unreachable_from ||
-		 format->bases.nr ||
-		 format->is_base_tips.nr);
+	for (size_t i = 0; i < used_atom_cnt; i++) {
+		if (used_atom[i].atom_type == ATOM_AHEADBEHIND)
+			return 0;
+		if (used_atom[i].atom_type == ATOM_ISBASE)
+			return 0;
+	}
+	return !(filter->reachable_from || filter->unreachable_from);
 }
 
 void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
 			    struct ref_sorting *sorting,
 			    struct ref_format *format)
 {
-	if (can_do_iterative_format(filter, sorting, format)) {
+	if (can_do_iterative_format(filter, sorting)) {
 		int save_commit_buffer_orig;
 		struct ref_filter_and_format_cbdata ref_cbdata = {
 			.filter = filter,
@@ -3303,8 +3325,8 @@ void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
 	} else {
 		struct ref_array array = { 0 };
 		filter_refs(&array, filter, type);
-		filter_ahead_behind(the_repository, format, &array);
-		filter_is_base(the_repository, format, &array);
+		filter_ahead_behind(the_repository, &array);
+		filter_is_base(the_repository, &array);
 		ref_array_sort(sorting, &array);
 		print_formatted_ref_array(&array, format);
 		ref_array_clear(&array);
@@ -3638,16 +3660,3 @@ void ref_filter_clear(struct ref_filter *filter)
 	free_commit_list(filter->unreachable_from);
 	ref_filter_init(filter);
 }
-
-void ref_format_init(struct ref_format *format)
-{
-	struct ref_format blank = REF_FORMAT_INIT;
-	memcpy(format, &blank, sizeof(blank));
-}
-
-void ref_format_clear(struct ref_format *format)
-{
-	string_list_clear(&format->bases, 0);
-	string_list_clear(&format->is_base_tips, 0);
-	ref_format_init(format);
-}
diff --git a/ref-filter.h b/ref-filter.h
index 754038a..013d4cf 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -99,12 +99,6 @@ struct ref_format {
 	/* Internal state to ref-filter */
 	int need_color_reset_at_eol;
 
-	/* List of bases for ahead-behind counts. */
-	struct string_list bases;
-
-	/* List of bases for is-base indicators. */
-	struct string_list is_base_tips;
-
 	struct {
 		int max_count;
 		int omit_empty;
@@ -117,8 +111,6 @@ struct ref_format {
 }
 #define REF_FORMAT_INIT {             \
 	.use_color = -1,              \
-	.bases = STRING_LIST_INIT_DUP, \
-	.is_base_tips = STRING_LIST_INIT_DUP, \
 }
 
 /*  Macros for checking --merged and --no-merged options */
@@ -205,7 +197,6 @@ struct ref_array_item *ref_array_push(struct ref_array *array,
  * If this is not called, then any ahead-behind atoms will be blank.
  */
 void filter_ahead_behind(struct repository *r,
-			 struct ref_format *format,
 			 struct ref_array *array);
 
 /*
@@ -215,13 +206,9 @@ void filter_ahead_behind(struct repository *r,
  * If this is not called, then any is-base atoms will be blank.
  */
 void filter_is_base(struct repository *r,
-		    struct ref_format *format,
 		    struct ref_array *array);
 
 void ref_filter_init(struct ref_filter *filter);
 void ref_filter_clear(struct ref_filter *filter);
 
-void ref_format_init(struct ref_format *format);
-void ref_format_clear(struct ref_format *format);
-
 #endif /*  REF_FILTER_H  */
diff --git a/refs.c b/refs.c
index 0f41b2f..1184652 100644
--- a/refs.c
+++ b/refs.c
@@ -1318,19 +1318,27 @@ int ref_transaction_update(struct ref_transaction *transaction,
 	return 0;
 }
 
-int ref_transaction_update_reflog(struct ref_transaction *transaction,
-				  const char *refname,
-				  const struct object_id *new_oid,
-				  const struct object_id *old_oid,
-				  const char *committer_info, unsigned int flags,
-				  const char *msg, unsigned int index,
-				  struct strbuf *err)
+/*
+ * Similar to`ref_transaction_update`, but this function is only for adding
+ * a reflog update. Supports providing custom committer information. The index
+ * field can be utiltized to order updates as desired. When not used, the
+ * updates default to being ordered by refname.
+ */
+static int ref_transaction_update_reflog(struct ref_transaction *transaction,
+					 const char *refname,
+					 const struct object_id *new_oid,
+					 const struct object_id *old_oid,
+					 const char *committer_info,
+					 unsigned int flags,
+					 const char *msg,
+					 uint64_t index,
+					 struct strbuf *err)
 {
 	struct ref_update *update;
 
 	assert(err);
 
-	flags |= REF_LOG_ONLY | REF_NO_DEREF;
+	flags |= REF_LOG_ONLY | REF_FORCE_CREATE_REFLOG | REF_NO_DEREF;
 
 	if (!transaction_refname_valid(refname, new_oid, flags, err))
 		return -1;
@@ -1345,6 +1353,13 @@ int ref_transaction_update_reflog(struct ref_transaction *transaction,
 	update->flags &= ~REF_HAVE_OLD;
 	update->index = index;
 
+	/*
+	 * Reference backends may need to know the max index to optimize
+	 * their writes. So we store the max_index on the transaction level.
+	 */
+	if (index > transaction->max_index)
+		transaction->max_index = index;
+
 	return 0;
 }
 
@@ -2139,7 +2154,7 @@ struct ref_store *repo_get_submodule_ref_store(struct repository *repo,
 	if (!is_nonbare_repository_dir(&submodule_sb))
 		goto done;
 
-	if (submodule_to_gitdir(&submodule_sb, submodule))
+	if (submodule_to_gitdir(repo, &submodule_sb, submodule))
 		goto done;
 
 	subrepo = xmalloc(sizeof(*subrepo));
@@ -2177,8 +2192,8 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt)
 
 	if (wt->id) {
 		struct strbuf common_path = STRBUF_INIT;
-		strbuf_git_common_path(&common_path, wt->repo,
-				      "worktrees/%s", wt->id);
+		repo_common_path_append(wt->repo, &common_path,
+					"worktrees/%s", wt->id);
 		refs = ref_store_init(wt->repo, wt->repo->ref_storage_format,
 				      common_path.buf, REF_STORE_ALL_CAPS);
 		strbuf_release(&common_path);
@@ -2798,7 +2813,7 @@ static int migrate_one_ref(const char *refname, const char *referent UNUSED, con
 }
 
 struct reflog_migration_data {
-	unsigned int index;
+	uint64_t index;
 	const char *refname;
 	struct ref_store *old_refs;
 	struct ref_transaction *transaction;
@@ -3028,9 +3043,11 @@ int repo_migrate_ref_storage_format(struct repository *repo,
 	if (ret < 0)
 		goto done;
 
-	ret = refs_for_each_reflog(old_refs, migrate_one_reflog, &data);
-	if (ret < 0)
-		goto done;
+	if (!(flags & REPO_MIGRATE_REF_STORAGE_FORMAT_SKIP_REFLOG)) {
+		ret = refs_for_each_reflog(old_refs, migrate_one_reflog, &data);
+		if (ret < 0)
+			goto done;
+	}
 
 	ret = ref_transaction_commit(transaction, errbuf);
 	if (ret < 0)
diff --git a/refs.h b/refs.h
index a0cdd99..8442e89 100644
--- a/refs.h
+++ b/refs.h
@@ -577,7 +577,7 @@ int refs_for_each_reflog(struct ref_store *refs, each_reflog_fn fn, void *cb_dat
 
 /*
  * Return 0 iff refname has the correct format for a refname according
- * to the rules described in Documentation/git-check-ref-format.txt.
+ * to the rules described in Documentation/git-check-ref-format.adoc.
  * If REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level
  * reference names.  If REFNAME_REFSPEC_PATTERN is set in flags, then
  * allow a single "*" wildcard character in the refspec. No leading or
@@ -772,20 +772,6 @@ int ref_transaction_update(struct ref_transaction *transaction,
 			   struct strbuf *err);
 
 /*
- * Similar to`ref_transaction_update`, but this function is only for adding
- * a reflog update. Supports providing custom committer information. The index
- * field can be utiltized to order updates as desired. When not used, the
- * updates default to being ordered by refname.
- */
-int ref_transaction_update_reflog(struct ref_transaction *transaction,
-				  const char *refname,
-				  const struct object_id *new_oid,
-				  const struct object_id *old_oid,
-				  const char *committer_info, unsigned int flags,
-				  const char *msg, unsigned int index,
-				  struct strbuf *err);
-
-/*
  * Add a reference creation to transaction. new_oid is the value that
  * the reference should have after the update; it must not be
  * null_oid. It is verified that the reference does not exist
@@ -1157,8 +1143,11 @@ int is_pseudo_ref(const char *refname);
  *   - REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN: perform a dry-run migration
  *     without touching the main repository. The result will be written into a
  *     temporary ref storage directory.
+ *
+ *   - REPO_MIGRATE_REF_STORAGE_FORMAT_SKIP_REFLOG: skip migration of reflogs.
  */
-#define REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN (1 << 0)
+#define REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN      (1 << 0)
+#define REPO_MIGRATE_REF_STORAGE_FORMAT_SKIP_REFLOG (1 << 1)
 
 /*
  * Migrate the ref storage format used by the repository to the
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 5cfb8b7..6c6e67d 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1831,7 +1831,7 @@ static int log_ref_setup(struct files_ref_store *refs,
 	}
 
 	if (*logfd >= 0)
-		adjust_shared_perm(logfile);
+		adjust_shared_perm(the_repository, logfile);
 
 	free(logfile);
 	return 0;
@@ -2615,9 +2615,6 @@ static int lock_ref_for_update(struct files_ref_store *refs,
 
 	update->backend_data = lock;
 
-	if (update->flags & REF_LOG_ONLY)
-		goto out;
-
 	if (update->type & REF_ISSYMREF) {
 		if (update->flags & REF_NO_DEREF) {
 			/*
@@ -3491,8 +3488,8 @@ static int files_ref_store_create_on_disk(struct ref_store *ref_store,
 	 *   they do not understand the reference format extension.
 	 */
 	strbuf_addf(&sb, "%s/refs", ref_store->gitdir);
-	safe_create_dir(sb.buf, 1);
-	adjust_shared_perm(sb.buf);
+	safe_create_dir(the_repository, sb.buf, 1);
+	adjust_shared_perm(the_repository, sb.buf);
 
 	/*
 	 * There is no need to create directories for common refs when creating
@@ -3504,11 +3501,11 @@ static int files_ref_store_create_on_disk(struct ref_store *ref_store,
 		 */
 		strbuf_reset(&sb);
 		files_ref_path(refs, &sb, "refs/heads");
-		safe_create_dir(sb.buf, 1);
+		safe_create_dir(the_repository, sb.buf, 1);
 
 		strbuf_reset(&sb);
 		files_ref_path(refs, &sb, "refs/tags");
-		safe_create_dir(sb.buf, 1);
+		safe_create_dir(the_repository, sb.buf, 1);
 	}
 
 	strbuf_release(&sb);
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 1655086..8894b43 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -120,7 +120,7 @@ struct ref_update {
 	 * when migrating reflogs and we want to ensure we carry over the
 	 * same order.
 	 */
-	unsigned int index;
+	uint64_t index;
 
 	/*
 	 * If this ref_update was split off of a symref update via
@@ -203,6 +203,7 @@ struct ref_transaction {
 	enum ref_transaction_state state;
 	void *backend_data;
 	unsigned int flags;
+	uint64_t max_index;
 };
 
 /*
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 00d95a9..771f50d 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -380,7 +380,7 @@ static struct ref_store *reftable_be_init(struct repository *repo,
 	default:
 		BUG("unknown hash algorithm %d", repo->hash_algo->format_id);
 	}
-	refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask);
+	refs->write_options.default_permissions = calc_shared_perm(the_repository, 0666 & ~mask);
 	refs->write_options.disable_auto_compact =
 		!git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
 	refs->write_options.lock_timeout_ms = 100;
@@ -470,21 +470,21 @@ static int reftable_be_create_on_disk(struct ref_store *ref_store,
 	struct strbuf sb = STRBUF_INIT;
 
 	strbuf_addf(&sb, "%s/reftable", refs->base.gitdir);
-	safe_create_dir(sb.buf, 1);
+	safe_create_dir(the_repository, sb.buf, 1);
 	strbuf_reset(&sb);
 
 	strbuf_addf(&sb, "%s/HEAD", refs->base.gitdir);
 	write_file(sb.buf, "ref: refs/heads/.invalid");
-	adjust_shared_perm(sb.buf);
+	adjust_shared_perm(the_repository, sb.buf);
 	strbuf_reset(&sb);
 
 	strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
-	safe_create_dir(sb.buf, 1);
+	safe_create_dir(the_repository, sb.buf, 1);
 	strbuf_reset(&sb);
 
 	strbuf_addf(&sb, "%s/refs/heads", refs->base.gitdir);
 	write_file(sb.buf, "this repository uses the reftable format");
-	adjust_shared_perm(sb.buf);
+	adjust_shared_perm(the_repository, sb.buf);
 
 	strbuf_release(&sb);
 	return 0;
@@ -942,6 +942,7 @@ struct write_transaction_table_arg {
 	size_t updates_nr;
 	size_t updates_alloc;
 	size_t updates_expected;
+	uint64_t max_index;
 };
 
 struct reftable_transaction_data {
@@ -1019,6 +1020,7 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
 		arg->updates_nr = 0;
 		arg->updates_alloc = 0;
 		arg->updates_expected = 0;
+		arg->max_index = 0;
 	}
 
 	arg->updates_expected++;
@@ -1428,7 +1430,6 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
 	struct reftable_log_record *logs = NULL;
 	struct ident_split committer_ident = {0};
 	size_t logs_nr = 0, logs_alloc = 0, i;
-	uint64_t max_update_index = ts;
 	const char *committer_info;
 	int ret = 0;
 
@@ -1438,7 +1439,14 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
 
 	QSORT(arg->updates, arg->updates_nr, transaction_update_cmp);
 
-	reftable_writer_set_limits(writer, ts, ts);
+	/*
+	 * During reflog migration, we add indexes for a single reflog with
+	 * multiple entries. Each entry will contain a different update_index,
+	 * so set the limits accordingly.
+	 */
+	ret = reftable_writer_set_limits(writer, ts, ts + arg->max_index);
+	if (ret < 0)
+		goto done;
 
 	for (i = 0; i < arg->updates_nr; i++) {
 		struct reftable_transaction_update *tx_update = &arg->updates[i];
@@ -1540,12 +1548,6 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
 				 */
 				log->update_index = ts + u->index;
 
-				/*
-				 * Note the max update_index so the limit can be set later on.
-				 */
-				if (log->update_index > max_update_index)
-					max_update_index = log->update_index;
-
 				log->refname = xstrdup(u->refname);
 				memcpy(log->value.update.new_hash,
 				       u->new_oid.hash, GIT_MAX_RAWSZ);
@@ -1609,8 +1611,6 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
 	 * and log blocks.
 	 */
 	if (logs) {
-		reftable_writer_set_limits(writer, ts, max_update_index);
-
 		ret = reftable_writer_add_logs(writer, logs, logs_nr);
 		if (ret < 0)
 			goto done;
@@ -1632,6 +1632,8 @@ static int reftable_be_transaction_finish(struct ref_store *ref_store UNUSED,
 	int ret = 0;
 
 	for (size_t i = 0; i < tx_data->args_nr; i++) {
+		tx_data->args[i].max_index = transaction->max_index;
+
 		ret = reftable_addition_add(tx_data->args[i].addition,
 					    write_transaction_table, &tx_data->args[i]);
 		if (ret < 0)
@@ -1766,7 +1768,9 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
 	deletion_ts = creation_ts = reftable_stack_next_update_index(arg->be->stack);
 	if (arg->delete_old)
 		creation_ts++;
-	reftable_writer_set_limits(writer, deletion_ts, creation_ts);
+	ret = reftable_writer_set_limits(writer, deletion_ts, creation_ts);
+	if (ret < 0)
+		goto done;
 
 	/*
 	 * Add the new reference. If this is a rename then we also delete the
@@ -2298,7 +2302,9 @@ static int write_reflog_existence_table(struct reftable_writer *writer,
 	if (ret <= 0)
 		goto done;
 
-	reftable_writer_set_limits(writer, ts, ts);
+	ret = reftable_writer_set_limits(writer, ts, ts);
+	if (ret < 0)
+		goto done;
 
 	/*
 	 * The existence entry has both old and new object ID set to the
@@ -2357,7 +2363,9 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
 	uint64_t ts = reftable_stack_next_update_index(arg->stack);
 	int ret;
 
-	reftable_writer_set_limits(writer, ts, ts);
+	ret = reftable_writer_set_limits(writer, ts, ts);
+	if (ret < 0)
+		goto out;
 
 	ret = reftable_stack_init_log_iterator(arg->stack, &it);
 	if (ret < 0)
@@ -2434,7 +2442,9 @@ static int write_reflog_expiry_table(struct reftable_writer *writer, void *cb_da
 		if (arg->records[i].value_type == REFTABLE_LOG_UPDATE)
 			live_records++;
 
-	reftable_writer_set_limits(writer, ts, ts);
+	ret = reftable_writer_set_limits(writer, ts, ts);
+	if (ret < 0)
+		return ret;
 
 	if (!is_null_oid(&arg->update_oid)) {
 		struct reftable_ref_record ref = {0};
diff --git a/refspec.c b/refspec.c
index 6d86e04..4cb80b5 100644
--- a/refspec.c
+++ b/refspec.c
@@ -5,9 +5,11 @@
 #include "gettext.h"
 #include "hash.h"
 #include "hex.h"
+#include "string-list.h"
 #include "strvec.h"
 #include "refs.h"
 #include "refspec.h"
+#include "remote.h"
 #include "strbuf.h"
 
 /*
@@ -236,16 +238,6 @@ int valid_fetch_refspec(const char *fetch_refspec_str)
 	return ret;
 }
 
-int valid_remote_name(const char *name)
-{
-	int result;
-	struct strbuf refspec = STRBUF_INIT;
-	strbuf_addf(&refspec, "refs/heads/test:refs/remotes/%s/test", name);
-	result = valid_fetch_refspec(refspec.buf);
-	strbuf_release(&refspec);
-	return result;
-}
-
 void refspec_ref_prefixes(const struct refspec *rs,
 			  struct strvec *ref_prefixes)
 {
@@ -276,3 +268,204 @@ void refspec_ref_prefixes(const struct refspec *rs,
 		}
 	}
 }
+
+int match_refname_with_pattern(const char *pattern, const char *refname,
+				   const char *replacement, char **result)
+{
+	const char *kstar = strchr(pattern, '*');
+	size_t klen;
+	size_t ksuffixlen;
+	size_t namelen;
+	int ret;
+	if (!kstar)
+		die(_("pattern '%s' has no '*'"), pattern);
+	klen = kstar - pattern;
+	ksuffixlen = strlen(kstar + 1);
+	namelen = strlen(refname);
+	ret = !strncmp(refname, pattern, klen) && namelen >= klen + ksuffixlen &&
+		!memcmp(refname + namelen - ksuffixlen, kstar + 1, ksuffixlen);
+	if (ret && replacement) {
+		struct strbuf sb = STRBUF_INIT;
+		const char *vstar = strchr(replacement, '*');
+		if (!vstar)
+			die(_("replacement '%s' has no '*'"), replacement);
+		strbuf_add(&sb, replacement, vstar - replacement);
+		strbuf_add(&sb, refname + klen, namelen - klen - ksuffixlen);
+		strbuf_addstr(&sb, vstar + 1);
+		*result = strbuf_detach(&sb, NULL);
+	}
+	return ret;
+}
+
+static int refspec_match(const struct refspec_item *refspec,
+			 const char *name)
+{
+	if (refspec->pattern)
+		return match_refname_with_pattern(refspec->src, name, NULL, NULL);
+
+	return !strcmp(refspec->src, name);
+}
+
+int refname_matches_negative_refspec_item(const char *refname, struct refspec *rs)
+{
+	int i;
+
+	for (i = 0; i < rs->nr; i++) {
+		if (rs->items[i].negative && refspec_match(&rs->items[i], refname))
+			return 1;
+	}
+	return 0;
+}
+
+static int refspec_find_negative_match(struct refspec *rs, struct refspec_item *query)
+{
+	int i, matched_negative = 0;
+	int find_src = !query->src;
+	struct string_list reversed = STRING_LIST_INIT_DUP;
+	const char *needle = find_src ? query->dst : query->src;
+
+	/*
+	 * Check whether the queried ref matches any negative refpsec. If so,
+	 * then we should ultimately treat this as not matching the query at
+	 * all.
+	 *
+	 * Note that negative refspecs always match the source, but the query
+	 * item uses the destination. To handle this, we apply pattern
+	 * refspecs in reverse to figure out if the query source matches any
+	 * of the negative refspecs.
+	 *
+	 * The first loop finds and expands all positive refspecs
+	 * matched by the queried ref.
+	 *
+	 * The second loop checks if any of the results of the first loop
+	 * match any negative refspec.
+	 */
+	for (i = 0; i < rs->nr; i++) {
+		struct refspec_item *refspec = &rs->items[i];
+		char *expn_name;
+
+		if (refspec->negative)
+			continue;
+
+		/* Note the reversal of src and dst */
+		if (refspec->pattern) {
+			const char *key = refspec->dst ? refspec->dst : refspec->src;
+			const char *value = refspec->src;
+
+			if (match_refname_with_pattern(key, needle, value, &expn_name))
+				string_list_append_nodup(&reversed, expn_name);
+		} else if (refspec->matching) {
+			/* For the special matching refspec, any query should match */
+			string_list_append(&reversed, needle);
+		} else if (!refspec->src) {
+			BUG("refspec->src should not be null here");
+		} else if (!strcmp(needle, refspec->src)) {
+			string_list_append(&reversed, refspec->src);
+		}
+	}
+
+	for (i = 0; !matched_negative && i < reversed.nr; i++) {
+		if (refname_matches_negative_refspec_item(reversed.items[i].string, rs))
+			matched_negative = 1;
+	}
+
+	string_list_clear(&reversed, 0);
+
+	return matched_negative;
+}
+
+void refspec_find_all_matches(struct refspec *rs,
+				    struct refspec_item *query,
+				    struct string_list *results)
+{
+	int i;
+	int find_src = !query->src;
+
+	if (find_src && !query->dst)
+		BUG("refspec_find_all_matches: need either src or dst");
+
+	if (refspec_find_negative_match(rs, query))
+		return;
+
+	for (i = 0; i < rs->nr; i++) {
+		struct refspec_item *refspec = &rs->items[i];
+		const char *key = find_src ? refspec->dst : refspec->src;
+		const char *value = find_src ? refspec->src : refspec->dst;
+		const char *needle = find_src ? query->dst : query->src;
+		char **result = find_src ? &query->src : &query->dst;
+
+		if (!refspec->dst || refspec->negative)
+			continue;
+		if (refspec->pattern) {
+			if (match_refname_with_pattern(key, needle, value, result))
+				string_list_append_nodup(results, *result);
+		} else if (!strcmp(needle, key)) {
+			string_list_append(results, value);
+		}
+	}
+}
+
+int refspec_find_match(struct refspec *rs, struct refspec_item *query)
+{
+	int i;
+	int find_src = !query->src;
+	const char *needle = find_src ? query->dst : query->src;
+	char **result = find_src ? &query->src : &query->dst;
+
+	if (find_src && !query->dst)
+		BUG("refspec_find_match: need either src or dst");
+
+	if (refspec_find_negative_match(rs, query))
+		return -1;
+
+	for (i = 0; i < rs->nr; i++) {
+		struct refspec_item *refspec = &rs->items[i];
+		const char *key = find_src ? refspec->dst : refspec->src;
+		const char *value = find_src ? refspec->src : refspec->dst;
+
+		if (!refspec->dst || refspec->negative)
+			continue;
+		if (refspec->pattern) {
+			if (match_refname_with_pattern(key, needle, value, result)) {
+				query->force = refspec->force;
+				return 0;
+			}
+		} else if (!strcmp(needle, key)) {
+			*result = xstrdup(value);
+			query->force = refspec->force;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+struct ref *apply_negative_refspecs(struct ref *ref_map, struct refspec *rs)
+{
+	struct ref **tail;
+
+	for (tail = &ref_map; *tail; ) {
+		struct ref *ref = *tail;
+
+		if (refname_matches_negative_refspec_item(ref->name, rs)) {
+			*tail = ref->next;
+			free(ref->peer_ref);
+			free(ref);
+		} else
+			tail = &ref->next;
+	}
+
+	return ref_map;
+}
+
+char *apply_refspecs(struct refspec *rs, const char *name)
+{
+	struct refspec_item query;
+
+	memset(&query, 0, sizeof(struct refspec_item));
+	query.src = (char *)name;
+
+	if (refspec_find_match(rs, &query))
+		return NULL;
+
+	return query.dst;
+}
diff --git a/refspec.h b/refspec.h
index 69d693c..e2b5cc5 100644
--- a/refspec.h
+++ b/refspec.h
@@ -30,6 +30,8 @@ struct refspec_item {
 	char *raw;
 };
 
+struct string_list;
+
 #define REFSPEC_FETCH 1
 #define REFSPEC_PUSH 0
 
@@ -61,7 +63,6 @@ void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);
 void refspec_clear(struct refspec *rs);
 
 int valid_fetch_refspec(const char *refspec);
-int valid_remote_name(const char *name);
 
 struct strvec;
 /*
@@ -71,4 +72,40 @@ struct strvec;
 void refspec_ref_prefixes(const struct refspec *rs,
 			  struct strvec *ref_prefixes);
 
+int refname_matches_negative_refspec_item(const char *refname, struct refspec *rs);
+
+/*
+ * Checks if a refname matches a globbing refspec pattern.
+ * If replacement is provided, computes the corresponding mapped refname.
+ * Returns 1 if refname matches pattern, 0 otherwise.
+ */
+int match_refname_with_pattern(const char *pattern, const char *refname,
+				   const char *replacement, char **result);
+
+/*
+ * Queries a refspec for a match and updates the query item.
+ * Returns 0 on success, -1 if no match is found or negative refspec matches.
+ */
+int refspec_find_match(struct refspec *rs, struct refspec_item *query);
+
+/*
+ * Queries a refspec for all matches and appends results to the provided string
+ * list.
+ */
+void refspec_find_all_matches(struct refspec *rs,
+				    struct refspec_item *query,
+				    struct string_list *results);
+
+/*
+ * Remove all entries in the input list which match any negative refspec in
+ * the refspec list.
+ */
+struct ref *apply_negative_refspecs(struct ref *ref_map, struct refspec *rs);
+
+/*
+ * Search for a refspec that matches the given name and return the
+ * corresponding destination (dst) if a match is found, NULL otherwise.
+ */
+char *apply_refspecs(struct refspec *rs, const char *name);
+
 #endif /* REFSPEC_H */
diff --git a/reftable/basics.c b/reftable/basics.c
index fe2b83f..3b5ea27 100644
--- a/reftable/basics.c
+++ b/reftable/basics.c
@@ -263,18 +263,16 @@ int names_equal(const char **a, const char **b)
 	return a[i] == b[i];
 }
 
-int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b)
+size_t common_prefix_size(struct reftable_buf *a, struct reftable_buf *b)
 {
-	int p = 0;
-	for (; p < a->len && p < b->len; p++) {
+	size_t p = 0;
+	for (; p < a->len && p < b->len; p++)
 		if (a->buf[p] != b->buf[p])
 			break;
-	}
-
 	return p;
 }
 
-int hash_size(enum reftable_hash id)
+uint32_t hash_size(enum reftable_hash id)
 {
 	if (!id)
 		return REFTABLE_HASH_SIZE_SHA1;
diff --git a/reftable/basics.h b/reftable/basics.h
index 4bf71b0..a2a010a 100644
--- a/reftable/basics.h
+++ b/reftable/basics.h
@@ -169,9 +169,9 @@ static inline void *reftable_alloc_grow(void *p, size_t nelem, size_t elsize,
 #endif
 
 /* Find the longest shared prefix size of `a` and `b` */
-int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b);
+size_t common_prefix_size(struct reftable_buf *a, struct reftable_buf *b);
 
-int hash_size(enum reftable_hash id);
+uint32_t hash_size(enum reftable_hash id);
 
 /*
  * Format IDs that identify the hash function used by a reftable. Note that
diff --git a/reftable/block.c b/reftable/block.c
index 9858bbc..b14a8f1 100644
--- a/reftable/block.c
+++ b/reftable/block.c
@@ -13,9 +13,8 @@ license that can be found in the LICENSE file or at
 #include "record.h"
 #include "reftable-error.h"
 #include "system.h"
-#include <zlib.h>
 
-int header_size(int version)
+size_t header_size(int version)
 {
 	switch (version) {
 	case 1:
@@ -26,7 +25,7 @@ int header_size(int version)
 	abort();
 }
 
-int footer_size(int version)
+size_t footer_size(int version)
 {
 	switch (version) {
 	case 1:
@@ -40,16 +39,15 @@ int footer_size(int version)
 static int block_writer_register_restart(struct block_writer *w, int n,
 					 int is_restart, struct reftable_buf *key)
 {
-	int rlen, err;
+	uint32_t rlen;
+	int err;
 
 	rlen = w->restart_len;
-	if (rlen >= MAX_RESTARTS) {
+	if (rlen >= MAX_RESTARTS)
 		is_restart = 0;
-	}
 
-	if (is_restart) {
+	if (is_restart)
 		rlen++;
-	}
 	if (2 + 3 * rlen + n > w->block_size - w->next)
 		return -1;
 	if (is_restart) {
@@ -72,7 +70,7 @@ static int block_writer_register_restart(struct block_writer *w, int n,
 }
 
 int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *block,
-		      uint32_t block_size, uint32_t header_off, int hash_size)
+		      uint32_t block_size, uint32_t header_off, uint32_t hash_size)
 {
 	bw->block = block;
 	bw->hash_size = hash_size;
@@ -148,8 +146,7 @@ int block_writer_add(struct block_writer *w, struct reftable_record *rec)
 
 int block_writer_finish(struct block_writer *w)
 {
-	int i;
-	for (i = 0; i < w->restart_len; i++) {
+	for (uint32_t i = 0; i < w->restart_len; i++) {
 		put_be24(w->block + w->next, w->restarts[i]);
 		w->next += 3;
 	}
@@ -214,7 +211,7 @@ int block_writer_finish(struct block_writer *w)
 
 int block_reader_init(struct block_reader *br, struct reftable_block *block,
 		      uint32_t header_off, uint32_t table_block_size,
-		      int hash_size)
+		      uint32_t hash_size)
 {
 	uint32_t full_block_size = table_block_size;
 	uint8_t typ = block->data[header_off];
diff --git a/reftable/block.h b/reftable/block.h
index 0431e85..bef2b8a 100644
--- a/reftable/block.h
+++ b/reftable/block.h
@@ -30,7 +30,7 @@ struct block_writer {
 
 	/* How often to restart keys. */
 	uint16_t restart_interval;
-	int hash_size;
+	uint32_t hash_size;
 
 	/* Offset of next uint8_t to write. */
 	uint32_t next;
@@ -48,7 +48,7 @@ struct block_writer {
  * initializes the blockwriter to write `typ` entries, using `block` as temporary
  * storage. `block` is not owned by the block_writer. */
 int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *block,
-		      uint32_t block_size, uint32_t header_off, int hash_size);
+		      uint32_t block_size, uint32_t header_off, uint32_t hash_size);
 
 /* returns the block type (eg. 'r' for ref records. */
 uint8_t block_writer_type(struct block_writer *bw);
@@ -72,7 +72,7 @@ struct block_reader {
 
 	/* the memory block */
 	struct reftable_block block;
-	int hash_size;
+	uint32_t hash_size;
 
 	/* Uncompressed data for log entries. */
 	z_stream *zstream;
@@ -92,7 +92,7 @@ struct block_reader {
 /* initializes a block reader. */
 int block_reader_init(struct block_reader *br, struct reftable_block *bl,
 		      uint32_t header_off, uint32_t table_block_size,
-		      int hash_size);
+		      uint32_t hash_size);
 
 void block_reader_release(struct block_reader *br);
 
@@ -108,7 +108,7 @@ struct block_iter {
 	uint32_t next_off;
 	const unsigned char *block;
 	size_t block_len;
-	int hash_size;
+	uint32_t hash_size;
 
 	/* key for last entry we read. */
 	struct reftable_buf last_key;
@@ -137,10 +137,10 @@ void block_iter_reset(struct block_iter *it);
 void block_iter_close(struct block_iter *it);
 
 /* size of file header, depending on format version */
-int header_size(int version);
+size_t header_size(int version);
 
 /* size of file footer, depending on format version */
-int footer_size(int version);
+size_t footer_size(int version);
 
 /* returns a block to its source. */
 void reftable_block_done(struct reftable_block *ret);
diff --git a/reftable/blocksource.c b/reftable/blocksource.c
index 52e0915..bba4a45 100644
--- a/reftable/blocksource.c
+++ b/reftable/blocksource.c
@@ -24,8 +24,8 @@ static void reftable_buf_close(void *b UNUSED)
 {
 }
 
-static int reftable_buf_read_block(void *v, struct reftable_block *dest,
-				   uint64_t off, uint32_t size)
+static ssize_t reftable_buf_read_block(void *v, struct reftable_block *dest,
+				       uint64_t off, uint32_t size)
 {
 	struct reftable_buf *b = v;
 	assert(off + size <= b->len);
@@ -78,8 +78,8 @@ static void file_close(void *v)
 	reftable_free(b);
 }
 
-static int file_read_block(void *v, struct reftable_block *dest, uint64_t off,
-			   uint32_t size)
+static ssize_t file_read_block(void *v, struct reftable_block *dest, uint64_t off,
+			       uint32_t size)
 {
 	struct file_block_source *b = v;
 	assert(off + size <= b->size);
diff --git a/reftable/reader.c b/reftable/reader.c
index ea82955..24bae50 100644
--- a/reftable/reader.c
+++ b/reftable/reader.c
@@ -20,11 +20,11 @@ uint64_t block_source_size(struct reftable_block_source *source)
 	return source->ops->size(source->arg);
 }
 
-int block_source_read_block(struct reftable_block_source *source,
-			    struct reftable_block *dest, uint64_t off,
-			    uint32_t size)
+ssize_t block_source_read_block(struct reftable_block_source *source,
+				struct reftable_block *dest, uint64_t off,
+				uint32_t size)
 {
-	int result = source->ops->read_block(source->arg, dest, off, size);
+	ssize_t result = source->ops->read_block(source->arg, dest, off, size);
 	dest->source = *source;
 	return result;
 }
@@ -57,14 +57,17 @@ static int reader_get_block(struct reftable_reader *r,
 			    struct reftable_block *dest, uint64_t off,
 			    uint32_t sz)
 {
+	ssize_t bytes_read;
 	if (off >= r->size)
 		return 0;
-
-	if (off + sz > r->size) {
+	if (off + sz > r->size)
 		sz = r->size - off;
-	}
 
-	return block_source_read_block(&r->source, dest, off, sz);
+	bytes_read = block_source_read_block(&r->source, dest, off, sz);
+	if (bytes_read < 0)
+		return (int)bytes_read;
+
+	return 0;
 }
 
 enum reftable_hash reftable_reader_hash_id(struct reftable_reader *r)
@@ -601,6 +604,7 @@ int reftable_reader_new(struct reftable_reader **out,
 	struct reftable_reader *r;
 	uint64_t file_size = block_source_size(source);
 	uint32_t read_size;
+	ssize_t bytes_read;
 	int err;
 
 	REFTABLE_CALLOC_ARRAY(r, 1);
@@ -619,8 +623,8 @@ int reftable_reader_new(struct reftable_reader **out,
 		goto done;
 	}
 
-	err = block_source_read_block(source, &header, 0, read_size);
-	if (err != read_size) {
+	bytes_read = block_source_read_block(source, &header, 0, read_size);
+	if (bytes_read < 0 || (size_t)bytes_read != read_size) {
 		err = REFTABLE_IO_ERROR;
 		goto done;
 	}
@@ -645,9 +649,9 @@ int reftable_reader_new(struct reftable_reader **out,
 	r->hash_id = 0;
 	r->refcount = 1;
 
-	err = block_source_read_block(source, &footer, r->size,
-				      footer_size(r->version));
-	if (err != footer_size(r->version)) {
+	bytes_read = block_source_read_block(source, &footer, r->size,
+					     footer_size(r->version));
+	if (bytes_read < 0 || (size_t)bytes_read != footer_size(r->version)) {
 		err = REFTABLE_IO_ERROR;
 		goto done;
 	}
@@ -662,6 +666,8 @@ int reftable_reader_new(struct reftable_reader **out,
 	reftable_block_done(&footer);
 	reftable_block_done(&header);
 	if (err) {
+		if (r)
+			reftable_free(r->name);
 		reftable_free(r);
 		block_source_close(source);
 	}
@@ -750,7 +756,7 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
 	struct table_iter *ti;
 	struct filtering_ref_iterator *filter = NULL;
 	struct filtering_ref_iterator empty = FILTERING_REF_ITERATOR_INIT;
-	int oid_len = hash_size(r->hash_id);
+	uint32_t oid_len = hash_size(r->hash_id);
 	int err;
 
 	REFTABLE_ALLOC_ARRAY(ti, 1);
diff --git a/reftable/reader.h b/reftable/reader.h
index d2b48a4..bb72108 100644
--- a/reftable/reader.h
+++ b/reftable/reader.h
@@ -16,9 +16,9 @@ license that can be found in the LICENSE file or at
 
 uint64_t block_source_size(struct reftable_block_source *source);
 
-int block_source_read_block(struct reftable_block_source *source,
-			    struct reftable_block *dest, uint64_t off,
-			    uint32_t size);
+ssize_t block_source_read_block(struct reftable_block_source *source,
+				struct reftable_block *dest, uint64_t off,
+				uint32_t size);
 void block_source_close(struct reftable_block_source *source);
 
 /* metadata for a block type */
diff --git a/reftable/record.c b/reftable/record.c
index 04429d2..8919df8 100644
--- a/reftable/record.c
+++ b/reftable/record.c
@@ -21,47 +21,49 @@ static void *reftable_record_data(struct reftable_record *rec);
 
 int get_var_int(uint64_t *dest, struct string_view *in)
 {
-	int ptr = 0;
+	const unsigned char *buf = in->buf;
+	unsigned char c;
 	uint64_t val;
 
-	if (in->len == 0)
+	if (!in->len)
 		return -1;
-	val = in->buf[ptr] & 0x7f;
+	c = *buf++;
+	val = c & 0x7f;
 
-	while (in->buf[ptr] & 0x80) {
-		ptr++;
-		if (ptr > in->len) {
+	while (c & 0x80) {
+		/*
+		 * We use a micro-optimization here: whenever we see that the
+		 * 0x80 bit is set, we know that the remainder of the value
+		 * cannot be 0. The zero-values thus doesn't need to be encoded
+		 * at all, which is why we subtract 1 when encoding and add 1
+		 * when decoding.
+		 *
+		 * This allows us to save a byte in some edge cases.
+		 */
+		val += 1;
+		if (!val || (val & (uint64_t)(~0ULL << (64 - 7))))
+			return -1; /* overflow */
+		if (buf >= in->buf + in->len)
 			return -1;
-		}
-		val = (val + 1) << 7 | (uint64_t)(in->buf[ptr] & 0x7f);
+		c = *buf++;
+		val = (val << 7) + (c & 0x7f);
 	}
 
 	*dest = val;
-	return ptr + 1;
+	return buf - in->buf;
 }
 
-int put_var_int(struct string_view *dest, uint64_t val)
+int put_var_int(struct string_view *dest, uint64_t value)
 {
-	uint8_t buf[10] = { 0 };
-	int i = 9;
-	int n = 0;
-	buf[i] = (uint8_t)(val & 0x7f);
-	i--;
-	while (1) {
-		val >>= 7;
-		if (!val) {
-			break;
-		}
-		val--;
-		buf[i] = 0x80 | (uint8_t)(val & 0x7f);
-		i--;
-	}
-
-	n = sizeof(buf) - i - 1;
-	if (dest->len < n)
+	unsigned char varint[10];
+	unsigned pos = sizeof(varint) - 1;
+	varint[pos] = value & 0x7f;
+	while (value >>= 7)
+		varint[--pos] = 0x80 | (--value & 0x7f);
+	if (dest->len < sizeof(varint) - pos)
 		return -1;
-	memcpy(dest->buf, &buf[i + 1], n);
-	return n;
+	memcpy(dest->buf, varint + pos, sizeof(varint) - pos);
+	return sizeof(varint) - pos;
 }
 
 int reftable_is_block_type(uint8_t typ)
@@ -124,7 +126,7 @@ static int decode_string(struct reftable_buf *dest, struct string_view in)
 static int encode_string(const char *str, struct string_view s)
 {
 	struct string_view start = s;
-	int l = strlen(str);
+	size_t l = strlen(str);
 	int n = put_var_int(&s, l);
 	if (n < 0)
 		return -1;
@@ -142,9 +144,9 @@ int reftable_encode_key(int *restart, struct string_view dest,
 			uint8_t extra)
 {
 	struct string_view start = dest;
-	int prefix_len = common_prefix_size(&prev_key, &key);
+	size_t prefix_len = common_prefix_size(&prev_key, &key);
 	uint64_t suffix_len = key.len - prefix_len;
-	int n = put_var_int(&dest, (uint64_t)prefix_len);
+	int n = put_var_int(&dest, prefix_len);
 	if (n < 0)
 		return -1;
 	string_view_consume(&dest, n);
@@ -227,7 +229,7 @@ static int reftable_ref_record_key(const void *r, struct reftable_buf *dest)
 }
 
 static int reftable_ref_record_copy_from(void *rec, const void *src_rec,
-					 int hash_size)
+					 uint32_t hash_size)
 {
 	struct reftable_ref_record *ref = rec;
 	const struct reftable_ref_record *src = src_rec;
@@ -235,8 +237,6 @@ static int reftable_ref_record_copy_from(void *rec, const void *src_rec,
 	size_t refname_cap = 0;
 	int err;
 
-	assert(hash_size > 0);
-
 	SWAP(refname, ref->refname);
 	SWAP(refname_cap, ref->refname_cap);
 	reftable_ref_record_release(ref);
@@ -317,13 +317,12 @@ static uint8_t reftable_ref_record_val_type(const void *rec)
 }
 
 static int reftable_ref_record_encode(const void *rec, struct string_view s,
-				      int hash_size)
+				      uint32_t hash_size)
 {
 	const struct reftable_ref_record *r =
 		(const struct reftable_ref_record *)rec;
 	struct string_view start = s;
 	int n = put_var_int(&s, r->update_index);
-	assert(hash_size > 0);
 	if (n < 0)
 		return -1;
 	string_view_consume(&s, n);
@@ -363,7 +362,7 @@ static int reftable_ref_record_encode(const void *rec, struct string_view s,
 
 static int reftable_ref_record_decode(void *rec, struct reftable_buf key,
 				      uint8_t val_type, struct string_view in,
-				      int hash_size, struct reftable_buf *scratch)
+				      uint32_t hash_size, struct reftable_buf *scratch)
 {
 	struct reftable_ref_record *r = rec;
 	struct string_view start = in;
@@ -372,8 +371,6 @@ static int reftable_ref_record_decode(void *rec, struct reftable_buf key,
 	size_t refname_cap = 0;
 	int n, err;
 
-	assert(hash_size > 0);
-
 	n = get_var_int(&update_index, &in);
 	if (n < 0)
 		return n;
@@ -449,7 +446,7 @@ static int reftable_ref_record_is_deletion_void(const void *p)
 }
 
 static int reftable_ref_record_equal_void(const void *a,
-					  const void *b, int hash_size)
+					  const void *b, uint32_t hash_size)
 {
 	struct reftable_ref_record *ra = (struct reftable_ref_record *) a;
 	struct reftable_ref_record *rb = (struct reftable_ref_record *) b;
@@ -493,7 +490,7 @@ static void reftable_obj_record_release(void *rec)
 }
 
 static int reftable_obj_record_copy_from(void *rec, const void *src_rec,
-					 int hash_size UNUSED)
+					 uint32_t hash_size UNUSED)
 {
 	struct reftable_obj_record *obj = rec;
 	const struct reftable_obj_record *src = src_rec;
@@ -525,7 +522,7 @@ static uint8_t reftable_obj_record_val_type(const void *rec)
 }
 
 static int reftable_obj_record_encode(const void *rec, struct string_view s,
-				      int hash_size UNUSED)
+				      uint32_t hash_size UNUSED)
 {
 	const struct reftable_obj_record *r = rec;
 	struct string_view start = s;
@@ -560,7 +557,7 @@ static int reftable_obj_record_encode(const void *rec, struct string_view s,
 
 static int reftable_obj_record_decode(void *rec, struct reftable_buf key,
 				      uint8_t val_type, struct string_view in,
-				      int hash_size UNUSED,
+				      uint32_t hash_size UNUSED,
 				      struct reftable_buf *scratch UNUSED)
 {
 	struct string_view start = in;
@@ -568,7 +565,6 @@ static int reftable_obj_record_decode(void *rec, struct reftable_buf key,
 	uint64_t count = val_type;
 	int n = 0;
 	uint64_t last;
-	int j;
 
 	reftable_obj_record_release(r);
 
@@ -603,8 +599,7 @@ static int reftable_obj_record_decode(void *rec, struct reftable_buf key,
 	string_view_consume(&in, n);
 
 	last = r->offsets[0];
-	j = 1;
-	while (j < count) {
+	for (uint64_t j = 1; j < count; j++) {
 		uint64_t delta = 0;
 		int n = get_var_int(&delta, &in);
 		if (n < 0) {
@@ -613,7 +608,6 @@ static int reftable_obj_record_decode(void *rec, struct reftable_buf key,
 		string_view_consume(&in, n);
 
 		last = r->offsets[j] = (delta + last);
-		j++;
 	}
 	return start.len - in.len;
 }
@@ -624,7 +618,7 @@ static int not_a_deletion(const void *p UNUSED)
 }
 
 static int reftable_obj_record_equal_void(const void *a, const void *b,
-					  int hash_size UNUSED)
+					  uint32_t hash_size UNUSED)
 {
 	struct reftable_obj_record *ra = (struct reftable_obj_record *) a;
 	struct reftable_obj_record *rb = (struct reftable_obj_record *) b;
@@ -699,7 +693,7 @@ static int reftable_log_record_key(const void *r, struct reftable_buf *dest)
 }
 
 static int reftable_log_record_copy_from(void *rec, const void *src_rec,
-					 int hash_size)
+					 uint32_t hash_size)
 {
 	struct reftable_log_record *dst = rec;
 	const struct reftable_log_record *src =
@@ -780,7 +774,7 @@ static uint8_t reftable_log_record_val_type(const void *rec)
 }
 
 static int reftable_log_record_encode(const void *rec, struct string_view s,
-				      int hash_size)
+				      uint32_t hash_size)
 {
 	const struct reftable_log_record *r = rec;
 	struct string_view start = s;
@@ -828,7 +822,7 @@ static int reftable_log_record_encode(const void *rec, struct string_view s,
 
 static int reftable_log_record_decode(void *rec, struct reftable_buf key,
 				      uint8_t val_type, struct string_view in,
-				      int hash_size, struct reftable_buf *scratch)
+				      uint32_t hash_size, struct reftable_buf *scratch)
 {
 	struct string_view start = in;
 	struct reftable_log_record *r = rec;
@@ -976,7 +970,7 @@ static int null_streq(const char *a, const char *b)
 }
 
 static int reftable_log_record_equal_void(const void *a,
-					  const void *b, int hash_size)
+					  const void *b, uint32_t hash_size)
 {
 	return reftable_log_record_equal((struct reftable_log_record *) a,
 					 (struct reftable_log_record *) b,
@@ -1000,7 +994,7 @@ static int reftable_log_record_cmp_void(const void *_a, const void *_b)
 }
 
 int reftable_log_record_equal(const struct reftable_log_record *a,
-			      const struct reftable_log_record *b, int hash_size)
+			      const struct reftable_log_record *b, uint32_t hash_size)
 {
 	if (!(null_streq(a->refname, b->refname) &&
 	      a->update_index == b->update_index &&
@@ -1054,7 +1048,7 @@ static int reftable_index_record_key(const void *r, struct reftable_buf *dest)
 }
 
 static int reftable_index_record_copy_from(void *rec, const void *src_rec,
-					   int hash_size UNUSED)
+					   uint32_t hash_size UNUSED)
 {
 	struct reftable_index_record *dst = rec;
 	const struct reftable_index_record *src = src_rec;
@@ -1081,7 +1075,7 @@ static uint8_t reftable_index_record_val_type(const void *rec UNUSED)
 }
 
 static int reftable_index_record_encode(const void *rec, struct string_view out,
-					int hash_size UNUSED)
+					uint32_t hash_size UNUSED)
 {
 	const struct reftable_index_record *r =
 		(const struct reftable_index_record *)rec;
@@ -1099,7 +1093,7 @@ static int reftable_index_record_encode(const void *rec, struct string_view out,
 static int reftable_index_record_decode(void *rec, struct reftable_buf key,
 					uint8_t val_type UNUSED,
 					struct string_view in,
-					int hash_size UNUSED,
+					uint32_t hash_size UNUSED,
 					struct reftable_buf *scratch UNUSED)
 {
 	struct string_view start = in;
@@ -1120,7 +1114,7 @@ static int reftable_index_record_decode(void *rec, struct reftable_buf key,
 }
 
 static int reftable_index_record_equal(const void *a, const void *b,
-				       int hash_size UNUSED)
+				       uint32_t hash_size UNUSED)
 {
 	struct reftable_index_record *ia = (struct reftable_index_record *) a;
 	struct reftable_index_record *ib = (struct reftable_index_record *) b;
@@ -1154,14 +1148,14 @@ int reftable_record_key(struct reftable_record *rec, struct reftable_buf *dest)
 }
 
 int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
-			   int hash_size)
+			   uint32_t hash_size)
 {
 	return reftable_record_vtable(rec)->encode(reftable_record_data(rec),
 						   dest, hash_size);
 }
 
 int reftable_record_copy_from(struct reftable_record *rec,
-			       struct reftable_record *src, int hash_size)
+			       struct reftable_record *src, uint32_t hash_size)
 {
 	assert(src->type == rec->type);
 
@@ -1176,7 +1170,7 @@ uint8_t reftable_record_val_type(struct reftable_record *rec)
 }
 
 int reftable_record_decode(struct reftable_record *rec, struct reftable_buf key,
-			   uint8_t extra, struct string_view src, int hash_size,
+			   uint8_t extra, struct string_view src, uint32_t hash_size,
 			   struct reftable_buf *scratch)
 {
 	return reftable_record_vtable(rec)->decode(reftable_record_data(rec),
@@ -1203,7 +1197,7 @@ int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b)
 		reftable_record_data(a), reftable_record_data(b));
 }
 
-int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size)
+int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, uint32_t hash_size)
 {
 	if (a->type != b->type)
 		return 0;
@@ -1211,7 +1205,7 @@ int reftable_record_equal(struct reftable_record *a, struct reftable_record *b,
 		reftable_record_data(a), reftable_record_data(b), hash_size);
 }
 
-static int hash_equal(const unsigned char *a, const unsigned char *b, int hash_size)
+static int hash_equal(const unsigned char *a, const unsigned char *b, uint32_t hash_size)
 {
 	if (a && b)
 		return !memcmp(a, b, hash_size);
@@ -1220,9 +1214,8 @@ static int hash_equal(const unsigned char *a, const unsigned char *b, int hash_s
 }
 
 int reftable_ref_record_equal(const struct reftable_ref_record *a,
-			      const struct reftable_ref_record *b, int hash_size)
+			      const struct reftable_ref_record *b, uint32_t hash_size)
 {
-	assert(hash_size > 0);
 	if (!null_streq(a->refname, b->refname))
 		return 0;
 
diff --git a/reftable/record.h b/reftable/record.h
index 25aa908..c7755a4 100644
--- a/reftable/record.h
+++ b/reftable/record.h
@@ -32,8 +32,10 @@ static inline void string_view_consume(struct string_view *s, int n)
 	s->len -= n;
 }
 
-/* utilities for de/encoding varints */
-
+/*
+ * Decode and encode a varint. Returns the number of bytes read/written, or a
+ * negative value in case encoding/decoding the varint has failed.
+ */
 int get_var_int(uint64_t *dest, struct string_view *in);
 int put_var_int(struct string_view *dest, uint64_t val);
 
@@ -45,18 +47,18 @@ struct reftable_record_vtable {
 	/* The record type of ('r' for ref). */
 	uint8_t type;
 
-	int (*copy_from)(void *dest, const void *src, int hash_size);
+	int (*copy_from)(void *dest, const void *src, uint32_t hash_size);
 
 	/* a value of [0..7], indicating record subvariants (eg. ref vs. symref
 	 * vs ref deletion) */
 	uint8_t (*val_type)(const void *rec);
 
 	/* encodes rec into dest, returning how much space was used. */
-	int (*encode)(const void *rec, struct string_view dest, int hash_size);
+	int (*encode)(const void *rec, struct string_view dest, uint32_t hash_size);
 
 	/* decode data from `src` into the record. */
 	int (*decode)(void *rec, struct reftable_buf key, uint8_t extra,
-		      struct string_view src, int hash_size,
+		      struct string_view src, uint32_t hash_size,
 		      struct reftable_buf *scratch);
 
 	/* deallocate and null the record. */
@@ -66,16 +68,13 @@ struct reftable_record_vtable {
 	int (*is_deletion)(const void *rec);
 
 	/* Are two records equal? This assumes they have the same type. Returns 0 for non-equal. */
-	int (*equal)(const void *a, const void *b, int hash_size);
+	int (*equal)(const void *a, const void *b, uint32_t hash_size);
 
 	/*
 	 * Compare keys of two records with each other. The records must have
 	 * the same type.
 	 */
 	int (*cmp)(const void *a, const void *b);
-
-	/* Print on stdout, for debugging. */
-	void (*print)(const void *rec, int hash_size);
 };
 
 /* returns true for recognized block types. Block start with the block type. */
@@ -136,16 +135,16 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ);
 
 /* see struct record_vtable */
 int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b);
-int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
+int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, uint32_t hash_size);
 int reftable_record_key(struct reftable_record *rec, struct reftable_buf *dest);
 int reftable_record_copy_from(struct reftable_record *rec,
-			      struct reftable_record *src, int hash_size);
+			      struct reftable_record *src, uint32_t hash_size);
 uint8_t reftable_record_val_type(struct reftable_record *rec);
 int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
-			   int hash_size);
+			   uint32_t hash_size);
 int reftable_record_decode(struct reftable_record *rec, struct reftable_buf key,
 			   uint8_t extra, struct string_view src,
-			   int hash_size, struct reftable_buf *scratch);
+			   uint32_t hash_size, struct reftable_buf *scratch);
 int reftable_record_is_deletion(struct reftable_record *rec);
 
 static inline uint8_t reftable_record_type(struct reftable_record *rec)
diff --git a/reftable/reftable-blocksource.h b/reftable/reftable-blocksource.h
index 5aa3990..6b326aa 100644
--- a/reftable/reftable-blocksource.h
+++ b/reftable/reftable-blocksource.h
@@ -22,7 +22,7 @@ struct reftable_block_source {
  * so it can return itself into the pool. */
 struct reftable_block {
 	uint8_t *data;
-	int len;
+	size_t len;
 	struct reftable_block_source source;
 };
 
@@ -31,10 +31,13 @@ struct reftable_block_source_vtable {
 	/* returns the size of a block source */
 	uint64_t (*size)(void *source);
 
-	/* reads a segment from the block source. It is an error to read
-	   beyond the end of the block */
-	int (*read_block)(void *source, struct reftable_block *dest,
-			  uint64_t off, uint32_t size);
+	/*
+	 * Reads a segment from the block source. It is an error to read beyond
+	 * the end of the block.
+	 */
+	ssize_t (*read_block)(void *source, struct reftable_block *dest,
+			     uint64_t off, uint32_t size);
+
 	/* mark the block as read; may return the data back to malloc */
 	void (*return_block)(void *source, struct reftable_block *blockp);
 
diff --git a/reftable/reftable-error.h b/reftable/reftable-error.h
index f404826..a7e33d9 100644
--- a/reftable/reftable-error.h
+++ b/reftable/reftable-error.h
@@ -30,6 +30,7 @@ enum reftable_error {
 
 	/* Misuse of the API:
 	 *  - on writing a record with NULL refname.
+	 *  - on writing a record before setting the writer limits.
 	 *  - on writing a reftable_ref_record outside the table limits
 	 *  - on writing a ref or log record before the stack's
 	 * next_update_inde*x
diff --git a/reftable/reftable-record.h b/reftable/reftable-record.h
index ddd48eb..931e594 100644
--- a/reftable/reftable-record.h
+++ b/reftable/reftable-record.h
@@ -65,7 +65,7 @@ void reftable_ref_record_release(struct reftable_ref_record *ref);
 
 /* returns whether two reftable_ref_records are the same. Useful for testing. */
 int reftable_ref_record_equal(const struct reftable_ref_record *a,
-			      const struct reftable_ref_record *b, int hash_size);
+			      const struct reftable_ref_record *b, uint32_t hash_size);
 
 /* reftable_log_record holds a reflog entry */
 struct reftable_log_record {
@@ -105,6 +105,6 @@ void reftable_log_record_release(struct reftable_log_record *log);
 
 /* returns whether two records are equal. Useful for testing. */
 int reftable_log_record_equal(const struct reftable_log_record *a,
-			      const struct reftable_log_record *b, int hash_size);
+			      const struct reftable_log_record *b, uint32_t hash_size);
 
 #endif
diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h
index 5f9afa6..1befe3b 100644
--- a/reftable/reftable-writer.h
+++ b/reftable/reftable-writer.h
@@ -84,7 +84,7 @@ struct reftable_block_stats {
 	/* total number of entries written */
 	int entries;
 	/* total number of key restarts */
-	int restarts;
+	uint32_t restarts;
 	/* total number of blocks */
 	int blocks;
 	/* total number of index blocks */
@@ -124,17 +124,21 @@ int reftable_writer_new(struct reftable_writer **out,
 			int (*flush_func)(void *),
 			void *writer_arg, const struct reftable_write_options *opts);
 
-/* Set the range of update indices for the records we will add. When writing a
-   table into a stack, the min should be at least
-   reftable_stack_next_update_index(), or REFTABLE_API_ERROR is returned.
-
-   For transactional updates to a stack, typically min==max, and the
-   update_index can be obtained by inspeciting the stack. When converting an
-   existing ref database into a single reftable, this would be a range of
-   update-index timestamps.
+/*
+ * Set the range of update indices for the records we will add. When writing a
+ * table into a stack, the min should be at least
+ * reftable_stack_next_update_index(), or REFTABLE_API_ERROR is returned.
+ *
+ * For transactional updates to a stack, typically min==max, and the
+ * update_index can be obtained by inspeciting the stack. When converting an
+ * existing ref database into a single reftable, this would be a range of
+ * update-index timestamps.
+ *
+ * The function should be called before adding any records to the writer. If not
+ * it will fail with REFTABLE_API_ERROR.
  */
-void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
-				uint64_t max);
+int reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
+			       uint64_t max);
 
 /*
   Add a reftable_ref_record. The record should have names that come after
diff --git a/reftable/stack.c b/reftable/stack.c
index 531660a..6c4e8be 100644
--- a/reftable/stack.c
+++ b/reftable/stack.c
@@ -220,9 +220,9 @@ void reftable_stack_destroy(struct reftable_stack *st)
 	}
 
 	if (st->readers) {
-		int i = 0;
 		struct reftable_buf filename = REFTABLE_BUF_INIT;
-		for (i = 0; i < st->readers_len; i++) {
+
+		for (size_t i = 0; i < st->readers_len; i++) {
 			const char *name = reader_name(st->readers[i]);
 			int try_unlinking = 1;
 
@@ -238,6 +238,7 @@ void reftable_stack_destroy(struct reftable_stack *st)
 				unlink(filename.buf);
 			}
 		}
+
 		reftable_buf_release(&filename);
 		st->readers_len = 0;
 		REFTABLE_FREE_AND_NULL(st->readers);
@@ -493,7 +494,7 @@ static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
 		close(fd);
 		fd = -1;
 
-		delay = delay + (delay * rand()) / RAND_MAX + 1;
+		delay = delay + (delay * git_rand(CSPRNG_BYTES_INSECURE)) / UINT32_MAX + 1;
 		sleep_millisec(delay);
 	}
 
@@ -568,7 +569,6 @@ static int stack_uptodate(struct reftable_stack *st)
 {
 	char **names = NULL;
 	int err;
-	int i = 0;
 
 	/*
 	 * When we have cached stat information available then we use it to
@@ -608,7 +608,7 @@ static int stack_uptodate(struct reftable_stack *st)
 	if (err < 0)
 		return err;
 
-	for (i = 0; i < st->readers_len; i++) {
+	for (size_t i = 0; i < st->readers_len; i++) {
 		if (!names[i]) {
 			err = 1;
 			goto done;
@@ -659,7 +659,7 @@ int reftable_stack_add(struct reftable_stack *st,
 static int format_name(struct reftable_buf *dest, uint64_t min, uint64_t max)
 {
 	char buf[100];
-	uint32_t rnd = (uint32_t)git_rand();
+	uint32_t rnd = git_rand(CSPRNG_BYTES_INSECURE);
 	snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64 "-%08x",
 		 min, max, rnd);
 	reftable_buf_reset(dest);
@@ -1058,8 +1058,10 @@ static int stack_write_compact(struct reftable_stack *st,
 
 	for (size_t i = first; i <= last; i++)
 		st->stats.bytes += st->readers[i]->size;
-	reftable_writer_set_limits(wr, st->readers[first]->min_update_index,
-				   st->readers[last]->max_update_index);
+	err = reftable_writer_set_limits(wr, st->readers[first]->min_update_index,
+					 st->readers[last]->max_update_index);
+	if (err < 0)
+		goto done;
 
 	err = reftable_merged_table_new(&mt, st->readers + first, subtabs_len,
 					st->opts.hash_id);
@@ -1767,14 +1769,12 @@ static int reftable_stack_clean_locked(struct reftable_stack *st)
 	}
 
 	while ((d = readdir(dir))) {
-		int i = 0;
 		int found = 0;
 		if (!is_table_name(d->d_name))
 			continue;
 
-		for (i = 0; !found && i < st->readers_len; i++) {
+		for (size_t i = 0; !found && i < st->readers_len; i++)
 			found = !strcmp(reader_name(st->readers[i]), d->d_name);
-		}
 		if (found)
 			continue;
 
diff --git a/reftable/system.h b/reftable/system.h
index 5274eca..d02eace 100644
--- a/reftable/system.h
+++ b/reftable/system.h
@@ -11,9 +11,8 @@ license that can be found in the LICENSE file or at
 
 /* This header glues the reftable library to the rest of Git */
 
-#define DISABLE_SIGN_COMPARE_WARNINGS
-
 #include "git-compat-util.h"
+#include "compat/zlib-compat.h"
 
 /*
  * An implementation-specific temporary file. By making this specific to the
diff --git a/reftable/writer.c b/reftable/writer.c
index 740c980..f3ab103 100644
--- a/reftable/writer.c
+++ b/reftable/writer.c
@@ -179,11 +179,24 @@ int reftable_writer_new(struct reftable_writer **out,
 	return 0;
 }
 
-void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
+int reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
 				uint64_t max)
 {
+	/*
+	  * Set the min/max update index limits for the reftable writer.
+	  * This must be called before adding any records, since:
+	  * - The 'next' field gets set after writing the first block.
+	  * - The 'last_key' field updates with each new record (but resets
+	  *   after sections).
+	  * Returns REFTABLE_API_ERROR if called after writing has begun.
+	 */
+	if (w->next || w->last_key.len)
+		return REFTABLE_API_ERROR;
+
 	w->min_update_index = min;
 	w->max_update_index = max;
+
+	return 0;
 }
 
 static void writer_release(struct reftable_writer *w)
@@ -577,7 +590,7 @@ static int writer_finish_section(struct reftable_writer *w)
 
 struct common_prefix_arg {
 	struct reftable_buf *last;
-	int max;
+	size_t max;
 };
 
 static void update_common(void *void_arg, void *key)
@@ -585,10 +598,9 @@ static void update_common(void *void_arg, void *key)
 	struct common_prefix_arg *arg = void_arg;
 	struct obj_index_tree_node *entry = key;
 	if (arg->last) {
-		int n = common_prefix_size(&entry->hash, arg->last);
-		if (n > arg->max) {
+		size_t n = common_prefix_size(&entry->hash, arg->last);
+		if (n > arg->max)
 			arg->max = n;
-		}
 	}
 	arg->last = &entry->hash;
 }
diff --git a/remote-curl.c b/remote-curl.c
index a24e3a8..1273507 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -942,7 +942,7 @@ static int post_rpc(struct rpc_state *rpc, int stateless_connect, int flush_rece
 		do {
 			err = probe_rpc(rpc, &results);
 			if (err == HTTP_REAUTH)
-				credential_fill(&http_auth, 0);
+				credential_fill(the_repository, &http_auth, 0);
 		} while (err == HTTP_REAUTH);
 		if (err != HTTP_OK)
 			return -1;
@@ -1064,7 +1064,7 @@ static int post_rpc(struct rpc_state *rpc, int stateless_connect, int flush_rece
 	rpc->any_written = 0;
 	err = run_slot(slot, NULL);
 	if (err == HTTP_REAUTH && !large_request) {
-		credential_fill(&http_auth, 0);
+		credential_fill(the_repository, &http_auth, 0);
 		curl_slist_free_all(headers);
 		goto retry;
 	}
diff --git a/remote.c b/remote.c
index 18e5ccf..e609cf5 100644
--- a/remote.c
+++ b/remote.c
@@ -294,6 +294,7 @@ static void add_instead_of(struct rewrite *rewrite, const char *instead_of)
 	rewrite->instead_of_nr++;
 }
 
+#ifndef WITH_BREAKING_CHANGES
 static const char *skip_spaces(const char *s)
 {
 	while (isspace(*s))
@@ -301,14 +302,33 @@ static const char *skip_spaces(const char *s)
 	return s;
 }
 
+static void warn_about_deprecated_remote_type(const char *type,
+					      const struct remote *remote)
+{
+	warning(_("reading remote from \"%s/%s\", which is nominated for removal.\n"
+		  "\n"
+		  "If you still use the \"remotes/\" directory it is recommended to\n"
+		  "migrate to config-based remotes:\n"
+		  "\n"
+		  "\tgit remote rename %s %s\n"
+		  "\n"
+		  "If you cannot, please let us know why you still need to use it by\n"
+		  "sending an e-mail to <git@vger.kernel.org>."),
+		type, remote->name, remote->name, remote->name);
+}
+
 static void read_remotes_file(struct remote_state *remote_state,
 			      struct remote *remote)
 {
 	struct strbuf buf = STRBUF_INIT;
-	FILE *f = fopen_or_warn(git_path("remotes/%s", remote->name), "r");
+	FILE *f = fopen_or_warn(repo_git_path_append(the_repository, &buf,
+						     "remotes/%s", remote->name), "r");
 
 	if (!f)
-		return;
+		goto out;
+
+	warn_about_deprecated_remote_type("remotes", remote);
+
 	remote->configured_in_repo = 1;
 	remote->origin = REMOTE_REMOTES;
 	while (strbuf_getline(&buf, f) != EOF) {
@@ -324,8 +344,10 @@ static void read_remotes_file(struct remote_state *remote_state,
 		else if (skip_prefix(buf.buf, "Pull:", &v))
 			refspec_append(&remote->fetch, skip_spaces(v));
 	}
-	strbuf_release(&buf);
 	fclose(f);
+
+out:
+	strbuf_release(&buf);
 }
 
 static void read_branches_file(struct remote_state *remote_state,
@@ -333,18 +355,19 @@ static void read_branches_file(struct remote_state *remote_state,
 {
 	char *frag, *to_free = NULL;
 	struct strbuf buf = STRBUF_INIT;
-	FILE *f = fopen_or_warn(git_path("branches/%s", remote->name), "r");
+	FILE *f = fopen_or_warn(repo_git_path_append(the_repository, &buf,
+						     "branches/%s", remote->name), "r");
 
 	if (!f)
-		return;
+		goto out;
+
+	warn_about_deprecated_remote_type("branches", remote);
 
 	strbuf_getline_lf(&buf, f);
 	fclose(f);
 	strbuf_trim(&buf);
-	if (!buf.len) {
-		strbuf_release(&buf);
-		return;
-	}
+	if (!buf.len)
+		goto out;
 
 	remote->configured_in_repo = 1;
 	remote->origin = REMOTE_BRANCHES;
@@ -372,9 +395,11 @@ static void read_branches_file(struct remote_state *remote_state,
 	refspec_appendf(&remote->push, "HEAD:refs/heads/%s", frag);
 	remote->fetch_tags = 1; /* always auto-follow */
 
+out:
 	strbuf_release(&buf);
 	free(to_free);
 }
+#endif /* WITH_BREAKING_CHANGES */
 
 static int handle_config(const char *key, const char *value,
 			 const struct config_context *ctx, void *cb)
@@ -591,6 +616,7 @@ static void read_config(struct repository *repo, int early)
 	alias_all_urls(repo->remote_state);
 }
 
+#ifndef WITH_BREAKING_CHANGES
 static int valid_remote_nick(const char *name)
 {
 	if (!name[0] || is_dot_or_dotdot(name))
@@ -602,6 +628,7 @@ static int valid_remote_nick(const char *name)
 			return 0;
 	return 1;
 }
+#endif /* WITH_BREAKING_CHANGES */
 
 static const char *remotes_remote_for_branch(struct remote_state *remote_state,
 					     struct branch *branch,
@@ -744,12 +771,14 @@ remotes_remote_get_1(struct remote_state *remote_state, const char *name,
 				   &name_given);
 
 	ret = make_remote(remote_state, name, 0);
+#ifndef WITH_BREAKING_CHANGES
 	if (valid_remote_nick(name) && have_git_dir()) {
 		if (!valid_remote(ret))
 			read_remotes_file(remote_state, ret);
 		if (!valid_remote(ret))
 			read_branches_file(remote_state, ret);
 	}
+#endif /* WITH_BREAKING_CHANGES */
 	if (name_given && !valid_remote(ret))
 		add_url_alias(remote_state, ret, name);
 	if (!valid_remote(ret))
@@ -907,210 +936,9 @@ void ref_push_report_free(struct ref_push_report *report)
 	}
 }
 
-static int match_name_with_pattern(const char *key, const char *name,
-				   const char *value, char **result)
-{
-	const char *kstar = strchr(key, '*');
-	size_t klen;
-	size_t ksuffixlen;
-	size_t namelen;
-	int ret;
-	if (!kstar)
-		die(_("key '%s' of pattern had no '*'"), key);
-	klen = kstar - key;
-	ksuffixlen = strlen(kstar + 1);
-	namelen = strlen(name);
-	ret = !strncmp(name, key, klen) && namelen >= klen + ksuffixlen &&
-		!memcmp(name + namelen - ksuffixlen, kstar + 1, ksuffixlen);
-	if (ret && value) {
-		struct strbuf sb = STRBUF_INIT;
-		const char *vstar = strchr(value, '*');
-		if (!vstar)
-			die(_("value '%s' of pattern has no '*'"), value);
-		strbuf_add(&sb, value, vstar - value);
-		strbuf_add(&sb, name + klen, namelen - klen - ksuffixlen);
-		strbuf_addstr(&sb, vstar + 1);
-		*result = strbuf_detach(&sb, NULL);
-	}
-	return ret;
-}
-
-static int refspec_match(const struct refspec_item *refspec,
-			 const char *name)
-{
-	if (refspec->pattern)
-		return match_name_with_pattern(refspec->src, name, NULL, NULL);
-
-	return !strcmp(refspec->src, name);
-}
-
-int omit_name_by_refspec(const char *name, struct refspec *rs)
-{
-	int i;
-
-	for (i = 0; i < rs->nr; i++) {
-		if (rs->items[i].negative && refspec_match(&rs->items[i], name))
-			return 1;
-	}
-	return 0;
-}
-
-struct ref *apply_negative_refspecs(struct ref *ref_map, struct refspec *rs)
-{
-	struct ref **tail;
-
-	for (tail = &ref_map; *tail; ) {
-		struct ref *ref = *tail;
-
-		if (omit_name_by_refspec(ref->name, rs)) {
-			*tail = ref->next;
-			free(ref->peer_ref);
-			free(ref);
-		} else
-			tail = &ref->next;
-	}
-
-	return ref_map;
-}
-
-static int query_matches_negative_refspec(struct refspec *rs, struct refspec_item *query)
-{
-	int i, matched_negative = 0;
-	int find_src = !query->src;
-	struct string_list reversed = STRING_LIST_INIT_DUP;
-	const char *needle = find_src ? query->dst : query->src;
-
-	/*
-	 * Check whether the queried ref matches any negative refpsec. If so,
-	 * then we should ultimately treat this as not matching the query at
-	 * all.
-	 *
-	 * Note that negative refspecs always match the source, but the query
-	 * item uses the destination. To handle this, we apply pattern
-	 * refspecs in reverse to figure out if the query source matches any
-	 * of the negative refspecs.
-	 *
-	 * The first loop finds and expands all positive refspecs
-	 * matched by the queried ref.
-	 *
-	 * The second loop checks if any of the results of the first loop
-	 * match any negative refspec.
-	 */
-	for (i = 0; i < rs->nr; i++) {
-		struct refspec_item *refspec = &rs->items[i];
-		char *expn_name;
-
-		if (refspec->negative)
-			continue;
-
-		/* Note the reversal of src and dst */
-		if (refspec->pattern) {
-			const char *key = refspec->dst ? refspec->dst : refspec->src;
-			const char *value = refspec->src;
-
-			if (match_name_with_pattern(key, needle, value, &expn_name))
-				string_list_append_nodup(&reversed, expn_name);
-		} else if (refspec->matching) {
-			/* For the special matching refspec, any query should match */
-			string_list_append(&reversed, needle);
-		} else if (!refspec->src) {
-			BUG("refspec->src should not be null here");
-		} else if (!strcmp(needle, refspec->src)) {
-			string_list_append(&reversed, refspec->src);
-		}
-	}
-
-	for (i = 0; !matched_negative && i < reversed.nr; i++) {
-		if (omit_name_by_refspec(reversed.items[i].string, rs))
-			matched_negative = 1;
-	}
-
-	string_list_clear(&reversed, 0);
-
-	return matched_negative;
-}
-
-static void query_refspecs_multiple(struct refspec *rs,
-				    struct refspec_item *query,
-				    struct string_list *results)
-{
-	int i;
-	int find_src = !query->src;
-
-	if (find_src && !query->dst)
-		BUG("query_refspecs_multiple: need either src or dst");
-
-	if (query_matches_negative_refspec(rs, query))
-		return;
-
-	for (i = 0; i < rs->nr; i++) {
-		struct refspec_item *refspec = &rs->items[i];
-		const char *key = find_src ? refspec->dst : refspec->src;
-		const char *value = find_src ? refspec->src : refspec->dst;
-		const char *needle = find_src ? query->dst : query->src;
-		char **result = find_src ? &query->src : &query->dst;
-
-		if (!refspec->dst || refspec->negative)
-			continue;
-		if (refspec->pattern) {
-			if (match_name_with_pattern(key, needle, value, result))
-				string_list_append_nodup(results, *result);
-		} else if (!strcmp(needle, key)) {
-			string_list_append(results, value);
-		}
-	}
-}
-
-int query_refspecs(struct refspec *rs, struct refspec_item *query)
-{
-	int i;
-	int find_src = !query->src;
-	const char *needle = find_src ? query->dst : query->src;
-	char **result = find_src ? &query->src : &query->dst;
-
-	if (find_src && !query->dst)
-		BUG("query_refspecs: need either src or dst");
-
-	if (query_matches_negative_refspec(rs, query))
-		return -1;
-
-	for (i = 0; i < rs->nr; i++) {
-		struct refspec_item *refspec = &rs->items[i];
-		const char *key = find_src ? refspec->dst : refspec->src;
-		const char *value = find_src ? refspec->src : refspec->dst;
-
-		if (!refspec->dst || refspec->negative)
-			continue;
-		if (refspec->pattern) {
-			if (match_name_with_pattern(key, needle, value, result)) {
-				query->force = refspec->force;
-				return 0;
-			}
-		} else if (!strcmp(needle, key)) {
-			*result = xstrdup(value);
-			query->force = refspec->force;
-			return 0;
-		}
-	}
-	return -1;
-}
-
-char *apply_refspecs(struct refspec *rs, const char *name)
-{
-	struct refspec_item query;
-
-	memset(&query, 0, sizeof(struct refspec_item));
-	query.src = (char *)name;
-
-	if (query_refspecs(rs, &query))
-		return NULL;
-
-	return query.dst;
-}
-
 int remote_find_tracking(struct remote *remote, struct refspec_item *refspec)
 {
-	return query_refspecs(&remote->fetch, refspec);
+	return refspec_find_match(&remote->fetch, refspec);
 }
 
 static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
@@ -1234,7 +1062,7 @@ int count_refspec_match(const char *pattern,
 	}
 }
 
-static void tail_link_ref(struct ref *ref, struct ref ***tail)
+void tail_link_ref(struct ref *ref, struct ref ***tail)
 {
 	**tail = ref;
 	while (ref->next)
@@ -1497,9 +1325,9 @@ static char *get_ref_match(const struct refspec *rs, const struct ref *ref,
 			const char *dst_side = item->dst ? item->dst : item->src;
 			int match;
 			if (direction == FROM_SRC)
-				match = match_name_with_pattern(item->src, ref->name, dst_side, &name);
+				match = match_refname_with_pattern(item->src, ref->name, dst_side, &name);
 			else
-				match = match_name_with_pattern(dst_side, ref->name, item->src, &name);
+				match = match_refname_with_pattern(dst_side, ref->name, item->src, &name);
 			if (match) {
 				matching_refs = i;
 				break;
@@ -1535,7 +1363,7 @@ static struct ref **tail_ref(struct ref **head)
 
 struct tips {
 	struct commit **tip;
-	int nr, alloc;
+	size_t nr, alloc;
 };
 
 static void add_to_tips(struct tips *tips, const struct object_id *oid)
@@ -1602,7 +1430,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
 		const int reachable_flag = 1;
 		struct commit_list *found_commits;
 		struct commit **src_commits;
-		int nr_src_commits = 0, alloc_src_commits = 16;
+		size_t nr_src_commits = 0, alloc_src_commits = 16;
 		ALLOC_ARRAY(src_commits, alloc_src_commits);
 
 		for_each_string_list_item(item, &src_tag) {
@@ -2117,7 +1945,7 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
 
 		if (strchr(ref->name, '^'))
 			continue; /* a dereference item */
-		if (match_name_with_pattern(refspec->src, ref->name,
+		if (match_refname_with_pattern(refspec->src, ref->name,
 					    refspec->dst, &expn_name) &&
 		    !ignore_symref_update(expn_name, &scratch)) {
 			struct ref *cpy = copy_ref(ref);
@@ -2535,7 +2363,7 @@ static int get_stale_heads_cb(const char *refname, const char *referent UNUSED,
 	memset(&query, 0, sizeof(struct refspec_item));
 	query.dst = (char *)refname;
 
-	query_refspecs_multiple(info->rs, &query, &matches);
+	refspec_find_all_matches(info->rs, &query, &matches);
 	if (matches.nr == 0)
 		goto clean_exit; /* No matches */
 
@@ -3003,3 +2831,13 @@ char *relative_url(const char *remote_url, const char *url,
 	free(out);
 	return strbuf_detach(&sb, NULL);
 }
+
+int valid_remote_name(const char *name)
+{
+	int result;
+	struct strbuf refspec = STRBUF_INIT;
+	strbuf_addf(&refspec, "refs/heads/test:refs/remotes/%s/test", name);
+	result = valid_fetch_refspec(refspec.buf);
+	strbuf_release(&refspec);
+	return result;
+}
diff --git a/remote.h b/remote.h
index bda10dd..6be5031 100644
--- a/remote.h
+++ b/remote.h
@@ -21,8 +21,10 @@ struct transport_ls_refs_options;
 enum {
 	REMOTE_UNCONFIGURED = 0,
 	REMOTE_CONFIG,
+#ifndef WITH_BREAKING_CHANGES
 	REMOTE_REMOTES,
 	REMOTE_BRANCHES
+#endif /* WITH_BREAKING_CHANGES */
 };
 
 struct rewrite {
@@ -219,6 +221,11 @@ struct ref *alloc_ref(const char *name);
 struct ref *copy_ref(const struct ref *ref);
 struct ref *copy_ref_list(const struct ref *ref);
 int count_refspec_match(const char *, struct ref *refs, struct ref **matched_ref);
+/*
+ * Put a ref in the tail and prepare tail for adding another one.
+ * *tail is the pointer to the tail of the list of refs.
+ */
+void tail_link_ref(struct ref *ref, struct ref ***tail);
 
 int check_ref_type(const struct ref *ref, int flags);
 
@@ -261,21 +268,6 @@ int resolve_remote_symref(struct ref *ref, struct ref *list);
  */
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
-/*
- * Check whether a name matches any negative refspec in rs. Returns 1 if the
- * name matches at least one negative refspec, and 0 otherwise.
- */
-int omit_name_by_refspec(const char *name, struct refspec *rs);
-
-/*
- * Remove all entries in the input list which match any negative refspec in
- * the refspec list.
- */
-struct ref *apply_negative_refspecs(struct ref *ref_map, struct refspec *rs);
-
-int query_refspecs(struct refspec *rs, struct refspec_item *query);
-char *apply_refspecs(struct refspec *rs, const char *name);
-
 int check_push_refs(struct ref *src, struct refspec *rs);
 int match_push_refs(struct ref *src, struct ref **dst,
 		    struct refspec *rs, int flags);
@@ -461,4 +453,6 @@ void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
 char *relative_url(const char *remote_url, const char *url,
 		   const char *up_path);
 
+int valid_remote_name(const char *name);
+
 #endif
diff --git a/repo-settings.c b/repo-settings.c
index 9d16d53..67e9cfd 100644
--- a/repo-settings.c
+++ b/repo-settings.c
@@ -4,6 +4,7 @@
 #include "repository.h"
 #include "midx.h"
 #include "pack-objects.h"
+#include "setup.h"
 
 static void repo_cfg_bool(struct repository *r, const char *key, int *dest,
 			  int def)
@@ -21,7 +22,6 @@ static void repo_cfg_int(struct repository *r, const char *key, int *dest,
 
 void prepare_repo_settings(struct repository *r)
 {
-	const struct repo_settings defaults = REPO_SETTINGS_INIT;
 	int experimental;
 	int value;
 	const char *strval;
@@ -35,7 +35,7 @@ void prepare_repo_settings(struct repository *r)
 	if (r->settings.initialized)
 		return;
 
-	memcpy(&r->settings, &defaults, sizeof(defaults));
+	repo_settings_clear(r);
 	r->settings.initialized++;
 
 	/* Booleans config or default, cascades to other settings */
@@ -143,6 +143,14 @@ void prepare_repo_settings(struct repository *r)
 		r->settings.packed_git_limit = ulongval;
 }
 
+void repo_settings_clear(struct repository *r)
+{
+	struct repo_settings empty = REPO_SETTINGS_INIT;
+	FREE_AND_NULL(r->settings.fsmonitor);
+	FREE_AND_NULL(r->settings.hooks_path);
+	r->settings = empty;
+}
+
 enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo)
 {
 	const char *value;
@@ -167,3 +175,35 @@ int repo_settings_get_warn_ambiguous_refs(struct repository *repo)
 			      &repo->settings.warn_ambiguous_refs, 1);
 	return repo->settings.warn_ambiguous_refs;
 }
+
+const char *repo_settings_get_hooks_path(struct repository *repo)
+{
+	if (!repo->settings.hooks_path)
+		repo_config_get_pathname(repo, "core.hookspath", &repo->settings.hooks_path);
+	return repo->settings.hooks_path;
+}
+
+int repo_settings_get_shared_repository(struct repository *repo)
+{
+	if (!repo->settings.shared_repository_initialized) {
+		const char *var = "core.sharedrepository";
+		const char *value;
+		if (!repo_config_get_value(repo, var, &value))
+			repo->settings.shared_repository = git_config_perm(var, value);
+		else
+			repo->settings.shared_repository = PERM_UMASK;
+		repo->settings.shared_repository_initialized = 1;
+	}
+	return repo->settings.shared_repository;
+}
+
+void repo_settings_set_shared_repository(struct repository *repo, int value)
+{
+	repo->settings.shared_repository = value;
+	repo->settings.shared_repository_initialized = 1;
+}
+
+void repo_settings_reset_shared_repository(struct repository *repo)
+{
+	repo->settings.shared_repository_initialized = 0;
+}
diff --git a/repo-settings.h b/repo-settings.h
index 93ea0c3..ddc1196 100644
--- a/repo-settings.h
+++ b/repo-settings.h
@@ -37,6 +37,9 @@ struct repo_settings {
 	int pack_use_bitmap_boundary_traversal;
 	int pack_use_multi_pack_reuse;
 
+	int shared_repository;
+	int shared_repository_initialized;
+
 	/*
 	 * Does this repository have core.useReplaceRefs=true (on by
 	 * default)? This provides a repository-scoped version of this
@@ -61,8 +64,11 @@ struct repo_settings {
 	size_t delta_base_cache_limit;
 	size_t packed_git_window_size;
 	size_t packed_git_limit;
+
+	char *hooks_path;
 };
 #define REPO_SETTINGS_INIT { \
+	.shared_repository = -1, \
 	.index_version = -1, \
 	.core_untracked_cache = UNTRACKED_CACHE_KEEP, \
 	.fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE, \
@@ -73,10 +79,18 @@ struct repo_settings {
 }
 
 void prepare_repo_settings(struct repository *r);
+void repo_settings_clear(struct repository *r);
 
 /* Read the value for "core.logAllRefUpdates". */
 enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo);
 /* Read the value for "core.warnAmbiguousRefs". */
 int repo_settings_get_warn_ambiguous_refs(struct repository *repo);
+/* Read the value for "core.hooksPath". */
+const char *repo_settings_get_hooks_path(struct repository *repo);
+
+/* Read, set or reset the value for "core.sharedRepository". */
+int repo_settings_get_shared_repository(struct repository *repo);
+void repo_settings_set_shared_repository(struct repository *repo, int value);
+void repo_settings_reset_shared_repository(struct repository *repo);
 
 #endif /* REPO_SETTINGS_H */
diff --git a/repository.c b/repository.c
index 1a6a62b..6cbaf2e 100644
--- a/repository.c
+++ b/repository.c
@@ -312,8 +312,8 @@ int repo_submodule_init(struct repository *subrepo,
 	struct strbuf worktree = STRBUF_INIT;
 	int ret = 0;
 
-	strbuf_repo_worktree_path(&gitdir, superproject, "%s/.git", path);
-	strbuf_repo_worktree_path(&worktree, superproject, "%s", path);
+	repo_worktree_path_append(superproject, &gitdir, "%s/.git", path);
+	repo_worktree_path_append(superproject, &worktree, "%s", path);
 
 	if (repo_init(subrepo, gitdir.buf, worktree.buf)) {
 		/*
@@ -380,7 +380,7 @@ 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);
+	repo_settings_clear(repo);
 
 	if (repo->config) {
 		git_configset_clear(repo->config);
diff --git a/rerere.c b/rerere.c
index e7fa642..740e8ad 100644
--- a/rerere.c
+++ b/rerere.c
@@ -91,16 +91,18 @@ static void assign_variant(struct rerere_id *id)
 	id->variant = variant;
 }
 
-const char *rerere_path(const struct rerere_id *id, const char *file)
+const char *rerere_path(struct strbuf *buf, const struct rerere_id *id, const char *file)
 {
 	if (!file)
-		return git_path("rr-cache/%s", rerere_id_hex(id));
+		return repo_git_path_replace(the_repository, buf, "rr-cache/%s",
+					     rerere_id_hex(id));
 
 	if (id->variant <= 0)
-		return git_path("rr-cache/%s/%s", rerere_id_hex(id), file);
+		return repo_git_path_replace(the_repository, buf, "rr-cache/%s/%s",
+					     rerere_id_hex(id), file);
 
-	return git_path("rr-cache/%s/%s.%d",
-			rerere_id_hex(id), file, id->variant);
+	return repo_git_path_replace(the_repository, buf, "rr-cache/%s/%s.%d",
+				     rerere_id_hex(id), file, id->variant);
 }
 
 static int is_rr_file(const char *name, const char *filename, int *variant)
@@ -125,8 +127,12 @@ static int is_rr_file(const char *name, const char *filename, int *variant)
 static void scan_rerere_dir(struct rerere_dir *rr_dir)
 {
 	struct dirent *de;
-	DIR *dir = opendir(git_path("rr-cache/%s", rr_dir->name));
+	char *path;
+	DIR *dir;
 
+	path = repo_git_path(the_repository, "rr-cache/%s", rr_dir->name);
+	dir = opendir(path);
+	free(path);
 	if (!dir)
 		return;
 	while ((de = readdir(dir)) != NULL) {
@@ -358,7 +364,7 @@ static void rerere_strbuf_putconflict(struct strbuf *buf, int ch, size_t size)
 }
 
 static int handle_conflict(struct strbuf *out, struct rerere_io *io,
-			   int marker_size, git_hash_ctx *ctx)
+			   int marker_size, struct git_hash_ctx *ctx)
 {
 	enum {
 		RR_SIDE_1 = 0, RR_SIDE_2, RR_ORIGINAL
@@ -396,12 +402,12 @@ static int handle_conflict(struct strbuf *out, struct rerere_io *io,
 			strbuf_addbuf(out, &two);
 			rerere_strbuf_putconflict(out, '>', marker_size);
 			if (ctx) {
-				the_hash_algo->update_fn(ctx, one.buf ?
-							 one.buf : "",
-							 one.len + 1);
-				the_hash_algo->update_fn(ctx, two.buf ?
-							 two.buf : "",
-							 two.len + 1);
+				git_hash_update(ctx, one.buf ?
+						one.buf : "",
+						one.len + 1);
+				git_hash_update(ctx, two.buf ?
+						two.buf : "",
+						two.len + 1);
 			}
 			break;
 		} else if (hunk == RR_SIDE_1)
@@ -432,7 +438,7 @@ static int handle_conflict(struct strbuf *out, struct rerere_io *io,
  */
 static int handle_path(unsigned char *hash, struct rerere_io *io, int marker_size)
 {
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 	struct strbuf buf = STRBUF_INIT, out = STRBUF_INIT;
 	int has_conflicts = 0;
 	if (hash)
@@ -453,7 +459,7 @@ static int handle_path(unsigned char *hash, struct rerere_io *io, int marker_siz
 	strbuf_release(&out);
 
 	if (hash)
-		the_hash_algo->final_fn(hash, &ctx);
+		git_hash_final(hash, &ctx);
 
 	return has_conflicts;
 }
@@ -624,9 +630,10 @@ static int try_merge(struct index_state *istate,
 {
 	enum ll_merge_result ret;
 	mmfile_t base = {NULL, 0}, other = {NULL, 0};
+	struct strbuf buf = STRBUF_INIT;
 
-	if (read_mmfile(&base, rerere_path(id, "preimage")) ||
-	    read_mmfile(&other, rerere_path(id, "postimage"))) {
+	if (read_mmfile(&base, rerere_path(&buf, id, "preimage")) ||
+	    read_mmfile(&other, rerere_path(&buf, id, "postimage"))) {
 		ret = LL_MERGE_CONFLICT;
 	} else {
 		/*
@@ -637,6 +644,7 @@ static int try_merge(struct index_state *istate,
 			       istate, NULL);
 	}
 
+	strbuf_release(&buf);
 	free(base.ptr);
 	free(other.ptr);
 
@@ -657,6 +665,7 @@ static int merge(struct index_state *istate, const struct rerere_id *id, const c
 {
 	FILE *f;
 	int ret;
+	struct strbuf buf = STRBUF_INIT;
 	mmfile_t cur = {NULL, 0};
 	mmbuffer_t result = {NULL, 0};
 
@@ -664,8 +673,8 @@ static int merge(struct index_state *istate, const struct rerere_id *id, const c
 	 * Normalize the conflicts in path and write it out to
 	 * "thisimage" temporary file.
 	 */
-	if ((handle_file(istate, path, NULL, rerere_path(id, "thisimage")) < 0) ||
-	    read_mmfile(&cur, rerere_path(id, "thisimage"))) {
+	if ((handle_file(istate, path, NULL, rerere_path(&buf, id, "thisimage")) < 0) ||
+	    read_mmfile(&cur, rerere_path(&buf, id, "thisimage"))) {
 		ret = 1;
 		goto out;
 	}
@@ -678,9 +687,9 @@ static int merge(struct index_state *istate, const struct rerere_id *id, const c
 	 * A successful replay of recorded resolution.
 	 * Mark that "postimage" was used to help gc.
 	 */
-	if (utime(rerere_path(id, "postimage"), NULL) < 0)
+	if (utime(rerere_path(&buf, id, "postimage"), NULL) < 0)
 		warning_errno(_("failed utime() on '%s'"),
-			      rerere_path(id, "postimage"));
+			      rerere_path(&buf, id, "postimage"));
 
 	/* Update "path" with the resolution */
 	f = fopen(path, "w");
@@ -694,6 +703,7 @@ static int merge(struct index_state *istate, const struct rerere_id *id, const c
 out:
 	free(cur.ptr);
 	free(result.ptr);
+	strbuf_release(&buf);
 
 	return ret;
 }
@@ -720,9 +730,11 @@ static void update_paths(struct repository *r, struct string_list *update)
 
 static void remove_variant(struct rerere_id *id)
 {
-	unlink_or_warn(rerere_path(id, "postimage"));
-	unlink_or_warn(rerere_path(id, "preimage"));
+	struct strbuf buf = STRBUF_INIT;
+	unlink_or_warn(rerere_path(&buf, id, "postimage"));
+	unlink_or_warn(rerere_path(&buf, id, "preimage"));
 	id->collection->status[id->variant] = 0;
+	strbuf_release(&buf);
 }
 
 /*
@@ -739,6 +751,7 @@ static void do_rerere_one_path(struct index_state *istate,
 	const char *path = rr_item->string;
 	struct rerere_id *id = rr_item->util;
 	struct rerere_dir *rr_dir = id->collection;
+	struct strbuf buf = STRBUF_INIT;
 	int variant;
 
 	variant = id->variant;
@@ -746,12 +759,12 @@ static void do_rerere_one_path(struct index_state *istate,
 	/* Has the user resolved it already? */
 	if (variant >= 0) {
 		if (!handle_file(istate, path, NULL, NULL)) {
-			copy_file(rerere_path(id, "postimage"), path, 0666);
+			copy_file(rerere_path(&buf, id, "postimage"), path, 0666);
 			id->collection->status[variant] |= RR_HAS_POSTIMAGE;
 			fprintf_ln(stderr, _("Recorded resolution for '%s'."), path);
 			free_rerere_id(rr_item);
 			rr_item->util = NULL;
-			return;
+			goto out;
 		}
 		/*
 		 * There may be other variants that can cleanly
@@ -787,22 +800,25 @@ static void do_rerere_one_path(struct index_state *istate,
 				   path);
 		free_rerere_id(rr_item);
 		rr_item->util = NULL;
-		return;
+		goto out;
 	}
 
 	/* None of the existing one applies; we need a new variant */
 	assign_variant(id);
 
 	variant = id->variant;
-	handle_file(istate, path, NULL, rerere_path(id, "preimage"));
+	handle_file(istate, path, NULL, rerere_path(&buf, id, "preimage"));
 	if (id->collection->status[variant] & RR_HAS_POSTIMAGE) {
-		const char *path = rerere_path(id, "postimage");
+		const char *path = rerere_path(&buf, id, "postimage");
 		if (unlink(path))
 			die_errno(_("cannot unlink stray '%s'"), path);
 		id->collection->status[variant] &= ~RR_HAS_POSTIMAGE;
 	}
 	id->collection->status[variant] |= RR_HAS_PREIMAGE;
 	fprintf_ln(stderr, _("Recorded preimage for '%s'"), path);
+
+out:
+	strbuf_release(&buf);
 }
 
 static int do_plain_rerere(struct repository *r,
@@ -810,6 +826,7 @@ static int do_plain_rerere(struct repository *r,
 {
 	struct string_list conflict = STRING_LIST_INIT_DUP;
 	struct string_list update = STRING_LIST_INIT_DUP;
+	struct strbuf buf = STRBUF_INIT;
 	int i;
 
 	find_conflict(r, &conflict);
@@ -843,7 +860,7 @@ static int do_plain_rerere(struct repository *r,
 		string_list_insert(rr, path)->util = id;
 
 		/* Ensure that the directory exists. */
-		mkdir_in_gitdir(rerere_path(id, NULL));
+		mkdir_in_gitdir(rerere_path(&buf, id, NULL));
 	}
 
 	for (i = 0; i < rr->nr; i++)
@@ -854,6 +871,7 @@ static int do_plain_rerere(struct repository *r,
 
 	string_list_clear(&conflict, 0);
 	string_list_clear(&update, 0);
+	strbuf_release(&buf);
 	return write_rr(rr, fd);
 }
 
@@ -1033,6 +1051,7 @@ static int rerere_forget_one_path(struct index_state *istate,
 	struct rerere_id *id;
 	unsigned char hash[GIT_MAX_RAWSZ];
 	int ret;
+	struct strbuf buf = STRBUF_INIT;
 	struct string_list_item *item;
 
 	/*
@@ -1056,8 +1075,8 @@ static int rerere_forget_one_path(struct index_state *istate,
 		if (!has_rerere_resolution(id))
 			continue;
 
-		handle_cache(istate, path, hash, rerere_path(id, "thisimage"));
-		if (read_mmfile(&cur, rerere_path(id, "thisimage"))) {
+		handle_cache(istate, path, hash, rerere_path(&buf, id, "thisimage"));
+		if (read_mmfile(&cur, rerere_path(&buf, id, "thisimage"))) {
 			free(cur.ptr);
 			error(_("failed to update conflicted state in '%s'"), path);
 			goto fail_exit;
@@ -1074,7 +1093,7 @@ static int rerere_forget_one_path(struct index_state *istate,
 		goto fail_exit;
 	}
 
-	filename = rerere_path(id, "postimage");
+	filename = rerere_path(&buf, id, "postimage");
 	if (unlink(filename)) {
 		if (errno == ENOENT)
 			error(_("no remembered resolution for '%s'"), path);
@@ -1088,7 +1107,7 @@ static int rerere_forget_one_path(struct index_state *istate,
 	 * conflict in the working tree, run us again to record
 	 * the postimage.
 	 */
-	handle_cache(istate, path, hash, rerere_path(id, "preimage"));
+	handle_cache(istate, path, hash, rerere_path(&buf, id, "preimage"));
 	fprintf_ln(stderr, _("Updated preimage for '%s'"), path);
 
 	/*
@@ -1099,9 +1118,11 @@ static int rerere_forget_one_path(struct index_state *istate,
 	free_rerere_id(item);
 	item->util = id;
 	fprintf(stderr, _("Forgot resolution for '%s'\n"), path);
+	strbuf_release(&buf);
 	return 0;
 
 fail_exit:
+	strbuf_release(&buf);
 	free(id);
 	return -1;
 }
@@ -1147,16 +1168,26 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)
 
 static timestamp_t rerere_created_at(struct rerere_id *id)
 {
+	struct strbuf buf = STRBUF_INIT;
 	struct stat st;
+	timestamp_t ret;
 
-	return stat(rerere_path(id, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
+	ret = stat(rerere_path(&buf, id, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
+
+	strbuf_release(&buf);
+	return ret;
 }
 
 static timestamp_t rerere_last_used_at(struct rerere_id *id)
 {
+	struct strbuf buf = STRBUF_INIT;
 	struct stat st;
+	timestamp_t ret;
 
-	return stat(rerere_path(id, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
+	ret = stat(rerere_path(&buf, id, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
+
+	strbuf_release(&buf);
+	return ret;
 }
 
 /*
@@ -1164,9 +1195,11 @@ static timestamp_t rerere_last_used_at(struct rerere_id *id)
  */
 static void unlink_rr_item(struct rerere_id *id)
 {
-	unlink_or_warn(rerere_path(id, "thisimage"));
+	struct strbuf buf = STRBUF_INIT;
+	unlink_or_warn(rerere_path(&buf, id, "thisimage"));
 	remove_variant(id);
 	id->collection->status[id->variant] = 0;
+	strbuf_release(&buf);
 }
 
 static void prune_one(struct rerere_id *id,
@@ -1205,6 +1238,7 @@ void rerere_gc(struct repository *r, struct string_list *rr)
 	timestamp_t now = time(NULL);
 	timestamp_t cutoff_noresolve = now - 15 * 86400;
 	timestamp_t cutoff_resolve = now - 60 * 86400;
+	struct strbuf buf = STRBUF_INIT;
 
 	if (setup_rerere(r, rr, 0) < 0)
 		return;
@@ -1214,7 +1248,7 @@ void rerere_gc(struct repository *r, struct string_list *rr)
 	repo_config_get_expiry_in_days(the_repository, "gc.rerereunresolved",
 				       &cutoff_noresolve, now);
 	git_config(git_default_config, NULL);
-	dir = opendir(git_path("rr-cache"));
+	dir = opendir(repo_git_path_replace(the_repository, &buf, "rr-cache"));
 	if (!dir)
 		die_errno(_("unable to open rr-cache directory"));
 	/* Collect stale conflict IDs ... */
@@ -1243,9 +1277,12 @@ void rerere_gc(struct repository *r, struct string_list *rr)
 
 	/* ... and then remove the empty directories */
 	for (i = 0; i < to_remove.nr; i++)
-		rmdir(git_path("rr-cache/%s", to_remove.items[i].string));
+		rmdir(repo_git_path_replace(the_repository, &buf,
+					    "rr-cache/%s", to_remove.items[i].string));
+
 	string_list_clear(&to_remove, 0);
 	rollback_lock_file(&write_lock);
+	strbuf_release(&buf);
 }
 
 /*
@@ -1264,10 +1301,14 @@ void rerere_clear(struct repository *r, struct string_list *merge_rr)
 
 	for (i = 0; i < merge_rr->nr; i++) {
 		struct rerere_id *id = merge_rr->items[i].util;
+		struct strbuf buf = STRBUF_INIT;
+
 		if (!has_rerere_resolution(id)) {
 			unlink_rr_item(id);
-			rmdir(rerere_path(id, NULL));
+			rmdir(rerere_path(&buf, id, NULL));
 		}
+
+		strbuf_release(&buf);
 	}
 	unlink_or_warn(git_path_merge_rr(r));
 	rollback_lock_file(&write_lock);
diff --git a/rerere.h b/rerere.h
index 5d6cb63..d4b5f7c 100644
--- a/rerere.h
+++ b/rerere.h
@@ -32,7 +32,8 @@ int repo_rerere(struct repository *, int);
  * path to that filesystem entity.  With "file" specified with NULL,
  * return the path to the directory that houses these files.
  */
-const char *rerere_path(const struct rerere_id *, const char *file);
+const char *rerere_path(struct strbuf *buf, const struct rerere_id *,
+			const char *file);
 int rerere_forget(struct repository *, struct pathspec *);
 int rerere_remaining(struct repository *, struct string_list *);
 void rerere_clear(struct repository *, struct string_list *);
diff --git a/resolve-undo.c b/resolve-undo.c
index b5a9dfb..52c45e5 100644
--- a/resolve-undo.c
+++ b/resolve-undo.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -34,7 +33,8 @@ void record_resolve_undo(struct index_state *istate, struct cache_entry *ce)
 	ui->mode[stage - 1] = ce->ce_mode;
 }
 
-void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo)
+void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo,
+			const struct git_hash_algo *algop)
 {
 	struct string_list_item *item;
 	for_each_string_list_item(item, resolve_undo) {
@@ -50,18 +50,19 @@ void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo)
 		for (i = 0; i < 3; i++) {
 			if (!ui->mode[i])
 				continue;
-			strbuf_add(sb, ui->oid[i].hash, the_hash_algo->rawsz);
+			strbuf_add(sb, ui->oid[i].hash, algop->rawsz);
 		}
 	}
 }
 
-struct string_list *resolve_undo_read(const char *data, unsigned long size)
+struct string_list *resolve_undo_read(const char *data, unsigned long size,
+				      const struct git_hash_algo *algop)
 {
 	struct string_list *resolve_undo;
 	size_t len;
 	char *endptr;
 	int i;
-	const unsigned rawsz = the_hash_algo->rawsz;
+	const unsigned rawsz = algop->rawsz;
 
 	CALLOC_ARRAY(resolve_undo, 1);
 	resolve_undo->strdup_strings = 1;
@@ -96,8 +97,7 @@ struct string_list *resolve_undo_read(const char *data, unsigned long size)
 				continue;
 			if (size < rawsz)
 				goto error;
-			oidread(&ui->oid[i], (const unsigned char *)data,
-				the_repository->hash_algo);
+			oidread(&ui->oid[i], (const unsigned char *)data, algop);
 			size -= rawsz;
 			data += rawsz;
 		}
diff --git a/resolve-undo.h b/resolve-undo.h
index 89a3227..7ed11a1 100644
--- a/resolve-undo.h
+++ b/resolve-undo.h
@@ -14,8 +14,10 @@ struct resolve_undo_info {
 };
 
 void record_resolve_undo(struct index_state *, struct cache_entry *);
-void resolve_undo_write(struct strbuf *, struct string_list *);
-struct string_list *resolve_undo_read(const char *, unsigned long);
+void resolve_undo_write(struct strbuf *, struct string_list *,
+			const struct git_hash_algo *algop);
+struct string_list *resolve_undo_read(const char *, unsigned long,
+				      const struct git_hash_algo *algop);
 void resolve_undo_clear_index(struct index_state *);
 int unmerge_index_entry(struct index_state *, const char *, struct resolve_undo_info *, unsigned);
 void unmerge_index(struct index_state *, const struct pathspec *, unsigned);
diff --git a/revision.c b/revision.c
index 474fa1e..c4390f0 100644
--- a/revision.c
+++ b/revision.c
@@ -1874,15 +1874,20 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
 	for (p = worktrees; *p; p++) {
 		struct worktree *wt = *p;
 		struct index_state istate = INDEX_STATE_INIT(revs->repo);
+		char *wt_gitdir;
 
 		if (wt->is_current)
 			continue; /* current index already taken care of */
 
+		wt_gitdir = get_worktree_git_dir(wt);
+
 		if (read_index_from(&istate,
 				    worktree_git_path(the_repository, wt, "index"),
-				    get_worktree_git_dir(wt)) > 0)
+				    wt_gitdir) > 0)
 			do_add_index_objects_to_pending(revs, &istate, flags);
+
 		discard_index(&istate);
+		free(wt_gitdir);
 	}
 	free_worktrees(worktrees);
 }
diff --git a/scalar.c b/scalar.c
index f24bcd0..da42b4b 100644
--- a/scalar.c
+++ b/scalar.c
@@ -409,6 +409,7 @@ void load_builtin_commands(const char *prefix UNUSED,
 static int cmd_clone(int argc, const char **argv)
 {
 	const char *branch = NULL;
+	char *branch_to_free = NULL;
 	int full_clone = 0, single_branch = 0, show_progress = isatty(2);
 	int src = 1, tags = 1;
 	struct option clone_options[] = {
@@ -490,7 +491,7 @@ static int cmd_clone(int argc, const char **argv)
 	/* common-main already logs `argv` */
 	trace2_def_repo(the_repository);
 
-	if (!branch && !(branch = remote_default_branch(url))) {
+	if (!branch && !(branch = branch_to_free = remote_default_branch(url))) {
 		res = error(_("failed to get default branch for '%s'"), url);
 		goto cleanup;
 	}
@@ -552,6 +553,7 @@ static int cmd_clone(int argc, const char **argv)
 	res = register_dir();
 
 cleanup:
+	free(branch_to_free);
 	free(enlistment);
 	free(dir);
 	strbuf_release(&buf);
diff --git a/send-pack.c b/send-pack.c
index 7e83213..856a65d 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "config.h"
 #include "commit.h"
@@ -44,10 +42,11 @@ int option_parse_push_signed(const struct option *opt,
 	die("bad %s argument: %s", opt->long_name, arg);
 }
 
-static void feed_object(const struct object_id *oid, FILE *fh, int negative)
+static void feed_object(struct repository *r,
+			const struct object_id *oid, FILE *fh, int negative)
 {
 	if (negative &&
-	    !repo_has_object_file_with_flags(the_repository, oid,
+	    !repo_has_object_file_with_flags(r, oid,
 					     OBJECT_INFO_SKIP_FETCH_OBJECT |
 					     OBJECT_INFO_QUICK))
 		return;
@@ -61,7 +60,8 @@ static void feed_object(const struct object_id *oid, FILE *fh, int negative)
 /*
  * Make a pack stream and spit it out into file descriptor fd
  */
-static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
+static int pack_objects(struct repository *r,
+			int fd, struct ref *refs, struct oid_array *advertised,
 			struct oid_array *negotiated,
 			struct send_pack_args *args)
 {
@@ -74,7 +74,7 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
 	FILE *po_in;
 	int rc;
 
-	trace2_region_enter("send_pack", "pack_objects", the_repository);
+	trace2_region_enter("send_pack", "pack_objects", r);
 	strvec_push(&po.args, "pack-objects");
 	strvec_push(&po.args, "--all-progress-implied");
 	strvec_push(&po.args, "--revs");
@@ -87,7 +87,7 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
 		strvec_push(&po.args, "-q");
 	if (args->progress)
 		strvec_push(&po.args, "--progress");
-	if (is_repository_shallow(the_repository))
+	if (is_repository_shallow(r))
 		strvec_push(&po.args, "--shallow");
 	if (args->disable_bitmaps)
 		strvec_push(&po.args, "--no-use-bitmap-index");
@@ -104,15 +104,15 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
 	 */
 	po_in = xfdopen(po.in, "w");
 	for (size_t i = 0; i < advertised->nr; i++)
-		feed_object(&advertised->oid[i], po_in, 1);
+		feed_object(r, &advertised->oid[i], po_in, 1);
 	for (size_t i = 0; i < negotiated->nr; i++)
-		feed_object(&negotiated->oid[i], po_in, 1);
+		feed_object(r, &negotiated->oid[i], po_in, 1);
 
 	while (refs) {
 		if (!is_null_oid(&refs->old_oid))
-			feed_object(&refs->old_oid, po_in, 1);
+			feed_object(r, &refs->old_oid, po_in, 1);
 		if (!is_null_oid(&refs->new_oid))
-			feed_object(&refs->new_oid, po_in, 0);
+			feed_object(r, &refs->new_oid, po_in, 0);
 		refs = refs->next;
 	}
 
@@ -146,10 +146,10 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
 		 */
 		if (rc > 128 && rc != 141)
 			error("pack-objects died of signal %d", rc - 128);
-		trace2_region_leave("send_pack", "pack_objects", the_repository);
+		trace2_region_leave("send_pack", "pack_objects", r);
 		return -1;
 	}
-	trace2_region_leave("send_pack", "pack_objects", the_repository);
+	trace2_region_leave("send_pack", "pack_objects", r);
 	return 0;
 }
 
@@ -164,7 +164,8 @@ static int receive_unpack_status(struct packet_reader *reader)
 	return 0;
 }
 
-static int receive_status(struct packet_reader *reader, struct ref *refs)
+static int receive_status(struct repository *r,
+			  struct packet_reader *reader, struct ref *refs)
 {
 	struct ref *hint;
 	int ret;
@@ -172,7 +173,7 @@ static int receive_status(struct packet_reader *reader, struct ref *refs)
 	int new_report = 0;
 	int once = 0;
 
-	trace2_region_enter("send_pack", "receive_status", the_repository);
+	trace2_region_enter("send_pack", "receive_status", r);
 	hint = NULL;
 	ret = receive_unpack_status(reader);
 	while (1) {
@@ -221,10 +222,10 @@ static int receive_status(struct packet_reader *reader, struct ref *refs)
 			if (!strcmp(key, "refname"))
 				report->ref_name = xstrdup_or_null(val);
 			else if (!strcmp(key, "old-oid") && val &&
-				 !parse_oid_hex(val, &old_oid, &val))
+				 !parse_oid_hex_algop(val, &old_oid, &val, r->hash_algo))
 				report->old_oid = oiddup(&old_oid);
 			else if (!strcmp(key, "new-oid") && val &&
-				 !parse_oid_hex(val, &new_oid, &val))
+				 !parse_oid_hex_algop(val, &new_oid, &val, r->hash_algo))
 				report->new_oid = oiddup(&new_oid);
 			else if (!strcmp(key, "forced-update"))
 				report->forced_update = 1;
@@ -271,7 +272,7 @@ static int receive_status(struct packet_reader *reader, struct ref *refs)
 			new_report = 1;
 		}
 	}
-	trace2_region_leave("send_pack", "receive_status", the_repository);
+	trace2_region_leave("send_pack", "receive_status", r);
 	return ret;
 }
 
@@ -293,9 +294,9 @@ static int advertise_shallow_grafts_cb(const struct commit_graft *graft, void *c
 	return 0;
 }
 
-static void advertise_shallow_grafts_buf(struct strbuf *sb)
+static void advertise_shallow_grafts_buf(struct repository *r, struct strbuf *sb)
 {
-	if (!is_repository_shallow(the_repository))
+	if (!is_repository_shallow(r))
 		return;
 	for_each_commit_graft(advertise_shallow_grafts_cb, sb);
 }
@@ -426,13 +427,14 @@ static void reject_invalid_nonce(const char *nonce, int len)
 	}
 }
 
-static void get_commons_through_negotiation(const char *url,
+static void get_commons_through_negotiation(struct repository *r,
+					    const char *url,
 					    const struct ref *remote_refs,
 					    struct oid_array *commons)
 {
 	struct child_process child = CHILD_PROCESS_INIT;
 	const struct ref *ref;
-	int len = the_hash_algo->hexsz + 1; /* hash + NL */
+	int len = r->hash_algo->hexsz + 1; /* hash + NL */
 	int nr_negotiation_tip = 0;
 
 	child.git_cmd = 1;
@@ -466,7 +468,7 @@ static void get_commons_through_negotiation(const char *url,
 			break;
 		if (read_len != len)
 			die("invalid length read %d", read_len);
-		if (parse_oid_hex(hex_hash, &oid, &end) || *end != '\n')
+		if (parse_oid_hex_algop(hex_hash, &oid, &end, r->hash_algo) || *end != '\n')
 			die("invalid hash");
 		oid_array_append(commons, &oid);
 	} while (1);
@@ -480,7 +482,8 @@ static void get_commons_through_negotiation(const char *url,
 	}
 }
 
-int send_pack(struct send_pack_args *args,
+int send_pack(struct repository *r,
+	      struct send_pack_args *args,
 	      int fd[], struct child_process *conn,
 	      struct ref *remote_refs,
 	      struct oid_array *extra_have)
@@ -518,17 +521,17 @@ int send_pack(struct send_pack_args *args,
 		goto out;
 	}
 
-	git_config_get_bool("push.negotiate", &push_negotiate);
+	repo_config_get_bool(r, "push.negotiate", &push_negotiate);
 	if (push_negotiate) {
-		trace2_region_enter("send_pack", "push_negotiate", the_repository);
-		get_commons_through_negotiation(args->url, remote_refs, &commons);
-		trace2_region_leave("send_pack", "push_negotiate", the_repository);
+		trace2_region_enter("send_pack", "push_negotiate", r);
+		get_commons_through_negotiation(r, args->url, remote_refs, &commons);
+		trace2_region_leave("send_pack", "push_negotiate", r);
 	}
 
-	if (!git_config_get_bool("push.usebitmaps", &use_bitmaps))
+	if (!repo_config_get_bool(r, "push.usebitmaps", &use_bitmaps))
 		args->disable_bitmaps = !use_bitmaps;
 
-	git_config_get_bool("transfer.advertisesid", &advertise_sid);
+	repo_config_get_bool(r, "transfer.advertisesid", &advertise_sid);
 
 	/* Does the other end support the reporting? */
 	if (server_supports("report-status-v2"))
@@ -554,7 +557,7 @@ int send_pack(struct send_pack_args *args,
 	if (server_supports("push-options"))
 		push_options_supported = 1;
 
-	if (!server_supports_hash(the_hash_algo->name, &object_format_supported))
+	if (!server_supports_hash(r->hash_algo->name, &object_format_supported))
 		die(_("the receiving end does not support this repository's hash algorithm"));
 
 	if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) {
@@ -596,7 +599,7 @@ int send_pack(struct send_pack_args *args,
 	if (use_push_options)
 		strbuf_addstr(&cap_buf, " push-options");
 	if (object_format_supported)
-		strbuf_addf(&cap_buf, " object-format=%s", the_hash_algo->name);
+		strbuf_addf(&cap_buf, " object-format=%s", r->hash_algo->name);
 	if (agent_supported)
 		strbuf_addf(&cap_buf, " agent=%s", git_user_agent_sanitized());
 	if (advertise_sid)
@@ -629,7 +632,8 @@ int send_pack(struct send_pack_args *args,
 				reject_atomic_push(remote_refs, args->send_mirror);
 				error("atomic push failed for ref %s. status: %d",
 				      ref->name, ref->status);
-				ret = args->porcelain ? 0 : -1;
+				ret = ERROR_SEND_PACK_BAD_REF_STATUS;
+				packet_flush(out);
 				goto out;
 			}
 			/* else fallthrough */
@@ -646,7 +650,7 @@ int send_pack(struct send_pack_args *args,
 	}
 
 	if (!args->dry_run)
-		advertise_shallow_grafts_buf(&req_buf);
+		advertise_shallow_grafts_buf(r, &req_buf);
 
 	/*
 	 * Finally, tell the other end!
@@ -686,7 +690,7 @@ int send_pack(struct send_pack_args *args,
 	}
 
 	if (args->stateless_rpc) {
-		if (!args->dry_run && (cmds_sent || is_repository_shallow(the_repository))) {
+		if (!args->dry_run && (cmds_sent || is_repository_shallow(r))) {
 			packet_buf_flush(&req_buf);
 			send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
 		}
@@ -711,7 +715,7 @@ int send_pack(struct send_pack_args *args,
 			   PACKET_READ_DIE_ON_ERR_PACKET);
 
 	if (need_pack_data && cmds_sent) {
-		if (pack_objects(out, remote_refs, extra_have, &commons, args) < 0) {
+		if (pack_objects(r, out, remote_refs, extra_have, &commons, args) < 0) {
 			if (args->stateless_rpc)
 				close(out);
 			if (git_connection_is_socket(conn))
@@ -724,7 +728,7 @@ int send_pack(struct send_pack_args *args,
 			 * we get one).
 			 */
 			if (status_report)
-				receive_status(&reader, remote_refs);
+				receive_status(r, &reader, remote_refs);
 
 			if (use_sideband) {
 				close(demux.out);
@@ -743,7 +747,7 @@ int send_pack(struct send_pack_args *args,
 		packet_flush(out);
 
 	if (status_report && cmds_sent)
-		ret = receive_status(&reader, remote_refs);
+		ret = receive_status(r, &reader, remote_refs);
 	else
 		ret = 0;
 	if (args->stateless_rpc)
@@ -760,11 +764,6 @@ int send_pack(struct send_pack_args *args,
 	if (ret < 0)
 		goto out;
 
-	if (args->porcelain) {
-		ret = 0;
-		goto out;
-	}
-
 	for (ref = remote_refs; ref; ref = ref->next) {
 		switch (ref->status) {
 		case REF_STATUS_NONE:
@@ -772,7 +771,7 @@ int send_pack(struct send_pack_args *args,
 		case REF_STATUS_OK:
 			break;
 		default:
-			ret = -1;
+			ret = ERROR_SEND_PACK_BAD_REF_STATUS;
 			goto out;
 		}
 	}
diff --git a/send-pack.h b/send-pack.h
index 7edb805..c5ded2d 100644
--- a/send-pack.h
+++ b/send-pack.h
@@ -6,12 +6,16 @@
 struct child_process;
 struct oid_array;
 struct ref;
+struct repository;
 
 /* Possible values for push_cert field in send_pack_args. */
 #define SEND_PACK_PUSH_CERT_NEVER 0
 #define SEND_PACK_PUSH_CERT_IF_ASKED 1
 #define SEND_PACK_PUSH_CERT_ALWAYS 2
 
+/* At least one reference has been rejected by the remote side. */
+#define ERROR_SEND_PACK_BAD_REF_STATUS 1
+
 struct send_pack_args {
 	const char *url;
 	unsigned verbose:1,
@@ -35,7 +39,17 @@ struct option;
 int option_parse_push_signed(const struct option *opt,
 			     const char *arg, int unset);
 
-int send_pack(struct send_pack_args *args,
+/*
+ * Compute a packfile and write it to a file descriptor. The `fd` array needs
+ * to contain two file descriptors: `fd[0]` is the file descriptor used as
+ * input for the packet reader, whereas `fd[1]` is the file descriptor the
+ * packfile will be written to.
+ *
+ * Returns 0 on success, non-zero otherwise. Negative return values indicate a
+ * generic error, whereas positive return values indicate specific error
+ * conditions as documented with the `ERROR_SEND_PACK_*` constants.
+ */
+int send_pack(struct repository *r, struct send_pack_args *args,
 	      int fd[], struct child_process *conn,
 	      struct ref *remote_refs, struct oid_array *extra_have);
 
diff --git a/sequencer.c b/sequencer.c
index 407ee4e..ad0ab75 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2510,9 +2510,15 @@ static int do_pick_commit(struct repository *r,
 		*check_todo = !!(flags & EDIT_MSG);
 		if (!res && reword) {
 fast_forward_edit:
-			res = run_git_commit(NULL, opts, EDIT_MSG |
-					     VERIFY_MSG | AMEND_MSG |
-					     (flags & ALLOW_EMPTY));
+			/*
+			 * To reword we amend the commit we just
+			 * picked or fast-forwarded. As the commit has
+			 * already been picked we want to use the same
+			 * set of commit flags regardless of how we
+			 * got here.
+			 */
+			flags = EDIT_MSG | VERIFY_MSG | AMEND_MSG | ALLOW_EMPTY;
+			res = run_git_commit(NULL, opts, flags);
 			*check_todo = 1;
 		}
 	}
diff --git a/serve.c b/serve.c
index c8694e3..e3ccf15 100644
--- a/serve.c
+++ b/serve.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "repository.h"
 #include "config.h"
@@ -12,6 +10,7 @@
 #include "upload-pack.h"
 #include "bundle-uri.h"
 #include "trace2.h"
+#include "promisor-remote.h"
 
 static int advertise_sid = -1;
 static int advertise_object_info = -1;
@@ -31,6 +30,26 @@ static int agent_advertise(struct repository *r UNUSED,
 	return 1;
 }
 
+static int promisor_remote_advertise(struct repository *r,
+				     struct strbuf *value)
+{
+	if (value) {
+		char *info = promisor_remote_info(r);
+		if (!info)
+			return 0;
+		strbuf_addstr(value, info);
+		free(info);
+	}
+	return 1;
+}
+
+static void promisor_remote_receive(struct repository *r,
+				    const char *remotes)
+{
+	mark_promisor_remotes_as_accepted(r, remotes);
+}
+
+
 static int object_format_advertise(struct repository *r,
 				   struct strbuf *value)
 {
@@ -157,9 +176,14 @@ static struct protocol_capability capabilities[] = {
 		.advertise = bundle_uri_advertise,
 		.command = bundle_uri_command,
 	},
+	{
+		.name = "promisor-remote",
+		.advertise = promisor_remote_advertise,
+		.receive = promisor_remote_receive,
+	},
 };
 
-void protocol_v2_advertise_capabilities(void)
+void protocol_v2_advertise_capabilities(struct repository *r)
 {
 	struct strbuf capability = STRBUF_INIT;
 	struct strbuf value = STRBUF_INIT;
@@ -170,7 +194,7 @@ void protocol_v2_advertise_capabilities(void)
 	for (size_t i = 0; i < ARRAY_SIZE(capabilities); i++) {
 		struct protocol_capability *c = &capabilities[i];
 
-		if (c->advertise(the_repository, &value)) {
+		if (c->advertise(r, &value)) {
 			strbuf_addstr(&capability, c->name);
 
 			if (value.len) {
@@ -214,20 +238,20 @@ static struct protocol_capability *get_capability(const char *key, const char **
 	return NULL;
 }
 
-static int receive_client_capability(const char *key)
+static int receive_client_capability(struct repository *r, const char *key)
 {
 	const char *value;
 	const struct protocol_capability *c = get_capability(key, &value);
 
-	if (!c || c->command || !c->advertise(the_repository, NULL))
+	if (!c || c->command || !c->advertise(r, NULL))
 		return 0;
 
 	if (c->receive)
-		c->receive(the_repository, value);
+		c->receive(r, value);
 	return 1;
 }
 
-static int parse_command(const char *key, struct protocol_capability **command)
+static int parse_command(struct repository *r, const char *key, struct protocol_capability **command)
 {
 	const char *out;
 
@@ -238,7 +262,7 @@ static int parse_command(const char *key, struct protocol_capability **command)
 		if (*command)
 			die("command '%s' requested after already requesting command '%s'",
 			    out, (*command)->name);
-		if (!cmd || !cmd->advertise(the_repository, NULL) || !cmd->command || value)
+		if (!cmd || !cmd->advertise(r, NULL) || !cmd->command || value)
 			die("invalid command '%s'", out);
 
 		*command = cmd;
@@ -253,7 +277,7 @@ enum request_state {
 	PROCESS_REQUEST_DONE,
 };
 
-static int process_request(void)
+static int process_request(struct repository *r)
 {
 	enum request_state state = PROCESS_REQUEST_KEYS;
 	struct packet_reader reader;
@@ -278,8 +302,8 @@ static int process_request(void)
 		case PACKET_READ_EOF:
 			BUG("Should have already died when seeing EOF");
 		case PACKET_READ_NORMAL:
-			if (parse_command(reader.line, &command) ||
-			    receive_client_capability(reader.line))
+			if (parse_command(r, reader.line, &command) ||
+			    receive_client_capability(r, reader.line))
 				seen_capability_or_command = 1;
 			else
 				die("unknown capability '%s'", reader.line);
@@ -319,30 +343,30 @@ static int process_request(void)
 	if (!command)
 		die("no command requested");
 
-	if (client_hash_algo != hash_algo_by_ptr(the_repository->hash_algo))
+	if (client_hash_algo != hash_algo_by_ptr(r->hash_algo))
 		die("mismatched object format: server %s; client %s",
-		    the_repository->hash_algo->name,
+		    r->hash_algo->name,
 		    hash_algos[client_hash_algo].name);
 
-	command->command(the_repository, &reader);
+	command->command(r, &reader);
 
 	return 0;
 }
 
-void protocol_v2_serve_loop(int stateless_rpc)
+void protocol_v2_serve_loop(struct repository *r, int stateless_rpc)
 {
 	if (!stateless_rpc)
-		protocol_v2_advertise_capabilities();
+		protocol_v2_advertise_capabilities(r);
 
 	/*
 	 * If stateless-rpc was requested then exit after
 	 * a single request/response exchange
 	 */
 	if (stateless_rpc) {
-		process_request();
+		process_request(r);
 	} else {
 		for (;;)
-			if (process_request())
+			if (process_request(r))
 				break;
 	}
 }
diff --git a/serve.h b/serve.h
index f946cf9..85bf73c 100644
--- a/serve.h
+++ b/serve.h
@@ -1,7 +1,9 @@
 #ifndef SERVE_H
 #define SERVE_H
 
-void protocol_v2_advertise_capabilities(void);
-void protocol_v2_serve_loop(int stateless_rpc);
+struct repository;
+
+void protocol_v2_advertise_capabilities(struct repository *r);
+void protocol_v2_serve_loop(struct repository *r, int stateless_rpc);
 
 #endif /* SERVE_H */
diff --git a/server-info.c b/server-info.c
index ef2f3f4..1ca0e00 100644
--- a/server-info.c
+++ b/server-info.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -18,6 +17,7 @@
 #include "tempfile.h"
 
 struct update_info_ctx {
+	struct repository *repo;
 	FILE *cur_fp;
 	FILE *old_fp; /* becomes NULL if it differs from cur_fp */
 	struct strbuf cur_sb;
@@ -73,7 +73,7 @@ static int uic_printf(struct update_info_ctx *uic, const char *fmt, ...)
  * it into place. The contents of the file come from "generate", which
  * should return non-zero if it encounters an error.
  */
-static int update_info_file(char *path,
+static int update_info_file(struct repository *r, char *path,
 			int (*generate)(struct update_info_ctx *),
 			int force)
 {
@@ -81,6 +81,7 @@ static int update_info_file(char *path,
 	struct tempfile *f = NULL;
 	int ret = -1;
 	struct update_info_ctx uic = {
+		.repo = r,
 		.cur_fp = NULL,
 		.old_fp = NULL,
 		.cur_sb = STRBUF_INIT,
@@ -124,7 +125,7 @@ static int update_info_file(char *path,
 	uic.cur_fp = NULL;
 
 	if (uic_is_stale(&uic)) {
-		if (adjust_shared_perm(get_tempfile_path(f)) < 0)
+		if (adjust_shared_perm(r, get_tempfile_path(f)) < 0)
 			goto out;
 		if (rename_tempfile(&f, path) < 0)
 			goto out;
@@ -152,7 +153,7 @@ static int add_info_ref(const char *path, const char *referent UNUSED, const str
 			void *cb_data)
 {
 	struct update_info_ctx *uic = cb_data;
-	struct object *o = parse_object(the_repository, oid);
+	struct object *o = parse_object(uic->repo, oid);
 	if (!o)
 		return -1;
 
@@ -160,7 +161,7 @@ static int add_info_ref(const char *path, const char *referent UNUSED, const str
 		return -1;
 
 	if (o->type == OBJ_TAG) {
-		o = deref_tag(the_repository, o, path, 0);
+		o = deref_tag(uic->repo, o, path, 0);
 		if (o)
 			if (uic_printf(uic, "%s	%s^{}\n",
 				oid_to_hex(&o->oid), path) < 0)
@@ -171,14 +172,14 @@ static int add_info_ref(const char *path, const char *referent UNUSED, const str
 
 static int generate_info_refs(struct update_info_ctx *uic)
 {
-	return refs_for_each_ref(get_main_ref_store(the_repository),
+	return refs_for_each_ref(get_main_ref_store(uic->repo),
 				 add_info_ref, uic);
 }
 
-static int update_info_refs(int force)
+static int update_info_refs(struct repository *r, int force)
 {
-	char *path = git_pathdup("info/refs");
-	int ret = update_info_file(path, generate_info_refs, force);
+	char *path = repo_git_path(r, "info/refs");
+	int ret = update_info_file(r, path, generate_info_refs, force);
 	free(path);
 	return ret;
 }
@@ -284,14 +285,14 @@ static int compare_info(const void *a_, const void *b_)
 		return 1;
 }
 
-static void init_pack_info(const char *infofile, int force)
+static void init_pack_info(struct repository *r, const char *infofile, int force)
 {
 	struct packed_git *p;
 	int stale;
 	int i;
 	size_t alloc = 0;
 
-	for (p = get_all_packs(the_repository); p; p = p->next) {
+	for (p = get_all_packs(r); p; p = p->next) {
 		/* we ignore things on alternate path since they are
 		 * not available to the pullers in general.
 		 */
@@ -340,33 +341,36 @@ static int write_pack_info_file(struct update_info_ctx *uic)
 	return 0;
 }
 
-static int update_info_packs(int force)
+static int update_info_packs(struct repository *r, int force)
 {
 	char *infofile = mkpathdup("%s/info/packs",
-				   repo_get_object_directory(the_repository));
+				   repo_get_object_directory(r));
 	int ret;
 
-	init_pack_info(infofile, force);
-	ret = update_info_file(infofile, write_pack_info_file, force);
+	init_pack_info(r, infofile, force);
+	ret = update_info_file(r, infofile, write_pack_info_file, force);
 	free_pack_info();
 	free(infofile);
 	return ret;
 }
 
 /* public */
-int update_server_info(int force)
+int update_server_info(struct repository *r, int force)
 {
 	/* We would add more dumb-server support files later,
 	 * including index of available pack files and their
 	 * intended audiences.
 	 */
 	int errs = 0;
+	char *path;
 
-	errs = errs | update_info_refs(force);
-	errs = errs | update_info_packs(force);
+	errs = errs | update_info_refs(r, force);
+	errs = errs | update_info_packs(r, force);
 
 	/* remove leftover rev-cache file if there is any */
-	unlink_or_warn(git_path("info/rev-cache"));
+	path = repo_git_path(r, "info/rev-cache");
+	unlink_or_warn(path);
+	free(path);
 
 	return errs;
 }
diff --git a/server-info.h b/server-info.h
index 13bbde2..e634d17 100644
--- a/server-info.h
+++ b/server-info.h
@@ -1,7 +1,9 @@
 #ifndef SERVER_INFO_H
 #define SERVER_INFO_H
 
+struct repository;
+
 /* Dumb servers support */
-int update_server_info(int);
+int update_server_info(struct repository *r, int force);
 
 #endif /* SERVER_INFO_H */
diff --git a/setup.c b/setup.c
index 8a488f3..f93bd6a 100644
--- a/setup.c
+++ b/setup.c
@@ -792,7 +792,7 @@ int upgrade_repository_format(int target_version)
 	struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
 	int ret;
 
-	strbuf_git_common_path(&sb, the_repository, "config");
+	repo_common_path_append(the_repository, &sb, "config");
 	read_repository_format(&repo_fmt, sb.buf);
 	strbuf_release(&sb);
 
@@ -1822,7 +1822,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
 	 *
 	 * Regardless of the state of nongit_ok, startup_info->prefix and
 	 * the GIT_PREFIX environment variable must always match. For details
-	 * see Documentation/config/alias.txt.
+	 * see Documentation/config/alias.adoc.
 	 */
 	if (nongit_ok && *nongit_ok)
 		startup_info->have_repository = 0;
@@ -2088,7 +2088,7 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
 	 * with the way the namespace under .git/ is organized, should
 	 * be really carefully chosen.
 	 */
-	safe_create_dir(path->buf, 1);
+	safe_create_dir(the_repository, path->buf, 1);
 	while ((de = readdir(dir)) != NULL) {
 		struct stat st_git, st_template;
 		int exists = 0;
@@ -2242,7 +2242,7 @@ void initialize_repository_version(int hash_algo,
 		struct strbuf config = STRBUF_INIT;
 		struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
 
-		strbuf_git_common_path(&config, the_repository, "config");
+		repo_common_path_append(the_repository, &config, "config");
 		read_repository_format(&repo_fmt, config.buf);
 
 		if (repo_fmt.v1_only_extensions.nr)
@@ -2264,7 +2264,7 @@ static int is_reinit(void)
 	char junk[2];
 	int ret;
 
-	git_path_buf(&buf, "HEAD");
+	repo_git_path_replace(the_repository, &buf, "HEAD");
 	ret = !access(buf.buf, R_OK) || readlink(buf.buf, junk, sizeof(junk) - 1) != -1;
 	strbuf_release(&buf);
 	return ret;
@@ -2316,8 +2316,7 @@ static int create_default_files(const char *template_path,
 				int init_shared_repository)
 {
 	struct stat st1;
-	struct strbuf buf = STRBUF_INIT;
-	char *path;
+	struct strbuf path = STRBUF_INIT;
 	int reinit;
 	int filemode;
 	const char *work_tree = repo_get_work_tree(the_repository);
@@ -2333,7 +2332,7 @@ static int create_default_files(const char *template_path,
 	 */
 	copy_templates(template_path);
 	git_config_clear();
-	reset_shared_repository();
+	repo_settings_reset_shared_repository(the_repository);
 	git_config(git_default_config, NULL);
 
 	reinit = is_reinit();
@@ -2343,7 +2342,8 @@ static int create_default_files(const char *template_path,
 	 * values we might have just re-read from the config.
 	 */
 	if (init_shared_repository != -1)
-		set_shared_repository(init_shared_repository);
+		repo_settings_set_shared_repository(the_repository,
+						    init_shared_repository);
 
 	is_bare_repository_cfg = !work_tree;
 
@@ -2351,21 +2351,21 @@ static int create_default_files(const char *template_path,
 	 * We would have created the above under user's umask -- under
 	 * shared-repository settings, we would need to fix them up.
 	 */
-	if (get_shared_repository()) {
-		adjust_shared_perm(repo_get_git_dir(the_repository));
+	if (repo_settings_get_shared_repository(the_repository)) {
+		adjust_shared_perm(the_repository, repo_get_git_dir(the_repository));
 	}
 
 	initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, reinit);
 
 	/* Check filemode trustability */
-	path = git_path_buf(&buf, "config");
+	repo_git_path_replace(the_repository, &path, "config");
 	filemode = TEST_FILEMODE;
-	if (TEST_FILEMODE && !lstat(path, &st1)) {
+	if (TEST_FILEMODE && !lstat(path.buf, &st1)) {
 		struct stat st2;
-		filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
-				!lstat(path, &st2) &&
+		filemode = (!chmod(path.buf, st1.st_mode ^ S_IXUSR) &&
+				!lstat(path.buf, &st2) &&
 				st1.st_mode != st2.st_mode &&
-				!chmod(path, st1.st_mode));
+				!chmod(path.buf, st1.st_mode));
 		if (filemode && !reinit && (st1.st_mode & S_IXUSR))
 			filemode = 0;
 	}
@@ -2384,24 +2384,24 @@ static int create_default_files(const char *template_path,
 
 	if (!reinit) {
 		/* Check if symlink is supported in the work tree */
-		path = git_path_buf(&buf, "tXXXXXX");
-		if (!close(xmkstemp(path)) &&
-		    !unlink(path) &&
-		    !symlink("testing", path) &&
-		    !lstat(path, &st1) &&
+		repo_git_path_replace(the_repository, &path, "tXXXXXX");
+		if (!close(xmkstemp(path.buf)) &&
+		    !unlink(path.buf) &&
+		    !symlink("testing", path.buf) &&
+		    !lstat(path.buf, &st1) &&
 		    S_ISLNK(st1.st_mode))
-			unlink(path); /* good */
+			unlink(path.buf); /* good */
 		else
 			git_config_set("core.symlinks", "false");
 
 		/* Check if the filesystem is case-insensitive */
-		path = git_path_buf(&buf, "CoNfIg");
-		if (!access(path, F_OK))
+		repo_git_path_replace(the_repository, &path, "CoNfIg");
+		if (!access(path.buf, F_OK))
 			git_config_set("core.ignorecase", "true");
 		probe_utf8_pathname_composition();
 	}
 
-	strbuf_release(&buf);
+	strbuf_release(&path);
 	return reinit;
 }
 
@@ -2413,15 +2413,15 @@ static void create_object_directory(void)
 	strbuf_addstr(&path, repo_get_object_directory(the_repository));
 	baselen = path.len;
 
-	safe_create_dir(path.buf, 1);
+	safe_create_dir(the_repository, path.buf, 1);
 
 	strbuf_setlen(&path, baselen);
 	strbuf_addstr(&path, "/pack");
-	safe_create_dir(path.buf, 1);
+	safe_create_dir(the_repository, path.buf, 1);
 
 	strbuf_setlen(&path, baselen);
 	strbuf_addstr(&path, "/info");
-	safe_create_dir(path.buf, 1);
+	safe_create_dir(the_repository, path.buf, 1);
 
 	strbuf_release(&path);
 }
@@ -2517,7 +2517,9 @@ static void repository_format_configure(struct repository_format *repo_fmt,
 		int env_algo = hash_algo_by_name(env);
 		if (env_algo == GIT_HASH_UNKNOWN)
 			die(_("unknown hash algorithm '%s'"), env);
-		repo_fmt->hash_algo = env_algo;
+		if (repo_fmt->version < 0 ||
+		    repo_fmt->hash_algo == GIT_HASH_UNKNOWN)
+			repo_fmt->hash_algo = env_algo;
 	} else if (cfg.hash != GIT_HASH_UNKNOWN) {
 		repo_fmt->hash_algo = cfg.hash;
 	}
@@ -2534,7 +2536,9 @@ static void repository_format_configure(struct repository_format *repo_fmt,
 		ref_format = ref_storage_format_by_name(env);
 		if (ref_format == REF_STORAGE_FORMAT_UNKNOWN)
 			die(_("unknown ref storage format '%s'"), env);
-		repo_fmt->ref_storage_format = ref_format;
+		if (repo_fmt->version < 0 ||
+		    repo_fmt->ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+			repo_fmt->ref_storage_format = ref_format;
 	} else if (cfg.ref_format != REF_STORAGE_FORMAT_UNKNOWN) {
 		repo_fmt->ref_storage_format = cfg.ref_format;
 	}
@@ -2588,7 +2592,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
 	 */
 	git_config(platform_core_config, NULL);
 
-	safe_create_dir(git_dir, 0);
+	safe_create_dir(the_repository, git_dir, 0);
 
 	reinit = create_default_files(template_dir, original_git_dir,
 				      &repo_fmt, init_shared_repository);
@@ -2598,7 +2602,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
 					  initial_branch, flags & INIT_DB_QUIET);
 	create_object_directory();
 
-	if (get_shared_repository()) {
+	if (repo_settings_get_shared_repository(the_repository)) {
 		char buf[10];
 		/* We do not spell "group" and such, so that
 		 * the configuration can be read by older version
@@ -2606,12 +2610,12 @@ int init_db(const char *git_dir, const char *real_git_dir,
 		 * and compatibility values for PERM_GROUP and
 		 * PERM_EVERYBODY.
 		 */
-		if (get_shared_repository() < 0)
+		if (repo_settings_get_shared_repository(the_repository) < 0)
 			/* force to the mode value */
-			xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
-		else if (get_shared_repository() == PERM_GROUP)
+			xsnprintf(buf, sizeof(buf), "0%o", -repo_settings_get_shared_repository(the_repository));
+		else if (repo_settings_get_shared_repository(the_repository) == PERM_GROUP)
 			xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP);
-		else if (get_shared_repository() == PERM_EVERYBODY)
+		else if (repo_settings_get_shared_repository(the_repository) == PERM_EVERYBODY)
 			xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
 		else
 			BUG("invalid value for shared_repository");
@@ -2623,12 +2627,12 @@ int init_db(const char *git_dir, const char *real_git_dir,
 		int len = strlen(git_dir);
 
 		if (reinit)
-			printf(get_shared_repository()
+			printf(repo_settings_get_shared_repository(the_repository)
 			       ? _("Reinitialized existing shared Git repository in %s%s\n")
 			       : _("Reinitialized existing Git repository in %s%s\n"),
 			       git_dir, len && git_dir[len-1] != '/' ? "/" : "");
 		else
-			printf(get_shared_repository()
+			printf(repo_settings_get_shared_repository(the_repository)
 			       ? _("Initialized empty shared Git repository in %s%s\n")
 			       : _("Initialized empty Git repository in %s%s\n"),
 			       git_dir, len && git_dir[len-1] != '/' ? "/" : "");
diff --git a/shallow.c b/shallow.c
index 82a8da3..4bd9342 100644
--- a/shallow.c
+++ b/shallow.c
@@ -1,5 +1,4 @@
 #define USE_THE_REPOSITORY_VARIABLE
-#define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
 #include "hex.h"
@@ -134,7 +133,8 @@ static void free_depth_in_slab(int **ptr)
 struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
 		int shallow_flag, int not_shallow_flag)
 {
-	int i = 0, cur_depth = 0;
+	size_t i = 0;
+	int cur_depth = 0;
 	struct commit_list *result = NULL;
 	struct object_array stack = OBJECT_ARRAY_INIT;
 	struct commit *commit = NULL;
@@ -335,16 +335,16 @@ static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol,
 				   const struct oid_array *extra,
 				   unsigned flags)
 {
-	struct write_shallow_data data;
-	int i;
-	data.out = out;
-	data.use_pack_protocol = use_pack_protocol;
-	data.count = 0;
-	data.flags = flags;
+	struct write_shallow_data data = {
+		.out = out,
+		.use_pack_protocol = use_pack_protocol,
+		.flags = flags,
+	};
+
 	for_each_commit_graft(write_one_shallow, &data);
 	if (!extra)
 		return data.count;
-	for (i = 0; i < extra->nr; i++) {
+	for (size_t i = 0; i < extra->nr; i++) {
 		strbuf_addstr(out, oid_to_hex(extra->oid + i));
 		strbuf_addch(out, '\n');
 		data.count++;
@@ -364,7 +364,9 @@ const char *setup_temporary_shallow(const struct oid_array *extra)
 	struct strbuf sb = STRBUF_INIT;
 
 	if (write_shallow_commits(&sb, 0, extra)) {
-		temp = xmks_tempfile(git_path("shallow_XXXXXX"));
+		char *path = repo_git_path(the_repository, "shallow_XXXXXX");
+		temp = xmks_tempfile(path);
+		free(path);
 
 		if (write_in_full(temp->fd, sb.buf, sb.len) < 0 ||
 		    close_tempfile_gently(temp) < 0)
@@ -466,7 +468,6 @@ struct trace_key trace_shallow = TRACE_KEY_INIT(SHALLOW);
  */
 void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa)
 {
-	int i;
 	trace_printf_key(&trace_shallow, "shallow: prepare_shallow_info\n");
 	memset(info, 0, sizeof(*info));
 	info->shallow = sa;
@@ -474,7 +475,7 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa)
 		return;
 	ALLOC_ARRAY(info->ours, sa->nr);
 	ALLOC_ARRAY(info->theirs, sa->nr);
-	for (i = 0; i < sa->nr; i++) {
+	for (size_t i = 0; i < sa->nr; i++) {
 		if (repo_has_object_file(the_repository, sa->oid + i)) {
 			struct commit_graft *graft;
 			graft = lookup_commit_graft(the_repository,
@@ -507,7 +508,7 @@ void clear_shallow_info(struct shallow_info *info)
 void remove_nonexistent_theirs_shallow(struct shallow_info *info)
 {
 	struct object_id *oid = info->shallow->oid;
-	int i, dst;
+	size_t i, dst;
 	trace_printf_key(&trace_shallow, "shallow: remove_nonexistent_theirs_shallow\n");
 	for (i = dst = 0; i < info->nr_theirs; i++) {
 		if (i != dst)
@@ -535,7 +536,7 @@ static uint32_t *paint_alloc(struct paint_info *info)
 	unsigned nr = DIV_ROUND_UP(info->nr_bits, 32);
 	unsigned size = nr * sizeof(uint32_t);
 	void *p;
-	if (!info->pool_count || size > info->end - info->free) {
+	if (!info->pool_count || info->end < info->free + size) {
 		if (size > POOL_SIZE)
 			BUG("pool size too small for %d in paint_alloc()",
 			    size);
@@ -560,7 +561,7 @@ static void paint_down(struct paint_info *info, const struct object_id *oid,
 {
 	unsigned int i, nr;
 	struct commit_list *head = NULL;
-	int bitmap_nr = DIV_ROUND_UP(info->nr_bits, 32);
+	size_t bitmap_nr = DIV_ROUND_UP(info->nr_bits, 32);
 	size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr);
 	struct commit *c = lookup_commit_reference_gently(the_repository, oid,
 							  1);
@@ -660,7 +661,7 @@ void assign_shallow_commits_to_refs(struct shallow_info *info,
 	struct object_id *oid = info->shallow->oid;
 	struct oid_array *ref = info->ref;
 	unsigned int i, nr;
-	int *shallow, nr_shallow = 0;
+	size_t *shallow, nr_shallow = 0;
 	struct paint_info pi;
 
 	trace_printf_key(&trace_shallow, "shallow: assign_shallow_commits_to_refs\n");
@@ -735,7 +736,7 @@ void assign_shallow_commits_to_refs(struct shallow_info *info,
 
 struct commit_array {
 	struct commit **commits;
-	int nr, alloc;
+	size_t nr, alloc;
 };
 
 static int add_ref(const char *refname UNUSED,
@@ -753,12 +754,11 @@ static int add_ref(const char *refname UNUSED,
 	return 0;
 }
 
-static void update_refstatus(int *ref_status, int nr, uint32_t *bitmap)
+static void update_refstatus(int *ref_status, size_t nr, uint32_t *bitmap)
 {
-	unsigned int i;
 	if (!ref_status)
 		return;
-	for (i = 0; i < nr; i++)
+	for (size_t i = 0; i < nr; i++)
 		if (bitmap[i / 32] & (1U << (i % 32)))
 			ref_status[i]++;
 }
@@ -773,8 +773,8 @@ static void post_assign_shallow(struct shallow_info *info,
 	struct object_id *oid = info->shallow->oid;
 	struct commit *c;
 	uint32_t **bitmap;
-	int dst, i, j;
-	int bitmap_nr = DIV_ROUND_UP(info->ref->nr, 32);
+	size_t dst, i, j;
+	size_t bitmap_nr = DIV_ROUND_UP(info->ref->nr, 32);
 	struct commit_array ca;
 
 	trace_printf_key(&trace_shallow, "shallow: post_assign_shallow\n");
diff --git a/shallow.h b/shallow.h
index e9ca7e4..9bfeade 100644
--- a/shallow.h
+++ b/shallow.h
@@ -59,8 +59,8 @@ void prune_shallow(unsigned options);
  */
 struct shallow_info {
 	struct oid_array *shallow;
-	int *ours, nr_ours;
-	int *theirs, nr_theirs;
+	size_t *ours, nr_ours;
+	size_t *theirs, nr_theirs;
 	struct oid_array *ref;
 
 	/* for receive-pack */
@@ -69,7 +69,7 @@ struct shallow_info {
 	int *reachable;
 	int *shallow_ref;
 	struct commit **commits;
-	int nr_commits;
+	size_t nr_commits;
 };
 
 void prepare_shallow_info(struct shallow_info *, struct oid_array *);
diff --git a/simple-ipc.h b/simple-ipc.h
index 3916eaf..701e005 100644
--- a/simple-ipc.h
+++ b/simple-ipc.h
@@ -2,7 +2,7 @@
 #define GIT_SIMPLE_IPC_H
 
 /*
- * See Documentation/technical/api-simple-ipc.txt
+ * See Documentation/technical/api-simple-ipc.adoc
  */
 
 enum ipc_active_state {
diff --git a/submodule.c b/submodule.c
index b361076..0530e8c 100644
--- a/submodule.c
+++ b/submodule.c
@@ -536,7 +536,8 @@ static struct repository *open_submodule(const char *path)
 	struct strbuf sb = STRBUF_INIT;
 	struct repository *out = xmalloc(sizeof(*out));
 
-	if (submodule_to_gitdir(&sb, path) || repo_init(out, sb.buf, NULL)) {
+	if (submodule_to_gitdir(the_repository, &sb, path) ||
+	    repo_init(out, sb.buf, NULL)) {
 		strbuf_release(&sb);
 		free(out);
 		return NULL;
@@ -1315,7 +1316,7 @@ static int repo_has_absorbed_submodules(struct repository *r)
 	int ret;
 	struct strbuf buf = STRBUF_INIT;
 
-	strbuf_repo_git_path(&buf, r, "modules/");
+	repo_git_path_append(r, &buf, "modules/");
 	ret = file_exists(buf.buf) && !is_empty_dir(buf.buf);
 	strbuf_release(&buf);
 	return ret;
@@ -2572,7 +2573,8 @@ int get_superproject_working_tree(struct strbuf *buf)
  * Put the gitdir for a submodule (given relative to the main
  * repository worktree) into `buf`, or return -1 on error.
  */
-int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
+int submodule_to_gitdir(struct repository *repo,
+			struct strbuf *buf, const char *submodule)
 {
 	const struct submodule *sub;
 	const char *git_dir;
@@ -2592,14 +2594,13 @@ int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
 		strbuf_addstr(buf, git_dir);
 	}
 	if (!is_git_directory(buf->buf)) {
-		sub = submodule_from_path(the_repository, null_oid(),
-					  submodule);
+		sub = submodule_from_path(repo, null_oid(), submodule);
 		if (!sub) {
 			ret = -1;
 			goto cleanup;
 		}
 		strbuf_reset(buf);
-		submodule_name_to_gitdir(buf, the_repository, sub->name);
+		submodule_name_to_gitdir(buf, repo, sub->name);
 	}
 
 cleanup:
@@ -2629,6 +2630,6 @@ void submodule_name_to_gitdir(struct strbuf *buf, struct repository *r,
 	 * administrators can explicitly set. Nothing has been decided,
 	 * so for now, just append the name at the end of the path.
 	 */
-	strbuf_repo_git_path(buf, r, "modules/");
+	repo_git_path_append(r, buf, "modules/");
 	strbuf_addstr(buf, submodule_name);
 }
diff --git a/submodule.h b/submodule.h
index 4deb1b5..db980c1 100644
--- a/submodule.h
+++ b/submodule.h
@@ -136,7 +136,8 @@ int push_unpushed_submodules(struct repository *r,
  * path of that submodule in 'buf'. Return -1 on error or when the
  * submodule is not initialized.
  */
-int submodule_to_gitdir(struct strbuf *buf, const char *submodule);
+int submodule_to_gitdir(struct repository *repo,
+			struct strbuf *buf, const char *submodule);
 
 /*
  * Given a submodule name, create a path to where the submodule's gitdir lives
diff --git a/t/Makefile b/t/Makefile
index daa5fca..2994eb5 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -177,3 +177,18 @@
 
 .PHONY: pre-clean $(T) aggregate-results clean valgrind perf \
 	check-chainlint clean-chainlint test-chainlint $(UNIT_TESTS)
+
+.PHONY: libgit-sys-test libgit-rs-test
+libgit-sys-test:
+	$(QUIET)(\
+		cd ../contrib/libgit-sys && \
+		cargo test \
+	)
+libgit-rs-test:
+	$(QUIET)(\
+		cd ../contrib/libgit-rs && \
+		cargo test \
+	)
+ifdef INCLUDE_LIBGIT_RS
+all:: libgit-sys-test libgit-rs-test
+endif
diff --git a/t/README b/t/README
index e84824d..53e5b4a 100644
--- a/t/README
+++ b/t/README
@@ -471,6 +471,10 @@
 sure the expected tests are executed and not silently skipped when their
 dependency breaks or is simply not present in a new environment.
 
+GIT_TEST_NAME_HASH_VERSION=<int>, when set, causes 'git pack-objects' to
+assume '--name-hash-version=<n>'.
+
+
 Naming Tests
 ------------
 
diff --git a/t/aggregate-results.sh b/t/aggregate-results.sh
index 6e3bcc4..6cb0ff1 100755
--- a/t/aggregate-results.sh
+++ b/t/aggregate-results.sh
@@ -44,7 +44,7 @@
 		tr -s "," "\n" |
 		grep -v '^$' |
 		sort -u |
-		paste -s -d ' ')
+		paste -s -d ' ' -)
 	if test -n "$unique_missing_prereq"
 	then
 		printf "\nmissing prereq: $unique_missing_prereq\n\n"
diff --git a/t/helper/meson.build b/t/helper/meson.build
index 5e83884..d2cabaa 100644
--- a/t/helper/meson.build
+++ b/t/helper/meson.build
@@ -34,12 +34,14 @@
   'test-match-trees.c',
   'test-mergesort.c',
   'test-mktemp.c',
+  'test-name-hash.c',
   'test-online-cpus.c',
   'test-pack-mtimes.c',
   'test-parse-options.c',
   'test-parse-pathspec-file.c',
   'test-partial-clone.c',
   'test-path-utils.c',
+  'test-path-walk.c',
   'test-pcre2-config.c',
   'test-pkt-line.c',
   'test-proc-receive.c',
@@ -78,14 +80,14 @@
 
 test_tool = executable('test-tool',
   sources: test_tool_sources,
-  dependencies: [libgit, common_main],
+  dependencies: [libgit_commonmain],
 )
 bin_wrappers += test_tool
 test_dependencies += test_tool
 
 test_fake_ssh = executable('test-fake-ssh',
   sources: 'test-fake-ssh.c',
-  dependencies: [libgit, common_main],
+  dependencies: [libgit_commonmain],
 )
 bin_wrappers += test_fake_ssh
 test_dependencies += test_fake_ssh
diff --git a/t/helper/test-csprng.c b/t/helper/test-csprng.c
index a4a0aca..c86dcc4 100644
--- a/t/helper/test-csprng.c
+++ b/t/helper/test-csprng.c
@@ -15,7 +15,7 @@ int cmd__csprng(int argc, const char **argv)
 
 	while (count) {
 		unsigned long chunk = count < sizeof(buf) ? count : sizeof(buf);
-		if (csprng_bytes(buf, chunk) < 0) {
+		if (csprng_bytes(buf, chunk, 0) < 0) {
 			perror("failed to read");
 			return 5;
 		}
diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c
index 80df1aa..fbf67fe 100644
--- a/t/helper/test-hash-speed.c
+++ b/t/helper/test-hash-speed.c
@@ -3,16 +3,16 @@
 
 #define NUM_SECONDS 3
 
-static inline void compute_hash(const struct git_hash_algo *algo, git_hash_ctx *ctx, uint8_t *final, const void *p, size_t len)
+static inline void compute_hash(const struct git_hash_algo *algo, struct git_hash_ctx *ctx, uint8_t *final, const void *p, size_t len)
 {
 	algo->init_fn(ctx);
-	algo->update_fn(ctx, p, len);
-	algo->final_fn(final, ctx);
+	git_hash_update(ctx, p, len);
+	git_hash_final(final, ctx);
 }
 
 int cmd__hash_speed(int ac, const char **av)
 {
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 	unsigned char hash[GIT_MAX_RAWSZ];
 	clock_t initial, start, end;
 	unsigned bufsizes[] = { 64, 256, 1024, 8192, 16384 };
diff --git a/t/helper/test-hash.c b/t/helper/test-hash.c
index 45d829c..f0ee61c 100644
--- a/t/helper/test-hash.c
+++ b/t/helper/test-hash.c
@@ -1,14 +1,16 @@
 #include "test-tool.h"
 #include "hex.h"
 
-int cmd_hash_impl(int ac, const char **av, int algo)
+int cmd_hash_impl(int ac, const char **av, int algo, int unsafe)
 {
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 	unsigned char hash[GIT_MAX_HEXSZ];
 	unsigned bufsz = 8192;
 	int binary = 0;
 	char *buffer;
 	const struct git_hash_algo *algop = &hash_algos[algo];
+	if (unsafe)
+		algop = unsafe_hash_algo(algop);
 
 	if (ac == 2) {
 		if (!strcmp(av[1], "-b"))
@@ -46,9 +48,9 @@ int cmd_hash_impl(int ac, const char **av, int algo)
 		}
 		if (this_sz == 0)
 			break;
-		algop->update_fn(&ctx, buffer, this_sz);
+		git_hash_update(&ctx, buffer, this_sz);
 	}
-	algop->final_fn(hash, &ctx);
+	git_hash_final(hash, &ctx);
 
 	if (binary)
 		fwrite(hash, 1, algop->rawsz, stdout);
diff --git a/t/helper/test-name-hash.c b/t/helper/test-name-hash.c
new file mode 100644
index 0000000..af1d52d
--- /dev/null
+++ b/t/helper/test-name-hash.c
@@ -0,0 +1,23 @@
+/*
+ * test-name-hash.c: Read a list of paths over stdin and report on their
+ * name-hash and full name-hash.
+ */
+
+#include "test-tool.h"
+#include "git-compat-util.h"
+#include "pack-objects.h"
+#include "strbuf.h"
+
+int cmd__name_hash(int argc UNUSED, const char **argv UNUSED)
+{
+	struct strbuf line = STRBUF_INIT;
+
+	while (!strbuf_getline(&line, stdin)) {
+		printf("%10u ", pack_name_hash(line.buf));
+		printf("%10u ", pack_name_hash_v2((unsigned const char *)line.buf));
+		printf("%s\n", line.buf);
+	}
+
+	strbuf_release(&line);
+	return 0;
+}
diff --git a/t/helper/test-path-walk.c b/t/helper/test-path-walk.c
new file mode 100644
index 0000000..61e845e
--- /dev/null
+++ b/t/helper/test-path-walk.c
@@ -0,0 +1,132 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "test-tool.h"
+#include "dir.h"
+#include "environment.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object.h"
+#include "pretty.h"
+#include "revision.h"
+#include "setup.h"
+#include "parse-options.h"
+#include "strbuf.h"
+#include "path-walk.h"
+#include "oid-array.h"
+
+static const char * const path_walk_usage[] = {
+	N_("test-tool path-walk <options> -- <revision-options>"),
+	NULL
+};
+
+struct path_walk_test_data {
+	uintmax_t batch_nr;
+
+	uintmax_t commit_nr;
+	uintmax_t tree_nr;
+	uintmax_t blob_nr;
+	uintmax_t tag_nr;
+};
+
+static int emit_block(const char *path, struct oid_array *oids,
+		      enum object_type type, void *data)
+{
+	struct path_walk_test_data *tdata = data;
+	const char *typestr;
+
+	if (type == OBJ_TREE)
+		tdata->tree_nr += oids->nr;
+	else if (type == OBJ_BLOB)
+		tdata->blob_nr += oids->nr;
+	else if (type == OBJ_COMMIT)
+		tdata->commit_nr += oids->nr;
+	else if (type == OBJ_TAG)
+		tdata->tag_nr += oids->nr;
+	else
+		BUG("we do not understand this type");
+
+	typestr = type_name(type);
+
+	/* This should never be output during tests. */
+	if (!oids->nr)
+		printf("%"PRIuMAX":%s:%s:EMPTY\n",
+		       tdata->batch_nr, typestr, path);
+
+	for (size_t i = 0; i < oids->nr; i++) {
+		struct object *o = lookup_unknown_object(the_repository,
+							 &oids->oid[i]);
+		printf("%"PRIuMAX":%s:%s:%s%s\n",
+		       tdata->batch_nr, typestr, path,
+		       oid_to_hex(&oids->oid[i]),
+		       o->flags & UNINTERESTING ? ":UNINTERESTING" : "");
+	}
+
+	tdata->batch_nr++;
+	return 0;
+}
+
+int cmd__path_walk(int argc, const char **argv)
+{
+	int res, stdin_pl = 0;
+	struct rev_info revs = REV_INFO_INIT;
+	struct path_walk_info info = PATH_WALK_INFO_INIT;
+	struct path_walk_test_data data = { 0 };
+	struct option options[] = {
+		OPT_BOOL(0, "blobs", &info.blobs,
+			 N_("toggle inclusion of blob objects")),
+		OPT_BOOL(0, "commits", &info.commits,
+			 N_("toggle inclusion of commit objects")),
+		OPT_BOOL(0, "tags", &info.tags,
+			 N_("toggle inclusion of tag objects")),
+		OPT_BOOL(0, "trees", &info.trees,
+			 N_("toggle inclusion of tree objects")),
+		OPT_BOOL(0, "prune", &info.prune_all_uninteresting,
+			 N_("toggle pruning of uninteresting paths")),
+		OPT_BOOL(0, "stdin-pl", &stdin_pl,
+			 N_("read a pattern list over stdin")),
+		OPT_END(),
+	};
+
+	setup_git_directory();
+	revs.repo = the_repository;
+
+	argc = parse_options(argc, argv, NULL,
+			     options, path_walk_usage,
+			     PARSE_OPT_KEEP_UNKNOWN_OPT | PARSE_OPT_KEEP_ARGV0);
+
+	if (argc > 1)
+		setup_revisions(argc, argv, &revs, NULL);
+	else
+		usage(path_walk_usage[0]);
+
+	info.revs = &revs;
+	info.path_fn = emit_block;
+	info.path_fn_data = &data;
+
+	if (stdin_pl) {
+		struct strbuf in = STRBUF_INIT;
+		CALLOC_ARRAY(info.pl, 1);
+
+		info.pl->use_cone_patterns = 1;
+
+		strbuf_fread(&in, 2048, stdin);
+		add_patterns_from_buffer(in.buf, in.len, "", 0, info.pl);
+		strbuf_release(&in);
+	}
+
+	res = walk_objects_by_path(&info);
+
+	printf("commits:%" PRIuMAX "\n"
+	       "trees:%" PRIuMAX "\n"
+	       "blobs:%" PRIuMAX "\n"
+	       "tags:%" PRIuMAX "\n",
+	       data.commit_nr, data.tree_nr, data.blob_nr, data.tag_nr);
+
+	if (info.pl) {
+		clear_pattern_list(info.pl);
+		free(info.pl);
+	}
+
+	release_revisions(&revs);
+	return res;
+}
diff --git a/t/helper/test-progress.c b/t/helper/test-progress.c
index 44be264..1f75b7b 100644
--- a/t/helper/test-progress.c
+++ b/t/helper/test-progress.c
@@ -17,10 +17,14 @@
  *
  * See 't0500-progress-display.sh' for examples.
  */
+
+#define USE_THE_REPOSITORY_VARIABLE
 #define GIT_TEST_PROGRESS_ONLY
+
 #include "test-tool.h"
 #include "parse-options.h"
 #include "progress.h"
+#include "repository.h"
 #include "strbuf.h"
 #include "string-list.h"
 
@@ -64,7 +68,7 @@ int cmd__progress(int argc, const char **argv)
 			else
 				die("invalid input: '%s'", line.buf);
 
-			progress = start_progress(title, total);
+			progress = start_progress(the_repository, title, total);
 		} else if (skip_prefix(line.buf, "progress ", (const char **) &end)) {
 			uint64_t item_count = strtoull(end, &end, 10);
 			if (*end != '\0')
diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c
index 01cf77a..028ec00 100644
--- a/t/helper/test-reach.c
+++ b/t/helper/test-reach.c
@@ -35,7 +35,7 @@ int cmd__reach(int ac, const char **av)
 	struct commit_list *X, *Y;
 	struct object_array X_obj = OBJECT_ARRAY_INIT;
 	struct commit **X_array, **Y_array;
-	int X_nr, X_alloc, Y_nr, Y_alloc;
+	size_t X_nr, X_alloc, Y_nr, Y_alloc;
 	struct strbuf buf = STRBUF_INIT;
 	struct repository *r = the_repository;
 
@@ -157,7 +157,7 @@ int cmd__reach(int ac, const char **av)
 		clear_contains_cache(&cache);
 	} else if (!strcmp(av[1], "get_reachable_subset")) {
 		const int reachable_flag = 1;
-		int i, count = 0;
+		int count = 0;
 		struct commit_list *current;
 		struct commit_list *list = get_reachable_subset(X_array, X_nr,
 								Y_array, Y_nr,
@@ -169,7 +169,7 @@ int cmd__reach(int ac, const char **av)
 				    oid_to_hex(&list->item->object.oid));
 			count++;
 		}
-		for (i = 0; i < Y_nr; i++) {
+		for (size_t i = 0; i < Y_nr; i++) {
 			if (Y_array[i]->object.flags & reachable_flag)
 				count--;
 		}
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 1cc05f0..e00fce5 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -75,11 +75,10 @@ static const char **get_store(const char **argv, struct ref_store **refs)
 		*refs = get_main_ref_store(the_repository);
 	} else if (skip_prefix(argv[0], "submodule:", &gitdir)) {
 		struct strbuf sb = STRBUF_INIT;
-		int ret;
 
-		ret = strbuf_git_path_submodule(&sb, gitdir, "objects/");
-		if (ret)
-			die("strbuf_git_path_submodule failed: %d", ret);
+		if (!repo_submodule_path_append(the_repository,
+						&sb, gitdir, "objects/"))
+			die("computing submodule path failed");
 		add_to_alternates_memory(sb.buf);
 		strbuf_release(&sb);
 
diff --git a/t/helper/test-rot13-filter.c b/t/helper/test-rot13-filter.c
index ff407b5..722b1cb 100644
--- a/t/helper/test-rot13-filter.c
+++ b/t/helper/test-rot13-filter.c
@@ -1,6 +1,6 @@
 /*
  * Example implementation for the Git filter protocol version 2
- * See Documentation/gitattributes.txt, section "Filter Protocol"
+ * See Documentation/gitattributes.adoc, section "Filter Protocol"
  *
  * Usage: test-tool rot13-filter [--always-delay] --log=<path> <capabilities>
  *
diff --git a/t/helper/test-serve-v2.c b/t/helper/test-serve-v2.c
index 054cbcf..63a200b 100644
--- a/t/helper/test-serve-v2.c
+++ b/t/helper/test-serve-v2.c
@@ -1,6 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "test-tool.h"
 #include "gettext.h"
 #include "parse-options.h"
+#include "repository.h"
 #include "serve.h"
 #include "setup.h"
 
@@ -28,9 +31,9 @@ int cmd__serve_v2(int argc, const char **argv)
 			     PARSE_OPT_KEEP_UNKNOWN_OPT);
 
 	if (advertise_capabilities)
-		protocol_v2_advertise_capabilities();
+		protocol_v2_advertise_capabilities(the_repository);
 	else
-		protocol_v2_serve_loop(stateless_rpc);
+		protocol_v2_serve_loop(the_repository, stateless_rpc);
 
 	return 0;
 }
diff --git a/t/helper/test-sha1.c b/t/helper/test-sha1.c
index e60d000..349540c 100644
--- a/t/helper/test-sha1.c
+++ b/t/helper/test-sha1.c
@@ -3,7 +3,7 @@
 
 int cmd__sha1(int ac, const char **av)
 {
-	return cmd_hash_impl(ac, av, GIT_HASH_SHA1);
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA1, 0);
 }
 
 int cmd__sha1_is_sha1dc(int argc UNUSED, const char **argv UNUSED)
@@ -13,3 +13,8 @@ int cmd__sha1_is_sha1dc(int argc UNUSED, const char **argv UNUSED)
 #endif
 	return 1;
 }
+
+int cmd__sha1_unsafe(int ac, const char **av)
+{
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA1, 1);
+}
diff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh
index 8459488..bf387d3 100755
--- a/t/helper/test-sha1.sh
+++ b/t/helper/test-sha1.sh
@@ -3,25 +3,31 @@
 dd if=/dev/zero bs=1048576 count=100 2>/dev/null |
 /usr/bin/time t/helper/test-tool sha1 >/dev/null
 
+dd if=/dev/zero bs=1048576 count=100 2>/dev/null |
+/usr/bin/time t/helper/test-tool sha1-unsafe >/dev/null
+
 while read expect cnt pfx
 do
 	case "$expect" in '#'*) continue ;; esac
-	actual=$(
-		{
-			test -z "$pfx" || echo "$pfx"
-			dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
-			perl -pe 'y/\000/g/'
-		} | ./t/helper/test-tool sha1 $cnt
-	)
-	if test "$expect" = "$actual"
-	then
-		echo "OK: $expect $cnt $pfx"
-	else
-		echo >&2 "OOPS: $cnt"
-		echo >&2 "expect: $expect"
-		echo >&2 "actual: $actual"
-		exit 1
-	fi
+	for sha1 in sha1 sha1-unsafe
+	do
+		actual=$(
+			{
+				test -z "$pfx" || echo "$pfx"
+				dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
+				perl -pe 'y/\000/g/'
+			} | ./t/helper/test-tool $sha1 $cnt
+		)
+		if test "$expect" = "$actual"
+		then
+			echo "OK ($sha1): $expect $cnt $pfx"
+		else
+			echo >&2 "OOPS ($sha1): $cnt"
+			echo >&2 "expect ($sha1): $expect"
+			echo >&2 "actual ($sha1): $actual"
+			exit 1
+		fi
+	done
 done <<EOF
 da39a3ee5e6b4b0d3255bfef95601890afd80709 0
 3f786850e387550fdab836ed7e6dc881de23001b 0 a
diff --git a/t/helper/test-sha256.c b/t/helper/test-sha256.c
index 2fb2043..7fd0aa1 100644
--- a/t/helper/test-sha256.c
+++ b/t/helper/test-sha256.c
@@ -3,5 +3,5 @@
 
 int cmd__sha256(int ac, const char **av)
 {
-	return cmd_hash_impl(ac, av, GIT_HASH_SHA256);
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA256, 0);
 }
diff --git a/t/helper/test-simple-ipc.c b/t/helper/test-simple-ipc.c
index fb59277..03cc5ee 100644
--- a/t/helper/test-simple-ipc.c
+++ b/t/helper/test-simple-ipc.c
@@ -612,8 +612,8 @@ int cmd__simple_ipc(int argc, const char **argv)
 	if (argc < 2)
 		usage_with_options(simple_ipc_usage, options);
 
-	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(simple_ipc_usage, options);
+	show_usage_with_options_if_asked(argc, argv,
+					 simple_ipc_usage, options);
 
 	if (argc == 2 && !strcmp(argv[1], "SUPPORTS_SIMPLE_IPC"))
 		return 0;
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 4a7aa99..50dc4da 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -44,6 +44,7 @@ static struct test_cmd cmds[] = {
 	{ "match-trees", cmd__match_trees },
 	{ "mergesort", cmd__mergesort },
 	{ "mktemp", cmd__mktemp },
+	{ "name-hash", cmd__name_hash },
 	{ "online-cpus", cmd__online_cpus },
 	{ "pack-mtimes", cmd__pack_mtimes },
 	{ "parse-options", cmd__parse_options },
@@ -52,6 +53,7 @@ static struct test_cmd cmds[] = {
 	{ "parse-subcommand", cmd__parse_subcommand },
 	{ "partial-clone", cmd__partial_clone },
 	{ "path-utils", cmd__path_utils },
+	{ "path-walk", cmd__path_walk },
 	{ "pcre2-config", cmd__pcre2_config },
 	{ "pkt-line", cmd__pkt_line },
 	{ "proc-receive", cmd__proc_receive },
@@ -70,6 +72,7 @@ static struct test_cmd cmds[] = {
 	{ "serve-v2", cmd__serve_v2 },
 	{ "sha1", cmd__sha1 },
 	{ "sha1-is-sha1dc", cmd__sha1_is_sha1dc },
+	{ "sha1-unsafe", cmd__sha1_unsafe },
 	{ "sha256", cmd__sha256 },
 	{ "sigchain", cmd__sigchain },
 	{ "simple-ipc", cmd__simple_ipc },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 21802ac..6d62a5b 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -37,6 +37,7 @@ int cmd__lazy_init_name_hash(int argc, const char **argv);
 int cmd__match_trees(int argc, const char **argv);
 int cmd__mergesort(int argc, const char **argv);
 int cmd__mktemp(int argc, const char **argv);
+int cmd__name_hash(int argc, const char **argv);
 int cmd__online_cpus(int argc, const char **argv);
 int cmd__pack_mtimes(int argc, const char **argv);
 int cmd__parse_options(int argc, const char **argv);
@@ -45,6 +46,7 @@ int cmd__parse_pathspec_file(int argc, const char** argv);
 int cmd__parse_subcommand(int argc, const char **argv);
 int cmd__partial_clone(int argc, const char **argv);
 int cmd__path_utils(int argc, const char **argv);
+int cmd__path_walk(int argc, const char **argv);
 int cmd__pcre2_config(int argc, const char **argv);
 int cmd__pkt_line(int argc, const char **argv);
 int cmd__proc_receive(int argc, const char **argv);
@@ -63,6 +65,7 @@ int cmd__scrap_cache_tree(int argc, const char **argv);
 int cmd__serve_v2(int argc, const char **argv);
 int cmd__sha1(int argc, const char **argv);
 int cmd__sha1_is_sha1dc(int argc, const char **argv);
+int cmd__sha1_unsafe(int argc, const char **argv);
 int cmd__sha256(int argc, const char **argv);
 int cmd__sigchain(int argc, const char **argv);
 int cmd__simple_ipc(int argc, const char **argv);
@@ -81,6 +84,6 @@ int cmd__windows_named_pipe(int argc, const char **argv);
 #endif
 int cmd__write_cache(int argc, const char **argv);
 
-int cmd_hash_impl(int ac, const char **av, int algo);
+int cmd_hash_impl(int ac, const char **av, int algo, int unsafe);
 
 #endif
diff --git a/t/interop/Makefile b/t/interop/Makefile
index 6911c29..4ff4ed0 100644
--- a/t/interop/Makefile
+++ b/t/interop/Makefile
@@ -1,3 +1,6 @@
+# The default target of this Makefile is...
+all::
+
 # Import tree-wide shared Makefile behavior and libraries
 include ../../shared.mak
 
@@ -8,7 +11,7 @@
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
 T = $(sort $(wildcard i[0-9][0-9][0-9][0-9]-*.sh))
 
-all: $(T)
+all:: $(T)
 
 $(T):
 	@echo "*** $@ ***"; '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 58b9c74..cc6bf9a 100644
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -566,6 +566,21 @@
 		EOF
 	'
 
+	test_expect_success "helper ($HELPER) gets authtype and credential only if request has authtype capability" '
+		check fill $HELPER <<-\EOF
+		protocol=https
+		host=git.example.com
+		--
+		protocol=https
+		host=git.example.com
+		username=askpass-username
+		password=askpass-password
+		--
+		askpass: Username for '\''https://git.example.com'\'':
+		askpass: Password for '\''https://askpass-username@git.example.com'\'':
+		EOF
+	'
+
 	test_expect_success "helper ($HELPER) stores authtype and credential with username" '
 		check approve $HELPER <<-\EOF
 		capability[]=authtype
diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh
index 7a734c6..b3dd68b 100644
--- a/t/lib-gettext.sh
+++ b/t/lib-gettext.sh
@@ -7,7 +7,7 @@
 . ./test-lib.sh
 
 GIT_TEXTDOMAINDIR="$GIT_TEST_TEXTDOMAINDIR"
-GIT_PO_PATH="$GIT_TEST_POPATH"
+GIT_PO_PATH="$GIT_SOURCE_DIR/po"
 export GIT_TEXTDOMAINDIR GIT_PO_PATH
 
 if test -n "$GIT_TEST_INSTALLED"
diff --git a/t/meson.build b/t/meson.build
index 602ebfe..a59da26 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -1,11 +1,23 @@
 clar_test_suites = [
   'unit-tests/u-ctype.c',
+  'unit-tests/u-example-decorate.c',
+  'unit-tests/u-hash.c',
+  'unit-tests/u-hashmap.c',
+  'unit-tests/u-mem-pool.c',
+  'unit-tests/u-oid-array.c',
+  'unit-tests/u-oidmap.c',
+  'unit-tests/u-oidtree.c',
+  'unit-tests/u-prio-queue.c',
+  'unit-tests/u-reftable-tree.c',
+  'unit-tests/u-strbuf.c',
+  'unit-tests/u-strcmp-offset.c',
   'unit-tests/u-strvec.c',
 ]
 
 clar_sources = [
   'unit-tests/clar/clar.c',
   'unit-tests/unit-test.c',
+  'unit-tests/lib-oid.c'
 ]
 
 clar_decls_h = custom_target(
@@ -35,19 +47,11 @@
 
 clar_unit_tests = executable('unit-tests',
   sources: clar_sources + clar_test_suites,
-  dependencies: [libgit, common_main],
+  dependencies: [libgit_commonmain],
 )
 test('unit-tests', clar_unit_tests)
 
 unit_test_programs = [
-  'unit-tests/t-example-decorate.c',
-  'unit-tests/t-hash.c',
-  'unit-tests/t-hashmap.c',
-  'unit-tests/t-mem-pool.c',
-  'unit-tests/t-oid-array.c',
-  'unit-tests/t-oidmap.c',
-  'unit-tests/t-oidtree.c',
-  'unit-tests/t-prio-queue.c',
   'unit-tests/t-reftable-basics.c',
   'unit-tests/t-reftable-block.c',
   'unit-tests/t-reftable-merged.c',
@@ -56,9 +60,6 @@
   'unit-tests/t-reftable-readwrite.c',
   'unit-tests/t-reftable-record.c',
   'unit-tests/t-reftable-stack.c',
-  'unit-tests/t-reftable-tree.c',
-  'unit-tests/t-strbuf.c',
-  'unit-tests/t-strcmp-offset.c',
   'unit-tests/t-trailer.c',
   'unit-tests/t-urlmatch-normalization.c',
 ]
@@ -68,11 +69,10 @@
   unit_test = executable(unit_test_name,
     sources: [
       'unit-tests/test-lib.c',
-      'unit-tests/lib-oid.c',
       'unit-tests/lib-reftable.c',
       unit_test_program,
     ],
-    dependencies: [libgit, common_main],
+    dependencies: [libgit_commonmain],
   )
   test(unit_test_name, unit_test,
     workdir: meson.current_source_dir(),
@@ -721,12 +721,15 @@
   't5617-clone-submodules-remote.sh',
   't5618-alternate-refs.sh',
   't5619-clone-local-ambiguous-transport.sh',
+  't5620-backfill.sh',
+  't5621-clone-revision.sh',
   't5700-protocol-v1.sh',
   't5701-git-serve.sh',
   't5702-protocol-v2.sh',
   't5703-upload-pack-ref-in-want.sh',
   't5704-protocol-violations.sh',
   't5705-session-id-in-capabilities.sh',
+  't5710-promisor-remote-capability.sh',
   't5730-protocol-v2-bundle-uri-file.sh',
   't5731-protocol-v2-bundle-uri-git.sh',
   't5732-protocol-v2-bundle-uri-http.sh',
@@ -829,6 +832,7 @@
   't6500-gc.sh',
   't6501-freshen-objects.sh',
   't6600-test-reach.sh',
+  't6601-path-walk.sh',
   't6700-tree-depth.sh',
   't7001-mv.sh',
   't7002-mv-sparse-checkout.sh',
diff --git a/t/perf/Makefile b/t/perf/Makefile
index e4808ae..9b3090c 100644
--- a/t/perf/Makefile
+++ b/t/perf/Makefile
@@ -1,10 +1,13 @@
+# The default target of this Makefile is...
+all::
+
 # Import tree-wide shared Makefile behavior and libraries
 include ../../shared.mak
 
 -include ../../config.mak
 export GIT_TEST_OPTIONS
 
-all: test-lint perf
+all:: test-lint perf
 
 perf: pre-clean
 	./run
diff --git a/t/perf/p5313-pack-objects.sh b/t/perf/p5313-pack-objects.sh
new file mode 100755
index 0000000..be5229a
--- /dev/null
+++ b/t/perf/p5313-pack-objects.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+test_description='Tests pack performance using bitmaps'
+. ./perf-lib.sh
+
+GIT_TEST_PASSING_SANITIZE_LEAK=0
+export GIT_TEST_PASSING_SANITIZE_LEAK
+
+test_perf_large_repo
+
+test_expect_success 'create rev input' '
+	cat >in-thin <<-EOF &&
+	$(git rev-parse HEAD)
+	^$(git rev-parse HEAD~1)
+	EOF
+
+	cat >in-big <<-EOF &&
+	$(git rev-parse HEAD)
+	^$(git rev-parse HEAD~1000)
+	EOF
+
+	cat >in-shallow <<-EOF
+	$(git rev-parse HEAD)
+	--shallow $(git rev-parse HEAD)
+	EOF
+'
+
+for version in 1 2
+do
+	export version
+
+	test_perf "thin pack with version $version" '
+		git pack-objects --thin --stdout --revs --sparse \
+			--name-hash-version=$version <in-thin >out
+	'
+
+	test_size "thin pack size with version $version" '
+		test_file_size out
+	'
+
+	test_perf "big pack with version $version" '
+		git pack-objects --stdout --revs --sparse \
+			--name-hash-version=$version <in-big >out
+	'
+
+	test_size "big pack size with version $version" '
+		test_file_size out
+	'
+
+	test_perf "shallow fetch pack with version $version" '
+		git pack-objects --stdout --revs --sparse --shallow \
+			--name-hash-version=$version <in-shallow >out
+	'
+
+	test_size "shallow pack size with version $version" '
+		test_file_size out
+	'
+
+	test_perf "repack with version $version" '
+		git repack -adf --name-hash-version=$version
+	'
+
+	test_size "repack size with version $version" '
+		gitdir=$(git rev-parse --git-dir) &&
+		pack=$(ls $gitdir/objects/pack/pack-*.pack) &&
+		test_file_size "$pack"
+	'
+done
+
+test_done
diff --git a/t/perf/p5314-name-hash.sh b/t/perf/p5314-name-hash.sh
new file mode 100755
index 0000000..4ef0ba7
--- /dev/null
+++ b/t/perf/p5314-name-hash.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+test_description='Tests pack performance using bitmaps'
+. ./perf-lib.sh
+
+GIT_TEST_PASSING_SANITIZE_LEAK=0
+export GIT_TEST_PASSING_SANITIZE_LEAK
+
+test_perf_large_repo
+
+test_size 'paths at head' '
+	git ls-tree -r --name-only HEAD >path-list &&
+	wc -l <path-list &&
+	test-tool name-hash <path-list >name-hashes
+'
+
+for version in 1 2
+do
+	test_size "distinct hash value: v$version" '
+		awk "{ print \$$version; }" <name-hashes | sort | \
+			uniq -c >name-hash-count &&
+		wc -l <name-hash-count
+	'
+
+	test_size "maximum multiplicity: v$version" '
+		sort -nr <name-hash-count | head -n 1 |	\
+			awk "{ print \$1; }"
+	'
+done
+
+test_done
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 72a0c2e..c49d9e0 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -586,6 +586,18 @@
 	echo sha256 >expected
 '
 
+for hash in sha1 sha256
+do
+	test_expect_success "reinit repository with GIT_DEFAULT_HASH=$hash does not change format" '
+		test_when_finished "rm -rf repo" &&
+		git init repo &&
+		git -C repo rev-parse --show-object-format >expect &&
+		GIT_DEFAULT_HASH=$hash git init repo &&
+		git -C repo rev-parse --show-object-format >actual &&
+		test_cmp expect actual
+	'
+done
+
 test_expect_success 'extensions.objectFormat is not allowed with repo version 0' '
 	test_when_finished "rm -rf explicit-v0" &&
 	git init --object-format=sha256 explicit-v0 &&
@@ -697,6 +709,15 @@
 		git -C refformat rev-parse --show-ref-format >actual &&
 		test_cmp expect actual
 	'
+
+	test_expect_success "reinit repository with GIT_DEFAULT_REF_FORMAT=$format does not change format" '
+		test_when_finished "rm -rf refformat" &&
+		git init refformat &&
+		git -C refformat rev-parse --show-ref-format >expect &&
+		GIT_DEFAULT_REF_FORMAT=$format git init refformat &&
+		git -C refformat rev-parse --show-ref-format >actual &&
+		test_cmp expect actual
+	'
 done
 
 test_expect_success "--ref-format= overrides GIT_DEFAULT_REF_FORMAT" '
@@ -861,15 +882,6 @@
 	test_cmp expect actual
 '
 
-test_expect_success 're-init with includeIf.onbranch condition' '
-	test_when_finished "rm -rf repo" &&
-	git init repo &&
-	git -c includeIf.onbranch:nonexistent.path=/does/not/exist init repo &&
-	echo $GIT_DEFAULT_REF_FORMAT >expect &&
-	git -C repo rev-parse --show-ref-format >actual &&
-	test_cmp expect actual
-'
-
 test_expect_success 're-init skips non-matching includeIf.onbranch' '
 	test_when_finished "rm -rf repo config" &&
 	cat >config <<-EOF &&
diff --git a/t/t0012-help.sh b/t/t0012-help.sh
index 1d273d9..d3a0967 100755
--- a/t/t0012-help.sh
+++ b/t/t0012-help.sh
@@ -255,8 +255,9 @@
 		(
 			GIT_CEILING_DIRECTORIES=$(pwd) &&
 			export GIT_CEILING_DIRECTORIES &&
-			test_expect_code 129 git -C sub $builtin -h >output 2>&1
+			test_expect_code 129 git -C sub $builtin -h >output 2>err
 		) &&
+		test_must_be_empty err &&
 		test_grep usage output
 	'
 done <builtins
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index dbb2e73..8545cdf 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -592,17 +592,19 @@
 	./git rev-parse
 '
 
+test_expect_success !VALGRIND,RUNTIME_PREFIX,CAN_EXEC_IN_PWD 'setup runtime prefix' '
+	mkdir -p pretend/bin &&
+	cp "$GIT_EXEC_PATH"/git$X pretend/bin/
+'
+
 test_expect_success !VALGRIND,RUNTIME_PREFIX,CAN_EXEC_IN_PWD 'RUNTIME_PREFIX works' '
-	mkdir -p pretend/bin pretend/libexec/git-core &&
+	mkdir -p pretend/libexec/git-core &&
 	echo "echo HERE" | write_script pretend/libexec/git-core/git-here &&
-	cp "$GIT_EXEC_PATH"/git$X pretend/bin/ &&
 	GIT_EXEC_PATH= ./pretend/bin/git here >actual &&
 	echo HERE >expect &&
 	test_cmp expect actual'
 
 test_expect_success !VALGRIND,RUNTIME_PREFIX,CAN_EXEC_IN_PWD '%(prefix)/ works' '
-	mkdir -p pretend/bin &&
-	cp "$GIT_EXEC_PATH"/git$X pretend/bin/ &&
 	git config yes.path "%(prefix)/yes" &&
 	GIT_EXEC_PATH= ./pretend/bin/git config --path yes.path >actual &&
 	echo "$(pwd)/pretend/yes" >expect &&
diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh
index e11d819..e38ca7a 100755
--- a/t/t0091-bugreport.sh
+++ b/t/t0091-bugreport.sh
@@ -47,7 +47,8 @@
 	# This is bound to differ from environment to environment,
 	# so we just do some rather high-level checks.
 	grep "uname: ." system &&
-	grep "compiler info: ." system
+	grep "compiler info: ." system &&
+	grep "zlib." system
 '
 
 test_expect_success 'dies if file with same name as report already exists' '
diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index eff9a59..4287ed3 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -243,6 +243,15 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'a valueless true configuration variable is handled' '
+	test_when_finished "rm -f trace2.normal actual expect" &&
+	echo >expect &&
+	GIT_TRACE2="$(pwd)/trace2.normal" \
+	GIT_TRACE2_CONFIG_PARAMS=foo.true \
+	git -c foo.true config foo.true >actual &&
+	test_cmp expect actual
+'
+
 sane_unset GIT_TRACE2_BRIEF
 
 # Now test without environment variables and get all Trace2 settings
diff --git a/t/t0450-txt-doc-vs-help.sh b/t/t0450-txt-doc-vs-help.sh
index 853101b..2f7504a 100755
--- a/t/t0450-txt-doc-vs-help.sh
+++ b/t/t0450-txt-doc-vs-help.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='assert (unbuilt) Documentation/*.txt and -h output
+test_description='assert (unbuilt) Documentation/*.adoc and -h output
 
 Run this with --debug to see a summary of where we still fail to make
 the two versions consistent with one another.'
@@ -11,11 +11,11 @@
 	git --list-cmds=builtins >builtins
 '
 
-test_expect_success 'list of txt and help mismatches is sorted' '
-	sort -u "$TEST_DIRECTORY"/t0450/txt-help-mismatches >expect &&
-	if ! test_cmp expect "$TEST_DIRECTORY"/t0450/txt-help-mismatches
+test_expect_success 'list of adoc and help mismatches is sorted' '
+	sort -u "$TEST_DIRECTORY"/t0450/adoc-help-mismatches >expect &&
+	if ! test_cmp expect "$TEST_DIRECTORY"/t0450/adoc-help-mismatches
 	then
-		BUG "please keep the list of txt and help mismatches sorted"
+		BUG "please keep the list of adoc and help mismatches sorted"
 	fi
 '
 
@@ -40,20 +40,20 @@
 	echo "$out"
 }
 
-builtin_to_txt () {
-       echo "$GIT_BUILD_DIR/Documentation/git-$1.txt"
+builtin_to_adoc () {
+       echo "$GIT_BUILD_DIR/Documentation/git-$1.adoc"
 }
 
-txt_to_synopsis () {
+adoc_to_synopsis () {
 	builtin="$1" &&
 	out_dir="out/$builtin" &&
-	out="$out_dir/txt.synopsis" &&
+	out="$out_dir/adoc.synopsis" &&
 	if test -f "$out"
 	then
 		echo "$out" &&
 		return 0
 	fi &&
-	b2t="$(builtin_to_txt "$builtin")" &&
+	b2t="$(builtin_to_adoc "$builtin")" &&
 	sed -n \
 		-E '/^\[(verse|synopsis)\]$/,/^$/ {
 			/^$/d;
@@ -109,29 +109,29 @@
 		fi
 	'
 
-	txt="$(builtin_to_txt "$builtin")" &&
-	preq="$(echo BUILTIN_TXT_$builtin | tr '[:lower:]-' '[:upper:]_')" &&
+	adoc="$(builtin_to_adoc "$builtin")" &&
+	preq="$(echo BUILTIN_ADOC_$builtin | tr '[:lower:]-' '[:upper:]_')" &&
 
-	if test -f "$txt"
+	if test -f "$adoc"
 	then
 		test_set_prereq "$preq"
 	fi &&
 
-	# *.txt output assertions
-	test_expect_success "$preq" "$builtin *.txt SYNOPSIS has dashed labels" '
-		check_dashed_labels "$(txt_to_synopsis "$builtin")"
+	# *.adoc output assertions
+	test_expect_success "$preq" "$builtin *.adoc SYNOPSIS has dashed labels" '
+		check_dashed_labels "$(adoc_to_synopsis "$builtin")"
 	'
 
-	# *.txt output consistency assertions
+	# *.adoc output consistency assertions
 	result=
-	if grep -q "^$builtin$" "$TEST_DIRECTORY"/t0450/txt-help-mismatches
+	if grep -q "^$builtin$" "$TEST_DIRECTORY"/t0450/adoc-help-mismatches
 	then
 		result=failure
 	else
 		result=success
 	fi &&
 	test_expect_$result "$preq" "$builtin -h output and SYNOPSIS agree" '
-		t2s="$(txt_to_synopsis "$builtin")" &&
+		t2s="$(adoc_to_synopsis "$builtin")" &&
 		if test "$builtin" = "merge-tree"
 		then
 			test_when_finished "rm -f t2s.new" &&
@@ -140,17 +140,17 @@
 		fi &&
 		h2s="$(help_to_synopsis "$builtin")" &&
 
-		# The *.txt and -h use different spacing for the
+		# The *.adoc and -h use different spacing for the
 		# alignment of continued usage output, normalize it.
-		align_after_nl "$builtin" <"$t2s" >txt &&
+		align_after_nl "$builtin" <"$t2s" >adoc &&
 		align_after_nl "$builtin" <"$h2s" >help &&
-		test_cmp txt help
+		test_cmp adoc help
 	'
 
-	if test_have_prereq "$preq" && test -e txt && test -e help
+	if test_have_prereq "$preq" && test -e adoc && test -e help
 	then
 		test_debug '
-			if test_cmp txt help >cmp 2>/dev/null
+			if test_cmp adoc help >cmp 2>/dev/null
 			then
 				echo "=== DONE: $builtin ==="
 			else
@@ -161,7 +161,7 @@
 
 		# Not in test_expect_success in case --run is being
 		# used with --debug
-		rm -f txt help tmp 2>/dev/null
+		rm -f adoc help tmp 2>/dev/null
 	fi
 done <builtins
 
diff --git a/t/t0450/txt-help-mismatches b/t/t0450/adoc-help-mismatches
similarity index 98%
rename from t/t0450/txt-help-mismatches
rename to t/t0450/adoc-help-mismatches
index 28003f1..c4a15fd 100644
--- a/t/t0450/txt-help-mismatches
+++ b/t/t0450/adoc-help-mismatches
@@ -45,7 +45,6 @@
 remote
 remote-ext
 remote-fd
-repack
 reset
 restore
 rev-parse
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index ff9bf21..398865d 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -240,7 +240,8 @@
 	git config extensions.objectformat $test_hash_algo &&
 	git config extensions.compatobjectformat $test_compat_hash_algo &&
 	echo_without_newline "$hello_content" > hello &&
-	git update-index --add hello
+	git update-index --add hello &&
+	git commit -m "add hello file"
 '
 
 run_blob_tests () {
@@ -602,6 +603,34 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'setup with curly braches in input' '
+	git branch "foo{bar" HEAD &&
+	git branch "foo@" HEAD
+'
+
+test_expect_success 'object reference with curly brace' '
+	git cat-file -p "foo{bar:hello" >actual &&
+	git cat-file -p HEAD:hello >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'object reference with at-sign' '
+	git cat-file -p "foo@@{0}:hello" >actual &&
+	git cat-file -p HEAD:hello >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'setup with commit with colon' '
+	git commit-tree -m "testing: just a bunch of junk" HEAD^{tree} >out &&
+	git branch other $(cat out)
+'
+
+test_expect_success 'object reference via commit text search' '
+	git cat-file -p "other^{/testing:}:hello" >actual &&
+	git cat-file -p HEAD:hello >expect &&
+	test_cmp expect actual
+'
+
 test_expect_success 'setup blobs which are likely to delta' '
 	test-tool genrandom foo 10240 >foo &&
 	{ cat foo && echo plus; } >foo-plus &&
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index e2316f1..29045aa 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -2068,4 +2068,13 @@
 
 done
 
+test_expect_success 'update-ref should also create reflog for HEAD' '
+	test_commit to-rewind &&
+	git rev-parse HEAD >expect &&
+	head=$(git symbolic-ref HEAD) &&
+	git update-ref --create-reflog "$head" HEAD~ &&
+	git rev-parse HEAD@{1} >actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t1460-refs-migrate.sh b/t/t1460-refs-migrate.sh
index f59bc48..2ab97e1 100755
--- a/t/t1460-refs-migrate.sh
+++ b/t/t1460-refs-migrate.sh
@@ -9,14 +9,21 @@
 
 # Migrate the provided repository from one format to the other and
 # verify that the references and logs are migrated over correctly.
-# Usage: test_migration <repo> <format> <skip_reflog_verify>
+# Usage: test_migration <repo> <format> [<skip_reflog_verify> [<options...>]]
 #   <repo> is the relative path to the repo to be migrated.
 #   <format> is the ref format to be migrated to.
-#   <skip_reflog_verify> (true or false) whether to skip reflog verification.
+#   <skip_reflog_verify> (default: false) whether to skip reflog verification.
+#   <options...> are other options be passed directly to 'git refs migrate'.
 test_migration () {
 	repo=$1 &&
 	format=$2 &&
-	skip_reflog_verify=${3:-false} &&
+	shift 2 &&
+	skip_reflog_verify=false &&
+	if test $# -ge 1
+	then
+		skip_reflog_verify=$1
+		shift
+	fi &&
 	git -C "$repo" for-each-ref --include-root-refs \
 		--format='%(refname) %(objectname) %(symref)' >expect &&
 	if ! $skip_reflog_verify
@@ -25,7 +32,7 @@
 	   git -C "$repo" reflog list >expect_log_list
 	fi &&
 
-	git -C "$repo" refs migrate --ref-format="$2" &&
+	git -C "$repo" refs migrate --ref-format="$format" "$@" &&
 
 	git -C "$repo" for-each-ref --include-root-refs \
 		--format='%(refname) %(objectname) %(symref)' >actual &&
@@ -224,9 +231,51 @@
 			test_commit --date "100003000 +0700" --no-tag -C repo second &&
 			test_migration repo "$to_format"
 		'
+
+		test_expect_success "$from_format -> $to_format: stash is retained" '
+			test_when_finished "rm -rf repo" &&
+			git init --ref-format=$from_format repo &&
+			(
+				cd repo &&
+				test_commit initial A &&
+				echo foo >A &&
+				git stash push &&
+				echo bar >A &&
+				git stash push &&
+				git stash list >expect.reflog &&
+				test_migration . "$to_format" &&
+				git stash list >actual.reflog &&
+				test_cmp expect.reflog actual.reflog
+			)
+		'
+
+		test_expect_success "$from_format -> $to_format: skip reflog with --skip-reflog" '
+			test_when_finished "rm -rf repo" &&
+			git init --ref-format=$from_format repo &&
+			test_commit -C repo initial &&
+			# we see that the repository contains reflogs.
+			git -C repo reflog --all >reflogs &&
+			test_line_count = 2 reflogs &&
+			test_migration repo "$to_format" true --no-reflog &&
+			# there should be no reflogs post migration.
+			git -C repo reflog --all >reflogs &&
+			test_must_be_empty reflogs
+		'
 	done
 done
 
+test_expect_success 'multiple reftable blocks with multiple entries' '
+	test_when_finished "rm -rf repo" &&
+	git init --ref-format=files repo &&
+	test_commit -C repo first &&
+	printf "create refs/heads/ref-%d HEAD\n" $(test_seq 5000) >stdin &&
+	git -C repo update-ref --stdin <stdin &&
+	test_commit -C repo second &&
+	printf "update refs/heads/ref-%d HEAD\n" $(test_seq 3000) >stdin &&
+	git -C repo update-ref --stdin <stdin &&
+	test_migration repo reftable
+'
+
 test_expect_success 'migrating from files format deletes backend files' '
 	test_when_finished "rm -rf repo" &&
 	git init --ref-format=files repo &&
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index a3a21c5..f3e720d 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -410,6 +410,20 @@
 	git -C secondary branch -D main
 '
 
+test_expect_success 'secondary worktrees recognize core.bare=true in main config.worktree' '
+	test_when_finished "rm -rf bare_repo non_bare_repo secondary_worktree" &&
+	git init -b main non_bare_repo &&
+	test_commit -C non_bare_repo x &&
+
+	git clone --bare non_bare_repo bare_repo &&
+	git -C bare_repo config extensions.worktreeConfig true &&
+	git -C bare_repo config unset core.bare &&
+	git -C bare_repo config --worktree core.bare true &&
+
+	git -C bare_repo worktree add ../secondary_worktree &&
+	git -C secondary_worktree checkout main
+'
+
 test_expect_success 'git branch --list -v with --abbrev' '
 	test_when_finished "git branch -D t" &&
 	git branch t &&
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 500c9d0..a6bd88a 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -368,6 +368,34 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'git branch `--sort=[-]ahead-behind` option' '
+	cat >expect <<-\EOF &&
+	(HEAD detached from fromtag) 0 0
+	refs/heads/ambiguous 0 0
+	refs/heads/branch-two 0 0
+	refs/heads/branch-one 1 0
+	refs/heads/main 1 0
+	refs/heads/ref-to-branch 1 0
+	refs/heads/ref-to-remote 1 0
+	EOF
+	git branch --format="%(refname) %(ahead-behind:HEAD)" \
+		--sort=refname --sort=ahead-behind:HEAD >actual &&
+	test_cmp expect actual &&
+
+	cat >expect <<-\EOF &&
+	(HEAD detached from fromtag) 0 0
+	refs/heads/branch-one 1 0
+	refs/heads/main 1 0
+	refs/heads/ref-to-branch 1 0
+	refs/heads/ref-to-remote 1 0
+	refs/heads/ambiguous 0 0
+	refs/heads/branch-two 0 0
+	EOF
+	git branch --format="%(refname) %(ahead-behind:HEAD)" \
+		--sort=refname --sort=-ahead-behind:HEAD >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'git branch with --format=%(rest) must fail' '
 	test_must_fail git branch --format="%(rest)" >actual
 '
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index ecfc020..2aee978 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -791,6 +791,20 @@
 	grep "C changed" actual
 '
 
+test_expect_success 'reword fast-forwarded empty commit' '
+	git commit --allow-empty -m "empty commit" --only &&
+	(
+		set_fake_editor &&
+		FAKE_COMMIT_AMEND=edited FAKE_LINES="reword 1" \
+			git rebase -i HEAD^
+	) &&
+	test_commit_message HEAD <<-\EOF
+	empty commit
+
+	edited
+	EOF
+'
+
 test_expect_success 'no uncommitted changes when rewording and the todo list is reloaded' '
 	git checkout E &&
 	test_when_finished "git checkout @{-1}" &&
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index 2593711..b84d68c 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -610,4 +610,24 @@
 	grep "label 0123456789-$" out
 '
 
+test_expect_success 'reword fast-forwarded empty merge commit' '
+	oid="$(git commit-tree -m "D1" -p A D^{tree})" &&
+	oid="$(git commit-tree -m "empty merge" -p D -p $oid D^{tree})" &&
+
+	write_script sequence-editor.sh <<-\EOF &&
+	sed /^merge/s/-C/-c/ "$1" >"$1.tmp"
+	mv "$1.tmp" "$1"
+	EOF
+
+	(
+		test_set_sequence_editor "$(pwd)/sequence-editor.sh" &&
+		GIT_EDITOR="echo edited >>" git rebase -i -r D $oid
+	) &&
+	test_commit_message HEAD <<-\EOF
+	empty merge
+
+	edited
+	EOF
+'
+
 test_done
diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh
index 146e73d..a5664f3 100755
--- a/t/t4100-apply-stat.sh
+++ b/t/t4100-apply-stat.sh
@@ -38,4 +38,17 @@
 incomplete (2)
 EOF
 
+test_expect_success 'applying a hunk header which overflows fails' '
+	cat >patch <<-\EOF &&
+	diff -u a/file b/file
+	--- a/file
+	+++ b/file
+	@@ -98765432109876543210 +98765432109876543210 @@
+	-a
+	+b
+	EOF
+	test_must_fail git apply patch 2>err &&
+	echo "error: corrupt patch at line 4" >expect &&
+	test_cmp expect err
+'
 test_done
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 2421491..4a6242f 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -113,6 +113,18 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'check-mailmap name and address: mapping' '
+	test_when_finished "rm .mailmap" &&
+	cat >.mailmap <<-EOF &&
+	Bug Reports <bugs-new@company.xx> Bugs <bugs@company.xx>
+	EOF
+	cat >expect <<-EOF &&
+	<bugs@company.xx>
+	EOF
+	git check-mailmap "bugs@company.xx" >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'No mailmap' '
 	cat >expect <<-EOF &&
 	$GIT_AUTHOR_NAME (1):
diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh
index a675ace..0e2f80a 100755
--- a/t/t4209-log-pickaxe.sh
+++ b/t/t4209-log-pickaxe.sh
@@ -93,6 +93,22 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'usage: -G and -S with empty argument' '
+	cat >expect <<-\EOF &&
+	error: -S requires a non-empty argument
+	EOF
+
+	test_expect_code 129 git log -S "" 2>actual &&
+	test_cmp expect actual &&
+
+	cat >expect <<-\EOF &&
+	error: -G requires a non-empty argument
+	EOF
+
+	test_expect_code 129 git log -G "" 2>actual &&
+	test_cmp expect actual
+'
+
 test_log	expect_initial	--grep initial
 test_log	expect_nomatch	--grep InItial
 test_log_icase	expect_initial	--grep InItial
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index d1d6248..5ac8d39 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -689,4 +689,38 @@
 	'
 done
 
+test_expect_success 'valid and invalid --name-hash-versions' '
+	sane_unset GIT_TEST_NAME_HASH_VERSION &&
+
+	# Valid values are hard to verify other than "do not fail".
+	# Performance tests will be more valuable to validate these versions.
+	# Negative values are converted to version 1.
+	for value in -1 1 2
+	do
+		git pack-objects base --all --name-hash-version=$value || return 1
+	done &&
+
+	# Invalid values have clear post-conditions.
+	for value in 0 3
+	do
+		test_must_fail git pack-objects base --all --name-hash-version=$value 2>err &&
+		test_grep "invalid --name-hash-version option" err || return 1
+	done
+'
+
+# The following test is not necessarily a permanent choice, but since we do not
+# have a "name hash version" bit in the .bitmap file format, we cannot write the
+# hash values into the .bitmap file without risking breakage later.
+#
+# TODO: Make these compatible in the future and replace this test with the
+# expected behavior when both are specified.
+test_expect_success '--name-hash-version=2 and --write-bitmap-index are incompatible' '
+	git pack-objects base --all --name-hash-version=2 --write-bitmap-index 2>err &&
+	test_grep "currently, --write-bitmap-index requires --name-hash-version=1" err &&
+
+	# --stdout option silently removes --write-bitmap-index
+	git pack-objects --stdout --all --name-hash-version=2 --write-bitmap-index >out 2>err &&
+	! test_grep "currently, --write-bitmap-index requires --name-hash-version=1" err
+'
+
 test_done
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index eabfcd7..621bbbd 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -26,6 +26,36 @@
 	grep -Ff "$1" "$2"
 }
 
+# Since name-hash values are stored in the .bitmap files, add a test
+# that checks that the name-hash calculations are stable across versions.
+# Not exhaustive, but these hashing algorithms would be hard to change
+# without causing deviations here.
+test_expect_success 'name-hash value stability' '
+	cat >names <<-\EOF &&
+	first
+	second
+	third
+	a/one-long-enough-for-collisions
+	b/two-long-enough-for-collisions
+	many/parts/to/this/path/enough/to/collide/in/v2
+	enough/parts/to/this/path/enough/to/collide/in/v2
+	EOF
+
+	test-tool name-hash <names >out &&
+
+	cat >expect <<-\EOF &&
+	2582249472 1763573760 first
+	2289942528 1188134912 second
+	2300837888 1130758144 third
+	2544516325 3963087891 a/one-long-enough-for-collisions
+	2544516325 4013419539 b/two-long-enough-for-collisions
+	1420111091 1709547268 many/parts/to/this/path/enough/to/collide/in/v2
+	1420111091 1709547268 enough/parts/to/this/path/enough/to/collide/in/v2
+	EOF
+
+	test_cmp expect out
+'
+
 test_bitmap_cases () {
 	writeLookupTable=false
 	for i in "$@"
@@ -419,7 +449,10 @@
 			cat >expect <<-\EOF &&
 			error: missing value for '\''pack.preferbitmaptips'\''
 			EOF
-			git repack -adb 2>actual &&
+
+			# Disable name hash version adjustment due to stderr comparison.
+			GIT_TEST_NAME_HASH_VERSION=1 \
+				git repack -adb 2>actual &&
 			test_cmp expect actual
 		)
 	'
diff --git a/t/t5323-pack-redundant.sh b/t/t5323-pack-redundant.sh
index 8dbbcc5..688cd97 100755
--- a/t/t5323-pack-redundant.sh
+++ b/t/t5323-pack-redundant.sh
@@ -36,6 +36,12 @@
 
 . ./test-lib.sh
 
+if ! test_have_prereq WITHOUT_BREAKING_CHANGES
+then
+	skip_all='skipping git-pack-redundant tests; built with breaking changes'
+	test_done
+fi
+
 main_repo=main.git
 shared_repo=shared.git
 
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
index 1dd6284..3905cb6 100755
--- a/t/t5333-pseudo-merge-bitmaps.sh
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -208,7 +208,8 @@
 '
 
 test_expect_success 'out of order thresholds are rejected' '
-	test_must_fail git \
+	# Disable the test var to remove a stderr message.
+	test_must_fail env GIT_TEST_NAME_HASH_VERSION=1 git \
 		-c bitmapPseudoMerge.test.pattern="refs/*" \
 		-c bitmapPseudoMerge.test.threshold=1.month.ago \
 		-c bitmapPseudoMerge.test.stableThreshold=1.week.ago \
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
index 723d1e1..17a46fd 100755
--- a/t/t5401-update-hooks.sh
+++ b/t/t5401-update-hooks.sh
@@ -64,14 +64,14 @@
 '
 
 test_expect_success 'hooks ran' '
-	test -f victim.git/pre-receive.args &&
-	test -f victim.git/pre-receive.stdin &&
-	test -f victim.git/update.args &&
-	test -f victim.git/update.stdin &&
-	test -f victim.git/post-receive.args &&
-	test -f victim.git/post-receive.stdin &&
-	test -f victim.git/post-update.args &&
-	test -f victim.git/post-update.stdin
+	test_path_is_file victim.git/pre-receive.args &&
+	test_path_is_file victim.git/pre-receive.stdin &&
+	test_path_is_file victim.git/update.args &&
+	test_path_is_file victim.git/update.stdin &&
+	test_path_is_file victim.git/post-receive.args &&
+	test_path_is_file victim.git/post-receive.stdin &&
+	test_path_is_file victim.git/post-update.args &&
+	test_path_is_file victim.git/post-update.stdin
 '
 
 test_expect_success 'pre-receive hook input' '
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 195fc64..845ca43 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -160,4 +160,18 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'fetch specific OID with tag following' '
+	git init --bare clone3.git &&
+	(
+		cd clone3.git &&
+		git remote add origin .. &&
+		git fetch origin $B:refs/heads/main &&
+
+		git -C .. for-each-ref >expect &&
+		git for-each-ref >actual &&
+
+		test_cmp expect actual
+	)
+'
+
 test_done
diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh
index 8212a70..5807450 100755
--- a/t/t5504-fetch-receive-strict.sh
+++ b/t/t5504-fetch-receive-strict.sh
@@ -64,12 +64,6 @@
 	)
 '
 
-cat >exp <<EOF
-To dst
-!	refs/heads/main:refs/heads/test	[remote rejected] (missing necessary objects)
-Done
-EOF
-
 test_expect_success 'push without strict' '
 	rm -rf dst &&
 	git init dst &&
@@ -78,6 +72,11 @@
 		git config fetch.fsckobjects false &&
 		git config transfer.fsckobjects false
 	) &&
+	cat >exp <<-\EOF &&
+	To dst
+	!	refs/heads/main:refs/heads/test	[remote rejected] (missing necessary objects)
+	Done
+	EOF
 	test_must_fail git push --porcelain dst main:refs/heads/test >act &&
 	test_cmp exp act
 '
@@ -94,11 +93,6 @@
 	test_cmp exp act
 '
 
-cat >exp <<EOF
-To dst
-!	refs/heads/main:refs/heads/test	[remote rejected] (unpacker error)
-EOF
-
 test_expect_success 'push with receive.fsckobjects' '
 	rm -rf dst &&
 	git init dst &&
@@ -107,6 +101,10 @@
 		git config receive.fsckobjects true &&
 		git config transfer.fsckobjects false
 	) &&
+	cat >exp <<-\EOF &&
+	To dst
+	!	refs/heads/main:refs/heads/test	[remote rejected] (unpacker error)
+	EOF
 	test_must_fail git push --porcelain dst main:refs/heads/test >act &&
 	test_cmp exp act
 '
@@ -129,15 +127,14 @@
 	git fsck
 '
 
-cat >bogus-commit <<EOF
-tree $EMPTY_TREE
-author Bugs Bunny 1234567890 +0000
-committer Bugs Bunny <bugs@bun.ni> 1234567890 +0000
-
-This commit object intentionally broken
-EOF
-
 test_expect_success 'setup bogus commit' '
+	cat >bogus-commit <<-EOF &&
+	tree $EMPTY_TREE
+	author Bugs Bunny 1234567890 +0000
+	committer Bugs Bunny <bugs@bun.ni> 1234567890 +0000
+
+	This commit object intentionally broken
+	EOF
 	commit="$(git hash-object --literally -t commit -w --stdin <bogus-commit)"
 '
 
@@ -167,6 +164,8 @@
 
 test_expect_success 'fsck with invalid or bogus skipList input' '
 	git -c fsck.skipList=/dev/null -c fsck.missingEmail=ignore fsck &&
+	test_must_fail git -c fsck.skipList -c fsck.missingEmail=ignore fsck 2>err &&
+	test_grep "unable to parse '\'fsck.skiplist\'' from command-line config" err &&
 	test_must_fail git -c fsck.skipList=does-not-exist -c fsck.missingEmail=ignore fsck 2>err &&
 	test_grep "could not open.*: does-not-exist" err &&
 	test_must_fail git -c fsck.skipList=.git/config -c fsck.missingEmail=ignore fsck 2>err &&
@@ -213,6 +212,11 @@
 	test_must_be_empty err
 '
 
+test_expect_success 'receive-pack with missing receive.fsck.skipList path' '
+	test_must_fail git -c receive.fsck.skipList receive-pack dst 2>err &&
+	test_grep "unable to parse '\'receive.fsck.skiplist\'' from command-line config" err
+'
+
 test_expect_success 'push with receive.fsck.skipList' '
 	git push . $commit:refs/heads/bogus &&
 	rm -rf dst &&
@@ -255,6 +259,9 @@
 	test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec &&
 
 	# Invalid and/or bogus skipList input
+	test_must_fail git --git-dir=dst/.git -c fetch.fsck.skipList fetch \
+		"file://$(pwd)" $refspec 2>err &&
+	test_grep "unable to parse '\'fetch.fsck.skiplist\'' from command-line config" err &&
 	git --git-dir=dst/.git config fetch.fsck.skipList /dev/null &&
 	test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec &&
 	git --git-dir=dst/.git config fetch.fsck.skipList does-not-exist &&
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 519f797..bb7e0c6 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -589,6 +589,16 @@
 	)
 '
 
+test_expect_success 'non-mirror fetch does not interfere with mirror' '
+	test_when_finished rm -rf headnotmain &&
+	(
+		git init --bare -b notmain headnotmain &&
+		cd headnotmain &&
+		git remote add -f other ../two &&
+		test "$(git symbolic-ref HEAD)" = "refs/heads/notmain"
+	)
+'
+
 test_expect_success 'add --mirror=fetch' '
 	mkdir mirror-fetch &&
 	git init -b main mirror-fetch/parent &&
@@ -1113,7 +1123,7 @@
 Pull: refs/heads/next:refs/heads/origin2
 EOF
 
-test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' '
+test_expect_success WITHOUT_BREAKING_CHANGES 'migrate a remote from named file in $GIT_DIR/remotes' '
 	git clone one five &&
 	origin_url=$(pwd)/one &&
 	(
@@ -1139,7 +1149,7 @@
 	)
 '
 
-test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' '
+test_expect_success WITHOUT_BREAKING_CHANGES 'migrate a remote from named file in $GIT_DIR/branches' '
 	git clone --template= one six &&
 	origin_url=$(pwd)/one &&
 	(
@@ -1155,7 +1165,7 @@
 	)
 '
 
-test_expect_success 'migrate a remote from named file in $GIT_DIR/branches (2)' '
+test_expect_success WITHOUT_BREAKING_CHANGES 'migrate a remote from named file in $GIT_DIR/branches (2)' '
 	git clone --template= one seven &&
 	(
 		cd seven &&
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 2d95870..5f350fa 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -34,14 +34,11 @@
 	git clone . three &&
 	(
 		cd three &&
-		git config branch.main.remote two &&
-		git config branch.main.merge refs/heads/one &&
-		mkdir -p .git/remotes &&
-		cat >.git/remotes/two <<-\EOF
-		URL: ../two/.git/
-		Pull: refs/heads/main:refs/heads/two
-		Pull: refs/heads/one:refs/heads/one
-		EOF
+		git config set remote.two.url ../two/.git/ &&
+		git config set remote.two.fetch refs/heads/main:refs/heads/two &&
+		git config set --append remote.two.fetch refs/heads/one:refs/heads/one &&
+		git config set branch.main.remote two &&
+		git config set branch.main.merge refs/heads/one
 	) &&
 	git clone . bundle &&
 	git clone . seven
@@ -84,6 +81,23 @@
 	branch=$(git rev-parse refs/remotes/origin/main) &&
 	test "z$head" = "z$branch"'
 
+test_expect_success "fetch test remote HEAD in bare repository" '
+	test_when_finished rm -rf barerepo &&
+	(
+		cd "$D" &&
+		git init --bare barerepo &&
+		cd barerepo &&
+		git remote add upstream ../two &&
+		git fetch upstream &&
+		git rev-parse --verify refs/remotes/upstream/HEAD &&
+		git rev-parse --verify refs/remotes/upstream/main &&
+		head=$(git rev-parse refs/remotes/upstream/HEAD) &&
+		branch=$(git rev-parse refs/remotes/upstream/main) &&
+		test "z$head" = "z$branch"
+	)
+'
+
+
 test_expect_success "fetch test remote HEAD change" '
 	cd "$D" &&
 	cd two &&
@@ -1240,7 +1254,12 @@
 	test_tick &&
 	git merge otherside &&
 	ad=$(git log --no-walk --format=%ad HEAD) &&
-	git bundle create twoside-boundary.bdl main --since="$ad" &&
+
+	# If the a different name hash function is used here, then no delta
+	# pair is found and the bundle does not expand to three objects
+	# when fixing the thin object.
+	GIT_TEST_NAME_HASH_VERSION=1 \
+		git bundle create twoside-boundary.bdl main --since="$ad" &&
 	test_bundle_object_count --thin twoside-boundary.bdl 3
 '
 
diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh
index 320d267..4e6026c 100755
--- a/t/t5515-fetch-merge-logic.sh
+++ b/t/t5515-fetch-merge-logic.sh
@@ -104,28 +104,31 @@
 	git config remote.config-glob.fetch refs/heads/*:refs/remotes/rem/* &&
 	remotes="$remotes config-glob" &&
 
-	mkdir -p .git/remotes &&
-	cat >.git/remotes/remote-explicit <<-\EOF &&
-	URL: ../.git/
-	Pull: refs/heads/main:remotes/rem/main
-	Pull: refs/heads/one:remotes/rem/one
-	Pull: two:remotes/rem/two
-	Pull: refs/heads/three:remotes/rem/three
-	EOF
-	remotes="$remotes remote-explicit" &&
+	if test_have_prereq WITHOUT_BREAKING_CHANGES
+	then
+		mkdir -p .git/remotes &&
+		cat >.git/remotes/remote-explicit <<-\EOF &&
+		URL: ../.git/
+		Pull: refs/heads/main:remotes/rem/main
+		Pull: refs/heads/one:remotes/rem/one
+		Pull: two:remotes/rem/two
+		Pull: refs/heads/three:remotes/rem/three
+		EOF
+		remotes="$remotes remote-explicit" &&
 
-	cat >.git/remotes/remote-glob <<-\EOF &&
-	URL: ../.git/
-	Pull: refs/heads/*:refs/remotes/rem/*
-	EOF
-	remotes="$remotes remote-glob" &&
+		cat >.git/remotes/remote-glob <<-\EOF &&
+		URL: ../.git/
+		Pull: refs/heads/*:refs/remotes/rem/*
+		EOF
+		remotes="$remotes remote-glob" &&
 
-	mkdir -p .git/branches &&
-	echo "../.git" > .git/branches/branches-default &&
-	remotes="$remotes branches-default" &&
+		mkdir -p .git/branches &&
+		echo "../.git" > .git/branches/branches-default &&
+		remotes="$remotes branches-default" &&
 
-	echo "../.git#one" > .git/branches/branches-one &&
-	remotes="$remotes branches-one" &&
+		echo "../.git#one" > .git/branches/branches-one &&
+		remotes="$remotes branches-one"
+	fi &&
 
 	for remote in $remotes ; do
 		git config branch.br-$remote.remote $remote &&
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 041d7d8..85ed049 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -975,7 +975,7 @@
 	! grep "warning: updating the current branch" stderr
 '
 
-test_expect_success 'fetch with branches' '
+test_expect_success WITHOUT_BREAKING_CHANGES 'fetch with branches' '
 	mk_empty testrepo &&
 	git branch second $the_first_commit &&
 	git checkout second &&
@@ -991,7 +991,7 @@
 	git checkout main
 '
 
-test_expect_success 'fetch with branches containing #' '
+test_expect_success WITHOUT_BREAKING_CHANGES 'fetch with branches containing #' '
 	mk_empty testrepo &&
 	mkdir testrepo/.git/branches &&
 	echo "..#second" > testrepo/.git/branches/branch2 &&
@@ -1005,7 +1005,7 @@
 	git checkout main
 '
 
-test_expect_success 'push with branches' '
+test_expect_success WITHOUT_BREAKING_CHANGES 'push with branches' '
 	mk_empty testrepo &&
 	git checkout second &&
 
@@ -1022,7 +1022,7 @@
 	)
 '
 
-test_expect_success 'push with branches containing #' '
+test_expect_success WITHOUT_BREAKING_CHANGES 'push with branches containing #' '
 	mk_empty testrepo &&
 
 	test_when_finished "rm -rf .git/branches" &&
@@ -1211,18 +1211,16 @@
 '
 
 test_expect_success 'push --prune' '
-	mk_test testrepo heads/main heads/second heads/foo heads/bar &&
+	mk_test testrepo heads/main heads/foo heads/bar &&
 	git push --prune testrepo : &&
 	check_push_result testrepo $the_commit heads/main &&
-	check_push_result testrepo $the_first_commit heads/second &&
 	! check_push_result testrepo $the_first_commit heads/foo heads/bar
 '
 
 test_expect_success 'push --prune refspec' '
-	mk_test testrepo tmp/main tmp/second tmp/foo tmp/bar &&
+	mk_test testrepo tmp/main tmp/foo tmp/bar &&
 	git push --prune testrepo "refs/heads/*:refs/tmp/*" &&
 	check_push_result testrepo $the_commit tmp/main &&
-	check_push_result testrepo $the_first_commit tmp/second &&
 	! check_push_result testrepo $the_first_commit tmp/foo tmp/bar
 '
 
diff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh
index 37db3de..3fa05ff 100755
--- a/t/t5540-http-push-webdav.sh
+++ b/t/t5540-http-push-webdav.sh
@@ -201,4 +201,14 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'push to password-protected repository (netrc)' '
+	test_commit pw-netrc &&
+	echo "default login user@host password pass@host" >"$HOME/.netrc" &&
+	GIT_TRACE=1 GIT_CURL_VERBOSE=1 git push "$HTTPD_URL/auth/dumb/test_repo.git" HEAD &&
+	git rev-parse --verify HEAD >expect &&
+	git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
+		rev-parse --verify HEAD >actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh
index 04b47ad..3a700b0 100755
--- a/t/t5543-atomic-push.sh
+++ b/t/t5543-atomic-push.sh
@@ -280,4 +280,34 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'atomic push reports exit code failure' '
+	write_script receive-pack-wrapper <<-\EOF &&
+	git-receive-pack "$@"
+	exit 1
+	EOF
+	test_must_fail git -C workbench push --atomic \
+		--receive-pack="${SQ}$(pwd)${SQ}/receive-pack-wrapper" \
+		up HEAD:refs/heads/no-conflict 2>err &&
+	cat >expect <<-EOF &&
+	To ../upstream
+	 * [new branch]      HEAD -> no-conflict
+	error: failed to push some refs to ${SQ}../upstream${SQ}
+	EOF
+	test_cmp expect err
+'
+
+test_expect_success 'atomic push reports exit code failure with porcelain' '
+	write_script receive-pack-wrapper <<-\EOF &&
+	git-receive-pack "$@"
+	exit 1
+	EOF
+	test_must_fail git -C workbench push --atomic --porcelain \
+		--receive-pack="${SQ}$(pwd)${SQ}/receive-pack-wrapper" \
+		up HEAD:refs/heads/no-conflict-porcelain 2>err &&
+	cat >expect <<-EOF &&
+	error: failed to push some refs to ${SQ}../upstream${SQ}
+	EOF
+	test_cmp expect err
+'
+
 test_done
diff --git a/t/t5548-push-porcelain.sh b/t/t5548-push-porcelain.sh
index 6282728..4c19404 100755
--- a/t/t5548-push-porcelain.sh
+++ b/t/t5548-push-porcelain.sh
@@ -54,29 +54,67 @@
 	sed -e 's/^> //' -e 's/Z$//' >expect
 }
 
+create_upstream_template () {
+	git init --bare upstream-template.git &&
+	git clone upstream-template.git tmp_work_dir &&
+	create_commits_in tmp_work_dir A B &&
+	(
+		cd tmp_work_dir &&
+		git push origin \
+			$B:refs/heads/main \
+			$A:refs/heads/foo \
+			$A:refs/heads/bar \
+			$A:refs/heads/baz
+	) &&
+	rm -rf tmp_work_dir
+}
+
+setup_upstream () {
+	if test $# -ne 1
+	then
+		BUG "location of upstream repository is not provided"
+	fi &&
+	rm -rf "$1" &&
+	if ! test -d upstream-template.git
+	then
+		create_upstream_template
+	fi &&
+	git clone --mirror upstream-template.git "$1" &&
+	# The upstream repository provides services using the HTTP protocol.
+	if ! test "$1" = "upstream.git"
+	then
+		git -C "$1" config http.receivepack true
+	fi
+}
+
 setup_upstream_and_workbench () {
-	# Upstream  after setup : main(B)  foo(A)  bar(A)  baz(A)
-	# Workbench after setup : main(A)
+	if test $# -ne 1
+	then
+		BUG "location of upstream repository is not provided"
+	fi
+	upstream="$1"
+
+	# Upstream  after setup: main(B)  foo(A)  bar(A)  baz(A)
+	# Workbench after setup: main(A)                  baz(A)  next(A)
 	test_expect_success "setup upstream repository and workbench" '
-		rm -rf upstream.git workbench &&
-		git init --bare upstream.git &&
-		git init workbench &&
-		create_commits_in workbench A B &&
+		setup_upstream "$upstream" &&
+		rm -rf workbench &&
+		git clone "$upstream" workbench &&
 		(
 			cd workbench &&
+			git update-ref refs/heads/main $A &&
+			git update-ref refs/heads/baz $A &&
+			git update-ref refs/heads/next $A &&
 			# Try to make a stable fixed width for abbreviated commit ID,
 			# this fixed-width oid will be replaced with "<OID>".
 			git config core.abbrev 7 &&
-			git remote add origin ../upstream.git &&
-			git update-ref refs/heads/main $A &&
-			git push origin \
-				$B:refs/heads/main \
-				$A:refs/heads/foo \
-				$A:refs/heads/bar \
-				$A:refs/heads/baz
+			git config advice.pushUpdateRejected false
 		) &&
-		git -C "workbench" config advice.pushUpdateRejected false &&
-		upstream=upstream.git
+		# The upstream repository provides services using the HTTP protocol.
+		if ! test "$upstream" = "upstream.git"
+		then
+			git -C workbench remote set-url origin "$HTTPD_URL/smart/upstream.git"
+		fi
 	'
 }
 
@@ -88,26 +126,55 @@
 		;;
 	file)
 		PROTOCOL="builtin protocol"
-		URL_PREFIX="\.\."
+		URL_PREFIX=".*"
 		;;
 	esac
 
 	# Refs of upstream : main(B)  foo(A)  bar(A)  baz(A)
 	# Refs of workbench: main(A)                  baz(A)  next(A)
 	# git-push         : main(A)  NULL    (B)     baz(A)  next(A)
-	test_expect_success "porcelain output of successful git-push ($PROTOCOL)" '
-		(
-			cd workbench &&
-			git update-ref refs/heads/main $A &&
-			git update-ref refs/heads/baz $A &&
-			git update-ref refs/heads/next $A &&
-			git push --porcelain --force origin \
-				main \
-				:refs/heads/foo \
-				$B:bar \
-				baz \
-				next
-		) >out &&
+	test_expect_success ".. git-push --porcelain ($PROTOCOL)" '
+		test_when_finished "setup_upstream \"$upstream\"" &&
+		test_must_fail git -C workbench push --porcelain origin \
+			main \
+			:refs/heads/foo \
+			$B:bar \
+			baz \
+			next >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		format_and_save_expect <<-\EOF &&
+		> To <URL/of/upstream.git>
+		> =	refs/heads/baz:refs/heads/baz	[up to date]
+		>  	<COMMIT-B>:refs/heads/bar	<COMMIT-A>..<COMMIT-B>
+		> -	:refs/heads/foo	[deleted]
+		> *	refs/heads/next:refs/heads/next	[new branch]
+		> !	refs/heads/main:refs/heads/main	[rejected] (non-fast-forward)
+		> Done
+		EOF
+		test_cmp expect actual &&
+
+		git -C "$upstream" show-ref >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		cat >expect <<-EOF &&
+		<COMMIT-B> refs/heads/bar
+		<COMMIT-A> refs/heads/baz
+		<COMMIT-B> refs/heads/main
+		<COMMIT-A> refs/heads/next
+		EOF
+		test_cmp expect actual
+	'
+
+	# Refs of upstream : main(B)  foo(A)  bar(A)  baz(A)
+	# Refs of workbench: main(A)                  baz(A)  next(A)
+	# git-push         : main(A)  NULL    (B)     baz(A)  next(A)
+	test_expect_success ".. git-push --porcelain --force ($PROTOCOL)" '
+		test_when_finished "setup_upstream \"$upstream\"" &&
+		git -C workbench push --porcelain --force origin \
+			main \
+			:refs/heads/foo \
+			$B:bar \
+			baz \
+			next >out &&
 		make_user_friendly_and_stable_output <out >actual &&
 		format_and_save_expect <<-EOF &&
 		> To <URL/of/upstream.git>
@@ -131,108 +198,129 @@
 		test_cmp expect actual
 	'
 
-	# Refs of upstream : main(A)  bar(B)  baz(A)  next(A)
-	# Refs of workbench: main(B)  bar(A)  baz(A)  next(A)
-	# git-push         : main(B)  bar(A)  NULL    next(A)
-	test_expect_success "atomic push failed ($PROTOCOL)" '
-		(
-			cd workbench &&
-			git update-ref refs/heads/main $B &&
-			git update-ref refs/heads/bar $A &&
-			test_must_fail git push --atomic --porcelain origin \
-				main \
-				bar \
-				:baz \
-				next
-		) >out &&
+	# Refs of upstream : main(B)  foo(A)  bar(A)  baz(A)
+	# Refs of workbench: main(A)                  baz(A)  next(A)
+	# git-push         : main(A)  NULL    (B)     baz(A)  next(A)
+	test_expect_success ".. git push --porcelain --atomic ($PROTOCOL)" '
+		test_when_finished "setup_upstream \"$upstream\"" &&
+		test_must_fail git -C workbench push --porcelain --atomic origin \
+			main \
+			:refs/heads/foo \
+			$B:bar \
+			baz \
+			next >out &&
 		make_user_friendly_and_stable_output <out >actual &&
 		format_and_save_expect <<-EOF &&
-		To <URL/of/upstream.git>
-		> =	refs/heads/next:refs/heads/next	[up to date]
-		> !	refs/heads/bar:refs/heads/bar	[rejected] (non-fast-forward)
-		> !	(delete):refs/heads/baz	[rejected] (atomic push failed)
-		> !	refs/heads/main:refs/heads/main	[rejected] (atomic push failed)
-		Done
+		> To <URL/of/upstream.git>
+		> =	refs/heads/baz:refs/heads/baz	[up to date]
+		> !	<COMMIT-B>:refs/heads/bar	[rejected] (atomic push failed)
+		> !	(delete):refs/heads/foo	[rejected] (atomic push failed)
+		> !	refs/heads/main:refs/heads/main	[rejected] (non-fast-forward)
+		> !	refs/heads/next:refs/heads/next	[rejected] (atomic push failed)
+		> Done
 		EOF
 		test_cmp expect actual &&
 
 		git -C "$upstream" show-ref >out &&
 		make_user_friendly_and_stable_output <out >actual &&
 		cat >expect <<-EOF &&
-		<COMMIT-B> refs/heads/bar
+		<COMMIT-A> refs/heads/bar
 		<COMMIT-A> refs/heads/baz
-		<COMMIT-A> refs/heads/main
-		<COMMIT-A> refs/heads/next
+		<COMMIT-A> refs/heads/foo
+		<COMMIT-B> refs/heads/main
 		EOF
 		test_cmp expect actual
 	'
 
-	test_expect_success "prepare pre-receive hook ($PROTOCOL)" '
-		test_hook --setup -C "$upstream" pre-receive <<-EOF
-		exit 1
+	# Refs of upstream : main(B)  foo(A)  bar(A)  baz(A)
+	# Refs of workbench: main(A)                  baz(A)  next(A)
+	# git-push         : main(A)  NULL    (B)     baz(A)  next(A)
+	test_expect_success ".. pre-receive hook declined ($PROTOCOL)" '
+		test_when_finished "rm -f \"$upstream/hooks/pre-receive\" &&
+			setup_upstream \"$upstream\"" &&
+		test_hook --setup -C "$upstream" pre-receive <<-EOF &&
+			exit 1
 		EOF
-	'
-
-	# Refs of upstream : main(A)  bar(B)  baz(A)  next(A)
-	# Refs of workbench: main(B)  bar(A)  baz(A)  next(A)
-	# git-push         : main(B)  bar(A)  NULL    next(A)
-	test_expect_success "pre-receive hook declined ($PROTOCOL)" '
-		(
-			cd workbench &&
-			git update-ref refs/heads/main $B &&
-			git update-ref refs/heads/bar $A &&
-			test_must_fail git push --porcelain --force origin \
-				main \
-				bar \
-				:baz \
-				next
-		) >out &&
+		test_must_fail git -C workbench push --porcelain --force origin \
+			main \
+			:refs/heads/foo \
+			$B:bar \
+			baz \
+			next >out &&
 		make_user_friendly_and_stable_output <out >actual &&
 		format_and_save_expect <<-EOF &&
-		To <URL/of/upstream.git>
-		> =	refs/heads/next:refs/heads/next	[up to date]
-		> !	refs/heads/bar:refs/heads/bar	[remote rejected] (pre-receive hook declined)
-		> !	:refs/heads/baz	[remote rejected] (pre-receive hook declined)
+		> To <URL/of/upstream.git>
+		> =	refs/heads/baz:refs/heads/baz	[up to date]
+		> !	<COMMIT-B>:refs/heads/bar	[remote rejected] (pre-receive hook declined)
+		> !	:refs/heads/foo	[remote rejected] (pre-receive hook declined)
 		> !	refs/heads/main:refs/heads/main	[remote rejected] (pre-receive hook declined)
-		Done
+		> !	refs/heads/next:refs/heads/next	[remote rejected] (pre-receive hook declined)
+		> Done
 		EOF
 		test_cmp expect actual &&
 
 		git -C "$upstream" show-ref >out &&
 		make_user_friendly_and_stable_output <out >actual &&
 		cat >expect <<-EOF &&
-		<COMMIT-B> refs/heads/bar
+		<COMMIT-A> refs/heads/bar
 		<COMMIT-A> refs/heads/baz
-		<COMMIT-A> refs/heads/main
-		<COMMIT-A> refs/heads/next
+		<COMMIT-A> refs/heads/foo
+		<COMMIT-B> refs/heads/main
 		EOF
 		test_cmp expect actual
 	'
 
-	test_expect_success "remove pre-receive hook ($PROTOCOL)" '
-		rm "$upstream/hooks/pre-receive"
-	'
-
-	# Refs of upstream : main(A)  bar(B)  baz(A)  next(A)
-	# Refs of workbench: main(B)  bar(A)  baz(A)  next(A)
-	# git-push         : main(B)  bar(A)  NULL    next(A)
-	test_expect_success "non-fastforward push ($PROTOCOL)" '
+	# Refs of upstream : main(B)  foo(A)  bar(A)  baz(A)
+	# Refs of workbench: main(A)                  baz(A)  next(A)
+	# git-push         : main(A)                          next(A)
+	test_expect_success ".. non-fastforward push ($PROTOCOL)" '
+		test_when_finished "setup_upstream \"$upstream\"" &&
 		(
 			cd workbench &&
 			test_must_fail git push --porcelain origin \
 				main \
-				bar \
-				:baz \
 				next
 		) >out &&
 		make_user_friendly_and_stable_output <out >actual &&
 		format_and_save_expect <<-EOF &&
-		To <URL/of/upstream.git>
-		> =	refs/heads/next:refs/heads/next	[up to date]
-		> -	:refs/heads/baz	[deleted]
-		>  	refs/heads/main:refs/heads/main	<COMMIT-A>..<COMMIT-B>
-		> !	refs/heads/bar:refs/heads/bar	[rejected] (non-fast-forward)
-		Done
+		> To <URL/of/upstream.git>
+		> *	refs/heads/next:refs/heads/next	[new branch]
+		> !	refs/heads/main:refs/heads/main	[rejected] (non-fast-forward)
+		> Done
+		EOF
+		test_cmp expect actual &&
+
+		git -C "$upstream" show-ref >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		cat >expect <<-EOF &&
+		<COMMIT-A> refs/heads/bar
+		<COMMIT-A> refs/heads/baz
+		<COMMIT-A> refs/heads/foo
+		<COMMIT-B> refs/heads/main
+		<COMMIT-A> refs/heads/next
+		EOF
+		test_cmp expect actual
+	'
+
+	# Refs of upstream : main(B)  foo(A)  bar(A)  baz(A)
+	# Refs of workbench: main(A)                  baz(A)  next(A)
+	# git-push         : main(A)  NULL    (B)     baz(A)  next(A)
+	test_expect_success ".. git push --porcelain --atomic --force ($PROTOCOL)" '
+		git -C workbench push --porcelain --atomic --force origin \
+			main \
+			:refs/heads/foo \
+			$B:bar \
+			baz \
+			next >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		format_and_save_expect <<-\EOF &&
+		> To <URL/of/upstream.git>
+		> =	refs/heads/baz:refs/heads/baz	[up to date]
+		>  	<COMMIT-B>:refs/heads/bar	<COMMIT-A>..<COMMIT-B>
+		> -	:refs/heads/foo	[deleted]
+		> +	refs/heads/main:refs/heads/main	<COMMIT-B>...<COMMIT-A> (forced update)
+		> *	refs/heads/next:refs/heads/next	[new branch]
+		> Done
 		EOF
 		test_cmp expect actual &&
 
@@ -240,39 +328,180 @@
 		make_user_friendly_and_stable_output <out >actual &&
 		cat >expect <<-EOF &&
 		<COMMIT-B> refs/heads/bar
-		<COMMIT-B> refs/heads/main
+		<COMMIT-A> refs/heads/baz
+		<COMMIT-A> refs/heads/main
 		<COMMIT-A> refs/heads/next
 		EOF
 		test_cmp expect actual
 	'
 }
 
-# Initialize the upstream repository and local workbench.
-setup_upstream_and_workbench
+run_git_push_dry_run_porcelain_output_test() {
+	case $1 in
+	http)
+		PROTOCOL="HTTP protocol"
+		URL_PREFIX="http://.*"
+		;;
+	file)
+		PROTOCOL="builtin protocol"
+		URL_PREFIX=".*"
+		;;
+	esac
 
-# Run git-push porcelain test on builtin protocol
+	# Refs of upstream : main(B)  foo(A)  bar(A)  baz(A)
+	# Refs of workbench: main(A)                  baz(A)  next(A)
+	# git-push         : main(A)  NULL    (B)     baz(A)  next(A)
+	test_expect_success ".. git-push --porcelain --dry-run ($PROTOCOL)" '
+		test_must_fail git -C workbench push --porcelain --dry-run origin \
+			main \
+			:refs/heads/foo \
+			$B:bar \
+			baz \
+			next >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		format_and_save_expect <<-EOF &&
+		> To <URL/of/upstream.git>
+		> =	refs/heads/baz:refs/heads/baz	[up to date]
+		>  	<COMMIT-B>:refs/heads/bar	<COMMIT-A>..<COMMIT-B>
+		> -	:refs/heads/foo	[deleted]
+		> *	refs/heads/next:refs/heads/next	[new branch]
+		> !	refs/heads/main:refs/heads/main	[rejected] (non-fast-forward)
+		> Done
+		EOF
+		test_cmp expect actual &&
+
+		git -C "$upstream" show-ref >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		cat >expect <<-EOF &&
+		<COMMIT-A> refs/heads/bar
+		<COMMIT-A> refs/heads/baz
+		<COMMIT-A> refs/heads/foo
+		<COMMIT-B> refs/heads/main
+		EOF
+		test_cmp expect actual
+	'
+
+	# Refs of upstream : main(B)  foo(A)  bar(A)  baz(A)
+	# Refs of workbench: main(A)                  baz(A)  next(A)
+	# push             : main(A)  NULL    (B)     baz(A)  next(A)
+	test_expect_success ".. git-push --porcelain --dry-run --force ($PROTOCOL)" '
+		git -C workbench push --porcelain --dry-run --force origin \
+			main \
+			:refs/heads/foo \
+			$B:bar \
+			baz \
+			next >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		format_and_save_expect <<-EOF &&
+		> To <URL/of/upstream.git>
+		> =	refs/heads/baz:refs/heads/baz	[up to date]
+		>  	<COMMIT-B>:refs/heads/bar	<COMMIT-A>..<COMMIT-B>
+		> -	:refs/heads/foo	[deleted]
+		> +	refs/heads/main:refs/heads/main	<COMMIT-B>...<COMMIT-A> (forced update)
+		> *	refs/heads/next:refs/heads/next	[new branch]
+		> Done
+		EOF
+		test_cmp expect actual &&
+
+		git -C "$upstream" show-ref >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		cat >expect <<-EOF &&
+		<COMMIT-A> refs/heads/bar
+		<COMMIT-A> refs/heads/baz
+		<COMMIT-A> refs/heads/foo
+		<COMMIT-B> refs/heads/main
+		EOF
+		test_cmp expect actual
+	'
+
+	# Refs of upstream : main(B)  foo(A)  bar(A)  baz(A)
+	# Refs of workbench: main(A)                  baz(A)  next(A)
+	# git-push         : main(A)  NULL    (B)     baz(A)  next(A)
+	test_expect_success ".. git-push --porcelain --dry-run --atomic ($PROTOCOL)" '
+		test_must_fail git -C workbench push --porcelain --dry-run --atomic origin \
+			main \
+			:refs/heads/foo \
+			$B:bar \
+			baz \
+			next >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		format_and_save_expect <<-EOF &&
+		> To <URL/of/upstream.git>
+		> =	refs/heads/baz:refs/heads/baz	[up to date]
+		> !	<COMMIT-B>:refs/heads/bar	[rejected] (atomic push failed)
+		> !	(delete):refs/heads/foo	[rejected] (atomic push failed)
+		> !	refs/heads/main:refs/heads/main	[rejected] (non-fast-forward)
+		> !	refs/heads/next:refs/heads/next	[rejected] (atomic push failed)
+		> Done
+		EOF
+		test_cmp expect actual &&
+
+		git -C "$upstream" show-ref >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		cat >expect <<-EOF &&
+		<COMMIT-A> refs/heads/bar
+		<COMMIT-A> refs/heads/baz
+		<COMMIT-A> refs/heads/foo
+		<COMMIT-B> refs/heads/main
+		EOF
+		test_cmp expect actual
+	'
+
+	# Refs of upstream : main(B)  foo(A)  bar(A)  baz(A)
+	# Refs of workbench: main(A)                  baz(A)  next(A)
+	# push             : main(A)  NULL    (B)     baz(A)  next(A)
+	test_expect_success ".. git-push --porcelain --dry-run --atomic --force ($PROTOCOL)" '
+		git -C workbench push --porcelain --dry-run --atomic --force origin \
+			main \
+			:refs/heads/foo \
+			$B:bar \
+			baz \
+			next >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		format_and_save_expect <<-EOF &&
+		> To <URL/of/upstream.git>
+		> =	refs/heads/baz:refs/heads/baz	[up to date]
+		>  	<COMMIT-B>:refs/heads/bar	<COMMIT-A>..<COMMIT-B>
+		> -	:refs/heads/foo	[deleted]
+		> +	refs/heads/main:refs/heads/main	<COMMIT-B>...<COMMIT-A> (forced update)
+		> *	refs/heads/next:refs/heads/next	[new branch]
+		> Done
+		EOF
+		test_cmp expect actual &&
+
+		git -C "$upstream" show-ref >out &&
+		make_user_friendly_and_stable_output <out >actual &&
+		cat >expect <<-EOF &&
+		<COMMIT-A> refs/heads/bar
+		<COMMIT-A> refs/heads/baz
+		<COMMIT-A> refs/heads/foo
+		<COMMIT-B> refs/heads/main
+		EOF
+		test_cmp expect actual
+	'
+}
+
+setup_upstream_and_workbench upstream.git
+
 run_git_push_porcelain_output_test file
 
+setup_upstream_and_workbench upstream.git
+
+run_git_push_dry_run_porcelain_output_test file
+
 ROOT_PATH="$PWD"
 . "$TEST_DIRECTORY"/lib-gpg.sh
 . "$TEST_DIRECTORY"/lib-httpd.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 start_httpd
-
-# Re-initialize the upstream repository and local workbench.
-setup_upstream_and_workbench
-
-test_expect_success "setup for http" '
-	git -C upstream.git config http.receivepack true &&
-	upstream="$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" &&
-	mv upstream.git "$upstream" &&
-
-	git -C workbench remote set-url origin $HTTPD_URL/smart/upstream.git
-'
-
 setup_askpass_helper
 
-# Run git-push porcelain test on HTTP protocol
+setup_upstream_and_workbench "$HTTPD_DOCUMENT_ROOT_PATH/upstream.git"
+
 run_git_push_porcelain_output_test http
 
+setup_upstream_and_workbench "$HTTPD_DOCUMENT_ROOT_PATH/upstream.git"
+
+run_git_push_dry_run_porcelain_output_test http
+
 test_done
diff --git a/t/t5620-backfill.sh b/t/t5620-backfill.sh
new file mode 100755
index 0000000..58c8155
--- /dev/null
+++ b/t/t5620-backfill.sh
@@ -0,0 +1,211 @@
+#!/bin/sh
+
+test_description='git backfill on partial clones'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# We create objects in the 'src' repo.
+test_expect_success 'setup repo for object creation' '
+	echo "{print \$1}" >print_1.awk &&
+	echo "{print \$2}" >print_2.awk &&
+
+	git init src &&
+
+	mkdir -p src/a/b/c &&
+	mkdir -p src/d/e &&
+
+	for i in 1 2
+	do
+		for n in 1 2 3 4
+		do
+			echo "Version $i of file $n" > src/file.$n.txt &&
+			echo "Version $i of file a/$n" > src/a/file.$n.txt &&
+			echo "Version $i of file a/b/$n" > src/a/b/file.$n.txt &&
+			echo "Version $i of file a/b/c/$n" > src/a/b/c/file.$n.txt &&
+			echo "Version $i of file d/$n" > src/d/file.$n.txt &&
+			echo "Version $i of file d/e/$n" > src/d/e/file.$n.txt &&
+			git -C src add . &&
+			git -C src commit -m "Iteration $n" || return 1
+		done
+	done
+'
+
+# Clone 'src' into 'srv.bare' so we have a bare repo to be our origin
+# server for the partial clone.
+test_expect_success 'setup bare clone for server' '
+	git clone --bare "file://$(pwd)/src" srv.bare &&
+	git -C srv.bare config --local uploadpack.allowfilter 1 &&
+	git -C srv.bare config --local uploadpack.allowanysha1inwant 1
+'
+
+# do basic partial clone from "srv.bare"
+test_expect_success 'do partial clone 1, backfill gets all objects' '
+	git clone --no-checkout --filter=blob:none	\
+		--single-branch --branch=main 		\
+		"file://$(pwd)/srv.bare" backfill1 &&
+
+	# Backfill with no options gets everything reachable from HEAD.
+	GIT_TRACE2_EVENT="$(pwd)/backfill-file-trace" git \
+		-C backfill1 backfill &&
+
+	# We should have engaged the partial clone machinery
+	test_trace2_data promisor fetch_count 48 <backfill-file-trace &&
+
+	# No more missing objects!
+	git -C backfill1 rev-list --quiet --objects --missing=print HEAD >revs2 &&
+	test_line_count = 0 revs2
+'
+
+test_expect_success 'do partial clone 2, backfill min batch size' '
+	git clone --no-checkout --filter=blob:none	\
+		--single-branch --branch=main 		\
+		"file://$(pwd)/srv.bare" backfill2 &&
+
+	GIT_TRACE2_EVENT="$(pwd)/batch-trace" git \
+		-C backfill2 backfill --min-batch-size=20 &&
+
+	# Batches were used
+	test_trace2_data promisor fetch_count 20 <batch-trace >matches &&
+	test_line_count = 2 matches &&
+	test_trace2_data promisor fetch_count 8 <batch-trace &&
+
+	# No more missing objects!
+	git -C backfill2 rev-list --quiet --objects --missing=print HEAD >revs2 &&
+	test_line_count = 0 revs2
+'
+
+test_expect_success 'backfill --sparse without sparse-checkout fails' '
+	git init not-sparse &&
+	test_must_fail git -C not-sparse backfill --sparse 2>err &&
+	grep "problem loading sparse-checkout" err
+'
+
+test_expect_success 'backfill --sparse' '
+	git clone --sparse --filter=blob:none		\
+		--single-branch --branch=main 		\
+		"file://$(pwd)/srv.bare" backfill3 &&
+
+	# Initial checkout includes four files at root.
+	git -C backfill3 rev-list --quiet --objects --missing=print HEAD >missing &&
+	test_line_count = 44 missing &&
+
+	# Initial sparse-checkout is just the files at root, so we get the
+	# older versions of the four files at tip.
+	GIT_TRACE2_EVENT="$(pwd)/sparse-trace1" git \
+		-C backfill3 backfill --sparse &&
+	test_trace2_data promisor fetch_count 4 <sparse-trace1 &&
+	test_trace2_data path-walk paths 5 <sparse-trace1 &&
+	git -C backfill3 rev-list --quiet --objects --missing=print HEAD >missing &&
+	test_line_count = 40 missing &&
+
+	# Expand the sparse-checkout to include 'd' recursively. This
+	# engages the algorithm to skip the trees for 'a'. Note that
+	# the "sparse-checkout set" command downloads the objects at tip
+	# to satisfy the current checkout.
+	git -C backfill3 sparse-checkout set d &&
+	GIT_TRACE2_EVENT="$(pwd)/sparse-trace2" git \
+		-C backfill3 backfill --sparse &&
+	test_trace2_data promisor fetch_count 8 <sparse-trace2 &&
+	test_trace2_data path-walk paths 15 <sparse-trace2 &&
+	git -C backfill3 rev-list --quiet --objects --missing=print HEAD >missing &&
+	test_line_count = 24 missing &&
+
+	# Disabling the --sparse option (on by default) will download everything
+	git -C backfill3 backfill --no-sparse &&
+	git -C backfill3 rev-list --quiet --objects --missing=print HEAD >missing &&
+	test_line_count = 0 missing
+'
+
+test_expect_success 'backfill --sparse without cone mode (positive)' '
+	git clone --no-checkout --filter=blob:none		\
+		--single-branch --branch=main 		\
+		"file://$(pwd)/srv.bare" backfill4 &&
+
+	# No blobs yet
+	git -C backfill4 rev-list --quiet --objects --missing=print HEAD >missing &&
+	test_line_count = 48 missing &&
+
+	# Define sparse-checkout by filename regardless of parent directory.
+	# This downloads 6 blobs to satisfy the checkout.
+	git -C backfill4 sparse-checkout set --no-cone "**/file.1.txt" &&
+	git -C backfill4 checkout main &&
+
+	# Track new blob count
+	git -C backfill4 rev-list --quiet --objects --missing=print HEAD >missing &&
+	test_line_count = 42 missing &&
+
+	GIT_TRACE2_EVENT="$(pwd)/no-cone-trace1" git \
+		-C backfill4 backfill --sparse &&
+	test_trace2_data promisor fetch_count 6 <no-cone-trace1 &&
+
+	# This walk needed to visit all directories to search for these paths.
+	test_trace2_data path-walk paths 12 <no-cone-trace1 &&
+	git -C backfill4 rev-list --quiet --objects --missing=print HEAD >missing &&
+	test_line_count = 36 missing
+'
+
+test_expect_success 'backfill --sparse without cone mode (negative)' '
+	git clone --no-checkout --filter=blob:none		\
+		--single-branch --branch=main 		\
+		"file://$(pwd)/srv.bare" backfill5 &&
+
+	# No blobs yet
+	git -C backfill5 rev-list --quiet --objects --missing=print HEAD >missing &&
+	test_line_count = 48 missing &&
+
+	# Define sparse-checkout by filename regardless of parent directory.
+	# This downloads 18 blobs to satisfy the checkout
+	git -C backfill5 sparse-checkout set --no-cone "**/file*" "!**/file.1.txt" &&
+	git -C backfill5 checkout main &&
+
+	# Track new blob count
+	git -C backfill5 rev-list --quiet --objects --missing=print HEAD >missing &&
+	test_line_count = 30 missing &&
+
+	GIT_TRACE2_EVENT="$(pwd)/no-cone-trace2" git \
+		-C backfill5 backfill --sparse &&
+	test_trace2_data promisor fetch_count 18 <no-cone-trace2 &&
+
+	# This walk needed to visit all directories to search for these paths, plus
+	# 12 extra "file.?.txt" paths than the previous test.
+	test_trace2_data path-walk paths 24 <no-cone-trace2 &&
+	git -C backfill5 rev-list --quiet --objects --missing=print HEAD >missing &&
+	test_line_count = 12 missing
+'
+
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+test_expect_success 'create a partial clone over HTTP' '
+	SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
+	rm -rf "$SERVER" repo &&
+	git clone --bare "file://$(pwd)/src" "$SERVER" &&
+	test_config -C "$SERVER" uploadpack.allowfilter 1 &&
+	test_config -C "$SERVER" uploadpack.allowanysha1inwant 1 &&
+
+	git clone --no-checkout --filter=blob:none \
+		"$HTTPD_URL/smart/server" backfill-http
+'
+
+test_expect_success 'backfilling over HTTP succeeds' '
+	GIT_TRACE2_EVENT="$(pwd)/backfill-http-trace" git \
+		-C backfill-http backfill &&
+
+	# We should have engaged the partial clone machinery
+	test_trace2_data promisor fetch_count 48 <backfill-http-trace &&
+
+	# Confirm all objects are present, none missing.
+	git -C backfill-http rev-list --objects --all >rev-list-out &&
+	awk "{print \$1;}" <rev-list-out >oids &&
+	GIT_TRACE2_EVENT="$(pwd)/walk-trace" git -C backfill-http \
+		cat-file --batch-check <oids >batch-out &&
+	! grep missing batch-out
+'
+
+# 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.
+
+test_done
diff --git a/t/t5621-clone-revision.sh b/t/t5621-clone-revision.sh
new file mode 100755
index 0000000..db3b8cf
--- /dev/null
+++ b/t/t5621-clone-revision.sh
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+test_description='tests for git clone --revision'
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit --no-tag "initial commit" README "Hello" &&
+	test_commit --annotate "second commit" README "Hello world" v1.0 &&
+	test_commit --no-tag "third commit" README "Hello world!" &&
+	git switch -c feature v1.0 &&
+	test_commit --no-tag "feature commit" README "Hello world!" &&
+	git switch main
+'
+
+test_expect_success 'clone with --revision being a branch' '
+	test_when_finished "rm -rf dst" &&
+	git clone --revision=refs/heads/feature . dst &&
+	git rev-parse refs/heads/feature >expect &&
+	git -C dst rev-parse HEAD >actual &&
+	test_must_fail git -C dst symbolic-ref -q HEAD >/dev/null &&
+	test_cmp expect actual &&
+	git -C dst for-each-ref refs >expect &&
+	test_must_be_empty expect &&
+	test_must_fail git -C dst config remote.origin.fetch
+'
+
+test_expect_success 'clone with --depth and --revision being a branch' '
+	test_when_finished "rm -rf dst" &&
+	git clone --no-local --depth=1 --revision=refs/heads/feature . dst &&
+	git rev-parse refs/heads/feature >expect &&
+	git -C dst rev-parse HEAD >actual &&
+	test_must_fail git -C dst symbolic-ref -q HEAD >/dev/null &&
+	test_cmp expect actual &&
+	git -C dst for-each-ref refs >expect &&
+	test_must_be_empty expect &&
+	test_must_fail git -C dst config remote.origin.fetch &&
+	git -C dst rev-list HEAD >actual &&
+	test_line_count = 1 actual
+'
+
+test_expect_success 'clone with --revision being a tag' '
+	test_when_finished "rm -rf dst" &&
+	git clone --revision=refs/tags/v1.0 . dst &&
+	git rev-parse refs/tags/v1.0^{} >expect &&
+	git -C dst rev-parse HEAD >actual &&
+	test_must_fail git -C dst symbolic-ref -q HEAD >/dev/null &&
+	test_cmp expect actual &&
+	git -C dst for-each-ref refs >expect &&
+	test_must_be_empty expect &&
+	test_must_fail git -C dst config remote.origin.fetch
+'
+
+test_expect_success 'clone with --revision being HEAD' '
+	test_when_finished "rm -rf dst" &&
+	git clone --revision=HEAD . dst &&
+	git rev-parse HEAD >expect &&
+	git -C dst rev-parse HEAD >actual &&
+	test_must_fail git -C dst symbolic-ref -q HEAD >/dev/null &&
+	test_cmp expect actual &&
+	git -C dst for-each-ref refs >expect &&
+	test_must_be_empty expect &&
+	test_must_fail git -C dst config remote.origin.fetch
+'
+
+test_expect_success 'clone with --revision being a raw commit hash' '
+	test_when_finished "rm -rf dst" &&
+	oid=$(git rev-parse refs/heads/feature) &&
+	git clone --revision=$oid . dst &&
+	echo $oid >expect &&
+	git -C dst rev-parse HEAD >actual &&
+	test_must_fail git -C dst symbolic-ref -q HEAD >/dev/null &&
+	test_cmp expect actual &&
+	git -C dst for-each-ref refs >expect &&
+	test_must_be_empty expect &&
+	test_must_fail git -C dst config remote.origin.fetch
+'
+
+test_expect_success 'clone with --revision and --bare' '
+	test_when_finished "rm -rf dst" &&
+	git clone --revision=refs/heads/main --bare . dst &&
+	oid=$(git rev-parse refs/heads/main) &&
+	git -C dst cat-file -t $oid >actual &&
+	echo "commit" >expect &&
+	test_cmp expect actual &&
+	git -C dst for-each-ref refs >expect &&
+	test_must_be_empty expect &&
+	test_must_fail git -C dst config remote.origin.fetch
+'
+
+test_expect_success 'clone with --revision being a short raw commit hash' '
+	test_when_finished "rm -rf dst" &&
+	oid=$(git rev-parse --short refs/heads/feature) &&
+	test_must_fail git clone --revision=$oid . dst 2>err &&
+	test_grep "fatal: Remote revision $oid not found in upstream origin" err
+'
+
+test_expect_success 'clone with --revision being a tree hash' '
+	test_when_finished "rm -rf dst" &&
+	oid=$(git rev-parse refs/heads/feature^{tree}) &&
+	test_must_fail git clone --revision=$oid . dst 2>err &&
+	test_grep "error: object $oid is a tree, not a commit" err
+'
+
+test_expect_success 'clone with --revision being the parent of a ref fails' '
+	test_when_finished "rm -rf dst" &&
+	test_must_fail git clone --revision=refs/heads/main^ . dst
+'
+
+test_expect_success 'clone with --revision and --branch fails' '
+	test_when_finished "rm -rf dst" &&
+	test_must_fail git clone --revision=refs/heads/main --branch=main . dst
+'
+
+test_expect_success 'clone with --revision and --mirror fails' '
+	test_when_finished "rm -rf dst" &&
+	test_must_fail git clone --revision=refs/heads/main --mirror . dst
+'
+
+test_done
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index de904c1..678a346 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -7,24 +7,40 @@
 
 . ./test-lib.sh
 
-test_expect_success 'test capability advertisement' '
+test_expect_success 'setup to generate files with expected content' '
+	printf "agent=git/%s" "$(git version | cut -d" " -f3)" >agent_capability &&
+
 	test_oid_cache <<-EOF &&
 	wrong_algo sha1:sha256
 	wrong_algo sha256:sha1
 	EOF
+
+	if test_have_prereq WINDOWS
+	then
+		printf "agent=FAKE\n" >agent_capability
+	else
+		printf -- "-%s\n" $(uname -s | test_redact_non_printables) >>agent_capability
+	fi &&
 	cat >expect.base <<-EOF &&
 	version 2
-	agent=git/$(git version | cut -d" " -f3)
+	$(cat agent_capability)
 	ls-refs=unborn
 	fetch=shallow wait-for-done
 	server-option
 	object-format=$(test_oid algo)
 	EOF
-	cat >expect.trailer <<-EOF &&
+	cat >expect.trailer <<-EOF
 	0000
 	EOF
+'
+
+test_expect_success 'test capability advertisement' '
 	cat expect.base expect.trailer >expect &&
 
+	if test_have_prereq WINDOWS
+	then
+		GIT_USER_AGENT=FAKE && export GIT_USER_AGENT
+	fi &&
 	GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
 		--advertise-capabilities >out &&
 	test-tool pkt-line unpack <out >actual &&
@@ -355,6 +371,10 @@
 	    expect.extra \
 	    expect.trailer >expect &&
 
+	if test_have_prereq WINDOWS
+	then
+		GIT_USER_AGENT=FAKE && export GIT_USER_AGENT
+	fi &&
 	GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
 		--advertise-capabilities >out &&
 	test-tool pkt-line unpack <out >actual &&
diff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh
new file mode 100755
index 0000000..d2cc69a
--- /dev/null
+++ b/t/t5710-promisor-remote-capability.sh
@@ -0,0 +1,312 @@
+#!/bin/sh
+
+test_description='handling of promisor remote advertisement'
+
+. ./test-lib.sh
+
+GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
+
+# Setup the repository with three commits, this way HEAD is always
+# available and we can hide commit 1 or 2.
+test_expect_success 'setup: create "template" repository' '
+	git init template &&
+	test_commit -C template 1 &&
+	test_commit -C template 2 &&
+	test_commit -C template 3 &&
+	test-tool genrandom foo 10240 >template/foo &&
+	git -C template add foo &&
+	git -C template commit -m foo
+'
+
+# A bare repo will act as a server repo with unpacked objects.
+test_expect_success 'setup: create bare "server" repository' '
+	git clone --bare --no-local template server &&
+	mv server/objects/pack/pack-* . &&
+	packfile=$(ls pack-*.pack) &&
+	git -C server unpack-objects --strict <"$packfile"
+'
+
+check_missing_objects () {
+	git -C "$1" rev-list --objects --all --missing=print > all.txt &&
+	perl -ne 'print if s/^[?]//' all.txt >missing.txt &&
+	test_line_count = "$2" missing.txt &&
+	if test "$2" -lt 2
+	then
+		test "$3" = "$(cat missing.txt)"
+	else
+		test -f "$3" &&
+		sort <"$3" >expected_sorted &&
+		sort <missing.txt >actual_sorted &&
+		test_cmp expected_sorted actual_sorted
+	fi
+}
+
+initialize_server () {
+	count="$1"
+	missing_oids="$2"
+
+	# Repack everything first
+	git -C server -c repack.writebitmaps=false repack -a -d &&
+
+	# Remove promisor file in case they exist, useful when reinitializing
+	rm -rf server/objects/pack/*.promisor &&
+
+	# Repack without the largest object and create a promisor pack on server
+	git -C server -c repack.writebitmaps=false repack -a -d \
+	    --filter=blob:limit=5k --filter-to="$(pwd)/pack" &&
+	promisor_file=$(ls server/objects/pack/*.pack | sed "s/\.pack/.promisor/") &&
+	>"$promisor_file" &&
+
+	# Check objects missing on the server
+	check_missing_objects server "$count" "$missing_oids"
+}
+
+copy_to_lop () {
+	oid_path="$(test_oid_to_path $1)" &&
+	path="server/objects/$oid_path" &&
+	path2="lop/objects/$oid_path" &&
+	mkdir -p $(dirname "$path2") &&
+	cp "$path" "$path2"
+}
+
+test_expect_success "setup for testing promisor remote advertisement" '
+	# Create another bare repo called "lop" (for Large Object Promisor)
+	git init --bare lop &&
+
+	# Copy the largest object from server to lop
+	obj="HEAD:foo" &&
+	oid="$(git -C server rev-parse $obj)" &&
+	copy_to_lop "$oid" &&
+
+	initialize_server 1 "$oid" &&
+
+	# Configure lop as promisor remote for server
+	git -C server remote add lop "file://$(pwd)/lop" &&
+	git -C server config remote.lop.promisor true &&
+
+	git -C lop config uploadpack.allowFilter true &&
+	git -C lop config uploadpack.allowAnySHA1InWant true &&
+	git -C server config uploadpack.allowFilter true &&
+	git -C server config uploadpack.allowAnySHA1InWant true
+'
+
+test_expect_success "clone with promisor.advertise set to 'true'" '
+	git -C server config promisor.advertise true &&
+
+	# Clone from server to create a client
+	GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
+		-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
+		-c remote.lop.url="file://$(pwd)/lop" \
+		-c promisor.acceptfromserver=All \
+		--no-local --filter="blob:limit=5k" server client &&
+	test_when_finished "rm -rf client" &&
+
+	# Check that the largest object is still missing on the server
+	check_missing_objects server 1 "$oid"
+'
+
+test_expect_success "clone with promisor.advertise set to 'false'" '
+	git -C server config promisor.advertise false &&
+
+	# Clone from server to create a client
+	GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
+		-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
+		-c remote.lop.url="file://$(pwd)/lop" \
+		-c promisor.acceptfromserver=All \
+		--no-local --filter="blob:limit=5k" server client &&
+	test_when_finished "rm -rf client" &&
+
+	# Check that the largest object is not missing on the server
+	check_missing_objects server 0 "" &&
+
+	# Reinitialize server so that the largest object is missing again
+	initialize_server 1 "$oid"
+'
+
+test_expect_success "clone with promisor.acceptfromserver set to 'None'" '
+	git -C server config promisor.advertise true &&
+
+	# Clone from server to create a client
+	GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
+		-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
+		-c remote.lop.url="file://$(pwd)/lop" \
+		-c promisor.acceptfromserver=None \
+		--no-local --filter="blob:limit=5k" server client &&
+	test_when_finished "rm -rf client" &&
+
+	# Check that the largest object is not missing on the server
+	check_missing_objects server 0 "" &&
+
+	# Reinitialize server so that the largest object is missing again
+	initialize_server 1 "$oid"
+'
+
+test_expect_success "init + fetch with promisor.advertise set to 'true'" '
+	git -C server config promisor.advertise true &&
+
+	test_when_finished "rm -rf client" &&
+	mkdir client &&
+	git -C client init &&
+	git -C client config remote.lop.promisor true &&
+	git -C client config remote.lop.fetch "+refs/heads/*:refs/remotes/lop/*" &&
+	git -C client config remote.lop.url "file://$(pwd)/lop" &&
+	git -C client config remote.server.url "file://$(pwd)/server" &&
+	git -C client config remote.server.fetch "+refs/heads/*:refs/remotes/server/*" &&
+	git -C client config promisor.acceptfromserver All &&
+	GIT_NO_LAZY_FETCH=0 git -C client fetch --filter="blob:limit=5k" server &&
+
+	# Check that the largest object is still missing on the server
+	check_missing_objects server 1 "$oid"
+'
+
+test_expect_success "clone with promisor.acceptfromserver set to 'KnownName'" '
+	git -C server config promisor.advertise true &&
+
+	# Clone from server to create a client
+	GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
+		-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
+		-c remote.lop.url="file://$(pwd)/lop" \
+		-c promisor.acceptfromserver=KnownName \
+		--no-local --filter="blob:limit=5k" server client &&
+	test_when_finished "rm -rf client" &&
+
+	# Check that the largest object is still missing on the server
+	check_missing_objects server 1 "$oid"
+'
+
+test_expect_success "clone with 'KnownName' and different remote names" '
+	git -C server config promisor.advertise true &&
+
+	# Clone from server to create a client
+	GIT_NO_LAZY_FETCH=0 git clone -c remote.serverTwo.promisor=true \
+		-c remote.serverTwo.fetch="+refs/heads/*:refs/remotes/lop/*" \
+		-c remote.serverTwo.url="file://$(pwd)/lop" \
+		-c promisor.acceptfromserver=KnownName \
+		--no-local --filter="blob:limit=5k" server client &&
+	test_when_finished "rm -rf client" &&
+
+	# Check that the largest object is not missing on the server
+	check_missing_objects server 0 "" &&
+
+	# Reinitialize server so that the largest object is missing again
+	initialize_server 1 "$oid"
+'
+
+test_expect_success "clone with promisor.acceptfromserver set to 'KnownUrl'" '
+	git -C server config promisor.advertise true &&
+
+	# Clone from server to create a client
+	GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
+		-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
+		-c remote.lop.url="file://$(pwd)/lop" \
+		-c promisor.acceptfromserver=KnownUrl \
+		--no-local --filter="blob:limit=5k" server client &&
+	test_when_finished "rm -rf client" &&
+
+	# Check that the largest object is still missing on the server
+	check_missing_objects server 1 "$oid"
+'
+
+test_expect_success "clone with 'KnownUrl' and different remote urls" '
+	ln -s lop serverTwo &&
+
+	git -C server config promisor.advertise true &&
+
+	# Clone from server to create a client
+	GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
+		-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
+		-c remote.lop.url="file://$(pwd)/serverTwo" \
+		-c promisor.acceptfromserver=KnownUrl \
+		--no-local --filter="blob:limit=5k" server client &&
+	test_when_finished "rm -rf client" &&
+
+	# Check that the largest object is not missing on the server
+	check_missing_objects server 0 "" &&
+
+	# Reinitialize server so that the largest object is missing again
+	initialize_server 1 "$oid"
+'
+
+test_expect_success "clone with promisor.advertise set to 'true' but don't delete the client" '
+	git -C server config promisor.advertise true &&
+
+	# Clone from server to create a client
+	GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
+		-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
+		-c remote.lop.url="file://$(pwd)/lop" \
+		-c promisor.acceptfromserver=All \
+		--no-local --filter="blob:limit=5k" server client &&
+
+	# Check that the largest object is still missing on the server
+	check_missing_objects server 1 "$oid"
+'
+
+test_expect_success "setup for subsequent fetches" '
+	# Generate new commit with large blob
+	test-tool genrandom bar 10240 >template/bar &&
+	git -C template add bar &&
+	git -C template commit -m bar &&
+
+	# Fetch new commit with large blob
+	git -C server fetch origin &&
+	git -C server update-ref HEAD FETCH_HEAD &&
+	git -C server rev-parse HEAD >expected_head &&
+
+	# Repack everything twice and remove .promisor files before
+	# each repack. This makes sure everything gets repacked
+	# into a single packfile. The second repack is necessary
+	# because the first one fetches from lop and creates a new
+	# packfile and its associated .promisor file.
+
+	rm -f server/objects/pack/*.promisor &&
+	git -C server -c repack.writebitmaps=false repack -a -d &&
+	rm -f server/objects/pack/*.promisor &&
+	git -C server -c repack.writebitmaps=false repack -a -d &&
+
+	# Unpack everything
+	rm pack-* &&
+	mv server/objects/pack/pack-* . &&
+	packfile=$(ls pack-*.pack) &&
+	git -C server unpack-objects --strict <"$packfile" &&
+
+	# Copy new large object to lop
+	obj_bar="HEAD:bar" &&
+	oid_bar="$(git -C server rev-parse $obj_bar)" &&
+	copy_to_lop "$oid_bar" &&
+
+	# Reinitialize server so that the 2 largest objects are missing
+	printf "%s\n" "$oid" "$oid_bar" >expected_missing.txt &&
+	initialize_server 2 expected_missing.txt &&
+
+	# Create one more client
+	cp -r client client2
+'
+
+test_expect_success "subsequent fetch from a client when promisor.advertise is true" '
+	git -C server config promisor.advertise true &&
+
+	GIT_NO_LAZY_FETCH=0 git -C client pull origin &&
+
+	git -C client rev-parse HEAD >actual &&
+	test_cmp expected_head actual &&
+
+	cat client/bar >/dev/null &&
+
+	check_missing_objects server 2 expected_missing.txt
+'
+
+test_expect_success "subsequent fetch from a client when promisor.advertise is false" '
+	git -C server config promisor.advertise false &&
+
+	GIT_NO_LAZY_FETCH=0 git -C client2 pull origin &&
+
+	git -C client2 rev-parse HEAD >actual &&
+	test_cmp expected_head actual &&
+
+	cat client2/bar >/dev/null &&
+
+	check_missing_objects server 1 "$oid"
+'
+
+test_done
diff --git a/t/t6012-rev-list-simplify.sh b/t/t6012-rev-list-simplify.sh
index de1e87f..4cecb62 100755
--- a/t/t6012-rev-list-simplify.sh
+++ b/t/t6012-rev-list-simplify.sh
@@ -177,7 +177,7 @@
 #   \ /      /\        /
 #    `---X--'  `---Y--'
 #
-# This example is explained in Documentation/rev-list-options.txt
+# This example is explained in Documentation/rev-list-options.adoc
 
 test_expect_success 'setup rebuild repo' '
 	rm -rf .git * &&
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index 4ce62fe..b3807e8 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -246,7 +246,11 @@
 	EOF
 	test_cmp expect actual &&
 
-	git bundle create since.bdl \
+	# If a different name hash function is used, then one fewer
+	# delta base is found and this counts a different number
+	# of objects after performing --fix-thin.
+	GIT_TEST_NAME_HASH_VERSION=1 \
+		git bundle create since.bdl \
 		--since "Thu Apr 7 15:27:00 2005 -0700" \
 		--all &&
 
diff --git a/t/t6022-rev-list-missing.sh b/t/t6022-rev-list-missing.sh
index 7553a9c..3e2790d 100755
--- a/t/t6022-rev-list-missing.sh
+++ b/t/t6022-rev-list-missing.sh
@@ -145,4 +145,57 @@
 	done
 done
 
+for obj in "HEAD~1" "HEAD^{tree}" "HEAD:foo" "HEAD:foo/bar" "HEAD:baz baz"
+do
+	test_expect_success "--missing=print-info with missing '$obj'" '
+		test_when_finished rm -rf missing-info &&
+
+		git init missing-info &&
+		(
+			cd missing-info &&
+			git commit --allow-empty -m first &&
+
+			mkdir foo &&
+			echo bar >foo/bar &&
+			echo baz >"baz baz" &&
+			echo bat >bat\" &&
+			git add -A &&
+			git commit -m second &&
+
+			oid="$(git rev-parse "$obj")" &&
+			path=".git/objects/$(test_oid_to_path $oid)" &&
+			type_info=" type=$(git cat-file -t $oid)" &&
+
+			case $obj in
+			HEAD:foo)
+				path_info=" path=foo"
+				;;
+			HEAD:foo/bar)
+				path_info=" path=foo/bar"
+				;;
+			"HEAD:baz baz")
+				path_info=" path=\"baz baz\""
+				;;
+			"HEAD:bat\"")
+				path_info=" path=\"bat\\\"\""
+				;;
+			esac &&
+
+			# Before the object is made missing, we use rev-list to
+			# get the expected oids.
+			git rev-list --objects --no-object-names \
+				HEAD ^"$obj" >expect.raw &&
+			echo "?$oid$path_info$type_info" >>expect.raw &&
+
+			mv "$path" "$path.hidden" &&
+			git rev-list --objects --no-object-names \
+				--missing=print-info HEAD >actual.raw &&
+
+			sort actual.raw >actual &&
+			sort expect.raw >expect &&
+			test_cmp expect actual
+		)
+	'
+done
+
 test_done
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 3f6160d..76843a6 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -82,11 +82,13 @@
 check_describe A-3-gHASH HEAD^^2
 check_describe B HEAD^^2^
 check_describe R-1-gHASH HEAD^^^
+check_describe R-1-gHASH R-1-g$(git rev-parse --short HEAD^^)~1
 
 check_describe c-7-gHASH --tags HEAD
 check_describe c-6-gHASH --tags HEAD^
 check_describe e-1-gHASH --tags HEAD^^
 check_describe c-2-gHASH --tags HEAD^^2
+check_describe c-2-gHASH --tags c-2-g$(git rev-parse --short HEAD^^2)^0
 check_describe B --tags HEAD^^2^
 check_describe e --tags HEAD^^^
 check_describe e --tags --exact-match HEAD^^^
@@ -725,4 +727,26 @@
 	test_must_fail git describe --exact-match --always
 '
 
+test_expect_success 'avoid being fooled by describe-like filename' '
+	test_when_finished rm out &&
+
+	git rev-parse --short HEAD >out &&
+	FILENAME=filename-g$(cat out) &&
+	touch $FILENAME &&
+	git add $FILENAME &&
+	git commit -m "Add $FILENAME" &&
+
+	git cat-file -t HEAD:$FILENAME >actual &&
+
+	echo blob >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'do not be fooled by invalid describe format ' '
+	test_when_finished rm out &&
+
+	git rev-parse --short HEAD >out &&
+	test_must_fail git cat-file -t "refs/tags/super-invalid/./../...../ ~^:/?*[////\\\\\\&}/busted.lock-42-g"$(cat out)
+'
+
 test_done
diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh
index 88d1cf2..94080c6 100755
--- a/t/t6423-merge-rename-directories.sh
+++ b/t/t6423-merge-rename-directories.sh
@@ -5071,7 +5071,8 @@
 		test_path_is_file source/bar &&
 		test_path_is_file source/baz &&
 
-		git ls-files | uniq >tracked &&
+		git ls-files >actual &&
+		uniq <actual >tracked &&
 		test_line_count = 3 tracked &&
 
 		git status --porcelain -uno >actual &&
@@ -5129,7 +5130,8 @@
 		test_path_is_file bar &&
 		test_path_is_file baz &&
 
-		git ls-files | uniq >tracked &&
+		git ls-files >actual &&
+		uniq <actual >tracked &&
 		test_line_count = 3 tracked &&
 
 		git status --porcelain -uno >actual &&
@@ -5187,7 +5189,8 @@
 		test_path_is_file dirA/bar &&
 		test_path_is_file dirA/baz &&
 
-		git ls-files | uniq >tracked &&
+		git ls-files >actual &&
+		uniq <actual >tracked &&
 		test_line_count = 3 tracked &&
 
 		git status --porcelain -uno >actual &&
diff --git a/t/t6434-merge-recursive-rename-options.sh b/t/t6434-merge-recursive-rename-options.sh
index a117078..6e913c3 100755
--- a/t/t6434-merge-recursive-rename-options.sh
+++ b/t/t6434-merge-recursive-rename-options.sh
@@ -22,7 +22,7 @@
 R100    3-old   3-new
 
 Actual similarity indices are parsed from diff output. We rely on the fact that
-they are rounded down (see, e.g., Documentation/diff-generate-patch.txt, which
+they are rounded down (see, e.g., Documentation/diff-generate-patch.adoc, which
 mentions this in a different context).
 '
 
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index 5378455..bef472c 100755
--- a/t/t6500-gc.sh
+++ b/t/t6500-gc.sh
@@ -338,6 +338,39 @@
 	test_subcommand $cruft_max_size_opts --max-cruft-size=3145728 <trace2.txt
 '
 
+test_expect_success '--expire-to sets repack --expire-to' '
+	rm -rf expired &&
+	mkdir expired &&
+	expire_to="$(pwd)/expired/pack" &&
+	GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --cruft --expire-to="$expire_to" &&
+	test_subcommand $cruft_max_size_opts --expire-to="$expire_to" <trace2.txt
+'
+
+test_expect_success '--expire-to with --prune=now sets repack --expire-to' '
+	rm -rf expired &&
+	mkdir expired &&
+	expire_to="$(pwd)/expired/pack" &&
+	GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --cruft --prune=now --expire-to="$expire_to" &&
+	test_subcommand git repack -d -l --cruft --cruft-expiration=now --expire-to="$expire_to" <trace2.txt
+'
+
+
+test_expect_success '--expire-to with --no-cruft sets repack -A' '
+	rm -rf expired &&
+	mkdir expired &&
+	expire_to="$(pwd)/expired/pack" &&
+	GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --no-cruft --expire-to="$expire_to" &&
+	test_subcommand git repack -d -l -A --unpack-unreachable=2.weeks.ago <trace2.txt
+'
+
+test_expect_success '--expire-to with --no-cruft sets repack -a' '
+	rm -rf expired &&
+	mkdir expired &&
+	expire_to="$(pwd)/expired/pack" &&
+	GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --no-cruft --prune=now --expire-to="$expire_to" &&
+	test_subcommand git repack -d -l -a <trace2.txt
+'
+
 run_and_wait_for_gc () {
 	# We read stdout from gc for the side effect of waiting until the
 	# background gc process exits, closing its fd 9.  Furthermore, the
diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh
index 2591f8b..6638d1a 100755
--- a/t/t6600-test-reach.sh
+++ b/t/t6600-test-reach.sh
@@ -733,4 +733,33 @@
 		--format="%(refname)[%(is-base:commit-2-3)-%(is-base:commit-6-5)]" --stdin
 '
 
+test_expect_success 'for-each-ref is-base: --sort' '
+	cat >input <<-\EOF &&
+	refs/heads/commit-1-1
+	refs/heads/commit-4-2
+	refs/heads/commit-4-4
+	refs/heads/commit-8-4
+	EOF
+
+	cat >expect <<-\EOF &&
+	refs/heads/commit-1-1
+	refs/heads/commit-4-4
+	refs/heads/commit-8-4
+	refs/heads/commit-4-2
+	EOF
+	run_all_modes git for-each-ref \
+		--format="%(refname)" --stdin \
+		--sort=refname --sort=is-base:commit-2-3 &&
+
+	cat >expect <<-\EOF &&
+	refs/heads/commit-4-2
+	refs/heads/commit-1-1
+	refs/heads/commit-4-4
+	refs/heads/commit-8-4
+	EOF
+	run_all_modes git for-each-ref \
+		--format="%(refname)" --stdin \
+		--sort=refname --sort=-is-base:commit-2-3
+'
+
 test_done
diff --git a/t/t6601-path-walk.sh b/t/t6601-path-walk.sh
new file mode 100755
index 0000000..c89b0f1
--- /dev/null
+++ b/t/t6601-path-walk.sh
@@ -0,0 +1,400 @@
+#!/bin/sh
+
+TEST_PASSES_SANITIZE_LEAK=true
+
+test_description='direct path-walk API tests'
+
+. ./test-lib.sh
+
+test_expect_success 'setup test repository' '
+	git checkout -b base &&
+
+	# Make some objects that will only be reachable
+	# via non-commit tags.
+	mkdir child &&
+	echo file >child/file &&
+	git add child &&
+	git commit -m "will abandon" &&
+	git tag -a -m "tree" tree-tag HEAD^{tree} &&
+	echo file2 >file2 &&
+	git add file2 &&
+	git commit --amend -m "will abandon" &&
+	git tag tree-tag2 HEAD^{tree} &&
+
+	echo blob >file &&
+	blob_oid=$(git hash-object -t blob -w --stdin <file) &&
+	git tag -a -m "blob" blob-tag "$blob_oid" &&
+	echo blob2 >file2 &&
+	blob2_oid=$(git hash-object -t blob -w --stdin <file2) &&
+	git tag blob-tag2 "$blob2_oid" &&
+
+	rm -fr child file file2 &&
+
+	mkdir left &&
+	mkdir right &&
+	echo a >a &&
+	echo b >left/b &&
+	echo c >right/c &&
+	git add . &&
+	git commit --amend -m "first" &&
+	git tag -m "first" first HEAD &&
+
+	echo d >right/d &&
+	git add right &&
+	git commit -m "second" &&
+	git tag -a -m "second (under)" second.1 HEAD &&
+	git tag -a -m "second (top)" second.2 second.1 &&
+
+	# Set up file/dir collision in history.
+	rm a &&
+	mkdir a &&
+	echo a >a/a &&
+	echo bb >left/b &&
+	git add a left &&
+	git commit -m "third" &&
+	git tag -a -m "third" third &&
+
+	git checkout -b topic HEAD~1 &&
+	echo cc >right/c &&
+	git commit -a -m "topic" &&
+	git tag -a -m "fourth" fourth
+'
+
+test_expect_success 'all' '
+	test-tool path-walk -- --all >out &&
+
+	cat >expect <<-EOF &&
+	0:commit::$(git rev-parse topic)
+	0:commit::$(git rev-parse base)
+	0:commit::$(git rev-parse base~1)
+	0:commit::$(git rev-parse base~2)
+	1:tag:/tags:$(git rev-parse refs/tags/first)
+	1:tag:/tags:$(git rev-parse refs/tags/second.1)
+	1:tag:/tags:$(git rev-parse refs/tags/second.2)
+	1:tag:/tags:$(git rev-parse refs/tags/third)
+	1:tag:/tags:$(git rev-parse refs/tags/fourth)
+	1:tag:/tags:$(git rev-parse refs/tags/tree-tag)
+	1:tag:/tags:$(git rev-parse refs/tags/blob-tag)
+	2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag^{})
+	2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
+	3:tree::$(git rev-parse topic^{tree})
+	3:tree::$(git rev-parse base^{tree})
+	3:tree::$(git rev-parse base~1^{tree})
+	3:tree::$(git rev-parse base~2^{tree})
+	3:tree::$(git rev-parse refs/tags/tree-tag^{})
+	3:tree::$(git rev-parse refs/tags/tree-tag2^{})
+	4:blob:a:$(git rev-parse base~2:a)
+	5:blob:file2:$(git rev-parse refs/tags/tree-tag2^{}:file2)
+	6:tree:a/:$(git rev-parse base:a)
+	7:tree:child/:$(git rev-parse refs/tags/tree-tag:child)
+	8:blob:child/file:$(git rev-parse refs/tags/tree-tag:child/file)
+	9:tree:left/:$(git rev-parse base:left)
+	9:tree:left/:$(git rev-parse base~2:left)
+	10:blob:left/b:$(git rev-parse base~2:left/b)
+	10:blob:left/b:$(git rev-parse base:left/b)
+	11:tree:right/:$(git rev-parse topic:right)
+	11:tree:right/:$(git rev-parse base~1:right)
+	11:tree:right/:$(git rev-parse base~2:right)
+	12:blob:right/c:$(git rev-parse base~2:right/c)
+	12:blob:right/c:$(git rev-parse topic:right/c)
+	13:blob:right/d:$(git rev-parse base~1:right/d)
+	blobs:10
+	commits:4
+	tags:7
+	trees:13
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'indexed objects' '
+	test_when_finished git reset --hard &&
+
+	# stage change into index, adding a blob but
+	# also invalidating the cache-tree for the root
+	# and the "left" directory.
+	echo bogus >left/c &&
+	git add left &&
+
+	test-tool path-walk -- --indexed-objects >out &&
+
+	cat >expect <<-EOF &&
+	0:blob:a:$(git rev-parse HEAD:a)
+	1:blob:left/b:$(git rev-parse HEAD:left/b)
+	2:blob:left/c:$(git rev-parse :left/c)
+	3:blob:right/c:$(git rev-parse HEAD:right/c)
+	4:blob:right/d:$(git rev-parse HEAD:right/d)
+	5:tree:right/:$(git rev-parse topic:right)
+	blobs:5
+	commits:0
+	tags:0
+	trees:1
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'branches and indexed objects mix well' '
+	test_when_finished git reset --hard &&
+
+	# stage change into index, adding a blob but
+	# also invalidating the cache-tree for the root
+	# and the "right" directory.
+	echo fake >right/d &&
+	git add right &&
+
+	test-tool path-walk -- --indexed-objects --branches >out &&
+
+	cat >expect <<-EOF &&
+	0:commit::$(git rev-parse topic)
+	0:commit::$(git rev-parse base)
+	0:commit::$(git rev-parse base~1)
+	0:commit::$(git rev-parse base~2)
+	1:tree::$(git rev-parse topic^{tree})
+	1:tree::$(git rev-parse base^{tree})
+	1:tree::$(git rev-parse base~1^{tree})
+	1:tree::$(git rev-parse base~2^{tree})
+	2:tree:a/:$(git rev-parse refs/tags/third:a)
+	3:tree:left/:$(git rev-parse base:left)
+	3:tree:left/:$(git rev-parse base~2:left)
+	4:blob:left/b:$(git rev-parse base:left/b)
+	4:blob:left/b:$(git rev-parse base~2:left/b)
+	5:tree:right/:$(git rev-parse topic:right)
+	5:tree:right/:$(git rev-parse base~1:right)
+	5:tree:right/:$(git rev-parse base~2:right)
+	6:blob:right/c:$(git rev-parse base~2:right/c)
+	6:blob:right/c:$(git rev-parse topic:right/c)
+	7:blob:right/d:$(git rev-parse base~1:right/d)
+	7:blob:right/d:$(git rev-parse :right/d)
+	8:blob:a:$(git rev-parse base~2:a)
+	blobs:7
+	commits:4
+	tags:0
+	trees:10
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'base & topic, sparse' '
+	cat >patterns <<-EOF &&
+	/*
+	!/*/
+	/left/
+	EOF
+
+	test-tool path-walk --stdin-pl -- base topic <patterns >out &&
+
+	cat >expect <<-EOF &&
+	0:commit::$(git rev-parse topic)
+	0:commit::$(git rev-parse base)
+	0:commit::$(git rev-parse base~1)
+	0:commit::$(git rev-parse base~2)
+	1:tree::$(git rev-parse topic^{tree})
+	1:tree::$(git rev-parse base^{tree})
+	1:tree::$(git rev-parse base~1^{tree})
+	1:tree::$(git rev-parse base~2^{tree})
+	2:blob:a:$(git rev-parse base~2:a)
+	3:tree:left/:$(git rev-parse base:left)
+	3:tree:left/:$(git rev-parse base~2:left)
+	4:blob:left/b:$(git rev-parse base~2:left/b)
+	4:blob:left/b:$(git rev-parse base:left/b)
+	blobs:3
+	commits:4
+	tags:0
+	trees:6
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'topic only' '
+	test-tool path-walk -- topic >out &&
+
+	cat >expect <<-EOF &&
+	0:commit::$(git rev-parse topic)
+	0:commit::$(git rev-parse base~1)
+	0:commit::$(git rev-parse base~2)
+	1:tree::$(git rev-parse topic^{tree})
+	1:tree::$(git rev-parse base~1^{tree})
+	1:tree::$(git rev-parse base~2^{tree})
+	2:blob:a:$(git rev-parse base~2:a)
+	3:tree:left/:$(git rev-parse base~2:left)
+	4:blob:left/b:$(git rev-parse base~2:left/b)
+	5:tree:right/:$(git rev-parse topic:right)
+	5:tree:right/:$(git rev-parse base~1:right)
+	5:tree:right/:$(git rev-parse base~2:right)
+	6:blob:right/c:$(git rev-parse base~2:right/c)
+	6:blob:right/c:$(git rev-parse topic:right/c)
+	7:blob:right/d:$(git rev-parse base~1:right/d)
+	blobs:5
+	commits:3
+	tags:0
+	trees:7
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'topic, not base' '
+	test-tool path-walk -- topic --not base >out &&
+
+	cat >expect <<-EOF &&
+	0:commit::$(git rev-parse topic)
+	1:tree::$(git rev-parse topic^{tree})
+	2:blob:a:$(git rev-parse topic:a):UNINTERESTING
+	3:tree:left/:$(git rev-parse topic:left):UNINTERESTING
+	4:blob:left/b:$(git rev-parse topic:left/b):UNINTERESTING
+	5:tree:right/:$(git rev-parse topic:right)
+	6:blob:right/c:$(git rev-parse topic:right/c)
+	7:blob:right/d:$(git rev-parse topic:right/d):UNINTERESTING
+	blobs:4
+	commits:1
+	tags:0
+	trees:3
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'fourth, blob-tag2, not base' '
+	test-tool path-walk -- fourth blob-tag2 --not base >out &&
+
+	cat >expect <<-EOF &&
+	0:commit::$(git rev-parse topic)
+	1:tag:/tags:$(git rev-parse fourth)
+	2:blob:/tagged-blobs:$(git rev-parse refs/tags/blob-tag2^{})
+	3:tree::$(git rev-parse topic^{tree})
+	4:blob:a:$(git rev-parse base~1:a):UNINTERESTING
+	5:tree:left/:$(git rev-parse base~1:left):UNINTERESTING
+	6:blob:left/b:$(git rev-parse base~1:left/b):UNINTERESTING
+	7:tree:right/:$(git rev-parse topic:right)
+	8:blob:right/c:$(git rev-parse topic:right/c)
+	9:blob:right/d:$(git rev-parse base~1:right/d):UNINTERESTING
+	blobs:5
+	commits:1
+	tags:1
+	trees:3
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'topic, not base, only blobs' '
+	test-tool path-walk --no-trees --no-commits \
+		-- topic --not base >out &&
+
+	cat >expect <<-EOF &&
+	0:blob:a:$(git rev-parse topic:a):UNINTERESTING
+	1:blob:left/b:$(git rev-parse topic:left/b):UNINTERESTING
+	2:blob:right/c:$(git rev-parse topic:right/c)
+	3:blob:right/d:$(git rev-parse topic:right/d):UNINTERESTING
+	blobs:4
+	commits:0
+	tags:0
+	trees:0
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+# No, this doesn't make a lot of sense for the path-walk API,
+# but it is possible to do.
+test_expect_success 'topic, not base, only commits' '
+	test-tool path-walk --no-blobs --no-trees \
+		-- topic --not base >out &&
+
+	cat >expect <<-EOF &&
+	0:commit::$(git rev-parse topic)
+	commits:1
+	blobs:0
+	tags:0
+	trees:0
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'topic, not base, only trees' '
+	test-tool path-walk --no-blobs --no-commits \
+		-- topic --not base >out &&
+
+	cat >expect <<-EOF &&
+	0:tree::$(git rev-parse topic^{tree})
+	1:tree:left/:$(git rev-parse topic:left):UNINTERESTING
+	2:tree:right/:$(git rev-parse topic:right)
+	commits:0
+	blobs:0
+	tags:0
+	trees:3
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'topic, not base, boundary' '
+	test-tool path-walk -- --boundary topic --not base >out &&
+
+	cat >expect <<-EOF &&
+	0:commit::$(git rev-parse topic)
+	0:commit::$(git rev-parse base~1):UNINTERESTING
+	1:tree::$(git rev-parse topic^{tree})
+	1:tree::$(git rev-parse base~1^{tree}):UNINTERESTING
+	2:blob:a:$(git rev-parse base~1:a):UNINTERESTING
+	3:tree:left/:$(git rev-parse base~1:left):UNINTERESTING
+	4:blob:left/b:$(git rev-parse base~1:left/b):UNINTERESTING
+	5:tree:right/:$(git rev-parse topic:right)
+	5:tree:right/:$(git rev-parse base~1:right):UNINTERESTING
+	6:blob:right/c:$(git rev-parse base~1:right/c):UNINTERESTING
+	6:blob:right/c:$(git rev-parse topic:right/c)
+	7:blob:right/d:$(git rev-parse base~1:right/d):UNINTERESTING
+	blobs:5
+	commits:2
+	tags:0
+	trees:5
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'topic, not base, boundary with pruning' '
+	test-tool path-walk --prune -- --boundary topic --not base >out &&
+
+	cat >expect <<-EOF &&
+	0:commit::$(git rev-parse topic)
+	0:commit::$(git rev-parse base~1):UNINTERESTING
+	1:tree::$(git rev-parse topic^{tree})
+	1:tree::$(git rev-parse base~1^{tree}):UNINTERESTING
+	2:tree:right/:$(git rev-parse topic:right)
+	2:tree:right/:$(git rev-parse base~1:right):UNINTERESTING
+	3:blob:right/c:$(git rev-parse base~1:right/c):UNINTERESTING
+	3:blob:right/c:$(git rev-parse topic:right/c)
+	blobs:2
+	commits:2
+	tags:0
+	trees:4
+	EOF
+
+	test_cmp_sorted expect out
+'
+
+test_expect_success 'trees are reported exactly once' '
+	test_when_finished "rm -rf unique-trees" &&
+	test_create_repo unique-trees &&
+	(
+		cd unique-trees &&
+		mkdir initial &&
+		test_commit initial/file &&
+		git switch -c move-to-top &&
+		git mv initial/file.t ./ &&
+		test_tick &&
+		git commit -m moved &&
+		git update-ref refs/heads/other HEAD
+	) &&
+	test-tool -C unique-trees path-walk -- --all >out &&
+	tree=$(git -C unique-trees rev-parse HEAD:) &&
+	grep "$tree" out >out-filtered &&
+	test_line_count = 1 out-filtered
+'
+
+test_done
diff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh
index 61669a2..9a33507 100755
--- a/t/t7110-reset-merge.sh
+++ b/t/t7110-reset-merge.sh
@@ -270,13 +270,13 @@
 	git reset --hard third &&
 	rm -f file2 &&
 	test_must_fail git merge branch3 &&
-	! test -f file2 &&
-	test -f file3 &&
+	test_path_is_missing file2 &&
+	test_path_is_file file3 &&
 	git diff --exit-code file3 &&
 	git diff --exit-code branch3 file3 &&
 	git reset --merge HEAD &&
-	! test -f file3 &&
-	! test -f file2 &&
+	test_path_is_missing file3 &&
+	test_path_is_missing file2 &&
 	git diff --exit-code --cached
 '
 
@@ -284,8 +284,8 @@
 	git reset --hard third &&
 	rm -f file2 &&
 	test_must_fail git merge branch3 &&
-	! test -f file2 &&
-	test -f file3 &&
+	test_path_is_missing file2 &&
+	test_path_is_file file3 &&
 	git diff --exit-code file3 &&
 	git diff --exit-code branch3 file3 &&
 	test_must_fail git reset --keep HEAD 2>err.log &&
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 297c6c3..c562bad 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -1093,7 +1093,9 @@
 	) &&
 	git clone super4 super5 &&
 	(cd super5 &&
-	 git submodule update --quiet --init --depth=1 submodule3 >out 2>err &&
+	 # This test var can mess with the stderr output checked in this test.
+	 GIT_TEST_NAME_HASH_VERSION=1 \
+		git submodule update --quiet --init --depth=1 submodule3 >out 2>err &&
 	 test_must_be_empty out &&
 	 test_must_be_empty err
 	) &&
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 8d7b234..77b6d00 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -426,14 +426,14 @@
 		git submodule foreach "echo be --quiet" > ../expected &&
 		git submodule foreach echo be --quiet > ../actual
 	) &&
-	grep -sq -e "--quiet" expected &&
+	test_grep -e "--quiet" expected &&
 	test_cmp expected actual
 '
 
 test_expect_success 'option-like arguments passed to foreach recurse correctly' '
 	git -C clone2 submodule foreach --recursive "echo be --an-option" >expect &&
 	git -C clone2 submodule foreach --recursive echo be --an-option >actual &&
-	grep -e "--an-option" expect &&
+	test_grep -e "--an-option" expect &&
 	test_cmp expect actual
 '
 
diff --git a/t/t7422-submodule-output.sh b/t/t7422-submodule-output.sh
index f21e920..023a5cb 100755
--- a/t/t7422-submodule-output.sh
+++ b/t/t7422-submodule-output.sh
@@ -167,10 +167,45 @@
 done
 
 test_expect_success !MINGW 'git submodule status --recursive propagates SIGPIPE' '
-	{ git submodule status --recursive 2>err; echo $?>status; } |
-		grep -q X/S &&
-	test_must_be_empty err &&
-	test_match_signal 13 "$(cat status)"
+	# The test setup is somewhat involved because triggering a SIGPIPE is
+	# racy with buffered pipes. To avoid the raciness we thus need to make
+	# sure that the subprocess in question fills the buffers completely,
+	# which requires a couple thousand submodules in total.
+	test_when_finished "rm -rf submodule repo" &&
+	git init submodule &&
+	(
+		cd submodule &&
+		test_commit initial &&
+
+		COMMIT=$(git rev-parse HEAD) &&
+		for i in $(test_seq 2000)
+		do
+			printf "[submodule \"sm-$i\"]\npath = recursive-submodule-path-$i\n" "$i" ||
+			return 1
+		done >gitmodules &&
+		BLOB=$(git hash-object -w --stdin <gitmodules) &&
+
+		printf "100644 blob $BLOB\t.gitmodules\n" >tree &&
+		for i in $(test_seq 2000)
+		do
+			printf "160000 commit $COMMIT\trecursive-submodule-path-%d\n" "$i" ||
+			return 1
+		done >>tree &&
+		TREE=$(git mktree <tree) &&
+
+		COMMIT=$(git commit-tree "$TREE") &&
+		git reset --hard "$COMMIT"
+	) &&
+
+	git init repo &&
+	(
+		cd repo &&
+		GIT_ALLOW_PROTOCOL=file git submodule add "$(pwd)"/../submodule &&
+		{ git submodule status --recursive 2>err; echo $?>status; } |
+			grep -q recursive-submodule-path-1 &&
+		test_must_be_empty err &&
+		test_match_signal 13 "$(cat status)"
+	)
 '
 
 test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index ef54cff..2a8df29 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -173,7 +173,7 @@
 		cd broken &&
 		git init &&
 		>.git/index &&
-		test_expect_code 129 git merge -h 2>usage
+		test_expect_code 129 git merge -h >usage
 	) &&
 	test_grep "[Uu]sage: git merge" broken/usage
 '
diff --git a/t/t7603-merge-reduce-heads.sh b/t/t7603-merge-reduce-heads.sh
index 4887ca7..1f8c3b7 100755
--- a/t/t7603-merge-reduce-heads.sh
+++ b/t/t7603-merge-reduce-heads.sh
@@ -52,12 +52,12 @@
 	test "$(git rev-parse c3)" = "$(git rev-parse HEAD^3)" &&
 	test "$(git rev-parse c5)" = "$(git rev-parse HEAD^4)" &&
 	git diff --exit-code &&
-	test -f c0.c &&
-	test -f c1.c &&
-	test -f c2.c &&
-	test -f c3.c &&
-	test -f c4.c &&
-	test -f c5.c &&
+	test_path_is_file c0.c &&
+	test_path_is_file c1.c &&
+	test_path_is_file c2.c &&
+	test_path_is_file c3.c &&
+	test_path_is_file c4.c &&
+	test_path_is_file c5.c &&
 	git show --format=%s -s >actual &&
 	! grep c1 actual &&
 	grep c2 actual &&
@@ -75,12 +75,12 @@
 	test "$(git rev-parse c3)" = "$(git rev-parse HEAD^3)" &&
 	test "$(git rev-parse c5)" = "$(git rev-parse HEAD^4)" &&
 	git diff --exit-code &&
-	test -f c0.c &&
-	test -f c1.c &&
-	test -f c2.c &&
-	test -f c3.c &&
-	test -f c4.c &&
-	test -f c5.c &&
+	test_path_is_file c0.c &&
+	test_path_is_file c1.c &&
+	test_path_is_file c2.c &&
+	test_path_is_file c3.c &&
+	test_path_is_file c4.c &&
+	test_path_is_file c5.c &&
 	git show --format=%s -s >actual &&
 	! grep c1 actual &&
 	grep c2 actual &&
diff --git a/t/t7609-mergetool--lib.sh b/t/t7609-mergetool--lib.sh
index e8e2057..af3ad28 100755
--- a/t/t7609-mergetool--lib.sh
+++ b/t/t7609-mergetool--lib.sh
@@ -7,7 +7,7 @@
 . ./test-lib.sh
 
 test_expect_success 'mergetool --tool=vimdiff creates the expected layout' '
-	. "$GIT_TEST_MERGE_TOOLS_DIR"/vimdiff &&
+	. "$GIT_SOURCE_DIR"/mergetools/vimdiff &&
 	run_unit_tests
 '
 
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index be1188e..611755c 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -308,7 +308,10 @@
 	keep=${pack%.pack}.keep &&
 	test_when_finished "rm -f \"\$keep\"" &&
 	>"$keep" &&
-	git -C bare.git repack -ad 2>stderr &&
+
+	# Disable --name-hash-version test due to stderr comparison.
+	GIT_TEST_NAME_HASH_VERSION=1 \
+		git -C bare.git repack -ad 2>stderr &&
 	test_must_be_empty stderr &&
 	find bare.git/objects/pack/ -type f -name "*.bitmap" >actual &&
 	test_must_be_empty actual
@@ -319,7 +322,10 @@
 	blob=$(test-tool genrandom big $((1024*1024)) |
 	       git -C bare.git hash-object -w --stdin) &&
 	git -C bare.git update-ref refs/tags/big $blob &&
-	git -C bare.git repack -ad 2>stderr &&
+
+	# Disable --name-hash-version test due to stderr comparison.
+	GIT_TEST_NAME_HASH_VERSION=1 \
+		git -C bare.git repack -ad 2>stderr &&
 	test_must_be_empty stderr &&
 	find bare.git/objects/pack -type f -name "*.bitmap" >actual &&
 	test_must_be_empty actual
@@ -776,6 +782,12 @@
 	test_must_be_empty tmpfiles
 '
 
+test_expect_success '--name-hash-version option passes through to pack-objects' '
+	GIT_TRACE2_EVENT="$(pwd)/hash-trace.txt" \
+		git repack -a --name-hash-version=2 &&
+	test_subcommand_flex git pack-objects --name-hash-version=2 <hash-trace.txt
+'
+
 test_expect_success 'setup for update-server-info' '
 	git init update-server-info &&
 	test_commit -C update-server-info message
diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh
index 5715f4d..5559d4c 100755
--- a/t/t7701-repack-unpack-unreachable.sh
+++ b/t/t7701-repack-unpack-unreachable.sh
@@ -195,4 +195,20 @@
 	git cat-file -p $sha1
 '
 
+test_expect_success 'repack -k packs unreachable loose objects without existing packfiles' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+
+		oid=$(echo would-be-deleted-loose | git hash-object -w --stdin) &&
+		objpath=.git/objects/$(echo $sha1 | sed "s,..,&/,") &&
+		test_path_is_file $objpath &&
+
+		git repack -ad --keep-unreachable &&
+		test_path_is_missing $objpath &&
+		git cat-file -p $oid
+	)
+'
+
 test_done
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index 1ad039e..e989932 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -138,7 +138,7 @@
 	# Note that `--abbrev=` always gets incremented by 1, which is why we
 	# expect 11 leading spaces and not 10.
 	cat >expect <<-EOF &&
-	$(printf "%0.s " $(test_seq 11)) (<author@example.com> 2005-04-07 15:45:13 -0700 1) abbrev
+	$(printf "%11s" "") (<author@example.com> 2005-04-07 15:45:13 -0700 1) abbrev
 	EOF
 	git blame -b --abbrev=10 ^HEAD -- abbrev.t >actual &&
 	test_cmp expect actual
@@ -146,7 +146,7 @@
 
 test_expect_success 'blame with excessive --abbrev and -b culls to hash length' '
 	cat >expect <<-EOF &&
-	$(printf "%0.s " $(test_seq $hexsz)) (<author@example.com> 2005-04-07 15:45:13 -0700 1) abbrev
+	$(printf "%${hexsz}s" "") (<author@example.com> 2005-04-07 15:45:13 -0700 1) abbrev
 	EOF
 	git blame -b --abbrev=9000 ^HEAD -- abbrev.t >actual &&
 	test_cmp expect actual
diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh
index 85a5074..8da318d 100755
--- a/t/t9003-help-autocorrect.sh
+++ b/t/t9003-help-autocorrect.sh
@@ -28,15 +28,18 @@
 	test_cmp expect actual
 '
 
-test_expect_success 'autocorrect showing candidates' '
-	git config help.autocorrect 0 &&
+for show in false no off 0 show
+do
+	test_expect_success 'autocorrect showing candidates' '
+		git config help.autocorrect $show &&
 
-	test_must_fail git lfg 2>actual &&
-	grep "^	lgf" actual &&
+		test_must_fail git lfg 2>actual &&
+		grep "^	lgf" actual &&
 
-	test_must_fail git distimdist 2>actual &&
-	grep "^	distimdistim" actual
-'
+		test_must_fail git distimdist 2>actual &&
+		grep "^	distimdistim" actual
+	'
+done
 
 for immediate in -1 immediate
 do
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 78e054a..79377bc 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -927,7 +927,7 @@
 		test -n "$test_skip_test_preamble" ||
 		say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $test_body"
 		if test_run_ "$test_body" &&
-		   check_test_results_san_file_empty_
+		   ! check_test_results_san_file_has_entries_
 		then
 			test_ok_ "$1"
 		else
@@ -1268,6 +1268,16 @@
 	eval "$GIT_TEST_CMP" '"$@"'
 }
 
+# test_cmp_sorted runs test_cmp on sorted versions of the two
+# input files. Uses "$1.sorted" and "$2.sorted" as temp files.
+
+test_cmp_sorted () {
+	sort <"$1" >"$1.sorted" &&
+	sort <"$2" >"$2.sorted" &&
+	test_cmp "$1.sorted" "$2.sorted" &&
+	rm "$1.sorted" "$2.sorted"
+}
+
 # Check that the given config key has the expected value.
 #
 #    test_cmp_config [-C <dir>] <expected-value>
@@ -1886,6 +1896,32 @@
 	fi
 }
 
+# Check that the given subcommand was run with the given set of
+# arguments in order (but with possible extra arguments).
+#
+#	test_subcommand_flex [!] <command> <args>... < <trace>
+#
+# If the first parameter passed is !, this instead checks that
+# the given command was not called.
+#
+test_subcommand_flex () {
+	local negate=
+	if test "$1" = "!"
+	then
+		negate=t
+		shift
+	fi
+
+	local expr="$(printf '"%s".*' "$@")"
+
+	if test -n "$negate"
+	then
+		! grep "\[$expr\]"
+	else
+		grep "\[$expr\]"
+	fi
+}
+
 # Check that the given command was invoked as part of the
 # trace2-format trace on stdin.
 #
@@ -2007,3 +2043,11 @@
 		test-tool hexdump |
 		sed "s/ //g"
 }
+
+# Trim and replace each character with ascii code below 32 or above
+# 127 (included) using a dot '.' character.
+# Octal intervals \001-\040 and \177-\377
+# correspond to decimal intervals 1-32 and 127-255
+test_redact_non_printables () {
+    tr -d "\n\r" | tr "[\001-\040][\177-\377]" "."
+}
diff --git a/t/test-lib.sh b/t/test-lib.sh
index d1f62ad..9001ed3 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1169,20 +1169,20 @@
 	teardown_malloc_check
 }
 
-check_test_results_san_file_empty_ () {
-	test -z "$TEST_RESULTS_SAN_FILE" && return 0
+check_test_results_san_file_has_entries_ () {
+	test -z "$TEST_RESULTS_SAN_FILE" && return 1
 
-	# stderr piped to /dev/null because the directory may have
-	# been "rmdir"'d already.
-	! find "$TEST_RESULTS_SAN_DIR" \
-		-type f \
-		-name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null |
-	xargs grep ^DEDUP_TOKEN |
+	# Lines marked with DEDUP_TOKEN show unique leaks. We only care that we
+	# found at least one.
+	#
+	# But also suppress any false positives caused by bugs or races in the
+	# sanitizer itself.
+	grep -s ^DEDUP_TOKEN "$TEST_RESULTS_SAN_FILE".* |
 	grep -qv sanitizer::GetThreadStackTopAndBottom
 }
 
 check_test_results_san_file_ () {
-	if check_test_results_san_file_empty_
+	if ! check_test_results_san_file_has_entries_
 	then
 		return
 	fi &&
@@ -1862,6 +1862,10 @@
 	curl --version
 '
 
+test_lazy_prereq WITHOUT_BREAKING_CHANGES '
+	test -z "$WITH_BREAKING_CHANGES"
+'
+
 # SHA1 is a test if the hash algorithm in use is SHA-1.  This is both for tests
 # which will not work with other hash algorithms and tests that work but don't
 # test anything meaningful (e.g. special values which cause short collisions).
diff --git a/t/unit-tests/generate-clar-decls.sh b/t/unit-tests/generate-clar-decls.sh
index 3b315c6..abf6a2e 100755
--- a/t/unit-tests/generate-clar-decls.sh
+++ b/t/unit-tests/generate-clar-decls.sh
@@ -14,6 +14,7 @@
 	suite_name=$(basename "$suite")
 	suite_name=${suite_name%.c}
 	suite_name=${suite_name#u-}
+	suite_name=$(echo "$suite_name" | tr '-' '_')
 	sed -ne "s/^\(void test_${suite_name}__[a-zA-Z_0-9][a-zA-Z_0-9]*(void)\)$/extern \1;/p" "$suite" ||
 	exit 1
 done >"$OUTPUT"
diff --git a/t/unit-tests/lib-oid.c b/t/unit-tests/lib-oid.c
index 8f0ccac..e0b3180 100644
--- a/t/unit-tests/lib-oid.c
+++ b/t/unit-tests/lib-oid.c
@@ -1,9 +1,9 @@
-#include "test-lib.h"
+#include "unit-test.h"
 #include "lib-oid.h"
 #include "strbuf.h"
 #include "hex.h"
 
-int init_hash_algo(void)
+int cl_setup_hash_algo(void)
 {
 	static int algo = -1;
 
@@ -11,42 +11,32 @@ int init_hash_algo(void)
 		const char *algo_name = getenv("GIT_TEST_DEFAULT_HASH");
 		algo = algo_name ? hash_algo_by_name(algo_name) : GIT_HASH_SHA1;
 
-		if (!check(algo != GIT_HASH_UNKNOWN))
-			test_msg("BUG: invalid GIT_TEST_DEFAULT_HASH value ('%s')",
-				 algo_name);
+		cl_assert(algo != GIT_HASH_UNKNOWN);
 	}
 	return algo;
 }
 
-static int get_oid_arbitrary_hex_algop(const char *hex, struct object_id *oid,
+static void cl_parse_oid(const char *hex, struct object_id *oid,
 				       const struct git_hash_algo *algop)
 {
-	int ret;
 	size_t sz = strlen(hex);
 	struct strbuf buf = STRBUF_INIT;
 
-	if (!check(sz <= algop->hexsz)) {
-		test_msg("BUG: hex string (%s) bigger than maximum allowed (%lu)",
-			 hex, (unsigned long)algop->hexsz);
-		return -1;
-	}
+	cl_assert(sz <= algop->hexsz);
 
 	strbuf_add(&buf, hex, sz);
 	strbuf_addchars(&buf, '0', algop->hexsz - sz);
 
-	ret = get_oid_hex_algop(buf.buf, oid, algop);
-	if (!check_int(ret, ==, 0))
-		test_msg("BUG: invalid hex input (%s) provided", hex);
+	cl_assert_equal_i(get_oid_hex_algop(buf.buf, oid, algop), 0);
 
 	strbuf_release(&buf);
-	return ret;
 }
 
-int get_oid_arbitrary_hex(const char *hex, struct object_id *oid)
-{
-	int hash_algo = init_hash_algo();
 
-	if (!check_int(hash_algo, !=, GIT_HASH_UNKNOWN))
-		return -1;
-	return get_oid_arbitrary_hex_algop(hex, oid, &hash_algos[hash_algo]);
+void cl_parse_any_oid(const char *hex, struct object_id *oid)
+{
+	int hash_algo = cl_setup_hash_algo();
+
+	cl_assert(hash_algo != GIT_HASH_UNKNOWN);
+	cl_parse_oid(hex, oid, &hash_algos[hash_algo]);
 }
diff --git a/t/unit-tests/lib-oid.h b/t/unit-tests/lib-oid.h
index 4e77c04..4031775 100644
--- a/t/unit-tests/lib-oid.h
+++ b/t/unit-tests/lib-oid.h
@@ -5,6 +5,7 @@
 
 /*
  * Convert arbitrary hex string to object_id.
+ *
  * For example, passing "abc12" will generate
  * "abc1200000000000000000000000000000000000" hex of length 40 for SHA-1 and
  * create object_id with that.
@@ -12,14 +13,16 @@
  * algo is not allowed. The hash algo is decided based on GIT_TEST_DEFAULT_HASH
  * environment variable.
  */
-int get_oid_arbitrary_hex(const char *s, struct object_id *oid);
+
+void cl_parse_any_oid (const char *s, struct object_id *oid);
 /*
  * Returns one of GIT_HASH_{SHA1, SHA256, UNKNOWN} based on the value of
  * GIT_TEST_DEFAULT_HASH environment variable. The fallback value in the
  * absence of GIT_TEST_DEFAULT_HASH is GIT_HASH_SHA1. It also uses
- * check(algo != GIT_HASH_UNKNOWN) before returning to verify if the
+ * cl_assert(algo != GIT_HASH_UNKNOWN) before returning to verify if the
  * GIT_TEST_DEFAULT_HASH's value is valid or not.
  */
-int init_hash_algo(void);
+
+int cl_setup_hash_algo(void);
 
 #endif /* LIB_OID_H */
diff --git a/t/unit-tests/t-example-decorate.c b/t/unit-tests/t-example-decorate.c
deleted file mode 100644
index bfc776e..0000000
--- a/t/unit-tests/t-example-decorate.c
+++ /dev/null
@@ -1,74 +0,0 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "test-lib.h"
-#include "object.h"
-#include "decorate.h"
-#include "repository.h"
-
-struct test_vars {
-	struct object *one, *two, *three;
-	struct decoration n;
-	int decoration_a, decoration_b;
-};
-
-static void t_add(struct test_vars *vars)
-{
-	void *ret = add_decoration(&vars->n, vars->one, &vars->decoration_a);
-
-	check(ret == NULL);
-	ret = add_decoration(&vars->n, vars->two, NULL);
-	check(ret == NULL);
-}
-
-static void t_readd(struct test_vars *vars)
-{
-	void *ret = add_decoration(&vars->n, vars->one, NULL);
-
-	check(ret == &vars->decoration_a);
-	ret = add_decoration(&vars->n, vars->two, &vars->decoration_b);
-	check(ret == NULL);
-}
-
-static void t_lookup(struct test_vars *vars)
-{
-	void *ret = lookup_decoration(&vars->n, vars->one);
-
-	check(ret == NULL);
-	ret = lookup_decoration(&vars->n, vars->two);
-	check(ret == &vars->decoration_b);
-	ret = lookup_decoration(&vars->n, vars->three);
-	check(ret == NULL);
-}
-
-static void t_loop(struct test_vars *vars)
-{
-	int objects_noticed = 0;
-
-	for (size_t i = 0; i < vars->n.size; i++) {
-		if (vars->n.entries[i].base)
-			objects_noticed++;
-	}
-	check_int(objects_noticed, ==, 2);
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
-	struct object_id one_oid = { { 1 } }, two_oid = { { 2 } }, three_oid = { { 3 } };
-	struct test_vars vars = { 0 };
-
-	vars.one = lookup_unknown_object(the_repository, &one_oid);
-	vars.two = lookup_unknown_object(the_repository, &two_oid);
-	vars.three = lookup_unknown_object(the_repository, &three_oid);
-
-	TEST(t_add(&vars),
-	     "Add 2 objects, one with a non-NULL decoration and one with a NULL decoration.");
-	TEST(t_readd(&vars),
-	     "When re-adding an already existing object, the old decoration is returned.");
-	TEST(t_lookup(&vars),
-	     "Lookup returns the added declarations, or NULL if the object was never added.");
-	TEST(t_loop(&vars), "The user can also loop through all entries.");
-
-	clear_decoration(&vars.n, NULL);
-
-	return test_done();
-}
diff --git a/t/unit-tests/t-mem-pool.c b/t/unit-tests/t-mem-pool.c
deleted file mode 100644
index fe500c7..0000000
--- a/t/unit-tests/t-mem-pool.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "test-lib.h"
-#include "mem-pool.h"
-
-static void setup_static(void (*f)(struct mem_pool *), size_t block_alloc)
-{
-	struct mem_pool pool = { .block_alloc = block_alloc };
-	f(&pool);
-	mem_pool_discard(&pool, 0);
-}
-
-static void t_calloc_100(struct mem_pool *pool)
-{
-	size_t size = 100;
-	char *buffer = mem_pool_calloc(pool, 1, size);
-	for (size_t i = 0; i < size; i++)
-		check_int(buffer[i], ==, 0);
-	if (!check(pool->mp_block != NULL))
-		return;
-	check(pool->mp_block->next_free != NULL);
-	check(pool->mp_block->end != NULL);
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
-	TEST(setup_static(t_calloc_100, 1024 * 1024),
-	     "mem_pool_calloc returns 100 zeroed bytes with big block");
-	TEST(setup_static(t_calloc_100, 1),
-	     "mem_pool_calloc returns 100 zeroed bytes with tiny block");
-
-	return test_done();
-}
diff --git a/t/unit-tests/t-oid-array.c b/t/unit-tests/t-oid-array.c
deleted file mode 100644
index 45b59a2..0000000
--- a/t/unit-tests/t-oid-array.c
+++ /dev/null
@@ -1,126 +0,0 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "test-lib.h"
-#include "lib-oid.h"
-#include "oid-array.h"
-#include "hex.h"
-
-static int fill_array(struct oid_array *array, const char *hexes[], size_t n)
-{
-	for (size_t i = 0; i < n; i++) {
-		struct object_id oid;
-
-		if (!check_int(get_oid_arbitrary_hex(hexes[i], &oid), ==, 0))
-			return -1;
-		oid_array_append(array, &oid);
-	}
-	if (!check_uint(array->nr, ==, n))
-		return -1;
-	return 0;
-}
-
-static int add_to_oid_array(const struct object_id *oid, void *data)
-{
-	struct oid_array *array = data;
-
-	oid_array_append(array, oid);
-	return 0;
-}
-
-static void t_enumeration(const char **input_args, size_t input_sz,
-			  const char **expect_args, size_t expect_sz)
-{
-	struct oid_array input = OID_ARRAY_INIT, expect = OID_ARRAY_INIT,
-			 actual = OID_ARRAY_INIT;
-	size_t i;
-
-	if (fill_array(&input, input_args, input_sz))
-		return;
-	if (fill_array(&expect, expect_args, expect_sz))
-		return;
-
-	oid_array_for_each_unique(&input, add_to_oid_array, &actual);
-	if (!check_uint(actual.nr, ==, expect.nr))
-		return;
-
-	for (i = 0; i < actual.nr; i++) {
-		if (!check(oideq(&actual.oid[i], &expect.oid[i])))
-			test_msg("expected: %s\n       got: %s\n     index: %" PRIuMAX,
-				 oid_to_hex(&expect.oid[i]), oid_to_hex(&actual.oid[i]),
-				 (uintmax_t)i);
-	}
-
-	oid_array_clear(&actual);
-	oid_array_clear(&input);
-	oid_array_clear(&expect);
-}
-
-#define TEST_ENUMERATION(input, expect, desc)                                     \
-	TEST(t_enumeration(input, ARRAY_SIZE(input), expect, ARRAY_SIZE(expect)), \
-			   desc " works")
-
-static void t_lookup(const char **input_hexes, size_t n, const char *query_hex,
-		     int lower_bound, int upper_bound)
-{
-	struct oid_array array = OID_ARRAY_INIT;
-	struct object_id oid_query;
-	int ret;
-
-	if (!check_int(get_oid_arbitrary_hex(query_hex, &oid_query), ==, 0))
-		return;
-	if (fill_array(&array, input_hexes, n))
-		return;
-	ret = oid_array_lookup(&array, &oid_query);
-
-	if (!check_int(ret, <=, upper_bound) ||
-	    !check_int(ret, >=, lower_bound))
-		test_msg("oid query for lookup: %s", oid_to_hex(&oid_query));
-
-	oid_array_clear(&array);
-}
-
-#define TEST_LOOKUP(input_hexes, query, lower_bound, upper_bound, desc) \
-	TEST(t_lookup(input_hexes, ARRAY_SIZE(input_hexes), query,      \
-		      lower_bound, upper_bound),                        \
-	     desc " works")
-
-static void setup(void)
-{
-	/* The hash algo is used by oid_array_lookup() internally */
-	int algo = init_hash_algo();
-	if (check_int(algo, !=, GIT_HASH_UNKNOWN))
-		repo_set_hash_algo(the_repository, algo);
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
-	const char *arr_input[] = { "88", "44", "aa", "55" };
-	const char *arr_input_dup[] = { "88", "44", "aa", "55",
-					"88", "44", "aa", "55",
-					"88", "44", "aa", "55" };
-	const char *res_sorted[] = { "44", "55", "88", "aa" };
-	const char *nearly_55;
-
-	if (!TEST(setup(), "setup"))
-		test_skip_all("hash algo initialization failed");
-
-	TEST_ENUMERATION(arr_input, res_sorted, "ordered enumeration");
-	TEST_ENUMERATION(arr_input_dup, res_sorted,
-			 "ordered enumeration with duplicate suppression");
-
-	TEST_LOOKUP(arr_input, "55", 1, 1, "lookup");
-	TEST_LOOKUP(arr_input, "33", INT_MIN, -1, "lookup non-existent entry");
-	TEST_LOOKUP(arr_input_dup, "55", 3, 5, "lookup with duplicates");
-	TEST_LOOKUP(arr_input_dup, "66", INT_MIN, -1,
-		    "lookup non-existent entry with duplicates");
-
-	nearly_55 = init_hash_algo() == GIT_HASH_SHA1 ?
-			"5500000000000000000000000000000000000001" :
-			"5500000000000000000000000000000000000000000000000000000000000001";
-	TEST_LOOKUP(((const char *[]){ "55", nearly_55 }), "55", 0, 0,
-		    "lookup with almost duplicate values");
-	TEST_LOOKUP(((const char *[]){ "55", "55" }), "55", 0, 1,
-		    "lookup with single duplicate value");
-
-	return test_done();
-}
diff --git a/t/unit-tests/t-oidmap.c b/t/unit-tests/t-oidmap.c
deleted file mode 100644
index b22e52d..0000000
--- a/t/unit-tests/t-oidmap.c
+++ /dev/null
@@ -1,181 +0,0 @@
-#include "test-lib.h"
-#include "lib-oid.h"
-#include "oidmap.h"
-#include "hash.h"
-#include "hex.h"
-
-/*
- * Elements we will put in oidmap structs are made of a key: the entry.oid
- * field, which is of type struct object_id, and a value: the name field (could
- * be a refname for example).
- */
-struct test_entry {
-	struct oidmap_entry entry;
-	char name[FLEX_ARRAY];
-};
-
-static const char *const key_val[][2] = { { "11", "one" },
-					  { "22", "two" },
-					  { "33", "three" } };
-
-static void setup(void (*f)(struct oidmap *map))
-{
-	struct oidmap map = OIDMAP_INIT;
-	int ret = 0;
-
-	for (size_t i = 0; i < ARRAY_SIZE(key_val); i++){
-		struct test_entry *entry;
-
-		FLEX_ALLOC_STR(entry, name, key_val[i][1]);
-		if ((ret = get_oid_arbitrary_hex(key_val[i][0], &entry->entry.oid))) {
-			free(entry);
-			break;
-		}
-		entry = oidmap_put(&map, entry);
-		if (!check(entry == NULL))
-			free(entry);
-	}
-
-	if (!ret)
-		f(&map);
-	oidmap_free(&map, 1);
-}
-
-static void t_replace(struct oidmap *map)
-{
-	struct test_entry *entry, *prev;
-
-	FLEX_ALLOC_STR(entry, name, "un");
-	if (get_oid_arbitrary_hex("11", &entry->entry.oid))
-		return;
-	prev = oidmap_put(map, entry);
-	if (!check(prev != NULL))
-		return;
-	check_str(prev->name, "one");
-	free(prev);
-
-	FLEX_ALLOC_STR(entry, name, "deux");
-	if (get_oid_arbitrary_hex("22", &entry->entry.oid))
-		return;
-	prev = oidmap_put(map, entry);
-	if (!check(prev != NULL))
-		return;
-	check_str(prev->name, "two");
-	free(prev);
-}
-
-static void t_get(struct oidmap *map)
-{
-	struct test_entry *entry;
-	struct object_id oid;
-
-	if (get_oid_arbitrary_hex("22", &oid))
-		return;
-	entry = oidmap_get(map, &oid);
-	if (!check(entry != NULL))
-		return;
-	check_str(entry->name, "two");
-
-	if (get_oid_arbitrary_hex("44", &oid))
-		return;
-	check(oidmap_get(map, &oid) == NULL);
-
-	if (get_oid_arbitrary_hex("11", &oid))
-		return;
-	entry = oidmap_get(map, &oid);
-	if (!check(entry != NULL))
-		return;
-	check_str(entry->name, "one");
-}
-
-static void t_remove(struct oidmap *map)
-{
-	struct test_entry *entry;
-	struct object_id oid;
-
-	if (get_oid_arbitrary_hex("11", &oid))
-		return;
-	entry = oidmap_remove(map, &oid);
-	if (!check(entry != NULL))
-		return;
-	check_str(entry->name, "one");
-	check(oidmap_get(map, &oid) == NULL);
-	free(entry);
-
-	if (get_oid_arbitrary_hex("22", &oid))
-		return;
-	entry = oidmap_remove(map, &oid);
-	if (!check(entry != NULL))
-		return;
-	check_str(entry->name, "two");
-	check(oidmap_get(map, &oid) == NULL);
-	free(entry);
-
-	if (get_oid_arbitrary_hex("44", &oid))
-		return;
-	check(oidmap_remove(map, &oid) == NULL);
-}
-
-static int key_val_contains(struct test_entry *entry, char seen[])
-{
-	for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
-		struct object_id oid;
-
-		if (get_oid_arbitrary_hex(key_val[i][0], &oid))
-			return -1;
-
-		if (oideq(&entry->entry.oid, &oid)) {
-			if (seen[i])
-				return 2;
-			seen[i] = 1;
-			return 0;
-		}
-	}
-	return 1;
-}
-
-static void t_iterate(struct oidmap *map)
-{
-	struct oidmap_iter iter;
-	struct test_entry *entry;
-	char seen[ARRAY_SIZE(key_val)] = { 0 };
-	int count = 0;
-
-	oidmap_iter_init(map, &iter);
-	while ((entry = oidmap_iter_next(&iter))) {
-		int ret;
-		if (!check_int((ret = key_val_contains(entry, seen)), ==, 0)) {
-			switch (ret) {
-			case -1:
-				break; /* error message handled by get_oid_arbitrary_hex() */
-			case 1:
-				test_msg("obtained entry was not given in the input\n"
-					 "  name: %s\n   oid: %s\n",
-					 entry->name, oid_to_hex(&entry->entry.oid));
-				break;
-			case 2:
-				test_msg("duplicate entry detected\n"
-					 "  name: %s\n   oid: %s\n",
-					 entry->name, oid_to_hex(&entry->entry.oid));
-				break;
-			default:
-				test_msg("BUG: invalid return value (%d) from key_val_contains()",
-					 ret);
-				break;
-			}
-		} else {
-			count++;
-		}
-	}
-	check_int(count, ==, ARRAY_SIZE(key_val));
-	check_int(hashmap_get_size(&map->map), ==, ARRAY_SIZE(key_val));
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
-	TEST(setup(t_replace), "replace works");
-	TEST(setup(t_get), "get works");
-	TEST(setup(t_remove), "remove works");
-	TEST(setup(t_iterate), "iterate works");
-	return test_done();
-}
diff --git a/t/unit-tests/t-oidtree.c b/t/unit-tests/t-oidtree.c
deleted file mode 100644
index a38754b..0000000
--- a/t/unit-tests/t-oidtree.c
+++ /dev/null
@@ -1,122 +0,0 @@
-#include "test-lib.h"
-#include "lib-oid.h"
-#include "oidtree.h"
-#include "hash.h"
-#include "hex.h"
-#include "strvec.h"
-
-#define FILL_TREE(tree, ...)                                       \
-	do {                                                       \
-		const char *hexes[] = { __VA_ARGS__ };             \
-		if (fill_tree_loc(tree, hexes, ARRAY_SIZE(hexes))) \
-			return;                                    \
-	} while (0)
-
-static int fill_tree_loc(struct oidtree *ot, const char *hexes[], size_t n)
-{
-	for (size_t i = 0; i < n; i++) {
-		struct object_id oid;
-		if (!check_int(get_oid_arbitrary_hex(hexes[i], &oid), ==, 0))
-			return -1;
-		oidtree_insert(ot, &oid);
-	}
-	return 0;
-}
-
-static void check_contains(struct oidtree *ot, const char *hex, int expected)
-{
-	struct object_id oid;
-
-	if (!check_int(get_oid_arbitrary_hex(hex, &oid), ==, 0))
-		return;
-	if (!check_int(oidtree_contains(ot, &oid), ==, expected))
-		test_msg("oid: %s", oid_to_hex(&oid));
-}
-
-struct expected_hex_iter {
-	size_t i;
-	struct strvec expected_hexes;
-	const char *query;
-};
-
-static enum cb_next check_each_cb(const struct object_id *oid, void *data)
-{
-	struct expected_hex_iter *hex_iter = data;
-	struct object_id expected;
-
-	if (!check_int(hex_iter->i, <, hex_iter->expected_hexes.nr)) {
-		test_msg("error: extraneous callback for query: ('%s'), object_id: ('%s')",
-			 hex_iter->query, oid_to_hex(oid));
-		return CB_BREAK;
-	}
-
-	if (!check_int(get_oid_arbitrary_hex(hex_iter->expected_hexes.v[hex_iter->i],
-					     &expected), ==, 0))
-		; /* the data is bogus and cannot be used */
-	else if (!check(oideq(oid, &expected)))
-		test_msg("expected: %s\n       got: %s\n     query: %s",
-			 oid_to_hex(&expected), oid_to_hex(oid), hex_iter->query);
-
-	hex_iter->i += 1;
-	return CB_CONTINUE;
-}
-
-LAST_ARG_MUST_BE_NULL
-static void check_each(struct oidtree *ot, const char *query, ...)
-{
-	struct object_id oid;
-	struct expected_hex_iter hex_iter = { .expected_hexes = STRVEC_INIT,
-					      .query = query };
-	const char *arg;
-	va_list hex_args;
-
-	va_start(hex_args, query);
-	while ((arg = va_arg(hex_args, const char *)))
-		strvec_push(&hex_iter.expected_hexes, arg);
-	va_end(hex_args);
-
-	if (!check_int(get_oid_arbitrary_hex(query, &oid), ==, 0))
-		return;
-	oidtree_each(ot, &oid, strlen(query), check_each_cb, &hex_iter);
-
-	if (!check_int(hex_iter.i, ==, hex_iter.expected_hexes.nr))
-		test_msg("error: could not find some 'object_id's for query ('%s')", query);
-	strvec_clear(&hex_iter.expected_hexes);
-}
-
-static void setup(void (*f)(struct oidtree *ot))
-{
-	struct oidtree ot;
-
-	oidtree_init(&ot);
-	f(&ot);
-	oidtree_clear(&ot);
-}
-
-static void t_contains(struct oidtree *ot)
-{
-	FILL_TREE(ot, "444", "1", "2", "3", "4", "5", "a", "b", "c", "d", "e");
-	check_contains(ot, "44", 0);
-	check_contains(ot, "441", 0);
-	check_contains(ot, "440", 0);
-	check_contains(ot, "444", 1);
-	check_contains(ot, "4440", 1);
-	check_contains(ot, "4444", 0);
-}
-
-static void t_each(struct oidtree *ot)
-{
-	FILL_TREE(ot, "f", "9", "8", "123", "321", "320", "a", "b", "c", "d", "e");
-	check_each(ot, "12300", "123", NULL);
-	check_each(ot, "3211", NULL); /* should not reach callback */
-	check_each(ot, "3210", "321", NULL);
-	check_each(ot, "32100", "321", NULL);
-	check_each(ot, "32", "320", "321", NULL);
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
-	TEST(setup(t_contains), "oidtree insert and contains works");
-	TEST(setup(t_each), "oidtree each works");
-	return test_done();
-}
diff --git a/t/unit-tests/t-prio-queue.c b/t/unit-tests/t-prio-queue.c
deleted file mode 100644
index a053635..0000000
--- a/t/unit-tests/t-prio-queue.c
+++ /dev/null
@@ -1,91 +0,0 @@
-#include "test-lib.h"
-#include "prio-queue.h"
-
-static int intcmp(const void *va, const void *vb, void *data UNUSED)
-{
-	const int *a = va, *b = vb;
-	return *a - *b;
-}
-
-
-#define MISSING  -1
-#define DUMP	 -2
-#define STACK	 -3
-#define GET	 -4
-#define REVERSE  -5
-
-static int show(int *v)
-{
-	return v ? *v : MISSING;
-}
-
-static void test_prio_queue(int *input, size_t input_size,
-			    int *result, size_t result_size)
-{
-	struct prio_queue pq = { intcmp };
-	int j = 0;
-
-	for (size_t i = 0; i < input_size; i++) {
-		void *peek, *get;
-		switch(input[i]) {
-		case GET:
-			peek = prio_queue_peek(&pq);
-			get = prio_queue_get(&pq);
-			if (!check(peek == get))
-				return;
-			if (!check_uint(j, <, result_size))
-				break;
-			if (!check_int(result[j], ==, show(get)))
-				test_msg("      j: %d", j);
-			j++;
-			break;
-		case DUMP:
-			while ((peek = prio_queue_peek(&pq))) {
-				get = prio_queue_get(&pq);
-				if (!check(peek == get))
-					return;
-				if (!check_uint(j, <, result_size))
-					break;
-				if (!check_int(result[j], ==, show(get)))
-					test_msg("      j: %d", j);
-				j++;
-			}
-			break;
-		case STACK:
-			pq.compare = NULL;
-			break;
-		case REVERSE:
-			prio_queue_reverse(&pq);
-			break;
-		default:
-			prio_queue_put(&pq, &input[i]);
-			break;
-		}
-	}
-	check_uint(j, ==, result_size);
-	clear_prio_queue(&pq);
-}
-
-#define TEST_INPUT(input, result) \
-	test_prio_queue(input, ARRAY_SIZE(input), result, ARRAY_SIZE(result))
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
-	TEST(TEST_INPUT(((int []){ 2, 6, 3, 10, 9, 5, 7, 4, 5, 8, 1, DUMP }),
-			((int []){ 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10 })),
-	     "prio-queue works for basic input");
-	TEST(TEST_INPUT(((int []){ 6, 2, 4, GET, 5, 3, GET, GET, 1, DUMP }),
-			((int []){ 2, 3, 4, 1, 5, 6 })),
-	     "prio-queue works for mixed put & get commands");
-	TEST(TEST_INPUT(((int []){ 1, 2, GET, GET, GET, 1, 2, GET, GET, GET }),
-			((int []){ 1, 2, MISSING, 1, 2, MISSING })),
-	     "prio-queue works when queue is empty");
-	TEST(TEST_INPUT(((int []){ STACK, 8, 1, 5, 4, 6, 2, 3, DUMP }),
-			((int []){ 3, 2, 6, 4, 5, 1, 8 })),
-	     "prio-queue works when used as a LIFO stack");
-	TEST(TEST_INPUT(((int []){ STACK, 1, 2, 3, 4, 5, 6, REVERSE, DUMP }),
-			((int []){ 1, 2, 3, 4, 5, 6 })),
-	     "prio-queue works when LIFO stack is reversed");
-
-	return test_done();
-}
diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c
index 1d640b2..9ba7eb0 100644
--- a/t/unit-tests/t-reftable-basics.c
+++ b/t/unit-tests/t-reftable-basics.c
@@ -120,7 +120,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
 		for (size_t i = 0; i < ARRAY_SIZE(cases); i++) {
 			check(!reftable_buf_addstr(&a, cases[i].a));
 			check(!reftable_buf_addstr(&b, cases[i].b));
-			check_int(common_prefix_size(&a, &b), ==, cases[i].want);
+			check_uint(common_prefix_size(&a, &b), ==, cases[i].want);
 			reftable_buf_reset(&a);
 			reftable_buf_reset(&b);
 		}
diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c
index 6b75a41..c962683 100644
--- a/t/unit-tests/t-reftable-readwrite.c
+++ b/t/unit-tests/t-reftable-readwrite.c
@@ -108,8 +108,8 @@ static void t_log_buffer_size(void)
 	   hash, to ensure that the compressed part is larger than the original.
 	*/
 	for (i = 0; i < REFTABLE_HASH_SIZE_SHA1; i++) {
-		log.value.update.old_hash[i] = (uint8_t)(git_rand() % 256);
-		log.value.update.new_hash[i] = (uint8_t)(git_rand() % 256);
+		log.value.update.old_hash[i] = (uint8_t)(git_rand(0) % 256);
+		log.value.update.new_hash[i] = (uint8_t)(git_rand(0) % 256);
 	}
 	reftable_writer_set_limits(w, update_index, update_index);
 	err = reftable_writer_add_log(w, &log);
@@ -325,7 +325,7 @@ static void t_log_zlib_corruption(void)
 	};
 
 	for (i = 0; i < sizeof(message) - 1; i++)
-		message[i] = (uint8_t)(git_rand() % 64 + ' ');
+		message[i] = (uint8_t)(git_rand(0) % 64 + ' ');
 
 	reftable_writer_set_limits(w, 1, 1);
 
@@ -643,7 +643,7 @@ static void t_write_empty_table(void)
 	check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR);
 	reftable_writer_free(w);
 
-	check_int(buf.len, ==, header_size(1) + footer_size(1));
+	check_uint(buf.len, ==, header_size(1) + footer_size(1));
 
 	block_source_from_buf(&source, &buf);
 
diff --git a/t/unit-tests/t-reftable-record.c b/t/unit-tests/t-reftable-record.c
index 42bc64c..d49d2a2 100644
--- a/t/unit-tests/t-reftable-record.c
+++ b/t/unit-tests/t-reftable-record.c
@@ -58,9 +58,25 @@ static void t_varint_roundtrip(void)
 	}
 }
 
+static void t_varint_overflow(void)
+{
+	unsigned char buf[] = {
+		0xFF, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0xFF,
+		0xFF, 0x00,
+	};
+	struct string_view view = {
+		.buf = buf,
+		.len = sizeof(buf),
+	};
+	uint64_t value;
+	int err = get_var_int(&value, &view);
+	check_int(err, ==, -1);
+}
+
 static void set_hash(uint8_t *h, int j)
 {
-	for (int i = 0; i < hash_size(REFTABLE_HASH_SHA1); i++)
+	for (size_t i = 0; i < hash_size(REFTABLE_HASH_SHA1); i++)
 		h[i] = (j >> i) & 0xff;
 }
 
@@ -544,6 +560,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
 	TEST(t_reftable_log_record_roundtrip(), "record operations work on log record");
 	TEST(t_reftable_ref_record_roundtrip(), "record operations work on ref record");
 	TEST(t_varint_roundtrip(), "put_var_int and get_var_int work");
+	TEST(t_varint_overflow(), "get_var_int notices an integer overflow");
 	TEST(t_key_roundtrip(), "reftable_encode_key and reftable_decode_key work");
 	TEST(t_reftable_obj_record_roundtrip(), "record operations work on obj record");
 	TEST(t_reftable_index_record_roundtrip(), "record operations work on index record");
diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c
index aeec195..c3f0059 100644
--- a/t/unit-tests/t-reftable-stack.c
+++ b/t/unit-tests/t-reftable-stack.c
@@ -103,7 +103,8 @@ static void t_read_file(void)
 static int write_test_ref(struct reftable_writer *wr, void *arg)
 {
 	struct reftable_ref_record *ref = arg;
-	reftable_writer_set_limits(wr, ref->update_index, ref->update_index);
+	check(!reftable_writer_set_limits(wr, ref->update_index,
+					  ref->update_index));
 	return reftable_writer_add_ref(wr, ref);
 }
 
@@ -143,7 +144,8 @@ static int write_test_log(struct reftable_writer *wr, void *arg)
 {
 	struct write_log_arg *wla = arg;
 
-	reftable_writer_set_limits(wr, wla->update_index, wla->update_index);
+	check(!reftable_writer_set_limits(wr, wla->update_index,
+					  wla->update_index));
 	return reftable_writer_add_log(wr, wla->log);
 }
 
@@ -961,7 +963,7 @@ static void t_reflog_expire(void)
 
 static int write_nothing(struct reftable_writer *wr, void *arg UNUSED)
 {
-	reftable_writer_set_limits(wr, 1, 1);
+	check(!reftable_writer_set_limits(wr, 1, 1));
 	return 0;
 }
 
@@ -1369,11 +1371,57 @@ static void t_reftable_stack_reload_with_missing_table(void)
 	clear_dir(dir);
 }
 
+static int write_limits_after_ref(struct reftable_writer *wr, void *arg)
+{
+	struct reftable_ref_record *ref = arg;
+	check(!reftable_writer_set_limits(wr, ref->update_index, ref->update_index));
+	check(!reftable_writer_add_ref(wr, ref));
+	return reftable_writer_set_limits(wr, ref->update_index, ref->update_index);
+}
+
+static void t_reftable_invalid_limit_updates(void)
+{
+	struct reftable_ref_record ref = {
+		.refname = (char *) "HEAD",
+		.update_index = 1,
+		.value_type = REFTABLE_REF_SYMREF,
+		.value.symref = (char *) "master",
+	};
+	struct reftable_write_options opts = {
+		.default_permissions = 0660,
+	};
+	struct reftable_addition *add = NULL;
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_stack *st = NULL;
+	int err;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	reftable_addition_destroy(add);
+
+	err = reftable_stack_new_addition(&add, st, 0);
+	check(!err);
+
+	/*
+	 * write_limits_after_ref also updates the update indexes after adding
+	 * the record. This should cause an err to be returned, since the limits
+	 * must be set at the start.
+	 */
+	err = reftable_addition_add(add, write_limits_after_ref, &ref);
+	check_int(err, ==, REFTABLE_API_ERROR);
+
+	reftable_addition_destroy(add);
+	reftable_stack_destroy(st);
+	clear_dir(dir);
+}
+
 int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
 {
 	TEST(t_empty_add(), "empty addition to stack");
 	TEST(t_read_file(), "read_lines works");
 	TEST(t_reflog_expire(), "expire reflog entries");
+	TEST(t_reftable_invalid_limit_updates(), "prevent limit updates after adding records");
 	TEST(t_reftable_stack_add(), "add multiple refs and logs to stack");
 	TEST(t_reftable_stack_add_one(), "add a single ref record to stack");
 	TEST(t_reftable_stack_add_performs_auto_compaction(), "addition to stack triggers auto-compaction");
diff --git a/t/unit-tests/t-strbuf.c b/t/unit-tests/t-strbuf.c
deleted file mode 100644
index 3f4044d..0000000
--- a/t/unit-tests/t-strbuf.c
+++ /dev/null
@@ -1,122 +0,0 @@
-#include "test-lib.h"
-#include "strbuf.h"
-
-/* wrapper that supplies tests with an empty, initialized strbuf */
-static void setup(void (*f)(struct strbuf*, const void*),
-		  const void *data)
-{
-	struct strbuf buf = STRBUF_INIT;
-
-	f(&buf, data);
-	strbuf_release(&buf);
-	check_uint(buf.len, ==, 0);
-	check_uint(buf.alloc, ==, 0);
-}
-
-/* wrapper that supplies tests with a populated, initialized strbuf */
-static void setup_populated(void (*f)(struct strbuf*, const void*),
-			    const char *init_str, const void *data)
-{
-	struct strbuf buf = STRBUF_INIT;
-
-	strbuf_addstr(&buf, init_str);
-	check_uint(buf.len, ==, strlen(init_str));
-	f(&buf, data);
-	strbuf_release(&buf);
-	check_uint(buf.len, ==, 0);
-	check_uint(buf.alloc, ==, 0);
-}
-
-static int assert_sane_strbuf(struct strbuf *buf)
-{
-	/* Initialized strbufs should always have a non-NULL buffer */
-	if (!check(!!buf->buf))
-		return 0;
-	/* Buffers should always be NUL-terminated */
-	if (!check_char(buf->buf[buf->len], ==, '\0'))
-		return 0;
-	/*
-	 * Freshly-initialized strbufs may not have a dynamically allocated
-	 * buffer
-	 */
-	if (buf->len == 0 && buf->alloc == 0)
-		return 1;
-	/* alloc must be at least one byte larger than len */
-	return check_uint(buf->len, <, buf->alloc);
-}
-
-static void t_static_init(void)
-{
-	struct strbuf buf = STRBUF_INIT;
-
-	check_uint(buf.len, ==, 0);
-	check_uint(buf.alloc, ==, 0);
-	check_char(buf.buf[0], ==, '\0');
-}
-
-static void t_dynamic_init(void)
-{
-	struct strbuf buf;
-
-	strbuf_init(&buf, 1024);
-	check(assert_sane_strbuf(&buf));
-	check_uint(buf.len, ==, 0);
-	check_uint(buf.alloc, >=, 1024);
-	check_char(buf.buf[0], ==, '\0');
-	strbuf_release(&buf);
-}
-
-static void t_addch(struct strbuf *buf, const void *data)
-{
-	const char *p_ch = data;
-	const char ch = *p_ch;
-	size_t orig_alloc = buf->alloc;
-	size_t orig_len = buf->len;
-
-	if (!check(assert_sane_strbuf(buf)))
-		return;
-	strbuf_addch(buf, ch);
-	if (!check(assert_sane_strbuf(buf)))
-		return;
-	if (!(check_uint(buf->len, ==, orig_len + 1) &&
-	      check_uint(buf->alloc, >=, orig_alloc)))
-		return; /* avoid de-referencing buf->buf */
-	check_char(buf->buf[buf->len - 1], ==, ch);
-	check_char(buf->buf[buf->len], ==, '\0');
-}
-
-static void t_addstr(struct strbuf *buf, const void *data)
-{
-	const char *text = data;
-	size_t len = strlen(text);
-	size_t orig_alloc = buf->alloc;
-	size_t orig_len = buf->len;
-
-	if (!check(assert_sane_strbuf(buf)))
-		return;
-	strbuf_addstr(buf, text);
-	if (!check(assert_sane_strbuf(buf)))
-		return;
-	if (!(check_uint(buf->len, ==, orig_len + len) &&
-	      check_uint(buf->alloc, >=, orig_alloc) &&
-	      check_uint(buf->alloc, >, orig_len + len) &&
-	      check_char(buf->buf[orig_len + len], ==, '\0')))
-	    return;
-	check_str(buf->buf + orig_len, text);
-}
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
-	if (!TEST(t_static_init(), "static initialization works"))
-		test_skip_all("STRBUF_INIT is broken");
-	TEST(t_dynamic_init(), "dynamic initialization works");
-	TEST(setup(t_addch, "a"), "strbuf_addch adds char");
-	TEST(setup(t_addch, ""), "strbuf_addch adds NUL char");
-	TEST(setup_populated(t_addch, "initial value", "a"),
-	     "strbuf_addch appends to initial value");
-	TEST(setup(t_addstr, "hello there"), "strbuf_addstr adds string");
-	TEST(setup_populated(t_addstr, "initial value", "hello there"),
-	     "strbuf_addstr appends string to initial value");
-
-	return test_done();
-}
diff --git a/t/unit-tests/t-strcmp-offset.c b/t/unit-tests/t-strcmp-offset.c
deleted file mode 100644
index 6880f21..0000000
--- a/t/unit-tests/t-strcmp-offset.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "test-lib.h"
-#include "read-cache-ll.h"
-
-static void check_strcmp_offset(const char *string1, const char *string2,
-				int expect_result, uintmax_t expect_offset)
-{
-	size_t offset;
-	int result = strcmp_offset(string1, string2, &offset);
-
-	/*
-	 * Because different CRTs behave differently, only rely on signs of the
-	 * result values.
-	 */
-	result = (result < 0 ? -1 :
-			result > 0 ? 1 :
-			0);
-
-	check_int(result, ==, expect_result);
-	check_uint((uintmax_t)offset, ==, expect_offset);
-}
-
-#define TEST_STRCMP_OFFSET(string1, string2, expect_result, expect_offset) \
-	TEST(check_strcmp_offset(string1, string2, expect_result,          \
-				 expect_offset),                           \
-	     "strcmp_offset(%s, %s) works", #string1, #string2)
-
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
-{
-	TEST_STRCMP_OFFSET("abc", "abc", 0, 3);
-	TEST_STRCMP_OFFSET("abc", "def", -1, 0);
-	TEST_STRCMP_OFFSET("abc", "abz", -1, 2);
-	TEST_STRCMP_OFFSET("abc", "abcdef", -1, 3);
-
-	return test_done();
-}
diff --git a/t/unit-tests/u-example-decorate.c b/t/unit-tests/u-example-decorate.c
new file mode 100644
index 0000000..9b1d1ce
--- /dev/null
+++ b/t/unit-tests/u-example-decorate.c
@@ -0,0 +1,64 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "unit-test.h"
+#include "object.h"
+#include "decorate.h"
+#include "repository.h"
+
+struct test_vars {
+	struct object *one, *two, *three;
+	struct decoration n;
+	int decoration_a, decoration_b;
+};
+
+static struct test_vars vars;
+
+void test_example_decorate__initialize(void)
+{
+	struct object_id one_oid = { { 1 } }, two_oid = { { 2 } }, three_oid = { { 3 } };
+
+	vars.one = lookup_unknown_object(the_repository, &one_oid);
+	vars.two = lookup_unknown_object(the_repository, &two_oid);
+	vars.three = lookup_unknown_object(the_repository, &three_oid);
+}
+
+void test_example_decorate__cleanup(void)
+{
+	clear_decoration(&vars.n, NULL);
+}
+
+void test_example_decorate__add(void)
+{
+	cl_assert_equal_p(add_decoration(&vars.n, vars.one, &vars.decoration_a), NULL);
+	cl_assert_equal_p(add_decoration(&vars.n, vars.two, NULL), NULL);
+}
+
+void test_example_decorate__readd(void)
+{
+	cl_assert_equal_p(add_decoration(&vars.n, vars.one, &vars.decoration_a), NULL);
+	cl_assert_equal_p(add_decoration(&vars.n, vars.two, NULL), NULL);
+	cl_assert_equal_p(add_decoration(&vars.n, vars.one, NULL), &vars.decoration_a);
+	cl_assert_equal_p(add_decoration(&vars.n, vars.two, &vars.decoration_b), NULL);
+}
+
+void test_example_decorate__lookup(void)
+{
+	cl_assert_equal_p(add_decoration(&vars.n, vars.two, &vars.decoration_b), NULL);
+	cl_assert_equal_p(add_decoration(&vars.n, vars.one, NULL), NULL);
+	cl_assert_equal_p(lookup_decoration(&vars.n, vars.two), &vars.decoration_b);
+	cl_assert_equal_p(lookup_decoration(&vars.n, vars.one), NULL);
+}
+
+void test_example_decorate__loop(void)
+{
+	int objects_noticed = 0;
+
+	cl_assert_equal_p(add_decoration(&vars.n, vars.one, &vars.decoration_a), NULL);
+	cl_assert_equal_p(add_decoration(&vars.n, vars.two, &vars.decoration_b), NULL);
+
+	for (size_t i = 0; i < vars.n.size; i++)
+		if (vars.n.entries[i].base)
+			objects_noticed++;
+
+	cl_assert_equal_i(objects_noticed, 2);
+}
diff --git a/t/unit-tests/t-hash.c b/t/unit-tests/u-hash.c
similarity index 77%
rename from t/unit-tests/t-hash.c
rename to t/unit-tests/u-hash.c
index e626470..bd4ac6a 100644
--- a/t/unit-tests/t-hash.c
+++ b/t/unit-tests/u-hash.c
@@ -1,84 +1,109 @@
-#include "test-lib.h"
+#include "unit-test.h"
 #include "hex.h"
 #include "strbuf.h"
 
 static void check_hash_data(const void *data, size_t data_length,
 			    const char *expected_hashes[])
 {
-	if (!check(data != NULL)) {
-		test_msg("BUG: NULL data pointer provided");
-		return;
-	}
+	cl_assert(data != NULL);
 
 	for (size_t i = 1; i < ARRAY_SIZE(hash_algos); i++) {
-		git_hash_ctx ctx;
+		struct git_hash_ctx ctx;
 		unsigned char hash[GIT_MAX_HEXSZ];
 		const struct git_hash_algo *algop = &hash_algos[i];
 
 		algop->init_fn(&ctx);
-		algop->update_fn(&ctx, data, data_length);
-		algop->final_fn(hash, &ctx);
+		git_hash_update(&ctx, data, data_length);
+		git_hash_final(hash, &ctx);
 
-		if (!check_str(hash_to_hex_algop(hash, algop), expected_hashes[i - 1]))
-			test_msg("result does not match with the expected for %s\n", hash_algos[i].name);
+		cl_assert_equal_s(hash_to_hex_algop(hash,algop), expected_hashes[i - 1]);
 	}
 }
 
 /* Works with a NUL terminated string. Doesn't work if it should contain a NUL character. */
 #define TEST_HASH_STR(data, expected_sha1, expected_sha256) do { \
 		const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \
-		TEST(check_hash_data(data, strlen(data), expected_hashes), \
-		     "SHA1 and SHA256 (%s) works", #data); \
+		check_hash_data(data, strlen(data), expected_hashes); \
 	} while (0)
 
 /* Only works with a literal string, useful when it contains a NUL character. */
 #define TEST_HASH_LITERAL(literal, expected_sha1, expected_sha256) do { \
 		const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \
-		TEST(check_hash_data(literal, (sizeof(literal) - 1), expected_hashes), \
-		     "SHA1 and SHA256 (%s) works", #literal); \
+		check_hash_data(literal, (sizeof(literal) - 1), expected_hashes); \
 	} while (0)
 
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
+void test_hash__empty_string(void)
 {
-	struct strbuf aaaaaaaaaa_100000 = STRBUF_INIT;
-	struct strbuf alphabet_100000 = STRBUF_INIT;
-
-	strbuf_addstrings(&aaaaaaaaaa_100000, "aaaaaaaaaa", 100000);
-	strbuf_addstrings(&alphabet_100000, "abcdefghijklmnopqrstuvwxyz", 100000);
-
 	TEST_HASH_STR("",
 		"da39a3ee5e6b4b0d3255bfef95601890afd80709",
 		"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+}
+
+void test_hash__single_character(void)
+{
 	TEST_HASH_STR("a",
 		"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
 		"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb");
+}
+
+void test_hash__multi_character(void)
+{
 	TEST_HASH_STR("abc",
 		"a9993e364706816aba3e25717850c26c9cd0d89d",
 		"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
+}
+
+void test_hash__message_digest(void)
+{
 	TEST_HASH_STR("message digest",
 		"c12252ceda8be8994d5fa0290a47231c1d16aae3",
 		"f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650");
+}
+
+void test_hash__alphabet(void)
+{
 	TEST_HASH_STR("abcdefghijklmnopqrstuvwxyz",
 		"32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
 		"71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73");
+}
+
+void test_hash__aaaaaaaaaa_100000(void)
+{
+	struct strbuf aaaaaaaaaa_100000 = STRBUF_INIT;
+	strbuf_addstrings(&aaaaaaaaaa_100000, "aaaaaaaaaa", 100000);
 	TEST_HASH_STR(aaaaaaaaaa_100000.buf,
 		"34aa973cd4c4daa4f61eeb2bdbad27316534016f",
 		"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
+	strbuf_release(&aaaaaaaaaa_100000);
+}
+
+void test_hash__alphabet_100000(void)
+{
+	struct strbuf alphabet_100000 = STRBUF_INIT;
+	strbuf_addstrings(&alphabet_100000, "abcdefghijklmnopqrstuvwxyz", 100000);
 	TEST_HASH_STR(alphabet_100000.buf,
 		"e7da7c55b3484fdf52aebec9cbe7b85a98f02fd4",
 		"e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35");
+	strbuf_release(&alphabet_100000);
+}
+
+void test_hash__zero_blob_literal(void)
+{
 	TEST_HASH_LITERAL("blob 0\0",
 		"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
 		"473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813");
+}
+
+void test_hash__three_blob_literal(void)
+{
 	TEST_HASH_LITERAL("blob 3\0abc",
 		"f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f",
 		"c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6");
+}
+
+void test_hash__zero_tree_literal(void)
+{
 	TEST_HASH_LITERAL("tree 0\0",
 		"4b825dc642cb6eb9a060e54bf8d69288fbee4904",
 		"6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321");
-
-	strbuf_release(&aaaaaaaaaa_100000);
-	strbuf_release(&alphabet_100000);
-
-	return test_done();
 }
diff --git a/t/unit-tests/t-hashmap.c b/t/unit-tests/u-hashmap.c
similarity index 61%
rename from t/unit-tests/t-hashmap.c
rename to t/unit-tests/u-hashmap.c
index 83b79df..eb80aa1 100644
--- a/t/unit-tests/t-hashmap.c
+++ b/t/unit-tests/u-hashmap.c
@@ -1,4 +1,4 @@
-#include "test-lib.h"
+#include "unit-test.h"
 #include "hashmap.h"
 #include "strbuf.h"
 
@@ -83,23 +83,23 @@ static void t_replace(struct hashmap *map, unsigned int ignore_case)
 	struct test_entry *entry;
 
 	entry = alloc_test_entry("key1", "value1", ignore_case);
-	check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+	cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
 
 	entry = alloc_test_entry(ignore_case ? "Key1" : "key1", "value2",
 				 ignore_case);
 	entry = hashmap_put_entry(map, entry, ent);
-	if (check(entry != NULL))
-		check_str(get_value(entry), "value1");
+	cl_assert(entry != NULL);
+	cl_assert_equal_s(get_value(entry), "value1");
 	free(entry);
 
 	entry = alloc_test_entry("fooBarFrotz", "value3", ignore_case);
-	check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+	cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
 
 	entry = alloc_test_entry(ignore_case ? "FOObarFrotz" : "fooBarFrotz",
 				 "value4", ignore_case);
 	entry = hashmap_put_entry(map, entry, ent);
-	if (check(entry != NULL))
-		check_str(get_value(entry), "value3");
+	cl_assert(entry != NULL);
+	cl_assert_equal_s(get_value(entry), "value3");
 	free(entry);
 }
 
@@ -122,20 +122,18 @@ static void t_get(struct hashmap *map, unsigned int ignore_case)
 	for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
 		entry = alloc_test_entry(key_val[i][0], key_val[i][1],
 					 ignore_case);
-		check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+		cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
 	}
 
 	for (size_t i = 0; i < ARRAY_SIZE(query); i++) {
 		entry = get_test_entry(map, query[i][0], ignore_case);
-		if (check(entry != NULL))
-			check_str(get_value(entry), query[i][1]);
-		else
-			test_msg("query key: %s", query[i][0]);
+		cl_assert(entry != NULL);
+		cl_assert_equal_s(get_value(entry), query[i][1]);
 	}
 
-	check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL);
-	check_int(map->tablesize, ==, 64);
-	check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+	cl_assert_equal_p(get_test_entry(map, "notInMap", ignore_case), NULL);
+	cl_assert_equal_i(map->tablesize, 64);
+	cl_assert_equal_i(hashmap_get_size(map), ARRAY_SIZE(key_val));
 }
 
 static void t_add(struct hashmap *map, unsigned int ignore_case)
@@ -165,39 +163,19 @@ static void t_add(struct hashmap *map, unsigned int ignore_case)
 
 		hashmap_for_each_entry_from(map, entry, ent)
 		{
-			int ret;
-			if (!check_int((ret = key_val_contains(
-						key_val, seen,
-						ARRAY_SIZE(key_val), entry)),
-				       ==, 0)) {
-				switch (ret) {
-				case 1:
-					test_msg("found entry was not given in the input\n"
-						 "    key: %s\n  value: %s",
-						 entry->key, get_value(entry));
-					break;
-				case 2:
-					test_msg("duplicate entry detected\n"
-						 "    key: %s\n  value: %s",
-						 entry->key, get_value(entry));
-					break;
-				}
-			} else {
-				count++;
-			}
+			int ret = key_val_contains(key_val, seen,
+						   ARRAY_SIZE(key_val), entry);
+			cl_assert_equal_i(ret, 0);
+			count++;
 		}
-		check_int(count, ==, 2);
+		cl_assert_equal_i(count, 2);
 	}
 
-	for (size_t i = 0; i < ARRAY_SIZE(seen); i++) {
-		if (!check_int(seen[i], ==, 1))
-			test_msg("following key-val pair was not iterated over:\n"
-				 "    key: %s\n  value: %s",
-				 key_val[i][0], key_val[i][1]);
-	}
+	for (size_t i = 0; i < ARRAY_SIZE(seen); i++)
+		cl_assert_equal_i(seen[i], 1);
 
-	check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
-	check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL);
+	cl_assert_equal_i(hashmap_get_size(map), ARRAY_SIZE(key_val));
+	cl_assert_equal_p(get_test_entry(map, "notInMap", ignore_case), NULL);
 }
 
 static void t_remove(struct hashmap *map, unsigned int ignore_case)
@@ -211,24 +189,25 @@ static void t_remove(struct hashmap *map, unsigned int ignore_case)
 
 	for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
 		entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case);
-		check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+		cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
 	}
 
 	for (size_t i = 0; i < ARRAY_SIZE(remove); i++) {
 		entry = alloc_test_entry(remove[i][0], "", ignore_case);
 		removed = hashmap_remove_entry(map, entry, ent, remove[i][0]);
-		if (check(removed != NULL))
-			check_str(get_value(removed), remove[i][1]);
+		cl_assert(removed != NULL);
+		cl_assert_equal_s(get_value(removed), remove[i][1]);
 		free(entry);
 		free(removed);
 	}
 
 	entry = alloc_test_entry("notInMap", "", ignore_case);
-	check_pointer_eq(hashmap_remove_entry(map, entry, ent, "notInMap"), NULL);
+	cl_assert_equal_p(hashmap_remove_entry(map, entry, ent, "notInMap"), NULL);
 	free(entry);
 
-	check_int(map->tablesize, ==, 64);
-	check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val) - ARRAY_SIZE(remove));
+	cl_assert_equal_i(map->tablesize, 64);
+	cl_assert_equal_i(hashmap_get_size(map),
+			  ARRAY_SIZE(key_val) - ARRAY_SIZE(remove));
 }
 
 static void t_iterate(struct hashmap *map, unsigned int ignore_case)
@@ -242,38 +221,21 @@ static void t_iterate(struct hashmap *map, unsigned int ignore_case)
 
 	for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
 		entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case);
-		check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+		cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
 	}
 
 	hashmap_for_each_entry(map, &iter, entry, ent /* member name */)
 	{
-		int ret;
-		if (!check_int((ret = key_val_contains(key_val, seen,
-						       ARRAY_SIZE(key_val),
-						       entry)), ==, 0)) {
-			switch (ret) {
-			case 1:
-				test_msg("found entry was not given in the input\n"
-					 "    key: %s\n  value: %s",
-					 entry->key, get_value(entry));
-				break;
-			case 2:
-				test_msg("duplicate entry detected\n"
-					 "    key: %s\n  value: %s",
-					 entry->key, get_value(entry));
-				break;
-			}
-		}
+		int ret = key_val_contains(key_val, seen,
+					   ARRAY_SIZE(key_val),
+					   entry);
+		cl_assert(ret == 0);
 	}
 
-	for (size_t i = 0; i < ARRAY_SIZE(seen); i++) {
-		if (!check_int(seen[i], ==, 1))
-			test_msg("following key-val pair was not iterated over:\n"
-				 "    key: %s\n  value: %s",
-				 key_val[i][0], key_val[i][1]);
-	}
+	for (size_t i = 0; i < ARRAY_SIZE(seen); i++)
+		cl_assert_equal_i(seen[i], 1);
 
-	check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+	cl_assert_equal_i(hashmap_get_size(map), ARRAY_SIZE(key_val));
 }
 
 static void t_alloc(struct hashmap *map, unsigned int ignore_case)
@@ -284,17 +246,17 @@ static void t_alloc(struct hashmap *map, unsigned int ignore_case)
 		char *key = xstrfmt("key%d", i);
 		char *value = xstrfmt("value%d", i);
 		entry = alloc_test_entry(key, value, ignore_case);
-		check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+		cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
 		free(key);
 		free(value);
 	}
-	check_int(map->tablesize, ==, 64);
-	check_int(hashmap_get_size(map), ==, 51);
+	cl_assert_equal_i(map->tablesize, 64);
+	cl_assert_equal_i(hashmap_get_size(map), 51);
 
 	entry = alloc_test_entry("key52", "value52", ignore_case);
-	check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
-	check_int(map->tablesize, ==, 256);
-	check_int(hashmap_get_size(map), ==, 52);
+	cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL);
+	cl_assert_equal_i(map->tablesize, 256);
+	cl_assert_equal_i(hashmap_get_size(map), 52);
 
 	for (int i = 1; i <= 12; i++) {
 		char *key = xstrfmt("key%d", i);
@@ -302,27 +264,27 @@ static void t_alloc(struct hashmap *map, unsigned int ignore_case)
 
 		entry = alloc_test_entry(key, "", ignore_case);
 		removed = hashmap_remove_entry(map, entry, ent, key);
-		if (check(removed != NULL))
-			check_str(value, get_value(removed));
+		cl_assert(removed != NULL);
+		cl_assert_equal_s(value, get_value(removed));
 		free(key);
 		free(value);
 		free(entry);
 		free(removed);
 	}
-	check_int(map->tablesize, ==, 256);
-	check_int(hashmap_get_size(map), ==, 40);
+	cl_assert_equal_i(map->tablesize, 256);
+	cl_assert_equal_i(hashmap_get_size(map), 40);
 
 	entry = alloc_test_entry("key40", "", ignore_case);
 	removed = hashmap_remove_entry(map, entry, ent, "key40");
-	if (check(removed != NULL))
-		check_str("value40", get_value(removed));
-	check_int(map->tablesize, ==, 64);
-	check_int(hashmap_get_size(map), ==, 39);
+	cl_assert(removed != NULL);
+	cl_assert_equal_s("value40", get_value(removed));
+	cl_assert_equal_i(map->tablesize, 64);
+	cl_assert_equal_i(hashmap_get_size(map), 39);
 	free(entry);
 	free(removed);
 }
 
-static void t_intern(void)
+void test_hashmap__intern(void)
 {
 	const char *values[] = { "value1", "Value1", "value2", "value2" };
 
@@ -330,32 +292,68 @@ static void t_intern(void)
 		const char *i1 = strintern(values[i]);
 		const char *i2 = strintern(values[i]);
 
-		if (!check(!strcmp(i1, values[i])))
-			test_msg("strintern(%s) returns %s\n", values[i], i1);
-		else if (!check(i1 != values[i]))
-			test_msg("strintern(%s) returns input pointer\n",
-				 values[i]);
-		else if (!check_pointer_eq(i1, i2))
-			test_msg("address('%s') != address('%s'), so strintern('%s') != strintern('%s')",
-				 i1, i2, values[i], values[i]);
-		else
-			check_str(i1, values[i]);
+		cl_assert_equal_s(i1, values[i]);
+		cl_assert(i1 != values[i]);
+		cl_assert_equal_p(i1, i2);
 	}
 }
 
-int cmd_main(int argc UNUSED, const char **argv UNUSED)
+void test_hashmap__replace_case_sensitive(void)
 {
-	TEST(setup(t_replace, 0), "replace works");
-	TEST(setup(t_replace, 1), "replace (case insensitive) works");
-	TEST(setup(t_get, 0), "get works");
-	TEST(setup(t_get, 1), "get (case insensitive) works");
-	TEST(setup(t_add, 0), "add works");
-	TEST(setup(t_add, 1), "add (case insensitive) works");
-	TEST(setup(t_remove, 0), "remove works");
-	TEST(setup(t_remove, 1), "remove (case insensitive) works");
-	TEST(setup(t_iterate, 0), "iterate works");
-	TEST(setup(t_iterate, 1), "iterate (case insensitive) works");
-	TEST(setup(t_alloc, 0), "grow / shrink works");
-	TEST(t_intern(), "string interning works");
-	return test_done();
+	setup(t_replace, 0);
+}
+
+void test_hashmap__replace_case_insensitive(void)
+{
+	setup(t_replace, 1);
+}
+
+void test_hashmap__get_case_sensitive(void)
+{
+	setup(t_get, 0);
+}
+
+void test_hashmap__get_case_insensitive(void)
+{
+	setup(t_get, 1);
+}
+
+void test_hashmap__add_case_sensitive(void)
+{
+	setup(t_add, 0);
+}
+
+void test_hashmap__add_case_insensitive(void)
+{
+	setup(t_add, 1);
+}
+
+void test_hashmap__remove_case_sensitive(void)
+{
+	setup(t_remove, 0);
+}
+
+void test_hashmap__remove_case_insensitive(void)
+{
+	setup(t_remove, 1);
+}
+
+void test_hashmap__iterate_case_sensitive(void)
+{
+	setup(t_iterate, 0);
+}
+
+void test_hashmap__iterate_case_insensitive(void)
+{
+	setup(t_iterate, 1);
+}
+
+void test_hashmap__alloc_case_sensitive(void)
+{
+	setup(t_alloc, 0);
+}
+
+void test_hashmap__alloc_case_insensitive(void)
+{
+	setup(t_alloc, 1);
 }
diff --git a/t/unit-tests/u-mem-pool.c b/t/unit-tests/u-mem-pool.c
new file mode 100644
index 0000000..2bc2493
--- /dev/null
+++ b/t/unit-tests/u-mem-pool.c
@@ -0,0 +1,25 @@
+#include "unit-test.h"
+#include "mem-pool.h"
+
+static void test_many_pool_allocations(size_t block_alloc)
+{
+	struct mem_pool pool = { .block_alloc = block_alloc };
+	size_t size = 100;
+	char *buffer = mem_pool_calloc(&pool, 1, size);
+	for (size_t i = 0; i < size; i++)
+		cl_assert_equal_i(0, buffer[i]);
+	cl_assert(pool.mp_block != NULL);
+	cl_assert(pool.mp_block->next_free != NULL);
+	cl_assert(pool.mp_block->end != NULL);
+	mem_pool_discard(&pool, 0);
+}
+
+void test_mem_pool__big_block(void)
+{
+	test_many_pool_allocations(1024 * 1024);
+}
+
+void test_mem_pool__tiny_block(void)
+{
+	test_many_pool_allocations(1);
+}
diff --git a/t/unit-tests/u-oid-array.c b/t/unit-tests/u-oid-array.c
new file mode 100644
index 0000000..e48a433
--- /dev/null
+++ b/t/unit-tests/u-oid-array.c
@@ -0,0 +1,129 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "unit-test.h"
+#include "lib-oid.h"
+#include "oid-array.h"
+#include "hex.h"
+
+static void fill_array(struct oid_array *array, const char *hexes[], size_t n)
+{
+	for (size_t i = 0; i < n; i++) {
+		struct object_id oid;
+
+		cl_parse_any_oid(hexes[i], &oid);
+		oid_array_append(array, &oid);
+	}
+	cl_assert_equal_i(array->nr, n);
+}
+
+static int add_to_oid_array(const struct object_id *oid, void *data)
+{
+	struct oid_array *array = data;
+
+	oid_array_append(array, oid);
+	return 0;
+}
+
+static void t_enumeration(const char **input_args, size_t input_sz,
+			  const char **expect_args, size_t expect_sz)
+{
+	struct oid_array input = OID_ARRAY_INIT, expect = OID_ARRAY_INIT,
+			 actual = OID_ARRAY_INIT;
+	size_t i;
+
+	fill_array(&input, input_args, input_sz);
+	fill_array(&expect, expect_args, expect_sz);
+
+	oid_array_for_each_unique(&input, add_to_oid_array, &actual);
+	cl_assert_equal_i(actual.nr, expect.nr);
+
+	for (i = 0; i < actual.nr; i++)
+		cl_assert(oideq(&actual.oid[i], &expect.oid[i]));
+
+	oid_array_clear(&actual);
+	oid_array_clear(&input);
+	oid_array_clear(&expect);
+}
+
+#define TEST_ENUMERATION(input, expect)                                     \
+	t_enumeration(input, ARRAY_SIZE(input), expect, ARRAY_SIZE(expect));
+
+static void t_lookup(const char **input_hexes, size_t n, const char *query_hex,
+		     int lower_bound, int upper_bound)
+{
+	struct oid_array array = OID_ARRAY_INIT;
+	struct object_id oid_query;
+	int ret;
+
+	cl_parse_any_oid(query_hex, &oid_query);
+	fill_array(&array, input_hexes, n);
+	ret = oid_array_lookup(&array, &oid_query);
+
+	cl_assert(ret <= upper_bound);
+	cl_assert(ret >= lower_bound);
+
+	oid_array_clear(&array);
+}
+
+#define TEST_LOOKUP(input_hexes, query, lower_bound, upper_bound) \
+	t_lookup(input_hexes, ARRAY_SIZE(input_hexes), query,      \
+		      lower_bound, upper_bound);
+
+void test_oid_array__initialize(void)
+{
+	/* The hash algo is used by oid_array_lookup() internally */
+	int algo = cl_setup_hash_algo();
+	repo_set_hash_algo(the_repository, algo);
+}
+
+static const char *arr_input[] = { "88", "44", "aa", "55" };
+static const char *arr_input_dup[] = { "88", "44", "aa", "55",
+				       "88", "44", "aa", "55",
+				       "88", "44", "aa", "55" };
+static const char *res_sorted[] = { "44", "55", "88", "aa" };
+
+void test_oid_array__enumerate_unique(void)
+{
+	TEST_ENUMERATION(arr_input, res_sorted);
+}
+
+void test_oid_array__enumerate_duplicate(void)
+{
+	TEST_ENUMERATION(arr_input_dup, res_sorted);
+}
+
+void test_oid_array__lookup(void)
+{
+	TEST_LOOKUP(arr_input, "55", 1, 1);
+}
+
+void test_oid_array__lookup_non_existent(void)
+{
+	TEST_LOOKUP(arr_input, "33", INT_MIN, -1);
+}
+
+void test_oid_array__lookup_duplicates(void)
+{
+	TEST_LOOKUP(arr_input_dup, "55", 3, 5);
+}
+
+void test_oid_array__lookup_non_existent_dup(void)
+{
+	TEST_LOOKUP(arr_input_dup, "66", INT_MIN, -1);
+}
+
+void test_oid_array__lookup_almost_dup(void)
+{
+	const char *nearly_55;
+
+	nearly_55 = cl_setup_hash_algo() == GIT_HASH_SHA1 ?
+			"5500000000000000000000000000000000000001" :
+			"5500000000000000000000000000000000000000000000000000000000000001";
+
+	TEST_LOOKUP(((const char *[]){ "55", nearly_55 }), "55", 0, 0);
+}
+
+void test_oid_array__lookup_single_dup(void)
+{
+	TEST_LOOKUP(((const char *[]){ "55", "55" }), "55", 0, 1);
+}
diff --git a/t/unit-tests/u-oidmap.c b/t/unit-tests/u-oidmap.c
new file mode 100644
index 0000000..dc805b7
--- /dev/null
+++ b/t/unit-tests/u-oidmap.c
@@ -0,0 +1,136 @@
+#include "unit-test.h"
+#include "lib-oid.h"
+#include "oidmap.h"
+#include "hash.h"
+#include "hex.h"
+
+/*
+ * Elements we will put in oidmap structs are made of a key: the entry.oid
+ * field, which is of type struct object_id, and a value: the name field (could
+ * be a refname for example).
+ */
+struct test_entry {
+	struct oidmap_entry entry;
+	char name[FLEX_ARRAY];
+};
+
+static const char *const key_val[][2] = { { "11", "one" },
+					  { "22", "two" },
+					  { "33", "three" } };
+
+static struct oidmap map;
+
+void test_oidmap__initialize(void)
+{
+	oidmap_init(&map, 0);
+
+	for (size_t i = 0; i < ARRAY_SIZE(key_val); i++){
+		struct test_entry *entry;
+
+		FLEX_ALLOC_STR(entry, name, key_val[i][1]);
+		cl_parse_any_oid(key_val[i][0], &entry->entry.oid);
+		cl_assert(oidmap_put(&map, entry) == NULL);
+	}
+}
+
+void test_oidmap__cleanup(void)
+{
+	oidmap_free(&map, 1);
+}
+
+void test_oidmap__replace(void)
+{
+	struct test_entry *entry, *prev;
+
+	FLEX_ALLOC_STR(entry, name, "un");
+	cl_parse_any_oid("11", &entry->entry.oid);
+	prev = oidmap_put(&map, entry);
+	cl_assert(prev != NULL);
+	cl_assert_equal_s(prev->name, "one");
+	free(prev);
+
+	FLEX_ALLOC_STR(entry, name, "deux");
+	cl_parse_any_oid("22", &entry->entry.oid);
+	prev = oidmap_put(&map, entry);
+	cl_assert(prev != NULL);
+	cl_assert_equal_s(prev->name, "two");
+	free(prev);
+}
+
+void test_oidmap__get(void)
+{
+	struct test_entry *entry;
+	struct object_id oid;
+
+	cl_parse_any_oid("22", &oid);
+	entry = oidmap_get(&map, &oid);
+	cl_assert(entry != NULL);
+	cl_assert_equal_s(entry->name, "two");
+
+	cl_parse_any_oid("44", &oid);
+	cl_assert(oidmap_get(&map, &oid) == NULL);
+
+	cl_parse_any_oid("11", &oid);
+	entry = oidmap_get(&map, &oid);
+	cl_assert(entry != NULL);
+	cl_assert_equal_s(entry->name, "one");
+}
+
+void test_oidmap__remove(void)
+{
+	struct test_entry *entry;
+	struct object_id oid;
+
+	cl_parse_any_oid("11", &oid);
+	entry = oidmap_remove(&map, &oid);
+	cl_assert(entry != NULL);
+	cl_assert_equal_s(entry->name, "one");
+	cl_assert(oidmap_get(&map, &oid) == NULL);
+	free(entry);
+
+	cl_parse_any_oid("22", &oid);
+	entry = oidmap_remove(&map, &oid);
+	cl_assert(entry != NULL);
+	cl_assert_equal_s(entry->name, "two");
+	cl_assert(oidmap_get(&map, &oid) == NULL);
+	free(entry);
+
+	cl_parse_any_oid("44", &oid);
+	cl_assert(oidmap_remove(&map, &oid) == NULL);
+}
+
+static int key_val_contains(struct test_entry *entry, char seen[])
+{
+	for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+		struct object_id oid;
+
+		cl_parse_any_oid(key_val[i][0], &oid);
+
+		if (oideq(&entry->entry.oid, &oid)) {
+			if (seen[i])
+				return 2;
+			seen[i] = 1;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+void test_oidmap__iterate(void)
+{
+	struct oidmap_iter iter;
+	struct test_entry *entry;
+	char seen[ARRAY_SIZE(key_val)] = { 0 };
+	int count = 0;
+
+	oidmap_iter_init(&map, &iter);
+	while ((entry = oidmap_iter_next(&iter))) {
+		if (key_val_contains(entry, seen) != 0) {
+			cl_failf("Unexpected entry: name = %s, oid = %s",
+				 entry->name, oid_to_hex(&entry->entry.oid));
+		}
+		count++;
+	}
+	cl_assert_equal_i(count, ARRAY_SIZE(key_val));
+	cl_assert_equal_i(hashmap_get_size(&map.map), ARRAY_SIZE(key_val));
+}
diff --git a/t/unit-tests/u-oidtree.c b/t/unit-tests/u-oidtree.c
new file mode 100644
index 0000000..e6eede2
--- /dev/null
+++ b/t/unit-tests/u-oidtree.c
@@ -0,0 +1,107 @@
+#include "unit-test.h"
+#include "lib-oid.h"
+#include "oidtree.h"
+#include "hash.h"
+#include "hex.h"
+#include "strvec.h"
+
+static struct oidtree ot;
+
+#define FILL_TREE(tree, ...)                                       \
+	do {                                                       \
+		const char *hexes[] = { __VA_ARGS__ };             \
+		if (fill_tree_loc(tree, hexes, ARRAY_SIZE(hexes))) \
+			return;                                    \
+	} while (0)
+
+static int fill_tree_loc(struct oidtree *ot, const char *hexes[], size_t n)
+{
+	for (size_t i = 0; i < n; i++) {
+		struct object_id oid;
+		cl_parse_any_oid(hexes[i], &oid);
+		oidtree_insert(ot, &oid);
+	}
+	return 0;
+}
+
+static void check_contains(struct oidtree *ot, const char *hex, int expected)
+{
+	struct object_id oid;
+
+	cl_parse_any_oid(hex, &oid);
+	cl_assert_equal_i(oidtree_contains(ot, &oid), expected);
+}
+
+struct expected_hex_iter {
+	size_t i;
+	struct strvec expected_hexes;
+	const char *query;
+};
+
+static enum cb_next check_each_cb(const struct object_id *oid, void *data)
+{
+	struct expected_hex_iter *hex_iter = data;
+	struct object_id expected;
+
+	cl_assert(hex_iter->i < hex_iter->expected_hexes.nr);
+
+	cl_parse_any_oid(hex_iter->expected_hexes.v[hex_iter->i],
+			 &expected);
+	cl_assert_equal_s(oid_to_hex(oid), oid_to_hex(&expected));
+	hex_iter->i += 1;
+	return CB_CONTINUE;
+}
+
+LAST_ARG_MUST_BE_NULL
+static void check_each(struct oidtree *ot, const char *query, ...)
+{
+	struct object_id oid;
+	struct expected_hex_iter hex_iter = { .expected_hexes = STRVEC_INIT,
+					      .query = query };
+	const char *arg;
+	va_list hex_args;
+
+	va_start(hex_args, query);
+	while ((arg = va_arg(hex_args, const char *)))
+		strvec_push(&hex_iter.expected_hexes, arg);
+	va_end(hex_args);
+
+	cl_parse_any_oid(query, &oid);
+	oidtree_each(ot, &oid, strlen(query), check_each_cb, &hex_iter);
+
+	if (hex_iter.i != hex_iter.expected_hexes.nr)
+		cl_failf("error: could not find some 'object_id's for query ('%s')", query);
+
+	strvec_clear(&hex_iter.expected_hexes);
+}
+
+void test_oidtree__initialize(void)
+{
+	oidtree_init(&ot);
+}
+
+void test_oidtree__cleanup(void)
+{
+	oidtree_clear(&ot);
+}
+
+void test_oidtree__contains(void)
+{
+	FILL_TREE(&ot, "444", "1", "2", "3", "4", "5", "a", "b", "c", "d", "e");
+	check_contains(&ot, "44", 0);
+	check_contains(&ot, "441", 0);
+	check_contains(&ot, "440", 0);
+	check_contains(&ot, "444", 1);
+	check_contains(&ot, "4440", 1);
+	check_contains(&ot, "4444", 0);
+}
+
+void test_oidtree__each(void)
+{
+	FILL_TREE(&ot, "f", "9", "8", "123", "321", "320", "a", "b", "c", "d", "e");
+	check_each(&ot, "12300", "123", NULL);
+	check_each(&ot, "3211", NULL); /* should not reach callback */
+	check_each(&ot, "3210", "321", NULL);
+	check_each(&ot, "32100", "321", NULL);
+	check_each(&ot, "32", "320", "321", NULL);
+}
diff --git a/t/unit-tests/u-prio-queue.c b/t/unit-tests/u-prio-queue.c
new file mode 100644
index 0000000..145e689
--- /dev/null
+++ b/t/unit-tests/u-prio-queue.c
@@ -0,0 +1,94 @@
+#include "unit-test.h"
+#include "prio-queue.h"
+
+static int intcmp(const void *va, const void *vb, void *data UNUSED)
+{
+	const int *a = va, *b = vb;
+	return *a - *b;
+}
+
+
+#define MISSING  -1
+#define DUMP	 -2
+#define STACK	 -3
+#define GET	 -4
+#define REVERSE  -5
+
+static int show(int *v)
+{
+	return v ? *v : MISSING;
+}
+
+static void test_prio_queue(int *input, size_t input_size,
+			    int *result, size_t result_size)
+{
+	struct prio_queue pq = { intcmp };
+	size_t j = 0;
+
+	for (size_t i = 0; i < input_size; i++) {
+		void *peek, *get;
+		switch(input[i]) {
+		case GET:
+			peek = prio_queue_peek(&pq);
+			get = prio_queue_get(&pq);
+			cl_assert(peek == get);
+			cl_assert(j < result_size);
+			cl_assert_equal_i(result[j], show(get));
+			j++;
+			break;
+		case DUMP:
+			while ((peek = prio_queue_peek(&pq))) {
+				get = prio_queue_get(&pq);
+				cl_assert(peek == get);
+				cl_assert(j < result_size);
+				cl_assert_equal_i(result[j], show(get));
+				j++;
+			}
+			break;
+		case STACK:
+			pq.compare = NULL;
+			break;
+		case REVERSE:
+			prio_queue_reverse(&pq);
+			break;
+		default:
+			prio_queue_put(&pq, &input[i]);
+			break;
+		}
+	}
+	cl_assert_equal_i(j, result_size);
+	clear_prio_queue(&pq);
+}
+
+#define TEST_INPUT(input, result) \
+	test_prio_queue(input, ARRAY_SIZE(input), result, ARRAY_SIZE(result))
+
+void test_prio_queue__basic(void)
+{
+	TEST_INPUT(((int []){ 2, 6, 3, 10, 9, 5, 7, 4, 5, 8, 1, DUMP }),
+		   ((int []){ 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10 }));
+}
+
+void test_prio_queue__mixed(void)
+{
+	TEST_INPUT(((int []){ 6, 2, 4, GET, 5, 3, GET, GET, 1, DUMP }),
+		   ((int []){ 2, 3, 4, 1, 5, 6 }));
+}
+
+void test_prio_queue__empty(void)
+{
+	TEST_INPUT(((int []){ 1, 2, GET, GET, GET, 1, 2, GET, GET, GET }),
+		   ((int []){ 1, 2, MISSING, 1, 2, MISSING }));
+}
+
+void test_prio_queue__stack(void)
+{
+	TEST_INPUT(((int []){ STACK, 8, 1, 5, 4, 6, 2, 3, DUMP }),
+		   ((int []){ 3, 2, 6, 4, 5, 1, 8 }));
+}
+
+void test_prio_queue__reverse_stack(void)
+{
+	TEST_INPUT(((int []){ STACK, 1, 2, 3, 4, 5, 6, REVERSE, DUMP }),
+		   ((int []){ 1, 2, 3, 4, 5, 6 }));
+}
diff --git a/t/unit-tests/t-reftable-tree.c b/t/unit-tests/u-reftable-tree.c
similarity index 68%
rename from t/unit-tests/t-reftable-tree.c
rename to t/unit-tests/u-reftable-tree.c
index 79b175a..bcf9061 100644
--- a/t/unit-tests/t-reftable-tree.c
+++ b/t/unit-tests/u-reftable-tree.c
@@ -6,7 +6,7 @@ license that can be found in the LICENSE file or at
 https://developers.google.com/open-source/licenses/bsd
 */
 
-#include "test-lib.h"
+#include "unit-test.h"
 #include "reftable/tree.h"
 
 static int t_compare(const void *a, const void *b)
@@ -25,7 +25,7 @@ static void store(void *arg, void *key)
 	c->arr[c->len++] = key;
 }
 
-static void t_tree_search(void)
+void test_reftable_tree__tree_search(void)
 {
 	struct tree_node *root = NULL;
 	void *values[11] = { 0 };
@@ -38,20 +38,20 @@ static void t_tree_search(void)
 	 */
 	do {
 		nodes[i] = tree_insert(&root, &values[i], &t_compare);
-		check(nodes[i] != NULL);
+		cl_assert(nodes[i] != NULL);
 		i = (i * 7) % 11;
 	} while (i != 1);
 
 	for (i = 1; i < ARRAY_SIZE(nodes); i++) {
-		check_pointer_eq(&values[i], nodes[i]->key);
-		check_pointer_eq(nodes[i], tree_search(root, &values[i], &t_compare));
+		cl_assert_equal_p(&values[i], nodes[i]->key);
+		cl_assert_equal_p(nodes[i], tree_search(root, &values[i], &t_compare));
 	}
 
-	check(!tree_search(root, values, t_compare));
+	cl_assert(tree_search(root, values, t_compare) == NULL);
 	tree_free(root);
 }
 
-static void t_infix_walk(void)
+void test_reftable_tree__infix_walk(void)
 {
 	struct tree_node *root = NULL;
 	void *values[11] = { 0 };
@@ -64,23 +64,15 @@ static void t_infix_walk(void)
 
 	do {
 		struct tree_node *node = tree_insert(&root, &values[i], t_compare);
-		check(node != NULL);
+		cl_assert(node != NULL);
 		i = (i * 7) % 11;
 		count++;
 	} while (i != 1);
 
 	infix_walk(root, &store, &c);
 	for (i = 1; i < ARRAY_SIZE(values); i++)
-		check_pointer_eq(&values[i], out[i - 1]);
-	check(!out[i - 1]);
-	check_int(c.len, ==, count);
+		cl_assert_equal_p(&values[i], out[i - 1]);
+	cl_assert(out[i - 1] == NULL);
+	cl_assert_equal_i(c.len, count);
 	tree_free(root);
 }
-
-int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
-{
-	TEST(t_tree_search(), "tree_search works");
-	TEST(t_infix_walk(), "infix_walk works");
-
-	return test_done();
-}
diff --git a/t/unit-tests/u-strbuf.c b/t/unit-tests/u-strbuf.c
new file mode 100644
index 0000000..caa5d78
--- /dev/null
+++ b/t/unit-tests/u-strbuf.c
@@ -0,0 +1,119 @@
+#include "unit-test.h"
+#include "strbuf.h"
+
+/* wrapper that supplies tests with an empty, initialized strbuf */
+static void setup(void (*f)(struct strbuf*, const void*),
+		  const void *data)
+{
+	struct strbuf buf = STRBUF_INIT;
+
+	f(&buf, data);
+	strbuf_release(&buf);
+	cl_assert_equal_i(buf.len, 0);
+	cl_assert_equal_i(buf.alloc, 0);
+}
+
+/* wrapper that supplies tests with a populated, initialized strbuf */
+static void setup_populated(void (*f)(struct strbuf*, const void*),
+			    const char *init_str, const void *data)
+{
+	struct strbuf buf = STRBUF_INIT;
+
+	strbuf_addstr(&buf, init_str);
+	cl_assert_equal_i(buf.len, strlen(init_str));
+	f(&buf, data);
+	strbuf_release(&buf);
+	cl_assert_equal_i(buf.len, 0);
+	cl_assert_equal_i(buf.alloc, 0);
+}
+
+static void assert_sane_strbuf(struct strbuf *buf)
+{
+	/* Initialized strbufs should always have a non-NULL buffer */
+	cl_assert(buf->buf != NULL);
+	/* Buffers should always be NUL-terminated */
+	cl_assert(buf->buf[buf->len] == '\0');
+	/*
+         * In case the buffer contains anything, `alloc` must alloc must
+         * be at least one byte larger than `len`.
+         */
+	if (buf->len)
+            cl_assert(buf->len < buf->alloc);
+}
+
+void test_strbuf__static_init(void)
+{
+	struct strbuf buf = STRBUF_INIT;
+
+	cl_assert_equal_i(buf.len, 0);
+	cl_assert_equal_i(buf.alloc, 0);
+	cl_assert(buf.buf[0] == '\0');
+}
+
+void test_strbuf__dynamic_init(void)
+{
+	struct strbuf buf;
+
+	strbuf_init(&buf, 1024);
+	assert_sane_strbuf(&buf);
+	cl_assert_equal_i(buf.len, 0);
+	cl_assert(buf.alloc >= 1024);
+	cl_assert(buf.buf[0] == '\0');
+	strbuf_release(&buf);
+}
+
+static void t_addch(struct strbuf *buf, const void *data)
+{
+	const char *p_ch = data;
+	const char ch = *p_ch;
+	size_t orig_alloc = buf->alloc;
+	size_t orig_len = buf->len;
+
+	assert_sane_strbuf(buf);
+	strbuf_addch(buf, ch);
+	assert_sane_strbuf(buf);
+	cl_assert_equal_i(buf->len, orig_len + 1);
+	cl_assert(buf->alloc >= orig_alloc);
+	cl_assert(buf->buf[buf->len] == '\0');
+}
+
+static void t_addstr(struct strbuf *buf, const void *data)
+{
+	const char *text = data;
+	size_t len = strlen(text);
+	size_t orig_alloc = buf->alloc;
+	size_t orig_len = buf->len;
+
+	assert_sane_strbuf(buf);
+	strbuf_addstr(buf, text);
+	assert_sane_strbuf(buf);
+	cl_assert_equal_i(buf->len, orig_len + len);
+	cl_assert(buf->alloc >= orig_alloc);
+	cl_assert(buf->buf[buf->len] == '\0');
+	cl_assert_equal_s(buf->buf + orig_len, text);
+}
+
+void test_strbuf__add_single_char(void)
+{
+	setup(t_addch, "a");
+}
+
+void test_strbuf__add_empty_char(void)
+{
+	setup(t_addch, "");
+}
+
+void test_strbuf__add_append_char(void)
+{
+	setup_populated(t_addch, "initial value", "a");
+}
+
+void test_strbuf__add_single_str(void)
+{
+	setup(t_addstr, "hello there");
+}
+
+void test_strbuf__add_append_str(void)
+{
+	setup_populated(t_addstr, "initial value", "hello there");
+}
diff --git a/t/unit-tests/u-strcmp-offset.c b/t/unit-tests/u-strcmp-offset.c
new file mode 100644
index 0000000..7e8e9ac
--- /dev/null
+++ b/t/unit-tests/u-strcmp-offset.c
@@ -0,0 +1,45 @@
+#include "unit-test.h"
+#include "read-cache-ll.h"
+
+static void check_strcmp_offset(const char *string1, const char *string2,
+				int expect_result, uintmax_t expect_offset)
+{
+	size_t offset;
+	int result = strcmp_offset(string1, string2, &offset);
+
+	/*
+	 * Because different CRTs behave differently, only rely on signs of the
+	 * result values.
+	 */
+	result = (result < 0 ? -1 :
+			result > 0 ? 1 :
+			0);
+
+	cl_assert_equal_i(result, expect_result);
+	cl_assert_equal_i((uintmax_t)offset, expect_offset);
+}
+
+void test_strcmp_offset__empty(void)
+{
+	check_strcmp_offset("", "", 0, 0);
+}
+
+void test_strcmp_offset__equal(void)
+{
+	check_strcmp_offset("abc", "abc", 0, 3);
+}
+
+void test_strcmp_offset__different(void)
+{
+	check_strcmp_offset("abc", "def", -1, 0);
+}
+
+void test_strcmp_offset__mismatch(void)
+{
+	check_strcmp_offset("abc", "abz", -1, 2);
+}
+
+void test_strcmp_offset__different_length(void)
+{
+	check_strcmp_offset("abc", "abcdef", -1, 3);
+}
diff --git a/t/unit-tests/unit-test.c b/t/unit-tests/unit-test.c
index fa88188..5af6450 100644
--- a/t/unit-tests/unit-test.c
+++ b/t/unit-tests/unit-test.c
@@ -1,5 +1,7 @@
 #include "unit-test.h"
+#include "hex.h"
 #include "parse-options.h"
+#include "strbuf.h"
 #include "string-list.h"
 #include "strvec.h"
 
diff --git a/tempfile.c b/tempfile.c
index ed88cf8..82dfa3d 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -42,6 +42,8 @@
  * file created by its parent.
  */
 
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "abspath.h"
 #include "path.h"
@@ -148,7 +150,7 @@ struct tempfile *create_tempfile_mode(const char *path, int mode)
 		return NULL;
 	}
 	activate_tempfile(tempfile);
-	if (adjust_shared_perm(tempfile->filename.buf)) {
+	if (adjust_shared_perm(the_repository, tempfile->filename.buf)) {
 		int save_errno = errno;
 		error("cannot fix permission bits on %s", tempfile->filename.buf);
 		delete_tempfile(&tempfile);
diff --git a/templates/Makefile b/templates/Makefile
index bd1e9e3..7227553 100644
--- a/templates/Makefile
+++ b/templates/Makefile
@@ -1,3 +1,6 @@
+# The default target of this Makefile is...
+all::
+
 # Import tree-wide shared Makefile behavior and libraries
 include ../shared.mak
 
@@ -23,7 +26,7 @@
 DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 template_instdir_SQ = $(subst ','\'',$(template_instdir))
 
-all: boilerplates.made custom
+all:: boilerplates.made custom
 
 # Put templates that can be copied straight from the source
 # in a file direc--tory--file in the source.  They will be
diff --git a/tmp-objdir.c b/tmp-objdir.c
index 659fcdc..31d16a4 100644
--- a/tmp-objdir.c
+++ b/tmp-objdir.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "tmp-objdir.h"
 #include "abspath.h"
@@ -16,6 +14,7 @@
 #include "repository.h"
 
 struct tmp_objdir {
+	struct repository *repo;
 	struct strbuf path;
 	struct strvec env;
 	struct object_directory *prev_odb;
@@ -116,7 +115,8 @@ static int setup_tmp_objdir(const char *root)
 	return ret;
 }
 
-struct tmp_objdir *tmp_objdir_create(const char *prefix)
+struct tmp_objdir *tmp_objdir_create(struct repository *r,
+				     const char *prefix)
 {
 	static int installed_handlers;
 	struct tmp_objdir *t;
@@ -125,6 +125,7 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix)
 		BUG("only one tmp_objdir can be used at a time");
 
 	t = xcalloc(1, sizeof(*t));
+	t->repo = r;
 	strbuf_init(&t->path, 0);
 	strvec_init(&t->env);
 
@@ -134,7 +135,7 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix)
 	 * them.
 	 */
 	strbuf_addf(&t->path, "%s/tmp_objdir-%s-XXXXXX",
-		    repo_get_object_directory(the_repository), prefix);
+		    repo_get_object_directory(r), prefix);
 
 	if (!mkdtemp(t->path.buf)) {
 		/* free, not destroy, as we never touched the filesystem */
@@ -154,7 +155,7 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix)
 	}
 
 	env_append(&t->env, ALTERNATE_DB_ENVIRONMENT,
-		   absolute_path(repo_get_object_directory(the_repository)));
+		   absolute_path(repo_get_object_directory(r)));
 	env_replace(&t->env, DB_ENVIRONMENT, absolute_path(t->path.buf));
 	env_replace(&t->env, GIT_QUARANTINE_ENVIRONMENT,
 		    absolute_path(t->path.buf));
@@ -206,10 +207,12 @@ static int read_dir_paths(struct string_list *out, const char *path)
 	return 0;
 }
 
-static int migrate_paths(struct strbuf *src, struct strbuf *dst,
+static int migrate_paths(struct tmp_objdir *t,
+			 struct strbuf *src, struct strbuf *dst,
 			 enum finalize_object_file_flags flags);
 
-static int migrate_one(struct strbuf *src, struct strbuf *dst,
+static int migrate_one(struct tmp_objdir *t,
+		       struct strbuf *src, struct strbuf *dst,
 		       enum finalize_object_file_flags flags)
 {
 	struct stat st;
@@ -218,11 +221,11 @@ static int migrate_one(struct strbuf *src, struct strbuf *dst,
 		return -1;
 	if (S_ISDIR(st.st_mode)) {
 		if (!mkdir(dst->buf, 0777)) {
-			if (adjust_shared_perm(dst->buf))
+			if (adjust_shared_perm(t->repo, dst->buf))
 				return -1;
 		} else if (errno != EEXIST)
 			return -1;
-		return migrate_paths(src, dst, flags);
+		return migrate_paths(t, src, dst, flags);
 	}
 	return finalize_object_file_flags(src->buf, dst->buf, flags);
 }
@@ -232,7 +235,8 @@ static int is_loose_object_shard(const char *name)
 	return strlen(name) == 2 && isxdigit(name[0]) && isxdigit(name[1]);
 }
 
-static int migrate_paths(struct strbuf *src, struct strbuf *dst,
+static int migrate_paths(struct tmp_objdir *t,
+			 struct strbuf *src, struct strbuf *dst,
 			 enum finalize_object_file_flags flags)
 {
 	size_t src_len = src->len, dst_len = dst->len;
@@ -254,7 +258,7 @@ static int migrate_paths(struct strbuf *src, struct strbuf *dst,
 		if (is_loose_object_shard(name))
 			flags_copy |= FOF_SKIP_COLLISION_CHECK;
 
-		ret |= migrate_one(src, dst, flags_copy);
+		ret |= migrate_one(t, src, dst, flags_copy);
 
 		strbuf_setlen(src, src_len);
 		strbuf_setlen(dst, dst_len);
@@ -273,16 +277,16 @@ int tmp_objdir_migrate(struct tmp_objdir *t)
 		return 0;
 
 	if (t->prev_odb) {
-		if (the_repository->objects->odb->will_destroy)
+		if (t->repo->objects->odb->will_destroy)
 			BUG("migrating an ODB that was marked for destruction");
 		restore_primary_odb(t->prev_odb, t->path.buf);
 		t->prev_odb = NULL;
 	}
 
 	strbuf_addbuf(&src, &t->path);
-	strbuf_addstr(&dst, repo_get_object_directory(the_repository));
+	strbuf_addstr(&dst, repo_get_object_directory(t->repo));
 
-	ret = migrate_paths(&src, &dst, 0);
+	ret = migrate_paths(t, &src, &dst, 0);
 
 	strbuf_release(&src);
 	strbuf_release(&dst);
diff --git a/tmp-objdir.h b/tmp-objdir.h
index 237d96b..fceda14 100644
--- a/tmp-objdir.h
+++ b/tmp-objdir.h
@@ -11,7 +11,7 @@
  * Example:
  *
  *	struct child_process child = CHILD_PROCESS_INIT;
- *	struct tmp_objdir *t = tmp_objdir_create("incoming");
+ *	struct tmp_objdir *t = tmp_objdir_create(repo, "incoming");
  *	strvec_push(&child.args, cmd);
  *	strvec_pushv(&child.env, tmp_objdir_env(t));
  *	if (!run_command(&child)) && !tmp_objdir_migrate(t))
@@ -21,13 +21,14 @@
  *
  */
 
+struct repository;
 struct tmp_objdir;
 
 /*
  * Create a new temporary object directory with the specified prefix;
  * returns NULL on failure.
  */
-struct tmp_objdir *tmp_objdir_create(const char *prefix);
+struct tmp_objdir *tmp_objdir_create(struct repository *r, const char *prefix);
 
 /*
  * Return a list of environment strings, suitable for use with
diff --git a/trace.c b/trace.c
index 2cfd259..9b99460 100644
--- a/trace.c
+++ b/trace.c
@@ -21,7 +21,6 @@
  *  along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -298,7 +297,7 @@ static const char *quote_crnl(const char *path)
 	return new_path.buf;
 }
 
-void trace_repo_setup(void)
+void trace_repo_setup(struct repository *r)
 {
 	const char *git_work_tree, *prefix = startup_info->prefix;
 	char *cwd;
@@ -308,14 +307,14 @@ void trace_repo_setup(void)
 
 	cwd = xgetcwd();
 
-	if (!(git_work_tree = repo_get_work_tree(the_repository)))
+	if (!(git_work_tree = repo_get_work_tree(r)))
 		git_work_tree = "(null)";
 
 	if (!startup_info->prefix)
 		prefix = "(null)";
 
-	trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(repo_get_git_dir(the_repository)));
-	trace_printf_key(&trace_setup_key, "setup: git_common_dir: %s\n", quote_crnl(repo_get_common_dir(the_repository)));
+	trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(repo_get_git_dir(r)));
+	trace_printf_key(&trace_setup_key, "setup: git_common_dir: %s\n", quote_crnl(repo_get_common_dir(r)));
 	trace_printf_key(&trace_setup_key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
 	trace_printf_key(&trace_setup_key, "setup: cwd: %s\n", quote_crnl(cwd));
 	trace_printf_key(&trace_setup_key, "setup: prefix: %s\n", quote_crnl(prefix));
diff --git a/trace.h b/trace.h
index d304d55..9152fe9 100644
--- a/trace.h
+++ b/trace.h
@@ -92,7 +92,9 @@ 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(void);
+struct repository;
+
+void trace_repo_setup(struct repository *r);
 
 /**
  * Checks whether the trace key is enabled. Used to prevent expensive
diff --git a/trace2.c b/trace2.c
index 82d16e2..c23c0a2 100644
--- a/trace2.c
+++ b/trace2.c
@@ -764,7 +764,7 @@ void trace2_def_param_fl(const char *file, int line, const char *param,
 	if (!trace2_enabled)
 		return;
 
-	redacted = redact_arg(value);
+	redacted = value ? redact_arg(value) : NULL;
 
 	for_each_wanted_builtin (j, tgt_j)
 		if (tgt_j->pfn_param_fl)
diff --git a/trace2.h b/trace2.h
index 901f392..e4f2378 100644
--- a/trace2.h
+++ b/trace2.h
@@ -31,7 +31,7 @@
  *
  * For more info about: trace2 targets, conventions for public functions and
  * macros, trace2 target formats and examples on trace2 API usage refer to
- * Documentation/technical/api-trace2.txt
+ * Documentation/technical/api-trace2.adoc
  *
  */
 
diff --git a/trace2/tr2_sid.c b/trace2/tr2_sid.c
index 09c4ef0..1c1d27b 100644
--- a/trace2/tr2_sid.c
+++ b/trace2/tr2_sid.c
@@ -32,7 +32,7 @@ static void tr2_sid_append_my_sid_component(void)
 {
 	const struct git_hash_algo *algo = &hash_algos[GIT_HASH_SHA1];
 	struct tr2_tbuf tb_now;
-	git_hash_ctx ctx;
+	struct git_hash_ctx ctx;
 	pid_t pid = getpid();
 	unsigned char hash[GIT_MAX_RAWSZ + 1];
 	char hex[GIT_MAX_HEXSZ + 1];
@@ -46,8 +46,8 @@ static void tr2_sid_append_my_sid_component(void)
 		strbuf_add(&tr2sid_buf, "Localhost", 9);
 	else {
 		algo->init_fn(&ctx);
-		algo->update_fn(&ctx, hostname, strlen(hostname));
-		algo->final_fn(hash, &ctx);
+		git_hash_update(&ctx, hostname, strlen(hostname));
+		git_hash_final(hash, &ctx);
 		hash_to_hex_algop_r(hex, hash, algo);
 		strbuf_addch(&tr2sid_buf, 'H');
 		strbuf_add(&tr2sid_buf, hex, 8);
diff --git a/trace2/tr2_sysenv.c b/trace2/tr2_sysenv.c
index 01379c5..4abc218 100644
--- a/trace2/tr2_sysenv.c
+++ b/trace2/tr2_sysenv.c
@@ -7,7 +7,7 @@
 
 /*
  * Each entry represents a trace2 setting.
- * See Documentation/technical/api-trace2.txt
+ * See Documentation/technical/api-trace2.adoc
  */
 struct tr2_sysenv_entry {
 	const char *env_var_name;
diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c
index 69ee404..5a03817 100644
--- a/trace2/tr2_tgt_event.c
+++ b/trace2/tr2_tgt_event.c
@@ -493,7 +493,8 @@ static void fn_param_fl(const char *file, int line, const char *param,
 	event_fmt_prepare(event_name, file, line, NULL, &jw);
 	jw_object_string(&jw, "scope", scope_name);
 	jw_object_string(&jw, "param", param);
-	jw_object_string(&jw, "value", value);
+	if (value)
+		jw_object_string(&jw, "value", value);
 	jw_end(&jw);
 
 	tr2_dst_write_line(&tr2dst_event, &jw.json);
diff --git a/trace2/tr2_tgt_normal.c b/trace2/tr2_tgt_normal.c
index baef48a..924736a 100644
--- a/trace2/tr2_tgt_normal.c
+++ b/trace2/tr2_tgt_normal.c
@@ -307,8 +307,9 @@ static void fn_param_fl(const char *file, int line, const char *param,
 	enum config_scope scope = kvi->scope;
 	const char *scope_name = config_scope_name(scope);
 
-	strbuf_addf(&buf_payload, "def_param scope:%s %s=%s", scope_name, param,
-		    value);
+	strbuf_addf(&buf_payload, "def_param scope:%s %s", scope_name, param);
+	if (value)
+		strbuf_addf(&buf_payload, "=%s", value);
 	normal_io_write_fl(file, line, &buf_payload);
 	strbuf_release(&buf_payload);
 }
diff --git a/trace2/tr2_tgt_perf.c b/trace2/tr2_tgt_perf.c
index 298ae27..4eb9289 100644
--- a/trace2/tr2_tgt_perf.c
+++ b/trace2/tr2_tgt_perf.c
@@ -448,8 +448,9 @@ static void fn_param_fl(const char *file, int line, const char *param,
 	struct strbuf scope_payload = STRBUF_INIT;
 	enum config_scope scope = kvi->scope;
 	const char *scope_name = config_scope_name(scope);
-
-	strbuf_addf(&buf_payload, "%s:%s", param, value);
+	strbuf_addstr(&buf_payload, param);
+	if (value)
+		strbuf_addf(&buf_payload, ":%s", value);
 	strbuf_addf(&scope_payload, "%s:%s", "scope", scope_name);
 
 	perf_io_write_fl(file, line, event_name, NULL, NULL, NULL,
diff --git a/transport.c b/transport.c
index 10d820c..6c2801b 100644
--- a/transport.c
+++ b/transport.c
@@ -207,6 +207,7 @@ static int fetch_refs_from_bundle(struct transport *transport,
 
 	ret = unbundle(the_repository, &data->header, data->fd,
 		       &extra_index_pack_args, &opts);
+	data->fd = -1; /* `unbundle()` closes the file descriptor */
 	transport->hash_algo = data->header.hash_algo;
 
 	strvec_clear(&extra_index_pack_args);
@@ -932,8 +933,15 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
 		break;
 	case protocol_v1:
 	case protocol_v0:
-		ret = send_pack(&args, data->fd, data->conn, remote_refs,
+		ret = send_pack(the_repository, &args, data->fd, data->conn, remote_refs,
 				&data->extra_have);
+		/*
+		 * Ignore the specific error code to maintain consistent behavior
+		 * with the "push_refs()" function across different transports,
+		 * such as "push_refs_with_push()" for HTTP protocol.
+		 */
+		if (ret == ERROR_SEND_PACK_BAD_REF_STATUS)
+			ret = 0;
 		break;
 	case protocol_unknown_version:
 		BUG("unknown protocol version");
@@ -941,15 +949,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
 
 	close(data->fd[1]);
 	close(data->fd[0]);
-	/*
-	 * Atomic push may abort the connection early and close the pipe,
-	 * which may cause an error for `finish_connect()`. Ignore this error
-	 * for atomic git-push.
-	 */
-	if (ret || args.atomic)
-		finish_connect(data->conn);
-	else
-		ret = finish_connect(data->conn);
+	ret |= finish_connect(data->conn);
 	data->conn = NULL;
 	data->finished_handshake = 0;
 
diff --git a/transport.h b/transport.h
index 44100fa..892f194 100644
--- a/transport.h
+++ b/transport.h
@@ -168,7 +168,7 @@ struct transport *transport_get(struct remote *, const char *);
  * Check whether a transport is allowed by the environment.
  *
  * Type should generally be the URL scheme, as described in
- * Documentation/git.txt
+ * Documentation/git.adoc
  *
  * from_user specifies if the transport was given by the user.  If unknown pass
  * a -1 to read from the environment to determine if the transport was given by
diff --git a/tree-diff.c b/tree-diff.c
index d9237ff..60c558c 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -48,8 +48,8 @@
 		free((x)); \
 } while(0)
 
-static struct combine_diff_path *ll_diff_tree_paths(
-	struct combine_diff_path *p, const struct object_id *oid,
+static void ll_diff_tree_paths(
+	struct combine_diff_path ***tail, const struct object_id *oid,
 	const struct object_id **parents_oid, int nparent,
 	struct strbuf *base, struct diff_options *opt,
 	int depth);
@@ -125,72 +125,6 @@ static int emit_diff_first_parent_only(struct diff_options *opt, struct combine_
 
 
 /*
- * Make a new combine_diff_path from path/mode/sha1
- * and append it to paths list tail.
- *
- * Memory for created elements could be reused:
- *
- *	- if last->next == NULL, the memory is allocated;
- *
- *	- if last->next != NULL, it is assumed that p=last->next was returned
- *	  earlier by this function, and p->next was *not* modified.
- *	  The memory is then reused from p.
- *
- * so for clients,
- *
- * - if you do need to keep the element
- *
- *	p = path_appendnew(p, ...);
- *	process(p);
- *	p->next = NULL;
- *
- * - if you don't need to keep the element after processing
- *
- *	pprev = p;
- *	p = path_appendnew(p, ...);
- *	process(p);
- *	p = pprev;
- *	; don't forget to free tail->next in the end
- *
- * p->parent[] remains uninitialized.
- */
-static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
-	int nparent, const struct strbuf *base, const char *path, int pathlen,
-	unsigned mode, const struct object_id *oid)
-{
-	struct combine_diff_path *p;
-	size_t len = st_add(base->len, pathlen);
-	size_t alloclen = combine_diff_path_size(nparent, len);
-
-	/* if last->next is !NULL - it is a pre-allocated memory, we can reuse */
-	p = last->next;
-	if (p && (alloclen > (intptr_t)p->next)) {
-		FREE_AND_NULL(p);
-	}
-
-	if (!p) {
-		p = xmalloc(alloclen);
-
-		/*
-		 * until we go to it next round, .next holds how many bytes we
-		 * allocated (for faster realloc - we don't need copying old data).
-		 */
-		p->next = (struct combine_diff_path *)(intptr_t)alloclen;
-	}
-
-	last->next = p;
-
-	p->path = (char *)&(p->parent[nparent]);
-	memcpy(p->path, base->buf, base->len);
-	memcpy(p->path + base->len, path, pathlen);
-	p->path[len] = 0;
-	p->mode = mode;
-	oidcpy(&p->oid, oid ? oid : null_oid());
-
-	return p;
-}
-
-/*
  * new path should be added to combine diff
  *
  * 3 cases on how/when it should be called and behaves:
@@ -200,10 +134,10 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
  *	 t,  tp		-> path modified/added
  *			   (M for tp[i]=tp[imin], A otherwise)
  */
-static struct combine_diff_path *emit_path(struct combine_diff_path *p,
-	struct strbuf *base, struct diff_options *opt, int nparent,
-	struct tree_desc *t, struct tree_desc *tp,
-	int imin, int depth)
+static void emit_path(struct combine_diff_path ***tail,
+		      struct strbuf *base, struct diff_options *opt,
+		      int nparent, struct tree_desc *t, struct tree_desc *tp,
+		      int imin, int depth)
 {
 	unsigned short mode;
 	const char *path;
@@ -243,8 +177,13 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 
 	if (emitthis) {
 		int keep;
-		struct combine_diff_path *pprev = p;
-		p = path_appendnew(p, nparent, base, path, pathlen, mode, oid);
+		struct combine_diff_path *p;
+
+		strbuf_add(base, path, pathlen);
+		p = combine_diff_path_new(base->buf, base->len, mode,
+					  oid ? oid : null_oid(),
+					  nparent);
+		strbuf_setlen(base, old_baselen);
 
 		for (i = 0; i < nparent; ++i) {
 			/*
@@ -279,21 +218,12 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 		if (opt->pathchange)
 			keep = opt->pathchange(opt, p);
 
-		/*
-		 * If a path was filtered or consumed - we don't need to add it
-		 * to the list and can reuse its memory, leaving it as
-		 * pre-allocated element on the tail.
-		 *
-		 * On the other hand, if path needs to be kept, we need to
-		 * correct its .next to NULL, as it was pre-initialized to how
-		 * much memory was allocated.
-		 *
-		 * see path_appendnew() for details.
-		 */
-		if (!keep)
-			p = pprev;
-		else
-			p->next = NULL;
+		if (keep) {
+			**tail = p;
+			*tail = &p->next;
+		} else {
+			free(p);
+		}
 	}
 
 	if (recurse) {
@@ -309,13 +239,12 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 
 		strbuf_add(base, path, pathlen);
 		strbuf_addch(base, '/');
-		p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt,
-				       depth + 1);
+		ll_diff_tree_paths(tail, oid, parents_oid, nparent, base, opt,
+				   depth + 1);
 		FAST_ARRAY_FREE(parents_oid, nparent);
 	}
 
 	strbuf_setlen(base, old_baselen);
-	return p;
 }
 
 static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
@@ -428,8 +357,8 @@ static inline void update_tp_entries(struct tree_desc *tp, int nparent)
 			update_tree_entry(&tp[i]);
 }
 
-static struct combine_diff_path *ll_diff_tree_paths(
-	struct combine_diff_path *p, const struct object_id *oid,
+static void ll_diff_tree_paths(
+	struct combine_diff_path ***tail, const struct object_id *oid,
 	const struct object_id **parents_oid, int nparent,
 	struct strbuf *base, struct diff_options *opt,
 	int depth)
@@ -533,8 +462,8 @@ static struct combine_diff_path *ll_diff_tree_paths(
 			}
 
 			/* D += {δ(t,pi) if pi=p[imin];  "+a" if pi > p[imin]} */
-			p = emit_path(p, base, opt, nparent,
-					&t, tp, imin, depth);
+			emit_path(tail, base, opt, nparent,
+				  &t, tp, imin, depth);
 
 		skip_emit_t_tp:
 			/* t↓,  ∀ pi=p[imin]  pi↓ */
@@ -545,8 +474,8 @@ static struct combine_diff_path *ll_diff_tree_paths(
 		/* t < p[imin] */
 		else if (cmp < 0) {
 			/* D += "+t" */
-			p = emit_path(p, base, opt, nparent,
-					&t, /*tp=*/NULL, -1, depth);
+			emit_path(tail, base, opt, nparent,
+				  &t, /*tp=*/NULL, -1, depth);
 
 			/* t↓ */
 			update_tree_entry(&t);
@@ -561,8 +490,8 @@ static struct combine_diff_path *ll_diff_tree_paths(
 						goto skip_emit_tp;
 			}
 
-			p = emit_path(p, base, opt, nparent,
-					/*t=*/NULL, tp, imin, depth);
+			emit_path(tail, base, opt, nparent,
+				  /*t=*/NULL, tp, imin, depth);
 
 		skip_emit_tp:
 			/* ∀ pi=p[imin]  pi↓ */
@@ -575,24 +504,16 @@ static struct combine_diff_path *ll_diff_tree_paths(
 		free(tptree[i]);
 	FAST_ARRAY_FREE(tptree, nparent);
 	FAST_ARRAY_FREE(tp, nparent);
-
-	return p;
 }
 
 struct combine_diff_path *diff_tree_paths(
-	struct combine_diff_path *p, const struct object_id *oid,
+	const struct object_id *oid,
 	const struct object_id **parents_oid, int nparent,
 	struct strbuf *base, struct diff_options *opt)
 {
-	p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt, 0);
-
-	/*
-	 * free pre-allocated last element, if any
-	 * (see path_appendnew() for details about why)
-	 */
-	FREE_AND_NULL(p->next);
-
-	return p;
+	struct combine_diff_path *head = NULL, **tail = &head;
+	ll_diff_tree_paths(&tail, oid, parents_oid, nparent, base, opt, 0);
+	return head;
 }
 
 /*
@@ -708,14 +629,13 @@ static void ll_diff_tree_oid(const struct object_id *old_oid,
 			     const struct object_id *new_oid,
 			     struct strbuf *base, struct diff_options *opt)
 {
-	struct combine_diff_path phead, *p;
+	struct combine_diff_path *paths, *p;
 	pathchange_fn_t pathchange_old = opt->pathchange;
 
-	phead.next = NULL;
 	opt->pathchange = emit_diff_first_parent_only;
-	diff_tree_paths(&phead, new_oid, &old_oid, 1, base, opt);
+	paths = diff_tree_paths(new_oid, &old_oid, 1, base, opt);
 
-	for (p = phead.next; p;) {
+	for (p = paths; p;) {
 		struct combine_diff_path *pprev = p;
 		p = p->next;
 		free(pprev);
diff --git a/unix-socket.c b/unix-socket.c
index 483c9c4..8860203 100644
--- a/unix-socket.c
+++ b/unix-socket.c
@@ -65,8 +65,10 @@ static int unix_sockaddr_init(struct sockaddr_un *sa, const char *path,
 		if (strbuf_getcwd(&cwd))
 			return -1;
 		ctx->orig_dir = strbuf_detach(&cwd, NULL);
-		if (chdir_len(dir, slash - dir) < 0)
+		if (chdir_len(dir, slash - dir) < 0) {
+			FREE_AND_NULL(ctx->orig_dir);
 			return -1;
+		}
 	}
 
 	memset(sa, 0, sizeof(*sa));
diff --git a/unpack-trees.c b/unpack-trees.c
index b3be5d5..cf5b73c 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -372,7 +372,8 @@ static struct progress *get_progress(struct unpack_trees_options *o,
 			total++;
 	}
 
-	return start_delayed_progress(_("Updating files"), total);
+	return start_delayed_progress(the_repository,
+				      _("Updating files"), total);
 }
 
 static void setup_collided_checkout_detection(struct checkout *state,
@@ -1773,6 +1774,7 @@ static int clear_ce_flags(struct index_state *istate,
 	strbuf_reset(&prefix);
 	if (show_progress)
 		istate->progress = start_delayed_progress(
+					the_repository,
 					_("Updating index flags"),
 					istate->cache_nr);
 
@@ -2902,7 +2904,7 @@ int threeway_merge(const struct cache_entry * const *stages,
  * The rule is to "carry forward" what is in the index without losing
  * information across a "fast-forward", favoring a successful merge
  * over a merge failure when it makes sense.  For details of the
- * "carry forward" rule, please see <Documentation/git-read-tree.txt>.
+ * "carry forward" rule, please see <Documentation/git-read-tree.adoc>.
  *
  */
 int twoway_merge(const struct cache_entry * const *src,
diff --git a/upload-pack.c b/upload-pack.c
index 728b247..7498b45 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -32,6 +32,7 @@
 #include "write-or-die.h"
 #include "json-writer.h"
 #include "strmap.h"
+#include "promisor-remote.h"
 
 /* Remember to update object flag allocation in object.h */
 #define THEY_HAVE	(1u << 11)
@@ -319,6 +320,8 @@ static void create_pack_file(struct upload_pack_data *pack_data,
 		strvec_push(&pack_objects.args, "--delta-base-offset");
 	if (pack_data->use_include_tag)
 		strvec_push(&pack_objects.args, "--include-tag");
+	if (repo_has_accepted_promisor_remote(the_repository))
+		strvec_push(&pack_objects.args, "--missing=allow-promisor");
 	if (pack_data->filter_options.choice) {
 		const char *spec =
 			expand_list_objects_filter_spec(&pack_data->filter_options);
diff --git a/usage.c b/usage.c
index 4770900..38b46bb 100644
--- a/usage.c
+++ b/usage.c
@@ -8,7 +8,7 @@
 #include "gettext.h"
 #include "trace2.h"
 
-static void vreportf(const char *prefix, const char *err, va_list params)
+static void vfreportf(FILE *f, const char *prefix, const char *err, va_list params)
 {
 	char msg[4096];
 	char *p, *pend = msg + sizeof(msg);
@@ -32,8 +32,13 @@ static void vreportf(const char *prefix, const char *err, va_list params)
 	}
 
 	*(p++) = '\n'; /* we no longer need a NUL */
-	fflush(stderr);
-	write_in_full(2, msg, p - msg);
+	fflush(f);
+	write_in_full(fileno(f), msg, p - msg);
+}
+
+static void vreportf(const char *prefix, const char *err, va_list params)
+{
+	vfreportf(stderr, prefix, err, params);
 }
 
 static NORETURN void usage_builtin(const char *err, va_list params)
@@ -173,6 +178,22 @@ void NORETURN usage(const char *err)
 	usagef("%s", err);
 }
 
+static void show_usage_if_asked_helper(const char *err, ...)
+{
+	va_list params;
+
+	va_start(params, err);
+	vfreportf(stdout, _("usage: "), err, params);
+	va_end(params);
+	exit(129);
+}
+
+void show_usage_if_asked(int ac, const char **av, const char *err)
+{
+	if (ac == 2 && !strcmp(av[1], "-h"))
+		show_usage_if_asked_helper(err);
+}
+
 void NORETURN die(const char *err, ...)
 {
 	va_list params;
diff --git a/version.c b/version.c
index 4d763ab..279269c 100644
--- a/version.c
+++ b/version.c
@@ -1,11 +1,32 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "version.h"
-#include "version-def.h"
 #include "strbuf.h"
+#include "gettext.h"
+
+#ifndef GIT_VERSION_H
+# include "version-def.h"
+#else
+# include GIT_VERSION_H
+#endif
 
 const char git_version_string[] = GIT_VERSION;
 const char git_built_from_commit_string[] = GIT_BUILT_FROM_COMMIT;
 
+/*
+ * Trim and replace each character with ascii code below 32 or above
+ * 127 (included) using a dot '.' character.
+ */
+static void redact_non_printables(struct strbuf *buf)
+{
+	strbuf_trim(buf);
+	for (size_t i = 0; i < buf->len; i++) {
+		if (!isprint(buf->buf[i]) || buf->buf[i] == ' ')
+			buf->buf[i] = '.';
+	}
+}
+
 const char *git_user_agent(void)
 {
 	static const char *agent = NULL;
@@ -19,6 +40,27 @@ const char *git_user_agent(void)
 	return agent;
 }
 
+/*
+  Retrieve, sanitize and cache operating system info for subsequent
+  calls. Return a pointer to the sanitized operating system info
+  string.
+*/
+static const char *os_info(void)
+{
+	static const char *os = NULL;
+
+	if (!os) {
+		struct strbuf buf = STRBUF_INIT;
+
+		get_uname_info(&buf, 0);
+		/* Sanitize the os information immediately */
+		redact_non_printables(&buf);
+		os = strbuf_detach(&buf, NULL);
+	}
+
+	return os;
+}
+
 const char *git_user_agent_sanitized(void)
 {
 	static const char *agent = NULL;
@@ -27,13 +69,35 @@ const char *git_user_agent_sanitized(void)
 		struct strbuf buf = STRBUF_INIT;
 
 		strbuf_addstr(&buf, git_user_agent());
-		strbuf_trim(&buf);
-		for (size_t i = 0; i < buf.len; i++) {
-			if (buf.buf[i] <= 32 || buf.buf[i] >= 127)
-				buf.buf[i] = '.';
+
+		if (!getenv("GIT_USER_AGENT")) {
+			strbuf_addch(&buf, '-');
+			strbuf_addstr(&buf, os_info());
 		}
-		agent = buf.buf;
+		redact_non_printables(&buf);
+		agent = strbuf_detach(&buf, NULL);
 	}
 
 	return agent;
 }
+
+int get_uname_info(struct strbuf *buf, unsigned int full)
+{
+	struct utsname uname_info;
+
+	if (uname(&uname_info)) {
+		strbuf_addf(buf, _("uname() failed with error '%s' (%d)\n"),
+			    strerror(errno),
+			    errno);
+		return -1;
+	}
+	if (full)
+		strbuf_addf(buf, "%s %s %s %s\n",
+			    uname_info.sysname,
+			    uname_info.release,
+			    uname_info.version,
+			    uname_info.machine);
+	else
+	     strbuf_addf(buf, "%s\n", uname_info.sysname);
+	return 0;
+}
diff --git a/version.h b/version.h
index 7c62e80..bbde6d3 100644
--- a/version.h
+++ b/version.h
@@ -1,10 +1,20 @@
 #ifndef VERSION_H
 #define VERSION_H
 
+struct repository;
+
 extern const char git_version_string[];
 extern const char git_built_from_commit_string[];
 
 const char *git_user_agent(void);
 const char *git_user_agent_sanitized(void);
 
+/*
+  Try to get information about the system using uname(2).
+  Return -1 and put an error message into 'buf' in case of uname()
+  error. Return 0 and put uname info into 'buf' otherwise.
+*/
+int get_uname_info(struct strbuf *buf, unsigned int full);
+
+
 #endif /* VERSION_H */
diff --git a/walker.c b/walker.c
index 7cc9dbe..1cf3da0 100644
--- a/walker.c
+++ b/walker.c
@@ -172,7 +172,8 @@ static int loop(struct walker *walker)
 	uint64_t nr = 0;
 
 	if (walker->get_progress)
-		progress = start_delayed_progress(_("Fetching objects"), 0);
+		progress = start_delayed_progress(the_repository,
+						  _("Fetching objects"), 0);
 
 	while (process_queue) {
 		struct object *obj = process_queue->item;
diff --git a/worktree.c b/worktree.c
index 248bbb3..6449b67 100644
--- a/worktree.c
+++ b/worktree.c
@@ -59,12 +59,35 @@ static void add_head_info(struct worktree *wt)
 static int is_current_worktree(struct worktree *wt)
 {
 	char *git_dir = absolute_pathdup(repo_get_git_dir(the_repository));
-	const char *wt_git_dir = get_worktree_git_dir(wt);
+	char *wt_git_dir = get_worktree_git_dir(wt);
 	int is_current = !fspathcmp(git_dir, absolute_path(wt_git_dir));
+	free(wt_git_dir);
 	free(git_dir);
 	return is_current;
 }
 
+/*
+* When in a secondary worktree, and when extensions.worktreeConfig
+* is true, only $commondir/config and $commondir/worktrees/<id>/
+* config.worktree are consulted, hence any core.bare=true setting in
+* $commondir/config.worktree gets overlooked. Thus, check it manually
+* to determine if the repository is bare.
+*/
+static int is_main_worktree_bare(struct repository *repo)
+{
+	int bare = 0;
+	struct config_set cs = {0};
+	char *worktree_config = xstrfmt("%s/config.worktree", repo_get_common_dir(repo));
+
+	git_configset_init(&cs);
+	git_configset_add_file(&cs, worktree_config);
+	git_configset_get_bool(&cs, "core.bare", &bare);
+
+	git_configset_clear(&cs);
+	free(worktree_config);
+	return bare;
+}
+
 /**
  * get the main worktree
  */
@@ -79,16 +102,17 @@ static struct worktree *get_main_worktree(int skip_reading_head)
 	CALLOC_ARRAY(worktree, 1);
 	worktree->repo = the_repository;
 	worktree->path = strbuf_detach(&worktree_path, NULL);
-	/*
-	 * NEEDSWORK: If this function is called from a secondary worktree and
-	 * config.worktree is present, is_bare_repository_cfg will reflect the
-	 * contents of config.worktree, not the contents of the main worktree.
-	 * This means that worktree->is_bare may be set to 0 even if the main
-	 * worktree is configured to be bare.
-	 */
-	worktree->is_bare = (is_bare_repository_cfg == 1) ||
-		is_bare_repository();
 	worktree->is_current = is_current_worktree(worktree);
+	worktree->is_bare = (is_bare_repository_cfg == 1) ||
+		is_bare_repository() ||
+		/*
+		 * When in a secondary worktree we have to also verify if the main
+		 * worktree is bare in $commondir/config.worktree.
+		 * This check is unnecessary if we're currently in the main worktree,
+		 * as prior checks already consulted all configs of the current worktree.
+		 */
+		(!worktree->is_current && is_main_worktree_bare(the_repository));
+
 	if (!skip_reading_head)
 		add_head_info(worktree);
 	return worktree;
@@ -104,7 +128,7 @@ struct worktree *get_linked_worktree(const char *id,
 	if (!id)
 		die("Missing linked worktree name");
 
-	strbuf_git_common_path(&path, the_repository, "worktrees/%s/gitdir", id);
+	repo_common_path_append(the_repository, &path, "worktrees/%s/gitdir", id);
 	if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
 		/* invalid gitdir file */
 		goto done;
@@ -175,14 +199,14 @@ struct worktree **get_worktrees(void)
 	return get_worktrees_internal(0);
 }
 
-const char *get_worktree_git_dir(const struct worktree *wt)
+char *get_worktree_git_dir(const struct worktree *wt)
 {
 	if (!wt)
-		return repo_get_git_dir(the_repository);
+		return xstrdup(repo_get_git_dir(the_repository));
 	else if (!wt->id)
-		return repo_get_common_dir(the_repository);
+		return xstrdup(repo_get_common_dir(the_repository));
 	else
-		return git_common_path("worktrees/%s", wt->id);
+		return repo_common_path(the_repository, "worktrees/%s", wt->id);
 }
 
 static struct worktree *find_worktree_by_suffix(struct worktree **list,
@@ -313,6 +337,7 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
 {
 	struct strbuf wt_path = STRBUF_INIT;
 	struct strbuf realpath = STRBUF_INIT;
+	struct strbuf buf = STRBUF_INIT;
 	char *path = NULL;
 	int err, ret = -1;
 
@@ -342,7 +367,7 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
 	if (!is_absolute_path(wt->path)) {
 		strbuf_addf_gently(errmsg,
 				   _("'%s' file does not contain absolute path to the working tree location"),
-				   git_common_path("worktrees/%s/gitdir", wt->id));
+				   repo_common_path_replace(the_repository, &buf, "worktrees/%s/gitdir", wt->id));
 		goto done;
 	}
 
@@ -364,14 +389,16 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
 		goto done;
 	}
 
-	strbuf_realpath(&realpath, git_common_path("worktrees/%s", wt->id), 1);
+	strbuf_realpath(&realpath, repo_common_path_replace(the_repository, &buf, "worktrees/%s", wt->id), 1);
 	ret = fspathcmp(path, realpath.buf);
 
 	if (ret)
 		strbuf_addf_gently(errmsg, _("'%s' does not point back to '%s'"),
-				   wt->path, git_common_path("worktrees/%s", wt->id));
+				   wt->path, repo_common_path_replace(the_repository, &buf,
+								      "worktrees/%s", wt->id));
 done:
 	free(path);
+	strbuf_release(&buf);
 	strbuf_release(&wt_path);
 	strbuf_release(&realpath);
 	return ret;
@@ -383,11 +410,13 @@ void update_worktree_location(struct worktree *wt, const char *path_,
 	struct strbuf path = STRBUF_INIT;
 	struct strbuf dotgit = STRBUF_INIT;
 	struct strbuf gitdir = STRBUF_INIT;
+	char *wt_gitdir;
 
 	if (is_main_worktree(wt))
 		BUG("can't relocate main worktree");
 
-	strbuf_realpath(&gitdir, git_common_path("worktrees/%s/gitdir", wt->id), 1);
+	wt_gitdir = repo_common_path(the_repository, "worktrees/%s/gitdir", wt->id);
+	strbuf_realpath(&gitdir, wt_gitdir, 1);
 	strbuf_realpath(&path, path_, 1);
 	strbuf_addf(&dotgit, "%s/.git", path.buf);
 	if (fspathcmp(wt->path, path.buf)) {
@@ -399,6 +428,7 @@ void update_worktree_location(struct worktree *wt, const char *path_,
 	strbuf_release(&path);
 	strbuf_release(&dotgit);
 	strbuf_release(&gitdir);
+	free(wt_gitdir);
 }
 
 int is_worktree_being_rebased(const struct worktree *wt,
@@ -487,7 +517,8 @@ int submodule_uses_worktrees(const char *path)
 	int ret = 0;
 	struct repository_format format = REPOSITORY_FORMAT_INIT;
 
-	submodule_gitdir = git_pathdup_submodule(path, "%s", "");
+	submodule_gitdir = repo_submodule_path(the_repository,
+					       path, "%s", "");
 	if (!submodule_gitdir)
 		return 0;
 
@@ -583,6 +614,7 @@ static void repair_gitfile(struct worktree *wt,
 	struct strbuf backlink = STRBUF_INIT;
 	char *dotgit_contents = NULL;
 	const char *repair = NULL;
+	char *path = NULL;
 	int err;
 
 	/* missing worktree can't be repaired */
@@ -594,7 +626,8 @@ static void repair_gitfile(struct worktree *wt,
 		goto done;
 	}
 
-	strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
+	path = repo_common_path(the_repository, "worktrees/%s", wt->id);
+	strbuf_realpath(&repo, path, 1);
 	strbuf_addf(&dotgit, "%s/.git", wt->path);
 	strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
 	dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
@@ -624,6 +657,7 @@ static void repair_gitfile(struct worktree *wt,
 
 done:
 	free(dotgit_contents);
+	free(path);
 	strbuf_release(&repo);
 	strbuf_release(&dotgit);
 	strbuf_release(&gitdir);
@@ -655,11 +689,13 @@ void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path
 	struct strbuf gitdir = STRBUF_INIT;
 	struct strbuf dotgit = STRBUF_INIT;
 	int is_relative_path;
+	char *path = NULL;
 
 	if (is_main_worktree(wt))
 		goto done;
 
-	strbuf_realpath(&gitdir, git_common_path("worktrees/%s/gitdir", wt->id), 1);
+	path = repo_common_path(the_repository, "worktrees/%s/gitdir", wt->id);
+	strbuf_realpath(&gitdir, path, 1);
 
 	if (strbuf_read_file(&dotgit, gitdir.buf, 0) < 0)
 		goto done;
@@ -678,6 +714,7 @@ void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path
 done:
 	strbuf_release(&gitdir);
 	strbuf_release(&dotgit);
+	free(path);
 }
 
 void repair_worktrees_after_gitdir_move(const char *old_path)
@@ -731,8 +768,7 @@ static ssize_t infer_backlink(const char *gitfile, struct strbuf *inferred)
 	id++; /* advance past '/' to point at <id> */
 	if (!*id)
 		goto error;
-	strbuf_reset(inferred);
-	strbuf_git_common_path(inferred, the_repository, "worktrees/%s", id);
+	repo_common_path_replace(the_repository, inferred, "worktrees/%s", id);
 	if (!is_directory(inferred->buf))
 		goto error;
 
@@ -870,7 +906,11 @@ int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath,
 	ssize_t read_result;
 
 	*wtpath = NULL;
-	strbuf_realpath(&repo, git_common_path("worktrees/%s", id), 1);
+
+	path = repo_common_path(the_repository, "worktrees/%s", id);
+	strbuf_realpath(&repo, path, 1);
+	FREE_AND_NULL(path);
+
 	strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
 	if (!is_directory(repo.buf)) {
 		strbuf_addstr(reason, _("not a valid directory"));
diff --git a/worktree.h b/worktree.h
index 38145df..1636858 100644
--- a/worktree.h
+++ b/worktree.h
@@ -39,7 +39,7 @@ int submodule_uses_worktrees(const char *path);
  * Return git dir of the worktree. Note that the path may be relative.
  * If wt is NULL, git dir of current worktree is returned.
  */
-const char *get_worktree_git_dir(const struct worktree *wt);
+char *get_worktree_git_dir(const struct worktree *wt);
 
 /*
  * Search for the worktree identified unambiguously by `arg` -- typically
diff --git a/wrapper.c b/wrapper.c
index fa79fd6..8b98593 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -479,7 +479,7 @@ int git_mkstemps_mode(char *pattern, int suffix_len, int mode)
 	for (count = 0; count < TMP_MAX; ++count) {
 		int i;
 		uint64_t v;
-		if (csprng_bytes(&v, sizeof(v)) < 0)
+		if (csprng_bytes(&v, sizeof(v), 0) < 0)
 			return error_errno("unable to get random bytes for temporary file");
 
 		/* Fill in the random bits. */
@@ -750,7 +750,7 @@ int open_nofollow(const char *path, int flags)
 #endif
 }
 
-int csprng_bytes(void *buf, size_t len)
+int csprng_bytes(void *buf, size_t len, MAYBE_UNUSED unsigned flags)
 {
 #if defined(HAVE_ARC4RANDOM) || defined(HAVE_ARC4RANDOM_LIBBSD)
 	/* This function never returns an error. */
@@ -785,14 +785,18 @@ int csprng_bytes(void *buf, size_t len)
 		return -1;
 	return 0;
 #elif defined(HAVE_OPENSSL_CSPRNG)
-	int res = RAND_bytes(buf, len);
-	if (res == 1)
+	switch (RAND_pseudo_bytes(buf, len)) {
+	case 1:
 		return 0;
-	if (res == -1)
-		errno = ENOTSUP;
-	else
+	case 0:
+		if (flags & CSPRNG_BYTES_INSECURE)
+			return 0;
 		errno = EIO;
-	return -1;
+		return -1;
+	default:
+		errno = ENOTSUP;
+		return -1;
+	}
 #else
 	ssize_t res;
 	char *p = buf;
@@ -816,11 +820,11 @@ int csprng_bytes(void *buf, size_t len)
 #endif
 }
 
-uint32_t git_rand(void)
+uint32_t git_rand(unsigned flags)
 {
 	uint32_t result;
 
-	if (csprng_bytes(&result, sizeof(result)) < 0)
+	if (csprng_bytes(&result, sizeof(result), flags) < 0)
 		die(_("unable to get random bytes"));
 
 	return result;
diff --git a/wrapper.h b/wrapper.h
index a6b3e1f..7df824e 100644
--- a/wrapper.h
+++ b/wrapper.h
@@ -127,18 +127,26 @@ int open_nofollow(const char *path, int flags);
 
 void sleep_millisec(int millisec);
 
+enum {
+	/*
+	 * Accept insecure bytes, which some CSPRNG implementations may return
+	 * in case the entropy pool has been exhausted.
+	 */
+	CSPRNG_BYTES_INSECURE = (1 << 0),
+};
+
 /*
  * Generate len bytes from the system cryptographically secure PRNG.
  * Returns 0 on success and -1 on error, setting errno.  The inability to
- * satisfy the full request is an error.
+ * satisfy the full request is an error. Accepts CSPRNG flags.
  */
-int csprng_bytes(void *buf, size_t len);
+int csprng_bytes(void *buf, size_t len, unsigned flags);
 
 /*
  * Returns a random uint32_t, uniformly distributed across all possible
- * values.
+ * values. Accepts CSPRNG flags.
  */
-uint32_t git_rand(void);
+uint32_t git_rand(unsigned flags);
 
 /* Provide log2 of the given `size_t`. */
 static inline unsigned log2u(uintmax_t sz)
diff --git a/wt-status.c b/wt-status.c
index 3ee9181..1da5732 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1289,7 +1289,8 @@ static void show_am_in_progress(struct wt_status *s,
 static char *read_line_from_git_path(const char *filename)
 {
 	struct strbuf buf = STRBUF_INIT;
-	FILE *fp = fopen_or_warn(git_path("%s", filename), "r");
+	FILE *fp = fopen_or_warn(repo_git_path_append(the_repository, &buf,
+						      "%s", filename), "r");
 
 	if (!fp) {
 		strbuf_release(&buf);
@@ -1383,27 +1384,33 @@ static void abbrev_oid_in_line(struct strbuf *line)
 
 static int read_rebase_todolist(const char *fname, struct string_list *lines)
 {
-	struct strbuf line = STRBUF_INIT;
-	FILE *f = fopen(git_path("%s", fname), "r");
+	struct strbuf buf = STRBUF_INIT;
+	FILE *f = fopen(repo_git_path_append(the_repository, &buf, "%s", fname), "r");
+	int ret;
 
 	if (!f) {
-		if (errno == ENOENT)
-			return -1;
+		if (errno == ENOENT) {
+			ret = -1;
+			goto out;
+		}
 		die_errno("Could not open file %s for reading",
-			  git_path("%s", fname));
+			  repo_git_path_replace(the_repository, &buf, "%s", fname));
 	}
-	while (!strbuf_getline_lf(&line, f)) {
-		if (starts_with(line.buf, comment_line_str))
+	while (!strbuf_getline_lf(&buf, f)) {
+		if (starts_with(buf.buf, comment_line_str))
 			continue;
-		strbuf_trim(&line);
-		if (!line.len)
+		strbuf_trim(&buf);
+		if (!buf.len)
 			continue;
-		abbrev_oid_in_line(&line);
-		string_list_append(lines, line.buf);
+		abbrev_oid_in_line(&buf);
+		string_list_append(lines, buf.buf);
 	}
 	fclose(f);
-	strbuf_release(&line);
-	return 0;
+
+	ret = 0;
+out:
+	strbuf_release(&buf);
+	return ret;
 }
 
 static void show_rebase_information(struct wt_status *s,
@@ -1434,9 +1441,12 @@ static void show_rebase_information(struct wt_status *s,
 				i < have_done.nr;
 				i++)
 				status_printf_ln(s, color, "   %s", have_done.items[i].string);
-			if (have_done.nr > nr_lines_to_show && s->hints)
+			if (have_done.nr > nr_lines_to_show && s->hints) {
+				char *path = repo_git_path(the_repository, "rebase-merge/done");
 				status_printf_ln(s, color,
-					_("  (see more in file %s)"), git_path("rebase-merge/done"));
+					_("  (see more in file %s)"), path);
+				free(path);
+			}
 		}
 
 		if (yet_to_do.nr == 0)
diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h
index bb56b23..2cecde5 100644
--- a/xdiff/xdiff.h
+++ b/xdiff/xdiff.h
@@ -85,7 +85,7 @@ typedef struct s_xpparam {
 	regex_t **ignore_regex;
 	size_t ignore_regex_nr;
 
-	/* See Documentation/diff-options.txt. */
+	/* See Documentation/diff-options.adoc. */
 	char **anchors;
 	size_t anchors_nr;
 } xpparam_t;
diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c
index 4685ba6..8889b8b 100644
--- a/xdiff/xdiffi.c
+++ b/xdiff/xdiffi.c
@@ -19,7 +19,6 @@
  *  Davide Libenzi <davidel@xmailserver.org>
  *
  */
-#define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "xinclude.h"
 
@@ -1014,7 +1013,7 @@ static void xdl_mark_ignorable_lines(xdchange_t *xscr, xdfenv_t *xe, long flags)
 
 static int record_matches_regex(xrecord_t *rec, xpparam_t const *xpp) {
 	regmatch_t regmatch;
-	int i;
+	size_t i;
 
 	for (i = 0; i < xpp->ignore_regex_nr; i++)
 		if (!regexec_buf(xpp->ignore_regex[i], rec->ptr, rec->size, 1,
diff --git a/xdiff/xemit.c b/xdiff/xemit.c
index 75f0fe4..f8e3f25 100644
--- a/xdiff/xemit.c
+++ b/xdiff/xemit.c
@@ -54,7 +54,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
 	xdchange_t *xch, *xchp, *lxch;
 	long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen;
 	long max_ignorable = xecfg->ctxlen;
-	unsigned long ignored = 0; /* number of ignored blank lines */
+	long ignored = 0; /* number of ignored blank lines */
 
 	/* remove ignorable changes that are too far before other changes */
 	for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) {
diff --git a/xdiff/xhistogram.c b/xdiff/xhistogram.c
index 16a8fe2..040d81e 100644
--- a/xdiff/xhistogram.c
+++ b/xdiff/xhistogram.c
@@ -106,7 +106,7 @@ static int scanA(struct histindex *index, int line1, int count1)
 	unsigned int chain_len;
 	struct record **rec_chain, *rec;
 
-	for (ptr = LINE_END(1); line1 <= ptr; ptr--) {
+	for (ptr = LINE_END(1); (unsigned int)line1 <= ptr; ptr--) {
 		tbl_idx = TABLE_HASH(index, 1, ptr);
 		rec_chain = index->records + tbl_idx;
 		rec = *rec_chain;
@@ -181,14 +181,14 @@ static int try_lcs(struct histindex *index, struct region *lcs, int b_ptr,
 			be = bs;
 			rc = rec->cnt;
 
-			while (line1 < as && line2 < bs
+			while ((unsigned int)line1 < as && (unsigned int)line2 < bs
 				&& CMP(index, 1, as - 1, 2, bs - 1)) {
 				as--;
 				bs--;
 				if (1 < rc)
 					rc = XDL_MIN(rc, CNT(index, as));
 			}
-			while (ae < LINE_END(1) && be < LINE_END(2)
+			while (ae < (unsigned int)LINE_END(1) && be < (unsigned int)LINE_END(2)
 				&& CMP(index, 1, ae + 1, 2, be + 1)) {
 				ae++;
 				be++;
@@ -313,7 +313,7 @@ static int histogram_diff(xpparam_t const *xpp, xdfenv_t *env,
 	if (count1 <= 0 && count2 <= 0)
 		return 0;
 
-	if (LINE_END(1) >= MAX_PTR)
+	if ((unsigned int)LINE_END(1) >= MAX_PTR)
 		return -1;
 
 	if (!count1) {
diff --git a/xdiff/xinclude.h b/xdiff/xinclude.h
index 7e56542..a4285ac 100644
--- a/xdiff/xinclude.h
+++ b/xdiff/xinclude.h
@@ -23,8 +23,6 @@
 #if !defined(XINCLUDE_H)
 #define XINCLUDE_H
 
-#define DISABLE_SIGN_COMPARE_WARNINGS
-
 #include "git-compat-util.h"
 #include "xmacros.h"
 #include "xdiff.h"
diff --git a/xdiff/xpatience.c b/xdiff/xpatience.c
index a2d8955..77dc411 100644
--- a/xdiff/xpatience.c
+++ b/xdiff/xpatience.c
@@ -19,6 +19,7 @@
  *  Davide Libenzi <davidel@xmailserver.org>
  *
  */
+
 #include "xinclude.h"
 
 /*
@@ -63,7 +64,7 @@ struct hashmap {
 
 		/*
 		 * If 1, this entry can serve as an anchor. See
-		 * Documentation/diff-options.txt for more information.
+		 * Documentation/diff-options.adoc for more information.
 		 */
 		unsigned anchor : 1;
 	} *entries, *first, *last;
@@ -75,7 +76,7 @@ struct hashmap {
 
 static int is_anchor(xpparam_t const *xpp, const char *line)
 {
-	int i;
+	size_t i;
 	for (i = 0; i < xpp->anchors_nr; i++) {
 		if (!strncmp(line, xpp->anchors[i], strlen(xpp->anchors[i])))
 			return 1;
diff --git a/xdiff/xutils.c b/xdiff/xutils.c
index 9e36f24..444a108 100644
--- a/xdiff/xutils.c
+++ b/xdiff/xutils.c
@@ -375,7 +375,7 @@ static int xdl_format_hunk_hdr(long s1, long c1, long s2, long c2,
 	nb += 3;
 	if (func && funclen) {
 		buf[nb++] = ' ';
-		if (funclen > sizeof(buf) - nb - 1)
+		if ((size_t)funclen > sizeof(buf) - nb - 1)
 			funclen = sizeof(buf) - nb - 1;
 		memcpy(buf + nb, func, funclen);
 		nb += funclen;
@@ -437,7 +437,7 @@ void* xdl_alloc_grow_helper(void *p, long nr, long *alloc, size_t size)
 {
 	void *tmp = NULL;
 	size_t n = ((LONG_MAX - 16) / 2 >= *alloc) ? 2 * *alloc + 16 : LONG_MAX;
-	if (nr > n)
+	if ((size_t)nr > n)
 		n = nr;
 	if (SIZE_MAX / size >= n)
 		tmp = xdl_realloc(p, n * size);