Sync with 2.46.4

* maint-2.46:
  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>
diff --git a/.cirrus.yml b/.cirrus.yml
index 77346a4..1fbdc26 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -9,7 +9,7 @@
     DEFAULT_TEST_TARGET: prove
     DEVELOPER: 1
   freebsd_instance:
-    image_family: freebsd-13-2
+    image_family: freebsd-13-4
     memory: 2G
   install_script:
     pkg install -y gettext gmake perl5
diff --git a/.clang-format b/.clang-format
index 6408251..41969ec 100644
--- a/.clang-format
+++ b/.clang-format
@@ -72,6 +72,10 @@
 BinPackArguments: true
 BinPackParameters: true
 
+# Add no space around the bit field
+# unsigned bf:2;
+BitFieldColonSpacing: None
+
 # Attach braces to surrounding context except break before braces on function
 # definitions.
 # void foo()
@@ -96,6 +100,14 @@
 # Switch statement body is always indented one level more than case labels.
 IndentCaseLabels: false
 
+# Indents directives before the hash. Each level uses a single space for
+# indentation.
+# #if FOO
+# # include <foo>
+# #endif
+IndentPPDirectives: AfterHash
+PPIndentWidth: 1
+
 # Don't indent a function definition or declaration if it is wrapped after the
 # type
 IndentWrappedFunctionNames: false
@@ -108,11 +120,18 @@
 # x = (int32)y;    not    x = (int32) y;
 SpaceAfterCStyleCast: false
 
+# No space is inserted after the logical not operator
+SpaceAfterLogicalNot: false
+
 # Insert spaces before and after assignment operators
 # int a = 5;    not    int a=5;
 # a += 42;             a+=42;
 SpaceBeforeAssignmentOperators: true
 
+# Spaces will be removed before case colon.
+# case 1: break;    not     case 1 : break;
+SpaceBeforeCaseColon: false
+
 # Put a space before opening parentheses only after control statement keywords.
 # void f() {
 #   if (true) {
@@ -124,6 +143,14 @@
 # Don't insert spaces inside empty '()'
 SpaceInEmptyParentheses: false
 
+# No space before first '[' in arrays
+# int a[5][5];     not      int a [5][5];
+SpaceBeforeSquareBrackets: false
+
+# No space will be inserted into {}
+# while (true) {}    not    while (true) { }
+SpaceInEmptyBlock: false
+
 # The number of spaces before trailing line comments (// - comments).
 # This does not affect trailing block comments (/* - comments).
 SpacesBeforeTrailingComments: 1
@@ -169,6 +196,11 @@
   - 'strmap_for_each_entry'
   - 'strset_for_each_entry'
 
+# A list of macros that should be interpreted as conditionals instead of as
+# function calls.
+IfMacros:
+  - 'if_test'
+
 # The maximum number of consecutive empty lines to keep.
 MaxEmptyLinesToKeep: 1
 
diff --git a/.github/workflows/check-style.yml b/.github/workflows/check-style.yml
new file mode 100644
index 0000000..c052a5d
--- /dev/null
+++ b/.github/workflows/check-style.yml
@@ -0,0 +1,34 @@
+name: check-style
+
+# Get the repository with all commits to ensure that we can analyze
+# all of the commits contributed via the Pull Request.
+
+on:
+  pull_request:
+    types: [opened, synchronize]
+
+# Avoid unnecessary builds. Unlike the main CI jobs, these are not
+# ci-configurable (but could be).
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  check-style:
+    env:
+      CC: clang
+      jobname: ClangFormat
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
+
+    - run: ci/install-dependencies.sh
+
+    - name: git clang-format
+      continue-on-error: true
+      id: check_out
+      run: |
+        ./ci/run-style-check.sh \
+          "${{github.event.pull_request.base.sha}}"
diff --git a/.gitignore b/.gitignore
index 8caf370..6687bd6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@
 /GIT-PYTHON-VARS
 /GIT-SCRIPT-DEFINES
 /GIT-SPATCH-DEFINES
+/GIT-TEST-SUITES
 /GIT-USER-AGENT
 /GIT-VERSION-FILE
 /bin-wrappers/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c4c45da..4abfbc3 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,6 +9,8 @@
 
 test:linux:
   image: $image
+  tags:
+    - saas-linux-medium-amd64
   variables:
     CUSTOM_PATH: "/custom"
   before_script:
@@ -121,8 +123,31 @@
   image: ubuntu:latest
   before_script:
     - ./ci/install-dependencies.sh
+  # Since $CI_MERGE_REQUEST_TARGET_BRANCH_SHA is only defined for merged
+  # pipelines, we fallback to $CI_MERGE_REQUEST_DIFF_BASE_SHA, which should
+  # be defined in all pipelines.
   script:
-    - ./ci/check-whitespace.sh "$CI_MERGE_REQUEST_TARGET_BRANCH_SHA"
+    - |
+      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'
+
+check-style:
+  image: ubuntu:latest
+  allow_failure: true
+  variables:
+    CC: clang
+    jobname: ClangFormat
+  before_script:
+    - ./ci/install-dependencies.sh
+  # Since $CI_MERGE_REQUEST_TARGET_BRANCH_SHA is only defined for merged
+  # pipelines, we fallback to $CI_MERGE_REQUEST_DIFF_BASE_SHA, which should
+  # be defined in all pipelines.
+  script:
+    - |
+      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/.mailmap b/.mailmap
index 18128a1..96c2740 100644
--- a/.mailmap
+++ b/.mailmap
@@ -257,6 +257,7 @@
 Stefan Sperling <stsp@elego.de> <stsp@stsp.name>
 Štěpán Němec <stepnem@gmail.com> <stepan.nemec@gmail.com>
 Stephen Boyd <bebarino@gmail.com> <sboyd@codeaurora.org>
+Stephen P. Smith <ishchis2@gmail.com> <ischis2@cox.net>
 Steven Drake <sdrake@xnet.co.nz> <sdrake@ihug.co.nz>
 Steven Grimm <koreth@midwinter.com> <sgrimm@sgrimm-mbp.local>
 Steven Grimm <koreth@midwinter.com> koreth@midwinter.com
diff --git a/Documentation/BreakingChanges.txt b/Documentation/BreakingChanges.txt
index 0532bfc..112770a 100644
--- a/Documentation/BreakingChanges.txt
+++ b/Documentation/BreakingChanges.txt
@@ -115,6 +115,26 @@
 +
 Cf. <20140304174806.GA11561@sigill.intra.peff.net>.
 
+* The git-pack-redundant(1) command can be used to remove redundant pack files.
+  The subcommand is unusably slow and the reason why nobody reports it as a
+  performance bug is suspected to be the absence of users. We have nominated
+  the command for removal and have started to emit a user-visible warning in
+  c3b58472be (pack-redundant: gauge the usage before proposing its removal,
+  2020-08-25) whenever the command is executed.
++
+So far there was a single complaint about somebody still using the command, but
+that complaint did not cause us to reverse course. On the contrary, we have
+doubled down on the deprecation and starting with 4406522b76 (pack-redundant:
+escalate deprecation warning to an error, 2023-03-23), the command dies unless
+the user passes the `--i-still-use-this` option.
++
+There have not been any subsequent complaints, so this command will finally be
+removed.
++
+Cf. <xmqq1rjuz6n3.fsf_-_@gitster.c.googlers.com>,
+    <CAKvOHKAFXQwt4D8yUCCkf_TQL79mYaJ=KAKhtpDNTvHJFuX1NA@mail.gmail.com>,
+    <20230323204047.GA9290@coredump.intra.peff.net>,
+
 == 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 5edd3a0..3263245 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -241,6 +241,16 @@
  - We use tabs to indent, and interpret tabs as taking up to
    8 spaces.
 
+ - Nested C preprocessor directives are indented after the hash by one
+   space per nesting level.
+
+	#if FOO
+	# include <foo.h>
+	# if BAR
+	#  include <bar.h>
+	# endif
+	#endif
+
  - We try to keep to at most 80 characters per line.
 
  - As a Git developer we assume you have a reasonably modern compiler
@@ -248,6 +258,14 @@
    ensure your patch is clear of all compiler warnings we care about,
    by e.g. "echo DEVELOPER=1 >>config.mak".
 
+ - When using DEVELOPER=1 mode, you may see warnings from the compiler
+   like "error: unused parameter 'foo' [-Werror=unused-parameter]",
+   which indicates that a function ignores its argument. If the unused
+   parameter can't be removed (e.g., because the function is used as a
+   callback and has to match a certain interface), you can annotate
+   the individual parameters with the UNUSED (or MAYBE_UNUSED)
+   keyword, like "int foo UNUSED".
+
  - We try to support a wide range of C compilers to compile Git with,
    including old ones.  As of Git v2.35.0 Git requires C99 (we check
    "__STDC_VERSION__"). You should not use features from a newer C
@@ -261,7 +279,7 @@
    . since around 2007 with 2b6854c863a, we have been using
      initializer elements which are not computable at load time. E.g.:
 
-	const char *args[] = {"constant", variable, NULL};
+	const char *args[] = { "constant", variable, NULL };
 
    . since early 2012 with e1327023ea, we have been using an enum
      definition whose last element is followed by a comma.  This, like
@@ -567,6 +585,42 @@
    use your own debugger and arguments. Example: `GIT_DEBUGGER="ddd --gdb"
    ./bin-wrappers/git log` (See `wrap-for-bin.sh`.)
 
+ - The primary data structure that a subsystem 'S' deals with is called
+   `struct S`. Functions that operate on `struct S` are named
+   `S_<verb>()` and should generally receive a pointer to `struct S` as
+   first parameter. E.g.
+
+	struct strbuf;
+
+	void strbuf_add(struct strbuf *buf, ...);
+
+	void strbuf_reset(struct strbuf *buf);
+
+    is preferred over:
+
+	struct strbuf;
+
+	void add_string(struct strbuf *buf, ...);
+
+	void reset_strbuf(struct strbuf *buf);
+
+ - There are several common idiomatic names for functions performing
+   specific tasks on a structure `S`:
+
+    - `S_init()` initializes a structure without allocating the
+      structure itself.
+
+    - `S_release()` releases a structure's contents without freeing the
+      structure.
+
+    - `S_clear()` is equivalent to `S_release()` followed by `S_init()`
+      such that the structure is directly usable after clearing it. When
+      `S_clear()` is provided, `S_init()` shall not allocate resources
+      that need to be released again.
+
+    - `S_free()` releases a structure's contents and frees the
+      structure.
+
 For Perl programs:
 
  - Most of the C guidelines above apply.
diff --git a/Documentation/DecisionMaking.txt b/Documentation/DecisionMaking.txt
index dbb4c1f..b43c472 100644
--- a/Documentation/DecisionMaking.txt
+++ b/Documentation/DecisionMaking.txt
@@ -54,7 +54,7 @@
 
 For non-technical decisions such as community norms or processes, it is up to
 the community as a whole to implement and sustain agreed-upon changes.
-The project leadership committe (PLC) may help the implementation of
+The project leadership committee (PLC) may help the implementation of
 policy decisions.
 
 
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 1bd23fb..0f55baa 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -118,6 +118,7 @@
 TECH_DOCS += technical/pack-heuristics
 TECH_DOCS += technical/parallel-checkout
 TECH_DOCS += technical/partial-clone
+TECH_DOCS += technical/platform-support
 TECH_DOCS += technical/racy-git
 TECH_DOCS += technical/reftable
 TECH_DOCS += technical/scalar
diff --git a/Documentation/RelNotes/2.47.0.txt b/Documentation/RelNotes/2.47.0.txt
new file mode 100644
index 0000000..b63c336
--- /dev/null
+++ b/Documentation/RelNotes/2.47.0.txt
@@ -0,0 +1,342 @@
+Git v2.47 Release Notes
+=======================
+
+UI, Workflows & Features
+------------------------
+
+ * Many Porcelain commands that internally use the merge machinery
+   were taught to consistently honor the diff.algorithm configuration.
+
+ * A few descriptions in "git show-ref -h" have been clarified.
+
+ * A 'P' command to "git add -p" that passes the patch hunk to the
+   pager has been added.
+
+ * "git grep -W" omits blank lines that follow the found function at
+   the end of the file, just like it omits blank lines before the next
+   function.
+
+ * The value of http.proxy can have "path" at the end for a socks
+   proxy that listens to a unix-domain socket, but we started to
+   discard it when we taught proxy auth code path to use the
+   credential helpers, which has been corrected.
+
+ * The code paths to compact multiple reftable files have been updated
+   to correctly deal with multiple compaction triggering at the same
+   time.
+
+ * Support to specify ref backend for submodules has been enhanced.
+
+ * "git svn" has been taught about svn:global-ignores property
+   recent versions of Subversion has.
+
+ * The default object hash and ref backend format used to be settable
+   only with explicit command line option to "git init" and
+   environment variables, but now they can be configured in the user's
+   global and system wide configuration.
+
+ * "git send-email" learned "--translate-aliases" option that reads
+   addresses from the standard input and emits the result of applying
+   aliases on them to the standard output.
+
+ * 'git for-each-ref' learned a new "--format" atom to find the branch
+   that the history leading to a given commit "%(is-base:<commit>)" is
+   likely based on.
+
+ * The command line prompt support used to be littered with bash-isms,
+   which has been corrected to work with more shells.
+
+ * Support for the RUNTIME_PREFIX feature has been added to z/OS port.
+
+ * "git send-email" learned "--mailmap" option to allow rewriting the
+   recipient addresses.
+
+ * "git mergetool" learned to use VSCode as a merge backend.
+
+ * "git pack-redundant" has been marked for removal in Git 3.0.
+
+ * One-line messages to "die" and other helper functions will get LF
+   added by these helper functions, but many existing messages had an
+   unnecessary LF at the end, which have been corrected.
+
+ * The "scalar clone" command learned the "--no-tags" option.
+
+ * The environment GIT_ADVICE has been intentionally kept undocumented
+   to discourage its use by interactive users.  Add documentation to
+   help tool writers.
+
+ * "git apply --3way" learned to take "--ours" and other options.
+
+
+Performance, Internal Implementation, Development Support etc.
+--------------------------------------------------------------
+
+ * A build tweak knob has been simplified by not setting the value
+   that is already the default; another unused one has been removed.
+
+ * A CI job that use clang-format to check coding style issues in new
+   code has been added.
+
+ * The reviewing guidelines document now explicitly encourages people
+   to give positive reviews and how.
+
+ * Test script linter has been updated to catch an attempt to use
+   one-shot export construct "VAR=VAL func" for shell functions (which
+   does not work for some shells) better.
+
+ * Some project conventions have been added to CodingGuidelines.
+
+ * In the refs subsystem, implicit reliance of the_repository has been
+   eliminated; the repository associated with the ref store object is
+   used instead.
+
+ * Various tests in reftable library have been rewritten using the unit test
+   framework.
+
+ * A test that fails on an unusually slow machine was found, and made
+   less likely to cause trouble by lengthening the expiry value it
+   uses.
+
+ * An existing test of hashmap API has been rewritten with the
+   unit-test framework.
+
+ * A policy document that describes platform support levels and
+   expectation on platform stakeholders has been introduced.
+
+ * The refs API has been taught to give symref target information to
+   the users of ref iterators, allowing for-each-ref and friends to
+   avoid an extra ref_resolve_* API call per a symbolic ref.
+
+ * Unit-test framework has learned a simple control structure to allow
+   embedding test statements in-line instead of having to create a new
+   function to contain them.
+
+ * Incremental updates of multi-pack index files is getting worked on.
+
+ * Use of API functions that implicitly depend on the_repository
+   object in the config subsystem has been rewritten to pass a
+   repository object through the callchain.
+
+ * Unused parameters have been either marked as UNUSED to squelch
+   -Wunused warnings or dropped from many functions..
+
+ * The code in the reftable library has been cleaned up by discarding
+   unused "generic" interface.
+
+ * The underlying machinery for "git diff-index" has long been made to
+   expand the sparse index as needed, but the command fully expanded
+   the sparse index upfront, which now has been taught not to do.
+
+ * More trace2 events at key points on push and fetch code paths have
+   been added.
+
+ * Make our codebase compilable with the -Werror=unused-parameter
+   option.
+
+ * "git cat-file" works well with the sparse-index, and gets marked as
+   such.
+
+ * CI started failing completely for linux32 jobs, as the step to
+   upload failed test directory uses GitHub actions that is deprecated
+   and is now disabled.
+
+ * Import clar unit tests framework libgit2 folks invented for our
+   use.
+
+ * The error messages from the test script checker have been improved.
+
+ * The convention to calling into built-in command implementation has
+   been updated to pass the repository, if known, together with the
+   prefix value.
+
+ * "git apply" had custom buffer management code that predated before
+   use of strbuf got widespread, which has been updated to use strbuf,
+   which also plugged some memory leaks.
+
+ * The reftable backend learned to more efficiently handle exclude
+   patterns while enumerating the refs.
+
+ * CI updates.  FreeBSD image has been updated to 13.4.
+   (merge 2eeb29702e cb/ci-freebsd-13-4 later to maint).
+
+ * Give timeout to the locking code to write to reftable, instead of
+   failing on the first failure without retrying.
+
+ * The checksum at the tail of files are now computed without
+   collision detection protection.  This is safe as the consumer of
+   the information to protect itself from replay attacks checks for
+   hash collisions independently.
+
+
+Fixes since v2.46
+-----------------
+
+ * "git add -p" by users with diff.suppressBlankEmpty set to true
+   failed to parse the patch that represents an unmodified empty line
+   with an empty line (not a line with a single space on it), which
+   has been corrected.
+
+ * "git checkout --ours" (no other arguments) complained that the
+   option is incompatible with branch switching, which is technically
+   correct, but found confusing by some users.  It now says that the
+   user needs to give pathspec to specify what paths to checkout.
+
+ * It has been documented that we avoid "VAR=VAL shell_func" and why.
+
+ * "git rebase --help" referred to "offset" (the difference between
+   the location a change was taken from and the change gets replaced)
+   incorrectly and called it "fuzz", which has been corrected.
+
+ * "git notes add -m '' --allow-empty" and friends that take prepared
+   data to create notes should not invoke an editor, but it started
+   doing so since Git 2.42, which has been corrected.
+
+ * An expensive operation to prepare tracing was done in re-encoding
+   code path even when the tracing was not requested, which has been
+   corrected.
+
+ * More leakfixes.
+
+ * The credential helper to talk to OSX keychain sometimes sent
+   garbage bytes after the username, which has been corrected.
+
+ * A recent update broke "git ls-remote" used outside a repository,
+   which has been corrected.
+
+ * The patch parser in 'git apply' has been a bit more lenient against
+   unexpected mode bits, like 100664, recorded on extended header lines.
+
+ * "git config --value=foo --fixed-value section.key newvalue" barfed
+   when the existing value in the configuration file used the
+   valueless true syntax, which has been corrected.
+
+ * The patch parser in "git patch-id" has been tightened to avoid
+   getting confused by lines that look like a patch header in the log
+   message.
+
+ * "git reflog expire" failed to honor annotated tags when computing
+   reachable commits.
+
+ * A flakey test and incorrect calls to strtoX() functions have been
+   fixed.
+
+ * Follow-up on 2.45.1 regression fix.
+
+ * "git rev-list ... | git diff-tree -p --remerge-diff --stdin" should
+   behave more or less like "git log -p --remerge-diff" but instead it
+   crashed, forgetting to prepare a temporary object store needed.
+
+ * "git bundle unbundle" outside a repository triggered a BUG()
+   unnecessarily, which has been corrected.
+
+ * Maintenance tasks other than "gc" now properly go background when
+   "git maintenance" runs them.
+
+ * We created a useless pseudo-merge reachability bitmap that is about
+   0 commits, and attempted to include commits that are not in packs,
+   which made no sense.  These bugs have been corrected.
+   (merge a72dfab8b8 tb/pseudo-merge-bitmap-fixes later to maint).
+
+ * "git rebase -x --quiet" was not quiet, which was corrected.
+
+ * The code path for compacting reftable files saw some bugfixes
+   against concurrent operation.
+
+ * The code forgot to discard unnecessary in-core commit buffer data
+   for commits that "git log --skip=<number>" traversed but omitted
+   from the output, which has been corrected.
+
+ * "git verify-pack" and "git index-pack" started dying outside a
+   repository, which has been corrected.
+
+ * A data corruption bug when multi-pack-index is used and the same
+   objects are stored in multiple packfiles has been corrected.
+
+ * "git pack-refs --auto" for the files backend was too aggressive,
+   which has been a bit tamed.
+   (merge c3459ae9ef ps/pack-refs-auto-heuristics later to maint).
+
+ * A file descriptor left open is now properly closed when "git
+   sparse-checkout" updates the sparse patterns.
+
+ * In a few corner cases "git diff --exit-code" failed to report
+   "changes" (e.g., renamed without any content change), which has
+   been corrected.
+
+ * Cygwin does have /dev/tty support that is needed by things like
+   single-key input mode.
+
+ * The interpret-trailers command failed to recognise the end of the
+   message when the commit log ends in an incomplete line.
+
+ * "git rebase --autostash" failed to resurrect the autostashed
+   changes when the command gets aborted after giving back control
+   asking for hlep in conflict resolution.
+   (merge bf6ab087d1 pw/rebase-autostash-fix later to maint).
+
+ * The "imap-send" now allows to be compiled with NO_OPENSSL and
+   OPENSSL_SHA1 defined together.
+   (merge 997950a750 jk/no-openssl-with-openssl-sha1 later to maint).
+
+ * The support to customize build options to adjust for older versions
+   and/or older systems for the interop tests has been improved.
+   (merge 22ef5f02a8 jk/interop-test-build-options later to maint).
+
+ * Update the character width table for Unicode 16.
+   (merge 44dc651132 bb/unicode-width-table-16 later to maint).
+
+ * In Git 2.39, Git.pm stopped working in a bare repository, which has
+   been corrected.
+   (merge d3edb0bdde jk/git-pm-bare-repo-fix later to maint).
+
+ * When a remote-helper dies before Git writes to it, SIGPIPE killed
+   Git silently.  We now explain the situation a bit better to the end
+   user in our error message.
+   (merge 6e7fac9bca jk/diag-unexpected-remote-helper-death later to maint).
+
+ * A few usability fixes to "git jump" (in contrib/).
+   (merge 083b82544d jk/jump-quickfix-fixes later to maint).
+
+ * "git diff --exit-code" ignored modified binary files, which has
+   been corrected.
+   (merge 9a41735af6 rs/diff-exit-code-binary later to maint).
+
+ * When a subprocess to work in a submodule spawned by "git submodule"
+   fails with SIGPIPE, the parent Git process caught the death of it,
+   but gave a generic "failed to work in that submodule", which was
+   misleading.  We now behave as if the parent got SIGPIPE and die.
+   (merge 082caf527e pw/submodule-process-sigpipe later to maint).
+
+ * "git archive" with pathspec magic that uses the attribute
+   information did not work well, which has been corrected.
+   (merge 296743a7ca rs/archive-with-attr-pathspec-fix later to maint).
+
+ * Background tasks "git maintenance" runs may need to use credential
+   information when going over the network, but a credential helper
+   may work only in an interactive environment, and end up blocking a
+   scheduled task waiting for UI.  Credential helpers can now behave
+   differently when they are not running interactively.
+   (merge b9183b0a02 ds/background-maintenance-with-credential later to maint).
+
+ * "git --git-dir=nowhere cmd" failed to properly notice that it
+   wasn't in any repository while processing includeIf.onbranch
+   configuration and instead crashed.
+
+ * When "git sparse-checkout disable" turns a sparse checkout into a
+   regular checkout, the index is fully expanded.  This totally
+   expected behaviour however had an "oops, we are expanding the
+   index" advice message, which has been corrected.
+   (merge 537e516a39 ds/sparse-checkout-expansion-advice later to maint).
+
+ * macOS with fsmonitor daemon can hang forever when a submodule is
+   involved, which has been corrected.
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge be10ac7037 jc/mailinfo-header-cleanup later to maint).
+   (merge 4460e052e0 jc/range-diff-lazy-setup later to maint).
+   (merge 0627c58e7a ak/typofixes later to maint).
+   (merge 83799f1500 jk/t9001-deflake later to maint).
+   (merge e02cc08a88 ak/typofix-2.46-maint later to maint).
+   (merge 5c5d29e1c4 ps/ci-gitlab-upgrade later to maint).
+   (merge 9c4c840901 jc/doc-discarding-stalled-topics later to maint).
+   (merge 5e6f359f6b ds/read-cache-mempool-leakfix later to maint).
diff --git a/Documentation/RelNotes/2.47.1.txt b/Documentation/RelNotes/2.47.1.txt
new file mode 100644
index 0000000..39206c0
--- /dev/null
+++ b/Documentation/RelNotes/2.47.1.txt
@@ -0,0 +1,31 @@
+Git 2.47.1 Release Notes
+========================
+
+This is to flush accumulated fixes since 2.47.0 on the 'master'
+front down to the maintenance track.
+
+
+Fixes since Git 2.47
+--------------------
+
+ * Use after free and double freeing at the end in "git log -L... -p"
+   had been identified and fixed.
+
+ * On macOS, fsmonitor can fall into a race condition that results in
+   a client waiting forever to be notified for an event that have
+   already happened.  This problem has been corrected.
+
+ * "git maintenance start" crashed due to an uninitialized variable
+   reference, which has been corrected.
+
+ * Fail gracefully instead of crashing when attempting to write the
+   contents of a corrupt in-core index as a tree object.
+
+ * A "git fetch" from the superproject going down to a submodule used
+   a wrong remote when the default remote names are set differently
+   between them.
+
+ * The "gitk" project tree has been synchronized again with its new
+   maintainer, Johannes Sixt.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.47.2.txt b/Documentation/RelNotes/2.47.2.txt
new file mode 100644
index 0000000..7a52ad8
--- /dev/null
+++ b/Documentation/RelNotes/2.47.2.txt
@@ -0,0 +1,7 @@
+Git v2.47.2 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.40.4, v2.41.3,
+v2.42.4, v2.43.6, v2.44.3, v2.45.3 and v2.46.3 to address the
+security issues CVE-2024-50349 and CVE-2024-52006; see the release
+notes for these versions for details.
diff --git a/Documentation/ReviewingGuidelines.txt b/Documentation/ReviewingGuidelines.txt
index 515d470..6534643 100644
--- a/Documentation/ReviewingGuidelines.txt
+++ b/Documentation/ReviewingGuidelines.txt
@@ -72,12 +72,29 @@
   could fix it. This not only helps the author to understand and fix the issue,
   it also deepens and improves your understanding of the topic.
 
-- Reviews do not need to exclusively point out problems. Feel free to "think out
+- Reviews do not need to exclusively point out problems.  Positive
+  reviews indicate that it is not only the original author of the
+  patches who care about the issue the patches address, and are
+  highly encouraged.
+
+- Do not hesitate to give positive reviews on a series from your
+  work colleague.  If your positive review is written well, it will
+  not make you look as if you two are representing corporate
+  interest on a series that is otherwise uninteresting to other
+  community members and shoving it down their throat.
+
+- Write a positive review in such a way that others can understand
+  why you support the goal, the approach, and the implementation the
+  patches took.  Make sure to demonstrate that you did thoroughly read
+  the series and understood problem area well enough to be able to
+  say that the patches are written well.  Feel free to "think out
   loud" in your review: describe how you read & understood a complex section of
   a patch, ask a question about something that confused you, point out something
-  you found exceptionally well-written, etc. In particular, uplifting feedback
-  goes a long way towards encouraging contributors to participate more actively
-  in the Git community.
+  you found exceptionally well-written, etc.
+
+- In particular, uplifting feedback goes a long way towards
+  encouraging contributors to participate more actively in the Git
+  community.
 
 ==== Performing your review
 - Provide your review comments per-patch in a plaintext "Reply-All" email to the
diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index 0ba8989..257db58 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -2,7 +2,13 @@
 	These variables control various optional help messages designed to
 	aid new users.  When left unconfigured, Git will give the message
 	alongside instructions on how to squelch it.  You can tell Git
-	that you do not need the help message by setting these to `false`:
+	that you have understood the issue and no longer need a specific
+	help message by setting the corresponding variable to `false`.
++
+As they are intended to help human users, these messages are output to
+the standard error. When tools that run Git as a subprocess find them
+disruptive, they can set `GIT_ADVICE=0` in the environment to squelch
+all advice messages.
 +
 --
 	addEmbeddedRepo::
diff --git a/Documentation/config/credential.txt b/Documentation/config/credential.txt
index 4195191..80a7c77 100644
--- a/Documentation/config/credential.txt
+++ b/Documentation/config/credential.txt
@@ -9,6 +9,14 @@
 Note that multiple helpers may be defined. See linkgit:gitcredentials[7]
 for details and examples.
 
+credential.interactive::
+	By default, Git and any configured credential helpers will ask for
+	user input when new credentials are required. Many of these helpers
+	will succeed based on stored credentials if those credentials are
+	still valid. To avoid the possibility of user interactivity from
+	Git, set `credential.interactive=false`. Some credential helpers
+	respect this option as well.
+
 credential.useHttpPath::
 	When acquiring credentials, consider the "path" component of an http
 	or https URL to be important. Defaults to false. See
diff --git a/Documentation/config/extensions.txt b/Documentation/config/extensions.txt
index 38dce3d..f0a7844 100644
--- a/Documentation/config/extensions.txt
+++ b/Documentation/config/extensions.txt
@@ -9,7 +9,7 @@
 
 extensions.compatObjectFormat::
 
-	Specify a compatitbility hash algorithm to use.  The acceptable values
+	Specify a compatibility hash algorithm to use.  The acceptable values
 	are `sha1` and `sha256`.  The value specified must be different from the
 	value of extensions.objectFormat.  This allows client level
 	interoperability between git repositories whose objectFormat matches
diff --git a/Documentation/config/gc.txt b/Documentation/config/gc.txt
index 664a3c2..21d56db 100644
--- a/Documentation/config/gc.txt
+++ b/Documentation/config/gc.txt
@@ -40,7 +40,8 @@
 
 gc.autoDetach::
 	Make `git gc --auto` return immediately and run in the background
-	if the system supports it. Default is true.
+	if the system supports it. Default is true. This config variable acts
+	as a fallback in case `maintenance.autoDetach` is not set.
 
 gc.bigPackThreshold::
 	If non-zero, all non-cruft packs larger than this limit are kept
@@ -162,7 +163,7 @@
 	containing the filtered out objects. **WARNING:** The
 	specified location should be accessible, using for example the
 	Git alternates mechanism, otherwise the repo could be
-	considered corrupt by Git as it migh not be able to access the
+	considered corrupt by Git as it might not be able to access the
 	objects in that packfile. See the `--filter-to=<dir>` option
 	of linkgit:git-repack[1] and the `objects/info/alternates`
 	section of linkgit:gitrepository-layout[5].
diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt
index 162b33f..a14371b 100644
--- a/Documentation/config/http.txt
+++ b/Documentation/config/http.txt
@@ -5,8 +5,8 @@
 	proxy string with a user name but no password, in which case git will
 	attempt to acquire one in the same way it does for other credentials. See
 	linkgit:gitcredentials[7] for more information. The syntax thus is
-	'[protocol://][user[:password]@]proxyhost[:port]'. This can be overridden
-	on a per-remote basis; see remote.<name>.proxy
+	'[protocol://][user[:password]@]proxyhost[:port][/path]'. This can be
+	overridden on a per-remote basis; see remote.<name>.proxy
 +
 Any proxy, however configured, must be completely transparent and must not
 modify, transform, or buffer the request or response in any way.  Proxies which
diff --git a/Documentation/config/init.txt b/Documentation/config/init.txt
index af03acd..e45b2a8 100644
--- a/Documentation/config/init.txt
+++ b/Documentation/config/init.txt
@@ -8,3 +8,13 @@
 `init.defaultBranch`::
 	Allows overriding the default branch name e.g. when initializing
 	a new repository.
+`init.defaultObjectFormat`::
+	Allows overriding the default object format for new repositories. See
+	`--object-format=` in linkgit:git-init[1]. Both the command line option
+	and the `GIT_DEFAULT_HASH` environment variable take precedence over
+	this config.
+`init.defaultRefFormat`::
+	Allows overriding the default ref storage format for new repositories.
+	See `--ref-format=` in linkgit:git-init[1]. Both the command line
+	option and the `GIT_DEFAULT_REF_FORMAT` environment variable take
+	precedence over this config.
diff --git a/Documentation/config/maintenance.txt b/Documentation/config/maintenance.txt
index 69a4f05..72a9d6c 100644
--- a/Documentation/config/maintenance.txt
+++ b/Documentation/config/maintenance.txt
@@ -3,6 +3,17 @@
 	`git maintenance run --auto` after doing their normal work. Defaults
 	to true.
 
+maintenance.autoDetach::
+	Many Git commands trigger automatic maintenance after they have
+	written data into the repository. This boolean config option
+	controls whether this automatic maintenance shall happen in the
+	foreground or whether the maintenance process shall detach and
+	continue to run in the background.
++
+If unset, the value of `gc.autoDetach` is used as a fallback. Defaults
+to true if both are unset, meaning that the maintenance process will
+detach.
+
 maintenance.strategy::
 	This string config option provides a way to specify one of a few
 	recommended schedules for background maintenance. This only affects
diff --git a/Documentation/config/reftable.txt b/Documentation/config/reftable.txt
index 0515727..5708780 100644
--- a/Documentation/config/reftable.txt
+++ b/Documentation/config/reftable.txt
@@ -46,3 +46,11 @@
 By default, the geometric sequence uses a factor of 2, meaning that for any
 table, the next-biggest table must at least be twice as big. A maximum factor
 of 256 is supported.
+
+reftable.lockTimeout::
+	Whenever the reftable backend appends a new table to the stack, it has
+	to lock the central "tables.list" file before updating it. This config
+	controls how long the process will wait to acquire the lock in case
+	another process has already acquired it. Value 0 means not to retry at
+	all; -1 means to try indefinitely. Default is 100 (i.e., retry for
+	100ms).
diff --git a/Documentation/config/remote.txt b/Documentation/config/remote.txt
index 36e7715..71d1fee 100644
--- a/Documentation/config/remote.txt
+++ b/Documentation/config/remote.txt
@@ -50,7 +50,7 @@
 	If true, this remote will be skipped when updating
 	using linkgit:git-fetch[1], the `update` subcommand of
 	linkgit:git-remote[1], and ignored by the prefetch task
-	of `git maitenance`.
+	of `git maintenance`.
 
 remote.<name>.receivepack::
 	The default program to execute on the remote side when pushing.  See
diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt
index 6a869d6..5ffcfc9 100644
--- a/Documentation/config/sendemail.txt
+++ b/Documentation/config/sendemail.txt
@@ -30,6 +30,21 @@
 	in the linkgit:git-send-email[1] documentation for the meaning of these
 	values.
 
+sendemail.mailmap::
+	If true, makes linkgit:git-send-email[1] assume `--mailmap`,
+	otherwise assume `--no-mailmap`. False by default.
+
+sendemail.mailmap.file::
+	The location of a linkgit:git-send-email[1] specific augmenting
+	mailmap file. The default mailmap and `mailmap.file` are loaded
+	first. Thus, entries in this file take precedence over entries in
+	the default mailmap locations. See linkgit:gitmailmap[5].
+
+sendemail.mailmap.blob::
+	Like `sendemail.mailmap.file`, but consider the value as a reference
+	to a blob in the repository. Entries in `sendemail.mailmap.file`
+	take precedence over entries here. See linkgit:gitmailmap[5].
+
 sendemail.aliasesFile::
 	To avoid typing long email addresses, point this to one or more
 	email aliases files.  You must also supply `sendemail.aliasFileType`.
diff --git a/Documentation/fsck-msgids.txt b/Documentation/fsck-msgids.txt
index f643585..68a2801 100644
--- a/Documentation/fsck-msgids.txt
+++ b/Documentation/fsck-msgids.txt
@@ -19,6 +19,12 @@
 `badParentSha1`::
 	(ERROR) A commit object has a bad parent sha1.
 
+`badRefFiletype`::
+	(ERROR) A ref has a bad file type.
+
+`badRefName`::
+	(ERROR) A ref has an invalid format.
+
 `badTagName`::
 	(INFO) A tag has an invalid format.
 
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index 9cce68a..dd4a61e 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -9,7 +9,8 @@
 SYNOPSIS
 --------
 [verse]
-'git apply' [--stat] [--numstat] [--summary] [--check] [--index | --intent-to-add] [--3way]
+'git apply' [--stat] [--numstat] [--summary] [--check]
+	  [--index | --intent-to-add] [--3way] [--ours | --theirs | --union]
 	  [--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]
 	  [--allow-binary-replacement | --binary] [--reject] [-z]
 	  [-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached]
@@ -92,6 +93,12 @@
 	When used with the `--cached` option, any conflicts are left at higher stages
 	in the cache.
 
+--ours::
+--theirs::
+--union::
+	Instead of leaving conflicts in the file, resolve conflicts favouring
+	our (or their or both) side of the lines. Requires --3way.
+
 --build-fake-ancestor=<file>::
 	Newer 'git diff' output has embedded 'index information'
 	for each blob to help identify the original version that
diff --git a/Documentation/git-check-mailmap.txt b/Documentation/git-check-mailmap.txt
index 02f4418..966c91c 100644
--- a/Documentation/git-check-mailmap.txt
+++ b/Documentation/git-check-mailmap.txt
@@ -15,10 +15,10 @@
 DESCRIPTION
 -----------
 
-For each ``Name $$<user@host>$$'' or ``$$<user@host>$$'' from the command-line
-or standard input (when using `--stdin`), look up the person's canonical name
-and email address (see "Mapping Authors" below). If found, print them;
-otherwise print the input as-is.
+For each ``Name $$<user@host>$$'', ``$$<user@host>$$'', or ``$$user@host$$''
+from the command-line or standard input (when using `--stdin`), look up the
+person's canonical name and email address (see "Mapping Authors" below). If
+found, print them; otherwise print the input as-is.
 
 
 OPTIONS
@@ -27,6 +27,16 @@
 	Read contacts, one per line, from the standard input after exhausting
 	contacts provided on the command-line.
 
+--mailmap-file=<file>::
+	In addition to any configured mailmap files, read the specified
+	mailmap file. Entries in this file take precedence over entries in
+	either the default mailmap file or any configured mailmap file.
+
+--mailmap-blob=<blob>::
+	Like `--mailmap-file`, but consider the value as a reference to a
+	blob in the repository. If both `--mailmap-file` and
+	`--mailmap-blob` are specified, entries in `--mailmap-file` will
+	take precedence.
 
 OUTPUT
 ------
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 8bdfa54..bf26655 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -290,10 +290,10 @@
 `--overlay`), and currently doesn't support overlay mode.
 
 --ignore-other-worktrees::
-	`git checkout` refuses when the wanted ref is already checked
-	out by another worktree. This option makes it check the ref
-	out anyway. In other words, the ref can be held by more than one
-	worktree.
+	`git checkout` refuses when the wanted branch is already checked
+	out or otherwise in use by another worktree. This option makes
+	it check the branch out anyway. In other words, the branch can
+	be in use by more than one worktree.
 
 --overwrite-ignore::
 --no-overwrite-ignore::
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 7f81fbb..3e42017 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -12,7 +12,7 @@
 'git config list' [<file-option>] [<display-option>] [--includes]
 'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>
 'git config set' [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>
-'git config unset' [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>
+'git config unset' [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>
 'git config rename-section' [<file-option>] <old-name> <new-name>
 'git config remove-section' [<file-option>] <name>
 'git config edit' [<file-option>]
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index c1dd12b..d376440 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -264,6 +264,48 @@
 	commits ahead and behind, respectively, when comparing the output
 	ref to the `<committish>` specified in the format.
 
+is-base:<committish>::
+	In at most one row, `(<committish>)` will appear to indicate the ref
+	that is most likely the ref used as a starting point for the branch
+	that produced `<committish>`. This choice is made using a heuristic:
+	choose the ref that minimizes the number of commits in the
+	first-parent history of `<committish>` and not in the first-parent
+	history of the ref.
++
+For example, consider the following figure of first-parent histories of
+several refs:
++
+----
+*--*--*--*--*--* refs/heads/A
+\
+ \
+  *--*--*--* refs/heads/B
+   \     \
+    \     \
+     *     * refs/heads/C
+      \
+       \
+	*--* refs/heads/D
+----
++
+Here, if `A`, `B`, and `C` are the filtered references, and the format
+string is `%(refname):%(is-base:D)`, then the output would be
++
+----
+refs/heads/A:
+refs/heads/B:(D)
+refs/heads/C:
+----
++
+This is because the first-parent history of `D` has its earliest
+intersection with the first-parent histories of the filtered refs at a
+common first-parent ancestor of `B` and `C` and ties are broken by the
+earliest ref in the sorted order.
++
+Note that this token will not appear if the first-parent history of
+`<committish>` does not intersect the first-parent histories of the
+filtered refs.
+
 describe[:options]::
 	A human-readable name, like linkgit:git-describe[1];
 	empty string for undescribable commits. The `describe` string may
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index b5561c4..370e22f 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -9,7 +9,7 @@
 SYNOPSIS
 --------
 [verse]
-'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune] [--force] [--keep-largest-pack]
+'git gc' [--aggressive] [--auto] [--[no-]detach] [--quiet] [--prune=<date> | --no-prune] [--force] [--keep-largest-pack]
 
 DESCRIPTION
 -----------
@@ -53,6 +53,9 @@
 other housekeeping tasks (e.g. rerere, working trees, reflog...) will
 be performed as well.
 
+--[no-]detach::
+	Run in the background if the system supports it. This option overrides
+	the `gc.autoDetach` config.
 
 --[no-]cruft::
 	When expiring unreachable objects, pack them separately into a
diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt
index 9d96819..6e66513 100644
--- a/Documentation/git-maintenance.txt
+++ b/Documentation/git-maintenance.txt
@@ -220,7 +220,9 @@
 that process also executes the "daily" tasks. At midnight on the first day
 of the week, that process also executes the "weekly" tasks. A single
 process iterates over each registered repository, performing the scheduled
-tasks for that frequency. Depending on the number of registered
+tasks for that frequency. The processes are scheduled to a random minute of
+the hour per client to spread out the load that multiple clients might
+generate (e.g. from prefetching). Depending on the number of registered
 repositories and their sizes, this process may take longer than an hour.
 In this case, multiple `git maintenance run` commands may run on the same
 repository at the same time, colliding on the object database lock. This
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt
index 84cb2ed..0b6a8a1 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.txt
@@ -211,9 +211,15 @@
 linkgit:git-update-ref[1], and linkgit:git-mktag[1].  Thus, it can be
 used as a part of a series of steps such as:
 
-       NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2)
-       test $? -eq 0 || die "There were conflicts..."
-       NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2)
+       vi message.txt
+       BRANCH1=refs/heads/test
+       BRANCH2=main
+       NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2) || {
+           echo "There were conflicts..." 1>&2
+           exit 1
+       }
+       NEWCOMMIT=$(git commit-tree $NEWTREE -F message.txt \
+           -p $BRANCH1 -p $BRANCH2)
        git update-ref $BRANCH1 $NEWCOMMIT
 
 Note that when the exit status is non-zero, `NEWTREE` in this sequence
diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt
index 3696506..631d5c7 100644
--- a/Documentation/git-multi-pack-index.txt
+++ b/Documentation/git-multi-pack-index.txt
@@ -64,6 +64,12 @@
 duplicates. (If a given OID is given more than once, it is marked as
 preferred if at least one instance of it begins with the special `+`
 marker).
+
+	--incremental::
+		Write an incremental MIDX file containing only objects
+		and packs not present in an existing MIDX layer.
+		Migrates non-incremental MIDXs to incremental ones when
+		necessary. Incompatible with `--bitmap`.
 --
 
 verify::
@@ -74,6 +80,8 @@
 	have no objects referenced by the MIDX (with the exception of
 	`.keep` packs and cruft packs). Rewrite the MIDX file afterward
 	to remove all references to these pack-files.
++
+NOTE: this mode is incompatible with incremental MIDX files.
 
 repack::
 	Create a new pack-file containing objects in small pack-files
@@ -95,7 +103,8 @@
 +
 If `repack.packKeptObjects` is `false`, then any pack-files with an
 associated `.keep` file will not be selected for the batch to repack.
-
++
+NOTE: this mode is incompatible with incremental MIDX files.
 
 EXAMPLES
 --------
diff --git a/Documentation/git-refs.txt b/Documentation/git-refs.txt
index 5b99e04..ce31f93 100644
--- a/Documentation/git-refs.txt
+++ b/Documentation/git-refs.txt
@@ -10,6 +10,7 @@
 --------
 [verse]
 'git refs migrate' --ref-format=<format> [--dry-run]
+'git refs verify' [--strict] [--verbose]
 
 DESCRIPTION
 -----------
@@ -22,6 +23,9 @@
 migrate::
 	Migrate ref store between different formats.
 
+verify::
+	Verify reference database consistency.
+
 OPTIONS
 -------
 
@@ -39,6 +43,15 @@
 	can be used to double check that the migration works as expected before
 	performing the actual migration.
 
+The following options are specific to 'git refs verify':
+
+--strict::
+	Enable stricter error checking. This will cause warnings to be
+	reported as errors. See linkgit:git-fsck[1].
+
+--verbose::
+	When verifying the reference database consistency, be chatty.
+
 KNOWN LIMITATIONS
 -----------------
 
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index c5d664f..bc3ef45 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -12,6 +12,7 @@
 'git send-email' [<options>] (<file>|<directory>)...
 'git send-email' [<options>] <format-patch-options>
 'git send-email' --dump-aliases
+'git send-email' --translate-aliases
 
 
 DESCRIPTION
@@ -413,6 +414,12 @@
 Failure to do so may not produce the expected result in the
 recipient's MUA.
 
+--[no-]mailmap::
+	Use the mailmap file (see linkgit:gitmailmap[5]) to map all
+	addresses to their canonical real name and email address. Additional
+	mailmap data specific to git-send-email may be provided using the
+	`sendemail.mailmap.file` or `sendemail.mailmap.blob` configuration
+	values. Defaults to `sendemail.mailmap`.
 
 Administering
 ~~~~~~~~~~~~~
@@ -475,6 +482,12 @@
 	that this only includes the alias name and not its expanded email addresses.
 	See 'sendemail.aliasesFile' for more information about aliases.
 
+--translate-aliases::
+	Instead of the normal operation, read from standard input and
+	interpret each line as an email alias. Translate it according to the
+	configured alias file(s). Output each translated name and email
+	address to standard output, one per line. See 'sendemail.aliasFile'
+	for more information about aliases.
 
 CONFIGURATION
 -------------
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index ca0347a..87d8e0f 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -34,7 +34,7 @@
 With no arguments, shows the status of existing submodules.  Several
 subcommands are available to perform operations on the submodules.
 
-add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]::
+add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--ref-format <format>] [--depth <depth>] [--] <repository> [<path>]::
 	Add the given repository as a submodule at the given path
 	to the changeset to be committed next to the current
 	project: the current project is termed the "superproject".
@@ -71,6 +71,9 @@
 location, and only the superproject's URL needs to be provided.
 git-submodule will correctly locate the submodule using the relative
 URL in `.gitmodules`.
++
+If `--ref-format <format>`  is specified, the ref storage format of newly
+cloned submodules will be set accordingly.
 
 status [--cached] [--recursive] [--] [<path>...]::
 	Show the status of the submodules. This will print the SHA-1 of the
@@ -136,7 +139,7 @@
 that use linkgit:git-rm[1] instead. See linkgit:gitsubmodules[7] for removal
 options.
 
-update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--filter <filter-spec>] [--] [<path>...]::
+update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--ref-format <format>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--filter <filter-spec>] [--] [<path>...]::
 +
 --
 Update the registered submodules to match what the superproject
@@ -185,6 +188,9 @@
 If `--recursive` is specified, this command will recurse into the
 registered submodules, and update any nested submodules within.
 
+If `--ref-format <format>`  is specified, the ref storage format of newly
+cloned submodules will be set accordingly.
+
 If `--filter <filter-spec>` is specified, the given partial clone filter will be
 applied to the submodule. See linkgit:git-rev-list[1] for details on filter
 specifications.
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 43c68c2..bcf7d84 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -431,14 +431,14 @@
 	independently of 'git svn' functions.
 
 'create-ignore'::
-	Recursively finds the svn:ignore property on directories and
-	creates matching .gitignore files. The resulting files are staged to
-	be committed, but are not committed. Use -r/--revision to refer to a
-	specific revision.
+	Recursively finds the svn:ignore and svn:global-ignores properties
+	on directories and creates matching .gitignore files. The resulting
+	files are staged to be committed, but are not committed. Use
+	-r/--revision to refer to a specific revision.
 
 'show-ignore'::
-	Recursively finds and lists the svn:ignore property on
-	directories.  The output is suitable for appending to
+	Recursively finds and lists the svn:ignore and svn:global-ignores
+	properties on directories. The output is suitable for appending to
 	the $GIT_DIR/info/exclude file.
 
 'mkdirs'::
@@ -871,7 +871,7 @@
 # Now commit your changes (that were committed previously using Git) to SVN,
 # as well as automatically updating your working HEAD:
 	git svn dcommit
-# Append svn:ignore settings to the default Git exclude file:
+# Append svn:ignore and svn:global-ignores settings to the default Git exclude file:
 	git svn show-ignore >> .git/info/exclude
 ------------------------------------------------------------------------
 
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 4489e22..d15a869 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -1027,6 +1027,17 @@
 	adequate and support for it is likely to be removed in the
 	foreseeable future (along with the variable).
 
+`GIT_ADVICE`::
+	If set to `0`, then disable all advice messages. These messages are
+	intended to provide hints to human users that may help them get out of
+	problematic situations or take advantage of new features. Users can
+	disable individual messages using the `advice.*` config keys. These
+	messages may be disruptive to tools that execute Git processes, so this
+	variable is available to disable the messages. (The `--no-advice`
+	global option is also available, but old Git versions may fail when
+	this option is not understood. The environment variable will be ignored
+	by Git versions that do not understand it.)
+
 Discussion[[Discussion]]
 ------------------------
 
diff --git a/Documentation/gitformat-commit-graph.txt b/Documentation/gitformat-commit-graph.txt
index 3e906e8..14d1631 100644
--- a/Documentation/gitformat-commit-graph.txt
+++ b/Documentation/gitformat-commit-graph.txt
@@ -122,7 +122,7 @@
       for commits with corrected commit date offsets that cannot be
       stored within 31 bits.
     * Generation Data Overflow chunk is present only when Generation Data
-      chunk is present and atleast one corrected commit date offset cannot
+      chunk is present and at least one corrected commit date offset cannot
       be stored within 31 bits.
 
 ==== Extra Edge List (ID: {'E', 'D', 'G', 'E'}) [Optional]
diff --git a/Documentation/gitprotocol-v2.txt b/Documentation/gitprotocol-v2.txt
index 414bc62..ca83b2e 100644
--- a/Documentation/gitprotocol-v2.txt
+++ b/Documentation/gitprotocol-v2.txt
@@ -527,8 +527,8 @@
 
 The provided options must not contain a NUL or LF character.
 
- object-format
-~~~~~~~~~~~~~~~
+object-format
+~~~~~~~~~~~~~
 
 The server can advertise the `object-format` capability with a value `X` (in the
 form `object-format=X`) to notify the client that the server is able to deal
diff --git a/Documentation/gitweb.txt b/Documentation/gitweb.txt
index 56d24a3..5e2b491 100644
--- a/Documentation/gitweb.txt
+++ b/Documentation/gitweb.txt
@@ -234,7 +234,7 @@
 configuration variable, but the file takes precedence.
 
 category (or `gitweb.category`)::
-	Singe line category of a project, used to group projects if
+	Single line category of a project, used to group projects if
 	`$projects_list_group_categories` is enabled.  By default (file and
 	configuration variable absent), uncategorized projects are put in the
 	`$project_list_default_category` category.  You can use the
diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.txt
index da31332..45e2599 100644
--- a/Documentation/howto/maintain-git.txt
+++ b/Documentation/howto/maintain-git.txt
@@ -67,7 +67,22 @@
    before getting merged to 'master'.
 
  - 'seen' branch is used to publish other proposed changes that do
-   not yet pass the criteria set for 'next' (see above).
+   not yet pass the criteria set for 'next' (see above), but there
+   is no promise that 'seen' will contain everything.  A topic that
+   had no reviewer reaction may not be picked up.
+
+   - A new topic will first get merged to 'seen', unless it is
+     trivially correct and clearly urgent, in which case it may be
+     directly merged to 'next' or even to 'master'.
+
+   - If a topic that was picked up to 'seen' becomes and stays
+     inactive for 3 calendar weeks without having seen a clear
+     consensus that it is good enough to be moved to 'next', the
+     topic may be discarded from 'seen'.  Interested parties are
+     still free to revive the topic.  For the purpose of this
+     guideline, the definition of being "inactive" is that nobody
+     has discussed the topic, no new iteration of the topic was
+     posted, and no responses to the review comments were given.
 
  - The tips of 'master' and 'maint' branches will not be rewound to
    allow people to build their own customization on top of them.
@@ -122,6 +137,13 @@
 structured slightly differently.  vX.Y.Z were feature releases while
 vX.Y.Z.W were maintenance releases for vX.Y.Z.
 
+Because most of the lines of code in Git are written by individual
+contributors, and contributions come in the form of e-mailed patches
+published on the mailing list, the project maintains a mapping from
+individual commits to the Message-Id of the e-mail that resulted in
+the commit, to help tracking the origin of the changes. The notes
+in "refs/notes/amlog" are used for this purpose, and are published
+along with the broken-out branches to the maintainer's repository.
 
 A Typical Git Day
 -----------------
@@ -165,6 +187,43 @@
    In practice, almost no patch directly goes to 'master' or
    'maint'.
 
+   Applying the e-mailed patches using "git am" automatically records
+   the mappings from 'Message-Id' to the applied commit in the "amlog"
+   notes. Periodically check that this is working with "git show -s
+   --notes=amlog $commit".
+
+   This mapping is maintained with the aid of the "post-applypatch"
+   hook found in the 'todo' branch. That hook should be installed
+   before applying patches. It is also helpful to carry forward any
+   relevant amlog entries when rebasing, so the following config may
+   be useful:
+
+      [notes]
+	rewriteRef = refs/notes/amlog
+
+   Avoid "cherry-pick", as it does not propagate notes by design. Use
+   either "git commit --amend" or "git rebase" to make corrections to
+   an existing commit, even for a single-patch topic.
+
+   Make sure that a push refspec for 'refs/notes/amlog' is in the
+   remote configuration for publishing repositories. A few sample
+   configurations look like the following:
+
+      [remote "github"]
+	url = https://github.com/gitster/git
+	pushurl = github.com:gitster/git.git
+	mirror
+
+      [remote "github2"]
+	url = https://github.com/git/git
+	fetch = +refs/heads/*:refs/remotes/github2/*
+	pushurl = github.com:git/git.git
+	push = refs/heads/maint:refs/heads/maint
+	push = refs/heads/master:refs/heads/master
+	push = refs/heads/next:refs/heads/next
+	push = +refs/heads/seen:refs/heads/seen
+	push = +refs/notes/amlog
+
  - Review the last issue of "What's cooking" message, review the
    topics ready for merging (topic->master and topic->maint).  Use
    "Meta/cook -w" script (where Meta/ contains a checkout of the
diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt
index c718f79..d79d2f6 100644
--- a/Documentation/pull-fetch-param.txt
+++ b/Documentation/pull-fetch-param.txt
@@ -25,14 +25,15 @@
 +
 The format of a <refspec> parameter is an optional plus
 `+`, followed by the source <src>, followed
-by a colon `:`, followed by the destination ref <dst>.
+by a colon `:`, followed by the destination <dst>.
 The colon can be omitted when <dst> is empty.  <src> is
-typically a ref, but it can also be a fully spelled hex object
+typically a ref, or a glob pattern with a single `*` that is used
+to match a set of refs, but it can also be a fully spelled hex object
 name.
 +
 A <refspec> may contain a `*` in its <src> to indicate a simple pattern
 match. Such a refspec functions like a glob that matches any ref with the
-same prefix. A pattern <refspec> must have a `*` in both the <src> and
+pattern. A pattern <refspec> must have one and only one `*` in both the <src> and
 <dst>. It will map refs to the destination by replacing the `*` with the
 contents matched from the source.
 +
diff --git a/Documentation/scalar.txt b/Documentation/scalar.txt
index 361f51a..7e4259c 100644
--- a/Documentation/scalar.txt
+++ b/Documentation/scalar.txt
@@ -86,6 +86,13 @@
 	`<entlistment>/src` directory. Use `--no-src` to place the cloned
 	repository directly in the `<enlistment>` directory.
 
+--[no-]tags::
+	By default, `scalar clone` will fetch the tag objects advertised by
+	the remote and future `git fetch` commands will do the same. Use
+	`--no-tags` to avoid fetching tags in `scalar clone` and to configure
+	the repository to avoid fetching tags in the future. To fetch tags after
+	cloning with `--no-tags`, run `git fetch --tags`.
+
 --[no-]full-clone::
 	A sparse-checkout is initialized by default. This behavior can be
 	turned off via `--full-clone`.
diff --git a/Documentation/technical/api-trace2.txt b/Documentation/technical/api-trace2.txt
index de5fc25..5817b18 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.txt
@@ -128,7 +128,7 @@
 
 ------------
 $ cat ~/log.event
-{"event":"version","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"3","exe":"2.20.1.155.g426c96fcdb"}
+{"event":"version","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"4","exe":"2.20.1.155.g426c96fcdb"}
 {"event":"start","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621027Z","file":"common-main.c","line":39,"t_abs":0.001173,"argv":["git","version"]}
 {"event":"cmd_name","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621122Z","file":"git.c","line":432,"name":"version","hierarchy":"version"}
 {"event":"exit","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621236Z","file":"git.c","line":662,"t_abs":0.001227,"code":0}
@@ -344,7 +344,7 @@
 {
 	"event":"version",
 	...
-	"evt":"3",		       # EVENT format version
+	"evt":"4",		       # EVENT format version
 	"exe":"2.20.1.155.g426c96fcdb" # git version
 }
 ------------
@@ -835,6 +835,19 @@
 }
 ------------
 
+`"printf"`::
+	This event logs a human-readable message with no particular formatting
+	guidelines.
++
+------------
+{
+	"event":"printf",
+	...
+	"t_abs":0.015905,      # elapsed time in seconds
+	"msg":"Hello world"    # optional
+}
+------------
+
 
 == Example Trace2 API Usage
 
diff --git a/Documentation/technical/multi-pack-index.txt b/Documentation/technical/multi-pack-index.txt
index f2221d2..cc063b3 100644
--- a/Documentation/technical/multi-pack-index.txt
+++ b/Documentation/technical/multi-pack-index.txt
@@ -61,6 +61,109 @@
 - The MIDX file format uses a chunk-based approach (similar to the
   commit-graph file) that allows optional data to be added.
 
+Incremental multi-pack indexes
+------------------------------
+
+As repositories grow in size, it becomes more expensive to write a
+multi-pack index (MIDX) that includes all packfiles. To accommodate
+this, the "incremental multi-pack indexes" feature allows for combining
+a "chain" of multi-pack indexes.
+
+Each individual component of the chain need only contain a small number
+of packfiles. Appending to the chain does not invalidate earlier parts
+of the chain, so repositories can control how much time is spent
+updating the MIDX chain by determining the number of packs in each layer
+of the MIDX chain.
+
+=== Design state
+
+At present, the incremental multi-pack indexes feature is missing two
+important components:
+
+  - The ability to rewrite earlier portions of the MIDX chain (i.e., to
+    "compact" some collection of adjacent MIDX layers into a single
+    MIDX). At present the only supported way of shrinking a MIDX chain
+    is to rewrite the entire chain from scratch without the `--split`
+    flag.
++
+There are no fundamental limitations that stand in the way of being able
+to implement this feature. It is omitted from the initial implementation
+in order to reduce the complexity, but will be added later.
+
+  - Support for reachability bitmaps. The classic single MIDX
+    implementation does support reachability bitmaps (see the section
+    titled "multi-pack-index reverse indexes" in
+    linkgit:gitformat-pack[5] for more details).
++
+As above, there are no fundamental limitations that stand in the way of
+extending the incremental MIDX format to support reachability bitmaps.
+The design below specifically takes this into account, and support for
+reachability bitmaps will be added in a future patch series. It is
+omitted from the current implementation for the same reason as above.
++
+In brief, to support reachability bitmaps with the incremental MIDX
+feature, the concept of the pseudo-pack order is extended across each
+layer of the incremental MIDX chain to form a concatenated pseudo-pack
+order. This concatenation takes place in the same order as the chain
+itself (in other words, the concatenated pseudo-pack order for a chain
+`{$H1, $H2, $H3}` would be the pseudo-pack order for `$H1`, followed by
+the pseudo-pack order for `$H2`, followed by the pseudo-pack order for
+`$H3`).
++
+The layout will then be extended so that each layer of the incremental
+MIDX chain can write a `*.bitmap`. The objects in each layer's bitmap
+are offset by the number of objects in the previous layers of the chain.
+
+=== File layout
+
+Instead of storing a single `multi-pack-index` file (with an optional
+`.rev` and `.bitmap` extension) in `$GIT_DIR/objects/pack`, incremental
+MIDXs are stored in the following layout:
+
+----
+$GIT_DIR/objects/pack/multi-pack-index.d/
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-chain
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H1.midx
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H2.midx
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H3.midx
+----
+
+The `multi-pack-index-chain` file contains a list of the incremental
+MIDX files in the chain, in order. The above example shows a chain whose
+`multi-pack-index-chain` file would contain the following lines:
+
+----
+$H1
+$H2
+$H3
+----
+
+The `multi-pack-index-$H1.midx` file contains the first layer of the
+multi-pack-index chain. The `multi-pack-index-$H2.midx` file contains
+the second layer of the chain, and so on.
+
+When both an incremental- and non-incremental MIDX are present, the
+non-incremental MIDX is always read first.
+
+=== Object positions for incremental MIDXs
+
+In the original multi-pack-index design, we refer to objects via their
+lexicographic position (by object IDs) within the repository's singular
+multi-pack-index. In the incremental multi-pack-index design, we refer
+to objects via their index into a concatenated lexicographic ordering
+among each component in the MIDX chain.
+
+If `objects_nr()` is a function that returns the number of objects in a
+given MIDX layer, then the index of an object at lexicographic position
+`i` within, say, $H3 is defined as:
+
+----
+objects_nr($H2) + objects_nr($H1) + i
+----
+
+(in the C implementation, this is often computed as `i +
+m->num_objects_in_base`).
+
 Future Work
 -----------
 
diff --git a/Documentation/technical/platform-support.txt b/Documentation/technical/platform-support.txt
new file mode 100644
index 0000000..0a2fb28
--- /dev/null
+++ b/Documentation/technical/platform-support.txt
@@ -0,0 +1,190 @@
+Platform Support Policy
+=======================
+
+Git has a history of providing broad "support" for exotic platforms and older
+platforms, without an explicit commitment. Stakeholders of these platforms may
+want a more predictable support commitment. This is only possible when platform
+stakeholders supply Git developers with adequate tooling, so we can test for
+compatibility or develop workarounds for platform-specific quirks on our own.
+Various levels of platform-specific tooling will allow us to make more solid
+commitments around Git's compatibility with that platform.
+
+Note that this document is about maintaining existing support for a platform
+that has generally worked in the past; for adding support to a platform which
+doesn't generally work with Git, the stakeholders for that platform are expected
+to do the bulk of that work themselves. We will consider such patches if they
+don't make life harder for other supported platforms or for Git contributors.
+Some contributors may volunteer to help with the initial or continued support,
+but that's not a given. Support work which is too intrusive or difficult for the
+project to maintain may still not be accepted.
+
+Minimum Requirements
+--------------------
+
+The rest of this doc describes best practices for platforms to make themselves
+easy to support. However, before considering support at all, platforms need to
+meet the following minimum requirements:
+
+* Has C99 or C11
+
+* Uses versions of dependencies which are generally accepted as stable and
+  supportable, e.g., in line with the version used by other long-term-support
+  distributions
+
+* Has active security support (taking security releases of dependencies, etc)
+
+These requirements are a starting point, and not sufficient on their own for the
+Git community to be enthusiastic about supporting your platform. Maintainers of
+platforms which do meet these requirements can follow the steps below to make it
+more likely that Git updates will respect the platform's needs.
+
+Compatible by next release
+--------------------------
+
+To increase probability that compatibility issues introduced in a release
+will be fixed in a later release:
+
+* You should send a bug report as soon as you notice the breakage on your
+  platform. The sooner you notice, the better; watching `seen` means you can
+  notice problems before they are considered "done with review"; whereas
+  watching `master` means the stable branch could break for your platform, but
+  you have a decent chance of avoiding a tagged release breaking you. See "The
+  Policy" in link:../howto/maintain-git.html["How to maintain Git"] for an
+  overview of which branches are used in the Git project, and how.
+
+* The bug report should include information about what platform you are using.
+
+* You should also use linkgit:git-bisect[1] and determine which commit
+  introduced the breakage.
+
+* Please include any information you have about the nature of the breakage: is
+  it a memory alignment issue? Is an underlying library missing or broken for
+  your platform? Is there some quirk about your platform which means typical
+  practices (like malloc) behave strangely?
+
+* If possible, build Git from the exact same source both for your platform and
+  for a mainstream platform, to see if the problem you noticed appears only
+  on your platform. If the problem appears in both, then it's not a
+  compatibility issue, but we of course appreciate hearing about it in a bug
+  report anyway, to benefit users of every platform. If it appears only on your
+  platform, mention clearly that it is a compatibility issue in your report.
+
+* Once we begin to fix the issue, please work closely with the contributor
+  working on it to test the proposed fix against your platform.
+
+Example: NonStop
+https://lore.kernel.org/git/01bd01da681a$b8d70a70$2a851f50$@nexbridge.com/[reports
+problems] when they're noticed.
+
+Compatible on `master` and releases
+-----------------------------------
+
+To make sure all stable builds and regular releases work for your platform the
+first time, help us avoid breaking `master` for your platform:
+
+* You should run regular tests against the `next` branch and
+  publish breakage reports to the mailing list immediately when they happen.
+
+** Ideally, these tests should run daily. They must run more often than
+   weekly, as topics generally spend at least 7 days in `next` before graduating
+   to `master`, and it takes time to put the brakes on a patch once it lands in
+   `next`.
+
+** You may want to ask to join the mailto:git-security@googlegroups.com[security
+   mailing list] in order to run tests against the fixes proposed there, too.
+
+* It may make sense to automate these; if you do, make sure they are not noisy
+  (you don't need to send a report when everything works, only when something
+  breaks; you don't need to send repeated reports for the same breakage night
+  after night).
+
+* Breakage reports should be actionable - include clear error messages that can
+  help developers who may not have access to test directly on your platform.
+
+* You should use git-bisect and determine which commit introduced the breakage;
+  if you can't do this with automation, you should do this yourself manually as
+  soon as you notice a breakage report was sent.
+
+* You should either:
+
+** Provide on-demand access to your platform to a trusted developer working to
+   fix the issue, so they can test their fix, OR
+
+** Work closely with the developer fixing the issue; the turnaround to check
+   that their proposed fix works for your platform should be fast enough that it
+   doesn't hinder the developer working on that fix. Slow testing turnarounds
+   may cause the fix to miss the next release, or the developer may lose
+   interest in working on the fix at all.
+
+Example:
+https://lore.kernel.org/git/CAHd-oW6X4cwD_yLNFONPnXXUAFPxgDoccv2SOdpeLrqmHCJB4Q@mail.gmail.com/[AIX]
+provides a build farm and runs tests against release candidates.
+
+Compatible on `next`
+--------------------
+
+To avoid reactive debugging and fixing when changes hit a release or stable, you
+can aim to ensure `next` always works for your platform. (See "The Policy" in
+link:../howto/maintain-git.html["How to maintain Git"] for an overview of how
+`next` is used in the Git project.) To do that:
+
+* You should add a runner for your platform to the GitHub Actions or GitLab CI
+  suite.  This suite is run when any Git developer proposes a new patch, and
+  having a runner for your platform/configuration means every developer will
+  know if they break you, immediately.
+
+** If adding it to an existing CI suite is infeasible (due to architecture
+   constraints or for performance reasons), any other method which runs as
+   automatically and quickly as possible works, too. For example, a service
+   which snoops on the mailing list and automatically runs tests on new [PATCH]
+   emails, replying to the author with the results, would also be within the
+   spirit of this requirement.
+
+* If you rely on Git avoiding a specific pattern that doesn't work well with
+  your platform (like a certain malloc pattern), raise it on the mailing list.
+  We'll work case-by-case to look for a solution that doesn't unnecessarily
+  constrain other platforms to keep compatibility with yours.
+
+* If you rely on some configuration or behavior, add a test for it. Untested
+  behavior is subject to breakage at any time.
+
+** Clearly label these tests as necessary for platform compatibility. Add them
+   to an isolated compatibility-related test suite, like a new t* file or unit
+   test suite, so that they're easy to remove when compatibility is no longer
+   required.  If the specific compatibility need is gated behind an issue with
+   another project, link to documentation of that issue (like a bug or email
+   thread) to make it easier to tell when that compatibility need goes away.
+
+** Include a comment with an expiration date for these tests no more than 1 year
+   from now. You can update the expiration date if your platform still needs
+   that assurance down the road, but we need to know you still care about that
+   compatibility case and are working to make it unnecessary.
+
+Example: We run our
+https://git.kernel.org/pub/scm/git/git.git/tree/.github/workflows/main.yml[CI
+suite] on Windows, Ubuntu, Mac, and others.
+
+Getting help writing platform support patches
+---------------------------------------------
+
+In general, when sending patches to fix platform support problems, follow
+these guidelines to make sure the patch is reviewed with the appropriate level
+of urgency:
+
+* Clearly state in the commit message that you are fixing a platform breakage,
+  and for which platform.
+
+* Use the CI and test suite to ensure that the fix for your platform doesn't
+  break other platforms.
+
+* If possible, add a test ensuring this regression doesn't happen again. If
+  it's not possible to add a test, explain why in the commit message.
+
+Platform Maintainers
+--------------------
+
+If you maintain a platform, or Git for that platform, and intend to work with
+the Git project to ensure compatibility, please send a patch to add yourself to
+this list.
+
+NonStop: Randall S. Becker <rsbecker@nexbridge.com>
diff --git a/Documentation/technical/sparse-checkout.txt b/Documentation/technical/sparse-checkout.txt
index fa0d01c..d968659 100644
--- a/Documentation/technical/sparse-checkout.txt
+++ b/Documentation/technical/sparse-checkout.txt
@@ -287,7 +287,7 @@
 checkouts and switches write fewer things, knowing the VFS will lazily
 write the rest on an as-needed basis).
 
-Since there is no publically available VFS-related code for folks to try,
+Since there is no publicly available VFS-related code for folks to try,
 the number of folks who can test such a usecase is limited.
 
 The primary reason to note the Behavior C usecase is that as we fix things
diff --git a/Documentation/technical/unit-tests.txt b/Documentation/technical/unit-tests.txt
index 206037f..5a432b7 100644
--- a/Documentation/technical/unit-tests.txt
+++ b/Documentation/technical/unit-tests.txt
@@ -203,6 +203,7 @@
 :criterion: https://github.com/Snaipe/Criterion[Criterion]
 :c-tap: https://github.com/rra/c-tap-harness/[C TAP]
 :check: https://libcheck.github.io/check/[Check]
+:clar: https://github.com/clar-test/clar[Clar]
 
 [format="csv",options="header",width="33%",subs="specialcharacters,attributes,quotes,macros"]
 |=====
@@ -212,6 +213,7 @@
 {criterion},{mit},{false},{partial},{true},{true},{true},{true},{true},{false},{true},19,1800
 {c-tap},{expat},{true},{partial},{partial},{true},{false},{true},{false},{false},{false},4,33
 {check},{lgpl},{false},{partial},{true},{true},{true},{false},{false},{false},{true},17,973
+{clar},{isc},{false},{partial},{true},{true},{true},{true},{false},{false},{true},1,192
 |=====
 
 === Additional framework candidates
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 0c7a842..5fcb9de 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.46.4
+DEF_VER=v2.47.1
 
 LF='
 '
diff --git a/Makefile b/Makefile
index d647909..2dde1fd 100644
--- a/Makefile
+++ b/Makefile
@@ -385,6 +385,10 @@
 # supports calling _NSGetExecutablePath to retrieve the path of the running
 # executable.
 #
+# When using RUNTIME_PREFIX, define HAVE_ZOS_GET_EXECUTABLE_PATH if your platform
+# supports calling __getprogramdir and getprogname to retrieve the path of the
+# running executable.
+#
 # When using RUNTIME_PREFIX, define HAVE_WPGMPTR if your platform offers
 # the global variable _wpgmptr containing the absolute path of the current
 # executable (this is the case on Windows).
@@ -517,6 +521,10 @@
 # Define APPLE_COMMON_CRYPTO_SHA1 to use Apple's CommonCrypto for
 # SHA-1.
 #
+# Define the same Makefile knobs as above, but suffixed with _UNSAFE to
+# use the corresponding implementations for unsafe SHA-1 hashing for
+# non-cryptographic purposes.
+#
 # If don't enable any of the *_SHA1 settings in this section, Git will
 # default to its built-in sha1collisiondetection library, which is a
 # collision-detecting sha1 This is slower, but may detect attempted
@@ -808,7 +816,6 @@
 TEST_BUILTINS_OBJS += test-match-trees.o
 TEST_BUILTINS_OBJS += test-mergesort.o
 TEST_BUILTINS_OBJS += test-mktemp.o
-TEST_BUILTINS_OBJS += test-oid-array.o
 TEST_BUILTINS_OBJS += test-online-cpus.o
 TEST_BUILTINS_OBJS += test-pack-mtimes.o
 TEST_BUILTINS_OBJS += test-parse-options.o
@@ -843,7 +850,6 @@
 TEST_BUILTINS_OBJS += test-subprocess.o
 TEST_BUILTINS_OBJS += test-trace2.o
 TEST_BUILTINS_OBJS += test-truncate.o
-TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
 TEST_BUILTINS_OBJS += test-userdiff.o
 TEST_BUILTINS_OBJS += test-wildmatch.o
 TEST_BUILTINS_OBJS += test-windows-named-pipe.o
@@ -909,11 +915,12 @@
 LIB_FILE = libgit.a
 XDIFF_LIB = xdiff/lib.a
 REFTABLE_LIB = reftable/libreftable.a
-REFTABLE_TEST_LIB = reftable/libreftable_test.a
 
 GENERATED_H += command-list.h
 GENERATED_H += config-list.h
 GENERATED_H += hook-list.h
+GENERATED_H += $(UNIT_TEST_DIR)/clar-decls.h
+GENERATED_H += $(UNIT_TEST_DIR)/clar.suite
 
 .PHONY: generated-hdrs
 generated-hdrs: $(GENERATED_H)
@@ -1331,24 +1338,41 @@
 THIRD_PARTY_SOURCES += compat/regex/%
 THIRD_PARTY_SOURCES += sha1collisiondetection/%
 THIRD_PARTY_SOURCES += sha1dc/%
+THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/%
+THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/%
 
-UNIT_TEST_PROGRAMS += t-ctype
+CLAR_TEST_SUITES += ctype
+CLAR_TEST_SUITES += 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
+
 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
+UNIT_TEST_PROGRAMS += t-reftable-pq
+UNIT_TEST_PROGRAMS += t-reftable-reader
+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-strvec
 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 = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(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
 GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE)
@@ -1376,7 +1400,7 @@
 
 # For the 'sparse' target
 SPARSE_FLAGS ?= -std=gnu99
-SP_EXTRA_FLAGS = -Wno-universal-initializer
+SP_EXTRA_FLAGS =
 
 # For informing GIT-BUILD-OPTIONS of the SANITIZE=leak,address targets
 SANITIZE_LEAK =
@@ -1977,6 +2001,27 @@
 endif
 endif
 
+ifdef OPENSSL_SHA1_UNSAFE
+ifndef OPENSSL_SHA1
+	EXTLIBS += $(LIB_4_CRYPTO)
+	BASIC_CFLAGS += -DSHA1_OPENSSL_UNSAFE
+endif
+else
+ifdef BLK_SHA1_UNSAFE
+ifndef BLK_SHA1
+	LIB_OBJS += block-sha1/sha1.o
+	BASIC_CFLAGS += -DSHA1_BLK_UNSAFE
+endif
+else
+ifdef APPLE_COMMON_CRYPTO_SHA1_UNSAFE
+ifndef APPLE_COMMON_CRYPTO_SHA1
+	COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
+	BASIC_CFLAGS += -DSHA1_APPLE_UNSAFE
+endif
+endif
+endif
+endif
+
 ifdef OPENSSL_SHA256
 	EXTLIBS += $(LIB_4_CRYPTO)
 	BASIC_CFLAGS += -DSHA256_OPENSSL
@@ -2151,6 +2196,10 @@
 	BASIC_CFLAGS += -DHAVE_NS_GET_EXECUTABLE_PATH
 endif
 
+ifdef HAVE_ZOS_GET_EXECUTABLE_PATH
+        BASIC_CFLAGS += -DHAVE_ZOS_GET_EXECUTABLE_PATH
+endif
+
 ifdef HAVE_WPGMPTR
 	BASIC_CFLAGS += -DHAVE_WPGMPTR
 endif
@@ -2673,20 +2722,10 @@
 REFTABLE_OBJS += reftable/pq.o
 REFTABLE_OBJS += reftable/reader.o
 REFTABLE_OBJS += reftable/record.o
-REFTABLE_OBJS += reftable/generic.o
 REFTABLE_OBJS += reftable/stack.o
 REFTABLE_OBJS += reftable/tree.o
 REFTABLE_OBJS += reftable/writer.o
 
-REFTABLE_TEST_OBJS += reftable/block_test.o
-REFTABLE_TEST_OBJS += reftable/dump.o
-REFTABLE_TEST_OBJS += reftable/merged_test.o
-REFTABLE_TEST_OBJS += reftable/pq_test.o
-REFTABLE_TEST_OBJS += reftable/readwrite_test.o
-REFTABLE_TEST_OBJS += reftable/stack_test.o
-REFTABLE_TEST_OBJS += reftable/test_framework.o
-REFTABLE_TEST_OBJS += reftable/tree_test.o
-
 TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
 
 .PHONY: test-objs
@@ -2711,6 +2750,8 @@
 OBJECTS += $(FUZZ_OBJS)
 OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS)
 OBJECTS += $(UNIT_TEST_OBJS)
+OBJECTS += $(CLAR_TEST_OBJS)
+OBJECTS += $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
 
 ifndef NO_CURL
 	OBJECTS += http.o http-walker.o remote-curl.o
@@ -2861,9 +2902,6 @@
 $(REFTABLE_LIB): $(REFTABLE_OBJS)
 	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
 
-$(REFTABLE_TEST_LIB): $(REFTABLE_TEST_OBJS)
-	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-
 export DEFAULT_EDITOR DEFAULT_PAGER
 
 Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
@@ -3213,7 +3251,7 @@
 
 test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))
 
-all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS)
+all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG)
 
 bin-wrappers/%: wrap-for-bin.sh
 	$(call mkdir_p_parent_template)
@@ -3243,15 +3281,16 @@
 
 t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) $(UNIT_TEST_DIR)/test-lib.o
 
-t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) $(REFTABLE_TEST_LIB)
+t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
 
 check-sha1:: t/helper/test-tool$X
 	t/helper/test-sha1.sh
 
-SP_OBJ = $(patsubst %.o,%.sp,$(OBJECTS))
+SP_SRC = $(filter-out $(THIRD_PARTY_SOURCES),$(patsubst %.o,%.c,$(OBJECTS)))
+SP_OBJ = $(patsubst %.c,%.sp,$(SP_SRC))
 
-$(SP_OBJ): %.sp: %.c %.o
+$(SP_OBJ): %.sp: %.c %.o $(GENERATED_H)
 	$(QUIET_SP)cgcc -no-compile $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) \
 		-Wsparse-error \
 		$(SPARSE_FLAGS) $(SP_EXTRA_FLAGS) $< && \
@@ -3260,7 +3299,7 @@
 .PHONY: sparse
 sparse: $(SP_OBJ)
 
-EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/%
+EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/% $(UNIT_TEST_DIR)/clar/% $(UNIT_TEST_DIR)/clar/clar/%
 ifndef OPENSSL_SHA1
 	EXCEPT_HDRS += sha1/openssl.h
 endif
@@ -3281,7 +3320,7 @@
 	@echo '#include "git-compat-util.h"' >$@
 	@echo '#include "$<"' >>$@
 
-$(HCO): %.hco: %.hcc FORCE
+$(HCO): %.hco: %.hcc $(GENERATED_H) FORCE
 	$(QUIET_HDR)$(CC) $(ALL_CFLAGS) -o /dev/null -c -xc $<
 
 .PHONY: hdr-check $(HCO)
@@ -3292,7 +3331,7 @@
 	git clang-format --style file --diff --extensions c,h
 
 .PHONY: check
-check: $(GENERATED_H)
+check:
 	@if sparse; \
 	then \
 		echo >&2 "Use 'make sparse' instead"; \
@@ -3644,7 +3683,7 @@
 
 artifacts-tar:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) \
 		GIT-BUILD-OPTIONS $(TEST_PROGRAMS) $(test_bindir_programs) \
-		$(UNIT_TEST_PROGS) $(MOFILES)
+		$(UNIT_TEST_PROGS) $(CLAR_TEST_PROG) $(MOFILES)
 	$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) \
 		SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
 	test -n "$(ARTIFACTS_DIRECTORY)"
@@ -3700,11 +3739,12 @@
 
 clean: profile-clean coverage-clean cocciclean
 	$(RM) -r .build $(UNIT_TEST_BIN)
+	$(RM) GIT-TEST-SUITES
 	$(RM) po/git.pot po/git-core.pot
 	$(RM) git.res
 	$(RM) $(OBJECTS)
 	$(RM) headless-git.o
-	$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB)
+	$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB)
 	$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
 	$(RM) $(TEST_PROGRAMS)
 	$(RM) $(FUZZ_PROGRAMS)
@@ -3851,15 +3891,32 @@
 		-Wl,--allow-multiple-definition \
 		$(filter %.o,$^) $(filter %.a,$^) $(LIBS) $(LIB_FUZZING_ENGINE)
 
-$(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o \
-	$(UNIT_TEST_DIR)/test-lib.o \
-	$(UNIT_TEST_DIR)/lib-oid.o \
+$(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o $(UNIT_TEST_OBJS) \
 	$(GITLIBS) GIT-LDFLAGS
 	$(call mkdir_p_parent_template)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
 		$(filter %.o,$^) $(filter %.a,$^) $(LIBS)
 
+GIT-TEST-SUITES: FORCE
+	@FLAGS='$(CLAR_TEST_SUITES)'; \
+	    if test x"$$FLAGS" != x"`cat GIT-TEST-SUITES 2>/dev/null`" ; then \
+		echo >&2 "    * new test suites"; \
+		echo "$$FLAGS" >GIT-TEST-SUITES; \
+            fi
+
+$(UNIT_TEST_DIR)/clar-decls.h: $(patsubst %,$(UNIT_TEST_DIR)/%.c,$(CLAR_TEST_SUITES)) GIT-TEST-SUITES
+	$(QUIET_GEN)for suite in $(CLAR_TEST_SUITES); do \
+		sed -ne "s/^\(void test_$${suite}__[a-zA-Z_0-9][a-zA-Z_0-9]*(void)$$\)/extern \1;/p" $(UNIT_TEST_DIR)/$$suite.c; \
+	done >$@
+$(UNIT_TEST_DIR)/clar.suite: $(UNIT_TEST_DIR)/clar-decls.h
+	$(QUIET_GEN)awk -f $(UNIT_TEST_DIR)/clar-generate.awk $< >$(UNIT_TEST_DIR)/clar.suite
+$(CLAR_TEST_OBJS): $(UNIT_TEST_DIR)/clar-decls.h
+$(CLAR_TEST_OBJS): EXTRA_CPPFLAGS = -I$(UNIT_TEST_DIR)
+$(CLAR_TEST_PROG): $(UNIT_TEST_DIR)/clar.suite $(CLAR_TEST_OBJS) $(GITLIBS) GIT-LDFLAGS
+	$(call mkdir_p_parent_template)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+
 .PHONY: build-unit-tests unit-tests
-build-unit-tests: $(UNIT_TEST_PROGS)
-unit-tests: $(UNIT_TEST_PROGS) t/helper/test-tool$X
+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
diff --git a/RelNotes b/RelNotes
index 1cdc9ff..768c16d 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.46.4.txt
\ No newline at end of file
+Documentation/RelNotes/2.47.1.txt
\ No newline at end of file
diff --git a/add-patch.c b/add-patch.c
index 46f6bdd..5579033 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -7,9 +7,11 @@
 #include "environment.h"
 #include "gettext.h"
 #include "object-name.h"
+#include "pager.h"
 #include "read-cache-ll.h"
 #include "repository.h"
 #include "strbuf.h"
+#include "sigchain.h"
 #include "run-command.h"
 #include "strvec.h"
 #include "pathspec.h"
@@ -1140,7 +1142,8 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
 				"removed, then the edit is\n"
 				"aborted and the hunk is left unchanged.\n"));
 
-	if (strbuf_edit_interactively(&s->buf, "addp-hunk-edit.diff", NULL) < 0)
+	if (strbuf_edit_interactively(the_repository, &s->buf,
+				      "addp-hunk-edit.diff", NULL) < 0)
 		return -1;
 
 	/* strip out commented lines */
@@ -1398,7 +1401,7 @@ N_("j - leave this hunk undecided, see next undecided hunk\n"
    "/ - search for a hunk matching the given regex\n"
    "s - split the current hunk into smaller hunks\n"
    "e - manually edit the current hunk\n"
-   "p - print the current hunk\n"
+   "p - print the current hunk, 'P' to use the pager\n"
    "? - print help\n");
 
 static int patch_update_file(struct add_p_state *s,
@@ -1409,7 +1412,7 @@ static int patch_update_file(struct add_p_state *s,
 	struct hunk *hunk;
 	char ch;
 	struct child_process cp = CHILD_PROCESS_INIT;
-	int colored = !!s->colored.len, quit = 0;
+	int colored = !!s->colored.len, quit = 0, use_pager = 0;
 	enum prompt_mode_type prompt_mode_type;
 	enum {
 		ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0,
@@ -1459,9 +1462,18 @@ static int patch_update_file(struct add_p_state *s,
 		strbuf_reset(&s->buf);
 		if (file_diff->hunk_nr) {
 			if (rendered_hunk_index != hunk_index) {
+				if (use_pager) {
+					setup_pager();
+					sigchain_push(SIGPIPE, SIG_IGN);
+				}
 				render_hunk(s, hunk, 0, colored, &s->buf);
 				fputs(s->buf.buf, stdout);
 				rendered_hunk_index = hunk_index;
+				if (use_pager) {
+					sigchain_pop(SIGPIPE);
+					wait_for_pager();
+					use_pager = 0;
+				}
 			}
 
 			strbuf_reset(&s->buf);
@@ -1682,8 +1694,9 @@ static int patch_update_file(struct add_p_state *s,
 				hunk->use = USE_HUNK;
 				goto soft_increment;
 			}
-		} else if (s->answer.buf[0] == 'p') {
+		} else if (ch == 'p') {
 			rendered_hunk_index = -1;
+			use_pager = (s->answer.buf[0] == 'P') ? 1 : 0;
 		} else if (s->answer.buf[0] == '?') {
 			const char *p = _(help_patch_remainder), *eol = p;
 
diff --git a/alias.c b/alias.c
index 4daafd9..1a1a141 100644
--- a/alias.c
+++ b/alias.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "alias.h"
 #include "config.h"
@@ -37,7 +39,7 @@ char *alias_lookup(const char *alias)
 {
 	struct config_alias_data data = { alias, NULL };
 
-	read_early_config(config_alias_cb, &data);
+	read_early_config(the_repository, config_alias_cb, &data);
 
 	return data.v;
 }
@@ -46,7 +48,7 @@ void list_aliases(struct string_list *list)
 {
 	struct config_alias_data data = { NULL, NULL, list };
 
-	read_early_config(config_alias_cb, &data);
+	read_early_config(the_repository, config_alias_cb, &data);
 }
 
 void quote_cmdline(struct strbuf *buf, const char **argv)
diff --git a/apply.c b/apply.c
index 6e1060a..a3fc2d5 100644
--- a/apply.c
+++ b/apply.c
@@ -30,6 +30,7 @@
 #include "path.h"
 #include "quote.h"
 #include "read-cache.h"
+#include "repository.h"
 #include "rerere.h"
 #include "apply.h"
 #include "entry.h"
@@ -277,13 +278,26 @@ struct line {
  * This represents a "file", which is an array of "lines".
  */
 struct image {
-	char *buf;
-	size_t len;
-	size_t nr;
-	size_t alloc;
-	struct line *line_allocated;
+	struct strbuf buf;
 	struct line *line;
+	size_t line_nr, line_alloc;
 };
+#define IMAGE_INIT { \
+	.buf = STRBUF_INIT, \
+}
+
+static void image_init(struct image *image)
+{
+	struct image empty = IMAGE_INIT;
+	memcpy(image, &empty, sizeof(*image));
+}
+
+static void image_clear(struct image *image)
+{
+	strbuf_release(&image->buf);
+	free(image->line);
+	image_init(image);
+}
 
 static uint32_t hash_line(const char *cp, size_t len)
 {
@@ -297,49 +311,13 @@ static uint32_t hash_line(const char *cp, size_t len)
 	return h;
 }
 
-/*
- * Compare lines s1 of length n1 and s2 of length n2, ignoring
- * whitespace difference. Returns 1 if they match, 0 otherwise
- */
-static int fuzzy_matchlines(const char *s1, size_t n1,
-			    const char *s2, size_t n2)
+static void image_add_line(struct image *img, const char *bol, size_t len, unsigned flag)
 {
-	const char *end1 = s1 + n1;
-	const char *end2 = s2 + n2;
-
-	/* ignore line endings */
-	while (s1 < end1 && (end1[-1] == '\r' || end1[-1] == '\n'))
-		end1--;
-	while (s2 < end2 && (end2[-1] == '\r' || end2[-1] == '\n'))
-		end2--;
-
-	while (s1 < end1 && s2 < end2) {
-		if (isspace(*s1)) {
-			/*
-			 * Skip whitespace. We check on both buffers
-			 * because we don't want "a b" to match "ab".
-			 */
-			if (!isspace(*s2))
-				return 0;
-			while (s1 < end1 && isspace(*s1))
-				s1++;
-			while (s2 < end2 && isspace(*s2))
-				s2++;
-		} else if (*s1++ != *s2++)
-			return 0;
-	}
-
-	/* If we reached the end on one side only, lines don't match. */
-	return s1 == end1 && s2 == end2;
-}
-
-static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag)
-{
-	ALLOC_GROW(img->line_allocated, img->nr + 1, img->alloc);
-	img->line_allocated[img->nr].len = len;
-	img->line_allocated[img->nr].hash = hash_line(bol, len);
-	img->line_allocated[img->nr].flag = flag;
-	img->nr++;
+	ALLOC_GROW(img->line, img->line_nr + 1, img->line_alloc);
+	img->line[img->line_nr].len = len;
+	img->line[img->line_nr].hash = hash_line(bol, len);
+	img->line[img->line_nr].flag = flag;
+	img->line_nr++;
 }
 
 /*
@@ -347,37 +325,43 @@ static void add_line_info(struct image *img, const char *bol, size_t len, unsign
  * attach it to "image" and add line-based index to it.
  * "image" now owns the "buf".
  */
-static void prepare_image(struct image *image, char *buf, size_t len,
+static void image_prepare(struct image *image, char *buf, size_t len,
 			  int prepare_linetable)
 {
 	const char *cp, *ep;
 
-	memset(image, 0, sizeof(*image));
-	image->buf = buf;
-	image->len = len;
+	image_clear(image);
+	strbuf_attach(&image->buf, buf, len, len + 1);
 
 	if (!prepare_linetable)
 		return;
 
-	ep = image->buf + image->len;
-	cp = image->buf;
+	ep = image->buf.buf + image->buf.len;
+	cp = image->buf.buf;
 	while (cp < ep) {
 		const char *next;
 		for (next = cp; next < ep && *next != '\n'; next++)
 			;
 		if (next < ep)
 			next++;
-		add_line_info(image, cp, next - cp, 0);
+		image_add_line(image, cp, next - cp, 0);
 		cp = next;
 	}
-	image->line = image->line_allocated;
 }
 
-static void clear_image(struct image *image)
+static void image_remove_first_line(struct image *img)
 {
-	free(image->buf);
-	free(image->line_allocated);
-	memset(image, 0, sizeof(*image));
+	strbuf_remove(&img->buf, 0, img->line[0].len);
+	img->line_nr--;
+	if (img->line_nr)
+		MOVE_ARRAY(img->line, img->line + 1, img->line_nr);
+}
+
+static void image_remove_last_line(struct image *img)
+{
+	size_t last_line_len = img->line[img->line_nr - 1].len;
+	strbuf_setlen(&img->buf, img->buf.len - last_line_len);
+	img->line_nr--;
 }
 
 /* fmt must contain _one_ %s and no other substitution */
@@ -2326,65 +2310,43 @@ static int read_old_data(struct stat *st, struct patch *patch,
 
 /*
  * Update the preimage, and the common lines in postimage,
- * from buffer buf of length len. If postlen is 0 the postimage
- * is updated in place, otherwise it's updated on a new buffer
- * of length postlen
+ * from buffer buf of length len.
  */
-
 static void update_pre_post_images(struct image *preimage,
 				   struct image *postimage,
-				   char *buf,
-				   size_t len, size_t postlen)
+				   char *buf, size_t len)
 {
+	struct image fixed_preimage = IMAGE_INIT;
+	size_t insert_pos = 0;
 	int i, ctx, reduced;
-	char *new_buf, *old_buf, *fixed;
-	struct image fixed_preimage;
+	const char *fixed;
 
 	/*
 	 * Update the preimage with whitespace fixes.  Note that we
 	 * are not losing preimage->buf -- apply_one_fragment() will
 	 * free "oldlines".
 	 */
-	prepare_image(&fixed_preimage, buf, len, 1);
-	assert(postlen
-	       ? fixed_preimage.nr == preimage->nr
-	       : fixed_preimage.nr <= preimage->nr);
-	for (i = 0; i < fixed_preimage.nr; i++)
+	image_prepare(&fixed_preimage, buf, len, 1);
+	for (i = 0; i < fixed_preimage.line_nr; i++)
 		fixed_preimage.line[i].flag = preimage->line[i].flag;
-	free(preimage->line_allocated);
+	image_clear(preimage);
 	*preimage = fixed_preimage;
+	fixed = preimage->buf.buf;
 
 	/*
-	 * Adjust the common context lines in postimage. This can be
-	 * done in-place when we are shrinking it with whitespace
-	 * fixing, but needs a new buffer when ignoring whitespace or
-	 * expanding leading tabs to spaces.
-	 *
-	 * We trust the caller to tell us if the update can be done
-	 * in place (postlen==0) or not.
+	 * Adjust the common context lines in postimage.
 	 */
-	old_buf = postimage->buf;
-	if (postlen)
-		new_buf = postimage->buf = xmalloc(postlen);
-	else
-		new_buf = old_buf;
-	fixed = preimage->buf;
-
-	for (i = reduced = ctx = 0; i < postimage->nr; i++) {
+	for (i = reduced = ctx = 0; i < postimage->line_nr; i++) {
 		size_t l_len = postimage->line[i].len;
+
 		if (!(postimage->line[i].flag & LINE_COMMON)) {
 			/* an added line -- no counterparts in preimage */
-			memmove(new_buf, old_buf, l_len);
-			old_buf += l_len;
-			new_buf += l_len;
+			insert_pos += l_len;
 			continue;
 		}
 
-		/* a common context -- skip it in the original postimage */
-		old_buf += l_len;
-
 		/* and find the corresponding one in the fixed preimage */
-		while (ctx < preimage->nr &&
+		while (ctx < preimage->line_nr &&
 		       !(preimage->line[ctx].flag & LINE_COMMON)) {
 			fixed += preimage->line[ctx].len;
 			ctx++;
@@ -2394,29 +2356,59 @@ static void update_pre_post_images(struct image *preimage,
 		 * preimage is expected to run out, if the caller
 		 * fixed addition of trailing blank lines.
 		 */
-		if (preimage->nr <= ctx) {
+		if (preimage->line_nr <= ctx) {
 			reduced++;
 			continue;
 		}
 
 		/* and copy it in, while fixing the line length */
 		l_len = preimage->line[ctx].len;
-		memcpy(new_buf, fixed, l_len);
-		new_buf += l_len;
+		strbuf_splice(&postimage->buf, insert_pos, postimage->line[i].len,
+			      fixed, l_len);
+		insert_pos += l_len;
 		fixed += l_len;
 		postimage->line[i].len = l_len;
 		ctx++;
 	}
 
-	if (postlen
-	    ? postlen < new_buf - postimage->buf
-	    : postimage->len < new_buf - postimage->buf)
-		BUG("caller miscounted postlen: asked %d, orig = %d, used = %d",
-		    (int)postlen, (int) postimage->len, (int)(new_buf - postimage->buf));
-
 	/* Fix the length of the whole thing */
-	postimage->len = new_buf - postimage->buf;
-	postimage->nr -= reduced;
+	postimage->line_nr -= reduced;
+}
+
+/*
+ * Compare lines s1 of length n1 and s2 of length n2, ignoring
+ * whitespace difference. Returns 1 if they match, 0 otherwise
+ */
+static int fuzzy_matchlines(const char *s1, size_t n1,
+			    const char *s2, size_t n2)
+{
+	const char *end1 = s1 + n1;
+	const char *end2 = s2 + n2;
+
+	/* ignore line endings */
+	while (s1 < end1 && (end1[-1] == '\r' || end1[-1] == '\n'))
+		end1--;
+	while (s2 < end2 && (end2[-1] == '\r' || end2[-1] == '\n'))
+		end2--;
+
+	while (s1 < end1 && s2 < end2) {
+		if (isspace(*s1)) {
+			/*
+			 * Skip whitespace. We check on both buffers
+			 * because we don't want "a b" to match "ab".
+			 */
+			if (!isspace(*s2))
+				return 0;
+			while (s1 < end1 && isspace(*s1))
+				s1++;
+			while (s2 < end2 && isspace(*s2))
+				s2++;
+		} else if (*s1++ != *s2++)
+			return 0;
+	}
+
+	/* If we reached the end on one side only, lines don't match. */
+	return s1 == end1 && s2 == end2;
 }
 
 static int line_by_line_fuzzy_match(struct image *img,
@@ -2429,7 +2421,6 @@ static int line_by_line_fuzzy_match(struct image *img,
 	int i;
 	size_t imgoff = 0;
 	size_t preoff = 0;
-	size_t postlen = postimage->len;
 	size_t extra_chars;
 	char *buf;
 	char *preimage_eof;
@@ -2442,11 +2433,9 @@ static int line_by_line_fuzzy_match(struct image *img,
 		size_t prelen = preimage->line[i].len;
 		size_t imglen = img->line[current_lno+i].len;
 
-		if (!fuzzy_matchlines(img->buf + current + imgoff, imglen,
-				      preimage->buf + preoff, prelen))
+		if (!fuzzy_matchlines(img->buf.buf + current + imgoff, imglen,
+				      preimage->buf.buf + preoff, prelen))
 			return 0;
-		if (preimage->line[i].flag & LINE_COMMON)
-			postlen += imglen - prelen;
 		imgoff += imglen;
 		preoff += prelen;
 	}
@@ -2462,10 +2451,10 @@ static int line_by_line_fuzzy_match(struct image *img,
 	 * are whitespace characters. (This can only happen if
 	 * we are removing blank lines at the end of the file.)
 	 */
-	buf = preimage_eof = preimage->buf + preoff;
-	for ( ; i < preimage->nr; i++)
+	buf = preimage_eof = preimage->buf.buf + preoff;
+	for ( ; i < preimage->line_nr; i++)
 		preoff += preimage->line[i].len;
-	preimage_end = preimage->buf + preoff;
+	preimage_end = preimage->buf.buf + preoff;
 	for ( ; buf < preimage_end; buf++)
 		if (!isspace(*buf))
 			return 0;
@@ -2479,11 +2468,11 @@ static int line_by_line_fuzzy_match(struct image *img,
 	 */
 	extra_chars = preimage_end - preimage_eof;
 	strbuf_init(&fixed, imgoff + extra_chars);
-	strbuf_add(&fixed, img->buf + current, imgoff);
+	strbuf_add(&fixed, img->buf.buf + current, imgoff);
 	strbuf_add(&fixed, preimage_eof, extra_chars);
 	fixed_buf = strbuf_detach(&fixed, &fixed_len);
 	update_pre_post_images(preimage, postimage,
-			       fixed_buf, fixed_len, postlen);
+			       fixed_buf, fixed_len);
 	return 1;
 }
 
@@ -2499,16 +2488,17 @@ static int match_fragment(struct apply_state *state,
 	int i;
 	const char *orig, *target;
 	struct strbuf fixed = STRBUF_INIT;
-	size_t postlen;
+	char *fixed_buf;
+	size_t fixed_len;
 	int preimage_limit;
 	int ret;
 
-	if (preimage->nr + current_lno <= img->nr) {
+	if (preimage->line_nr + current_lno <= img->line_nr) {
 		/*
 		 * The hunk falls within the boundaries of img.
 		 */
-		preimage_limit = preimage->nr;
-		if (match_end && (preimage->nr + current_lno != img->nr)) {
+		preimage_limit = preimage->line_nr;
+		if (match_end && (preimage->line_nr + current_lno != img->line_nr)) {
 			ret = 0;
 			goto out;
 		}
@@ -2521,7 +2511,7 @@ static int match_fragment(struct apply_state *state,
 		 * match with img, and the remainder of the preimage
 		 * must be blank.
 		 */
-		preimage_limit = img->nr - current_lno;
+		preimage_limit = img->line_nr - current_lno;
 	} else {
 		/*
 		 * The hunk extends beyond the end of the img and
@@ -2546,7 +2536,7 @@ static int match_fragment(struct apply_state *state,
 		}
 	}
 
-	if (preimage_limit == preimage->nr) {
+	if (preimage_limit == preimage->line_nr) {
 		/*
 		 * Do we have an exact match?  If we were told to match
 		 * at the end, size must be exactly at current+fragsize,
@@ -2555,9 +2545,9 @@ static int match_fragment(struct apply_state *state,
 		 * exactly.
 		 */
 		if ((match_end
-		     ? (current + preimage->len == img->len)
-		     : (current + preimage->len <= img->len)) &&
-		    !memcmp(img->buf + current, preimage->buf, preimage->len)) {
+		     ? (current + preimage->buf.len == img->buf.len)
+		     : (current + preimage->buf.len <= img->buf.len)) &&
+		    !memcmp(img->buf.buf + current, preimage->buf.buf, preimage->buf.len)) {
 			ret = 1;
 			goto out;
 		}
@@ -2571,7 +2561,7 @@ static int match_fragment(struct apply_state *state,
 		 */
 		const char *buf, *buf_end;
 
-		buf = preimage->buf;
+		buf = preimage->buf.buf;
 		buf_end = buf;
 		for (i = 0; i < preimage_limit; i++)
 			buf_end += preimage->line[i].len;
@@ -2616,21 +2606,14 @@ static int match_fragment(struct apply_state *state,
 	 * fixed.
 	 */
 
-	/* First count added lines in postimage */
-	postlen = 0;
-	for (i = 0; i < postimage->nr; i++) {
-		if (!(postimage->line[i].flag & LINE_COMMON))
-			postlen += postimage->line[i].len;
-	}
-
 	/*
 	 * The preimage may extend beyond the end of the file,
 	 * but in this loop we will only handle the part of the
 	 * preimage that falls within the file.
 	 */
-	strbuf_grow(&fixed, preimage->len + 1);
-	orig = preimage->buf;
-	target = img->buf + current;
+	strbuf_grow(&fixed, preimage->buf.len + 1);
+	orig = preimage->buf.buf;
+	target = img->buf.buf + current;
 	for (i = 0; i < preimage_limit; i++) {
 		size_t oldlen = preimage->line[i].len;
 		size_t tgtlen = img->line[current_lno + i].len;
@@ -2659,10 +2642,6 @@ static int match_fragment(struct apply_state *state,
 			 !memcmp(tgtfix.buf, fixed.buf + fixstart,
 					     fixed.len - fixstart));
 
-		/* Add the length if this is common with the postimage */
-		if (preimage->line[i].flag & LINE_COMMON)
-			postlen += tgtfix.len;
-
 		strbuf_release(&tgtfix);
 		if (!match) {
 			ret = 0;
@@ -2680,7 +2659,7 @@ static int match_fragment(struct apply_state *state,
 	 * empty or only contain whitespace (if WS_BLANK_AT_EOL is
 	 * false).
 	 */
-	for ( ; i < preimage->nr; i++) {
+	for ( ; i < preimage->line_nr; i++) {
 		size_t fixstart = fixed.len; /* start of the fixed preimage */
 		size_t oldlen = preimage->line[i].len;
 		int j;
@@ -2704,10 +2683,9 @@ static int match_fragment(struct apply_state *state,
 	 * has whitespace breakages unfixed, and fixing them makes the
 	 * hunk match.  Update the context lines in the postimage.
 	 */
-	if (postlen < postimage->len)
-		postlen = 0;
+	fixed_buf = strbuf_detach(&fixed, &fixed_len);
 	update_pre_post_images(preimage, postimage,
-			       fixed.buf, fixed.len, postlen);
+			       fixed_buf, fixed_len);
 
 	ret = 1;
 
@@ -2735,7 +2713,7 @@ static int find_pos(struct apply_state *state,
 	 * than `match_beginning`.
 	 */
 	if (state->allow_overlap && match_beginning && match_end &&
-	    img->nr - preimage->nr != 0)
+	    img->line_nr - preimage->line_nr != 0)
 		match_beginning = 0;
 
 	/*
@@ -2746,15 +2724,15 @@ static int find_pos(struct apply_state *state,
 	if (match_beginning)
 		line = 0;
 	else if (match_end)
-		line = img->nr - preimage->nr;
+		line = img->line_nr - preimage->line_nr;
 
 	/*
 	 * Because the comparison is unsigned, the following test
 	 * will also take care of a negative line number that can
 	 * result when match_end and preimage is larger than the target.
 	 */
-	if ((size_t) line > img->nr)
-		line = img->nr;
+	if ((size_t) line > img->line_nr)
+		line = img->line_nr;
 
 	current = 0;
 	for (i = 0; i < line; i++)
@@ -2777,7 +2755,7 @@ static int find_pos(struct apply_state *state,
 			return current_lno;
 
 	again:
-		if (backwards_lno == 0 && forwards_lno == img->nr)
+		if (backwards_lno == 0 && forwards_lno == img->line_nr)
 			break;
 
 		if (i & 1) {
@@ -2790,7 +2768,7 @@ static int find_pos(struct apply_state *state,
 			current = backwards;
 			current_lno = backwards_lno;
 		} else {
-			if (forwards_lno == img->nr) {
+			if (forwards_lno == img->line_nr) {
 				i++;
 				goto again;
 			}
@@ -2804,19 +2782,6 @@ static int find_pos(struct apply_state *state,
 	return -1;
 }
 
-static void remove_first_line(struct image *img)
-{
-	img->buf += img->line[0].len;
-	img->len -= img->line[0].len;
-	img->line++;
-	img->nr--;
-}
-
-static void remove_last_line(struct image *img)
-{
-	img->len -= img->line[--img->nr].len;
-}
-
 /*
  * The change from "preimage" and "postimage" has been found to
  * apply at applied_pos (counts in line numbers) in "img".
@@ -2834,6 +2799,7 @@ static void update_image(struct apply_state *state,
 	 */
 	int i, nr;
 	size_t remove_count, insert_count, applied_at = 0;
+	size_t result_alloc;
 	char *result;
 	int preimage_limit;
 
@@ -2846,9 +2812,9 @@ static void update_image(struct apply_state *state,
 	 * to the number of lines in the preimage that falls
 	 * within the boundaries.
 	 */
-	preimage_limit = preimage->nr;
-	if (preimage_limit > img->nr - applied_pos)
-		preimage_limit = img->nr - applied_pos;
+	preimage_limit = preimage->line_nr;
+	if (preimage_limit > img->line_nr - applied_pos)
+		preimage_limit = img->line_nr - applied_pos;
 
 	for (i = 0; i < applied_pos; i++)
 		applied_at += img->line[i].len;
@@ -2856,39 +2822,36 @@ static void update_image(struct apply_state *state,
 	remove_count = 0;
 	for (i = 0; i < preimage_limit; i++)
 		remove_count += img->line[applied_pos + i].len;
-	insert_count = postimage->len;
+	insert_count = postimage->buf.len;
 
 	/* Adjust the contents */
-	result = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1));
-	memcpy(result, img->buf, applied_at);
-	memcpy(result + applied_at, postimage->buf, postimage->len);
-	memcpy(result + applied_at + postimage->len,
-	       img->buf + (applied_at + remove_count),
-	       img->len - (applied_at + remove_count));
-	free(img->buf);
-	img->buf = result;
-	img->len += insert_count - remove_count;
-	result[img->len] = '\0';
+	result_alloc = st_add3(st_sub(img->buf.len, remove_count), insert_count, 1);
+	result = xmalloc(result_alloc);
+	memcpy(result, img->buf.buf, applied_at);
+	memcpy(result + applied_at, postimage->buf.buf, postimage->buf.len);
+	memcpy(result + applied_at + postimage->buf.len,
+	       img->buf.buf + (applied_at + remove_count),
+	       img->buf.len - (applied_at + remove_count));
+	strbuf_attach(&img->buf, result, postimage->buf.len + img->buf.len - remove_count,
+		      result_alloc);
 
 	/* Adjust the line table */
-	nr = img->nr + postimage->nr - preimage_limit;
-	if (preimage_limit < postimage->nr) {
+	nr = img->line_nr + postimage->line_nr - preimage_limit;
+	if (preimage_limit < postimage->line_nr)
 		/*
-		 * NOTE: this knows that we never call remove_first_line()
+		 * NOTE: this knows that we never call image_remove_first_line()
 		 * on anything other than pre/post image.
 		 */
 		REALLOC_ARRAY(img->line, nr);
-		img->line_allocated = img->line;
-	}
-	if (preimage_limit != postimage->nr)
-		MOVE_ARRAY(img->line + applied_pos + postimage->nr,
+	if (preimage_limit != postimage->line_nr)
+		MOVE_ARRAY(img->line + applied_pos + postimage->line_nr,
 			   img->line + applied_pos + preimage_limit,
-			   img->nr - (applied_pos + preimage_limit));
-	COPY_ARRAY(img->line + applied_pos, postimage->line, postimage->nr);
+			   img->line_nr - (applied_pos + preimage_limit));
+	COPY_ARRAY(img->line + applied_pos, postimage->line, postimage->line_nr);
 	if (!state->allow_overlap)
-		for (i = 0; i < postimage->nr; i++)
+		for (i = 0; i < postimage->line_nr; i++)
 			img->line[applied_pos + i].flag |= LINE_PATCHED;
-	img->nr = nr;
+	img->line_nr = nr;
 }
 
 /*
@@ -2911,11 +2874,9 @@ static int apply_one_fragment(struct apply_state *state,
 	int hunk_linenr = frag->linenr;
 	unsigned long leading, trailing;
 	int pos, applied_pos;
-	struct image preimage;
-	struct image postimage;
+	struct image preimage = IMAGE_INIT;
+	struct image postimage = IMAGE_INIT;
 
-	memset(&preimage, 0, sizeof(preimage));
-	memset(&postimage, 0, sizeof(postimage));
 	oldlines = xmalloc(size);
 	strbuf_init(&newlines, size);
 
@@ -2957,8 +2918,8 @@ static int apply_one_fragment(struct apply_state *state,
 				break;
 			*old++ = '\n';
 			strbuf_addch(&newlines, '\n');
-			add_line_info(&preimage, "\n", 1, LINE_COMMON);
-			add_line_info(&postimage, "\n", 1, LINE_COMMON);
+			image_add_line(&preimage, "\n", 1, LINE_COMMON);
+			image_add_line(&postimage, "\n", 1, LINE_COMMON);
 			is_blank_context = 1;
 			break;
 		case ' ':
@@ -2968,7 +2929,7 @@ static int apply_one_fragment(struct apply_state *state,
 			/* fallthrough */
 		case '-':
 			memcpy(old, patch + 1, plen);
-			add_line_info(&preimage, old, plen,
+			image_add_line(&preimage, old, plen,
 				      (first == ' ' ? LINE_COMMON : 0));
 			old += plen;
 			if (first == '-')
@@ -2988,7 +2949,7 @@ static int apply_one_fragment(struct apply_state *state,
 			else {
 				ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &state->applied_after_fixing_ws);
 			}
-			add_line_info(&postimage, newlines.buf + start, newlines.len - start,
+			image_add_line(&postimage, newlines.buf + start, newlines.len - start,
 				      (first == '+' ? 0 : LINE_COMMON));
 			if (first == '+' &&
 			    (ws_rule & WS_BLANK_AT_EOF) &&
@@ -3022,8 +2983,8 @@ static int apply_one_fragment(struct apply_state *state,
 	    newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
 		old--;
 		strbuf_setlen(&newlines, newlines.len - 1);
-		preimage.line_allocated[preimage.nr - 1].len--;
-		postimage.line_allocated[postimage.nr - 1].len--;
+		preimage.line[preimage.line_nr - 1].len--;
+		postimage.line[postimage.line_nr - 1].len--;
 	}
 
 	leading = frag->leading;
@@ -3053,12 +3014,8 @@ static int apply_one_fragment(struct apply_state *state,
 	match_end = !state->unidiff_zero && !trailing;
 
 	pos = frag->newpos ? (frag->newpos - 1) : 0;
-	preimage.buf = oldlines;
-	preimage.len = old - oldlines;
-	postimage.buf = newlines.buf;
-	postimage.len = newlines.len;
-	preimage.line = preimage.line_allocated;
-	postimage.line = postimage.line_allocated;
+	strbuf_add(&preimage.buf, oldlines, old - oldlines);
+	strbuf_swap(&postimage.buf, &newlines);
 
 	for (;;) {
 
@@ -3082,28 +3039,28 @@ static int apply_one_fragment(struct apply_state *state,
 		 * just reduce the larger context.
 		 */
 		if (leading >= trailing) {
-			remove_first_line(&preimage);
-			remove_first_line(&postimage);
+			image_remove_first_line(&preimage);
+			image_remove_first_line(&postimage);
 			pos--;
 			leading--;
 		}
 		if (trailing > leading) {
-			remove_last_line(&preimage);
-			remove_last_line(&postimage);
+			image_remove_last_line(&preimage);
+			image_remove_last_line(&postimage);
 			trailing--;
 		}
 	}
 
 	if (applied_pos >= 0) {
 		if (new_blank_lines_at_end &&
-		    preimage.nr + applied_pos >= img->nr &&
+		    preimage.line_nr + applied_pos >= img->line_nr &&
 		    (ws_rule & WS_BLANK_AT_EOF) &&
 		    state->ws_error_action != nowarn_ws_error) {
 			record_ws_error(state, WS_BLANK_AT_EOF, "+", 1,
 					found_new_blank_lines_at_end);
 			if (state->ws_error_action == correct_ws_error) {
 				while (new_blank_lines_at_end--)
-					remove_last_line(&postimage);
+					image_remove_last_line(&postimage);
 			}
 			/*
 			 * We would want to prevent write_out_results()
@@ -3146,8 +3103,8 @@ static int apply_one_fragment(struct apply_state *state,
 out:
 	free(oldlines);
 	strbuf_release(&newlines);
-	free(preimage.line_allocated);
-	free(postimage.line_allocated);
+	image_clear(&preimage);
+	image_clear(&postimage);
 
 	return (applied_pos < 0);
 }
@@ -3177,18 +3134,16 @@ static int apply_binary_fragment(struct apply_state *state,
 	}
 	switch (fragment->binary_patch_method) {
 	case BINARY_DELTA_DEFLATED:
-		dst = patch_delta(img->buf, img->len, fragment->patch,
+		dst = patch_delta(img->buf.buf, img->buf.len, fragment->patch,
 				  fragment->size, &len);
 		if (!dst)
 			return -1;
-		clear_image(img);
-		img->buf = dst;
-		img->len = len;
+		image_clear(img);
+		strbuf_attach(&img->buf, dst, len, len + 1);
 		return 0;
 	case BINARY_LITERAL_DEFLATED:
-		clear_image(img);
-		img->len = fragment->size;
-		img->buf = xmemdupz(fragment->patch, img->len);
+		image_clear(img);
+		strbuf_add(&img->buf, fragment->patch, fragment->size);
 		return 0;
 	}
 	return -1;
@@ -3224,8 +3179,8 @@ static int apply_binary(struct apply_state *state,
 		 * See if the old one matches what the patch
 		 * applies to.
 		 */
-		hash_object_file(the_hash_algo, img->buf, img->len, OBJ_BLOB,
-				 &oid);
+		hash_object_file(the_hash_algo, img->buf.buf, img->buf.len,
+				 OBJ_BLOB, &oid);
 		if (strcmp(oid_to_hex(&oid), patch->old_oid_prefix))
 			return error(_("the patch applies to '%s' (%s), "
 				       "which does not match the "
@@ -3234,14 +3189,14 @@ static int apply_binary(struct apply_state *state,
 	}
 	else {
 		/* Otherwise, the old one must be empty. */
-		if (img->len)
+		if (img->buf.len)
 			return error(_("the patch applies to an empty "
 				       "'%s' but it is not empty"), name);
 	}
 
 	get_oid_hex(patch->new_oid_prefix, &oid);
 	if (is_null_oid(&oid)) {
-		clear_image(img);
+		image_clear(img);
 		return 0; /* deletion patch */
 	}
 
@@ -3257,9 +3212,8 @@ static int apply_binary(struct apply_state *state,
 			return error(_("the necessary postimage %s for "
 				       "'%s' cannot be read"),
 				     patch->new_oid_prefix, name);
-		clear_image(img);
-		img->buf = result;
-		img->len = size;
+		image_clear(img);
+		strbuf_attach(&img->buf, result, size, size + 1);
 	} else {
 		/*
 		 * We have verified buf matches the preimage;
@@ -3271,7 +3225,7 @@ static int apply_binary(struct apply_state *state,
 				     name);
 
 		/* verify that the result matches */
-		hash_object_file(the_hash_algo, img->buf, img->len, OBJ_BLOB,
+		hash_object_file(the_hash_algo, img->buf.buf, img->buf.len, OBJ_BLOB,
 				 &oid);
 		if (strcmp(oid_to_hex(&oid), patch->new_oid_prefix))
 			return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
@@ -3533,7 +3487,7 @@ static int load_preimage(struct apply_state *state,
 	}
 
 	img = strbuf_detach(&buf, &len);
-	prepare_image(image, img, len, !patch->is_binary);
+	image_prepare(image, img, len, !patch->is_binary);
 	return 0;
 }
 
@@ -3541,14 +3495,14 @@ static int resolve_to(struct image *image, const struct object_id *result_id)
 {
 	unsigned long size;
 	enum object_type type;
+	char *data;
 
-	clear_image(image);
+	image_clear(image);
 
-	image->buf = repo_read_object_file(the_repository, result_id, &type,
-					   &size);
-	if (!image->buf || type != OBJ_BLOB)
+	data = repo_read_object_file(the_repository, result_id, &type, &size);
+	if (!data || type != OBJ_BLOB)
 		die("unable to read blob object %s", oid_to_hex(result_id));
-	image->len = size;
+	strbuf_attach(&image->buf, data, size, size + 1);
 
 	return 0;
 }
@@ -3561,6 +3515,7 @@ static int three_way_merge(struct apply_state *state,
 			   const struct object_id *theirs)
 {
 	mmfile_t base_file, our_file, their_file;
+	struct ll_merge_options merge_opts = LL_MERGE_OPTIONS_INIT;
 	mmbuffer_t result = { NULL };
 	enum ll_merge_result status;
 
@@ -3573,12 +3528,13 @@ static int three_way_merge(struct apply_state *state,
 	read_mmblob(&base_file, base);
 	read_mmblob(&our_file, ours);
 	read_mmblob(&their_file, theirs);
+	merge_opts.variant = state->merge_variant;
 	status = ll_merge(&result, path,
 			  &base_file, "base",
 			  &our_file, "ours",
 			  &their_file, "theirs",
 			  state->repo->index,
-			  NULL);
+			  &merge_opts);
 	if (status == LL_MERGE_BINARY_CONFLICT)
 		warning("Cannot merge binary files: %s (%s vs. %s)",
 			path, "ours", "theirs");
@@ -3589,9 +3545,8 @@ static int three_way_merge(struct apply_state *state,
 		free(result.ptr);
 		return -1;
 	}
-	clear_image(image);
-	image->buf = result.ptr;
-	image->len = result.size;
+	image_clear(image);
+	strbuf_attach(&image->buf, result.ptr, result.size, result.size);
 
 	return status;
 }
@@ -3636,7 +3591,7 @@ static int load_current(struct apply_state *state,
 	else if (status)
 		return -1;
 	img = strbuf_detach(&buf, &len);
-	prepare_image(image, img, len, !patch->is_binary);
+	image_prepare(image, img, len, !patch->is_binary);
 	return 0;
 }
 
@@ -3651,7 +3606,7 @@ static int try_threeway(struct apply_state *state,
 	size_t len;
 	int status;
 	char *img;
-	struct image tmp_image;
+	struct image tmp_image = IMAGE_INIT;
 
 	/* No point falling back to 3-way merge in these cases */
 	if (patch->is_delete ||
@@ -3671,15 +3626,15 @@ static int try_threeway(struct apply_state *state,
 		fprintf(stderr, _("Performing three-way merge...\n"));
 
 	img = strbuf_detach(&buf, &len);
-	prepare_image(&tmp_image, img, len, 1);
+	image_prepare(&tmp_image, img, len, 1);
 	/* Apply the patch to get the post image */
 	if (apply_fragments(state, &tmp_image, patch) < 0) {
-		clear_image(&tmp_image);
+		image_clear(&tmp_image);
 		return -1;
 	}
 	/* post_oid is theirs */
-	write_object_file(tmp_image.buf, tmp_image.len, OBJ_BLOB, &post_oid);
-	clear_image(&tmp_image);
+	write_object_file(tmp_image.buf.buf, tmp_image.buf.len, OBJ_BLOB, &post_oid);
+	image_clear(&tmp_image);
 
 	/* our_oid is ours */
 	if (patch->is_new) {
@@ -3691,8 +3646,8 @@ static int try_threeway(struct apply_state *state,
 			return error(_("cannot read the current contents of '%s'"),
 				     patch->old_name);
 	}
-	write_object_file(tmp_image.buf, tmp_image.len, OBJ_BLOB, &our_oid);
-	clear_image(&tmp_image);
+	write_object_file(tmp_image.buf.buf, tmp_image.buf.len, OBJ_BLOB, &our_oid);
+	image_clear(&tmp_image);
 
 	/* in-core three-way merge between post and our using pre as base */
 	status = three_way_merge(state, image, patch->new_name,
@@ -3728,7 +3683,7 @@ static int try_threeway(struct apply_state *state,
 static int apply_data(struct apply_state *state, struct patch *patch,
 		      struct stat *st, const struct cache_entry *ce)
 {
-	struct image image;
+	struct image image = IMAGE_INIT;
 
 	if (load_preimage(state, &image, patch, st, ce) < 0)
 		return -1;
@@ -3740,14 +3695,13 @@ static int apply_data(struct apply_state *state, struct patch *patch,
 
 		/* Note: with --reject, apply_fragments() returns 0 */
 		if (patch->direct_to_threeway || apply_fragments(state, &image, patch) < 0) {
-			clear_image(&image);
+			image_clear(&image);
 			return -1;
 		}
 	}
-	patch->result = image.buf;
-	patch->resultsize = image.len;
+	patch->result = strbuf_detach(&image.buf, &patch->resultsize);
 	add_to_fn_table(state, patch);
-	free(image.line_allocated);
+	free(image.line);
 
 	if (0 < patch->is_delete && patch->resultsize)
 		return error(_("removal patch leaves file contents"));
@@ -4111,7 +4065,7 @@ static int read_apply_cache(struct apply_state *state)
 {
 	if (state->index_file)
 		return read_index_from(state->repo->index, state->index_file,
-				       get_git_dir());
+				       repo_get_git_dir(the_repository));
 	else
 		return repo_read_index(state->repo);
 }
@@ -5151,6 +5105,15 @@ int apply_parse_options(int argc, const char **argv,
 			N_("also apply the patch (use with --stat/--summary/--check)")),
 		OPT_BOOL('3', "3way", &state->threeway,
 			 N_( "attempt three-way merge, fall back on normal patch if that fails")),
+		OPT_SET_INT_F(0, "ours", &state->merge_variant,
+			N_("for conflicts, use our version"),
+			XDL_MERGE_FAVOR_OURS, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "theirs", &state->merge_variant,
+			N_("for conflicts, use their version"),
+			XDL_MERGE_FAVOR_THEIRS, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "union", &state->merge_variant,
+			N_("for conflicts, use a union version"),
+			XDL_MERGE_FAVOR_UNION, PARSE_OPT_NONEG),
 		OPT_FILENAME(0, "build-fake-ancestor", &state->fake_ancestor,
 			N_("build a temporary index based on embedded index information")),
 		/* Think twice before adding "--nul" synonym to this */
@@ -5190,5 +5153,10 @@ int apply_parse_options(int argc, const char **argv,
 		OPT_END()
 	};
 
-	return parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0);
+	argc = parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0);
+
+	if (state->merge_variant && !state->threeway)
+		die(_("--ours, --theirs, and --union require --3way"));
+
+	return argc;
 }
diff --git a/apply.h b/apply.h
index cd25d24..90e887e 100644
--- a/apply.h
+++ b/apply.h
@@ -59,6 +59,7 @@ struct apply_state {
 	struct repository *repo;
 	const char *index_file;
 	enum apply_verbosity apply_verbosity;
+	int merge_variant;
 	char *fake_ancestor;
 	const char *patch_input_file;
 	int line_termination;
diff --git a/archive.c b/archive.c
index 7bd60d0..a7a92ff 100644
--- a/archive.c
+++ b/archive.c
@@ -304,8 +304,6 @@ int write_archive_entries(struct archiver_args *args,
 		write_archive_entry_fn_t write_entry)
 {
 	struct archiver_context context;
-	struct unpack_trees_options opts;
-	struct tree_desc t;
 	int err;
 	struct strbuf path_in_archive = STRBUF_INIT;
 	struct strbuf content = STRBUF_INIT;
@@ -331,23 +329,6 @@ int write_archive_entries(struct archiver_args *args,
 	context.args = args;
 	context.write_entry = write_entry;
 
-	/*
-	 * Setup index and instruct attr to read index only
-	 */
-	if (!args->worktree_attributes) {
-		memset(&opts, 0, sizeof(opts));
-		opts.index_only = 1;
-		opts.head_idx = -1;
-		opts.src_index = args->repo->index;
-		opts.dst_index = args->repo->index;
-		opts.fn = oneway_merge;
-		init_tree_desc(&t, &args->tree->object.oid,
-			       args->tree->buffer, args->tree->size);
-		if (unpack_trees(1, &t, &opts))
-			return -1;
-		git_attr_set_direction(GIT_ATTR_INDEX);
-	}
-
 	err = read_tree(args->repo, args->tree,
 			&args->pathspec,
 			queue_or_write_archive_entry,
@@ -540,6 +521,27 @@ static void parse_treeish_arg(const char **argv,
 	if (!tree)
 		die(_("not a tree object: %s"), oid_to_hex(&oid));
 
+	/*
+	 * Setup index and instruct attr to read index only
+	 */
+	if (!ar_args->worktree_attributes) {
+		struct unpack_trees_options opts;
+		struct tree_desc t;
+
+		memset(&opts, 0, sizeof(opts));
+		opts.index_only = 1;
+		opts.head_idx = -1;
+		opts.src_index = ar_args->repo->index;
+		opts.dst_index = ar_args->repo->index;
+		opts.fn = oneway_merge;
+		init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
+		if (unpack_trees(1, &t, &opts))
+			die(_("failed to unpack tree object %s"),
+			    oid_to_hex(&tree->object.oid));
+
+		git_attr_set_direction(GIT_ATTR_INDEX);
+	}
+
 	ar_args->refname = ref;
 	ar_args->tree = tree;
 	ar_args->commit_oid = commit_oid;
@@ -736,6 +738,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
 	struct pretty_print_describe_status describe_status = {0};
 	struct pretty_print_context ctx = {0};
 	struct archiver_args args;
+	const char **argv_copy;
 	int rc;
 
 	git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
@@ -749,6 +752,14 @@ int write_archive(int argc, const char **argv, const char *prefix,
 	args.repo = repo;
 	args.prefix = prefix;
 	string_list_init_dup(&args.extra_files);
+
+	/*
+	 * `parse_archive_args()` modifies contents of `argv`, which is what we
+	 * want. Our callers may not want it though, so we create a copy here.
+	 */
+	DUP_ARRAY(argv_copy, argv, argc);
+	argv = argv_copy;
+
 	argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
 	if (!startup_info->have_repository) {
 		/*
@@ -767,6 +778,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
 	string_list_clear_func(&args.extra_files, extra_file_info_clear);
 	free(args.refname);
 	clear_pathspec(&args.pathspec);
+	free(argv_copy);
 
 	return rc;
 }
diff --git a/attr.c b/attr.c
index 06b5b5e..c605d2c 100644
--- a/attr.c
+++ b/attr.c
@@ -187,7 +187,7 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)
 }
 
 /*
- * Atribute name cannot begin with "builtin_" which
+ * Attribute name cannot begin with "builtin_" which
  * is a reserved namespace for built in attributes values.
  */
 static int attr_name_reserved(const char *name)
diff --git a/bisect.c b/bisect.c
index 135f94b..4713226 100644
--- a/bisect.c
+++ b/bisect.c
@@ -448,7 +448,7 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
 	clear_commit_weight(&commit_weight);
 }
 
-static int register_ref(const char *refname, const struct object_id *oid,
+static int register_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			int flags UNUSED, void *cb_data UNUSED)
 {
 	struct strbuf good_prefix = STRBUF_INIT;
@@ -1130,16 +1130,6 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
 	return res;
 }
 
-static inline int log2i(int n)
-{
-	int log2 = 0;
-
-	for (; n > 1; n >>= 1)
-		log2++;
-
-	return log2;
-}
-
 static inline int exp2i(int n)
 {
 	return 1 << n;
@@ -1162,7 +1152,7 @@ int estimate_bisect_steps(int all)
 	if (all < 3)
 		return 0;
 
-	n = log2i(all);
+	n = log2u(all);
 	e = exp2i(n);
 	x = all - e;
 
@@ -1170,6 +1160,7 @@ int estimate_bisect_steps(int all)
 }
 
 static int mark_for_removal(const char *refname,
+			    const char *referent UNUSED,
 			    const struct object_id *oid UNUSED,
 			    int flag UNUSED, void *cb_data)
 {
diff --git a/block-sha1/sha1.h b/block-sha1/sha1.h
index 9fb0441..47bb916 100644
--- a/block-sha1/sha1.h
+++ b/block-sha1/sha1.h
@@ -16,7 +16,9 @@ void blk_SHA1_Init(blk_SHA_CTX *ctx);
 void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, size_t len);
 void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx);
 
+#ifndef platform_SHA_CTX
 #define platform_SHA_CTX	blk_SHA_CTX
 #define platform_SHA1_Init	blk_SHA1_Init
 #define platform_SHA1_Update	blk_SHA1_Update
 #define platform_SHA1_Final	blk_SHA1_Final
+#endif
diff --git a/bloom.h b/bloom.h
index d20e64b..6e46489 100644
--- a/bloom.h
+++ b/bloom.h
@@ -18,7 +18,7 @@ struct bloom_filter_settings {
 
 	/*
 	 * The number of times a path is hashed, i.e. the
-	 * number of bit positions tht cumulatively
+	 * number of bit positions that cumulatively
 	 * determine whether a path is present in the
 	 * Bloom filter.
 	 */
diff --git a/branch.c b/branch.c
index c887ea2..08fa409 100644
--- a/branch.c
+++ b/branch.c
@@ -601,6 +601,7 @@ void create_branch(struct repository *r,
 	int forcing = 0;
 	struct ref_transaction *transaction;
 	struct strbuf err = STRBUF_INIT;
+	int flags = 0;
 	char *msg;
 
 	if (track == BRANCH_TRACK_OVERRIDE)
@@ -619,7 +620,7 @@ void create_branch(struct repository *r,
 		goto cleanup;
 
 	if (reflog)
-		log_all_ref_updates = LOG_REFS_NORMAL;
+		flags |= REF_FORCE_CREATE_REFLOG;
 
 	if (forcing)
 		msg = xstrfmt("branch: Reset to %s", start_name);
@@ -630,7 +631,7 @@ void create_branch(struct repository *r,
 	if (!transaction ||
 		ref_transaction_update(transaction, ref.buf,
 					&oid, forcing ? NULL : null_oid(),
-					NULL, NULL, 0, msg, &err) ||
+					NULL, NULL, flags, msg, &err) ||
 		ref_transaction_commit(transaction, &err))
 		die("%s", err.buf);
 	ref_transaction_free(transaction);
diff --git a/builtin.h b/builtin.h
index 14fa017..f7b166b 100644
--- a/builtin.h
+++ b/builtin.h
@@ -1,15 +1,8 @@
 #ifndef BUILTIN_H
 #define BUILTIN_H
 
-/*
- * TODO: Almost all of our builtins access `the_repository` by necessity
- * because they do not get passed a pointer to it. We should adapt the function
- * signature of those main functions to accept a `struct repository *` and then
- * remove the macro here.
- */
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
+#include "repository.h"
 
 /*
  * builtin API
@@ -122,143 +115,143 @@ int is_builtin(const char *s);
 		BUG("unexpected prefix in builtin: %s", (prefix)); \
 } while (0)
 
-int cmd_add(int argc, const char **argv, const char *prefix);
-int cmd_am(int argc, const char **argv, const char *prefix);
-int cmd_annotate(int argc, const char **argv, const char *prefix);
-int cmd_apply(int argc, const char **argv, const char *prefix);
-int cmd_archive(int argc, const char **argv, const char *prefix);
-int cmd_bisect(int argc, const char **argv, const char *prefix);
-int cmd_blame(int argc, const char **argv, const char *prefix);
-int cmd_branch(int argc, const char **argv, const char *prefix);
-int cmd_bugreport(int argc, const char **argv, const char *prefix);
-int cmd_bundle(int argc, const char **argv, const char *prefix);
-int cmd_cat_file(int argc, const char **argv, const char *prefix);
-int cmd_checkout(int argc, const char **argv, const char *prefix);
-int cmd_checkout__worker(int argc, const char **argv, const char *prefix);
-int cmd_checkout_index(int argc, const char **argv, const char *prefix);
-int cmd_check_attr(int argc, const char **argv, const char *prefix);
-int cmd_check_ignore(int argc, const char **argv, const char *prefix);
-int cmd_check_mailmap(int argc, const char **argv, const char *prefix);
-int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
-int cmd_cherry(int argc, const char **argv, const char *prefix);
-int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
-int cmd_clone(int argc, const char **argv, const char *prefix);
-int cmd_clean(int argc, const char **argv, const char *prefix);
-int cmd_column(int argc, const char **argv, const char *prefix);
-int cmd_commit(int argc, const char **argv, const char *prefix);
-int cmd_commit_graph(int argc, const char **argv, const char *prefix);
-int cmd_commit_tree(int argc, const char **argv, const char *prefix);
-int cmd_config(int argc, const char **argv, const char *prefix);
-int cmd_count_objects(int argc, const char **argv, const char *prefix);
-int cmd_credential(int argc, const char **argv, const char *prefix);
-int cmd_credential_cache(int argc, const char **argv, const char *prefix);
-int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix);
-int cmd_credential_store(int argc, const char **argv, const char *prefix);
-int cmd_describe(int argc, const char **argv, const char *prefix);
-int cmd_diagnose(int argc, const char **argv, const char *prefix);
-int cmd_diff_files(int argc, const char **argv, const char *prefix);
-int cmd_diff_index(int argc, const char **argv, const char *prefix);
-int cmd_diff(int argc, const char **argv, const char *prefix);
-int cmd_diff_tree(int argc, const char **argv, const char *prefix);
-int cmd_difftool(int argc, const char **argv, const char *prefix);
-int cmd_env__helper(int argc, const char **argv, const char *prefix);
-int cmd_fast_export(int argc, const char **argv, const char *prefix);
-int cmd_fast_import(int argc, const char **argv, const char *prefix);
-int cmd_fetch(int argc, const char **argv, const char *prefix);
-int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
-int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
-int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
-int cmd_for_each_repo(int argc, const char **argv, const char *prefix);
-int cmd_format_patch(int argc, const char **argv, const char *prefix);
-int cmd_fsck(int argc, const char **argv, const char *prefix);
-int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix);
-int cmd_gc(int argc, const char **argv, const char *prefix);
-int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
-int cmd_grep(int argc, const char **argv, const char *prefix);
-int cmd_hash_object(int argc, const char **argv, const char *prefix);
-int cmd_help(int argc, const char **argv, const char *prefix);
-int cmd_hook(int argc, const char **argv, const char *prefix);
-int cmd_index_pack(int argc, const char **argv, const char *prefix);
-int cmd_init_db(int argc, const char **argv, const char *prefix);
-int cmd_interpret_trailers(int argc, const char **argv, const char *prefix);
-int cmd_log(int argc, const char **argv, const char *prefix);
-int cmd_log_reflog(int argc, const char **argv, const char *prefix);
-int cmd_ls_files(int argc, const char **argv, const char *prefix);
-int cmd_ls_tree(int argc, const char **argv, const char *prefix);
-int cmd_ls_remote(int argc, const char **argv, const char *prefix);
-int cmd_mailinfo(int argc, const char **argv, const char *prefix);
-int cmd_mailsplit(int argc, const char **argv, const char *prefix);
-int cmd_maintenance(int argc, const char **argv, const char *prefix);
-int cmd_merge(int argc, const char **argv, const char *prefix);
-int cmd_merge_base(int argc, const char **argv, const char *prefix);
-int cmd_merge_index(int argc, const char **argv, const char *prefix);
-int cmd_merge_ours(int argc, const char **argv, const char *prefix);
-int cmd_merge_file(int argc, const char **argv, const char *prefix);
-int cmd_merge_recursive(int argc, const char **argv, const char *prefix);
-int cmd_merge_tree(int argc, const char **argv, const char *prefix);
-int cmd_mktag(int argc, const char **argv, const char *prefix);
-int cmd_mktree(int argc, const char **argv, const char *prefix);
-int cmd_multi_pack_index(int argc, const char **argv, const char *prefix);
-int cmd_mv(int argc, const char **argv, const char *prefix);
-int cmd_name_rev(int argc, const char **argv, const char *prefix);
-int cmd_notes(int argc, const char **argv, const char *prefix);
-int cmd_pack_objects(int argc, const char **argv, const char *prefix);
-int cmd_pack_redundant(int argc, const char **argv, const char *prefix);
-int cmd_patch_id(int argc, const char **argv, const char *prefix);
-int cmd_prune(int argc, const char **argv, const char *prefix);
-int cmd_prune_packed(int argc, const char **argv, const char *prefix);
-int cmd_pull(int argc, const char **argv, const char *prefix);
-int cmd_push(int argc, const char **argv, const char *prefix);
-int cmd_range_diff(int argc, const char **argv, const char *prefix);
-int cmd_read_tree(int argc, const char **argv, const char *prefix);
-int cmd_rebase(int argc, const char **argv, const char *prefix);
-int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);
-int cmd_receive_pack(int argc, const char **argv, const char *prefix);
-int cmd_reflog(int argc, const char **argv, const char *prefix);
-int cmd_refs(int argc, const char **argv, const char *prefix);
-int cmd_remote(int argc, const char **argv, const char *prefix);
-int cmd_remote_ext(int argc, const char **argv, const char *prefix);
-int cmd_remote_fd(int argc, const char **argv, const char *prefix);
-int cmd_repack(int argc, const char **argv, const char *prefix);
-int cmd_replay(int argc, const char **argv, const char *prefix);
-int cmd_rerere(int argc, const char **argv, const char *prefix);
-int cmd_reset(int argc, const char **argv, const char *prefix);
-int cmd_restore(int argc, const char **argv, const char *prefix);
-int cmd_rev_list(int argc, const char **argv, const char *prefix);
-int cmd_rev_parse(int argc, const char **argv, const char *prefix);
-int cmd_revert(int argc, const char **argv, const char *prefix);
-int cmd_rm(int argc, const char **argv, const char *prefix);
-int cmd_send_pack(int argc, const char **argv, const char *prefix);
-int cmd_shortlog(int argc, const char **argv, const char *prefix);
-int cmd_show(int argc, const char **argv, const char *prefix);
-int cmd_show_branch(int argc, const char **argv, const char *prefix);
-int cmd_show_index(int argc, const char **argv, const char *prefix);
-int cmd_sparse_checkout(int argc, const char **argv, const char *prefix);
-int cmd_status(int argc, const char **argv, const char *prefix);
-int cmd_stash(int argc, const char **argv, const char *prefix);
-int cmd_stripspace(int argc, const char **argv, const char *prefix);
-int cmd_submodule__helper(int argc, const char **argv, const char *prefix);
-int cmd_switch(int argc, const char **argv, const char *prefix);
-int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
-int cmd_tag(int argc, const char **argv, const char *prefix);
-int cmd_unpack_file(int argc, const char **argv, const char *prefix);
-int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
-int cmd_update_index(int argc, const char **argv, const char *prefix);
-int cmd_update_ref(int argc, const char **argv, const char *prefix);
-int cmd_update_server_info(int argc, const char **argv, const char *prefix);
-int cmd_upload_archive(int argc, const char **argv, const char *prefix);
-int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix);
-int cmd_upload_pack(int argc, const char **argv, const char *prefix);
-int cmd_var(int argc, const char **argv, const char *prefix);
-int cmd_verify_commit(int argc, const char **argv, const char *prefix);
-int cmd_verify_tag(int argc, const char **argv, const char *prefix);
-int cmd_version(int argc, const char **argv, const char *prefix);
-int cmd_whatchanged(int argc, const char **argv, const char *prefix);
-int cmd_worktree(int argc, const char **argv, const char *prefix);
-int cmd_write_tree(int argc, const char **argv, const char *prefix);
-int cmd_verify_pack(int argc, const char **argv, const char *prefix);
-int cmd_show_ref(int argc, const char **argv, const char *prefix);
-int cmd_pack_refs(int argc, const char **argv, const char *prefix);
-int cmd_replace(int argc, const char **argv, const char *prefix);
+int cmd_add(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_am(int argc, const char **argv, const char *prefix, struct repository *repo);
+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_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);
+int cmd_bugreport(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_bundle(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_cat_file(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_checkout(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_checkout__worker(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_checkout_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_attr(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_ignore(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_mailmap(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_ref_format(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_cherry(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_cherry_pick(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_clone(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_clean(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_column(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_commit(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_commit_graph(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_commit_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_config(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_count_objects(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential_cache(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential_store(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_describe(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diagnose(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff_files(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_difftool(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_env__helper(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fast_export(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fast_import(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fetch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fetch_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_for_each_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_for_each_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_format_patch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fsck(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_gc(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_grep(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_hash_object(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_help(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_hook(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_index_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_init_db(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_interpret_trailers(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_log_reflog(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_log(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_ls_files(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_ls_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_ls_remote(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mailinfo(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mailsplit(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_maintenance(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_base(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_ours(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_file(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_recursive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mktag(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mktree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_multi_pack_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mv(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_name_rev(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_notes(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pack_objects(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pack_redundant(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_patch_id(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_prune(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_prune_packed(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pull(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_push(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_range_diff(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_read_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rebase(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rebase__interactive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_receive_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_reflog(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_refs(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_remote(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rev_list(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rev_parse(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_revert(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rm(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_send_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_shortlog(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show_branch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_sparse_checkout(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_status(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_stash(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_stripspace(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_submodule__helper(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_switch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_symbolic_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_tag(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_unpack_file(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_unpack_objects(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_update_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_update_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_update_server_info(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_upload_archive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_upload_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_var(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_verify_commit(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_verify_tag(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_version(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_whatchanged(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_worktree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_write_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_verify_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pack_refs(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_replace(int argc, const char **argv, const char *prefix, struct repository *repo);
 
 #endif
diff --git a/builtin/add.c b/builtin/add.c
index 40b61ef..773b722 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -3,7 +3,6 @@
  *
  * Copyright (C) 2006 Linus Torvalds
  */
-
 #include "builtin.h"
 #include "advice.h"
 #include "config.h"
@@ -18,7 +17,6 @@
 #include "preload-index.h"
 #include "diff.h"
 #include "read-cache.h"
-#include "repository.h"
 #include "revision.h"
 #include "bulk-checkin.h"
 #include "strvec.h"
@@ -36,24 +34,27 @@ static int pathspec_file_nul;
 static int include_sparse;
 static const char *pathspec_from_file;
 
-static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
+static int chmod_pathspec(struct repository *repo,
+			  struct pathspec *pathspec,
+			  char flip,
+			  int show_only)
 {
 	int i, ret = 0;
 
-	for (i = 0; i < the_repository->index->cache_nr; i++) {
-		struct cache_entry *ce = the_repository->index->cache[i];
+	for (i = 0; i < repo->index->cache_nr; i++) {
+		struct cache_entry *ce = repo->index->cache[i];
 		int err;
 
 		if (!include_sparse &&
 		    (ce_skip_worktree(ce) ||
-		     !path_in_sparse_checkout(ce->name, the_repository->index)))
+		     !path_in_sparse_checkout(ce->name, repo->index)))
 			continue;
 
-		if (pathspec && !ce_path_match(the_repository->index, ce, pathspec, NULL))
+		if (pathspec && !ce_path_match(repo->index, ce, pathspec, NULL))
 			continue;
 
 		if (!show_only)
-			err = chmod_index_entry(the_repository->index, ce, flip);
+			err = chmod_index_entry(repo->index, ce, flip);
 		else
 			err = S_ISREG(ce->ce_mode) ? 0 : -1;
 
@@ -64,31 +65,36 @@ static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
 	return ret;
 }
 
-static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
+static int renormalize_tracked_files(struct repository *repo,
+				     const struct pathspec *pathspec,
+				     int flags)
 {
 	int i, retval = 0;
 
-	for (i = 0; i < the_repository->index->cache_nr; i++) {
-		struct cache_entry *ce = the_repository->index->cache[i];
+	for (i = 0; i < repo->index->cache_nr; i++) {
+		struct cache_entry *ce = repo->index->cache[i];
 
 		if (!include_sparse &&
 		    (ce_skip_worktree(ce) ||
-		     !path_in_sparse_checkout(ce->name, the_repository->index)))
+		     !path_in_sparse_checkout(ce->name, repo->index)))
 			continue;
 		if (ce_stage(ce))
 			continue; /* do not touch unmerged paths */
 		if (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode))
 			continue; /* do not touch non blobs */
-		if (pathspec && !ce_path_match(the_repository->index, ce, pathspec, NULL))
+		if (pathspec && !ce_path_match(repo->index, ce, pathspec, NULL))
 			continue;
-		retval |= add_file_to_index(the_repository->index, ce->name,
+		retval |= add_file_to_index(repo->index, ce->name,
 					    flags | ADD_CACHE_RENORMALIZE);
 	}
 
 	return retval;
 }
 
-static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec, int prefix)
+static char *prune_directory(struct repository *repo,
+			     struct dir_struct *dir,
+			     struct pathspec *pathspec,
+			     int prefix)
 {
 	char *seen;
 	int i;
@@ -100,16 +106,16 @@ static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec,
 	i = dir->nr;
 	while (--i >= 0) {
 		struct dir_entry *entry = *src++;
-		if (dir_path_match(the_repository->index, entry, pathspec, prefix, seen))
+		if (dir_path_match(repo->index, entry, pathspec, prefix, seen))
 			*dst++ = entry;
 	}
 	dir->nr = dst - dir->entries;
-	add_pathspec_matches_against_index(pathspec, the_repository->index, seen,
+	add_pathspec_matches_against_index(pathspec, repo->index, seen,
 					   PS_IGNORE_SKIP_WORKTREE);
 	return seen;
 }
 
-static int refresh(int verbose, const struct pathspec *pathspec)
+static int refresh(struct repository *repo, int verbose, const struct pathspec *pathspec)
 {
 	char *seen;
 	int i, ret = 0;
@@ -119,14 +125,14 @@ static int refresh(int verbose, const struct pathspec *pathspec)
 		    (verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET);
 
 	seen = xcalloc(pathspec->nr, 1);
-	refresh_index(the_repository->index, flags, pathspec, seen,
+	refresh_index(repo->index, flags, pathspec, seen,
 		      _("Unstaged changes after refreshing the index:"));
 	for (i = 0; i < pathspec->nr; i++) {
 		if (!seen[i]) {
 			const char *path = pathspec->items[i].original;
 
 			if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
-			    !path_in_sparse_checkout(path, the_repository->index)) {
+			    !path_in_sparse_checkout(path, repo->index)) {
 				string_list_append(&only_match_skip_worktree,
 						   pathspec->items[i].original);
 			} else {
@@ -147,7 +153,10 @@ static int refresh(int verbose, const struct pathspec *pathspec)
 	return ret;
 }
 
-int interactive_add(const char **argv, const char *prefix, int patch)
+int interactive_add(struct repository *repo,
+		    const char **argv,
+		    const char *prefix,
+		    int patch)
 {
 	struct pathspec pathspec;
 	int ret;
@@ -159,28 +168,31 @@ int interactive_add(const char **argv, const char *prefix, int patch)
 		       prefix, argv);
 
 	if (patch)
-		ret = !!run_add_p(the_repository, ADD_P_ADD, NULL, &pathspec);
+		ret = !!run_add_p(repo, ADD_P_ADD, NULL, &pathspec);
 	else
-		ret = !!run_add_i(the_repository, &pathspec);
+		ret = !!run_add_i(repo, &pathspec);
 
 	clear_pathspec(&pathspec);
 	return ret;
 }
 
-static int edit_patch(int argc, const char **argv, const char *prefix)
+static int edit_patch(struct repository *repo,
+		      int argc,
+		      const char **argv,
+		      const char *prefix)
 {
-	char *file = git_pathdup("ADD_EDIT.patch");
+	char *file = repo_git_path(repo, "ADD_EDIT.patch");
 	struct child_process child = CHILD_PROCESS_INIT;
 	struct rev_info rev;
 	int out;
 	struct stat st;
 
-	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+	repo_config(repo, git_diff_basic_config, NULL);
 
-	if (repo_read_index(the_repository) < 0)
+	if (repo_read_index(repo) < 0)
 		die(_("could not read the index"));
 
-	repo_init_revisions(the_repository, &rev, prefix);
+	repo_init_revisions(repo, &rev, prefix);
 	rev.diffopt.context = 7;
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
@@ -318,7 +330,7 @@ static void check_embedded_repo(const char *path)
 	strbuf_release(&name);
 }
 
-static int add_files(struct dir_struct *dir, int flags)
+static int add_files(struct repository *repo, struct dir_struct *dir, int flags)
 {
 	int i, exit_status = 0;
 	struct string_list matched_sparse_paths = STRING_LIST_INIT_NODUP;
@@ -334,12 +346,12 @@ static int add_files(struct dir_struct *dir, int flags)
 
 	for (i = 0; i < dir->nr; i++) {
 		if (!include_sparse &&
-		    !path_in_sparse_checkout(dir->entries[i]->name, the_repository->index)) {
+		    !path_in_sparse_checkout(dir->entries[i]->name, repo->index)) {
 			string_list_append(&matched_sparse_paths,
 					   dir->entries[i]->name);
 			continue;
 		}
-		if (add_file_to_index(the_repository->index, dir->entries[i]->name, flags)) {
+		if (add_file_to_index(repo->index, dir->entries[i]->name, flags)) {
 			if (!ignore_add_errors)
 				die(_("adding files failed"));
 			exit_status = 1;
@@ -358,7 +370,10 @@ static int add_files(struct dir_struct *dir, int flags)
 	return exit_status;
 }
 
-int cmd_add(int argc, const char **argv, const char *prefix)
+int cmd_add(int argc,
+	    const char **argv,
+	    const char *prefix,
+	    struct repository *repo)
 {
 	int exit_status = 0;
 	struct pathspec pathspec;
@@ -370,7 +385,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 	char *ps_matched = NULL;
 	struct lock_file lock_file = LOCK_INIT;
 
-	git_config(add_config, NULL);
+	repo_config(repo, add_config, NULL);
 
 	argc = parse_options(argc, argv, prefix, builtin_add_options,
 			  builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
@@ -381,13 +396,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 			die(_("options '%s' and '%s' cannot be used together"), "--dry-run", "--interactive/--patch");
 		if (pathspec_from_file)
 			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch");
-		exit(interactive_add(argv + 1, prefix, patch_interactive));
+		exit(interactive_add(repo, argv + 1, prefix, patch_interactive));
 	}
 
 	if (edit_interactive) {
 		if (pathspec_from_file)
 			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--edit");
-		return(edit_patch(argc, argv, prefix));
+		return(edit_patch(repo, argc, argv, prefix));
 	}
 	argc--;
 	argv++;
@@ -410,10 +425,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 	add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
 	require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
 
-	prepare_repo_settings(the_repository);
-	the_repository->settings.command_requires_full_index = 0;
+	prepare_repo_settings(repo);
+	repo->settings.command_requires_full_index = 0;
 
-	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+	repo_hold_locked_index(repo, &lock_file, LOCK_DIE_ON_ERROR);
 
 	/*
 	 * Check the "pathspec '%s' did not match any files" block
@@ -454,11 +469,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 		 (!(addremove || take_worktree_changes)
 		  ? ADD_CACHE_IGNORE_REMOVAL : 0));
 
-	if (repo_read_index_preload(the_repository, &pathspec, 0) < 0)
+	if (repo_read_index_preload(repo, &pathspec, 0) < 0)
 		die(_("index file corrupt"));
 
-	die_in_unpopulated_submodule(the_repository->index, prefix);
-	die_path_inside_submodule(the_repository->index, &pathspec);
+	die_in_unpopulated_submodule(repo->index, prefix);
+	die_path_inside_submodule(repo->index, &pathspec);
 
 	if (add_new_files) {
 		int baselen;
@@ -470,13 +485,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 		}
 
 		/* This picks up the paths that are not tracked */
-		baselen = fill_directory(&dir, the_repository->index, &pathspec);
+		baselen = fill_directory(&dir, repo->index, &pathspec);
 		if (pathspec.nr)
-			seen = prune_directory(&dir, &pathspec, baselen);
+			seen = prune_directory(repo, &dir, &pathspec, baselen);
 	}
 
 	if (refresh_only) {
-		exit_status |= refresh(verbose, &pathspec);
+		exit_status |= refresh(repo, verbose, &pathspec);
 		goto finish;
 	}
 
@@ -487,7 +502,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
 		if (!seen)
 			seen = find_pathspecs_matching_against_index(&pathspec,
-					the_repository->index, PS_IGNORE_SKIP_WORKTREE);
+					repo->index, PS_IGNORE_SKIP_WORKTREE);
 
 		/*
 		 * file_exists() assumes exact match
@@ -523,8 +538,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 			    !file_exists(path)) {
 				if (ignore_missing) {
 					int dtype = DT_UNKNOWN;
-					if (is_excluded(&dir, the_repository->index, path, &dtype))
-						dir_add_ignored(&dir, the_repository->index,
+					if (is_excluded(&dir, repo->index, path, &dtype))
+						dir_add_ignored(&dir, repo->index,
 								path, pathspec.items[i].len);
 				} else
 					die(_("pathspec '%s' did not match any files"),
@@ -547,9 +562,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
 	ps_matched = xcalloc(pathspec.nr, 1);
 	if (add_renormalize)
-		exit_status |= renormalize_tracked_files(&pathspec, flags);
+		exit_status |= renormalize_tracked_files(repo, &pathspec, flags);
 	else
-		exit_status |= add_files_to_cache(the_repository, prefix,
+		exit_status |= add_files_to_cache(repo, prefix,
 						  &pathspec, ps_matched,
 						  include_sparse, flags);
 
@@ -558,14 +573,14 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 		exit(128);
 
 	if (add_new_files)
-		exit_status |= add_files(&dir, flags);
+		exit_status |= add_files(repo, &dir, flags);
 
 	if (chmod_arg && pathspec.nr)
-		exit_status |= chmod_pathspec(&pathspec, chmod_arg[0], show_only);
+		exit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only);
 	end_odb_transaction();
 
 finish:
-	if (write_locked_index(the_repository->index, &lock_file,
+	if (write_locked_index(repo->index, &lock_file,
 			       COMMIT_LOCK | SKIP_IF_UNCHANGED))
 		die(_("unable to write new index file"));
 
diff --git a/builtin/am.c b/builtin/am.c
index 370f559..bfa9514 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -4,6 +4,7 @@
  * Based on git-am.sh by Junio C Hamano.
  */
 
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "advice.h"
@@ -38,7 +39,6 @@
 #include "string-list.h"
 #include "pager.h"
 #include "path.h"
-#include "repository.h"
 #include "pretty.h"
 
 /**
@@ -490,7 +490,8 @@ static int run_applypatch_msg_hook(struct am_state *state)
 	assert(state->msg);
 
 	if (!state->no_verify)
-		ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
+		ret = run_hooks_l(the_repository, "applypatch-msg",
+				  am_path(state, "final-commit"), NULL);
 
 	if (!ret) {
 		FREE_AND_NULL(state->msg);
@@ -512,7 +513,7 @@ static int run_post_rewrite_hook(const struct am_state *state)
 	strvec_push(&opt.args, "rebase");
 	opt.path_to_stdin = am_path(state, "rewritten");
 
-	return run_hooks_opt("post-rewrite", &opt);
+	return run_hooks_opt(the_repository, "post-rewrite", &opt);
 }
 
 /**
@@ -1543,7 +1544,8 @@ static int run_apply(const struct am_state *state, const char *index_file)
 	if (index_file) {
 		/* Reload index as apply_all_patches() will have modified it. */
 		discard_index(the_repository->index);
-		read_index_from(the_repository->index, index_file, get_git_dir());
+		read_index_from(the_repository->index, index_file,
+				repo_get_git_dir(the_repository));
 	}
 
 	return 0;
@@ -1586,7 +1588,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
 		return error("could not build fake ancestor");
 
 	discard_index(the_repository->index);
-	read_index_from(the_repository->index, index_path, get_git_dir());
+	read_index_from(the_repository->index, index_path, repo_get_git_dir(the_repository));
 
 	if (write_index_as_tree(&bases[0], the_repository->index, index_path, 0, NULL))
 		return error(_("Repository lacks necessary blobs to fall back on 3-way merge."));
@@ -1630,7 +1632,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
 	 * changes.
 	 */
 
-	init_merge_options(&o, the_repository);
+	init_ui_merge_options(&o, the_repository);
 
 	o.branch1 = "HEAD";
 	their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
@@ -1663,10 +1665,12 @@ static void do_commit(const struct am_state *state)
 	const char *reflog_msg, *author, *committer = NULL;
 	struct strbuf sb = STRBUF_INIT;
 
-	if (!state->no_verify && run_hooks("pre-applypatch"))
+	if (!state->no_verify && run_hooks(the_repository, "pre-applypatch"))
 		exit(1);
 
-	if (write_index_as_tree(&tree, the_repository->index, get_index_file(), 0, NULL))
+	if (write_index_as_tree(&tree, the_repository->index,
+				repo_get_index_file(the_repository),
+				0, NULL))
 		die(_("git write-tree failed to write a tree"));
 
 	if (!repo_get_oid_commit(the_repository, "HEAD", &parent)) {
@@ -1716,7 +1720,7 @@ static void do_commit(const struct am_state *state)
 		fclose(fp);
 	}
 
-	run_hooks("post-applypatch");
+	run_hooks(the_repository, "post-applypatch");
 
 	free_commit_list(parents);
 	strbuf_release(&sb);
@@ -2076,7 +2080,9 @@ static int clean_index(const struct object_id *head, const struct object_id *rem
 	if (fast_forward_to(head_tree, head_tree, 1))
 		return -1;
 
-	if (write_index_as_tree(&index, the_repository->index, get_index_file(), 0, NULL))
+	if (write_index_as_tree(&index, the_repository->index,
+				repo_get_index_file(the_repository),
+				0, NULL))
 		return -1;
 
 	index_tree = parse_tree_indirect(&index);
@@ -2297,7 +2303,10 @@ static int parse_opt_show_current_patch(const struct option *opt, const char *ar
 	return 0;
 }
 
-int cmd_am(int argc, const char **argv, const char *prefix)
+int cmd_am(int argc,
+	   const char **argv,
+	   const char *prefix,
+	   struct repository *repo UNUSED)
 {
 	struct am_state state;
 	int binary = -1;
diff --git a/builtin/annotate.c b/builtin/annotate.c
index 58ff977..a99179f 100644
--- a/builtin/annotate.c
+++ b/builtin/annotate.c
@@ -3,11 +3,16 @@
  *
  * Copyright (C) 2006 Ryan Anderson
  */
+
+#define USE_THE_REPOSITORY_VARIABLE
 #include "git-compat-util.h"
 #include "builtin.h"
 #include "strvec.h"
 
-int cmd_annotate(int argc, const char **argv, const char *prefix)
+int cmd_annotate(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	struct strvec args = STRVEC_INIT;
 	int i;
@@ -18,5 +23,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix)
 		strvec_push(&args, argv[i]);
 	}
 
-	return cmd_blame(args.nr, args.v, prefix);
+	return cmd_blame(args.nr, args.v, prefix, the_repository);
 }
diff --git a/builtin/apply.c b/builtin/apply.c
index d623c52..84f1863 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1,6 +1,6 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "gettext.h"
-#include "repository.h"
 #include "hash.h"
 #include "apply.h"
 
@@ -9,7 +9,10 @@ static const char * const apply_usage[] = {
 	NULL
 };
 
-int cmd_apply(int argc, const char **argv, const char *prefix)
+int cmd_apply(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
 {
 	int force_apply = 0;
 	int options = 0;
diff --git a/builtin/archive.c b/builtin/archive.c
index b509815..dc926d1 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -2,13 +2,13 @@
  * Copyright (c) 2006 Franck Bui-Huu
  * Copyright (c) 2006 Rene Scharfe
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "archive.h"
 #include "gettext.h"
 #include "transport.h"
 #include "parse-options.h"
 #include "pkt-line.h"
-#include "repository.h"
 
 static void create_output_file(const char *output_file)
 {
@@ -76,7 +76,10 @@ static int run_remote_archiver(int argc, const char **argv,
 			     PARSE_OPT_KEEP_UNKNOWN_OPT |	\
 			     PARSE_OPT_NO_INTERNAL_HELP	)
 
-int cmd_archive(int argc, const char **argv, const char *prefix)
+int cmd_archive(int argc,
+		const char **argv,
+		const char *prefix,
+		struct repository *repo UNUSED)
 {
 	const char *exec = "git-upload-archive";
 	char *output = NULL;
@@ -100,13 +103,16 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
 	if (output)
 		create_output_file(output);
 
-	if (remote)
-		return run_remote_archiver(argc, argv, remote, exec, output);
+	if (remote) {
+		ret = run_remote_archiver(argc, argv, remote, exec, output);
+		goto out;
+	}
 
 	setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
 
 	ret = write_archive(argc, argv, prefix, the_repository, output, 0);
 
+out:
 	free(output);
 	return ret;
 }
diff --git a/builtin/bisect.c b/builtin/bisect.c
index dabce9b..21d17a6 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "copy.h"
 #include "environment.h"
@@ -356,6 +357,7 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
 }
 
 static int inc_nr(const char *refname UNUSED,
+		  const char *referent UNUSED,
 		  const struct object_id *oid UNUSED,
 		  int flag UNUSED, void *cb_data)
 {
@@ -545,7 +547,7 @@ static int bisect_append_log_quoted(const char **argv)
 	return res;
 }
 
-static int add_bisect_ref(const char *refname, const struct object_id *oid,
+static int add_bisect_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			  int flags UNUSED, void *cb)
 {
 	struct add_bisect_ref_data *data = cb;
@@ -582,7 +584,7 @@ static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
 	refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
 				  add_bisect_ref, good, "refs/bisect/", &cb);
 	if (prepare_revision_walk(revs))
-		res = error(_("revision walk setup failed\n"));
+		res = error(_("revision walk setup failed"));
 
 	free(good);
 	free(bad);
@@ -1107,7 +1109,7 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
 			setup_revisions(2, argv + i - 1, &revs, NULL);
 
 			if (prepare_revision_walk(&revs))
-				die(_("revision walk setup failed\n"));
+				die(_("revision walk setup failed"));
 			while ((commit = get_revision(&revs)) != NULL)
 				strvec_push(&argv_state,
 						oid_to_hex(&commit->object.oid));
@@ -1162,6 +1164,7 @@ static int bisect_visualize(struct bisect_terms *terms, int argc,
 }
 
 static int get_first_good(const char *refname UNUSED,
+			  const char *referent UNUSED,
 			  const struct object_id *oid,
 			  int flag UNUSED, void *cb_data)
 {
@@ -1409,7 +1412,10 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
 	return res;
 }
 
-int cmd_bisect(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	int res = 0;
 	parse_opt_subcommand_fn *fn = NULL;
diff --git a/builtin/blame.c b/builtin/blame.c
index 35e975f..e407a22 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -4,7 +4,7 @@
  * Copyright (c) 2006, 2014 by its authors
  * See COPYING for licensing conditions
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "color.h"
@@ -12,7 +12,6 @@
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
-#include "repository.h"
 #include "commit.h"
 #include "diff.h"
 #include "revision.h"
@@ -864,7 +863,10 @@ static void build_ignorelist(struct blame_scoreboard *sb,
 	}
 }
 
-int cmd_blame(int argc, const char **argv, const char *prefix)
+int cmd_blame(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
 {
 	struct rev_info revs;
 	char *path = NULL;
@@ -1081,7 +1083,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 			path = add_prefix(prefix, argv[1]);
 			argv[1] = argv[2];
 		} else {	/* (2a) */
-			if (argc == 2 && is_a_rev(argv[1]) && !get_git_work_tree())
+			if (argc == 2 && is_a_rev(argv[1]) && !repo_get_work_tree(the_repository))
 				die("missing <path> to blame");
 			path = add_prefix(prefix, argv[argc - 1]);
 		}
diff --git a/builtin/branch.c b/builtin/branch.c
index 48cac74..fd1611e 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -4,7 +4,7 @@
  * Copyright (c) 2006 Kristian Høgsberg <krh@redhat.com>
  * Based on git-branch.sh by Junio C Hamano.
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "color.h"
@@ -210,7 +210,7 @@ static void delete_branch_config(const char *branchname)
 {
 	struct strbuf buf = STRBUF_INIT;
 	strbuf_addf(&buf, "branch.%s", branchname);
-	if (git_config_rename_section(buf.buf, NULL) < 0)
+	if (repo_config_rename_section(the_repository, buf.buf, NULL) < 0)
 		warning(_("update of config-file failed"));
 	strbuf_release(&buf);
 }
@@ -659,9 +659,10 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 
 	strbuf_addf(&oldsection, "branch.%s", interpreted_oldname);
 	strbuf_addf(&newsection, "branch.%s", interpreted_newname);
-	if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0)
+	if (!copy && repo_config_rename_section(the_repository, oldsection.buf, newsection.buf) < 0)
 		die(_("branch is renamed, but update of config-file failed"));
-	if (copy && strcmp(interpreted_oldname, interpreted_newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0)
+	if (copy && strcmp(interpreted_oldname, interpreted_newname) &&
+	    repo_config_copy_section(the_repository, oldsection.buf, newsection.buf) < 0)
 		die(_("branch is copied, but update of config-file failed"));
 	strbuf_release(&oldref);
 	strbuf_release(&newref);
@@ -703,7 +704,10 @@ static int edit_branch_description(const char *branch_name)
 	return 0;
 }
 
-int cmd_branch(int argc, const char **argv, const char *prefix)
+int cmd_branch(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	/* possible actions */
 	int delete = 0, rename = 0, copy = 0, list = 0,
@@ -877,6 +881,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		string_list_clear(&output, 0);
 		ref_sorting_release(sorting);
 		ref_filter_clear(&filter);
+		ref_format_clear(&format);
 		return 0;
 	} else if (edit_description) {
 		const char *branch_name;
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index b3cc77a..7c2df03 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "editor.h"
@@ -58,7 +59,7 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
 	for (p = hook_name_list; *p; p++) {
 		const char *hook = *p;
 
-		if (hook_exists(hook))
+		if (hook_exists(the_repository, hook))
 			strbuf_addf(hook_info, "%s\n", hook);
 	}
 }
@@ -98,7 +99,10 @@ static void get_header(struct strbuf *buf, const char *title)
 	strbuf_addf(buf, "\n\n[%s]\n", title);
 }
 
-int cmd_bugreport(int argc, const char **argv, const char *prefix)
+int cmd_bugreport(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
 {
 	struct strbuf buffer = STRBUF_INIT;
 	struct strbuf report_path = STRBUF_INIT;
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 86d0ed7..127518c 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "gettext.h"
@@ -5,7 +6,6 @@
 #include "strvec.h"
 #include "parse-options.h"
 #include "pkt-line.h"
-#include "repository.h"
 #include "bundle.h"
 
 /*
@@ -221,12 +221,17 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
 			 &extra_index_pack_args, 0) ||
 		list_bundle_refs(&header, argc, argv);
 	bundle_header_release(&header);
+
 cleanup:
+	strvec_clear(&extra_index_pack_args);
 	free(bundle_file);
 	return ret;
 }
 
-int cmd_bundle(int argc, const char **argv, const char *prefix)
+int cmd_bundle(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	parse_opt_subcommand_fn *fn = NULL;
 	struct option options[] = {
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 18fe58d..bfdfb51 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "convert.h"
@@ -191,7 +191,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 			const char *ls_args[3] = { NULL };
 			ls_args[0] =  "ls-tree";
 			ls_args[1] =  obj_name;
-			ret = cmd_ls_tree(2, ls_args, NULL);
+			ret = cmd_ls_tree(2, ls_args, NULL, the_repository);
 			goto cleanup;
 		}
 
@@ -923,7 +923,10 @@ static int batch_option_callback(const struct option *opt,
 	return 0;
 }
 
-int cmd_cat_file(int argc, const char **argv, const char *prefix)
+int cmd_cat_file(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	int opt = 0;
 	int opt_cw = 0;
@@ -1047,6 +1050,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
 	if (batch.buffer_output < 0)
 		batch.buffer_output = batch.all_objects;
 
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
 	/* Return early if we're in batch mode? */
 	if (batch.enabled) {
 		if (opt_cw)
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 9376810..7cf275b 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "attr.h"
@@ -5,7 +6,6 @@
 #include "gettext.h"
 #include "object-name.h"
 #include "quote.h"
-#include "repository.h"
 #include "setup.h"
 #include "parse-options.h"
 #include "write-or-die.h"
@@ -107,7 +107,10 @@ static NORETURN void error_with_usage(const char *msg)
 	usage_with_options(check_attr_usage, check_attr_options);
 }
 
-int cmd_check_attr(int argc, const char **argv, const char *prefix)
+int cmd_check_attr(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	struct attr_check *check;
 	struct object_id initialized_oid;
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 2bda6a1..7b7831d 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "dir.h"
@@ -5,7 +6,6 @@
 #include "quote.h"
 #include "pathspec.h"
 #include "parse-options.h"
-#include "repository.h"
 #include "submodule.h"
 #include "write-or-die.h"
 
@@ -151,7 +151,10 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)
 	return num_ignored;
 }
 
-int cmd_check_ignore(int argc, const char **argv, const char *prefix)
+int cmd_check_ignore(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
 {
 	int num_ignored;
 	struct dir_struct dir = DIR_INIT;
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
index b8a05b8..df00b5e 100644
--- a/builtin/check-mailmap.c
+++ b/builtin/check-mailmap.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -9,6 +10,7 @@
 #include "write-or-die.h"
 
 static int use_stdin;
+static const char *mailmap_file, *mailmap_blob;
 static const char * const check_mailmap_usage[] = {
 N_("git check-mailmap [<options>] <contact>..."),
 NULL
@@ -16,6 +18,8 @@ NULL
 
 static const struct option check_mailmap_options[] = {
 	OPT_BOOL(0, "stdin", &use_stdin, N_("also read contacts from stdin")),
+	OPT_FILENAME(0, "mailmap-file", &mailmap_file, N_("read additional mailmap entries from file")),
+	OPT_STRING(0, "mailmap-blob", &mailmap_blob, N_("blob"), N_("read additional mailmap entries from blob")),
 	OPT_END()
 };
 
@@ -25,13 +29,17 @@ static void check_mailmap(struct string_list *mailmap, const char *contact)
 	size_t namelen, maillen;
 	struct ident_split ident;
 
-	if (split_ident_line(&ident, contact, strlen(contact)))
-		die(_("unable to parse contact: %s"), contact);
-
-	name = ident.name_begin;
-	namelen = ident.name_end - ident.name_begin;
-	mail = ident.mail_begin;
-	maillen = ident.mail_end - ident.mail_begin;
+	if (!split_ident_line(&ident, contact, strlen(contact))) {
+		name = ident.name_begin;
+		namelen = ident.name_end - ident.name_begin;
+		mail = ident.mail_begin;
+		maillen = ident.mail_end - ident.mail_begin;
+	} else {
+		name = NULL;
+		namelen = 0;
+		mail = contact;
+		maillen = strlen(contact);
+	}
 
 	map_user(mailmap, &mail, &maillen, &name, &namelen);
 
@@ -40,7 +48,10 @@ static void check_mailmap(struct string_list *mailmap, const char *contact)
 	printf("<%.*s>\n", (int)maillen, mail);
 }
 
-int cmd_check_mailmap(int argc, const char **argv, const char *prefix)
+int cmd_check_mailmap(int argc,
+		      const char **argv,
+		      const char *prefix,
+		      struct repository *repo UNUSED)
 {
 	int i;
 	struct string_list mailmap = STRING_LIST_INIT_NODUP;
@@ -52,6 +63,10 @@ int cmd_check_mailmap(int argc, const char **argv, const char *prefix)
 		die(_("no contacts specified"));
 
 	read_mailmap(&mailmap);
+	if (mailmap_blob)
+		read_mailmap_blob(&mailmap, mailmap_blob);
+	if (mailmap_file)
+		read_mailmap_file(&mailmap, mailmap_file, 0);
 
 	for (i = 0; i < argc; ++i)
 		check_mailmap(&mailmap, argv[i]);
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index 5eb6bdc..e86d8ef 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -1,7 +1,6 @@
 /*
  * GIT - The information manager from hell
  */
-
 #include "builtin.h"
 #include "refs.h"
 #include "setup.h"
@@ -51,7 +50,10 @@ static int check_ref_format_branch(const char *arg)
 	return 0;
 }
 
-int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
+int cmd_check_ref_format(int argc,
+			 const char **argv,
+			 const char *prefix,
+			 struct repository *repo UNUSED)
 {
 	int i;
 	int normalize = 0;
diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c
index 6b62b53..ff6cdcc 100644
--- a/builtin/checkout--worker.c
+++ b/builtin/checkout--worker.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "entry.h"
@@ -113,7 +114,10 @@ static const char * const checkout_worker_usage[] = {
 	NULL
 };
 
-int cmd_checkout__worker(int argc, const char **argv, const char *prefix)
+int cmd_checkout__worker(int argc,
+			 const char **argv,
+			 const char *prefix,
+			 struct repository *repo UNUSED)
 {
 	struct checkout state = CHECKOUT_INIT;
 	struct option checkout_worker_options[] = {
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 29e744d..6dd38eb 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -4,13 +4,12 @@
  * Copyright (C) 2005 Linus Torvalds
  *
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
 #include "lockfile.h"
 #include "quote.h"
-#include "repository.h"
 #include "cache-tree.h"
 #include "parse-options.h"
 #include "entry.h"
@@ -208,7 +207,10 @@ static int option_parse_stage(const struct option *opt,
 	return 0;
 }
 
-int cmd_checkout_index(int argc, const char **argv, const char *prefix)
+int cmd_checkout_index(int argc,
+		       const char **argv,
+		       const char *prefix,
+		       struct repository *repo UNUSED)
 {
 	int i;
 	struct lock_file lock_file = LOCK_INIT;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 1748d68..c449558 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "advice.h"
 #include "branch.h"
@@ -23,6 +24,7 @@
 #include "read-cache.h"
 #include "refs.h"
 #include "remote.h"
+#include "repo-settings.h"
 #include "resolve-undo.h"
 #include "revision.h"
 #include "setup.h"
@@ -125,7 +127,7 @@ static void branch_info_release(struct branch_info *info)
 static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
 			      int changed)
 {
-	return run_hooks_l("post-checkout",
+	return run_hooks_l(the_repository, "post-checkout",
 			   oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
 			   oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
 			   changed ? "1" : "0", NULL);
@@ -884,7 +886,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
 
 			add_files_to_cache(the_repository, NULL, NULL, NULL, 0,
 					   0);
-			init_merge_options(&o, the_repository);
+			init_ui_merge_options(&o, the_repository);
 			o.verbosity = 0;
 			work = write_in_core_index_as_tree(the_repository);
 
@@ -950,11 +952,13 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
 	const char *old_desc, *reflog_msg;
 	if (opts->new_branch) {
 		if (opts->new_orphan_branch) {
+			enum log_refs_config log_all_ref_updates =
+				repo_settings_get_log_all_ref_updates(the_repository);
 			char *refname;
 
 			refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch);
 			if (opts->new_branch_log &&
-			    !should_autocreate_reflog(refname)) {
+			    !should_autocreate_reflog(log_all_ref_updates, refname)) {
 				int ret;
 				struct strbuf err = STRBUF_INIT;
 
@@ -1045,7 +1049,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
 		report_tracking(new_branch_info);
 }
 
-static int add_pending_uninteresting_ref(const char *refname,
+static int add_pending_uninteresting_ref(const char *refname, const char *referent UNUSED,
 					 const struct object_id *oid,
 					 int flags UNUSED, void *cb_data)
 {
@@ -1712,7 +1716,7 @@ static struct option *add_common_switch_branch_options(
 			   N_("update ignored files (default)"),
 			   PARSE_OPT_NOCOMPLETE),
 		OPT_BOOL(0, "ignore-other-worktrees", &opts->ignore_other_worktrees,
-			 N_("do not check if another worktree is holding the given ref")),
+			 N_("do not check if another worktree is using this branch")),
 		OPT_END()
 	};
 	struct option *newopts = parse_options_concat(prevopts, options);
@@ -1953,7 +1957,10 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
 	return ret;
 }
 
-int cmd_checkout(int argc, const char **argv, const char *prefix)
+int cmd_checkout(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	struct checkout_opts opts = CHECKOUT_OPTS_INIT;
 	struct option *options;
@@ -2000,7 +2007,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 			     checkout_usage);
 }
 
-int cmd_switch(int argc, const char **argv, const char *prefix)
+int cmd_switch(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	struct checkout_opts opts = CHECKOUT_OPTS_INIT;
 	struct option *options = NULL;
@@ -2036,7 +2046,10 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
 			     switch_branch_usage);
 }
 
-int cmd_restore(int argc, const char **argv, const char *prefix)
+int cmd_restore(int argc,
+		const char **argv,
+		const char *prefix,
+		struct repository *repo UNUSED)
 {
 	struct checkout_opts opts = CHECKOUT_OPTS_INIT;
 	struct option *options;
diff --git a/builtin/clean.c b/builtin/clean.c
index ded5a91..9c48dd0 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -5,7 +5,7 @@
  *
  * Based on git-clean.sh by Pavel Roskin
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "config.h"
@@ -14,7 +14,6 @@
 #include "parse-options.h"
 #include "path.h"
 #include "read-cache-ll.h"
-#include "repository.h"
 #include "setup.h"
 #include "string-list.h"
 #include "quote.h"
@@ -915,7 +914,10 @@ static void correct_untracked_entries(struct dir_struct *dir)
 	dir->nr = dst;
 }
 
-int cmd_clean(int argc, const char **argv, const char *prefix)
+int cmd_clean(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
 {
 	int i, res;
 	int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
diff --git a/builtin/clone.c b/builtin/clone.c
index af6017d..e77339c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -7,8 +7,9 @@
  *
  * Clone a repository into a different directory that does not yet exist.
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
+
 #include "abspath.h"
 #include "advice.h"
 #include "config.h"
@@ -729,7 +730,8 @@ static int git_sparse_checkout_init(const char *repo)
 	return result;
 }
 
-static int checkout(int submodule_progress, int filter_submodules)
+static int checkout(int submodule_progress, int filter_submodules,
+		    enum ref_storage_format ref_storage_format)
 {
 	struct object_id oid;
 	char *head;
@@ -788,7 +790,7 @@ static int checkout(int submodule_progress, int filter_submodules)
 	if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
 		die(_("unable to write new index file"));
 
-	err |= run_hooks_l("post-checkout", oid_to_hex(null_oid()),
+	err |= run_hooks_l(the_repository, "post-checkout", oid_to_hex(null_oid()),
 			   oid_to_hex(&oid), "1", NULL);
 
 	if (!err && (option_recurse_submodules.nr > 0)) {
@@ -813,6 +815,10 @@ static int checkout(int submodule_progress, int filter_submodules)
 			strvec_push(&cmd.args, "--no-fetch");
 		}
 
+		if (ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+			strvec_pushf(&cmd.args, "--ref-format=%s",
+				     ref_storage_format_to_name(ref_storage_format));
+
 		if (filter_submodules && filter_options.choice)
 			strvec_pushf(&cmd.args, "--filter=%s",
 				     expand_list_objects_filter_spec(&filter_options));
@@ -951,7 +957,10 @@ static int path_exists(const char *path)
 	return !stat(path, &sb);
 }
 
-int cmd_clone(int argc, const char **argv, const char *prefix)
+int cmd_clone(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repository UNUSED)
 {
 	int is_bundle = 0, is_local;
 	int reject_shallow = 0;
@@ -1536,7 +1545,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 		return 1;
 
 	junk_mode = JUNK_LEAVE_REPO;
-	err = checkout(submodule_progress, filter_submodules);
+	err = checkout(submodule_progress, filter_submodules,
+		       ref_storage_format);
 
 	free(remote_name);
 	strbuf_release(&reflog_msg);
diff --git a/builtin/column.c b/builtin/column.c
index 10ff7e0..50314cc 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -18,7 +19,10 @@ static int column_config(const char *var, const char *value,
 	return git_column_config(var, value, cb, &colopts);
 }
 
-int cmd_column(int argc, const char **argv, const char *prefix)
+int cmd_column(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	struct string_list list = STRING_LIST_INIT_DUP;
 	struct strbuf sb = STRBUF_INIT;
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 7102ee9..7c991db 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -1,11 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "commit.h"
 #include "config.h"
-#include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "parse-options.h"
-#include "repository.h"
 #include "commit-graph.h"
 #include "object-store-ll.h"
 #include "progress.h"
@@ -95,7 +94,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
 		usage_with_options(builtin_commit_graph_verify_usage, options);
 
 	if (!opts.obj_dir)
-		opts.obj_dir = get_object_directory();
+		opts.obj_dir = repo_get_object_directory(the_repository);
 	if (opts.shallow)
 		flags |= COMMIT_GRAPH_VERIFY_SHALLOW;
 	if (opts.progress)
@@ -275,7 +274,7 @@ static int graph_write(int argc, const char **argv, const char *prefix)
 	if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
 		die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
 	if (!opts.obj_dir)
-		opts.obj_dir = get_object_directory();
+		opts.obj_dir = repo_get_object_directory(the_repository);
 	if (opts.append)
 		flags |= COMMIT_GRAPH_WRITE_APPEND;
 	if (opts.split)
@@ -331,7 +330,10 @@ static int graph_write(int argc, const char **argv, const char *prefix)
 	return result;
 }
 
-int cmd_commit_graph(int argc, const char **argv, const char *prefix)
+int cmd_commit_graph(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
 {
 	parse_opt_subcommand_fn *fn = NULL;
 	struct option builtin_commit_graph_options[] = {
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 84bb450..2ca1a57 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -3,13 +3,14 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
 #include "hex.h"
 #include "object-name.h"
 #include "object-store-ll.h"
-#include "repository.h"
+
 #include "commit.h"
 #include "parse-options.h"
 
@@ -90,7 +91,10 @@ static int parse_file_arg_callback(const struct option *opt,
 	return 0;
 }
 
-int cmd_commit_tree(int argc, const char **argv, const char *prefix)
+int cmd_commit_tree(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
 {
 	static struct strbuf buffer = STRBUF_INIT;
 	struct commit_list *parents = NULL;
diff --git a/builtin/commit.c b/builtin/commit.c
index 66427ba..8db4e9d 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -4,7 +4,7 @@
  * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
  * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "advice.h"
 #include "config.h"
@@ -26,6 +26,7 @@
 #include "path.h"
 #include "preload-index.h"
 #include "read-cache.h"
+#include "repository.h"
 #include "string-list.h"
 #include "rerere.h"
 #include "unpack-trees.h"
@@ -395,7 +396,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
 		old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
 		setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
 
-		if (interactive_add(argv, prefix, patch_interactive) != 0)
+		if (interactive_add(the_repository, argv, prefix, patch_interactive) != 0)
 			die(_("interactive add failed"));
 
 		the_repository->index_file = old_repo_index_file;
@@ -407,7 +408,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
 
 		discard_index(the_repository->index);
 		read_index_from(the_repository->index, get_lock_file_path(&index_lock),
-				get_git_dir());
+				repo_get_git_dir(the_repository));
 		if (cache_tree_update(the_repository->index, WRITE_TREE_SILENT) == 0) {
 			if (reopen_lock_file(&index_lock) < 0)
 				die(_("unable to write index file"));
@@ -472,7 +473,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
 				       COMMIT_LOCK | SKIP_IF_UNCHANGED))
 			die(_("unable to write new index file"));
 		commit_style = COMMIT_AS_IS;
-		ret = get_index_file();
+		ret = repo_get_index_file(the_repository);
 		goto out;
 	}
 
@@ -534,7 +535,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
 
 	discard_index(the_repository->index);
 	ret = get_lock_file_path(&false_lock);
-	read_index_from(the_repository->index, ret, get_git_dir());
+	read_index_from(the_repository->index, ret, repo_get_git_dir(the_repository));
 out:
 	string_list_clear(&partial, 0);
 	clear_pathspec(&pathspec);
@@ -684,7 +685,9 @@ static void adjust_comment_line_char(const struct strbuf *sb)
 	const char *p;
 
 	if (!memchr(sb->buf, candidates[0], sb->len)) {
-		comment_line_str = xstrfmt("%c", candidates[0]);
+		free(comment_line_str_to_free);
+		comment_line_str = comment_line_str_to_free =
+			xstrfmt("%c", candidates[0]);
 		return;
 	}
 
@@ -705,7 +708,8 @@ static void adjust_comment_line_char(const struct strbuf *sb)
 	if (!*p)
 		die(_("unable to select a comment character that is not used\n"
 		      "in the current commit message"));
-	comment_line_str = xstrfmt("%c", *p);
+	free(comment_line_str_to_free);
+	comment_line_str = comment_line_str_to_free = xstrfmt("%c", *p);
 }
 
 static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
@@ -1069,7 +1073,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 		 */
 		discard_index(the_repository->index);
 	}
-	read_index_from(the_repository->index, index_file, get_git_dir());
+	read_index_from(the_repository->index, index_file, repo_get_git_dir(the_repository));
 
 	if (cache_tree_update(the_repository->index, 0)) {
 		error(_("Error building trees"));
@@ -1499,7 +1503,10 @@ static int git_status_config(const char *k, const char *v,
 	return git_diff_ui_config(k, v, ctx, NULL);
 }
 
-int cmd_status(int argc, const char **argv, const char *prefix)
+int cmd_status(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
 {
 	static int no_renames = -1;
 	static const char *rename_score_arg = (const char *)-1;
@@ -1638,7 +1645,10 @@ static int git_commit_config(const char *k, const char *v,
 	return git_status_config(k, v, ctx, s);
 }
 
-int cmd_commit(int argc, const char **argv, const char *prefix)
+int cmd_commit(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	static struct wt_status s;
 	static struct option builtin_commit_options[] = {
@@ -1870,8 +1880,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
 	repo_rerere(the_repository, 0);
 	run_auto_maintenance(quiet);
-	run_commit_hook(use_editor, get_index_file(), NULL, "post-commit",
-			NULL);
+	run_commit_hook(use_editor, repo_get_index_file(the_repository),
+			NULL, "post-commit", NULL);
 	if (amend && !no_post_rewrite) {
 		commit_post_rewrite(the_repository, current_head, &oid);
 	}
diff --git a/builtin/config.c b/builtin/config.c
index 97e4d5f..cba7022 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -1,10 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "config.h"
 #include "color.h"
 #include "editor.h"
 #include "environment.h"
-#include "repository.h"
 #include "gettext.h"
 #include "ident.h"
 #include "parse-options.h"
@@ -19,7 +19,7 @@ static const char *const builtin_config_usage[] = {
 	N_("git config list [<file-option>] [<display-option>] [--includes]"),
 	N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
 	N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
-	N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+	N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"),
 	N_("git config rename-section [<file-option>] <old-name> <new-name>"),
 	N_("git config remove-section [<file-option>] <name>"),
 	N_("git config edit [<file-option>]"),
@@ -43,7 +43,7 @@ static const char *const builtin_config_set_usage[] = {
 };
 
 static const char *const builtin_config_unset_usage[] = {
-	N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+	N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"),
 	NULL
 };
 
@@ -807,8 +807,8 @@ static void location_options_init(struct config_location_options *opts,
 	else
 		opts->options.respect_includes = opts->respect_includes_opt;
 	if (startup_info->have_repository) {
-		opts->options.commondir = get_git_common_dir();
-		opts->options.git_dir = get_git_dir();
+		opts->options.commondir = repo_get_common_dir(the_repository);
+		opts->options.git_dir = repo_get_git_dir(the_repository);
 	}
 }
 
@@ -1026,8 +1026,8 @@ static int cmd_config_rename_section(int argc, const char **argv, const char *pr
 	location_options_init(&location_opts, prefix);
 	check_write(&location_opts.source);
 
-	ret = git_config_rename_section_in_file(location_opts.source.file,
-						argv[0], argv[1]);
+	ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+						 argv[0], argv[1]);
 	if (ret < 0)
 		goto out;
 	else if (!ret)
@@ -1055,8 +1055,8 @@ static int cmd_config_remove_section(int argc, const char **argv, const char *pr
 	location_options_init(&location_opts, prefix);
 	check_write(&location_opts.source);
 
-	ret = git_config_rename_section_in_file(location_opts.source.file,
-						argv[0], NULL);
+	ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+						 argv[0], NULL);
 	if (ret < 0)
 		goto out;
 	else if (!ret)
@@ -1353,8 +1353,8 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
 	else if (actions == ACTION_RENAME_SECTION) {
 		check_write(&location_opts.source);
 		check_argc(argc, 2, 2);
-		ret = git_config_rename_section_in_file(location_opts.source.file,
-							argv[0], argv[1]);
+		ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+							 argv[0], argv[1]);
 		if (ret < 0)
 			goto out;
 		else if (!ret)
@@ -1365,8 +1365,8 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
 	else if (actions == ACTION_REMOVE_SECTION) {
 		check_write(&location_opts.source);
 		check_argc(argc, 1, 1);
-		ret = git_config_rename_section_in_file(location_opts.source.file,
-							argv[0], NULL);
+		ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+							 argv[0], NULL);
 		if (ret < 0)
 			goto out;
 		else if (!ret)
@@ -1392,7 +1392,10 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
 	return ret;
 }
 
-int cmd_config(int argc, const char **argv, const char *prefix)
+int cmd_config(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	parse_opt_subcommand_fn *subcommand = NULL;
 	struct option subcommand_opts[] = {
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index 2d4bb5e..04d8088 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -3,14 +3,12 @@
  *
  * Copyright (c) 2006 Junio C Hamano
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "dir.h"
-#include "environment.h"
 #include "gettext.h"
 #include "path.h"
-#include "repository.h"
 #include "parse-options.h"
 #include "quote.h"
 #include "packfile.h"
@@ -95,7 +93,10 @@ static char const * const count_objects_usage[] = {
 	NULL
 };
 
-int cmd_count_objects(int argc, const char **argv, const char *prefix)
+int cmd_count_objects(int argc,
+		      const char **argv,
+		      const char *prefix,
+		      struct repository *repo UNUSED)
 {
 	int human_readable = 0;
 	struct option opts[] = {
@@ -113,10 +114,10 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
 		usage_with_options(count_objects_usage, opts);
 	if (verbose) {
 		report_garbage = real_report_garbage;
-		report_linked_checkout_garbage();
+		report_linked_checkout_garbage(the_repository);
 	}
 
-	for_each_loose_file_in_objdir(get_object_directory(),
+	for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
 				      count_loose, count_cruft, NULL, NULL);
 
 	if (verbose) {
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 4952b22..bc22f5c 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "gettext.h"
@@ -287,7 +288,10 @@ static void init_socket_directory(const char *path)
 	free(path_copy);
 }
 
-int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
+int cmd_credential_cache_daemon(int argc,
+				const char **argv,
+				const char *prefix,
+				struct repository *repo UNUSED)
 {
 	struct tempfile *socket_file;
 	const char *socket_path;
@@ -330,7 +334,10 @@ int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
 
 #else
 
-int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
+int cmd_credential_cache_daemon(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
 {
 	const char * const usage[] = {
 		"git credential-cache--daemon [--debug] <socket-path>",
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
index 3db8df7..5de8b91 100644
--- a/builtin/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -88,6 +88,8 @@ static void spawn_daemon(const char *socket)
 		die_errno("unable to read result code from cache daemon");
 	if (r != 3 || memcmp(buf, "ok\n", 3))
 		die("cache daemon did not start: %.*s", r, buf);
+
+	child_process_clear(&daemon);
 	close(daemon.out);
 }
 
@@ -135,9 +137,13 @@ static void announce_capabilities(void)
 	credential_announce_capabilities(&c, stdout);
 }
 
-int cmd_credential_cache(int argc, const char **argv, const char *prefix)
+int cmd_credential_cache(int argc,
+			 const char **argv,
+			 const char *prefix,
+			 struct repository *repo UNUSED)
 {
-	char *socket_path = NULL;
+	const char *socket_path_arg = NULL;
+	char *socket_path;
 	int timeout = 900;
 	const char *op;
 	const char * const usage[] = {
@@ -147,7 +153,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix)
 	struct option options[] = {
 		OPT_INTEGER(0, "timeout", &timeout,
 			    "number of seconds to cache credentials"),
-		OPT_STRING(0, "socket", &socket_path, "path",
+		OPT_STRING(0, "socket", &socket_path_arg, "path",
 			   "path of cache-daemon socket"),
 		OPT_END()
 	};
@@ -160,6 +166,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix)
 	if (!have_unix_sockets())
 		die(_("credential-cache unavailable; no unix socket support"));
 
+	socket_path = xstrdup_or_null(socket_path_arg);
 	if (!socket_path)
 		socket_path = get_socket_path();
 	if (!socket_path)
@@ -176,6 +183,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix)
 	else
 		; /* ignore unknown operation */
 
+	free(socket_path);
 	return 0;
 }
 
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index 494c809..e669e99 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -170,7 +171,10 @@ static void lookup_credential(const struct string_list *fns, struct credential *
 			return; /* Found credential */
 }
 
-int cmd_credential_store(int argc, const char **argv, const char *prefix)
+int cmd_credential_store(int argc,
+			 const char **argv,
+			 const char *prefix,
+			 struct repository *repo UNUSED)
 {
 	const char * const usage[] = {
 		"git credential-store [<options>] <action>",
@@ -218,5 +222,6 @@ int cmd_credential_store(int argc, const char **argv, const char *prefix)
 		; /* Ignore unknown operation. */
 
 	string_list_clear(&fns, 0);
+	credential_clear(&c);
 	return 0;
 }
diff --git a/builtin/credential.c b/builtin/credential.c
index b72e76d..14c8c66 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "credential.h"
 #include "builtin.h"
@@ -6,7 +8,10 @@
 static const char usage_msg[] =
 	"git credential (fill|approve|reject)";
 
-int cmd_credential(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_credential(int argc,
+		   const char **argv,
+		   const char *prefix UNUSED,
+		   struct repository *repo UNUSED)
 {
 	const char *op;
 	struct credential c = CREDENTIAL_INIT;
diff --git a/builtin/describe.c b/builtin/describe.c
index cf8edc4..7330a77 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "environment.h"
@@ -149,7 +150,7 @@ static void add_to_known_names(const char *path,
 	}
 }
 
-static int get_name(const char *path, const struct object_id *oid,
+static int get_name(const char *path, const char *referent UNUSED, const struct object_id *oid,
 		    int flag UNUSED, void *cb_data UNUSED)
 {
 	int is_tag = 0;
@@ -529,6 +530,7 @@ static void describe_blob(struct object_id oid, struct strbuf *dst)
 	traverse_commit_list(&revs, process_commit, process_object, &pcd);
 	reset_revision_walk();
 	release_revisions(&revs);
+	strvec_clear(&args);
 }
 
 static void describe(const char *arg, int last_one)
@@ -570,7 +572,10 @@ static int option_parse_exact_match(const struct option *opt, const char *arg,
 	return 0;
 }
 
-int cmd_describe(int argc, const char **argv, const char *prefix)
+int cmd_describe(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED )
 {
 	int contains = 0;
 	struct option options[] = {
@@ -619,6 +624,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 	if (contains) {
 		struct string_list_item *item;
 		struct strvec args;
+		const char **argv_copy;
+		int ret;
 
 		strvec_init(&args);
 		strvec_pushl(&args, "name-rev",
@@ -637,7 +644,21 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 			strvec_pushv(&args, argv);
 		else
 			strvec_push(&args, "HEAD");
-		return cmd_name_rev(args.nr, args.v, prefix);
+
+		/*
+		 * `cmd_name_rev()` modifies the array, so we'd leak its
+		 * contained strings if we didn't do a copy here.
+		 */
+		ALLOC_ARRAY(argv_copy, args.nr + 1);
+		for (size_t i = 0; i < args.nr; i++)
+			argv_copy[i] = args.v[i];
+		argv_copy[args.nr] = NULL;
+
+		ret = cmd_name_rev(args.nr, argv_copy, prefix, the_repository);
+
+		strvec_clear(&args);
+		free(argv_copy);
+		return ret;
 	}
 
 	hashmap_init(&names, commit_name_neq, NULL, 0);
@@ -679,7 +700,6 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 		} else if (dirty) {
 			struct lock_file index_lock = LOCK_INIT;
 			struct rev_info revs;
-			struct strvec args = STRVEC_INIT;
 			int fd;
 
 			setup_work_tree();
@@ -694,12 +714,13 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 				repo_update_index_if_able(the_repository, &index_lock);
 
 			repo_init_revisions(the_repository, &revs, prefix);
-			strvec_pushv(&args, diff_index_args);
-			if (setup_revisions(args.nr, args.v, &revs, NULL) != 1)
+
+			if (setup_revisions(ARRAY_SIZE(diff_index_args) - 1,
+					    diff_index_args, &revs, NULL) != 1)
 				BUG("malformed internal diff-index command line");
 			run_diff_index(&revs, 0);
 
-			if (!diff_result_code(&revs.diffopt))
+			if (!diff_result_code(&revs))
 				suffix = NULL;
 			else
 				suffix = dirty;
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
index 4857a43..66a22d9 100644
--- a/builtin/diagnose.c
+++ b/builtin/diagnose.c
@@ -11,7 +11,10 @@ static const char * const diagnose_usage[] = {
 	NULL
 };
 
-int cmd_diagnose(int argc, const char **argv, const char *prefix)
+int cmd_diagnose(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	struct strbuf zip_path = STRBUF_INIT;
 	time_t now = time(NULL);
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 018011f..e0e0cce 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -3,13 +3,13 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
 #include "diff-merges.h"
 #include "commit.h"
 #include "preload-index.h"
-#include "repository.h"
 #include "revision.h"
 
 static const char diff_files_usage[] =
@@ -17,7 +17,10 @@ static const char diff_files_usage[] =
 "\n"
 COMMON_DIFF_OPTIONS_HELP;
 
-int cmd_diff_files(int argc, const char **argv, const char *prefix)
+int cmd_diff_files(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	struct rev_info rev;
 	int result;
@@ -82,7 +85,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
 	if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0)
 		die_errno("repo_read_index_preload");
 	run_diff_files(&rev, options);
-	result = diff_result_code(&rev.diffopt);
+	result = diff_result_code(&rev);
 	release_revisions(&rev);
 	return result;
 }
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 3e05260..ad50362 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -1,10 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
 #include "diff-merges.h"
 #include "commit.h"
 #include "preload-index.h"
-#include "repository.h"
 #include "revision.h"
 #include "setup.h"
 
@@ -14,7 +14,10 @@ static const char diff_cache_usage[] =
 "\n"
 COMMON_DIFF_OPTIONS_HELP;
 
-int cmd_diff_index(int argc, const char **argv, const char *prefix)
+int cmd_diff_index(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	struct rev_info rev;
 	unsigned int option = 0;
@@ -25,6 +28,10 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
 		usage(diff_cache_usage);
 
 	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
 	repo_init_revisions(the_repository, &rev, prefix);
 	rev.abbrev = 0;
 	prefix = precompose_argv_prefix(argc, argv, prefix);
@@ -71,7 +78,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
 		return -1;
 	}
 	run_diff_index(&rev, option);
-	result = diff_result_code(&rev.diffopt);
+	result = diff_result_code(&rev);
 	release_revisions(&rev);
 	return result;
 }
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index b8df1d4..4b6656b 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
@@ -6,7 +7,6 @@
 #include "hex.h"
 #include "log-tree.h"
 #include "read-cache-ll.h"
-#include "repository.h"
 #include "revision.h"
 #include "tmp-objdir.h"
 #include "tree.h"
@@ -108,7 +108,10 @@ static void diff_tree_tweak_rev(struct rev_info *rev)
 	}
 }
 
-int cmd_diff_tree(int argc, const char **argv, const char *prefix)
+int cmd_diff_tree(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
 {
 	char line[1000];
 	struct object *tree1, *tree2;
@@ -167,13 +170,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 
 	opt->diffopt.rotate_to_strict = 1;
 
-	if (opt->remerge_diff) {
-		opt->remerge_objdir = tmp_objdir_create("remerge-diff");
-		if (!opt->remerge_objdir)
-			die(_("unable to create temporary object directory"));
-		tmp_objdir_replace_primary_odb(opt->remerge_objdir, 1);
-	}
-
 	/*
 	 * NOTE!  We expect "a..b" to expand to "^a b" but it is
 	 * perfectly valid for revision range parser to yield "b ^a",
@@ -238,10 +234,5 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 		diff_free(&opt->diffopt);
 	}
 
-	if (opt->remerge_diff) {
-		tmp_objdir_destroy(opt->remerge_objdir);
-		opt->remerge_objdir = NULL;
-	}
-
-	return diff_result_code(&opt->diffopt);
+	return diff_result_code(opt);
 }
diff --git a/builtin/diff.c b/builtin/diff.c
index 9b6cdab..dca52d4 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2006 Junio C Hamano
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "ewah/ewok.h"
@@ -388,7 +388,15 @@ static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym)
 	sym->skip = map;
 }
 
-int cmd_diff(int argc, const char **argv, const char *prefix)
+static void symdiff_release(struct symdiff *sdiff)
+{
+	bitmap_free(sdiff->skip);
+}
+
+int cmd_diff(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
 {
 	int i;
 	struct rev_info rev;
@@ -614,11 +622,12 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 		builtin_diff_combined(&rev, argc, argv,
 				      ent.objects, ent.nr,
 				      first_non_parent);
-	result = diff_result_code(&rev.diffopt);
+	result = diff_result_code(&rev);
 	if (1 < rev.diffopt.skip_stat_unmatch)
 		refresh_index_quietly();
 	release_revisions(&rev);
 	object_array_clear(&ent);
+	symdiff_release(&sdiff);
 	UNLEAK(blob);
 	return result;
 }
diff --git a/builtin/difftool.c b/builtin/difftool.c
index dcc68e1..5772e82 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -11,8 +11,9 @@
  *
  * Copyright (C) 2016 Johannes Schindelin
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
+
 #include "abspath.h"
 #include "config.h"
 #include "copy.h"
@@ -22,6 +23,7 @@
 #include "hex.h"
 #include "parse-options.h"
 #include "read-cache-ll.h"
+#include "repository.h"
 #include "sparse-index.h"
 #include "strvec.h"
 #include "strbuf.h"
@@ -214,7 +216,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
 	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(get_git_dir());
+	const char *git_dir = absolute_path(repo_get_git_dir(the_repository));
 	FILE *fp;
 
 	strvec_pushl(&update_index.args,
@@ -377,7 +379,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	struct hashmap wt_modified, tmp_modified;
 	int indices_loaded = 0;
 
-	workdir = get_git_work_tree();
+	workdir = repo_get_work_tree(the_repository);
 
 	/* Setup temp directories */
 	tmp = getenv("TMPDIR");
@@ -660,6 +662,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	if (fp)
 		fclose(fp);
 
+	hashmap_clear_and_free(&working_tree_dups, struct working_tree_entry, entry);
+	hashmap_clear_and_free(&wt_modified, struct path_entry, entry);
+	hashmap_clear_and_free(&tmp_modified, struct path_entry, entry);
+	hashmap_clear_and_free(&submodules, struct pair_entry, entry);
+	hashmap_clear_and_free(&symlinks2, struct pair_entry, entry);
+	release_index(&wtindex);
 	free(lbase_dir);
 	free(rbase_dir);
 	strbuf_release(&info);
@@ -690,7 +698,10 @@ static int run_file_diff(int prompt, const char *prefix,
 	return run_command(child);
 }
 
-int cmd_difftool(int argc, const char **argv, const char *prefix)
+int cmd_difftool(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	int use_gui_tool = -1, dir_diff = 0, prompt = -1, symlinks = 0,
 	    tool_help = 0, no_index = 0;
@@ -737,8 +748,8 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 
 	if (!no_index){
 		setup_work_tree();
-		setenv(GIT_DIR_ENVIRONMENT, absolute_path(get_git_dir()), 1);
-		setenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(get_git_work_tree()), 1);
+		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);
 	} else if (dir_diff)
 		die(_("options '%s' and '%s' cannot be used together"), "--dir-diff", "--no-index");
 
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 4b6e8c6..e17f262 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2007 Johannes E. Schindelin
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -42,8 +43,8 @@ static int full_tree;
 static int reference_excluded_commits;
 static int show_original_ids;
 static int mark_tags;
-static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
-static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
+static struct string_list extra_refs = STRING_LIST_INIT_DUP;
+static struct string_list tag_refs = STRING_LIST_INIT_DUP;
 static struct refspec refspecs = REFSPEC_INIT_FETCH;
 static int anonymize;
 static struct hashmap anonymized_seeds;
@@ -901,7 +902,7 @@ static void handle_tag(const char *name, struct tag *tag)
 	free(buf);
 }
 
-static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
+static struct commit *get_commit(struct rev_cmdline_entry *e, const char *full_name)
 {
 	switch (e->item->type) {
 	case OBJ_COMMIT:
@@ -932,14 +933,16 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
 		struct rev_cmdline_entry *e = info->rev + i;
 		struct object_id oid;
 		struct commit *commit;
-		char *full_name;
+		char *full_name = NULL;
 
 		if (e->flags & UNINTERESTING)
 			continue;
 
 		if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
-				  &oid, &full_name, 0) != 1)
+				  &oid, &full_name, 0) != 1) {
+			free(full_name);
 			continue;
+		}
 
 		if (refspecs.nr) {
 			char *private;
@@ -955,6 +958,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
 			warning("%s: Unexpected object of type %s, skipping.",
 				e->name,
 				type_name(e->item->type));
+			free(full_name);
 			continue;
 		}
 
@@ -963,10 +967,12 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
 			break;
 		case OBJ_BLOB:
 			export_blob(&commit->object.oid);
+			free(full_name);
 			continue;
 		default: /* OBJ_TAG (nested tags) is already handled */
 			warning("Tag points to object of unexpected type %s, skipping.",
 				type_name(commit->object.type));
+			free(full_name);
 			continue;
 		}
 
@@ -979,6 +985,8 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
 
 		if (!*revision_sources_at(&revision_sources, commit))
 			*revision_sources_at(&revision_sources, commit) = full_name;
+		else
+			free(full_name);
 	}
 
 	string_list_sort(&extra_refs);
@@ -1173,7 +1181,10 @@ static int parse_opt_anonymize_map(const struct option *opt,
 	return 0;
 }
 
-int cmd_fast_export(int argc, const char **argv, const char *prefix)
+int cmd_fast_export(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
 {
 	struct rev_info revs;
 	struct commit *commit;
@@ -1278,9 +1289,11 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 	revs.diffopt.format_callback = show_filemodify;
 	revs.diffopt.format_callback_data = &paths_of_changed_objects;
 	revs.diffopt.flags.recursive = 1;
+
 	revs.diffopt.no_free = 1;
 	while ((commit = get_revision(&revs)))
 		handle_commit(commit, &revs, &paths_of_changed_objects);
+	revs.diffopt.no_free = 0;
 
 	handle_tags_and_duplicates(&extra_refs);
 	handle_tags_and_duplicates(&tag_refs);
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index d21c405..1e7ab67 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1,9 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
-#include "repository.h"
 #include "config.h"
 #include "lockfile.h"
 #include "object.h"
@@ -206,8 +206,8 @@ static unsigned int object_entry_alloc = 5000;
 static struct object_entry_pool *blocks;
 static struct hashmap object_table;
 static struct mark_set *marks;
-static const char *export_marks_file;
-static const char *import_marks_file;
+static char *export_marks_file;
+static char *import_marks_file;
 static int import_marks_file_from_stream;
 static int import_marks_file_ignore_missing;
 static int import_marks_file_done;
@@ -3274,6 +3274,7 @@ static void option_import_marks(const char *marks,
 			read_marks();
 	}
 
+	free(import_marks_file);
 	import_marks_file = make_fast_import_path(marks);
 	import_marks_file_from_stream = from_stream;
 	import_marks_file_ignore_missing = ignore_missing;
@@ -3316,6 +3317,7 @@ static void option_active_branches(const char *branches)
 
 static void option_export_marks(const char *marks)
 {
+	free(export_marks_file);
 	export_marks_file = make_fast_import_path(marks);
 }
 
@@ -3357,6 +3359,8 @@ static void option_rewrite_submodules(const char *arg, struct string_list *list)
 	free(f);
 
 	string_list_insert(list, s)->util = ms;
+
+	free(s);
 }
 
 static int parse_one_option(const char *option)
@@ -3481,8 +3485,8 @@ static void git_pack_config(void)
 	if (!git_config_get_int("pack.indexversion", &indexversion_value)) {
 		pack_idx_opts.version = indexversion_value;
 		if (pack_idx_opts.version > 2)
-			git_die_config("pack.indexversion",
-					"bad pack.indexVersion=%"PRIu32, pack_idx_opts.version);
+			git_die_config(the_repository, "pack.indexversion",
+				       "bad pack.indexVersion=%"PRIu32, pack_idx_opts.version);
 	}
 	if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
 		max_packsize = packsizelimit_value;
@@ -3533,7 +3537,10 @@ static void parse_argv(void)
 	build_mark_map(&sub_marks_from, &sub_marks_to);
 }
 
-int cmd_fast_import(int argc, const char **argv, const char *prefix)
+int cmd_fast_import(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
 {
 	unsigned int i;
 
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index af329e8..62e8c3a 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "gettext.h"
 #include "hex.h"
@@ -43,12 +44,16 @@ static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
 	(*sought)[*nr - 1] = ref;
 }
 
-int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_fetch_pack(int argc,
+		   const char **argv,
+		   const char *prefix UNUSED,
+		   struct repository *repo UNUSED)
 {
 	int i, ret;
-	struct ref *ref = NULL;
+	struct ref *fetched_refs = NULL, *remote_refs = NULL;
 	const char *dest = NULL;
 	struct ref **sought = NULL;
+	struct ref **sought_to_free = NULL;
 	int nr_sought = 0, alloc_sought = 0;
 	int fd[2];
 	struct string_list pack_lockfiles = STRING_LIST_INIT_DUP;
@@ -228,19 +233,27 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
 	version = discover_version(&reader);
 	switch (version) {
 	case protocol_v2:
-		get_remote_refs(fd[1], &reader, &ref, 0, NULL, NULL,
+		get_remote_refs(fd[1], &reader, &remote_refs, 0, NULL, NULL,
 				args.stateless_rpc);
 		break;
 	case protocol_v1:
 	case protocol_v0:
-		get_remote_heads(&reader, &ref, 0, NULL, &shallow);
+		get_remote_heads(&reader, &remote_refs, 0, NULL, &shallow);
 		break;
 	case protocol_unknown_version:
 		BUG("unknown protocol version");
 	}
 
-	ref = fetch_pack(&args, fd, ref, sought, nr_sought,
+	/*
+	 * Create a shallow copy of `sought` so that we can free all of its entries.
+	 * This is because `fetch_pack()` will modify the array to evict some
+	 * entries, but won't free those.
+	 */
+	DUP_ARRAY(sought_to_free, sought, nr_sought);
+
+	fetched_refs = fetch_pack(&args, fd, remote_refs, sought, nr_sought,
 			 &shallow, pack_lockfiles_ptr, version);
+
 	if (pack_lockfiles.nr) {
 		int i;
 
@@ -260,7 +273,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
 	if (finish_connect(conn))
 		return 1;
 
-	ret = !ref;
+	ret = !fetched_refs;
 
 	/*
 	 * If the heads to pull were given, we should have consumed
@@ -270,11 +283,18 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix UNUSED)
 	 */
 	ret |= report_unmatched_refs(sought, nr_sought);
 
-	while (ref) {
+	for (struct ref *ref = fetched_refs; ref; ref = ref->next)
 		printf("%s %s\n",
 		       oid_to_hex(&ref->old_oid), ref->name);
-		ref = ref->next;
-	}
 
+	for (size_t i = 0; i < nr_sought; i++)
+		free_one_ref(sought_to_free[i]);
+	free(sought_to_free);
+	free(sought);
+	free_refs(fetched_refs);
+	free_refs(remote_refs);
+	list_objects_filter_release(&args.filter_options);
+	oid_array_clear(&shallow);
+	string_list_clear(&pack_lockfiles, 0);
 	return ret;
 }
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 693f02b..80a64d0 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1,13 +1,13 @@
 /*
  * "git fetch"
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "advice.h"
 #include "config.h"
 #include "gettext.h"
 #include "environment.h"
 #include "hex.h"
-#include "repository.h"
 #include "refs.h"
 #include "refspec.h"
 #include "object-name.h"
@@ -286,7 +286,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,
 	return ent;
 }
 
-static int add_one_refname(const char *refname,
+static int add_one_refname(const char *refname, const char *referent UNUSED,
 			   const struct object_id *oid,
 			   int flag UNUSED, void *cbdata)
 {
@@ -456,6 +456,7 @@ static void filter_prefetch_refspec(struct refspec *rs)
 
 			free(rs->items[i].src);
 			free(rs->items[i].dst);
+			free(rs->raw[i]);
 
 			for (j = i + 1; j < rs->nr; j++) {
 				rs->items[j - 1] = rs->items[j];
@@ -1161,7 +1162,7 @@ static int store_updated_refs(struct display_state *display_state,
 		opt.exclude_hidden_refs_section = "fetch";
 		rm = ref_map;
 		if (check_connected(iterate_ref_map, &rm, &opt)) {
-			rc = error(_("%s did not send all necessary objects\n"),
+			rc = error(_("%s did not send all necessary objects"),
 				   display_state->url);
 			goto abort;
 		}
@@ -1458,12 +1459,13 @@ static void set_option(struct transport *transport, const char *name, const char
 		die(_("option \"%s\" value \"%s\" is not valid for %s"),
 		    name, value, transport->url);
 	if (r > 0)
-		warning(_("option \"%s\" is ignored for %s\n"),
+		warning(_("option \"%s\" is ignored for %s"),
 			name, transport->url);
 }
 
 
 static int add_oid(const char *refname UNUSED,
+		   const char *referent UNUSED,
 		   const struct object_id *oid,
 		   int flags UNUSED, void *cb_data)
 {
@@ -1730,11 +1732,8 @@ static int do_fetch(struct transport *transport,
 			goto cleanup;
 
 		retcode = ref_transaction_commit(transaction, &err);
-		if (retcode) {
-			ref_transaction_free(transaction);
-			transaction = NULL;
+		if (retcode)
 			goto cleanup;
-		}
 	}
 
 	commit_fetch_head(&fetch_head);
@@ -1802,8 +1801,11 @@ static int do_fetch(struct transport *transport,
 		if (transaction && ref_transaction_abort(transaction, &err) &&
 		    err.len)
 			error("%s", err.buf);
+		transaction = NULL;
 	}
 
+	if (transaction)
+		ref_transaction_free(transaction);
 	display_state_release(&display_state);
 	close_fetch_head(&fetch_head);
 	strbuf_release(&err);
@@ -2137,7 +2139,10 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
 	return exit_code;
 }
 
-int cmd_fetch(int argc, const char **argv, const char *prefix)
+int cmd_fetch(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
 {
 	struct fetch_config config = {
 		.display_format = DISPLAY_FORMAT_FULL,
@@ -2407,6 +2412,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 		struct oidset_iter iter;
 		const struct object_id *oid;
 
+		trace2_region_enter("fetch", "negotiate-only", the_repository);
 		if (!remote)
 			die(_("must supply remote when using --negotiate-only"));
 		gtransport = prepare_transport(remote, 1);
@@ -2415,6 +2421,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 		} else {
 			warning(_("protocol does not support --negotiate-only, exiting"));
 			result = 1;
+			trace2_region_leave("fetch", "negotiate-only", the_repository);
 			goto cleanup;
 		}
 		if (server_options.nr)
@@ -2425,11 +2432,17 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 		while ((oid = oidset_iter_next(&iter)))
 			printf("%s\n", oid_to_hex(oid));
 		oidset_clear(&acked_commits);
+		trace2_region_leave("fetch", "negotiate-only", the_repository);
 	} else if (remote) {
-		if (filter_options.choice || repo_has_promisor_remote(the_repository))
+		if (filter_options.choice || repo_has_promisor_remote(the_repository)) {
+			trace2_region_enter("fetch", "setup-partial", the_repository);
 			fetch_one_setup_partial(remote);
+			trace2_region_leave("fetch", "setup-partial", the_repository);
+		}
+		trace2_region_enter("fetch", "fetch-one", the_repository);
 		result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs,
 				   &config);
+		trace2_region_leave("fetch", "fetch-one", the_repository);
 	} else {
 		int max_children = max_jobs;
 
@@ -2449,7 +2462,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 			max_children = config.parallel;
 
 		/* TODO should this also die if we have a previous partial-clone? */
+		trace2_region_enter("fetch", "fetch-multiple", the_repository);
 		result = fetch_multiple(&list, max_children, &config);
+		trace2_region_leave("fetch", "fetch-multiple", the_repository);
 	}
 
 	/*
@@ -2471,6 +2486,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 			max_children = config.parallel;
 
 		add_options_to_argv(&options, &config);
+		trace2_region_enter_printf("fetch", "recurse-submodule", the_repository, "%s", submodule_prefix);
 		result = fetch_submodules(the_repository,
 					  &options,
 					  submodule_prefix,
@@ -2478,6 +2494,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 					  recurse_submodules_default,
 					  verbosity < 0,
 					  max_children);
+		trace2_region_leave_printf("fetch", "recurse-submodule", the_repository, "%s", submodule_prefix);
 		strvec_clear(&options);
 	}
 
@@ -2501,9 +2518,11 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 		if (progress)
 			commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
 
+		trace2_region_enter("fetch", "write-commit-graph", the_repository);
 		write_commit_graph_reachable(the_repository->objects->odb,
 					     commit_graph_flags,
 					     NULL);
+		trace2_region_leave("fetch", "write-commit-graph", the_repository);
 	}
 
 	if (enable_auto_gc) {
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 957786d..189cd10 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "fmt-merge-msg.h"
@@ -9,7 +10,10 @@ static const char * const fmt_merge_msg_usage[] = {
 	NULL
 };
 
-int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
+int cmd_fmt_merge_msg(int argc,
+		      const char **argv,
+		      const char *prefix,
+		      struct repository *repo UNUSED)
 {
 	char *inpath = NULL;
 	const char *message = NULL;
@@ -67,6 +71,8 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
 		return ret;
 	write_in_full(STDOUT_FILENO, output.buf, output.len);
 
+	strbuf_release(&input);
+	strbuf_release(&output);
 	free(inpath);
 	return 0;
 }
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 5517a4a..715745a 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "commit.h"
 #include "config.h"
@@ -16,7 +17,10 @@ static char const * const for_each_ref_usage[] = {
 	NULL
 };
 
-int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
+int cmd_for_each_ref(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
 {
 	struct ref_sorting *sorting;
 	struct string_list sorting_options = STRING_LIST_INIT_DUP;
@@ -104,6 +108,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 	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/for-each-repo.c b/builtin/for-each-repo.c
index c4fa41f..fae7f91 100644
--- a/builtin/for-each-repo.c
+++ b/builtin/for-each-repo.c
@@ -1,9 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
 #include "parse-options.h"
 #include "path.h"
-#include "repository.h"
 #include "run-command.h"
 #include "string-list.h"
 
@@ -29,7 +29,10 @@ static int run_command_on_repo(const char *path, int argc, const char ** argv)
 	return run_command(&child);
 }
 
-int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
+int cmd_for_each_repo(int argc,
+		      const char **argv,
+		      const char *prefix,
+		      struct repository *repo UNUSED)
 {
 	static const char *config_key = NULL;
 	int keep_going = 0;
diff --git a/builtin/fsck.c b/builtin/fsck.c
index d13a226..7f4e2f0 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -1,7 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "gettext.h"
 #include "hex.h"
-#include "repository.h"
 #include "config.h"
 #include "commit.h"
 #include "tree.h"
@@ -89,13 +89,16 @@ static int objerror(struct object *obj, const char *err)
 	return -1;
 }
 
-static int fsck_error_func(struct fsck_options *o UNUSED,
-			   const struct object_id *oid,
-			   enum object_type object_type,
-			   enum fsck_msg_type msg_type,
-			   enum fsck_msg_id msg_id UNUSED,
-			   const char *message)
+static int fsck_objects_error_func(struct fsck_options *o UNUSED,
+				   void *fsck_report,
+				   enum fsck_msg_type msg_type,
+				   enum fsck_msg_id msg_id UNUSED,
+				   const char *message)
 {
+	struct fsck_object_report *report = fsck_report;
+	const struct object_id *oid = report->oid;
+	enum object_type object_type = report->object_type;
+
 	switch (msg_type) {
 	case FSCK_WARN:
 		/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
@@ -521,7 +524,7 @@ static int fsck_handle_reflog(const char *logname, void *cb_data)
 	return 0;
 }
 
-static int fsck_handle_ref(const char *refname, const struct object_id *oid,
+static int fsck_handle_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			   int flag UNUSED, void *cb_data UNUSED)
 {
 	struct object *obj;
@@ -576,7 +579,7 @@ static void get_default_heads(void)
 		strbuf_worktree_ref(wt, &ref, "HEAD");
 		fsck_head_link(ref.buf, &head_points_at, &head_oid);
 		if (head_points_at && !is_null_oid(&head_oid))
-			fsck_handle_ref(ref.buf, &head_oid, 0, NULL);
+			fsck_handle_ref(ref.buf, NULL, &head_oid, 0, NULL);
 		strbuf_release(&ref);
 
 		if (include_reflogs)
@@ -922,7 +925,10 @@ static struct option fsck_opts[] = {
 	OPT_END(),
 };
 
-int cmd_fsck(int argc, const char **argv, const char *prefix)
+int cmd_fsck(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
 {
 	int i;
 	struct object_directory *odb;
@@ -938,7 +944,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
 
 	fsck_walk_options.walk = mark_object;
 	fsck_obj_options.walk = mark_used;
-	fsck_obj_options.error_func = fsck_error_func;
+	fsck_obj_options.error_func = fsck_objects_error_func;
 	if (check_strict)
 		fsck_obj_options.strict = 1;
 
@@ -1050,7 +1056,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
 			 * and may get overwritten by other calls
 			 * while we're examining the index.
 			 */
-			path = xstrdup(worktree_git_path(wt, "index"));
+			path = xstrdup(worktree_git_path(the_repository, wt, "index"));
 			read_index_from(&istate, path, get_worktree_git_dir(wt));
 			fsck_index(&istate, path, wt->is_current);
 			discard_index(&istate);
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 1593713..f3f6bd3 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1,8 +1,8 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "config.h"
 #include "dir.h"
-#include "environment.h"
 #include "gettext.h"
 #include "parse-options.h"
 #include "fsmonitor-ll.h"
@@ -11,7 +11,7 @@
 #include "compat/fsmonitor/fsm-health.h"
 #include "compat/fsmonitor/fsm-listen.h"
 #include "fsmonitor--daemon.h"
-#include "repository.h"
+
 #include "simple-ipc.h"
 #include "khash.h"
 #include "run-command.h"
@@ -1208,9 +1208,9 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
 	 * system event listener thread so that we have the IPC handle
 	 * before we need it.
 	 */
-	if (ipc_server_run_async(&state->ipc_server_data,
-				 state->path_ipc.buf, &ipc_opts,
-				 handle_client, state))
+	if (ipc_server_init_async(&state->ipc_server_data,
+				  state->path_ipc.buf, &ipc_opts,
+				  handle_client, state))
 		return error_errno(
 			_("could not start IPC thread pool on '%s'"),
 			state->path_ipc.buf);
@@ -1291,7 +1291,8 @@ static int fsmonitor_run_daemon(void)
 
 	/* Prepare to (recursively) watch the <worktree-root> directory. */
 	strbuf_init(&state.path_worktree_watch, 0);
-	strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
+	strbuf_addstr(&state.path_worktree_watch,
+		      absolute_path(repo_get_work_tree(the_repository)));
 	state.nr_paths_watching = 1;
 
 	strbuf_init(&state.alias.alias, 0);
@@ -1311,7 +1312,9 @@ static int fsmonitor_run_daemon(void)
 	strbuf_addstr(&state.path_gitdir_watch, "/.git");
 	if (!is_directory(state.path_gitdir_watch.buf)) {
 		strbuf_reset(&state.path_gitdir_watch);
-		strbuf_addstr(&state.path_gitdir_watch, absolute_path(get_git_dir()));
+		strbuf_addstr(&state.path_gitdir_watch,
+			      absolute_path(repo_get_git_dir(the_repository)));
+		strbuf_strip_suffix(&state.path_gitdir_watch, "/.");
 		state.nr_paths_watching = 2;
 	}
 
@@ -1521,7 +1524,10 @@ static int try_to_start_background_daemon(void)
 	}
 }
 
-int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
+int cmd_fsmonitor__daemon(int argc,
+			  const char **argv,
+			  const char *prefix,
+			  struct repository *repo UNUSED)
 {
 	const char *subcmd;
 	enum fsmonitor_reason reason;
@@ -1584,7 +1590,7 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
 }
 
 #else
-int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED)
 {
 	struct option options[] = {
 		OPT_END()
diff --git a/builtin/gc.c b/builtin/gc.c
index 72bac25..d527353 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -9,13 +9,12 @@
  *
  * Copyright (c) 2006 Shawn O. Pearce
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "date.h"
 #include "environment.h"
 #include "hex.h"
-#include "repository.h"
 #include "config.h"
 #include "tempfile.h"
 #include "lockfile.h"
@@ -49,23 +48,7 @@ static const char * const builtin_gc_usage[] = {
 	NULL
 };
 
-static int pack_refs = 1;
-static int prune_reflogs = 1;
-static int cruft_packs = 1;
-static unsigned long max_cruft_size;
-static int aggressive_depth = 50;
-static int aggressive_window = 250;
-static int gc_auto_threshold = 6700;
-static int gc_auto_pack_limit = 50;
-static int detach_auto = 1;
 static timestamp_t gc_log_expire_time;
-static const char *gc_log_expire = "1.day.ago";
-static const char *prune_expire = "2.weeks.ago";
-static const char *prune_worktrees_expire = "3.months.ago";
-static char *repack_filter;
-static char *repack_filter_to;
-static unsigned long big_pack_threshold;
-static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
 
 static struct strvec reflog = STRVEC_INIT;
 static struct strvec repack = STRVEC_INIT;
@@ -125,13 +108,6 @@ static void process_log_file_at_exit(void)
 	process_log_file();
 }
 
-static void process_log_file_on_signal(int signo)
-{
-	process_log_file();
-	sigchain_pop(signo);
-	raise(signo);
-}
-
 static int gc_config_is_timestamp_never(const char *var)
 {
 	const char *value;
@@ -145,37 +121,100 @@ static int gc_config_is_timestamp_never(const char *var)
 	return 0;
 }
 
-static void gc_config(void)
+struct gc_config {
+	int pack_refs;
+	int prune_reflogs;
+	int cruft_packs;
+	unsigned long max_cruft_size;
+	int aggressive_depth;
+	int aggressive_window;
+	int gc_auto_threshold;
+	int gc_auto_pack_limit;
+	int detach_auto;
+	char *gc_log_expire;
+	char *prune_expire;
+	char *prune_worktrees_expire;
+	char *repack_filter;
+	char *repack_filter_to;
+	unsigned long big_pack_threshold;
+	unsigned long max_delta_cache_size;
+};
+
+#define GC_CONFIG_INIT { \
+	.pack_refs = 1, \
+	.prune_reflogs = 1, \
+	.cruft_packs = 1, \
+	.aggressive_depth = 50, \
+	.aggressive_window = 250, \
+	.gc_auto_threshold = 6700, \
+	.gc_auto_pack_limit = 50, \
+	.detach_auto = 1, \
+	.gc_log_expire = xstrdup("1.day.ago"), \
+	.prune_expire = xstrdup("2.weeks.ago"), \
+	.prune_worktrees_expire = xstrdup("3.months.ago"), \
+	.max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE, \
+}
+
+static void gc_config_release(struct gc_config *cfg)
+{
+	free(cfg->gc_log_expire);
+	free(cfg->prune_expire);
+	free(cfg->prune_worktrees_expire);
+	free(cfg->repack_filter);
+	free(cfg->repack_filter_to);
+}
+
+static void gc_config(struct gc_config *cfg)
 {
 	const char *value;
+	char *owned = NULL;
 
 	if (!git_config_get_value("gc.packrefs", &value)) {
 		if (value && !strcmp(value, "notbare"))
-			pack_refs = -1;
+			cfg->pack_refs = -1;
 		else
-			pack_refs = git_config_bool("gc.packrefs", value);
+			cfg->pack_refs = git_config_bool("gc.packrefs", value);
 	}
 
 	if (gc_config_is_timestamp_never("gc.reflogexpire") &&
 	    gc_config_is_timestamp_never("gc.reflogexpireunreachable"))
-		prune_reflogs = 0;
+		cfg->prune_reflogs = 0;
 
-	git_config_get_int("gc.aggressivewindow", &aggressive_window);
-	git_config_get_int("gc.aggressivedepth", &aggressive_depth);
-	git_config_get_int("gc.auto", &gc_auto_threshold);
-	git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
-	git_config_get_bool("gc.autodetach", &detach_auto);
-	git_config_get_bool("gc.cruftpacks", &cruft_packs);
-	git_config_get_ulong("gc.maxcruftsize", &max_cruft_size);
-	git_config_get_expiry("gc.pruneexpire", &prune_expire);
-	git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
-	git_config_get_expiry("gc.logexpiry", &gc_log_expire);
+	git_config_get_int("gc.aggressivewindow", &cfg->aggressive_window);
+	git_config_get_int("gc.aggressivedepth", &cfg->aggressive_depth);
+	git_config_get_int("gc.auto", &cfg->gc_auto_threshold);
+	git_config_get_int("gc.autopacklimit", &cfg->gc_auto_pack_limit);
+	git_config_get_bool("gc.autodetach", &cfg->detach_auto);
+	git_config_get_bool("gc.cruftpacks", &cfg->cruft_packs);
+	git_config_get_ulong("gc.maxcruftsize", &cfg->max_cruft_size);
 
-	git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
-	git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
+	if (!repo_config_get_expiry(the_repository, "gc.pruneexpire", &owned)) {
+		free(cfg->prune_expire);
+		cfg->prune_expire = owned;
+	}
 
-	git_config_get_string("gc.repackfilter", &repack_filter);
-	git_config_get_string("gc.repackfilterto", &repack_filter_to);
+	if (!repo_config_get_expiry(the_repository, "gc.worktreepruneexpire", &owned)) {
+		free(cfg->prune_worktrees_expire);
+		cfg->prune_worktrees_expire = owned;
+	}
+
+	if (!repo_config_get_expiry(the_repository, "gc.logexpiry", &owned)) {
+		free(cfg->gc_log_expire);
+		cfg->gc_log_expire = owned;
+	}
+
+	git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold);
+	git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size);
+
+	if (!git_config_get_string("gc.repackfilter", &owned)) {
+		free(cfg->repack_filter);
+		cfg->repack_filter = owned;
+	}
+
+	if (!git_config_get_string("gc.repackfilterto", &owned)) {
+		free(cfg->repack_filter_to);
+		cfg->repack_filter_to = owned;
+	}
 
 	git_config(git_default_config, NULL);
 }
@@ -202,11 +241,15 @@ static enum schedule_priority parse_schedule(const char *value)
 
 struct maintenance_run_opts {
 	int auto_flag;
+	int detach;
 	int quiet;
 	enum schedule_priority schedule;
 };
+#define MAINTENANCE_RUN_OPTS_INIT { \
+	.detach = -1, \
+}
 
-static int pack_refs_condition(void)
+static int pack_refs_condition(UNUSED struct gc_config *cfg)
 {
 	/*
 	 * The auto-repacking logic for refs is handled by the ref backends and
@@ -216,7 +259,8 @@ static int pack_refs_condition(void)
 	return 1;
 }
 
-static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
+static int maintenance_task_pack_refs(struct maintenance_run_opts *opts,
+				      UNUSED struct gc_config *cfg)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
 
@@ -228,7 +272,7 @@ static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *
 	return run_command(&cmd);
 }
 
-static int too_many_loose_objects(void)
+static int too_many_loose_objects(struct gc_config *cfg)
 {
 	/*
 	 * Quickly check if a "gc" is needed, by estimating how
@@ -247,7 +291,7 @@ static int too_many_loose_objects(void)
 	if (!dir)
 		return 0;
 
-	auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256);
+	auto_threshold = DIV_ROUND_UP(cfg->gc_auto_threshold, 256);
 	while ((ent = readdir(dir)) != NULL) {
 		if (strspn(ent->d_name, "0123456789abcdef") != hexsz_loose ||
 		    ent->d_name[hexsz_loose] != '\0')
@@ -283,12 +327,12 @@ static struct packed_git *find_base_packs(struct string_list *packs,
 	return base;
 }
 
-static int too_many_packs(void)
+static int too_many_packs(struct gc_config *cfg)
 {
 	struct packed_git *p;
 	int cnt;
 
-	if (gc_auto_pack_limit <= 0)
+	if (cfg->gc_auto_pack_limit <= 0)
 		return 0;
 
 	for (cnt = 0, p = get_all_packs(the_repository); p; p = p->next) {
@@ -302,7 +346,7 @@ static int too_many_packs(void)
 		 */
 		cnt++;
 	}
-	return gc_auto_pack_limit < cnt;
+	return cfg->gc_auto_pack_limit < cnt;
 }
 
 static uint64_t total_ram(void)
@@ -336,7 +380,8 @@ static uint64_t total_ram(void)
 	return 0;
 }
 
-static uint64_t estimate_repack_memory(struct packed_git *pack)
+static uint64_t estimate_repack_memory(struct gc_config *cfg,
+				       struct packed_git *pack)
 {
 	unsigned long nr_objects = repo_approximate_object_count(the_repository);
 	size_t os_cache, heap;
@@ -373,7 +418,7 @@ static uint64_t estimate_repack_memory(struct packed_git *pack)
 	 */
 	heap += delta_base_cache_limit;
 	/* and of course pack-objects has its own delta cache */
-	heap += max_delta_cache_size;
+	heap += cfg->max_delta_cache_size;
 
 	return os_cache + heap;
 }
@@ -384,30 +429,31 @@ static int keep_one_pack(struct string_list_item *item, void *data UNUSED)
 	return 0;
 }
 
-static void add_repack_all_option(struct string_list *keep_pack)
+static void add_repack_all_option(struct gc_config *cfg,
+				  struct string_list *keep_pack)
 {
-	if (prune_expire && !strcmp(prune_expire, "now"))
+	if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now"))
 		strvec_push(&repack, "-a");
-	else if (cruft_packs) {
+	else if (cfg->cruft_packs) {
 		strvec_push(&repack, "--cruft");
-		if (prune_expire)
-			strvec_pushf(&repack, "--cruft-expiration=%s", prune_expire);
-		if (max_cruft_size)
+		if (cfg->prune_expire)
+			strvec_pushf(&repack, "--cruft-expiration=%s", cfg->prune_expire);
+		if (cfg->max_cruft_size)
 			strvec_pushf(&repack, "--max-cruft-size=%lu",
-				     max_cruft_size);
+				     cfg->max_cruft_size);
 	} else {
 		strvec_push(&repack, "-A");
-		if (prune_expire)
-			strvec_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
+		if (cfg->prune_expire)
+			strvec_pushf(&repack, "--unpack-unreachable=%s", cfg->prune_expire);
 	}
 
 	if (keep_pack)
 		for_each_string_list(keep_pack, keep_one_pack, NULL);
 
-	if (repack_filter && *repack_filter)
-		strvec_pushf(&repack, "--filter=%s", repack_filter);
-	if (repack_filter_to && *repack_filter_to)
-		strvec_pushf(&repack, "--filter-to=%s", repack_filter_to);
+	if (cfg->repack_filter && *cfg->repack_filter)
+		strvec_pushf(&repack, "--filter=%s", cfg->repack_filter);
+	if (cfg->repack_filter_to && *cfg->repack_filter_to)
+		strvec_pushf(&repack, "--filter-to=%s", cfg->repack_filter_to);
 }
 
 static void add_repack_incremental_option(void)
@@ -415,13 +461,13 @@ static void add_repack_incremental_option(void)
 	strvec_push(&repack, "--no-write-bitmap-index");
 }
 
-static int need_to_gc(void)
+static int need_to_gc(struct gc_config *cfg)
 {
 	/*
 	 * Setting gc.auto to 0 or negative can disable the
 	 * automatic gc.
 	 */
-	if (gc_auto_threshold <= 0)
+	if (cfg->gc_auto_threshold <= 0)
 		return 0;
 
 	/*
@@ -430,13 +476,13 @@ static int need_to_gc(void)
 	 * we run "repack -A -d -l".  Otherwise we tell the caller
 	 * there is no need.
 	 */
-	if (too_many_packs()) {
+	if (too_many_packs(cfg)) {
 		struct string_list keep_pack = STRING_LIST_INIT_NODUP;
 
-		if (big_pack_threshold) {
-			find_base_packs(&keep_pack, big_pack_threshold);
-			if (keep_pack.nr >= gc_auto_pack_limit) {
-				big_pack_threshold = 0;
+		if (cfg->big_pack_threshold) {
+			find_base_packs(&keep_pack, cfg->big_pack_threshold);
+			if (keep_pack.nr >= cfg->gc_auto_pack_limit) {
+				cfg->big_pack_threshold = 0;
 				string_list_clear(&keep_pack, 0);
 				find_base_packs(&keep_pack, 0);
 			}
@@ -445,7 +491,7 @@ static int need_to_gc(void)
 			uint64_t mem_have, mem_want;
 
 			mem_have = total_ram();
-			mem_want = estimate_repack_memory(p);
+			mem_want = estimate_repack_memory(cfg, p);
 
 			/*
 			 * Only allow 1/2 of memory for pack-objects, leave
@@ -456,14 +502,14 @@ static int need_to_gc(void)
 				string_list_clear(&keep_pack, 0);
 		}
 
-		add_repack_all_option(&keep_pack);
+		add_repack_all_option(cfg, &keep_pack);
 		string_list_clear(&keep_pack, 0);
-	} else if (too_many_loose_objects())
+	} else if (too_many_loose_objects(cfg))
 		add_repack_incremental_option();
 	else
 		return 0;
 
-	if (run_hooks("pre-auto-gc"))
+	if (run_hooks(the_repository, "pre-auto-gc"))
 		return 0;
 	return 1;
 }
@@ -585,7 +631,8 @@ static int report_last_gc_error(void)
 	return ret;
 }
 
-static void gc_before_repack(struct maintenance_run_opts *opts)
+static void gc_before_repack(struct maintenance_run_opts *opts,
+			     struct gc_config *cfg)
 {
 	/*
 	 * We may be called twice, as both the pre- and
@@ -596,10 +643,10 @@ static void gc_before_repack(struct maintenance_run_opts *opts)
 	if (done++)
 		return;
 
-	if (pack_refs && maintenance_task_pack_refs(opts))
+	if (cfg->pack_refs && maintenance_task_pack_refs(opts, cfg))
 		die(FAILED_RUN, "pack-refs");
 
-	if (prune_reflogs) {
+	if (cfg->prune_reflogs) {
 		struct child_process cmd = CHILD_PROCESS_INIT;
 
 		cmd.git_cmd = 1;
@@ -609,7 +656,10 @@ static void gc_before_repack(struct maintenance_run_opts *opts)
 	}
 }
 
-int cmd_gc(int argc, const char **argv, const char *prefix)
+int cmd_gc(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
 {
 	int aggressive = 0;
 	int quiet = 0;
@@ -620,19 +670,25 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 	int keep_largest_pack = -1;
 	timestamp_t dummy;
 	struct child_process rerere_cmd = CHILD_PROCESS_INIT;
-	struct maintenance_run_opts opts = {0};
+	struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
+	struct gc_config cfg = GC_CONFIG_INIT;
+	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, N_("date"),
+		{ OPTION_STRING, 0, "prune", &prune_expire_arg, N_("date"),
 			N_("prune unreferenced objects"),
-			PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
-		OPT_BOOL(0, "cruft", &cruft_packs, N_("pack unreferenced objects separately")),
-		OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
+			PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire_arg },
+		OPT_BOOL(0, "cruft", &cfg.cruft_packs, N_("pack unreferenced objects separately")),
+		OPT_MAGNITUDE(0, "max-cruft-size", &cfg.max_cruft_size,
 			      N_("with --cruft, limit the size of new cruft packs")),
 		OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
 		OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"),
 			   PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL(0, "detach", &opts.detach,
+			 N_("perform garbage collection in the background")),
 		OPT_BOOL_F(0, "force", &force,
 			   N_("force running gc even if there may be another gc running"),
 			   PARSE_OPT_NOCOMPLETE),
@@ -650,84 +706,103 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 	strvec_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL);
 	strvec_pushl(&rerere, "rerere", "gc", NULL);
 
-	/* default expiry time, overwritten in gc_config */
-	gc_config();
-	if (parse_expiry_date(gc_log_expire, &gc_log_expire_time))
-		die(_("failed to parse gc.logExpiry value %s"), gc_log_expire);
+	gc_config(&cfg);
 
-	if (pack_refs < 0)
-		pack_refs = !is_bare_repository();
+	if (parse_expiry_date(cfg.gc_log_expire, &gc_log_expire_time))
+		die(_("failed to parse gc.logExpiry value %s"), cfg.gc_log_expire);
+
+	if (cfg.pack_refs < 0)
+		cfg.pack_refs = !is_bare_repository();
 
 	argc = parse_options(argc, argv, prefix, builtin_gc_options,
 			     builtin_gc_usage, 0);
 	if (argc > 0)
 		usage_with_options(builtin_gc_usage, builtin_gc_options);
 
-	if (prune_expire && parse_expiry_date(prune_expire, &dummy))
-		die(_("failed to parse prune expiry value %s"), prune_expire);
+	if (prune_expire_arg != prune_expire_sentinel) {
+		free(cfg.prune_expire);
+		cfg.prune_expire = xstrdup_or_null(prune_expire_arg);
+	}
+	if (cfg.prune_expire && parse_expiry_date(cfg.prune_expire, &dummy))
+		die(_("failed to parse prune expiry value %s"), cfg.prune_expire);
 
 	if (aggressive) {
 		strvec_push(&repack, "-f");
-		if (aggressive_depth > 0)
-			strvec_pushf(&repack, "--depth=%d", aggressive_depth);
-		if (aggressive_window > 0)
-			strvec_pushf(&repack, "--window=%d", aggressive_window);
+		if (cfg.aggressive_depth > 0)
+			strvec_pushf(&repack, "--depth=%d", cfg.aggressive_depth);
+		if (cfg.aggressive_window > 0)
+			strvec_pushf(&repack, "--window=%d", cfg.aggressive_window);
 	}
 	if (quiet)
 		strvec_push(&repack, "-q");
 
 	if (opts.auto_flag) {
+		if (cfg.detach_auto && opts.detach < 0)
+			opts.detach = 1;
+
 		/*
 		 * Auto-gc should be least intrusive as possible.
 		 */
-		if (!need_to_gc())
-			return 0;
+		if (!need_to_gc(&cfg)) {
+			ret = 0;
+			goto out;
+		}
+
 		if (!quiet) {
-			if (detach_auto)
+			if (opts.detach > 0)
 				fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n"));
 			else
 				fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
 			fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n"));
 		}
-		if (detach_auto) {
-			int ret = report_last_gc_error();
-
-			if (ret == 1)
-				/* Last gc --auto failed. Skip this one. */
-				return 0;
-			else if (ret)
-				/* an I/O error occurred, already reported */
-				return ret;
-
-			if (lock_repo_for_gc(force, &pid))
-				return 0;
-			gc_before_repack(&opts); /* dies on failure */
-			delete_tempfile(&pidfile);
-
-			/*
-			 * failure to daemonize is ok, we'll continue
-			 * in foreground
-			 */
-			daemonized = !daemonize();
-		}
 	} else {
 		struct string_list keep_pack = STRING_LIST_INIT_NODUP;
 
 		if (keep_largest_pack != -1) {
 			if (keep_largest_pack)
 				find_base_packs(&keep_pack, 0);
-		} else if (big_pack_threshold) {
-			find_base_packs(&keep_pack, big_pack_threshold);
+		} else if (cfg.big_pack_threshold) {
+			find_base_packs(&keep_pack, cfg.big_pack_threshold);
 		}
 
-		add_repack_all_option(&keep_pack);
+		add_repack_all_option(&cfg, &keep_pack);
 		string_list_clear(&keep_pack, 0);
 	}
 
+	if (opts.detach > 0) {
+		ret = report_last_gc_error();
+		if (ret == 1) {
+			/* Last gc --auto failed. Skip this one. */
+			ret = 0;
+			goto out;
+
+		} else if (ret) {
+			/* an I/O error occurred, already reported */
+			goto out;
+		}
+
+		if (lock_repo_for_gc(force, &pid)) {
+			ret = 0;
+			goto out;
+		}
+
+		gc_before_repack(&opts, &cfg); /* dies on failure */
+		delete_tempfile(&pidfile);
+
+		/*
+		 * failure to daemonize is ok, we'll continue
+		 * in foreground
+		 */
+		daemonized = !daemonize();
+	}
+
 	name = lock_repo_for_gc(force, &pid);
 	if (name) {
-		if (opts.auto_flag)
-			return 0; /* be quiet on --auto */
+		if (opts.auto_flag) {
+			ret = 0;
+			goto out; /* be quiet on --auto */
+		}
+
 		die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
 		    name, (uintmax_t)pid);
 	}
@@ -737,11 +812,10 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 					  git_path("gc.log"),
 					  LOCK_DIE_ON_ERROR);
 		dup2(get_lock_file_fd(&log_lock), 2);
-		sigchain_push_common(process_log_file_on_signal);
 		atexit(process_log_file_at_exit);
 	}
 
-	gc_before_repack(&opts);
+	gc_before_repack(&opts, &cfg);
 
 	if (!repository_format_precious_objects) {
 		struct child_process repack_cmd = CHILD_PROCESS_INIT;
@@ -752,11 +826,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 		if (run_command(&repack_cmd))
 			die(FAILED_RUN, repack.v[0]);
 
-		if (prune_expire) {
+		if (cfg.prune_expire) {
 			struct child_process prune_cmd = CHILD_PROCESS_INIT;
 
 			/* run `git prune` even if using cruft packs */
-			strvec_push(&prune, prune_expire);
+			strvec_push(&prune, cfg.prune_expire);
 			if (quiet)
 				strvec_push(&prune, "--no-progress");
 			if (repo_has_promisor_remote(the_repository))
@@ -769,10 +843,10 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 		}
 	}
 
-	if (prune_worktrees_expire) {
+	if (cfg.prune_worktrees_expire) {
 		struct child_process prune_worktrees_cmd = CHILD_PROCESS_INIT;
 
-		strvec_push(&prune_worktrees, prune_worktrees_expire);
+		strvec_push(&prune_worktrees, cfg.prune_worktrees_expire);
 		prune_worktrees_cmd.git_cmd = 1;
 		strvec_pushv(&prune_worktrees_cmd.args, prune_worktrees.v);
 		if (run_command(&prune_worktrees_cmd))
@@ -796,13 +870,15 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 					     !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
 					     NULL);
 
-	if (opts.auto_flag && too_many_loose_objects())
+	if (opts.auto_flag && too_many_loose_objects(&cfg))
 		warning(_("There are too many unreachable loose objects; "
 			"run 'git prune' to remove them."));
 
 	if (!daemonized)
 		unlink(git_path("gc.log"));
 
+out:
+	gc_config_release(&cfg);
 	return 0;
 }
 
@@ -836,6 +912,7 @@ struct cg_auto_data {
 };
 
 static int dfs_on_ref(const char *refname UNUSED,
+		      const char *referent UNUSED,
 		      const struct object_id *oid,
 		      int flags UNUSED,
 		      void *cb_data)
@@ -892,7 +969,7 @@ static int dfs_on_ref(const char *refname UNUSED,
 	return result;
 }
 
-static int should_write_commit_graph(void)
+static int should_write_commit_graph(struct gc_config *cfg UNUSED)
 {
 	int result;
 	struct cg_auto_data data;
@@ -929,7 +1006,8 @@ static int run_write_commit_graph(struct maintenance_run_opts *opts)
 	return !!run_command(&child);
 }
 
-static int maintenance_task_commit_graph(struct maintenance_run_opts *opts)
+static int maintenance_task_commit_graph(struct maintenance_run_opts *opts,
+					 struct gc_config *cfg UNUSED)
 {
 	prepare_repo_settings(the_repository);
 	if (!the_repository->settings.core_commit_graph)
@@ -963,7 +1041,8 @@ static int fetch_remote(struct remote *remote, void *cbdata)
 	return !!run_command(&child);
 }
 
-static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
+static int maintenance_task_prefetch(struct maintenance_run_opts *opts,
+				     struct gc_config *cfg UNUSED)
 {
 	if (for_each_remote(fetch_remote, opts)) {
 		error(_("failed to prefetch remotes"));
@@ -973,7 +1052,8 @@ static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
 	return 0;
 }
 
-static int maintenance_task_gc(struct maintenance_run_opts *opts)
+static int maintenance_task_gc(struct maintenance_run_opts *opts,
+			       struct gc_config *cfg UNUSED)
 {
 	struct child_process child = CHILD_PROCESS_INIT;
 
@@ -986,6 +1066,7 @@ static int maintenance_task_gc(struct maintenance_run_opts *opts)
 		strvec_push(&child.args, "--quiet");
 	else
 		strvec_push(&child.args, "--no-quiet");
+	strvec_push(&child.args, "--no-detach");
 
 	return run_command(&child);
 }
@@ -1021,7 +1102,7 @@ static int loose_object_count(const struct object_id *oid UNUSED,
 	return 0;
 }
 
-static int loose_object_auto_condition(void)
+static int loose_object_auto_condition(struct gc_config *cfg UNUSED)
 {
 	int count = 0;
 
@@ -1081,6 +1162,12 @@ static int pack_loose(struct maintenance_run_opts *opts)
 
 	pack_proc.in = -1;
 
+	/*
+	 * git-pack-objects(1) ends up writing the pack hash to stdout, which
+	 * we do not care for.
+	 */
+	pack_proc.out = -1;
+
 	if (start_command(&pack_proc)) {
 		error(_("failed to start 'git pack-objects' process"));
 		return 1;
@@ -1106,12 +1193,13 @@ static int pack_loose(struct maintenance_run_opts *opts)
 	return result;
 }
 
-static int maintenance_task_loose_objects(struct maintenance_run_opts *opts)
+static int maintenance_task_loose_objects(struct maintenance_run_opts *opts,
+					  struct gc_config *cfg UNUSED)
 {
 	return prune_packed(opts) || pack_loose(opts);
 }
 
-static int incremental_repack_auto_condition(void)
+static int incremental_repack_auto_condition(struct gc_config *cfg UNUSED)
 {
 	struct packed_git *p;
 	int incremental_repack_auto_limit = 10;
@@ -1230,7 +1318,8 @@ static int multi_pack_index_repack(struct maintenance_run_opts *opts)
 	return 0;
 }
 
-static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts)
+static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts,
+					       struct gc_config *cfg UNUSED)
 {
 	prepare_repo_settings(the_repository);
 	if (!the_repository->settings.core_multi_pack_index) {
@@ -1247,14 +1336,15 @@ static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts
 	return 0;
 }
 
-typedef int maintenance_task_fn(struct maintenance_run_opts *opts);
+typedef int maintenance_task_fn(struct maintenance_run_opts *opts,
+				struct gc_config *cfg);
 
 /*
  * An auto condition function returns 1 if the task should run
  * and 0 if the task should NOT run. See needs_to_gc() for an
  * example.
  */
-typedef int maintenance_auto_fn(void);
+typedef int maintenance_auto_fn(struct gc_config *cfg);
 
 struct maintenance_task {
 	const char *name;
@@ -1321,7 +1411,8 @@ static int compare_tasks_by_selection(const void *a_, const void *b_)
 	return b->selected_order - a->selected_order;
 }
 
-static int maintenance_run_tasks(struct maintenance_run_opts *opts)
+static int maintenance_run_tasks(struct maintenance_run_opts *opts,
+				 struct gc_config *cfg)
 {
 	int i, found_selected = 0;
 	int result = 0;
@@ -1345,6 +1436,13 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
 	}
 	free(lock_path);
 
+	/* Failure to daemonize is ok, we'll continue in foreground. */
+	if (opts->detach > 0) {
+		trace2_region_enter("maintenance", "detach", the_repository);
+		daemonize();
+		trace2_region_leave("maintenance", "detach", the_repository);
+	}
+
 	for (i = 0; !found_selected && i < TASK__COUNT; i++)
 		found_selected = tasks[i].selected_order >= 0;
 
@@ -1360,14 +1458,14 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
 
 		if (opts->auto_flag &&
 		    (!tasks[i].auto_condition ||
-		     !tasks[i].auto_condition()))
+		     !tasks[i].auto_condition(cfg)))
 			continue;
 
 		if (opts->schedule && tasks[i].schedule < opts->schedule)
 			continue;
 
 		trace2_region_enter("maintenance", tasks[i].name, r);
-		if (tasks[i].fn(opts)) {
+		if (tasks[i].fn(opts, cfg)) {
 			error(_("task '%s' failed"), tasks[i].name);
 			result = 1;
 		}
@@ -1380,9 +1478,9 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
 
 static void initialize_maintenance_strategy(void)
 {
-	char *config_str;
+	const char *config_str;
 
-	if (git_config_get_string("maintenance.strategy", &config_str))
+	if (git_config_get_string_tmp("maintenance.strategy", &config_str))
 		return;
 
 	if (!strcasecmp(config_str, "incremental")) {
@@ -1404,7 +1502,6 @@ static void initialize_task_config(int schedule)
 {
 	int i;
 	struct strbuf config_name = STRBUF_INIT;
-	gc_config();
 
 	if (schedule)
 		initialize_maintenance_strategy();
@@ -1467,10 +1564,13 @@ static int task_option_parse(const struct option *opt UNUSED,
 static int maintenance_run(int argc, const char **argv, const char *prefix)
 {
 	int i;
-	struct maintenance_run_opts opts;
+	struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
+	struct gc_config cfg = GC_CONFIG_INIT;
 	struct option builtin_maintenance_run_options[] = {
 		OPT_BOOL(0, "auto", &opts.auto_flag,
 			 N_("run tasks based on the state of the repository")),
+		OPT_BOOL(0, "detach", &opts.detach,
+			 N_("perform maintenance in the background")),
 		OPT_CALLBACK(0, "schedule", &opts.schedule, N_("frequency"),
 			     N_("run tasks based on frequency"),
 			     maintenance_opt_schedule),
@@ -1481,7 +1581,7 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
 			PARSE_OPT_NONEG, task_option_parse),
 		OPT_END()
 	};
-	memset(&opts, 0, sizeof(opts));
+	int ret;
 
 	opts.quiet = !isatty(2);
 
@@ -1496,12 +1596,16 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
 	if (opts.auto_flag && opts.schedule)
 		die(_("use at most one of --auto and --schedule=<frequency>"));
 
+	gc_config(&cfg);
 	initialize_task_config(opts.schedule);
 
 	if (argc != 0)
 		usage_with_options(builtin_maintenance_run_usage,
 				   builtin_maintenance_run_options);
-	return maintenance_run_tasks(&opts);
+
+	ret = maintenance_run_tasks(&opts, &cfg);
+	gc_config_release(&cfg);
+	return ret;
 }
 
 static char *get_maintpath(void)
@@ -1664,6 +1768,42 @@ static const char *get_frequency(enum schedule_priority schedule)
 	}
 }
 
+static const char *extraconfig[] = {
+	"credential.interactive=false",
+	"core.askPass=true", /* 'true' returns success, but no output. */
+	NULL
+};
+
+static const char *get_extra_config_parameters(void) {
+	static const char *result = NULL;
+	struct strbuf builder = STRBUF_INIT;
+
+	if (result)
+		return result;
+
+	for (const char **s = extraconfig; s && *s; s++)
+		strbuf_addf(&builder, "-c %s ", *s);
+
+	result = strbuf_detach(&builder, NULL);
+	return result;
+}
+
+static const char *get_extra_launchctl_strings(void) {
+	static const char *result = NULL;
+	struct strbuf builder = STRBUF_INIT;
+
+	if (result)
+		return result;
+
+	for (const char **s = extraconfig; s && *s; s++) {
+		strbuf_addstr(&builder, "<string>-c</string>\n");
+		strbuf_addf(&builder, "<string>%s</string>\n", *s);
+	}
+
+	result = strbuf_detach(&builder, NULL);
+	return result;
+}
+
 /*
  * get_schedule_cmd` reads the GIT_TEST_MAINT_SCHEDULER environment variable
  * to mock the schedulers that `git maintenance start` rely on.
@@ -1678,39 +1818,43 @@ static const char *get_frequency(enum schedule_priority schedule)
  * * If $GIT_TEST_MAINT_SCHEDULER is set, return true.
  *   In this case, the *cmd value is read as input.
  *
- *   * if the input value *cmd is the key of one of the comma-separated list
- *     item, then *is_available is set to true and *cmd is modified and becomes
+ *   * if the input value cmd is the key of one of the comma-separated list
+ *     item, then *is_available is set to true and *out is set to
  *     the mock command.
  *
  *   * if the input value *cmd isn’t the key of any of the comma-separated list
- *     item, then *is_available is set to false.
+ *     item, then *is_available is set to false and *out is set to the original
+ *     command.
  *
  * Ex.:
  *   GIT_TEST_MAINT_SCHEDULER not set
  *     +-------+-------------------------------------------------+
  *     | Input |                     Output                      |
- *     | *cmd  | return code |       *cmd        | *is_available |
+ *     | *cmd  | return code |       *out        | *is_available |
  *     +-------+-------------+-------------------+---------------+
- *     | "foo" |    false    | "foo" (unchanged) |  (unchanged)  |
+ *     | "foo" |    false    | "foo" (allocated) |  (unchanged)  |
  *     +-------+-------------+-------------------+---------------+
  *
  *   GIT_TEST_MAINT_SCHEDULER set to “foo:./mock_foo.sh,bar:./mock_bar.sh”
  *     +-------+-------------------------------------------------+
  *     | Input |                     Output                      |
- *     | *cmd  | return code |       *cmd        | *is_available |
+ *     | *cmd  | return code |       *out        | *is_available |
  *     +-------+-------------+-------------------+---------------+
  *     | "foo" |    true     |  "./mock.foo.sh"  |     true      |
- *     | "qux" |    true     | "qux" (unchanged) |     false     |
+ *     | "qux" |    true     | "qux" (allocated) |     false     |
  *     +-------+-------------+-------------------+---------------+
  */
-static int get_schedule_cmd(const char **cmd, int *is_available)
+static int get_schedule_cmd(const char *cmd, int *is_available, char **out)
 {
 	char *testing = xstrdup_or_null(getenv("GIT_TEST_MAINT_SCHEDULER"));
 	struct string_list_item *item;
 	struct string_list list = STRING_LIST_INIT_NODUP;
 
-	if (!testing)
+	if (!testing) {
+		if (out)
+			*out = xstrdup(cmd);
 		return 0;
+	}
 
 	if (is_available)
 		*is_available = 0;
@@ -1722,16 +1866,22 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
 		if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
 			continue;
 
-		if (!strcmp(*cmd, pair.items[0].string)) {
-			*cmd = pair.items[1].string;
+		if (!strcmp(cmd, pair.items[0].string)) {
+			if (out)
+				*out = xstrdup(pair.items[1].string);
 			if (is_available)
 				*is_available = 1;
-			string_list_clear(&list, 0);
-			UNLEAK(testing);
-			return 1;
+			string_list_clear(&pair, 0);
+			goto out;
 		}
+
+		string_list_clear(&pair, 0);
 	}
 
+	if (out)
+		*out = xstrdup(cmd);
+
+out:
 	string_list_clear(&list, 0);
 	free(testing);
 	return 1;
@@ -1748,9 +1898,8 @@ static int get_random_minute(void)
 
 static int is_launchctl_available(void)
 {
-	const char *cmd = "launchctl";
 	int is_available;
-	if (get_schedule_cmd(&cmd, &is_available))
+	if (get_schedule_cmd("launchctl", &is_available, NULL))
 		return is_available;
 
 #ifdef __APPLE__
@@ -1788,12 +1937,12 @@ static char *launchctl_get_uid(void)
 
 static int launchctl_boot_plist(int enable, const char *filename)
 {
-	const char *cmd = "launchctl";
+	char *cmd;
 	int result;
 	struct child_process child = CHILD_PROCESS_INIT;
 	char *uid = launchctl_get_uid();
 
-	get_schedule_cmd(&cmd, NULL);
+	get_schedule_cmd("launchctl", NULL, &cmd);
 	strvec_split(&child.args, cmd);
 	strvec_pushl(&child.args, enable ? "bootstrap" : "bootout", uid,
 		     filename, NULL);
@@ -1806,6 +1955,7 @@ static int launchctl_boot_plist(int enable, const char *filename)
 
 	result = finish_command(&child);
 
+	free(cmd);
 	free(uid);
 	return result;
 }
@@ -1857,10 +2007,10 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
 	static unsigned long lock_file_timeout_ms = ULONG_MAX;
 	struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT;
 	struct stat st;
-	const char *cmd = "launchctl";
+	char *cmd;
 	int minute = get_random_minute();
 
-	get_schedule_cmd(&cmd, NULL);
+	get_schedule_cmd("launchctl", NULL, &cmd);
 	preamble = "<?xml version=\"1.0\"?>\n"
 		   "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
 		   "<plist version=\"1.0\">"
@@ -1870,6 +2020,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
 		   "<array>\n"
 		   "<string>%s/git</string>\n"
 		   "<string>--exec-path=%s</string>\n"
+		   "%s" /* For extra config parameters. */
 		   "<string>for-each-repo</string>\n"
 		   "<string>--keep-going</string>\n"
 		   "<string>--config=maintenance.repo</string>\n"
@@ -1879,7 +2030,8 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
 		   "</array>\n"
 		   "<key>StartCalendarInterval</key>\n"
 		   "<array>\n";
-	strbuf_addf(&plist, preamble, name, exec_path, exec_path, frequency);
+	strbuf_addf(&plist, preamble, name, exec_path, exec_path,
+		    get_extra_launchctl_strings(), frequency);
 
 	switch (schedule) {
 	case SCHEDULE_HOURLY:
@@ -1950,6 +2102,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
 
 	free(filename);
 	free(name);
+	free(cmd);
 	strbuf_release(&plist);
 	strbuf_release(&plist2);
 	return 0;
@@ -1974,9 +2127,8 @@ static int launchctl_update_schedule(int run_maintenance, int fd UNUSED)
 
 static int is_schtasks_available(void)
 {
-	const char *cmd = "schtasks";
 	int is_available;
-	if (get_schedule_cmd(&cmd, &is_available))
+	if (get_schedule_cmd("schtasks", &is_available, NULL))
 		return is_available;
 
 #ifdef GIT_WINDOWS_NATIVE
@@ -1995,15 +2147,16 @@ static char *schtasks_task_name(const char *frequency)
 
 static int schtasks_remove_task(enum schedule_priority schedule)
 {
-	const char *cmd = "schtasks";
+	char *cmd;
 	struct child_process child = CHILD_PROCESS_INIT;
 	const char *frequency = get_frequency(schedule);
 	char *name = schtasks_task_name(frequency);
 
-	get_schedule_cmd(&cmd, NULL);
+	get_schedule_cmd("schtasks", NULL, &cmd);
 	strvec_split(&child.args, cmd);
 	strvec_pushl(&child.args, "/delete", "/tn", name, "/f", NULL);
 	free(name);
+	free(cmd);
 
 	return run_command(&child);
 }
@@ -2017,7 +2170,7 @@ static int schtasks_remove_tasks(void)
 
 static int schtasks_schedule_task(const char *exec_path, enum schedule_priority schedule)
 {
-	const char *cmd = "schtasks";
+	char *cmd;
 	int result;
 	struct child_process child = CHILD_PROCESS_INIT;
 	const char *xml;
@@ -2027,10 +2180,10 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
 	struct strbuf tfilename = STRBUF_INIT;
 	int minute = get_random_minute();
 
-	get_schedule_cmd(&cmd, NULL);
+	get_schedule_cmd("schtasks", NULL, &cmd);
 
 	strbuf_addf(&tfilename, "%s/schedule_%s_XXXXXX",
-		    get_git_common_dir(), frequency);
+		    repo_get_common_dir(the_repository), frequency);
 	tfile = xmks_tempfile(tfilename.buf);
 	strbuf_release(&tfilename);
 
@@ -2114,11 +2267,12 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
 	      "<Actions Context=\"Author\">\n"
 	      "<Exec>\n"
 	      "<Command>\"%s\\headless-git.exe\"</Command>\n"
-	      "<Arguments>--exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
+	      "<Arguments>--exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
 	      "</Exec>\n"
 	      "</Actions>\n"
 	      "</Task>\n";
-	fprintf(tfile->fp, xml, exec_path, exec_path, frequency);
+	fprintf(tfile->fp, xml, exec_path, exec_path,
+		get_extra_config_parameters(), frequency);
 	strvec_split(&child.args, cmd);
 	strvec_pushl(&child.args, "/create", "/tn", name, "/f", "/xml",
 				  get_tempfile_path(tfile), NULL);
@@ -2133,6 +2287,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
 
 	delete_tempfile(&tfile);
 	free(name);
+	free(cmd);
 	return result;
 }
 
@@ -2174,21 +2329,28 @@ static int check_crontab_process(const char *cmd)
 
 static int is_crontab_available(void)
 {
-	const char *cmd = "crontab";
+	char *cmd;
 	int is_available;
+	int ret;
 
-	if (get_schedule_cmd(&cmd, &is_available))
-		return is_available;
+	if (get_schedule_cmd("crontab", &is_available, &cmd)) {
+		ret = is_available;
+		goto out;
+	}
 
 #ifdef __APPLE__
 	/*
 	 * macOS has cron, but it requires special permissions and will
 	 * create a UI alert when attempting to run this command.
 	 */
-	return 0;
+	ret = 0;
 #else
-	return check_crontab_process(cmd);
+	ret = check_crontab_process(cmd);
 #endif
+
+out:
+	free(cmd);
+	return ret;
 }
 
 #define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE"
@@ -2196,7 +2358,7 @@ static int is_crontab_available(void)
 
 static int crontab_update_schedule(int run_maintenance, int fd)
 {
-	const char *cmd = "crontab";
+	char *cmd;
 	int result = 0;
 	int in_old_region = 0;
 	struct child_process crontab_list = CHILD_PROCESS_INIT;
@@ -2206,15 +2368,17 @@ static int crontab_update_schedule(int run_maintenance, int fd)
 	struct tempfile *tmpedit = NULL;
 	int minute = get_random_minute();
 
-	get_schedule_cmd(&cmd, NULL);
+	get_schedule_cmd("crontab", NULL, &cmd);
 	strvec_split(&crontab_list.args, cmd);
 	strvec_push(&crontab_list.args, "-l");
 	crontab_list.in = -1;
 	crontab_list.out = dup(fd);
 	crontab_list.git_cmd = 0;
 
-	if (start_command(&crontab_list))
-		return error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
+	if (start_command(&crontab_list)) {
+		result = error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
+		goto out;
+	}
 
 	/* Ignore exit code, as an empty crontab will return error. */
 	finish_command(&crontab_list);
@@ -2259,8 +2423,8 @@ static int crontab_update_schedule(int run_maintenance, int fd)
 			"# replaced in the future by a Git command.\n\n");
 
 		strbuf_addf(&line_format,
-			    "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%s\n",
-			    exec_path, exec_path);
+			    "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%s\n",
+			    exec_path, exec_path, get_extra_config_parameters());
 		fprintf(cron_in, line_format.buf, minute, "1-23", "*", "hourly");
 		fprintf(cron_in, line_format.buf, minute, "0", "1-6", "daily");
 		fprintf(cron_in, line_format.buf, minute, "0", "0", "weekly");
@@ -2284,8 +2448,10 @@ static int crontab_update_schedule(int run_maintenance, int fd)
 		result = error(_("'crontab' died"));
 	else
 		fclose(cron_list);
+
 out:
 	delete_tempfile(&tmpedit);
+	free(cmd);
 	return result;
 }
 
@@ -2308,10 +2474,9 @@ static int real_is_systemd_timer_available(void)
 
 static int is_systemd_timer_available(void)
 {
-	const char *cmd = "systemctl";
 	int is_available;
 
-	if (get_schedule_cmd(&cmd, &is_available))
+	if (get_schedule_cmd("systemctl", &is_available, NULL))
 		return is_available;
 
 	return real_is_systemd_timer_available();
@@ -2460,7 +2625,7 @@ static int systemd_timer_write_service_template(const char *exec_path)
 	       "\n"
 	       "[Service]\n"
 	       "Type=oneshot\n"
-	       "ExecStart=\"%s/git\" --exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%i\n"
+	       "ExecStart=\"%s/git\" --exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%i\n"
 	       "LockPersonality=yes\n"
 	       "MemoryDenyWriteExecute=yes\n"
 	       "NoNewPrivileges=yes\n"
@@ -2470,7 +2635,7 @@ static int systemd_timer_write_service_template(const char *exec_path)
 	       "RestrictSUIDSGID=yes\n"
 	       "SystemCallArchitectures=native\n"
 	       "SystemCallFilter=@system-service\n";
-	if (fprintf(file, unit, exec_path, exec_path) < 0) {
+	if (fprintf(file, unit, exec_path, exec_path, get_extra_config_parameters()) < 0) {
 		error(_("failed to write to '%s'"), filename);
 		fclose(file);
 		goto error;
@@ -2492,9 +2657,10 @@ static int systemd_timer_enable_unit(int enable,
 				     enum schedule_priority schedule,
 				     int minute)
 {
-	const char *cmd = "systemctl";
+	char *cmd = NULL;
 	struct child_process child = CHILD_PROCESS_INIT;
 	const char *frequency = get_frequency(schedule);
+	int ret;
 
 	/*
 	 * Disabling the systemd unit while it is already disabled makes
@@ -2505,20 +2671,25 @@ static int systemd_timer_enable_unit(int enable,
 	 * On the other hand, enabling a systemd unit which is already enabled
 	 * produces no error.
 	 */
-	if (!enable)
+	if (!enable) {
 		child.no_stderr = 1;
-	else if (systemd_timer_write_timer_file(schedule, minute))
-		return -1;
+	} else if (systemd_timer_write_timer_file(schedule, minute)) {
+		ret = -1;
+		goto out;
+	}
 
-	get_schedule_cmd(&cmd, NULL);
+	get_schedule_cmd("systemctl", NULL, &cmd);
 	strvec_split(&child.args, cmd);
 	strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
 		     "--now", NULL);
 	strvec_pushf(&child.args, SYSTEMD_UNIT_FORMAT, frequency, "timer");
 
-	if (start_command(&child))
-		return error(_("failed to start systemctl"));
-	if (finish_command(&child))
+	if (start_command(&child)) {
+		ret = error(_("failed to start systemctl"));
+		goto out;
+	}
+
+	if (finish_command(&child)) {
 		/*
 		 * Disabling an already disabled systemd unit makes
 		 * systemctl fail.
@@ -2526,9 +2697,17 @@ static int systemd_timer_enable_unit(int enable,
 		 *
 		 * Enabling an enabled systemd unit doesn't fail.
 		 */
-		if (enable)
-			return error(_("failed to run systemctl"));
-	return 0;
+		if (enable) {
+			ret = error(_("failed to run systemctl"));
+			goto out;
+		}
+	}
+
+	ret = 0;
+
+out:
+	free(cmd);
+	return ret;
 }
 
 /*
@@ -2788,7 +2967,10 @@ static const char * const builtin_maintenance_usage[] = {
 	NULL,
 };
 
-int cmd_maintenance(int argc, const char **argv, const char *prefix)
+int cmd_maintenance(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
 {
 	parse_opt_subcommand_fn *fn = NULL;
 	struct option builtin_maintenance_options[] = {
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
index 7195a07..6bec0d1 100644
--- a/builtin/get-tar-commit-id.c
+++ b/builtin/get-tar-commit-id.c
@@ -12,7 +12,10 @@ static const char builtin_get_tar_commit_id_usage[] =
 #define RECORDSIZE	(512)
 #define HEADERSIZE (2 * RECORDSIZE)
 
-int cmd_get_tar_commit_id(int argc, const char **argv UNUSED, const char *prefix)
+int cmd_get_tar_commit_id(int argc,
+			  const char **argv UNUSED,
+			  const char *prefix,
+			  struct repository *repo UNUSED)
 {
 	char buffer[HEADERSIZE];
 	struct ustar_header *header = (struct ustar_header *)buffer;
diff --git a/builtin/grep.c b/builtin/grep.c
index dfc3c3e..f17d46a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -3,11 +3,11 @@
  *
  * Copyright (c) 2006 Junio C Hamano
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "gettext.h"
 #include "hex.h"
-#include "repository.h"
 #include "config.h"
 #include "tag.h"
 #include "tree-walk.h"
@@ -888,7 +888,10 @@ static int pattern_callback(const struct option *opt, const char *arg,
 	return 0;
 }
 
-int cmd_grep(int argc, const char **argv, const char *prefix)
+int cmd_grep(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
 {
 	int hit = 0;
 	int cached = 0, untracked = 0, opt_exclude = -1;
@@ -1133,6 +1136,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 					 &oid, &oc)) {
 			if (seen_dashdash)
 				die(_("unable to resolve revision: %s"), arg);
+			object_context_release(&oc);
 			break;
 		}
 
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index c767414..a25f040 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -4,6 +4,7 @@
  * Copyright (C) Linus Torvalds, 2005
  * Copyright (C) Junio C Hamano, 2005
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "config.h"
@@ -84,7 +85,10 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
 	strbuf_release(&unquoted);
 }
 
-int cmd_hash_object(int argc, const char **argv, const char *prefix)
+int cmd_hash_object(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
 {
 	static const char * const hash_object_usage[] = {
 		N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters]\n"
diff --git a/builtin/help.c b/builtin/help.c
index dc1fbe2..4a5a079 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -1,6 +1,8 @@
+
 /*
  * Builtin help command
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "exec-cmd.h"
@@ -52,7 +54,7 @@ static enum help_action {
 	HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION,
 } cmd_mode;
 
-static const char *html_path;
+static char *html_path;
 static int verbose = 1;
 static enum help_format help_format = HELP_FORMAT_NONE;
 static int exclude_guides;
@@ -409,6 +411,7 @@ static int git_help_config(const char *var, const char *value,
 	if (!strcmp(var, "help.htmlpath")) {
 		if (!value)
 			return config_error_nonbool(var);
+		free(html_path);
 		html_path = xstrdup(value);
 		return 0;
 	}
@@ -513,23 +516,24 @@ static void show_info_page(const char *page)
 static void get_html_page_path(struct strbuf *page_path, const char *page)
 {
 	struct stat st;
+	const char *path = html_path;
 	char *to_free = NULL;
 
-	if (!html_path)
-		html_path = to_free = system_path(GIT_HTML_PATH);
+	if (!path)
+		path = to_free = system_path(GIT_HTML_PATH);
 
 	/*
 	 * Check that the page we're looking for exists.
 	 */
-	if (!strstr(html_path, "://")) {
-		if (stat(mkpath("%s/%s.html", html_path, page), &st)
+	if (!strstr(path, "://")) {
+		if (stat(mkpath("%s/%s.html", path, page), &st)
 		    || !S_ISREG(st.st_mode))
 			die("'%s/%s.html': documentation file not found.",
-				html_path, page);
+				path, page);
 	}
 
 	strbuf_init(page_path, 0);
-	strbuf_addf(page_path, "%s/%s.html", html_path, page);
+	strbuf_addf(page_path, "%s/%s.html", path, page);
 	free(to_free);
 }
 
@@ -540,7 +544,7 @@ static void open_html(const char *path)
 
 static void show_html_page(const char *page)
 {
-	struct strbuf page_path; /* it leaks but we exec bellow */
+	struct strbuf page_path; /* it leaks but we exec below */
 
 	get_html_page_path(&page_path, page);
 
@@ -631,7 +635,10 @@ static void opt_mode_usage(int argc, const char *opt_mode,
 	no_help_format(opt_mode, fmt);
 }
 
-int cmd_help(int argc, const char **argv, const char *prefix)
+int cmd_help(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
 {
 	int nongit;
 	enum help_format parsed_help_format;
diff --git a/builtin/hook.c b/builtin/hook.c
index 5234693..367ef3e 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -58,7 +59,7 @@ static int run(int argc, const char **argv, const char *prefix)
 	hook_name = argv[0];
 	if (!ignore_missing)
 		opt.error_if_missing = 1;
-	ret = run_hooks_opt(hook_name, &opt);
+	ret = run_hooks_opt(the_repository, hook_name, &opt);
 	if (ret < 0) /* error() return */
 		ret = 1;
 	return ret;
@@ -66,7 +67,10 @@ static int run(int argc, const char **argv, const char *prefix)
 	usage_with_options(builtin_hook_run_usage, run_options);
 }
 
-int cmd_hook(int argc, const char **argv, const char *prefix)
+int cmd_hook(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
 {
 	parse_opt_subcommand_fn *fn = NULL;
 	struct option builtin_hook_options[] = {
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 763b013..e228c56 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "delta.h"
@@ -1718,7 +1719,10 @@ static void show_pack_info(int stat_only)
 	free(chain_histogram);
 }
 
-int cmd_index_pack(int argc, const char **argv, const char *prefix)
+int cmd_index_pack(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	int i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index;
 	const char *curr_index;
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 582dcf2..7e00d57 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "environment.h"
@@ -11,7 +12,6 @@
 #include "parse-options.h"
 #include "path.h"
 #include "refs.h"
-#include "repository.h"
 #include "setup.h"
 #include "strbuf.h"
 
@@ -70,7 +70,10 @@ static const char *const init_db_usage[] = {
  * On the other hand, it might just make lookup slower and messier. You
  * be the judge.  The default case is to have one DB per managed directory.
  */
-int cmd_init_db(int argc, const char **argv, const char *prefix)
+int cmd_init_db(int argc,
+		const char **argv,
+		const char *prefix,
+		struct repository *repo UNUSED)
 {
 	const char *git_dir;
 	const char *real_git_dir = NULL;
@@ -231,9 +234,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 			set_git_work_tree(work_tree);
 		else
 			set_git_work_tree(git_work_tree_cfg);
-		if (access(get_git_work_tree(), X_OK))
+		if (access(repo_get_work_tree(the_repository), X_OK))
 			die_errno (_("Cannot access work tree '%s'"),
-				   get_git_work_tree());
+				   repo_get_work_tree(the_repository));
 	}
 	else {
 		if (real_git_dir)
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index e6f2245..c5e56e2 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -4,7 +4,7 @@
  * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
  *
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "gettext.h"
 #include "parse-options.h"
@@ -189,7 +189,10 @@ static void interpret_trailers(const struct process_trailer_options *opts,
 	strbuf_release(&sb);
 }
 
-int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
+int cmd_interpret_trailers(int argc,
+			   const char **argv,
+			   const char *prefix,
+			   struct repository *repo UNUSED)
 {
 	struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
 	LIST_HEAD(trailers);
diff --git a/builtin/log.c b/builtin/log.c
index 4d4b60c..368f658 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -4,6 +4,7 @@
  * (C) Copyright 2006 Linus Torvalds
  *		 2006 Junio Hamano
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "config.h"
@@ -37,7 +38,7 @@
 #include "mailmap.h"
 #include "progress.h"
 #include "commit-slab.h"
-#include "repository.h"
+
 #include "commit-reach.h"
 #include "range-diff.h"
 #include "tmp-objdir.h"
@@ -504,13 +505,7 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
 	struct commit *commit;
 	int saved_nrl = 0;
 	int saved_dcctc = 0;
-
-	if (rev->remerge_diff) {
-		rev->remerge_objdir = tmp_objdir_create("remerge-diff");
-		if (!rev->remerge_objdir)
-			die(_("unable to create temporary object directory"));
-		tmp_objdir_replace_primary_odb(rev->remerge_objdir, 1);
-	}
+	int result;
 
 	if (rev->early_output)
 		setup_early_output();
@@ -551,16 +546,12 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
 	rev->diffopt.degraded_cc_to_c = saved_dcctc;
 	rev->diffopt.needed_rename_limit = saved_nrl;
 
-	if (rev->remerge_diff) {
-		tmp_objdir_destroy(rev->remerge_objdir);
-		rev->remerge_objdir = NULL;
-	}
-
+	result = diff_result_code(rev);
 	if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
 	    rev->diffopt.flags.check_failed) {
-		return 02;
+		result = 02;
 	}
-	return diff_result_code(&rev->diffopt);
+	return result;
 }
 
 static int cmd_log_walk(struct rev_info *rev)
@@ -637,7 +628,10 @@ static int git_log_config(const char *var, const char *value,
 	return git_diff_ui_config(var, value, ctx, cb);
 }
 
-int cmd_whatchanged(int argc, const char **argv, const char *prefix)
+int cmd_whatchanged(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
 {
 	struct log_config cfg;
 	struct rev_info rev;
@@ -707,6 +701,7 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
 
 	write_or_die(1, buf, size);
 	object_context_release(&obj_context);
+	free(buf);
 	return 0;
 }
 
@@ -757,7 +752,10 @@ static void show_setup_revisions_tweak(struct rev_info *rev)
 		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 }
 
-int cmd_show(int argc, const char **argv, const char *prefix)
+int cmd_show(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
 {
 	struct log_config cfg;
 	struct rev_info rev;
@@ -873,7 +871,10 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 /*
  * This is equivalent to "git log -g --abbrev-commit --pretty=oneline"
  */
-int cmd_log_reflog(int argc, const char **argv, const char *prefix)
+int cmd_log_reflog(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	struct log_config cfg;
 	struct rev_info rev;
@@ -915,7 +916,10 @@ static void log_setup_revisions_tweak(struct rev_info *rev)
 		diff_merges_default_to_first_parent(rev);
 }
 
-int cmd_log(int argc, const char **argv, const char *prefix)
+int cmd_log(int argc,
+	    const char **argv,
+	    const char *prefix,
+	    struct repository *repo UNUSED)
 {
 	struct log_config cfg;
 	struct rev_info rev;
@@ -1434,6 +1438,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
 	int need_8bit_cte = 0;
 	struct pretty_print_context pp = {0};
 	struct commit *head = list[0];
+	char *to_free = NULL;
 
 	if (!cmit_fmt_is_mail(rev->commit_format))
 		die(_("cover letter needs email format"));
@@ -1455,7 +1460,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
 	}
 
 	if (!branch_name)
-		branch_name = find_branch_name(rev);
+		branch_name = to_free = find_branch_name(rev);
 
 	pp.fmt = CMIT_FMT_EMAIL;
 	pp.date_mode.type = DATE_RFC2822;
@@ -1466,6 +1471,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
 			   encoding, need_8bit_cte, cfg);
 	fprintf(rev->diffopt.file, "%s\n", sb.buf);
 
+	free(to_free);
 	free(pp.after_subject);
 	strbuf_release(&sb);
 
@@ -1825,12 +1831,14 @@ static struct commit *get_base_commit(const struct format_config *cfg,
 				if (die_on_failure) {
 					die(_("failed to find exact merge base"));
 				} else {
+					free_commit_list(merge_base);
 					free(rev);
 					return NULL;
 				}
 			}
 
 			rev[i] = merge_base->item;
+			free_commit_list(merge_base);
 		}
 
 		if (rev_nr % 2)
@@ -1981,7 +1989,10 @@ static void infer_range_diff_ranges(struct strbuf *r1,
 	}
 }
 
-int cmd_format_patch(int argc, const char **argv, const char *prefix)
+int cmd_format_patch(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
 {
 	struct format_config cfg;
 	struct commit *commit;
@@ -2021,6 +2032,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	const char *rfc = NULL;
 	int creation_factor = -1;
 	const char *signature = git_version_string;
+	char *signature_to_free = NULL;
 	char *signature_file_arg = NULL;
 	struct keep_callback_data keep_callback_data = {
 		.cfg = &cfg,
@@ -2441,7 +2453,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
 		if (strbuf_read_file(&buf, signature_file, 128) < 0)
 			die_errno(_("unable to read signature file '%s'"), signature_file);
-		signature = strbuf_detach(&buf, NULL);
+		signature = signature_to_free = strbuf_detach(&buf, NULL);
 	} else if (cfg.signature) {
 		signature = cfg.signature;
 	}
@@ -2546,12 +2558,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 			else
 				print_signature(signature, rev.diffopt.file);
 		}
-		if (output_directory)
+		if (output_directory) {
 			fclose(rev.diffopt.file);
+			rev.diffopt.file = NULL;
+		}
 	}
 	stop_progress(&progress);
 	free(list);
-	free(branch_name);
 	if (ignore_if_in_upstream)
 		free_patch_ids(&ids);
 
@@ -2563,11 +2576,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	strbuf_release(&rdiff_title);
 	free(description_file);
 	free(signature_file_arg);
+	free(signature_to_free);
+	free(branch_name);
 	free(to_free);
 	free(rev.message_id);
 	if (rev.ref_message_ids)
 		string_list_clear(rev.ref_message_ids, 0);
 	free(rev.ref_message_ids);
+	rev.diffopt.no_free = 0;
 	release_revisions(&rev);
 	format_config_release(&cfg);
 	return 0;
@@ -2609,7 +2625,10 @@ static void print_commit(char sign, struct commit *commit, int verbose,
 	}
 }
 
-int cmd_cherry(int argc, const char **argv, const char *prefix)
+int cmd_cherry(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	struct rev_info revs;
 	struct patch_ids ids;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 6eeb5cb..e016b04 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -5,8 +5,8 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
-#include "repository.h"
 #include "config.h"
 #include "convert.h"
 #include "quote.h"
@@ -507,7 +507,7 @@ static int get_common_prefix_len(const char *common_prefix)
 	common_prefix_len = strlen(common_prefix);
 
 	/*
-	 * If the prefix has a trailing slash, strip it so that submodules wont
+	 * If the prefix has a trailing slash, strip it so that submodules won't
 	 * be pruned from the index.
 	 */
 	if (common_prefix[common_prefix_len - 1] == '/')
@@ -561,7 +561,10 @@ static int option_parse_exclude_standard(const struct option *opt,
 	return 0;
 }
 
-int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
+int cmd_ls_files(int argc,
+		 const char **argv,
+		 const char *cmd_prefix,
+		 struct repository *repo UNUSED)
 {
 	int require_work_tree = 0, show_tag = 0, i;
 	char *max_prefix;
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 6da63a6..f723b3b 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "gettext.h"
 #include "hex.h"
@@ -19,17 +20,16 @@ static const char * const ls_remote_usage[] = {
  * Is there one among the list of patterns that match the tail part
  * of the path?
  */
-static int tail_match(const char **pattern, const char *path)
+static int tail_match(const struct strvec *pattern, const char *path)
 {
-	const char *p;
 	char *pathbuf;
 
-	if (!pattern)
+	if (!pattern->nr)
 		return 1; /* no restriction */
 
 	pathbuf = xstrfmt("/%s", path);
-	while ((p = *(pattern++)) != NULL) {
-		if (!wildmatch(p, pathbuf, 0)) {
+	for (size_t i = 0; i < pattern->nr; i++) {
+		if (!wildmatch(pattern->v[i], pathbuf, 0)) {
 			free(pathbuf);
 			return 1;
 		}
@@ -38,7 +38,10 @@ static int tail_match(const char **pattern, const char *path)
 	return 0;
 }
 
-int cmd_ls_remote(int argc, const char **argv, const char *prefix)
+int cmd_ls_remote(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
 {
 	const char *dest = NULL;
 	unsigned flags = 0;
@@ -47,7 +50,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
 	int status = 0;
 	int show_symref_target = 0;
 	const char *uploadpack = NULL;
-	const char **pattern = NULL;
+	struct strvec pattern = STRVEC_INIT;
 	struct transport_ls_refs_options transport_options =
 		TRANSPORT_LS_REFS_OPTIONS_INIT;
 	int i;
@@ -108,13 +111,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
 
 	packet_trace_identity("ls-remote");
 
-	if (argc > 1) {
-		int i;
-		CALLOC_ARRAY(pattern, argc);
-		for (i = 1; i < argc; i++) {
-			pattern[i - 1] = xstrfmt("*/%s", argv[i]);
-		}
-	}
+	for (int i = 1; i < argc; i++)
+		strvec_pushf(&pattern, "*/%s", argv[i]);
 
 	if (flags & REF_TAGS)
 		strvec_push(&transport_options.ref_prefixes, "refs/tags/");
@@ -151,7 +149,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
 		struct ref_array_item *item;
 		if (!check_ref_type(ref, flags))
 			continue;
-		if (!tail_match(pattern, ref->name))
+		if (!tail_match(&pattern, ref->name))
 			continue;
 		item = ref_array_push(&ref_array, ref->name, &ref->old_oid);
 		item->symref = xstrdup_or_null(ref->symref);
@@ -173,5 +171,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
 	if (transport_disconnect(transport))
 		status = 1;
 	transport_ls_refs_options_release(&transport_options);
+
+	strvec_clear(&pattern);
 	return status;
 }
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index bf372c6..8542b5d 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -3,7 +3,9 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
+
 #include "config.h"
 #include "gettext.h"
 #include "hex.h"
@@ -329,7 +331,10 @@ static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
 	},
 };
 
-int cmd_ls_tree(int argc, const char **argv, const char *prefix)
+int cmd_ls_tree(int argc,
+		const char **argv,
+		const char *prefix,
+		struct repository *repo UNUSED)
 {
 	struct object_id oid;
 	struct tree *tree;
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 53a2264..e17dec2 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -2,6 +2,7 @@
  * Another stupid program, this one parsing the headers of an
  * email to figure out authorship and subject
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "environment.h"
@@ -48,7 +49,10 @@ static int parse_opt_quoted_cr(const struct option *opt, const char *arg, int un
 	return 0;
 }
 
-int cmd_mailinfo(int argc, const char **argv, const char *prefix)
+int cmd_mailinfo(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	struct metainfo_charset meta_charset;
 	struct mailinfo mi;
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index fe6dbc5..b8f7150 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -269,7 +269,10 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
 	return ret;
 }
 
-int cmd_mailsplit(int argc, const char **argv, const char *prefix)
+int cmd_mailsplit(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
 {
 	int nr = 0, nr_prec = 4, num = 0;
 	int allow_bare = 0;
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 5a8e729..a20c93b 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "commit.h"
@@ -5,7 +6,6 @@
 #include "hex.h"
 #include "object-name.h"
 #include "parse-options.h"
-#include "repository.h"
 #include "commit-reach.h"
 
 static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
@@ -143,7 +143,10 @@ static int handle_fork_point(int argc, const char **argv)
 	return 0;
 }
 
-int cmd_merge_base(int argc, const char **argv, const char *prefix)
+int cmd_merge_base(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	struct commit **rev;
 	int rev_nr = 0;
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 1f98733..cb42865 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "diff.h"
@@ -53,7 +54,10 @@ static int diff_algorithm_cb(const struct option *opt,
 	return 0;
 }
 
-int cmd_merge_file(int argc, const char **argv, const char *prefix)
+int cmd_merge_file(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	const char *names[3] = { 0 };
 	mmfile_t mmfs[3] = { 0 };
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 0fabe3f..a5b87ee 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -1,7 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "hex.h"
 #include "read-cache-ll.h"
-#include "repository.h"
 #include "run-command.h"
 #include "sparse-index.h"
 
@@ -73,7 +73,10 @@ static void merge_all(void)
 	}
 }
 
-int cmd_merge_index(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_merge_index(int argc,
+		    const char **argv,
+		    const char *prefix UNUSED,
+		    struct repository *repo UNUSED)
 {
 	int i, force_file = 0;
 
diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c
index 932924e..1fcf53f 100644
--- a/builtin/merge-ours.c
+++ b/builtin/merge-ours.c
@@ -7,15 +7,19 @@
  *
  * Pretend we resolved the heads, but declare our tree trumps everybody else.
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "git-compat-util.h"
 #include "builtin.h"
 #include "diff.h"
-#include "repository.h"
+
 
 static const char builtin_merge_ours_usage[] =
 	"git merge-ours <base>... -- HEAD <remote>...";
 
-int cmd_merge_ours(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_merge_ours(int argc,
+		   const char **argv,
+		   const char *prefix UNUSED,
+		   struct repository *repo UNUSED)
 {
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage(builtin_merge_ours_usage);
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 82bebea..1dd2955 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -1,10 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "advice.h"
 #include "gettext.h"
 #include "hash.h"
 #include "merge-recursive.h"
 #include "object-name.h"
-#include "repository.h"
 
 static const char builtin_merge_recursive_usage[] =
 	"git %s <base>... -- <head> <remote> ...";
@@ -21,7 +21,10 @@ static char *better_branch_name(const char *branch)
 	return xstrdup(name ? name : branch);
 }
 
-int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_merge_recursive(int argc,
+			const char **argv,
+			const char *prefix UNUSED,
+			struct repository *repo UNUSED)
 {
 	struct object_id bases[21];
 	unsigned bases_count = 0;
@@ -31,7 +34,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED)
 	char *better1, *better2;
 	struct commit *result;
 
-	init_merge_options(&o, the_repository);
+	init_basic_merge_options(&o, the_repository);
 	if (argv[0] && ends_with(argv[0], "-subtree"))
 		o.subtree_shift = "";
 
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index dab2fdc..c5ed472 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "tree-walk.h"
 #include "xdiff-interface.h"
@@ -10,7 +11,6 @@
 #include "object-name.h"
 #include "object-store-ll.h"
 #include "parse-options.h"
-#include "repository.h"
 #include "blob.h"
 #include "merge-blobs.h"
 #include "quote.h"
@@ -526,13 +526,17 @@ static int real_merge(struct merge_tree_options *o,
 	return !result.clean; /* result.clean < 0 handled above */
 }
 
-int cmd_merge_tree(int argc, const char **argv, const char *prefix)
+int cmd_merge_tree(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	struct merge_tree_options o = { .show_messages = -1 };
 	struct strvec xopts = STRVEC_INIT;
 	int expected_remaining_argc;
 	int original_argc;
 	const char *merge_base = NULL;
+	int ret;
 
 	const char * const merge_tree_usage[] = {
 		N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
@@ -571,7 +575,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
 	};
 
 	/* Init merge options */
-	init_merge_options(&o.merge_options, the_repository);
+	init_ui_merge_options(&o.merge_options, the_repository);
 
 	/* Parse arguments */
 	original_argc = argc - 1; /* ignoring argv[0] */
@@ -625,7 +629,9 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
 			strbuf_list_free(split);
 		}
 		strbuf_release(&buf);
-		return 0;
+
+		ret = 0;
+		goto out;
 	}
 
 	/* Figure out which mode to use */
@@ -664,7 +670,11 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
 
 	/* Do the relevant type of merge */
 	if (o.mode == MODE_REAL)
-		return real_merge(&o, merge_base, argv[0], argv[1], prefix);
+		ret = real_merge(&o, merge_base, argv[0], argv[1], prefix);
 	else
-		return trivial_merge(argv[0], argv[1], argv[2]);
+		ret = trivial_merge(argv[0], argv[1], argv[2]);
+
+out:
+	strvec_clear(&xopts);
+	return ret;
 }
diff --git a/builtin/merge.c b/builtin/merge.c
index 9fba27d..84d0f36 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -5,8 +5,9 @@
  *
  * Based on git-merge.sh by Junio C Hamano.
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
+
 #include "abspath.h"
 #include "advice.h"
 #include "config.h"
@@ -17,6 +18,7 @@
 #include "object-name.h"
 #include "parse-options.h"
 #include "lockfile.h"
+#include "repository.h"
 #include "run-command.h"
 #include "hook.h"
 #include "diff.h"
@@ -478,7 +480,7 @@ static void finish(struct commit *head_commit,
 	}
 
 	/* Run a post-merge hook */
-	run_hooks_l("post-merge", squash ? "1" : "0", NULL);
+	run_hooks_l(the_repository, "post-merge", squash ? "1" : "0", NULL);
 
 	if (new_head)
 		apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
@@ -695,7 +697,9 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
 
 static void write_tree_trivial(struct object_id *oid)
 {
-	if (write_index_as_tree(oid, the_repository->index, get_index_file(), 0, NULL))
+	if (write_index_as_tree(oid, the_repository->index,
+				repo_get_index_file(the_repository),
+				0, NULL))
 		die(_("git write-tree failed to write a tree"));
 }
 
@@ -724,7 +728,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 			return 2;
 		}
 
-		init_merge_options(&o, the_repository);
+		init_ui_merge_options(&o, the_repository);
 		if (!strcmp(strategy, "subtree"))
 			o.subtree_shift = "";
 
@@ -757,7 +761,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 		}
 		if (write_locked_index(the_repository->index, &lock,
 				       COMMIT_LOCK | SKIP_IF_UNCHANGED))
-			die(_("unable to write %s"), get_index_file());
+			die(_("unable to write %s"), repo_get_index_file(the_repository));
 		return clean ? 0 : 1;
 	} else {
 		return try_merge_command(the_repository,
@@ -839,7 +843,7 @@ static void write_merge_heads(struct commit_list *);
 static void prepare_to_commit(struct commit_list *remoteheads)
 {
 	struct strbuf msg = STRBUF_INIT;
-	const char *index_file = get_index_file();
+	const char *index_file = repo_get_index_file(the_repository);
 
 	if (!no_verify) {
 		int invoked_hook;
@@ -855,7 +859,8 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 		if (invoked_hook)
 			discard_index(the_repository->index);
 	}
-	read_index_from(the_repository->index, index_file, get_git_dir());
+	read_index_from(the_repository->index, index_file,
+			repo_get_git_dir(the_repository));
 	strbuf_addbuf(&msg, &merge_msg);
 	if (squash)
 		BUG("the control must not reach here under --squash");
@@ -878,8 +883,8 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 		append_signoff(&msg, ignored_log_message_bytes(msg.buf, msg.len), 0);
 	write_merge_heads(remoteheads);
 	write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
-	if (run_commit_hook(0 < option_edit, get_index_file(), NULL,
-			    "prepare-commit-msg",
+	if (run_commit_hook(0 < option_edit, repo_get_index_file(the_repository),
+			    NULL, "prepare-commit-msg",
 			    git_path_merge_msg(the_repository), "merge", NULL))
 		abort_commit(remoteheads, NULL);
 	if (0 < option_edit) {
@@ -887,7 +892,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 			abort_commit(remoteheads, NULL);
 	}
 
-	if (!no_verify && run_commit_hook(0 < option_edit, get_index_file(),
+	if (!no_verify && run_commit_hook(0 < option_edit, repo_get_index_file(the_repository),
 					  NULL, "commit-msg",
 					  git_path_merge_msg(the_repository), NULL))
 		abort_commit(remoteheads, NULL);
@@ -1275,7 +1280,10 @@ static int merging_a_throwaway_tag(struct commit *commit)
 	return is_throwaway_tag;
 }
 
-int cmd_merge(int argc, const char **argv, const char *prefix)
+int cmd_merge(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
 {
 	struct object_id result_tree, stash, head_oid;
 	struct commit *head_commit;
@@ -1347,7 +1355,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 					REF_NO_DEREF);
 
 		/* Invoke 'git reset --merge' */
-		ret = cmd_reset(nargc, nargv, prefix);
+		ret = cmd_reset(nargc, nargv, prefix, the_repository);
 
 		if (!is_null_oid(&stash_oid)) {
 			oid_to_hex_r(stash_oid_hex, &stash_oid);
@@ -1379,7 +1387,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			die(_("There is no merge in progress (MERGE_HEAD missing)."));
 
 		/* Invoke 'git commit' */
-		ret = cmd_commit(nargc, nargv, prefix);
+		ret = cmd_commit(nargc, nargv, prefix, the_repository);
 		goto done;
 	}
 
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 4767f1a..6e188dc 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "gettext.h"
 #include "hex.h"
@@ -18,8 +19,7 @@ static int option_strict = 1;
 static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
 
 static int mktag_fsck_error_func(struct fsck_options *o UNUSED,
-				 const struct object_id *oid UNUSED,
-				 enum object_type object_type UNUSED,
+				 void *fsck_report UNUSED,
 				 enum fsck_msg_type msg_type,
 				 enum fsck_msg_id msg_id UNUSED,
 				 const char *message)
@@ -72,7 +72,10 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
 	return ret;
 }
 
-int cmd_mktag(int argc, const char **argv, const char *prefix)
+int cmd_mktag(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
 {
 	static struct option builtin_mktag_options[] = {
 		OPT_BOOL(0, "strict", &option_strict,
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 9a22d4e..3c16faa 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -3,6 +3,7 @@
  *
  * Copyright (c) Junio C Hamano, 2006, 2009
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "gettext.h"
 #include "hex.h"
@@ -150,7 +151,10 @@ static void mktree_line(char *buf, int nul_term_line, int allow_missing)
 	free(to_free);
 }
 
-int cmd_mktree(int ac, const char **av, const char *prefix)
+int cmd_mktree(int ac,
+	       const char **av,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	struct strbuf sb = STRBUF_INIT;
 	struct object_id oid;
@@ -199,5 +203,6 @@ int cmd_mktree(int ac, const char **av, const char *prefix)
 		used=0; /* reset tree entry buffer for re-use in batch mode */
 	}
 	strbuf_release(&sb);
+
 	return 0;
 }
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 9cf1a32..d159ed1 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -1,7 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "config.h"
-#include "environment.h"
 #include "gettext.h"
 #include "parse-options.h"
 #include "midx.h"
@@ -9,6 +9,7 @@
 #include "trace2.h"
 #include "object-store-ll.h"
 #include "replace-object.h"
+#include "repository.h"
 
 #define BUILTIN_MIDX_WRITE_USAGE \
 	N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]" \
@@ -63,7 +64,7 @@ static int parse_object_dir(const struct option *opt, const char *arg,
 	char **value = opt->value;
 	free(*value);
 	if (unset)
-		*value = xstrdup(get_object_directory());
+		*value = xstrdup(repo_get_object_directory(the_repository));
 	else
 		*value = real_pathdup(arg, 1);
 	return 0;
@@ -129,6 +130,8 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
 			MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
 		OPT_BIT(0, "progress", &opts.flags,
 			N_("force progress reporting"), MIDX_PROGRESS),
+		OPT_BIT(0, "incremental", &opts.flags,
+			N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
 		OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
 			 N_("write multi-pack index containing only given indexes")),
 		OPT_FILENAME(0, "refs-snapshot", &opts.refs_snapshot,
@@ -265,8 +268,10 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv,
 			   (size_t)opts.batch_size, opts.flags);
 }
 
-int cmd_multi_pack_index(int argc, const char **argv,
-			 const char *prefix)
+int cmd_multi_pack_index(int argc,
+			 const char **argv,
+			 const char *prefix,
+			 struct repository *repo UNUSED)
 {
 	int res;
 	parse_opt_subcommand_fn *fn = NULL;
diff --git a/builtin/mv.c b/builtin/mv.c
index 6c69033..472a278 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2006 Johannes Schindelin
  */
+#define USE_THE_REPOSITORY_VARIABLE
 
 #include "builtin.h"
 #include "abspath.h"
@@ -18,7 +19,7 @@
 #include "string-list.h"
 #include "parse-options.h"
 #include "read-cache-ll.h"
-#include "repository.h"
+
 #include "setup.h"
 #include "strvec.h"
 #include "submodule.h"
@@ -178,7 +179,10 @@ static void remove_empty_src_dirs(const char **src_dir, size_t src_dir_nr)
 	strbuf_release(&a_src_dir);
 }
 
-int cmd_mv(int argc, const char **argv, const char *prefix)
+int cmd_mv(int argc,
+	   const char **argv,
+	   const char *prefix,
+	   struct repository *repo UNUSED)
 {
 	int i, flags, gitmodules_modified = 0;
 	int verbose = 0, show_only = 0, force = 0, ignore_errors = 0, ignore_sparse = 0;
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 70e9ec4..765eb20 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -1,8 +1,8 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
-#include "repository.h"
 #include "config.h"
 #include "commit.h"
 #include "tag.h"
@@ -65,7 +65,7 @@ static void set_commit_cutoff(struct commit *commit)
 static void adjust_cutoff_timestamp_for_slop(void)
 {
 	if (cutoff) {
-		/* check for undeflow */
+		/* check for underflow */
 		if (cutoff > TIME_MIN + CUTOFF_DATE_SLOP)
 			cutoff = cutoff - CUTOFF_DATE_SLOP;
 		else
@@ -337,7 +337,7 @@ static int cmp_by_tag_and_age(const void *a_, const void *b_)
 	return a->taggerdate != b->taggerdate;
 }
 
-static int name_ref(const char *path, const struct object_id *oid,
+static int name_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
 		    int flags UNUSED, void *cb_data)
 {
 	struct object *o = parse_object(the_repository, oid);
@@ -558,7 +558,10 @@ static void name_rev_line(char *p, struct name_ref_data *data)
 	strbuf_release(&buf);
 }
 
-int cmd_name_rev(int argc, const char **argv, const char *prefix)
+int cmd_name_rev(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	struct mem_pool string_pool;
 	struct object_array revs = OBJECT_ARRAY_INIT;
@@ -677,7 +680,9 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 				  always, allow_undefined, data.name_only);
 	}
 
-	UNLEAK(string_pool);
-	UNLEAK(revs);
+	string_list_clear(&data.ref_filters, 0);
+	string_list_clear(&data.exclude_filters, 0);
+	mem_pool_discard(&string_pool, 0);
+	object_array_clear(&revs);
 	return 0;
 }
diff --git a/builtin/notes.c b/builtin/notes.c
index 4cc5bfe..8c26e45 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -6,7 +6,7 @@
  * Based on git-notes.sh by Johannes Schindelin,
  * and builtin/tag.c by Kristian Høgsberg and Carlos Rica.
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "editor.h"
@@ -17,7 +17,7 @@
 #include "object-name.h"
 #include "object-store-ll.h"
 #include "path.h"
-#include "repository.h"
+
 #include "pretty.h"
 #include "refs.h"
 #include "exec-cmd.h"
@@ -805,7 +805,7 @@ static int merge_commit(struct notes_merge_options *o)
 {
 	struct strbuf msg = STRBUF_INIT;
 	struct object_id oid, parent_oid;
-	struct notes_tree *t;
+	struct notes_tree t = {0};
 	struct commit *partial;
 	struct pretty_print_context pretty_ctx;
 	void *local_ref_to_free;
@@ -828,8 +828,7 @@ static int merge_commit(struct notes_merge_options *o)
 	else
 		oidclr(&parent_oid, the_repository->hash_algo);
 
-	CALLOC_ARRAY(t, 1);
-	init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
+	init_notes(&t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
 
 	o->local_ref = local_ref_to_free =
 		refs_resolve_refdup(get_main_ref_store(the_repository),
@@ -837,7 +836,7 @@ static int merge_commit(struct notes_merge_options *o)
 	if (!o->local_ref)
 		die(_("failed to resolve NOTES_MERGE_REF"));
 
-	if (notes_merge_commit(o, t, partial, &oid))
+	if (notes_merge_commit(o, &t, partial, &oid))
 		die(_("failed to finalize notes merge"));
 
 	/* Reuse existing commit message in reflog message */
@@ -851,7 +850,7 @@ static int merge_commit(struct notes_merge_options *o)
 			is_null_oid(&parent_oid) ? NULL : &parent_oid,
 			0, UPDATE_REFS_DIE_ON_ERR);
 
-	free_notes(t);
+	free_notes(&t);
 	strbuf_release(&msg);
 	ret = merge_abort(o);
 	free(local_ref_to_free);
@@ -866,7 +865,7 @@ static int git_config_get_notes_strategy(const char *key,
 	if (git_config_get_string(key, &value))
 		return 1;
 	if (parse_notes_merge_strategy(value, strategy))
-		git_die_config(key, _("unknown notes merge strategy %s"), value);
+		git_die_config(the_repository, key, _("unknown notes merge strategy %s"), value);
 
 	free(value);
 	return 0;
@@ -898,6 +897,7 @@ static int merge(int argc, const char **argv, const char *prefix)
 			      1, PARSE_OPT_NONEG),
 		OPT_END()
 	};
+	char *notes_ref;
 
 	argc = parse_options(argc, argv, prefix, options,
 			     git_notes_merge_usage, 0);
@@ -925,7 +925,8 @@ static int merge(int argc, const char **argv, const char *prefix)
 	if (do_commit)
 		return merge_commit(&o);
 
-	o.local_ref = default_notes_ref();
+	notes_ref = default_notes_ref(the_repository);
+	o.local_ref = notes_ref;
 	strbuf_addstr(&remote_ref, argv[0]);
 	expand_loose_notes_ref(&remote_ref);
 	o.remote_ref = remote_ref.buf;
@@ -954,7 +955,7 @@ static int merge(int argc, const char **argv, const char *prefix)
 	}
 
 	strbuf_addf(&msg, "notes: Merged notes from %s into %s",
-		    remote_ref.buf, default_notes_ref());
+		    remote_ref.buf, notes_ref);
 	strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */
 
 	result = notes_merge(&o, t, &result_oid);
@@ -962,7 +963,7 @@ static int merge(int argc, const char **argv, const char *prefix)
 	if (result >= 0) /* Merge resulted (trivially) in result_oid */
 		/* Update default notes ref with new commit */
 		refs_update_ref(get_main_ref_store(the_repository), msg.buf,
-				default_notes_ref(), &result_oid, NULL, 0,
+				notes_ref, &result_oid, NULL, 0,
 				UPDATE_REFS_DIE_ON_ERR);
 	else { /* Merge has unresolved conflicts */
 		struct worktree **worktrees;
@@ -974,14 +975,14 @@ static int merge(int argc, const char **argv, const char *prefix)
 		/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
 		worktrees = get_worktrees();
 		wt = find_shared_symref(worktrees, "NOTES_MERGE_REF",
-					default_notes_ref());
+					notes_ref);
 		if (wt)
 			die(_("a notes merge into %s is already in-progress at %s"),
-			    default_notes_ref(), wt->path);
+			    notes_ref, wt->path);
 		free_worktrees(worktrees);
-		if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", default_notes_ref(), NULL))
+		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)"),
-			    default_notes_ref());
+			    notes_ref);
 		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"),
@@ -989,6 +990,7 @@ static int merge(int argc, const char **argv, const char *prefix)
 	}
 
 	free_notes(t);
+	free(notes_ref);
 	strbuf_release(&remote_ref);
 	strbuf_release(&msg);
 	return result < 0; /* return non-zero on conflicts */
@@ -1085,6 +1087,7 @@ static int prune(int argc, const char **argv, const char *prefix)
 static int get_ref(int argc, const char **argv, const char *prefix)
 {
 	struct option options[] = { OPT_END() };
+	char *notes_ref;
 	argc = parse_options(argc, argv, prefix, options,
 			     git_notes_get_ref_usage, 0);
 
@@ -1093,11 +1096,16 @@ static int get_ref(int argc, const char **argv, const char *prefix)
 		usage_with_options(git_notes_get_ref_usage, options);
 	}
 
-	puts(default_notes_ref());
+	notes_ref = default_notes_ref(the_repository);
+	puts(notes_ref);
+	free(notes_ref);
 	return 0;
 }
 
-int cmd_notes(int argc, const char **argv, const char *prefix)
+int cmd_notes(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
 {
 	const char *override_notes_ref = NULL;
 	parse_opt_subcommand_fn *fn = NULL;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index f395488..0fc0680 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1,8 +1,8 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
-#include "repository.h"
 #include "config.h"
 #include "attr.h"
 #include "object.h"
@@ -771,7 +771,7 @@ static enum write_one_status write_one(struct hashfile *f,
 	return WRITE_ONE_WRITTEN;
 }
 
-static int mark_tagged(const char *path UNUSED, const struct object_id *oid,
+static int mark_tagged(const char *path UNUSED, const char *referent UNUSED, const struct object_id *oid,
 		       int flag UNUSED, void *cb_data UNUSED)
 {
 	struct object_id peeled;
@@ -1072,7 +1072,7 @@ static void write_reused_pack_one(struct packed_git *reuse_packfile,
 		fixup = find_reused_offset(offset) -
 			find_reused_offset(base_offset);
 		if (fixup) {
-			unsigned char ofs_header[10];
+			unsigned char ofs_header[MAX_PACK_OBJECT_HEADER];
 			unsigned i, ofs_len;
 			off_t ofs = offset - base_offset - fixup;
 
@@ -1191,6 +1191,7 @@ static void write_reused_pack(struct bitmapped_pack *reuse_packfile,
 		size_t pos = (i * BITS_IN_EWORD);
 
 		for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
+			uint32_t pack_pos;
 			if ((word >> offset) == 0)
 				break;
 
@@ -1199,14 +1200,41 @@ static void write_reused_pack(struct bitmapped_pack *reuse_packfile,
 				continue;
 			if (pos + offset >= reuse_packfile->bitmap_pos + reuse_packfile->bitmap_nr)
 				goto done;
-			/*
-			 * Can use bit positions directly, even for MIDX
-			 * bitmaps. See comment in try_partial_reuse()
-			 * for why.
-			 */
-			write_reused_pack_one(reuse_packfile->p,
-					      pos + offset - reuse_packfile->bitmap_pos,
-					      f, pack_start, &w_curs);
+
+			if (reuse_packfile->bitmap_pos) {
+				/*
+				 * When doing multi-pack reuse on a
+				 * non-preferred pack, translate bit positions
+				 * from the MIDX pseudo-pack order back to their
+				 * pack-relative positions before attempting
+				 * reuse.
+				 */
+				struct multi_pack_index *m = reuse_packfile->from_midx;
+				uint32_t midx_pos;
+				off_t pack_ofs;
+
+				if (!m)
+					BUG("non-zero bitmap position without MIDX");
+
+				midx_pos = pack_pos_to_midx(m, pos + offset);
+				pack_ofs = nth_midxed_offset(m, midx_pos);
+
+				if (offset_to_pack_pos(reuse_packfile->p,
+						       pack_ofs, &pack_pos) < 0)
+					BUG("could not find expected object at offset %"PRIuMAX" in pack %s",
+					    (uintmax_t)pack_ofs,
+					    pack_basename(reuse_packfile->p));
+			} else {
+				/*
+				 * Can use bit positions directly, even for MIDX
+				 * bitmaps. See comment in try_partial_reuse()
+				 * for why.
+				 */
+				pack_pos = pos + offset;
+			}
+
+			write_reused_pack_one(reuse_packfile->p, pack_pos, f,
+					      pack_start, &w_curs);
 			display_progress(progress_state, ++written);
 		}
 	}
@@ -1342,10 +1370,10 @@ static void write_pack_file(void)
 
 			if (write_bitmap_index) {
 				bitmap_writer_init(&bitmap_writer,
-						   the_repository);
+						   the_repository, &to_pack);
 				bitmap_writer_set_checksum(&bitmap_writer, hash);
 				bitmap_writer_build_type_index(&bitmap_writer,
-					&to_pack, written_list, nr_written);
+							       written_list);
 			}
 
 			if (cruft)
@@ -1367,10 +1395,10 @@ static void write_pack_file(void)
 				bitmap_writer_select_commits(&bitmap_writer,
 							     indexed_commits,
 							     indexed_commits_nr);
-				if (bitmap_writer_build(&bitmap_writer, &to_pack) < 0)
+				if (bitmap_writer_build(&bitmap_writer) < 0)
 					die(_("failed to write bitmap index"));
 				bitmap_writer_finish(&bitmap_writer,
-						     written_list, nr_written,
+						     written_list,
 						     tmpname.buf, write_bitmap_options);
 				bitmap_writer_free(&bitmap_writer);
 				write_bitmap_index = 0;
@@ -3129,7 +3157,7 @@ static void add_tag_chain(const struct object_id *oid)
 	}
 }
 
-static int add_ref_tag(const char *tag UNUSED, const struct object_id *oid,
+static int add_ref_tag(const char *tag UNUSED, const char *referent UNUSED, const struct object_id *oid,
 		       int flag UNUSED, void *cb_data UNUSED)
 {
 	struct object_id peeled;
@@ -3940,7 +3968,7 @@ static int add_loose_object(const struct object_id *oid, const char *path,
  */
 static void add_unreachable_loose_objects(void)
 {
-	for_each_loose_file_in_objdir(get_object_directory(),
+	for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
 				      add_loose_object,
 				      NULL, NULL, NULL);
 }
@@ -4076,6 +4104,7 @@ static void record_recent_commit(struct commit *commit, void *data UNUSED)
 }
 
 static int mark_bitmap_preferred_tip(const char *refname,
+				     const char *referent UNUSED,
 				     const struct object_id *oid,
 				     int flags UNUSED,
 				     void *data UNUSED)
@@ -4283,7 +4312,10 @@ static int option_parse_cruft_expiration(const struct option *opt UNUSED,
 	return 0;
 }
 
-int cmd_pack_objects(int argc, const char **argv, const char *prefix)
+int cmd_pack_objects(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
 {
 	int use_internal_rev_list = 0;
 	int shallow = 0;
@@ -4640,6 +4672,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 cleanup:
 	clear_packing_data(&to_pack);
 	list_objects_filter_release(&filter_options);
+	string_list_clear(&keep_pack_list, 0);
 	strvec_clear(&rp);
 
 	return 0;
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index dd9bf35..81f4494 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -5,11 +5,12 @@
 * This file is licensed under the GPL v2.
 *
 */
+#define USE_THE_REPOSITORY_VARIABLE
 
 #include "builtin.h"
 #include "gettext.h"
 #include "hex.h"
-#include "repository.h"
+
 #include "packfile.h"
 #include "object-store-ll.h"
 
@@ -561,11 +562,8 @@ static void load_all(void)
 	}
 }
 
-int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED)
-{
-	int i;
-	int i_still_use_this = 0;
-	struct pack_list *min = NULL, *red, *pl;
+int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED) {
+	int i; int i_still_use_this = 0; struct pack_list *min = NULL, *red, *pl;
 	struct llist *ignore;
 	struct object_id *oid;
 	char buf[GIT_MAX_HEXSZ + 2]; /* hex hash + \n + \0 */
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index db40825..2d83c1e 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -1,9 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
 #include "parse-options.h"
 #include "refs.h"
-#include "repository.h"
 #include "revision.h"
 
 static char const * const pack_refs_usage[] = {
@@ -11,7 +11,10 @@ static char const * const pack_refs_usage[] = {
 	NULL
 };
 
-int cmd_pack_refs(int argc, const char **argv, const char *prefix)
+int cmd_pack_refs(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
 {
 	struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
 	struct string_list included_refs = STRING_LIST_INIT_NODUP;
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index d790ae6..93b398e 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
@@ -214,7 +215,10 @@ static int git_patch_id_config(const char *var, const char *value,
 	return git_default_config(var, value, ctx, cb);
 }
 
-int cmd_patch_id(int argc, const char **argv, const char *prefix)
+int cmd_patch_id(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	/* if nothing is set, default to unstable */
 	struct patch_id_opts config = {0, 0};
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index ca3578e..4d63f26 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -8,7 +8,10 @@ static const char * const prune_packed_usage[] = {
 	NULL
 };
 
-int cmd_prune_packed(int argc, const char **argv, const char *prefix)
+int cmd_prune_packed(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
 {
 	int opts = isatty(2) ? PRUNE_PACKED_VERBOSE : 0;
 	const struct option prune_packed_options[] = {
diff --git a/builtin/prune.c b/builtin/prune.c
index 57fe314..2b1de01 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "commit.h"
 #include "diff.h"
@@ -147,7 +148,10 @@ static void remove_temporary_files(const char *path)
 	closedir(dir);
 }
 
-int cmd_prune(int argc, const char **argv, const char *prefix)
+int cmd_prune(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
 {
 	struct rev_info revs;
 	int exclude_promisor_objects = 0;
@@ -193,12 +197,12 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
 		revs.exclude_promisor_objects = 1;
 	}
 
-	for_each_loose_file_in_objdir(get_object_directory(), prune_object,
-				      prune_cruft, prune_subdir, &revs);
+	for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+				      prune_object, prune_cruft, prune_subdir, &revs);
 
 	prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0);
-	remove_temporary_files(get_object_directory());
-	s = mkpathdup("%s/pack", get_object_directory());
+	remove_temporary_files(repo_get_object_directory(the_repository));
+	s = mkpathdup("%s/pack", repo_get_object_directory(the_repository));
 	remove_temporary_files(s);
 	free(s);
 
diff --git a/builtin/pull.c b/builtin/pull.c
index 4c54d81..388ef3d 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -6,6 +6,7 @@
  * Fetch one or more remote refs and merge it/them into the current HEAD.
  */
 
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "advice.h"
 #include "config.h"
@@ -84,7 +85,7 @@ static const char *opt_squash;
 static const char *opt_commit;
 static const char *opt_edit;
 static const char *cleanup_arg;
-static const char *opt_ff;
+static char *opt_ff;
 static const char *opt_verify_signatures;
 static const char *opt_verify;
 static int opt_autostash = -1;
@@ -977,7 +978,10 @@ static void show_advice_pull_non_ff(void)
 		 "invocation.\n"));
 }
 
-int cmd_pull(int argc, const char **argv, const char *prefix)
+int cmd_pull(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repository UNUSED)
 {
 	const char *repo, **refspecs;
 	struct oid_array merge_heads = OID_ARRAY_INIT;
@@ -1024,8 +1028,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 		 * "--rebase" can override a config setting of
 		 * pull.ff=only.
 		 */
-		if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only"))
-			opt_ff = "--ff";
+		if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) {
+			free(opt_ff);
+			opt_ff = xstrdup("--ff");
+		}
 	}
 
 	if (opt_rebase < 0)
@@ -1135,7 +1141,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 		if (can_ff) {
 			/* we can fast-forward this without invoking rebase */
-			opt_ff = "--ff-only";
+			free(opt_ff);
+			opt_ff = xstrdup("--ff-only");
 			ret = run_merge();
 		} else {
 			ret = run_rebase(&newbase, &upstream);
diff --git a/builtin/push.c b/builtin/push.c
index 7a67398..59d4485 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -1,6 +1,7 @@
 /*
  * "git push"
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "advice.h"
 #include "branch.h"
@@ -13,7 +14,6 @@
 #include "transport.h"
 #include "parse-options.h"
 #include "pkt-line.h"
-#include "repository.h"
 #include "submodule.h"
 #include "submodule-config.h"
 #include "send-pack.h"
@@ -72,13 +72,15 @@ static void refspec_append_mapped(struct refspec *refspec, const char *ref,
 	const char *branch_name;
 
 	if (remote->push.nr) {
-		struct refspec_item query;
-		memset(&query, 0, sizeof(struct refspec_item));
-		query.src = matched->name;
+		struct refspec_item query = {
+			.src = matched->name,
+		};
+
 		if (!query_refspecs(&remote->push, &query) && query.dst) {
 			refspec_appendf(refspec, "%s%s:%s",
 					query.force ? "+" : "",
 					query.src, query.dst);
+			free(query.dst);
 			return;
 		}
 	}
@@ -546,7 +548,10 @@ static int git_push_config(const char *k, const char *v,
 	return git_default_config(k, v, ctx, NULL);
 }
 
-int cmd_push(int argc, const char **argv, const char *prefix)
+int cmd_push(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repository UNUSED)
 {
 	int flags = 0;
 	int tags = 0;
@@ -664,6 +669,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 	rc = do_push(flags, push_options, remote);
 	string_list_clear(&push_options_cmdline, 0);
 	string_list_clear(&push_options_config, 0);
+	clear_cas_option(&cas);
 	if (rc == -1)
 		usage_with_options(push_usage, options);
 	else
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index f02cbac..1b33ab6 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -1,10 +1,11 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "gettext.h"
 #include "object-name.h"
 #include "parse-options.h"
 #include "range-diff.h"
 #include "config.h"
-#include "repository.h"
+
 
 static const char * const builtin_range_diff_usage[] = {
 N_("git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"),
@@ -13,7 +14,10 @@ N_("git range-diff [<options>] <base> <old-tip> <new-tip>"),
 NULL
 };
 
-int cmd_range_diff(int argc, const char **argv, const char *prefix)
+int cmd_range_diff(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	struct diff_options diffopt = { NULL };
 	struct strvec other_arg = STRVEC_INIT;
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index a8cf850..d2a807a 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -16,7 +16,6 @@
 #include "cache-tree.h"
 #include "unpack-trees.h"
 #include "parse-options.h"
-#include "repository.h"
 #include "resolve-undo.h"
 #include "setup.h"
 #include "sparse-index.h"
@@ -108,7 +107,10 @@ static int git_read_tree_config(const char *var, const char *value,
 	return git_default_config(var, value, ctx, cb);
 }
 
-int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
+int cmd_read_tree(int argc,
+		  const char **argv,
+		  const char *cmd_prefix,
+		  struct repository *repo UNUSED)
 {
 	int i, stage = 0;
 	struct object_id oid;
diff --git a/builtin/rebase.c b/builtin/rebase.c
index e3a8e74..bbaca3c 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -3,8 +3,9 @@
  *
  * Copyright (c) 2018 Pratik Karki
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
+
 #include "abspath.h"
 #include "environment.h"
 #include "gettext.h"
@@ -186,6 +187,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
 	replay.committer_date_is_author_date =
 					opts->committer_date_is_author_date;
 	replay.ignore_date = opts->ignore_date;
+	free(replay.gpg_sign);
 	replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
 	replay.reflog_action = xstrdup(opts->reflog_action);
 	if (opts->strategy)
@@ -526,6 +528,23 @@ static int rebase_write_basic_state(struct rebase_options *opts)
 	return 0;
 }
 
+static int cleanup_autostash(struct rebase_options *opts)
+{
+	int ret;
+	struct strbuf dir = STRBUF_INIT;
+	const char *path = state_dir_path("autostash", opts);
+
+	if (!file_exists(path))
+		return 0;
+	ret = apply_autostash(path);
+	strbuf_addstr(&dir, opts->state_dir);
+	if (remove_dir_recursively(&dir, 0))
+		ret = error_errno(_("could not remove '%s'"), opts->state_dir);
+	strbuf_release(&dir);
+
+	return ret;
+}
+
 static int finish_rebase(struct rebase_options *opts)
 {
 	struct strbuf dir = STRBUF_INIT;
@@ -1062,7 +1081,10 @@ static int check_exec_cmd(const char *cmd)
 	return 0;
 }
 
-int cmd_rebase(int argc, const char **argv, const char *prefix)
+int cmd_rebase(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	struct rebase_options options = REBASE_OPTIONS_INIT;
 	const char *branch_name;
@@ -1726,7 +1748,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (require_clean_work_tree(the_repository, "rebase",
 				    _("Please commit or stash them."), 1, 1)) {
 		ret = -1;
-		goto cleanup;
+		goto cleanup_autostash;
 	}
 
 	/*
@@ -1749,7 +1771,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			if (options.switch_to) {
 				ret = checkout_up_to_date(&options);
 				if (ret)
-					goto cleanup;
+					goto cleanup_autostash;
 			}
 
 			if (!(options.flags & REBASE_NO_QUIET))
@@ -1774,9 +1796,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 	/* If a hook exists, give it a chance to interrupt*/
 	if (!ok_to_skip_pre_rebase &&
-	    run_hooks_l("pre-rebase", options.upstream_arg,
-			argc ? argv[0] : NULL, NULL))
-		die(_("The pre-rebase hook refused to rebase."));
+	    run_hooks_l(the_repository, "pre-rebase", options.upstream_arg,
+			argc ? argv[0] : NULL, NULL)) {
+		ret = error(_("The pre-rebase hook refused to rebase."));
+		goto cleanup_autostash;
+	}
 
 	if (options.flags & REBASE_DIFFSTAT) {
 		struct diff_options opts;
@@ -1821,9 +1845,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
 	ropts.head_msg = msg.buf;
 	ropts.default_reflog_action = options.reflog_action;
-	if (reset_head(the_repository, &ropts))
-		die(_("Could not detach HEAD"));
-	strbuf_release(&msg);
+	if (reset_head(the_repository, &ropts)) {
+		ret = error(_("Could not detach HEAD"));
+		goto cleanup_autostash;
+	}
 
 	/*
 	 * If the onto is a proper descendant of the tip of the branch, then
@@ -1851,9 +1876,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 cleanup:
 	strbuf_release(&buf);
+	strbuf_release(&msg);
 	strbuf_release(&revisions);
 	rebase_options_release(&options);
 	free(squash_onto_name);
 	free(keep_base_onto_name);
 	return !!ret;
+
+cleanup_autostash:
+	ret |= !!cleanup_autostash(&options);
+	goto cleanup;
 }
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 339524a..536d227 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1,6 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
-#include "repository.h"
+
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
@@ -300,7 +301,7 @@ static void show_ref(const char *path, const struct object_id *oid)
 	}
 }
 
-static int show_ref_cb(const char *path_full, const struct object_id *oid,
+static int show_ref_cb(const char *path_full, const char *referent UNUSED, const struct object_id *oid,
 		       int flag UNUSED, void *data)
 {
 	struct oidset *seen = data;
@@ -339,12 +340,26 @@ static void show_one_alternate_ref(const struct object_id *oid,
 static void write_head_info(void)
 {
 	static struct oidset seen = OIDSET_INIT;
+	struct strvec excludes_vector = STRVEC_INIT;
+	const char **exclude_patterns;
+
+	/*
+	 * We need access to the reference names both with and without their
+	 * namespace and thus cannot use `refs_for_each_namespaced_ref()`. We
+	 * thus have to adapt exclude patterns to carry the namespace prefix
+	 * ourselves.
+	 */
+	exclude_patterns = get_namespaced_exclude_patterns(
+		hidden_refs_to_excludes(&hidden_refs),
+		get_git_namespace(), &excludes_vector);
 
 	refs_for_each_fullref_in(get_main_ref_store(the_repository), "",
-				 hidden_refs_to_excludes(&hidden_refs),
-				 show_ref_cb, &seen);
+				 exclude_patterns, show_ref_cb, &seen);
 	for_each_alternate_ref(show_one_alternate_ref, &seen);
+
 	oidset_clear(&seen);
+	strvec_clear(&excludes_vector);
+
 	if (!sent_capabilities)
 		show_ref("capabilities^{}", null_oid());
 
@@ -792,7 +807,7 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
 	struct child_process proc = CHILD_PROCESS_INIT;
 	struct async muxer;
 	int code;
-	const char *hook_path = find_hook(hook_name);
+	const char *hook_path = find_hook(the_repository, hook_name);
 
 	if (!hook_path)
 		return 0;
@@ -922,7 +937,7 @@ static int run_update_hook(struct command *cmd)
 {
 	struct child_process proc = CHILD_PROCESS_INIT;
 	int code;
-	const char *hook_path = find_hook("update");
+	const char *hook_path = find_hook(the_repository, "update");
 
 	if (!hook_path)
 		return 0;
@@ -1098,7 +1113,7 @@ static int run_proc_receive_hook(struct command *commands,
 	int hook_use_push_options = 0;
 	int version = 0;
 	int code;
-	const char *hook_path = find_hook("proc-receive");
+	const char *hook_path = find_hook(the_repository, "proc-receive");
 
 	if (!hook_path) {
 		rp_error("cannot find hook 'proc-receive'");
@@ -1324,7 +1339,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
 }
 
 /*
- * NEEDSWORK: we should consolidate various implementions of "are we
+ * NEEDSWORK: we should consolidate various implementations of "are we
  * on an unborn branch?" test into one, and make the unified one more
  * robust. !get_sha1() based check used here and elsewhere would not
  * allow us to tell an unborn branch from corrupt ref, for example.
@@ -1409,7 +1424,7 @@ static const char *push_to_checkout(unsigned char *hash,
 	strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
 	strvec_pushv(&opt.env, env->v);
 	strvec_push(&opt.args, hash_to_hex(hash));
-	if (run_hooks_opt(push_to_checkout_hook, &opt))
+	if (run_hooks_opt(the_repository, push_to_checkout_hook, &opt))
 		return "push-to-checkout hook declined";
 	else
 		return NULL;
@@ -1618,7 +1633,7 @@ static void run_update_post_hook(struct command *commands)
 	struct child_process proc = CHILD_PROCESS_INIT;
 	const char *hook;
 
-	hook = find_hook("post-update");
+	hook = find_hook(the_repository, "post-update");
 	if (!hook)
 		return;
 
@@ -2480,7 +2495,10 @@ static int delete_only(struct command *commands)
 	return 1;
 }
 
-int cmd_receive_pack(int argc, const char **argv, const char *prefix)
+int cmd_receive_pack(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
 {
 	int advertise_refs = 0;
 	struct command *commands;
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 0d2ff95..22df683 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -1,7 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
-#include "repository.h"
 #include "revision.h"
 #include "reachable.h"
 #include "wildmatch.h"
@@ -244,7 +244,7 @@ static int cmd_reflog_show(int argc, const char **argv, const char *prefix)
 		      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
 		      PARSE_OPT_KEEP_UNKNOWN_OPT);
 
-	return cmd_log_reflog(argc, argv, prefix);
+	return cmd_log_reflog(argc, argv, prefix, the_repository);
 }
 
 static int show_reflog(const char *refname, void *cb_data UNUSED)
@@ -447,7 +447,10 @@ static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
  * main "reflog"
  */
 
-int cmd_reflog(int argc, const char **argv, const char *prefix)
+int cmd_reflog(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repository)
 {
 	parse_opt_subcommand_fn *fn = NULL;
 	struct option options[] = {
@@ -466,5 +469,5 @@ int cmd_reflog(int argc, const char **argv, const char *prefix)
 	if (fn)
 		return fn(argc - 1, argv + 1, prefix);
 	else
-		return cmd_log_reflog(argc, argv, prefix);
+		return cmd_log_reflog(argc, argv, prefix, repository);
 }
diff --git a/builtin/refs.c b/builtin/refs.c
index 46dcd15..24978a7 100644
--- a/builtin/refs.c
+++ b/builtin/refs.c
@@ -1,12 +1,17 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
+#include "config.h"
+#include "fsck.h"
 #include "parse-options.h"
 #include "refs.h"
-#include "repository.h"
 #include "strbuf.h"
 
 #define REFS_MIGRATE_USAGE \
 	N_("git refs migrate --ref-format=<format> [--dry-run]")
 
+#define REFS_VERIFY_USAGE \
+	N_("git refs verify [--strict] [--verbose]")
+
 static int cmd_refs_migrate(int argc, const char **argv, const char *prefix)
 {
 	const char * const migrate_usage[] = {
@@ -58,15 +63,47 @@ static int cmd_refs_migrate(int argc, const char **argv, const char *prefix)
 	return err;
 }
 
-int cmd_refs(int argc, const char **argv, const char *prefix)
+static int cmd_refs_verify(int argc, const char **argv, const char *prefix)
+{
+	struct fsck_options fsck_refs_options = FSCK_REFS_OPTIONS_DEFAULT;
+	const char * const verify_usage[] = {
+		REFS_VERIFY_USAGE,
+		NULL,
+	};
+	struct option options[] = {
+		OPT_BOOL(0, "verbose", &fsck_refs_options.verbose, N_("be verbose")),
+		OPT_BOOL(0, "strict", &fsck_refs_options.strict, N_("enable strict checking")),
+		OPT_END(),
+	};
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, options, verify_usage, 0);
+	if (argc)
+		usage(_("'git refs verify' takes no arguments"));
+
+	git_config(git_fsck_config, &fsck_refs_options);
+	prepare_repo_settings(the_repository);
+
+	ret = refs_fsck(get_main_ref_store(the_repository), &fsck_refs_options);
+
+	fsck_options_clear(&fsck_refs_options);
+	return ret;
+}
+
+int cmd_refs(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
 {
 	const char * const refs_usage[] = {
 		REFS_MIGRATE_USAGE,
+		REFS_VERIFY_USAGE,
 		NULL,
 	};
 	parse_opt_subcommand_fn *fn = NULL;
 	struct option opts[] = {
 		OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate),
+		OPT_SUBCOMMAND("verify", &fn, cmd_refs_verify),
 		OPT_END(),
 	};
 
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index 282782e..33c8ae0 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -195,7 +195,10 @@ static int command_loop(const char *child)
 	}
 }
 
-int cmd_remote_ext(int argc, const char **argv, const char *prefix)
+int cmd_remote_ext(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	BUG_ON_NON_EMPTY_PREFIX(prefix);
 
diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c
index 9020fab..ae896ed 100644
--- a/builtin/remote-fd.c
+++ b/builtin/remote-fd.c
@@ -53,7 +53,10 @@ static void command_loop(int input_fd, int output_fd)
 	}
 }
 
-int cmd_remote_fd(int argc, const char **argv, const char *prefix)
+int cmd_remote_fd(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
 {
 	int input_fd = -1;
 	int output_fd = -1;
diff --git a/builtin/remote.c b/builtin/remote.c
index 0829249..76670dd 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -164,6 +165,7 @@ static int add(int argc, const char **argv, const char *prefix)
 	struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
 	const char *name, *url;
 	int i;
+	int result = 0;
 
 	struct option options[] = {
 		OPT_BOOL('f', "fetch", &fetch, N_("fetch the remote branches")),
@@ -230,8 +232,10 @@ static int add(int argc, const char **argv, const char *prefix)
 			       fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
 	}
 
-	if (fetch && fetch_remote(name))
-		return 1;
+	if (fetch && fetch_remote(name)) {
+		result = 1;
+		goto out;
+	}
 
 	if (master) {
 		strbuf_reset(&buf);
@@ -241,14 +245,15 @@ static int add(int argc, const char **argv, const char *prefix)
 		strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master);
 
 		if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote add"))
-			return error(_("Could not setup master '%s'"), master);
+			result = error(_("Could not setup master '%s'"), master);
 	}
 
+out:
 	strbuf_release(&buf);
 	strbuf_release(&buf2);
 	string_list_clear(&track, 0);
 
-	return 0;
+	return result;
 }
 
 struct branch_info {
@@ -258,7 +263,7 @@ struct branch_info {
 	char *push_remote_name;
 };
 
-static struct string_list branch_list = STRING_LIST_INIT_NODUP;
+static struct string_list branch_list = STRING_LIST_INIT_DUP;
 
 static const char *abbrev_ref(const char *name, const char *prefix)
 {
@@ -292,8 +297,8 @@ static int config_read_branches(const char *key, const char *value,
 		type = PUSH_REMOTE;
 	else
 		return 0;
-	name = xmemdupz(key, key_len);
 
+	name = xmemdupz(key, key_len);
 	item = string_list_insert(&branch_list, name);
 
 	if (!item->util)
@@ -337,6 +342,7 @@ static int config_read_branches(const char *key, const char *value,
 		BUG("unexpected type=%d", type);
 	}
 
+	free(name);
 	return 0;
 }
 
@@ -543,6 +549,7 @@ struct branches_for_remote {
 };
 
 static int add_branch_for_removal(const char *refname,
+				  const char *referent UNUSED,
 				  const struct object_id *oid UNUSED,
 				  int flags UNUSED, void *cb_data)
 {
@@ -554,13 +561,16 @@ static int add_branch_for_removal(const char *refname,
 	refspec.dst = (char *)refname;
 	if (remote_find_tracking(branches->remote, &refspec))
 		return 0;
+	free(refspec.src);
 
 	/* don't delete a branch if another remote also uses it */
 	for (kr = branches->keep->list; kr; kr = kr->next) {
 		memset(&refspec, 0, sizeof(refspec));
 		refspec.dst = (char *)refname;
-		if (!remote_find_tracking(kr->remote, &refspec))
+		if (!remote_find_tracking(kr->remote, &refspec)) {
+			free(refspec.src);
 			return 0;
+		}
 	}
 
 	/* don't delete non-remote-tracking refs */
@@ -585,7 +595,7 @@ struct rename_info {
 	uint32_t symrefs_nr;
 };
 
-static int read_remote_branches(const char *refname,
+static int read_remote_branches(const char *refname, const char *referent UNUSED,
 				const struct object_id *oid UNUSED,
 				int flags UNUSED, void *cb_data)
 {
@@ -667,7 +677,11 @@ static int config_read_push_default(const char *key, const char *value,
 static void handle_push_default(const char* old_name, const char* new_name)
 {
 	struct push_default_info push_default = {
-		old_name, CONFIG_SCOPE_UNKNOWN, STRBUF_INIT, -1 };
+		.old_name = old_name,
+		.scope = CONFIG_SCOPE_UNKNOWN,
+		.origin = STRBUF_INIT,
+		.linenr = -1,
+	};
 	git_config(config_read_push_default, &push_default);
 	if (push_default.scope >= CONFIG_SCOPE_COMMAND)
 		; /* pass */
@@ -687,6 +701,8 @@ static void handle_push_default(const char* old_name, const char* new_name)
 			push_default.origin.buf, push_default.linenr,
 			old_name);
 	}
+
+	strbuf_release(&push_default.origin);
 }
 
 
@@ -704,6 +720,7 @@ static int mv(int argc, const char **argv, const char *prefix)
 	struct rename_info rename;
 	int i, refs_renamed_nr = 0, refspec_updated = 0;
 	struct progress *progress = NULL;
+	int result = 0;
 
 	argc = parse_options(argc, argv, prefix, options,
 			     builtin_remote_rename_usage, 0);
@@ -736,9 +753,11 @@ static int mv(int argc, const char **argv, const char *prefix)
 
 	strbuf_addf(&buf, "remote.%s", rename.old_name);
 	strbuf_addf(&buf2, "remote.%s", rename.new_name);
-	if (git_config_rename_section(buf.buf, buf2.buf) < 1)
-		return error(_("Could not rename config section '%s' to '%s'"),
-				buf.buf, buf2.buf);
+	if (repo_config_rename_section(the_repository, buf.buf, buf2.buf) < 1) {
+		result = error(_("Could not rename config section '%s' to '%s'"),
+			       buf.buf, buf2.buf);
+		goto out;
+	}
 
 	if (oldremote->fetch.raw_nr) {
 		strbuf_reset(&buf);
@@ -784,7 +803,7 @@ static int mv(int argc, const char **argv, const char *prefix)
 	}
 
 	if (!refspec_updated)
-		return 0;
+		goto out;
 
 	/*
 	 * First remove symrefs, then rename the rest, finally create
@@ -850,11 +869,16 @@ static int mv(int argc, const char **argv, const char *prefix)
 		display_progress(progress, ++refs_renamed_nr);
 	}
 	stop_progress(&progress);
-	string_list_clear(&remote_branches, 1);
 
 	handle_push_default(rename.old_name, rename.new_name);
 
-	return 0;
+out:
+	string_list_clear(&remote_branches, 1);
+	strbuf_release(&old_remote_context);
+	strbuf_release(&buf);
+	strbuf_release(&buf2);
+	strbuf_release(&buf3);
+	return result;
 }
 
 static int rm(int argc, const char **argv, const char *prefix)
@@ -944,12 +968,21 @@ static int rm(int argc, const char **argv, const char *prefix)
 
 	if (!result) {
 		strbuf_addf(&buf, "remote.%s", remote->name);
-		if (git_config_rename_section(buf.buf, NULL) < 1)
-			return error(_("Could not remove config section '%s'"), buf.buf);
+		if (repo_config_rename_section(the_repository, buf.buf, NULL) < 1) {
+			result = error(_("Could not remove config section '%s'"), buf.buf);
+			goto out;
+		}
 
 		handle_push_default(remote->name, NULL);
 	}
 
+out:
+	for (struct known_remote *r = known_remotes.list; r;) {
+		struct known_remote *next = r->next;
+		free(r);
+		r = next;
+	}
+	strbuf_release(&buf);
 	return result;
 }
 
@@ -971,6 +1004,7 @@ static void free_remote_ref_states(struct ref_states *states)
 }
 
 static int append_ref_to_tracked_list(const char *refname,
+				      const char *referent UNUSED,
 				      const struct object_id *oid UNUSED,
 				      int flags, void *cb_data)
 {
@@ -982,8 +1016,10 @@ static int append_ref_to_tracked_list(const char *refname,
 
 	memset(&refspec, 0, sizeof(refspec));
 	refspec.dst = (char *)refname;
-	if (!remote_find_tracking(states->remote, &refspec))
+	if (!remote_find_tracking(states->remote, &refspec)) {
 		string_list_append(&states->tracked, abbrev_branch(refspec.src));
+		free(refspec.src);
+	}
 
 	return 0;
 }
@@ -1726,7 +1762,10 @@ static int set_url(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
-int cmd_remote(int argc, const char **argv, const char *prefix)
+int cmd_remote(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	parse_opt_subcommand_fn *fn = NULL;
 	struct option options[] = {
diff --git a/builtin/repack.c b/builtin/repack.c
index f0317fa..d6bb37e 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "dir.h"
@@ -85,17 +86,34 @@ static int repack_config(const char *var, const char *value,
 		run_update_server_info = git_config_bool(var, value);
 		return 0;
 	}
-	if (!strcmp(var, "repack.cruftwindow"))
+	if (!strcmp(var, "repack.cruftwindow")) {
+		free(cruft_po_args->window);
 		return git_config_string(&cruft_po_args->window, var, value);
-	if (!strcmp(var, "repack.cruftwindowmemory"))
+	}
+	if (!strcmp(var, "repack.cruftwindowmemory")) {
+		free(cruft_po_args->window_memory);
 		return git_config_string(&cruft_po_args->window_memory, var, value);
-	if (!strcmp(var, "repack.cruftdepth"))
+	}
+	if (!strcmp(var, "repack.cruftdepth")) {
+		free(cruft_po_args->depth);
 		return git_config_string(&cruft_po_args->depth, var, value);
-	if (!strcmp(var, "repack.cruftthreads"))
+	}
+	if (!strcmp(var, "repack.cruftthreads")) {
+		free(cruft_po_args->threads);
 		return git_config_string(&cruft_po_args->threads, var, value);
+	}
 	return git_default_config(var, value, ctx, cb);
 }
 
+static void pack_objects_args_release(struct pack_objects_args *args)
+{
+	free(args->window);
+	free(args->window_memory);
+	free(args->depth);
+	free(args->threads);
+	list_objects_filter_release(&args->filter_options);
+}
+
 struct existing_packs {
 	struct string_list kept_packs;
 	struct string_list non_kept_packs;
@@ -425,9 +443,11 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
 
 		free(promisor_name);
 	}
+
 	fclose(out);
 	if (finish_command(&cmd))
 		die(_("could not finish pack-objects to repack promisor objects"));
+	strbuf_release(&line);
 }
 
 struct pack_geometry {
@@ -667,6 +687,7 @@ struct midx_snapshot_ref_data {
 };
 
 static int midx_snapshot_ref_one(const char *refname UNUSED,
+				 const char *referent UNUSED,
 				 const struct object_id *oid,
 				 int flag UNUSED, void *_data)
 {
@@ -731,14 +752,23 @@ static void midx_included_packs(struct string_list *include,
 				struct pack_geometry *geometry)
 {
 	struct string_list_item *item;
+	struct strbuf buf = STRBUF_INIT;
 
-	for_each_string_list_item(item, &existing->kept_packs)
-		string_list_insert(include, xstrfmt("%s.idx", item->string));
-	for_each_string_list_item(item, names)
-		string_list_insert(include, xstrfmt("pack-%s.idx", item->string));
+	for_each_string_list_item(item, &existing->kept_packs) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "%s.idx", item->string);
+		string_list_insert(include, buf.buf);
+	}
+
+	for_each_string_list_item(item, names) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "pack-%s.idx", item->string);
+		string_list_insert(include, buf.buf);
+	}
+
 	if (geometry->split_factor) {
-		struct strbuf buf = STRBUF_INIT;
 		uint32_t i;
+
 		for (i = geometry->split; i < geometry->pack_nr; i++) {
 			struct packed_git *p = geometry->pack[i];
 
@@ -753,17 +783,21 @@ static void midx_included_packs(struct string_list *include,
 			if (!p->pack_local)
 				continue;
 
+			strbuf_reset(&buf);
 			strbuf_addstr(&buf, pack_basename(p));
 			strbuf_strip_suffix(&buf, ".pack");
 			strbuf_addstr(&buf, ".idx");
 
-			string_list_insert(include, strbuf_detach(&buf, NULL));
+			string_list_insert(include, buf.buf);
 		}
 	} else {
 		for_each_string_list_item(item, &existing->non_kept_packs) {
 			if (pack_is_marked_for_deletion(item))
 				continue;
-			string_list_insert(include, xstrfmt("%s.idx", item->string));
+
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "%s.idx", item->string);
+			string_list_insert(include, buf.buf);
 		}
 	}
 
@@ -783,8 +817,13 @@ static void midx_included_packs(struct string_list *include,
 		 */
 		if (pack_is_marked_for_deletion(item))
 			continue;
-		string_list_insert(include, xstrfmt("%s.idx", item->string));
+
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "%s.idx", item->string);
+		string_list_insert(include, buf.buf);
 	}
+
+	strbuf_release(&buf);
 }
 
 static int write_midx_included_packs(struct string_list *include,
@@ -1115,7 +1154,10 @@ static const char *find_pack_prefix(const char *packdir, const char *packtmp)
 	return pack_prefix;
 }
 
-int cmd_repack(int argc, const char **argv, const char *prefix)
+int cmd_repack(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
 	struct string_list_item *item;
@@ -1131,12 +1173,16 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	const char *unpack_unreachable = NULL;
 	int keep_unreachable = 0;
 	struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
-	struct pack_objects_args po_args = {NULL};
-	struct pack_objects_args cruft_po_args = {NULL};
+	struct pack_objects_args po_args = { 0 };
+	struct pack_objects_args cruft_po_args = { 0 };
 	int write_midx = 0;
 	const char *cruft_expiration = NULL;
 	const char *expire_to = NULL;
 	const char *filter_to = NULL;
+	const char *opt_window = NULL;
+	const char *opt_window_memory = NULL;
+	const char *opt_depth = NULL;
+	const char *opt_threads = NULL;
 
 	struct option builtin_repack_options[] = {
 		OPT_BIT('a', NULL, &pack_everything,
@@ -1170,13 +1216,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 				N_("with -A, do not loosen objects older than this")),
 		OPT_BOOL('k', "keep-unreachable", &keep_unreachable,
 				N_("with -a, repack unreachable objects")),
-		OPT_STRING(0, "window", &po_args.window, N_("n"),
+		OPT_STRING(0, "window", &opt_window, N_("n"),
 				N_("size of the window used for delta compression")),
-		OPT_STRING(0, "window-memory", &po_args.window_memory, N_("bytes"),
+		OPT_STRING(0, "window-memory", &opt_window_memory, N_("bytes"),
 				N_("same as the above, but limit memory size instead of entries count")),
-		OPT_STRING(0, "depth", &po_args.depth, N_("n"),
+		OPT_STRING(0, "depth", &opt_depth, N_("n"),
 				N_("limits the maximum delta depth")),
-		OPT_STRING(0, "threads", &po_args.threads, N_("n"),
+		OPT_STRING(0, "threads", &opt_threads, N_("n"),
 				N_("limits the maximum number of threads")),
 		OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size,
 				N_("maximum size of each packfile")),
@@ -1203,6 +1249,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, builtin_repack_options,
 				git_repack_usage, 0);
 
+	po_args.window = xstrdup_or_null(opt_window);
+	po_args.window_memory = xstrdup_or_null(opt_window_memory);
+	po_args.depth = xstrdup_or_null(opt_depth);
+	po_args.threads = xstrdup_or_null(opt_threads);
+
 	if (delete_redundant && repository_format_precious_objects)
 		die(_("cannot delete packs in a precious-objects repo"));
 
@@ -1217,10 +1268,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 		if (!write_midx &&
 		    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
 			write_bitmaps = 0;
-	} else if (write_bitmaps &&
-		   git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0) &&
-		   git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP, 0)) {
-		write_bitmaps = 0;
 	}
 	if (pack_kept_objects < 0)
 		pack_kept_objects = write_bitmaps > 0 && !write_midx;
@@ -1243,7 +1290,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	if (write_midx && write_bitmaps) {
 		struct strbuf path = STRBUF_INIT;
 
-		strbuf_addf(&path, "%s/%s_XXXXXX", get_object_directory(),
+		strbuf_addf(&path, "%s/%s_XXXXXX", repo_get_object_directory(the_repository),
 			    "bitmap-ref-tips");
 
 		refs_snapshot = xmks_tempfile(path.buf);
@@ -1252,7 +1299,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 		strbuf_release(&path);
 	}
 
-	packdir = mkpathdup("%s/pack", get_object_directory());
+	packdir = mkpathdup("%s/pack", repo_get_object_directory(the_repository));
 	packtmp_name = xstrfmt(".tmp-%d-pack", (int)getpid());
 	packtmp = mkpathdup("%s/%s", packdir, packtmp_name);
 
@@ -1372,13 +1419,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 		const char *pack_prefix = find_pack_prefix(packdir, packtmp);
 
 		if (!cruft_po_args.window)
-			cruft_po_args.window = po_args.window;
+			cruft_po_args.window = xstrdup_or_null(po_args.window);
 		if (!cruft_po_args.window_memory)
-			cruft_po_args.window_memory = po_args.window_memory;
+			cruft_po_args.window_memory = xstrdup_or_null(po_args.window_memory);
 		if (!cruft_po_args.depth)
-			cruft_po_args.depth = po_args.depth;
+			cruft_po_args.depth = xstrdup_or_null(po_args.depth);
 		if (!cruft_po_args.threads)
-			cruft_po_args.threads = po_args.threads;
+			cruft_po_args.threads = xstrdup_or_null(po_args.threads);
 		if (!cruft_po_args.max_pack_size)
 			cruft_po_args.max_pack_size = po_args.max_pack_size;
 
@@ -1479,7 +1526,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 		mark_packs_for_deletion(&existing, &names);
 
 	if (write_midx) {
-		struct string_list include = STRING_LIST_INIT_NODUP;
+		struct string_list include = STRING_LIST_INIT_DUP;
 		midx_included_packs(&include, &existing, &names, &geometry);
 
 		ret = write_midx_included_packs(&include, &geometry, &names,
@@ -1520,16 +1567,19 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 
 	if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) {
 		unsigned flags = 0;
-		if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP, 0))
-			flags |= MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX;
-		write_midx_file(get_object_directory(), NULL, NULL, flags);
+		if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0))
+			flags |= MIDX_WRITE_INCREMENTAL;
+		write_midx_file(repo_get_object_directory(the_repository),
+				NULL, NULL, flags);
 	}
 
 cleanup:
+	string_list_clear(&keep_pack_list, 0);
 	string_list_clear(&names, 1);
 	existing_packs_release(&existing);
 	free_pack_geometry(&geometry);
-	list_objects_filter_release(&po_args.filter_options);
+	pack_objects_args_release(&po_args);
+	pack_objects_args_release(&cruft_po_args);
 
 	return ret;
 }
diff --git a/builtin/replace.c b/builtin/replace.c
index 1ef833c..a44f4e7 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -7,11 +7,10 @@
  * and Carlos Rica <jasampler@gmail.com> that was itself based on
  * git-tag.sh and mktag.c by Linus Torvalds.
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "editor.h"
-#include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "refs.h"
@@ -22,7 +21,6 @@
 #include "object-name.h"
 #include "object-store-ll.h"
 #include "replace-object.h"
-#include "repository.h"
 #include "tag.h"
 #include "wildmatch.h"
 
@@ -49,6 +47,7 @@ struct show_data {
 };
 
 static int show_reference(const char *refname,
+			  const char *referent UNUSED,
 			  const struct object_id *oid,
 			  int flag UNUSED, void *cb_data)
 {
@@ -513,7 +512,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
 
 static int convert_graft_file(int force)
 {
-	const char *graft_file = get_graft_file(the_repository);
+	const char *graft_file = repo_get_graft_file(the_repository);
 	FILE *fp = fopen_or_warn(graft_file, "r");
 	struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT;
 	struct strvec args = STRVEC_INIT;
@@ -544,7 +543,10 @@ static int convert_graft_file(int force)
 	return -1;
 }
 
-int cmd_replace(int argc, const char **argv, const char *prefix)
+int cmd_replace(int argc,
+		const char **argv,
+		const char *prefix,
+		struct repository *repo UNUSED)
 {
 	int force = 0;
 	int raw = 0;
diff --git a/builtin/replay.c b/builtin/replay.c
index 0448326..2d12a4e 100644
--- a/builtin/replay.c
+++ b/builtin/replay.c
@@ -4,6 +4,7 @@
 
 #include "git-compat-util.h"
 
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "environment.h"
 #include "hex.h"
@@ -151,7 +152,7 @@ static void get_ref_information(struct rev_cmdline_info *cmd_info,
 
 static void determine_replay_mode(struct rev_cmdline_info *cmd_info,
 				  const char *onto_name,
-				  const char **advance_name,
+				  char **advance_name,
 				  struct commit **onto,
 				  struct strset **update_refs)
 {
@@ -174,6 +175,7 @@ static void determine_replay_mode(struct rev_cmdline_info *cmd_info,
 		*onto = peel_committish(*advance_name);
 		if (repo_dwim_ref(the_repository, *advance_name, strlen(*advance_name),
 			     &oid, &fullname, 0) == 1) {
+			free(*advance_name);
 			*advance_name = fullname;
 		} else {
 			die(_("argument to --advance must be a reference"));
@@ -197,6 +199,7 @@ static void determine_replay_mode(struct rev_cmdline_info *cmd_info,
 		if (negative_refs_complete) {
 			struct hashmap_iter iter;
 			struct strmap_entry *entry;
+			const char *last_key = NULL;
 
 			if (rinfo.negative_refexprs == 0)
 				die(_("all positive revisions given must be references"));
@@ -208,8 +211,11 @@ static void determine_replay_mode(struct rev_cmdline_info *cmd_info,
 			/* Only one entry, but we have to loop to get it */
 			strset_for_each_entry(&rinfo.negative_refs,
 					      &iter, entry) {
-				*advance_name = entry->key;
+				last_key = entry->key;
 			}
+
+			free(*advance_name);
+			*advance_name = xstrdup_or_null(last_key);
 		} else { /* positive_refs_complete */
 			if (rinfo.negative_refexprs > 1)
 				die(_("cannot implicitly determine correct base for --onto"));
@@ -269,9 +275,13 @@ static struct commit *pick_regular_commit(struct commit *pickme,
 	return create_commit(result->tree, pickme, replayed_base);
 }
 
-int cmd_replay(int argc, const char **argv, const char *prefix)
+int cmd_replay(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
-	const char *advance_name = NULL;
+	const char *advance_name_opt = NULL;
+	char *advance_name = NULL;
 	struct commit *onto = NULL;
 	const char *onto_name = NULL;
 	int contained = 0;
@@ -292,7 +302,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
 		NULL
 	};
 	struct option replay_options[] = {
-		OPT_STRING(0, "advance", &advance_name,
+		OPT_STRING(0, "advance", &advance_name_opt,
 			   N_("branch"),
 			   N_("make replay advance given branch")),
 		OPT_STRING(0, "onto", &onto_name,
@@ -306,14 +316,15 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, replay_options, replay_usage,
 			     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
 
-	if (!onto_name && !advance_name) {
+	if (!onto_name && !advance_name_opt) {
 		error(_("option --onto or --advance is mandatory"));
 		usage_with_options(replay_usage, replay_options);
 	}
 
-	if (advance_name && contained)
+	if (advance_name_opt && contained)
 		die(_("options '%s' and '%s' cannot be used together"),
 		    "--advance", "--contained");
+	advance_name = xstrdup_or_null(advance_name_opt);
 
 	repo_init_revisions(the_repository, &revs, prefix);
 
@@ -377,7 +388,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 	}
 
-	init_merge_options(&merge_opt, the_repository);
+	init_basic_merge_options(&merge_opt, the_repository);
 	memset(&result, 0, sizeof(result));
 	merge_opt.show_rename_progress = 0;
 	last_commit = onto;
@@ -441,6 +452,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
 
 cleanup:
 	release_revisions(&revs);
+	free(advance_name);
 
 	/* Return */
 	if (ret < 0)
diff --git a/builtin/rerere.c b/builtin/rerere.c
index b2efc6f..f7143c3 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -1,8 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
 #include "parse-options.h"
-#include "repository.h"
+
 #include "string-list.h"
 #include "rerere.h"
 #include "xdiff/xdiff.h"
@@ -48,7 +49,10 @@ static int diff_two(const char *file1, const char *label1,
 	return ret;
 }
 
-int cmd_rerere(int argc, const char **argv, const char *prefix)
+int cmd_rerere(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	struct string_list merge_rr = STRING_LIST_INIT_DUP;
 	int i, autoupdate = -1, flags = 0;
@@ -73,11 +77,17 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
 
 	if (!strcmp(argv[0], "forget")) {
 		struct pathspec pathspec;
+		int ret;
+
 		if (argc < 2)
 			warning(_("'git rerere forget' without paths is deprecated"));
 		parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD,
 			       prefix, argv + 1);
-		return rerere_forget(the_repository, &pathspec);
+
+		ret = rerere_forget(the_repository, &pathspec);
+
+		clear_pathspec(&pathspec);
+		return ret;
 	}
 
 	if (!strcmp(argv[0], "clear")) {
diff --git a/builtin/reset.c b/builtin/reset.c
index 5f941fb..7154f88 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "advice.h"
 #include "config.h"
@@ -26,6 +26,7 @@
 #include "object-name.h"
 #include "parse-options.h"
 #include "path.h"
+#include "repository.h"
 #include "unpack-trees.h"
 #include "cache-tree.h"
 #include "setup.h"
@@ -330,7 +331,10 @@ static int git_reset_config(const char *var, const char *value,
 	return git_default_config(var, value, ctx, cb);
 }
 
-int cmd_reset(int argc, const char **argv, const char *prefix)
+int cmd_reset(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
 {
 	int reset_type = NONE, update_ref_status = 0, quiet = 0;
 	int no_refresh = 0;
@@ -441,7 +445,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 	else
 		trace2_cmd_mode(reset_type_names[reset_type]);
 
-	if (reset_type != SOFT && (reset_type != MIXED || get_git_work_tree()))
+	if (reset_type != SOFT && (reset_type != MIXED || repo_get_work_tree(the_repository)))
 		setup_work_tree();
 
 	if (reset_type == MIXED && is_bare_repository())
@@ -474,7 +478,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 				goto cleanup;
 			}
 			the_repository->index->updated_skipworktree = 1;
-			if (!no_refresh && get_git_work_tree()) {
+			if (!no_refresh && repo_get_work_tree(the_repository)) {
 				uint64_t t_begin, t_delta_in_ms;
 
 				t_begin = getnanotime();
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 97d077a..f62bcbf 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "commit.h"
@@ -513,7 +514,10 @@ static int try_bitmap_disk_usage(struct rev_info *revs,
 	return 0;
 }
 
-int cmd_rev_list(int argc, const char **argv, const char *prefix)
+int cmd_rev_list(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	struct rev_info revs;
 	struct rev_list_info info;
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 2e64f5b..8401b4d 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -3,8 +3,9 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
+
 #include "abspath.h"
 #include "config.h"
 #include "commit.h"
@@ -19,6 +20,8 @@
 #include "path.h"
 #include "diff.h"
 #include "read-cache-ll.h"
+#include "repo-settings.h"
+#include "repository.h"
 #include "revision.h"
 #include "setup.h"
 #include "split-index.h"
@@ -211,7 +214,7 @@ static int show_default(void)
 	return 0;
 }
 
-static int show_reference(const char *refname, const struct object_id *oid,
+static int show_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			  int flag UNUSED, void *cb_data UNUSED)
 {
 	if (ref_excluded(&ref_excludes, refname))
@@ -220,7 +223,7 @@ static int show_reference(const char *refname, const struct object_id *oid,
 	return 0;
 }
 
-static int anti_reference(const char *refname, const struct object_id *oid,
+static int anti_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			  int flag UNUSED, void *cb_data UNUSED)
 {
 	show_rev(REVERSED, oid, refname);
@@ -553,7 +556,10 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
 	strbuf_release(&sb);
 	strvec_clear(&longnames);
 	strvec_clear(&usage);
-	free((char *) opts->help);
+	for (size_t i = 0; i < opts_nr; i++) {
+		free((char *) opts[i].help);
+		free((char *) opts[i].argh);
+	}
 	free(opts);
 	return 0;
 }
@@ -685,7 +691,10 @@ static void print_path(const char *path, const char *prefix, enum format_type fo
 	free(cwd);
 }
 
-int cmd_rev_parse(int argc, const char **argv, const char *prefix)
+int cmd_rev_parse(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
 {
 	int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
 	const struct git_hash_algo *output_algo = NULL;
@@ -895,7 +904,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 			}
 			if (opt_with_value(arg, "--abbrev-ref", &arg)) {
 				abbrev_ref = 1;
-				abbrev_ref_strict = warn_ambiguous_refs;
+				abbrev_ref_strict =
+					repo_settings_get_warn_ambiguous_refs(the_repository);
 				if (arg) {
 					if (!strcmp(arg, "strict"))
 						abbrev_ref_strict = 1;
@@ -963,7 +973,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 				continue;
 			}
 			if (!strcmp(arg, "--show-toplevel")) {
-				const char *work_tree = get_git_work_tree();
+				const char *work_tree = repo_get_work_tree(the_repository);
 				if (work_tree)
 					print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
 				else
@@ -988,7 +998,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 				const char *pfx = prefix;
 				if (!is_inside_work_tree()) {
 					const char *work_tree =
-						get_git_work_tree();
+						repo_get_work_tree(the_repository);
 					if (work_tree)
 						printf("%s\n", work_tree);
 					continue;
@@ -1039,7 +1049,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 				continue;
 			}
 			if (!strcmp(arg, "--git-common-dir")) {
-				print_path(get_git_common_dir(), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
+				print_path(repo_get_common_dir(the_repository), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
 				continue;
 			}
 			if (!strcmp(arg, "--is-inside-git-dir")) {
diff --git a/builtin/revert.c b/builtin/revert.c
index 7bf2b4e..55ba109 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -1,9 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "git-compat-util.h"
 #include "builtin.h"
 #include "parse-options.h"
 #include "diff.h"
 #include "gettext.h"
-#include "repository.h"
 #include "revision.h"
 #include "rerere.h"
 #include "sequencer.h"
@@ -261,7 +261,10 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
 	return sequencer_pick_revisions(the_repository, opts);
 }
 
-int cmd_revert(int argc, const char **argv, const char *prefix)
+int cmd_revert(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
 {
 	struct replay_opts opts = REPLAY_OPTS_INIT;
 	int res;
@@ -275,7 +278,10 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
 	return res;
 }
 
-int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
+int cmd_cherry_pick(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
 {
 	struct replay_opts opts = REPLAY_OPTS_INIT;
 	int res;
diff --git a/builtin/rm.c b/builtin/rm.c
index 0e79cba..eaff027 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Linus Torvalds 2006
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "advice.h"
 #include "config.h"
@@ -15,7 +15,7 @@
 #include "object-name.h"
 #include "parse-options.h"
 #include "read-cache.h"
-#include "repository.h"
+
 #include "string-list.h"
 #include "setup.h"
 #include "sparse-index.h"
@@ -261,7 +261,10 @@ static struct option builtin_rm_options[] = {
 	OPT_END(),
 };
 
-int cmd_rm(int argc, const char **argv, const char *prefix)
+int cmd_rm(int argc,
+	   const char **argv,
+	   const char *prefix,
+	   struct repository *repo UNUSED)
 {
 	struct lock_file lock_file = LOCK_INIT;
 	int i, ret = 0;
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 17cae6b..8b1d46e 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "hex.h"
@@ -147,7 +148,10 @@ static int send_pack_config(const char *k, const char *v,
 	return git_default_config(k, v, ctx, cb);
 }
 
-int cmd_send_pack(int argc, const char **argv, const char *prefix)
+int cmd_send_pack(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
 {
 	struct refspec rs = REFSPEC_INIT_PUSH;
 	const char *remote_name = NULL;
@@ -338,5 +342,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 
 	free_refs(remote_refs);
 	free_refs(local_refs);
+	refspec_clear(&rs);
+	oid_array_clear(&shallow);
+	clear_cas_option(&cas);
 	return ret;
 }
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 5bde7c6..3ed5c46 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "commit.h"
@@ -5,7 +6,6 @@
 #include "environment.h"
 #include "gettext.h"
 #include "string-list.h"
-#include "repository.h"
 #include "revision.h"
 #include "utf8.h"
 #include "mailmap.h"
@@ -378,7 +378,10 @@ void shortlog_finish_setup(struct shortlog *log)
 	string_list_sort(&log->trailers);
 }
 
-int cmd_shortlog(int argc, const char **argv, const char *prefix)
+int cmd_shortlog(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	struct shortlog log = { STRING_LIST_INIT_NODUP };
 	struct rev_info rev;
@@ -514,4 +517,5 @@ void shortlog_output(struct shortlog *log)
 	string_list_clear(&log->list, 1);
 	clear_mailmap(&log->mailmap);
 	string_list_clear(&log->format, 0);
+	string_list_clear(&log->trailers, 0);
 }
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index d72f4cb..cd6bdf6 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "environment.h"
@@ -10,7 +11,7 @@
 #include "strvec.h"
 #include "object-name.h"
 #include "parse-options.h"
-#include "repository.h"
+
 #include "dir.h"
 #include "commit-slab.h"
 #include "date.h"
@@ -410,7 +411,7 @@ static int append_ref(const char *refname, const struct object_id *oid,
 	return 0;
 }
 
-static int append_head_ref(const char *refname, const struct object_id *oid,
+static int append_head_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			   int flag UNUSED, void *cb_data UNUSED)
 {
 	struct object_id tmp;
@@ -425,7 +426,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid,
 	return append_ref(refname + ofs, oid, 0);
 }
 
-static int append_remote_ref(const char *refname, const struct object_id *oid,
+static int append_remote_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			     int flag UNUSED, void *cb_data UNUSED)
 {
 	struct object_id tmp;
@@ -451,7 +452,7 @@ static int append_tag_ref(const char *refname, const struct object_id *oid,
 static const char *match_ref_pattern = NULL;
 static int match_ref_slash = 0;
 
-static int append_matching_ref(const char *refname, const struct object_id *oid,
+static int append_matching_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			       int flag, void *cb_data)
 {
 	/* we want to allow pattern hold/<asterisk> to show all
@@ -468,7 +469,7 @@ static int append_matching_ref(const char *refname, const struct object_id *oid,
 	if (wildmatch(match_ref_pattern, tail, 0))
 		return 0;
 	if (starts_with(refname, "refs/heads/"))
-		return append_head_ref(refname, oid, flag, cb_data);
+		return append_head_ref(refname, NULL, oid, flag, cb_data);
 	if (starts_with(refname, "refs/tags/"))
 		return append_tag_ref(refname, oid, flag, cb_data);
 	return append_ref(refname, oid, 0);
@@ -502,14 +503,14 @@ static int rev_is_head(const char *head, const char *name)
 	return !strcmp(head, name);
 }
 
-static int show_merge_base(struct commit_list *seen, int num_rev)
+static int show_merge_base(const struct commit_list *seen, int num_rev)
 {
 	int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
 	int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
 	int exit_status = 1;
 
-	while (seen) {
-		struct commit *commit = pop_commit(&seen);
+	for (const struct commit_list *s = seen; s; s = s->next) {
+		struct commit *commit = s->item;
 		int flags = commit->object.flags & all_mask;
 		if (!(flags & UNINTERESTING) &&
 		    ((flags & all_revs) == all_revs)) {
@@ -632,10 +633,13 @@ static int parse_reflog_param(const struct option *opt, const char *arg,
 	return 0;
 }
 
-int cmd_show_branch(int ac, const char **av, const char *prefix)
+int cmd_show_branch(int ac,
+		const char **av,
+		const char *prefix,
+		struct repository *repo UNUSED)
 {
 	struct commit *rev[MAX_REVS], *commit;
-	char *reflog_msg[MAX_REVS];
+	char *reflog_msg[MAX_REVS] = {0};
 	struct commit_list *list = NULL, *seen = NULL;
 	unsigned int rev_mask[MAX_REVS];
 	int num_rev, i, extra = 0;
@@ -692,6 +696,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 			    parse_reflog_param),
 		OPT_END()
 	};
+	const char **args_copy = NULL;
+	int ret;
 
 	init_commit_name_slab(&name_slab);
 
@@ -699,8 +705,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 
 	/* If nothing is specified, try the default first */
 	if (ac == 1 && default_args.nr) {
+		DUP_ARRAY(args_copy, default_args.v, default_args.nr);
 		ac = default_args.nr;
-		av = default_args.v;
+		av = args_copy;
 	}
 
 	ac = parse_options(ac, av, prefix, builtin_show_branch_options,
@@ -780,7 +787,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 		}
 
 		for (i = 0; i < reflog; i++) {
-			char *logmsg;
+			char *logmsg = NULL;
 			char *nth_desc;
 			const char *msg;
 			char *end;
@@ -790,6 +797,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 			if (read_ref_at(get_main_ref_store(the_repository),
 					ref, flags, 0, base + i, &oid, &logmsg,
 					&timestamp, &tz, NULL)) {
+				free(logmsg);
 				reflog = i;
 				break;
 			}
@@ -842,7 +850,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 
 	if (!ref_name_cnt) {
 		fprintf(stderr, "No revs to be shown.\n");
-		exit(0);
+		ret = 0;
+		goto out;
 	}
 
 	for (num_rev = 0; ref_name[num_rev]; num_rev++) {
@@ -879,11 +888,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 
 	commit_list_sort_by_date(&seen);
 
-	if (merge_base)
-		return show_merge_base(seen, num_rev);
+	if (merge_base) {
+		ret = show_merge_base(seen, num_rev);
+		goto out;
+	}
 
-	if (independent)
-		return show_independent(rev, num_rev, rev_mask);
+	if (independent) {
+		ret = show_independent(rev, num_rev, rev_mask);
+		goto out;
+	}
 
 	/* Show list; --more=-1 means list-only */
 	if (1 < num_rev || extra < 0) {
@@ -919,8 +932,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 			putchar('\n');
 		}
 	}
-	if (extra < 0)
-		exit(0);
+	if (extra < 0) {
+		ret = 0;
+		goto out;
+	}
 
 	/* Sort topologically */
 	sort_in_topological_order(&seen, sort_order);
@@ -932,8 +947,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 	all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
 	all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
 
-	while (seen) {
-		struct commit *commit = pop_commit(&seen);
+	for (struct commit_list *l = seen; l; l = l->next) {
+		struct commit *commit = l->item;
 		int this_flag = commit->object.flags;
 		int is_merge_point = ((this_flag & all_revs) == all_revs);
 
@@ -973,6 +988,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 		if (shown_merge_point && --extra < 0)
 			break;
 	}
+
+	ret = 0;
+
+out:
+	for (size_t i = 0; i < ARRAY_SIZE(reflog_msg); i++)
+		free(reflog_msg[i]);
+	free_commit_list(seen);
+	free_commit_list(list);
+	free(args_copy);
 	free(head);
-	return 0;
+	return ret;
 }
diff --git a/builtin/show-index.c b/builtin/show-index.c
index 540dc3d..f164c01 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c
@@ -1,17 +1,20 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "gettext.h"
 #include "hash.h"
 #include "hex.h"
 #include "pack.h"
 #include "parse-options.h"
-#include "repository.h"
 
 static const char *const show_index_usage[] = {
 	"git show-index [--object-format=<hash-algorithm>]",
 	NULL
 };
 
-int cmd_show_index(int argc, const char **argv, const char *prefix)
+int cmd_show_index(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	int i;
 	unsigned nr;
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 839a5c2..285cd3e 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -63,7 +64,7 @@ struct show_ref_data {
 	int show_head;
 };
 
-static int show_ref(const char *refname, const struct object_id *oid,
+static int show_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 		    int flag UNUSED, void *cbdata)
 {
 	struct show_ref_data *data = cbdata;
@@ -97,6 +98,7 @@ static int show_ref(const char *refname, const struct object_id *oid,
 }
 
 static int add_existing(const char *refname,
+			const char *referent UNUSED,
 			const struct object_id *oid UNUSED,
 			int flag UNUSED, void *cbdata)
 {
@@ -286,15 +288,18 @@ static int exclude_existing_callback(const struct option *opt, const char *arg,
 	return 0;
 }
 
-int cmd_show_ref(int argc, const char **argv, const char *prefix)
+int cmd_show_ref(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
 {
 	struct exclude_existing_options exclude_existing_opts = {0};
 	struct patterns_options patterns_opts = {0};
 	struct show_one_options show_one_opts = {0};
 	int verify = 0, exists = 0;
 	const struct option show_ref_options[] = {
-		OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with branches)")),
-		OPT_BOOL(0, "branches", &patterns_opts.branches_only, N_("only show branches (can be combined with tags)")),
+		OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with --branches)")),
+		OPT_BOOL(0, "branches", &patterns_opts.branches_only, N_("only show branches (can be combined with --tags)")),
 		OPT_HIDDEN_BOOL(0, "heads", &patterns_opts.branches_only,
 				N_("deprecated synonym for --branches")),
 		OPT_BOOL(0, "exists", &exists, N_("check for reference existence without resolving")),
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 2604ab0..49aedc1 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "dir.h"
@@ -7,7 +8,6 @@
 #include "object-name.h"
 #include "parse-options.h"
 #include "pathspec.h"
-#include "repository.h"
 #include "strbuf.h"
 #include "string-list.h"
 #include "lockfile.h"
@@ -327,7 +327,6 @@ static int write_patterns_and_update(struct pattern_list *pl)
 {
 	char *sparse_filename;
 	FILE *fp;
-	int fd;
 	struct lock_file lk = LOCK_INIT;
 	int result;
 
@@ -336,31 +335,31 @@ static int write_patterns_and_update(struct pattern_list *pl)
 	if (safe_create_leading_directories(sparse_filename))
 		die(_("failed to create directory for sparse-checkout file"));
 
-	fd = hold_lock_file_for_update(&lk, sparse_filename,
-				      LOCK_DIE_ON_ERROR);
-	free(sparse_filename);
+	hold_lock_file_for_update(&lk, sparse_filename, LOCK_DIE_ON_ERROR);
 
 	result = update_working_directory(pl);
 	if (result) {
 		rollback_lock_file(&lk);
-		clear_pattern_list(pl);
 		update_working_directory(NULL);
-		return result;
+		goto out;
 	}
 
-	fp = xfdopen(fd, "w");
+	fp = fdopen_lock_file(&lk, "w");
+	if (!fp)
+		die_errno(_("unable to fdopen %s"), get_lock_file_path(&lk));
 
 	if (core_sparse_checkout_cone)
 		write_cone_to_file(fp, pl);
 	else
 		write_patterns_to_file(fp, pl);
 
-	fflush(fp);
-	commit_lock_file(&lk);
+	if (commit_lock_file(&lk))
+		die_errno(_("unable to write %s"), sparse_filename);
 
+out:
 	clear_pattern_list(pl);
-
-	return 0;
+	free(sparse_filename);
+	return result;
 }
 
 enum sparse_checkout_mode {
@@ -925,6 +924,11 @@ static int sparse_checkout_disable(int argc, const char **argv,
 			     builtin_sparse_checkout_disable_options,
 			     builtin_sparse_checkout_disable_usage, 0);
 
+	/*
+	 * Disable the advice message for expanding a sparse index, as we
+	 * are expecting to do that when disabling sparse-checkout.
+	 */
+	give_advice_on_expansion = 0;
 	repo_read_index(the_repository);
 
 	memset(&pl, 0, sizeof(pl));
@@ -1030,7 +1034,10 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *
 	return ret;
 }
 
-int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
+int cmd_sparse_checkout(int argc,
+			const char **argv,
+			const char *prefix,
+			struct repository *repo UNUSED)
 {
 	parse_opt_subcommand_fn *fn = NULL;
 	struct option builtin_sparse_checkout_options[] = {
diff --git a/builtin/stash.c b/builtin/stash.c
index 80ccfc7..f1acc91 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "config.h"
@@ -19,6 +20,7 @@
 #include "entry.h"
 #include "preload-index.h"
 #include "read-cache.h"
+#include "repository.h"
 #include "rerere.h"
 #include "revision.h"
 #include "setup.h"
@@ -484,7 +486,7 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
 					 "         to make room.\n"),
 				       ce->name, new_path.buf);
 				if (rename(ce->name, new_path.buf))
-					die("Failed to move %s to %s\n",
+					die("Failed to move %s to %s",
 					    ce->name, new_path.buf);
 				strbuf_release(&new_path);
 			}
@@ -539,8 +541,8 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
 					 NULL, NULL, NULL))
 		return error(_("could not write index"));
 
-	if (write_index_as_tree(&c_tree, the_repository->index, get_index_file(), 0,
-				NULL))
+	if (write_index_as_tree(&c_tree, the_repository->index,
+				repo_get_index_file(the_repository), 0, NULL))
 		return error(_("cannot apply a stash in the middle of a merge"));
 
 	if (index) {
@@ -565,7 +567,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
 			discard_index(the_repository->index);
 			repo_read_index(the_repository);
 			if (write_index_as_tree(&index_tree, the_repository->index,
-						get_index_file(), 0, NULL))
+						repo_get_index_file(the_repository), 0, NULL))
 				return error(_("could not save index tree"));
 
 			reset_head();
@@ -574,7 +576,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
 		}
 	}
 
-	init_merge_options(&o, the_repository);
+	init_ui_merge_options(&o, the_repository);
 
 	o.branch1 = "Updated upstream";
 	o.branch2 = "Stashed changes";
@@ -640,9 +642,9 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
 		cp.git_cmd = 1;
 		cp.dir = prefix;
 		strvec_pushf(&cp.env, GIT_WORK_TREE_ENVIRONMENT"=%s",
-			     absolute_path(get_git_work_tree()));
+			     absolute_path(repo_get_work_tree(the_repository)));
 		strvec_pushf(&cp.env, GIT_DIR_ENVIRONMENT"=%s",
-			     absolute_path(get_git_dir()));
+			     absolute_path(repo_get_git_dir(the_repository)));
 		strvec_push(&cp.args, "status");
 		run_command(&cp);
 	}
@@ -974,7 +976,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
 	}
 	log_tree_diff_flush(&rev);
 
-	ret = diff_result_code(&rev.diffopt);
+	ret = diff_result_code(&rev);
 
 cleanup:
 	strvec_clear(&revision_args);
@@ -1126,13 +1128,13 @@ static int check_changes_tracked_files(const struct pathspec *ps)
 	diff_setup_done(&rev.diffopt);
 
 	run_diff_index(&rev, DIFF_INDEX_CACHED);
-	if (diff_result_code(&rev.diffopt)) {
+	if (diff_result_code(&rev)) {
 		ret = 1;
 		goto done;
 	}
 
 	run_diff_files(&rev, 0);
-	if (diff_result_code(&rev.diffopt)) {
+	if (diff_result_code(&rev)) {
 		ret = 1;
 		goto done;
 	}
@@ -1405,8 +1407,8 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
 
 	strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf);
 	commit_list_insert(head_commit, &parents);
-	if (write_index_as_tree(&info->i_tree, the_repository->index, get_index_file(), 0,
-				NULL) ||
+	if (write_index_as_tree(&info->i_tree, the_repository->index,
+				repo_get_index_file(the_repository), 0, NULL) ||
 	    commit_tree(commit_tree_label.buf, commit_tree_label.len,
 			&info->i_tree, parents, &info->i_commit, NULL, NULL)) {
 		if (!quiet)
@@ -1521,6 +1523,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
 	struct strbuf patch = STRBUF_INIT;
 	struct strbuf stash_msg_buf = STRBUF_INIT;
 	struct strbuf untracked_files = STRBUF_INIT;
+	struct strbuf out = STRBUF_INIT;
 
 	if (patch_mode && keep_index == -1)
 		keep_index = 1;
@@ -1626,7 +1629,6 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
 			struct child_process cp_add = CHILD_PROCESS_INIT;
 			struct child_process cp_diff = CHILD_PROCESS_INIT;
 			struct child_process cp_apply = CHILD_PROCESS_INIT;
-			struct strbuf out = STRBUF_INIT;
 
 			cp_add.git_cmd = 1;
 			strvec_push(&cp_add.args, "add");
@@ -1739,6 +1741,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
 
 done:
 	strbuf_release(&patch);
+	strbuf_release(&out);
 	free_stash_info(&info);
 	strbuf_release(&stash_msg_buf);
 	strbuf_release(&untracked_files);
@@ -1870,7 +1873,10 @@ static int save_stash(int argc, const char **argv, const char *prefix)
 	return ret;
 }
 
-int cmd_stash(int argc, const char **argv, const char *prefix)
+int cmd_stash(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
 {
 	pid_t pid = getpid();
 	const char *index_file;
@@ -1890,6 +1896,8 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
 		OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE),
 		OPT_END()
 	};
+	const char **args_copy;
+	int ret;
 
 	git_config(git_stash_config, NULL);
 
@@ -1901,7 +1909,7 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
 	prepare_repo_settings(the_repository);
 	the_repository->settings.command_requires_full_index = 0;
 
-	index_file = get_index_file();
+	index_file = repo_get_index_file(the_repository);
 	strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
 		    (uintmax_t)pid);
 
@@ -1913,5 +1921,16 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
 	/* Assume 'stash push' */
 	strvec_push(&args, "push");
 	strvec_pushv(&args, argv);
-	return !!push_stash(args.nr, args.v, prefix, 1);
+
+	/*
+	 * `push_stash()` ends up modifying the array, which causes memory
+	 * leaks if we didn't copy the array here.
+	 */
+	DUP_ARRAY(args_copy, args.v, args.nr);
+
+	ret = !!push_stash(args.nr, args_copy, prefix, 1);
+
+	strvec_clear(&args);
+	free(args_copy);
+	return ret;
 }
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index e5626e5..e147f3f 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "environment.h"
@@ -29,7 +30,10 @@ enum stripspace_mode {
 	COMMENT_LINES
 };
 
-int cmd_stripspace(int argc, const char **argv, const char *prefix)
+int cmd_stripspace(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	struct strbuf buf = STRBUF_INIT;
 	enum stripspace_mode mode = STRIP_DEFAULT;
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f1218a1..b6b5f1e 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1,9 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
-#include "repository.h"
+
 #include "config.h"
 #include "parse-options.h"
 #include "quote.h"
@@ -363,9 +364,13 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 	if (!info->quiet)
 		printf(_("Entering '%s'\n"), displaypath);
 
-	if (info->argv[0] && run_command(&cp))
-		die(_("run_command returned non-zero status for %s\n."),
-			displaypath);
+	if (info->argv[0]) {
+		if (run_command(&cp))
+			die(_("run_command returned non-zero status for %s\n."),
+			    displaypath);
+	} else {
+		child_process_clear(&cp);
+	}
 
 	if (info->recursive) {
 		struct child_process cpr = CHILD_PROCESS_INIT;
@@ -608,6 +613,7 @@ static void print_status(unsigned int flags, char state, const char *path,
 }
 
 static int handle_submodule_head_ref(const char *refname UNUSED,
+				     const char *referent UNUSED,
 				     const struct object_id *oid,
 				     int flags UNUSED,
 				     void *cb_data)
@@ -671,7 +677,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 	setup_revisions(diff_files_args.nr, diff_files_args.v, &rev, &opt);
 	run_diff_files(&rev, 0);
 
-	if (!diff_result_code(&rev.diffopt)) {
+	if (!diff_result_code(&rev)) {
 		print_status(flags, ' ', path, ce_oid,
 			     displaypath);
 	} else if (!(flags & OPT_CACHED)) {
@@ -694,6 +700,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 
 	if (flags & OPT_RECURSIVE) {
 		struct child_process cpr = CHILD_PROCESS_INIT;
+		int res;
 
 		cpr.git_cmd = 1;
 		cpr.dir = path;
@@ -709,7 +716,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		if (flags & OPT_QUIET)
 			strvec_push(&cpr.args, "--quiet");
 
-		if (run_command(&cpr))
+		res = run_command(&cpr);
+		if (res == SIGPIPE + 128)
+			raise(SIGPIPE);
+		else if (res)
 			die(_("failed to recurse into submodule '%s'"), path);
 	}
 
@@ -916,7 +926,7 @@ static void generate_submodule_summary(struct summary_cb *info,
 		} else {
 			/* for a submodule removal (mode:0000000), don't warn */
 			if (p->mod_dst)
-				warning(_("unexpected mode %o\n"), p->mod_dst);
+				warning(_("unexpected mode %o"), p->mod_dst);
 		}
 	}
 
@@ -1455,7 +1465,7 @@ static void deinit_submodule(const char *path, const char *prefix,
 		 * remove the whole section so we have a clean state when
 		 * the user later decides to init this submodule again
 		 */
-		git_config_rename_section_in_file(NULL, sub_key, NULL);
+		repo_config_rename_section_in_file(the_repository, NULL, sub_key, NULL);
 		if (!(flags & OPT_QUIET))
 			printf(_("Submodule '%s' (%s) unregistered for path '%s'\n"),
 				 sub->name, sub->url, displaypath);
@@ -1530,8 +1540,9 @@ struct module_clone_data {
 	const char *path;
 	const char *name;
 	const char *url;
-	const char *depth;
+	int depth;
 	struct list_objects_filter_options *filter_options;
+	enum ref_storage_format ref_storage_format;
 	unsigned int quiet: 1;
 	unsigned int progress: 1;
 	unsigned int dissociate: 1;
@@ -1540,6 +1551,7 @@ struct module_clone_data {
 };
 #define MODULE_CLONE_DATA_INIT { \
 	.single_branch = -1, \
+	.ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
 }
 
 struct submodule_alternate_setup {
@@ -1614,6 +1626,8 @@ static int add_possible_reference_from_superproject(
 				; /* nothing */
 			}
 		}
+
+		strbuf_release(&err);
 		strbuf_release(&sb);
 	}
 
@@ -1706,7 +1720,7 @@ static int clone_submodule(const struct module_clone_data *clone_data,
 		exit(128);
 
 	if (!is_absolute_path(clone_data->path))
-		clone_data_path = to_free = xstrfmt("%s/%s", get_git_work_tree(),
+		clone_data_path = to_free = xstrfmt("%s/%s", repo_get_work_tree(the_repository),
 						    clone_data->path);
 
 	if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
@@ -1729,8 +1743,8 @@ static int clone_submodule(const struct module_clone_data *clone_data,
 			strvec_push(&cp.args, "--quiet");
 		if (clone_data->progress)
 			strvec_push(&cp.args, "--progress");
-		if (clone_data->depth && *(clone_data->depth))
-			strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL);
+		if (clone_data->depth > 0)
+			strvec_pushf(&cp.args, "--depth=%d", clone_data->depth);
 		if (reference->nr) {
 			struct string_list_item *item;
 
@@ -1738,6 +1752,9 @@ static int clone_submodule(const struct module_clone_data *clone_data,
 				strvec_pushl(&cp.args, "--reference",
 					     item->string, NULL);
 		}
+		if (clone_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+			strvec_pushf(&cp.args, "--ref-format=%s",
+				     ref_storage_format_to_name(clone_data->ref_storage_format));
 		if (clone_data->dissociate)
 			strvec_push(&cp.args, "--dissociate");
 		if (sm_gitdir && *sm_gitdir)
@@ -1832,6 +1849,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
 	struct string_list reference = STRING_LIST_INIT_NODUP;
 	struct list_objects_filter_options filter_options =
 		LIST_OBJECTS_FILTER_INIT;
+	const char *ref_storage_format = NULL;
 
 	struct option module_clone_options[] = {
 		OPT_STRING(0, "prefix", &clone_data.prefix,
@@ -1849,10 +1867,11 @@ static int module_clone(int argc, const char **argv, const char *prefix)
 		OPT_STRING_LIST(0, "reference", &reference,
 			   N_("repo"),
 			   N_("reference repository")),
+		OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+			   N_("specify the reference format to use")),
 		OPT_BOOL(0, "dissociate", &dissociate,
 			   N_("use --reference only while cloning")),
-		OPT_STRING(0, "depth", &clone_data.depth,
-			   N_("string"),
+		OPT_INTEGER(0, "depth", &clone_data.depth,
 			   N_("depth for shallow clones")),
 		OPT__QUIET(&quiet, "suppress output for cloning a submodule"),
 		OPT_BOOL(0, "progress", &progress,
@@ -1875,6 +1894,11 @@ static int module_clone(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, module_clone_options,
 			     git_submodule_helper_usage, 0);
 
+	if (ref_storage_format) {
+		clone_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+		if (clone_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+			die(_("unknown ref storage format '%s'"), ref_storage_format);
+	}
 	clone_data.dissociate = !!dissociate;
 	clone_data.quiet = !!quiet;
 	clone_data.progress = !!progress;
@@ -1974,6 +1998,7 @@ struct update_data {
 	struct submodule_update_strategy update_strategy;
 	struct list_objects_filter_options *filter_options;
 	struct module_list list;
+	enum ref_storage_format ref_storage_format;
 	int depth;
 	int max_jobs;
 	int single_branch;
@@ -1997,6 +2022,7 @@ struct update_data {
 #define UPDATE_DATA_INIT { \
 	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
 	.list = MODULE_LIST_INIT, \
+	.ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
 	.recommend_shallow = -1, \
 	.references = STRING_LIST_INIT_DUP, \
 	.single_branch = -1, \
@@ -2006,6 +2032,7 @@ struct update_data {
 static void update_data_release(struct update_data *ud)
 {
 	free(ud->displaypath);
+	submodule_update_strategy_release(&ud->update_strategy);
 	module_list_release(&ud->list);
 }
 
@@ -2132,6 +2159,9 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
 			     expand_list_objects_filter_spec(suc->update_data->filter_options));
 	if (suc->update_data->require_init)
 		strvec_push(&child->args, "--require-init");
+	if (suc->update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+		strvec_pushf(&child->args, "--ref-format=%s",
+			     ref_storage_format_to_name(suc->update_data->ref_storage_format));
 	strvec_pushl(&child->args, "--path", sub->path, NULL);
 	strvec_pushl(&child->args, "--name", sub->name, NULL);
 	strvec_pushl(&child->args, "--url", url, NULL);
@@ -2269,6 +2299,7 @@ static int is_tip_reachable(const char *path, const struct object_id *oid)
 	struct child_process cp = CHILD_PROCESS_INIT;
 	struct strbuf rev = STRBUF_INIT;
 	char *hex = oid_to_hex(oid);
+	int reachable;
 
 	cp.git_cmd = 1;
 	cp.dir = path;
@@ -2278,9 +2309,12 @@ static int is_tip_reachable(const char *path, const struct object_id *oid)
 	prepare_submodule_repo_env(&cp.env);
 
 	if (capture_command(&cp, &rev, GIT_MAX_HEXSZ + 1) || rev.len)
-		return 0;
+		reachable = 0;
+	else
+		reachable = 1;
 
-	return 1;
+	strbuf_release(&rev);
+	return reachable;
 }
 
 static int fetch_in_submodule(const char *module_path, int depth, int quiet,
@@ -2299,7 +2333,14 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet,
 		strvec_pushf(&cp.args, "--depth=%d", depth);
 	if (oid) {
 		char *hex = oid_to_hex(oid);
-		char *remote = get_default_remote();
+		char *remote;
+		int code;
+
+		code = get_default_remote_submodule(module_path, &remote);
+		if (code) {
+			child_process_clear(&cp);
+			return code;
+		}
 
 		strvec_pushl(&cp.args, remote, hex, NULL);
 		free(remote);
@@ -2562,6 +2603,9 @@ static void update_data_to_args(const struct update_data *update_data,
 		for_each_string_list_item(item, &update_data->references)
 			strvec_pushl(args, "--reference", item->string, NULL);
 	}
+	if (update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+		strvec_pushf(args, "--ref-format=%s",
+			     ref_storage_format_to_name(update_data->ref_storage_format));
 	if (update_data->filter_options && update_data->filter_options->choice)
 		strvec_pushf(args, "--filter=%s",
 				expand_list_objects_filter_spec(
@@ -2616,15 +2660,20 @@ static int update_submodule(struct update_data *update_data)
 
 		if (!update_data->nofetch) {
 			if (fetch_in_submodule(update_data->sm_path, update_data->depth,
-					      0, NULL))
+					      0, NULL)) {
+				free(remote_ref);
 				return die_message(_("Unable to fetch in submodule path '%s'"),
 						   update_data->sm_path);
+			}
 		}
 
 		if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,
-					     remote_ref, &update_data->oid))
-			return die_message(_("Unable to find %s revision in submodule path '%s'"),
-					   remote_ref, update_data->sm_path);
+					     remote_ref, &update_data->oid)) {
+			ret = die_message(_("Unable to find %s revision in submodule path '%s'"),
+					  remote_ref, update_data->sm_path);
+			free(remote_ref);
+			return ret;
+		}
 
 		free(remote_ref);
 	}
@@ -2737,6 +2786,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 	struct update_data opt = UPDATE_DATA_INIT;
 	struct list_objects_filter_options filter_options =
 		LIST_OBJECTS_FILTER_INIT;
+	const char *ref_storage_format = NULL;
 	int ret;
 	struct option module_update_options[] = {
 		OPT__SUPER_PREFIX(&opt.super_prefix),
@@ -2760,6 +2810,8 @@ static int module_update(int argc, const char **argv, const char *prefix)
 			SM_UPDATE_REBASE),
 		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
 			   N_("reference repository")),
+		OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+			   N_("specify the reference format to use")),
 		OPT_BOOL(0, "dissociate", &opt.dissociate,
 			   N_("use --reference only while cloning")),
 		OPT_INTEGER(0, "depth", &opt.depth,
@@ -2803,6 +2855,12 @@ static int module_update(int argc, const char **argv, const char *prefix)
 				   module_update_options);
 	}
 
+	if (ref_storage_format) {
+		opt.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+		if (opt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+			die(_("unknown ref storage format '%s'"), ref_storage_format);
+	}
+
 	opt.filter_options = &filter_options;
 	opt.prefix = prefix;
 
@@ -2924,7 +2982,9 @@ static int push_check(int argc, const char **argv, const char *prefix UNUSED)
 				    rs->src);
 			}
 		}
+
 		refspec_clear(&refspec);
+		free_refs(local_refs);
 	}
 	free(head);
 
@@ -3098,13 +3158,17 @@ struct add_data {
 	const char *sm_name;
 	const char *repo;
 	const char *realrepo;
+	enum ref_storage_format ref_storage_format;
 	int depth;
 	unsigned int force: 1;
 	unsigned int quiet: 1;
 	unsigned int progress: 1;
 	unsigned int dissociate: 1;
 };
-#define ADD_DATA_INIT { .depth = -1 }
+#define ADD_DATA_INIT { \
+	.depth = -1, \
+	.ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
+}
 
 static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
 {
@@ -3198,9 +3262,10 @@ static int add_submodule(const struct add_data *add_data)
 
 			string_list_append(&reference, p)->util = p;
 		}
+		clone_data.ref_storage_format = add_data->ref_storage_format;
 		clone_data.dissociate = add_data->dissociate;
 		if (add_data->depth >= 0)
-			clone_data.depth = xstrfmt("%d", add_data->depth);
+			clone_data.depth = add_data->depth;
 
 		if (clone_submodule(&clone_data, &reference))
 			goto cleanup;
@@ -3223,6 +3288,7 @@ static int add_submodule(const struct add_data *add_data)
 			die(_("unable to checkout submodule '%s'"), add_data->sm_path);
 	}
 	ret = 0;
+
 cleanup:
 	string_list_clear(&reference, 1);
 	return ret;
@@ -3362,6 +3428,7 @@ static int module_add(int argc, const char **argv, const char *prefix)
 {
 	int force = 0, quiet = 0, progress = 0, dissociate = 0;
 	struct add_data add_data = ADD_DATA_INIT;
+	const char *ref_storage_format = NULL;
 	char *to_free = NULL;
 	struct option options[] = {
 		OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
@@ -3372,6 +3439,8 @@ static int module_add(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "progress", &progress, N_("force cloning progress")),
 		OPT_STRING(0, "reference", &add_data.reference_path, N_("repository"),
 			   N_("reference repository")),
+		OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+			   N_("specify the reference format to use")),
 		OPT_BOOL(0, "dissociate", &dissociate, N_("borrow the objects from reference repositories")),
 		OPT_STRING(0, "name", &add_data.sm_name, N_("name"),
 			   N_("sets the submodule's name to the given string "
@@ -3398,6 +3467,12 @@ static int module_add(int argc, const char **argv, const char *prefix)
 	if (argc == 0 || argc > 2)
 		usage_with_options(usage, options);
 
+	if (ref_storage_format) {
+		add_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+		if (add_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+			die(_("unknown ref storage format '%s'"), ref_storage_format);
+	}
+
 	add_data.repo = argv[0];
 	if (argc == 1)
 		add_data.sm_path = git_url_basename(add_data.repo, 0, 0);
@@ -3479,7 +3554,10 @@ static int module_add(int argc, const char **argv, const char *prefix)
 	return ret;
 }
 
-int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
+int cmd_submodule__helper(int argc,
+			  const char **argv,
+			  const char *prefix,
+			  struct repository *repo UNUSED)
 {
 	parse_opt_subcommand_fn *fn = NULL;
 	const char *const usage[] = {
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 81abdd1..299d23d 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -41,7 +42,10 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, i
 	return 0;
 }
 
-int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
+int cmd_symbolic_ref(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
 {
 	int quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;
 	const char *msg = NULL;
diff --git a/builtin/tag.c b/builtin/tag.c
index a1fb218..93d10d5 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -5,7 +5,7 @@
  *                    Carlos Rica <jasampler@gmail.com>
  * Based on git-tag.sh and mktag.c by Linus Torvalds.
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "advice.h"
 #include "config.h"
@@ -160,7 +160,7 @@ static int do_sign(struct strbuf *buffer, struct object_id **compat_oid,
 	const struct git_hash_algo *compat = the_repository->compat_hash_algo;
 	struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
 	struct strbuf compat_buf = STRBUF_INIT;
-	const char *keyid = get_signing_key();
+	char *keyid = get_signing_key();
 	int ret = -1;
 
 	if (sign_buffer(buffer, &sig, keyid))
@@ -190,6 +190,7 @@ static int do_sign(struct strbuf *buffer, struct object_id **compat_oid,
 	strbuf_release(&sig);
 	strbuf_release(&compat_sig);
 	strbuf_release(&compat_buf);
+	free(keyid);
 	return ret;
 }
 
@@ -457,7 +458,10 @@ static int strbuf_check_tag_ref(struct strbuf *sb, const char *name)
 	return check_refname_format(sb->buf, 0);
 }
 
-int cmd_tag(int argc, const char **argv, const char *prefix)
+int cmd_tag(int argc,
+	    const char **argv,
+	    const char *prefix,
+	    struct repository *repo UNUSED)
 {
 	struct strbuf buf = STRBUF_INIT;
 	struct strbuf ref = STRBUF_INIT;
@@ -702,6 +706,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 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 c129e2b..6da2825 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "hex.h"
@@ -25,7 +26,10 @@ static char *create_temp_file(struct object_id *oid)
 	return path;
 }
 
-int cmd_unpack_file(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_unpack_file(int argc,
+		    const char **argv,
+		    const char *prefix UNUSED,
+		    struct repository *repo UNUSED)
 {
 	struct object_id oid;
 
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 08fa2a7..02b8d02 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "bulk-checkin.h"
 #include "config.h"
@@ -601,7 +602,10 @@ static void unpack_all(void)
 		die("unresolved deltas left after unpacking");
 }
 
-int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_unpack_objects(int argc,
+		       const char **argv,
+		       const char *prefix UNUSED,
+		       struct repository *repo UNUSED)
 {
 	int i;
 	struct object_id oid;
diff --git a/builtin/update-index.c b/builtin/update-index.c
index d343416..45b4a8b 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "bulk-checkin.h"
 #include "config.h"
@@ -22,7 +22,6 @@
 #include "pathspec.h"
 #include "dir.h"
 #include "read-cache.h"
-#include "repository.h"
 #include "setup.h"
 #include "sparse-index.h"
 #include "split-index.h"
@@ -917,7 +916,10 @@ static enum parse_opt_result reupdate_callback(
 	return 0;
 }
 
-int cmd_update_index(int argc, const char **argv, const char *prefix)
+int cmd_update_index(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
 {
 	int newfd, entries, has_errors = 0, nul_term_line = 0;
 	enum uc_mode untracked_cache = UC_UNSPECIFIED;
@@ -1156,7 +1158,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 	end_odb_transaction();
 
 	if (split_index > 0) {
-		if (git_config_get_split_index() == 0)
+		if (repo_config_get_split_index(the_repository) == 0)
 			warning(_("core.splitIndex is set to false; "
 				  "remove or change it, if you really want to "
 				  "enable split index"));
@@ -1165,7 +1167,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 		else
 			add_split_index(the_repository->index);
 	} else if (!split_index) {
-		if (git_config_get_split_index() == 1)
+		if (repo_config_get_split_index(the_repository) == 1)
 			warning(_("core.splitIndex is set to true; "
 				  "remove or change it, if you really want to "
 				  "disable split index"));
@@ -1194,7 +1196,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 				  "remove or change it, if you really want to "
 				  "enable the untracked cache"));
 		add_untracked_cache(the_repository->index);
-		report(_("Untracked cache enabled for '%s'"), get_git_work_tree());
+		report(_("Untracked cache enabled for '%s'"), repo_get_work_tree(the_repository));
 		break;
 	default:
 		BUG("bad untracked_cache value: %d", untracked_cache);
@@ -1239,7 +1241,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 		if (newfd < 0) {
 			if (refresh_args.flags & REFRESH_QUIET)
 				exit(128);
-			unable_to_lock_die(get_index_file(), lock_error);
+			unable_to_lock_die(repo_get_index_file(the_repository), lock_error);
 		}
 		if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
 			die("Unable to write new index file");
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 6a6a2ff..8a98615 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -6,7 +7,6 @@
 #include "object-name.h"
 #include "parse-options.h"
 #include "quote.h"
-#include "repository.h"
 
 static const char * const git_update_ref_usage[] = {
 	N_("git update-ref [<options>] -d <refname> [<old-oid>]"),
@@ -274,7 +274,7 @@ static void parse_cmd_update(struct ref_transaction *transaction,
 }
 
 static void parse_cmd_symref_update(struct ref_transaction *transaction,
-				    const char *next, const char *end)
+				    const char *next, const char *end UNUSED)
 {
 	char *refname, *new_target, *old_arg;
 	char *old_target = NULL;
@@ -360,7 +360,7 @@ static void parse_cmd_create(struct ref_transaction *transaction,
 
 
 static void parse_cmd_symref_create(struct ref_transaction *transaction,
-				    const char *next, const char *end)
+				    const char *next, const char *end UNUSED)
 {
 	struct strbuf err = STRBUF_INIT;
 	char *refname, *new_target;
@@ -423,7 +423,7 @@ static void parse_cmd_delete(struct ref_transaction *transaction,
 
 
 static void parse_cmd_symref_delete(struct ref_transaction *transaction,
-				    const char *next, const char *end)
+				    const char *next, const char *end UNUSED)
 {
 	struct strbuf err = STRBUF_INIT;
 	char *refname, *old_target;
@@ -479,7 +479,7 @@ static void parse_cmd_verify(struct ref_transaction *transaction,
 }
 
 static void parse_cmd_symref_verify(struct ref_transaction *transaction,
-				    const char *next, const char *end)
+				    const char *next, const char *end UNUSED)
 {
 	struct strbuf err = STRBUF_INIT;
 	struct object_id old_oid;
@@ -713,7 +713,10 @@ static void update_refs_stdin(void)
 	strbuf_release(&input);
 }
 
-int cmd_update_ref(int argc, const char **argv, const char *prefix)
+int cmd_update_ref(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	const char *refname, *oldval;
 	struct object_id oid, oldoid;
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index 1dc3971..6769611 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -9,7 +10,10 @@ static const char * const update_server_info_usage[] = {
 	NULL
 };
 
-int cmd_update_server_info(int argc, const char **argv, const char *prefix)
+int cmd_update_server_info(int argc,
+			   const char **argv,
+			   const char *prefix,
+			   struct repository *repo UNUSED)
 {
 	int force = 0;
 	struct option options[] = {
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 1b09e5e..9e9343f 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -1,12 +1,12 @@
 /*
  * Copyright (c) 2006 Franck Bui-Huu
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "archive.h"
 #include "path.h"
 #include "pkt-line.h"
 #include "sideband.h"
-#include "repository.h"
 #include "run-command.h"
 #include "strvec.h"
 
@@ -18,10 +18,14 @@ static const char deadchild[] =
 
 #define MAX_ARGS (64)
 
-int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
+int cmd_upload_archive_writer(int argc,
+			      const char **argv,
+			      const char *prefix,
+			      struct repository *repo UNUSED)
 {
 	struct strvec sent_argv = STRVEC_INIT;
 	const char *arg_cmd = "argument ";
+	int ret;
 
 	if (argc != 2 || !strcmp(argv[1], "-h"))
 		usage(upload_archive_usage);
@@ -46,8 +50,11 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
 	}
 
 	/* parse all options sent by the client */
-	return write_archive(sent_argv.nr, sent_argv.v, prefix,
-			     the_repository, NULL, 1);
+	ret = write_archive(sent_argv.nr, sent_argv.v, prefix,
+			    the_repository, NULL, 1);
+
+	strvec_clear(&sent_argv);
+	return ret;
 }
 
 __attribute__((format (printf, 1, 2)))
@@ -76,7 +83,10 @@ static ssize_t process_input(int child_fd, int band)
 	return sz;
 }
 
-int cmd_upload_archive(int argc, const char **argv, const char *prefix)
+int cmd_upload_archive(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
 {
 	struct child_process writer = CHILD_PROCESS_INIT;
 
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index 46d9327..3b6c83f 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -17,7 +17,10 @@ static const char * const upload_pack_usage[] = {
 	NULL
 };
 
-int cmd_upload_pack(int argc, const char **argv, const char *prefix)
+int cmd_upload_pack(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
 {
 	const char *dir;
 	int strict = 0;
diff --git a/builtin/var.c b/builtin/var.c
index e30ff45..2ecaed5 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -3,7 +3,9 @@
  *
  * Copyright (C) Eric Biederman, 2005
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
+
 #include "attr.h"
 #include "config.h"
 #include "editor.h"
@@ -210,7 +212,10 @@ static int show_config(const char *var, const char *value,
 	return git_default_config(var, value, ctx, cb);
 }
 
-int cmd_var(int argc, const char **argv, const char *prefix UNUSED)
+int cmd_var(int argc,
+	    const char **argv,
+	    const char *prefix UNUSED,
+	    struct repository *repo UNUSED)
 {
 	const struct git_var *git_var;
 	char *val;
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index 0d2b9ae..779b798 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -5,11 +5,11 @@
  *
  * Based on git-verify-tag
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
 #include "object-name.h"
-#include "repository.h"
 #include "commit.h"
 #include "parse-options.h"
 #include "gpg-interface.h"
@@ -51,7 +51,10 @@ static int verify_commit(const char *name, unsigned flags)
 	return run_gpg_verify((struct commit *)obj, flags);
 }
 
-int cmd_verify_commit(int argc, const char **argv, const char *prefix)
+int cmd_verify_commit(int argc,
+		      const char **argv,
+		      const char *prefix,
+		      struct repository *repo UNUSED)
 {
 	int i = 1, verbose = 0, had_error = 0;
 	unsigned flags = 0;
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index 011dddd..34e4ed7 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -61,7 +62,10 @@ static const char * const verify_pack_usage[] = {
 	NULL
 };
 
-int cmd_verify_pack(int argc, const char **argv, const char *prefix)
+int cmd_verify_pack(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
 {
 	int err = 0;
 	unsigned int flags = 0;
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index c731e2f..a7f2061 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -5,6 +5,7 @@
  *
  * Based on git-verify-tag.sh
  */
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
@@ -19,7 +20,10 @@ static const char * const verify_tag_usage[] = {
 		NULL
 };
 
-int cmd_verify_tag(int argc, const char **argv, const char *prefix)
+int cmd_verify_tag(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
 {
 	int i = 1, verbose = 0, had_error = 0;
 	unsigned flags = 0;
@@ -65,5 +69,6 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
 		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 1d51e54..fc31d07 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -1,3 +1,4 @@
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
 #include "advice.h"
@@ -17,7 +18,6 @@
 #include "read-cache-ll.h"
 #include "refs.h"
 #include "remote.h"
-#include "repository.h"
 #include "run-command.h"
 #include "hook.h"
 #include "sigchain.h"
@@ -219,7 +219,7 @@ static void prune_worktrees(void)
 	}
 	closedir(dir);
 
-	strbuf_add_absolute_path(&main_path, get_git_common_dir());
+	strbuf_add_absolute_path(&main_path, repo_get_common_dir(the_repository));
 	/* massage main worktree absolute path to match 'gitdir' content */
 	strbuf_strip_suffix(&main_path, "/.");
 	string_list_append_nodup(&kept, strbuf_detach(&main_path, NULL));
@@ -492,7 +492,7 @@ static int add_worktree(const char *path, const char *refname,
 	strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
 	strbuf_realpath(&realpath, sb_git.buf, 1);
 	write_file(sb.buf, "%s", realpath.buf);
-	strbuf_realpath(&realpath, get_git_common_dir(), 1);
+	strbuf_realpath(&realpath, repo_get_common_dir(the_repository), 1);
 	write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
 		   realpath.buf, name);
 	strbuf_reset(&sb);
@@ -573,7 +573,7 @@ static int add_worktree(const char *path, const char *refname,
 			     NULL);
 		opt.dir = path;
 
-		ret = run_hooks_opt("post-checkout", &opt);
+		ret = run_hooks_opt(the_repository, "post-checkout", &opt);
 	}
 
 	strvec_clear(&child_env);
@@ -626,6 +626,7 @@ static void print_preparing_worktree_line(int detach,
  * Returns 0 on failure and non-zero on success.
  */
 static int first_valid_ref(const char *refname UNUSED,
+			   const char *referent UNUSED,
 			   const struct object_id *oid UNUSED,
 			   int flags UNUSED,
 			   void *cb_data UNUSED)
@@ -769,7 +770,7 @@ static int add(int ac, const char **av, const char *prefix)
 	char *branch_to_free = NULL;
 	char *new_branch_to_free = NULL;
 	const char *new_branch = NULL;
-	const char *opt_track = NULL;
+	char *opt_track = NULL;
 	const char *lock_reason = NULL;
 	int keep_locked = 0;
 	int used_new_branch_options;
@@ -846,7 +847,7 @@ static int add(int ac, const char **av, const char *prefix)
 	if (opts.orphan && !new_branch) {
 		int n;
 		const char *s = worktree_basename(path, &n);
-		new_branch = xstrndup(s, n);
+		new_branch = new_branch_to_free = xstrndup(s, n);
 	} else if (opts.orphan) {
 		; /* no-op */
 	} else if (opts.detach) {
@@ -875,7 +876,7 @@ static int add(int ac, const char **av, const char *prefix)
 			remote = unique_tracking_name(branch, &oid, NULL);
 			if (remote) {
 				new_branch = branch;
-				branch = remote;
+				branch = new_branch_to_free = remote;
 			}
 		}
 
@@ -923,6 +924,7 @@ static int add(int ac, const char **av, const char *prefix)
 
 	ret = add_worktree(path, branch, &opts);
 	free(path);
+	free(opt_track);
 	free(branch_to_free);
 	free(new_branch_to_free);
 	return ret;
@@ -1146,14 +1148,14 @@ static void validate_no_submodules(const struct worktree *wt)
 	struct strbuf path = STRBUF_INIT;
 	int i, found_submodules = 0;
 
-	if (is_directory(worktree_git_path(wt, "modules"))) {
+	if (is_directory(worktree_git_path(the_repository, wt, "modules"))) {
 		/*
 		 * There could be false positives, e.g. the "modules"
 		 * directory exists but is empty. But it's a rare case and
 		 * this simpler check is probably good enough for now.
 		 */
 		found_submodules = 1;
-	} else if (read_index_from(&istate, worktree_git_path(wt, "index"),
+	} else if (read_index_from(&istate, worktree_git_path(the_repository, wt, "index"),
 				   get_worktree_git_dir(wt)) > 0) {
 		for (i = 0; i < istate.cache_nr; i++) {
 			struct cache_entry *ce = istate.cache[i];
@@ -1390,7 +1392,10 @@ static int repair(int ac, const char **av, const char *prefix)
 	return rc;
 }
 
-int cmd_worktree(int ac, const char **av, const char *prefix)
+int cmd_worktree(int ac,
+		 const char **av,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
 {
 	parse_opt_subcommand_fn *fn = NULL;
 	struct option options[] = {
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index 8c75b46..43f233e 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -3,23 +3,24 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-
+#define USE_THE_REPOSITORY_VARIABLE
 #include "builtin.h"
 #include "config.h"
-#include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "tree.h"
 #include "cache-tree.h"
 #include "parse-options.h"
-#include "repository.h"
 
 static const char * const write_tree_usage[] = {
 	N_("git write-tree [--missing-ok] [--prefix=<prefix>/]"),
 	NULL
 };
 
-int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix)
+int cmd_write_tree(int argc,
+		   const char **argv,
+		   const char *cmd_prefix,
+		   struct repository *repo UNUSED)
 {
 	int flags = 0, ret;
 	const char *tree_prefix = NULL;
@@ -44,7 +45,8 @@ int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix)
 	prepare_repo_settings(the_repository);
 	the_repository->settings.command_requires_full_index = 0;
 
-	ret = write_index_as_tree(&oid, the_repository->index, get_index_file(),
+	ret = write_index_as_tree(&oid, the_repository->index,
+				  repo_get_index_file(the_repository),
 				  flags, tree_prefix);
 	switch (ret) {
 	case 0:
diff --git a/bulk-checkin.c b/bulk-checkin.c
index da86731..2753d5b 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -61,6 +61,7 @@ static void flush_bulk_checkin_packfile(struct bulk_checkin_packfile *state)
 
 	if (state->nr_written == 0) {
 		close(state->f->fd);
+		free_hashfile(state->f);
 		unlink(state->pack_tmp_name);
 		goto clear_exit;
 	} else if (state->nr_written == 1) {
@@ -74,7 +75,7 @@ static void flush_bulk_checkin_packfile(struct bulk_checkin_packfile *state)
 		close(fd);
 	}
 
-	strbuf_addf(&packname, "%s/pack/pack-%s.", get_object_directory(),
+	strbuf_addf(&packname, "%s/pack/pack-%s.", repo_get_object_directory(the_repository),
 		    hash_to_hex(hash));
 	finish_tmp_packfile(&packname, state->pack_tmp_name,
 			    state->written, state->nr_written,
@@ -83,6 +84,7 @@ static void flush_bulk_checkin_packfile(struct bulk_checkin_packfile *state)
 		free(state->written[i]);
 
 clear_exit:
+	free(state->pack_tmp_name);
 	free(state->written);
 	memset(state, 0, sizeof(*state));
 
@@ -111,7 +113,7 @@ static void flush_batch_fsync(void)
 	 * to ensure that the data in each new object file is durable before
 	 * the final name is visible.
 	 */
-	strbuf_addf(&temp_path, "%s/bulk_fsync_XXXXXX", get_object_directory());
+	strbuf_addf(&temp_path, "%s/bulk_fsync_XXXXXX", repo_get_object_directory(the_repository));
 	temp = xmks_tempfile(temp_path.buf);
 	fsync_or_die(get_tempfile_fd(temp), get_tempfile_path(temp));
 	delete_tempfile(&temp);
diff --git a/bundle-uri.c b/bundle-uri.c
index 93e19a1..0216440 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -4,7 +4,6 @@
 #include "bundle-uri.h"
 #include "bundle.h"
 #include "copy.h"
-#include "environment.h"
 #include "gettext.h"
 #include "refs.h"
 #include "run-command.h"
@@ -13,6 +12,8 @@
 #include "config.h"
 #include "fetch-pack.h"
 #include "remote.h"
+#include "trace2.h"
+#include "object-store-ll.h"
 
 static struct {
 	enum bundle_list_heuristic heuristic;
@@ -389,17 +390,23 @@ static int unbundle_from_file(struct repository *r, const char *file)
 	struct strbuf bundle_ref = STRBUF_INIT;
 	size_t bundle_prefix_len;
 
-	if ((bundle_fd = read_bundle_header(file, &header)) < 0)
-		return 1;
+	bundle_fd = read_bundle_header(file, &header);
+	if (bundle_fd < 0) {
+		result = 1;
+		goto cleanup;
+	}
 
 	/*
 	 * Skip the reachability walk here, since we will be adding
 	 * a reachable ref pointing to the new tips, which will reach
 	 * the prerequisite commits.
 	 */
-	if ((result = unbundle(r, &header, bundle_fd, NULL,
-			       VERIFY_BUNDLE_QUIET | (fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0))))
-		return 1;
+	result = unbundle(r, &header, bundle_fd, NULL,
+			  VERIFY_BUNDLE_QUIET | (fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0));
+	if (result) {
+		result = 1;
+		goto cleanup;
+	}
 
 	/*
 	 * Convert all refs/heads/ from the bundle into refs/bundles/
@@ -428,6 +435,8 @@ static int unbundle_from_file(struct repository *r, const char *file)
 				0, UPDATE_REFS_MSG_ON_ERR);
 	}
 
+cleanup:
+	strbuf_release(&bundle_ref);
 	bundle_header_release(&header);
 	return result;
 }
@@ -821,6 +830,8 @@ int fetch_bundle_uri(struct repository *r, const char *uri,
 		.id = xstrdup(""),
 	};
 
+	trace2_region_enter("fetch", "fetch-bundle-uri", the_repository);
+
 	init_bundle_list(&list);
 
 	/*
@@ -846,6 +857,7 @@ int fetch_bundle_uri(struct repository *r, const char *uri,
 	for_all_bundles_in_list(&list, unlink_bundle, NULL);
 	clear_bundle_list(&list);
 	clear_remote_bundle_info(&bundle, NULL);
+	trace2_region_leave("fetch", "fetch-bundle-uri", the_repository);
 	return result;
 }
 
diff --git a/bundle.c b/bundle.c
index b0a8a92..4773b51 100644
--- a/bundle.c
+++ b/bundle.c
@@ -644,10 +644,8 @@ int unbundle(struct repository *r, struct bundle_header *header,
 	if (flags & VERIFY_BUNDLE_FSCK)
 		strvec_push(&ip.args, "--fsck-objects");
 
-	if (extra_index_pack_args) {
+	if (extra_index_pack_args)
 		strvec_pushv(&ip.args, extra_index_pack_args->v);
-		strvec_clear(extra_index_pack_args);
-	}
 
 	ip.in = bundle_fd;
 	ip.no_stdout = 1;
diff --git a/cache-tree.c b/cache-tree.c
index 50610c3..c595e86 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -1,7 +1,7 @@
 #define USE_THE_REPOSITORY_VARIABLE
 
 #include "git-compat-util.h"
-#include "environment.h"
+#include "gettext.h"
 #include "hex.h"
 #include "lockfile.h"
 #include "tree.h"
@@ -12,6 +12,7 @@
 #include "object-store-ll.h"
 #include "read-cache-ll.h"
 #include "replace-object.h"
+#include "repository.h"
 #include "promisor-remote.h"
 #include "trace.h"
 #include "trace2.h"
@@ -725,7 +726,8 @@ int write_index_as_tree(struct object_id *oid, struct index_state *index_state,
 
 	hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
 
-	entries = read_index_from(index_state, index_path, get_git_dir());
+	entries = read_index_from(index_state, index_path,
+				  repo_get_git_dir(the_repository));
 	if (entries < 0) {
 		ret = WRITE_TREE_UNREADABLE_INDEX;
 		goto out;
@@ -864,15 +866,15 @@ int cache_tree_matches_traversal(struct cache_tree *root,
 	return 0;
 }
 
-static void verify_one_sparse(struct index_state *istate,
-			      struct strbuf *path,
-			      int pos)
+static int verify_one_sparse(struct index_state *istate,
+			     struct strbuf *path,
+			     int pos)
 {
 	struct cache_entry *ce = istate->cache[pos];
-
 	if (!S_ISSPARSEDIR(ce->ce_mode))
-		BUG("directory '%s' is present in index, but not sparse",
-		    path->buf);
+		return error(_("directory '%s' is present in index, but not sparse"),
+			     path->buf);
+	return 0;
 }
 
 /*
@@ -881,6 +883,7 @@ static void verify_one_sparse(struct index_state *istate,
  *  1 - Restart verification - a call to ensure_full_index() freed the cache
  *      tree that is being verified and verification needs to be restarted from
  *      the new toplevel cache tree.
+ *  -1 - Verification failed.
  */
 static int verify_one(struct repository *r,
 		      struct index_state *istate,
@@ -890,18 +893,23 @@ static int verify_one(struct repository *r,
 	int i, pos, len = path->len;
 	struct strbuf tree_buf = STRBUF_INIT;
 	struct object_id new_oid;
+	int ret;
 
 	for (i = 0; i < it->subtree_nr; i++) {
 		strbuf_addf(path, "%s/", it->down[i]->name);
-		if (verify_one(r, istate, it->down[i]->cache_tree, path))
-			return 1;
+		ret = verify_one(r, istate, it->down[i]->cache_tree, path);
+		if (ret)
+			goto out;
+
 		strbuf_setlen(path, len);
 	}
 
 	if (it->entry_count < 0 ||
 	    /* no verification on tests (t7003) that replace trees */
-	    lookup_replace_object(r, &it->oid) != &it->oid)
-		return 0;
+	    lookup_replace_object(r, &it->oid) != &it->oid) {
+		ret = 0;
+		goto out;
+	}
 
 	if (path->len) {
 		/*
@@ -911,12 +919,14 @@ static int verify_one(struct repository *r,
 		 */
 		int is_sparse = istate->sparse_index;
 		pos = index_name_pos(istate, path->buf, path->len);
-		if (is_sparse && !istate->sparse_index)
-			return 1;
+		if (is_sparse && !istate->sparse_index) {
+			ret = 1;
+			goto out;
+		}
 
 		if (pos >= 0) {
-			verify_one_sparse(istate, path, pos);
-			return 0;
+			ret = verify_one_sparse(istate, path, pos);
+			goto out;
 		}
 
 		pos = -pos - 1;
@@ -924,6 +934,11 @@ static int verify_one(struct repository *r,
 		pos = 0;
 	}
 
+	if (it->entry_count + pos > istate->cache_nr) {
+		ret = error(_("corrupted cache-tree has entries not present in index"));
+		goto out;
+	}
+
 	i = 0;
 	while (i < it->entry_count) {
 		struct cache_entry *ce = istate->cache[pos + i];
@@ -934,16 +949,23 @@ static int verify_one(struct repository *r,
 		unsigned mode;
 		int entlen;
 
-		if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE))
-			BUG("%s with flags 0x%x should not be in cache-tree",
-			    ce->name, ce->ce_flags);
+		if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE)) {
+			ret = error(_("%s with flags 0x%x should not be in cache-tree"),
+				    ce->name, ce->ce_flags);
+			goto out;
+		}
+
 		name = ce->name + path->len;
 		slash = strchr(name, '/');
 		if (slash) {
 			entlen = slash - name;
+
 			sub = find_subtree(it, ce->name + path->len, entlen, 0);
-			if (!sub || sub->cache_tree->entry_count < 0)
-				BUG("bad subtree '%.*s'", entlen, name);
+			if (!sub || sub->cache_tree->entry_count < 0) {
+				ret = error(_("bad subtree '%.*s'"), entlen, name);
+				goto out;
+			}
+
 			oid = &sub->cache_tree->oid;
 			mode = S_IFDIR;
 			i += sub->cache_tree->entry_count;
@@ -956,27 +978,50 @@ static int verify_one(struct repository *r,
 		strbuf_addf(&tree_buf, "%o %.*s%c", mode, entlen, name, '\0');
 		strbuf_add(&tree_buf, oid->hash, r->hash_algo->rawsz);
 	}
+
 	hash_object_file(r->hash_algo, tree_buf.buf, tree_buf.len, OBJ_TREE,
 			 &new_oid);
-	if (!oideq(&new_oid, &it->oid))
-		BUG("cache-tree for path %.*s does not match. "
-		    "Expected %s got %s", len, path->buf,
-		    oid_to_hex(&new_oid), oid_to_hex(&it->oid));
+
+	if (!oideq(&new_oid, &it->oid)) {
+		ret = error(_("cache-tree for path %.*s does not match. "
+			      "Expected %s got %s"), len, path->buf,
+			    oid_to_hex(&new_oid), oid_to_hex(&it->oid));
+		goto out;
+	}
+
+	ret = 0;
+out:
 	strbuf_setlen(path, len);
 	strbuf_release(&tree_buf);
-	return 0;
+	return ret;
 }
 
-void cache_tree_verify(struct repository *r, struct index_state *istate)
+int cache_tree_verify(struct repository *r, struct index_state *istate)
 {
 	struct strbuf path = STRBUF_INIT;
+	int ret;
 
-	if (!istate->cache_tree)
-		return;
-	if (verify_one(r, istate, istate->cache_tree, &path)) {
+	if (!istate->cache_tree) {
+		ret = 0;
+		goto out;
+	}
+
+	ret = verify_one(r, istate, istate->cache_tree, &path);
+	if (ret < 0)
+		goto out;
+	if (ret > 0) {
 		strbuf_reset(&path);
-		if (verify_one(r, istate, istate->cache_tree, &path))
+
+		ret = verify_one(r, istate, istate->cache_tree, &path);
+		if (ret < 0)
+			goto out;
+		if (ret > 0)
 			BUG("ensure_full_index() called twice while verifying cache tree");
 	}
+
+	ret = 0;
+
+out:
 	strbuf_release(&path);
+	return ret;
 }
diff --git a/cache-tree.h b/cache-tree.h
index faae88b..b82c496 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -33,7 +33,7 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
 
 int cache_tree_fully_valid(struct cache_tree *);
 int cache_tree_update(struct index_state *, int);
-void cache_tree_verify(struct repository *, struct index_state *);
+int cache_tree_verify(struct repository *, struct index_state *);
 
 /* bitmasks to write_index_as_tree flags */
 #define WRITE_TREE_MISSING_OK 1
diff --git a/cbtree.c b/cbtree.c
index c1cc30a..cf8cf75 100644
--- a/cbtree.c
+++ b/cbtree.c
@@ -12,7 +12,7 @@ static struct cb_node *cb_node_of(const void *p)
 	return (struct cb_node *)((uintptr_t)p - 1);
 }
 
-/* locate the best match, does not do a final comparision */
+/* locate the best match, does not do a final comparison */
 static struct cb_node *cb_internal_best_match(struct cb_node *p,
 					const uint8_t *k, size_t klen)
 {
diff --git a/ci/check-whitespace.sh b/ci/check-whitespace.sh
index db39909..c408043 100755
--- a/ci/check-whitespace.sh
+++ b/ci/check-whitespace.sh
@@ -9,7 +9,7 @@
 outputFile=$2
 url=$3
 
-if test "$#" -ne 1 && test "$#" -ne 3
+if test "$#" -ne 1 && test "$#" -ne 3 || test -z "$1"
 then
 	echo "USAGE: $0 <BASE_COMMIT> [<OUTPUT_FILE> <URL>]"
 	exit 1
@@ -21,6 +21,12 @@
 commitTextmd=
 goodParent=
 
+if ! git rev-parse --quiet --verify "${baseCommit}"
+then
+    echo "Invalid <BASE_COMMIT> '${baseCommit}'"
+    exit 1
+fi
+
 while read dash sha etc
 do
 	case "${dash}" in
@@ -67,7 +73,7 @@
 		goodParent=${baseCommit: 0:7}
 	fi
 
-	echo "A whitespace issue was found in onen of more of the commits."
+	echo "A whitespace issue was found in one or more of the commits."
 	echo "Run the following command to resolve whitespace issues:"
 	echo "git rebase --whitespace=fix ${goodParent}"
 
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
index e2c6ef0..08656a1 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -99,6 +99,10 @@
 esac
 
 case "$jobname" in
+ClangFormat)
+	sudo apt-get -q update
+	sudo apt-get -q -y install clang-format
+	;;
 StaticAnalysis)
 	sudo apt-get -q update
 	sudo apt-get -q -y install coccinelle libcurl4-openssl-dev libssl-dev \
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
index 98dda42..2e28d02 100755
--- a/ci/run-build-and-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -25,7 +25,7 @@
 	export GIT_TEST_COMMIT_GRAPH=1
 	export GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=1
 	export GIT_TEST_MULTI_PACK_INDEX=1
-	export GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=1
+	export GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=1
 	export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
 	export GIT_TEST_NO_WRITE_REV_INDEX=1
 	export GIT_TEST_CHECKOUT_WORKERS=2
diff --git a/ci/run-style-check.sh b/ci/run-style-check.sh
new file mode 100755
index 0000000..6cd4b1d
--- /dev/null
+++ b/ci/run-style-check.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Perform style check
+#
+
+baseCommit=$1
+
+# Remove optional braces of control statements (if, else, for, and while)
+# according to the LLVM coding style. This avoids braces on simple
+# single-statement bodies of statements but keeps braces if one side of
+# if/else if/.../else cascade has multi-statement body.
+#
+# As this rule comes with a warning [1], we want to experiment with it
+# before adding it in-tree. since the CI job for the style check is allowed
+# to fail, appending the rule here allows us to validate its efficacy.
+# While also ensuring that end-users are not affected directly.
+#
+# [1]: https://clang.llvm.org/docs/ClangFormatStyleOptions.html#removebracesllvm
+{
+	cat .clang-format
+	echo "RemoveBracesLLVM: true"
+} >/tmp/clang-format-rules
+
+git clang-format --style=file:/tmp/clang-format-rules \
+	--diff --extensions c,h "$baseCommit"
diff --git a/combine-diff.c b/combine-diff.c
index 829a44e..f6b624d 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -1393,9 +1393,8 @@ static struct combine_diff_path *find_paths_generic(const struct object_id *oid,
 {
 	struct combine_diff_path *paths = NULL;
 	int i, num_parent = parents->nr;
-
 	int output_format = opt->output_format;
-	const char *orderfile = opt->orderfile;
+	char *orderfile = opt->orderfile;
 
 	opt->output_format = DIFF_FORMAT_NO_OUTPUT;
 	/* tell diff_tree to emit paths in sorted (=tree) order */
diff --git a/commit-graph.c b/commit-graph.c
index 79b0e72..5bd89c0 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1847,6 +1847,7 @@ struct refs_cb_data {
 };
 
 static int add_ref_to_set(const char *refname UNUSED,
+			  const char *referent UNUSED,
 			  const struct object_id *oid,
 			  int flags UNUSED, void *cb_data)
 {
@@ -2054,7 +2055,6 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 	}
 
 	if (safe_create_leading_directories(ctx->graph_name)) {
-		UNLEAK(ctx->graph_name);
 		error(_("unable to create leading directories of %s"),
 			ctx->graph_name);
 		return -1;
diff --git a/commit-reach.c b/commit-reach.c
index dabc2972..c3518aa 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -1227,4 +1227,131 @@ void tips_reachable_from_bases(struct repository *r,
 done:
 	free(commits);
 	repo_clear_commit_marks(r, SEEN);
+	free_commit_list(stack);
+}
+
+/*
+ * This slab initializes integers to zero, so use "-1" for "tip is best" and
+ * "i + 1" for "bases[i] is best".
+ */
+define_commit_slab(best_branch_base, int);
+static struct best_branch_base best_branch_base;
+#define get_best(c) (*best_branch_base_at(&best_branch_base, (c)))
+#define set_best(c,v) (*best_branch_base_at(&best_branch_base, (c)) = (v))
+
+int get_branch_base_for_tip(struct repository *r,
+			    struct commit *tip,
+			    struct commit **bases,
+			    size_t bases_nr)
+{
+	int best_index = -1;
+	struct commit *branch_point = NULL;
+	struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
+	int found_missing_gen = 0;
+
+	if (!bases_nr)
+		return -1;
+
+	repo_parse_commit(r, tip);
+	if (commit_graph_generation(tip) == GENERATION_NUMBER_INFINITY)
+		found_missing_gen = 1;
+
+	/* Check for missing generation numbers. */
+	for (size_t i = 0; i < bases_nr; i++) {
+		struct commit *c = bases[i];
+		repo_parse_commit(r, c);
+		if (commit_graph_generation(c) == GENERATION_NUMBER_INFINITY)
+			found_missing_gen = 1;
+	}
+
+	if (found_missing_gen) {
+		struct commit **commits;
+		size_t commits_nr = bases_nr + 1;
+
+		CALLOC_ARRAY(commits, commits_nr);
+		COPY_ARRAY(commits, bases, bases_nr);
+		commits[bases_nr] = tip;
+		ensure_generations_valid(r, commits, commits_nr);
+		free(commits);
+	}
+
+	/* Initialize queue and slab now that generations are guaranteed. */
+	init_best_branch_base(&best_branch_base);
+	set_best(tip, -1);
+	prio_queue_put(&queue, tip);
+
+	for (size_t i = 0; i < bases_nr; i++) {
+		struct commit *c = bases[i];
+		int best = get_best(c);
+
+		/* Has this already been marked as best by another commit? */
+		if (best) {
+			if (best == -1) {
+				/* We agree at this position. Stop now. */
+				best_index = i + 1;
+				goto cleanup;
+			}
+			continue;
+		}
+
+		set_best(c, i + 1);
+		prio_queue_put(&queue, c);
+	}
+
+	while (queue.nr) {
+		struct commit *c = prio_queue_get(&queue);
+		int best_for_c = get_best(c);
+		int best_for_p, positive;
+		struct commit *parent;
+
+		/* Have we reached a known branch point? It's optimal. */
+		if (c == branch_point)
+			break;
+
+		repo_parse_commit(r, c);
+		if (!c->parents)
+			continue;
+
+		parent = c->parents->item;
+		repo_parse_commit(r, parent);
+		best_for_p = get_best(parent);
+
+		if (!best_for_p) {
+			/* 'parent' is new, so pass along best_for_c. */
+			set_best(parent, best_for_c);
+			prio_queue_put(&queue, parent);
+			continue;
+		}
+
+		if (best_for_p > 0 && best_for_c > 0) {
+			/* Collision among bases. Minimize. */
+			if (best_for_c < best_for_p)
+				set_best(parent, best_for_c);
+			continue;
+		}
+
+		/*
+		 * At this point, we have reached a commit that is reachable
+		 * from the tip, either from 'c' or from an earlier commit to
+		 * have 'parent' as its first parent.
+		 *
+		 * Update 'best_index' to match the minimum of all base indices
+		 * to reach 'parent'.
+		 */
+
+		/* Exactly one is positive due to initial conditions. */
+		positive = (best_for_c < 0) ? best_for_p : best_for_c;
+
+		if (best_index < 0 || positive < best_index)
+			best_index = positive;
+
+		/* No matter what, track that the parent is reachable from tip. */
+		set_best(parent, -1);
+		branch_point = parent;
+	}
+
+cleanup:
+	clear_best_branch_base(&best_branch_base);
+	clear_prio_queue(&queue);
+	return best_index > 0 ? best_index - 1 : -1;
 }
diff --git a/commit-reach.h b/commit-reach.h
index bf63cc4..9a745b7 100644
--- a/commit-reach.h
+++ b/commit-reach.h
@@ -139,4 +139,21 @@ void tips_reachable_from_bases(struct repository *r,
 			       struct commit **tips, size_t tips_nr,
 			       int mark);
 
+/*
+ * Given a 'tip' commit and a list potential 'bases', return the index 'i' that
+ * minimizes the number of commits in the first-parent history of 'tip' and not
+ * in the first-parent history of 'bases[i]'.
+ *
+ * Among a list of long-lived branches that are updated only by merges (with the
+ * first parent being the previous position of the branch), this would inform
+ * which branch was used to create the tip reference.
+ *
+ * Returns -1 if no common point is found in first-parent histories, which is
+ * rare, but possible with multiple root commits.
+ */
+int get_branch_base_for_tip(struct repository *r,
+			    struct commit *tip,
+			    struct commit **bases,
+			    size_t bases_nr);
+
 #endif
diff --git a/commit.c b/commit.c
index 087cb19..cc03a93 100644
--- a/commit.c
+++ b/commit.c
@@ -85,12 +85,18 @@ struct commit *lookup_commit(struct repository *r, const struct object_id *oid)
 
 struct commit *lookup_commit_reference_by_name(const char *name)
 {
+	return lookup_commit_reference_by_name_gently(name, 0);
+}
+
+struct commit *lookup_commit_reference_by_name_gently(const char *name,
+						      int quiet)
+{
 	struct object_id oid;
 	struct commit *commit;
 
 	if (repo_get_oid_committish(the_repository, name, &oid))
 		return NULL;
-	commit = lookup_commit_reference(the_repository, &oid);
+	commit = lookup_commit_reference_gently(the_repository, &oid, quiet);
 	if (repo_parse_commit(the_repository, commit))
 		return NULL;
 	return commit;
@@ -177,7 +183,7 @@ int commit_graft_pos(struct repository *r, const struct object_id *oid)
 		       commit_graft_oid_access);
 }
 
-static void unparse_commit(struct repository *r, const struct object_id *oid)
+void unparse_commit(struct repository *r, const struct object_id *oid)
 {
 	struct commit *c = lookup_commit(r, oid);
 
@@ -286,14 +292,14 @@ static int read_graft_file(struct repository *r, const char *graft_file)
 
 void prepare_commit_graft(struct repository *r)
 {
-	char *graft_file;
+	const char *graft_file;
 
 	if (r->parsed_objects->commit_graft_prepared)
 		return;
 	if (!startup_info->have_repository)
 		return;
 
-	graft_file = get_graft_file(r);
+	graft_file = repo_get_graft_file(r);
 	read_graft_file(r, graft_file);
 	/* make sure shallows are read */
 	is_repository_shallow(r);
@@ -318,18 +324,6 @@ int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
 	return ret;
 }
 
-void reset_commit_grafts(struct repository *r)
-{
-	int i;
-
-	for (i = 0; i < r->parsed_objects->grafts_nr; i++) {
-		unparse_commit(r, &r->parsed_objects->grafts[i]->oid);
-		free(r->parsed_objects->grafts[i]);
-	}
-	r->parsed_objects->grafts_nr = 0;
-	r->parsed_objects->commit_graft_prepared = 0;
-}
-
 struct commit_buffer {
 	void *buffer;
 	unsigned long size;
@@ -601,7 +595,8 @@ int repo_parse_commit_internal(struct repository *r,
 	}
 
 	ret = parse_commit_buffer(r, item, buffer, size, 0);
-	if (save_commit_buffer && !ret) {
+	if (save_commit_buffer && !ret &&
+	    !get_cached_commit_buffer(r, item, NULL)) {
 		set_commit_buffer(r, item, buffer, size);
 		return 0;
 	}
@@ -1150,11 +1145,14 @@ int add_header_signature(struct strbuf *buf, struct strbuf *sig, const struct gi
 
 static int sign_commit_to_strbuf(struct strbuf *sig, struct strbuf *buf, const char *keyid)
 {
+	char *keyid_to_free = NULL;
+	int ret = 0;
 	if (!keyid || !*keyid)
-		keyid = get_signing_key();
+		keyid = keyid_to_free = get_signing_key();
 	if (sign_buffer(buf, sig, keyid))
-		return -1;
-	return 0;
+		ret = -1;
+	free(keyid_to_free);
+	return ret;
 }
 
 int parse_signed_commit(const struct commit *commit,
@@ -1960,5 +1958,5 @@ int run_commit_hook(int editor_is_used, const char *index_file,
 	va_end(args);
 
 	opt.invoked_hook = invoked_hook;
-	return run_hooks_opt(name, &opt);
+	return run_hooks_opt(the_repository, name, &opt);
 }
diff --git a/commit.h b/commit.h
index d62b1d9..943e3d7 100644
--- a/commit.h
+++ b/commit.h
@@ -81,6 +81,8 @@ struct commit *lookup_commit_reference_gently(struct repository *r,
 					      const struct object_id *oid,
 					      int quiet);
 struct commit *lookup_commit_reference_by_name(const char *name);
+struct commit *lookup_commit_reference_by_name_gently(const char *name,
+						      int quiet);
 
 /*
  * Look up object named by "oid", dereference tag as necessary,
@@ -108,6 +110,8 @@ static inline int repo_parse_commit_no_graph(struct repository *r,
 
 void parse_commit_or_die(struct commit *item);
 
+void unparse_commit(struct repository *r, const struct object_id *oid);
+
 struct buffer_slab;
 struct buffer_slab *allocate_commit_buffer_slab(void);
 void free_commit_buffer_slab(struct buffer_slab *bs);
@@ -240,7 +244,6 @@ int commit_graft_pos(struct repository *r, const struct object_id *oid);
 int register_commit_graft(struct repository *r, struct commit_graft *, int);
 void prepare_commit_graft(struct repository *r);
 struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
-void reset_commit_grafts(struct repository *r);
 
 struct commit *get_fork_point(const char *refname, struct commit *commit);
 
@@ -251,7 +254,10 @@ struct oid_array;
 struct ref;
 int for_each_commit_graft(each_commit_graft_fn, void *);
 
-int interactive_add(const char **argv, const char *prefix, int patch);
+int interactive_add(struct repository *repo,
+		    const char **argv,
+		    const char *prefix,
+		    int patch);
 
 struct commit_extra_header {
 	struct commit_extra_header *next;
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
index 52f4f29..fe149a1 100644
--- a/compat/fsmonitor/fsm-ipc-darwin.c
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "gettext.h"
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 2fc6744..dfa5514 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -516,6 +516,12 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
 	}
 	data->stream_started = 1;
 
+	/*
+	 * Our fs event listener is now running, so it's safe to start
+	 * serving client requests.
+	 */
+	ipc_server_start_async(state->ipc_server_data);
+
 	pthread_mutex_lock(&data->dq_lock);
 	pthread_cond_wait(&data->dq_finished, &data->dq_lock);
 	pthread_mutex_unlock(&data->dq_lock);
diff --git a/compat/fsmonitor/fsm-listen-win32.c b/compat/fsmonitor/fsm-listen-win32.c
index 5a21dad..9a6efc9 100644
--- a/compat/fsmonitor/fsm-listen-win32.c
+++ b/compat/fsmonitor/fsm-listen-win32.c
@@ -431,9 +431,9 @@ static int recv_rdcw_watch(struct one_watch *watch)
 	 * but I observed ERROR_ACCESS_DENIED (0x05) errors during
 	 * testing.
 	 *
-	 * Note that we only get notificaiton events for events
+	 * Note that we only get notification events for events
 	 * *within* the directory, not *on* the directory itself.
-	 * (These might be properies of the parent directory, for
+	 * (These might be properties of the parent directory, for
 	 * example).
 	 *
 	 * NEEDSWORK: We might try to check for the deleted directory
@@ -741,6 +741,12 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
 	    start_rdcw_watch(data->watch_gitdir) == -1)
 		goto force_error_stop;
 
+	/*
+	 * Now that we've established the rdcw watches, we can start
+	 * serving clients.
+	 */
+	ipc_server_start_async(state->ipc_server_data);
+
 	for (;;) {
 		dwWait = WaitForMultipleObjects(data->nr_listener_handles,
 						data->hListener,
diff --git a/compat/mingw.c b/compat/mingw.c
index 29d3f09..0e851ec 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "../git-compat-util.h"
 #include "win32.h"
 #include <aclapi.h>
@@ -243,7 +245,8 @@ static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 static char *unset_environment_variables;
 
 int mingw_core_config(const char *var, const char *value,
-		      const struct config_context *ctx, void *cb)
+		      const struct config_context *ctx UNUSED,
+		      void *cb UNUSED)
 {
 	if (!strcmp(var, "core.hidedotfiles")) {
 		if (value && !strcasecmp(value, "dotgitonly"))
@@ -453,7 +456,7 @@ static int set_hidden_flag(const wchar_t *path, int set)
 	return -1;
 }
 
-int mingw_mkdir(const char *path, int mode)
+int mingw_mkdir(const char *path, int mode UNUSED)
 {
 	int ret;
 	wchar_t wpath[MAX_PATH];
@@ -597,7 +600,7 @@ int mingw_open (const char *filename, int oflags, ...)
 	return fd;
 }
 
-static BOOL WINAPI ctrl_ignore(DWORD type)
+static BOOL WINAPI ctrl_ignore(DWORD type UNUSED)
 {
 	return TRUE;
 }
@@ -1085,7 +1088,7 @@ int mkstemp(char *template)
 	return git_mkstemp_mode(template, 0600);
 }
 
-int gettimeofday(struct timeval *tv, void *tz)
+int gettimeofday(struct timeval *tv, void *tz UNUSED)
 {
 	FILETIME ft;
 	long long hnsec;
@@ -2252,7 +2255,7 @@ char *mingw_query_user_email(void)
 	return get_extended_user_info(NameUserPrincipal);
 }
 
-struct passwd *getpwuid(int uid)
+struct passwd *getpwuid(int uid UNUSED)
 {
 	static unsigned initialized;
 	static char user_name[100];
@@ -2304,7 +2307,7 @@ static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
  * length to call the signal handler.
  */
 
-static unsigned __stdcall ticktack(void *dummy)
+static unsigned __stdcall ticktack(void *dummy UNUSED)
 {
 	while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
 		mingw_raise(SIGALRM);
@@ -2352,7 +2355,7 @@ static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *
 	return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
 }
 
-int setitimer(int type, struct itimerval *in, struct itimerval *out)
+int setitimer(int type UNUSED, struct itimerval *in, struct itimerval *out)
 {
 	static const struct timeval zero;
 	static int atexit_done;
diff --git a/compat/mingw.h b/compat/mingw.h
index 27b6128..ebfb8ba 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -122,17 +122,17 @@ struct utsname {
  * trivial stubs
  */
 
-static inline int readlink(const char *path, char *buf, size_t bufsiz)
+static inline int readlink(const char *path UNUSED, char *buf UNUSED, size_t bufsiz UNUSED)
 { errno = ENOSYS; return -1; }
-static inline int symlink(const char *oldpath, const char *newpath)
+static inline int symlink(const char *oldpath UNUSED, const char *newpath UNUSED)
 { errno = ENOSYS; return -1; }
-static inline int fchmod(int fildes, mode_t mode)
+static inline int fchmod(int fildes UNUSED, mode_t mode UNUSED)
 { errno = ENOSYS; return -1; }
 #ifndef __MINGW64_VERSION_MAJOR
 static inline pid_t fork(void)
 { errno = ENOSYS; return -1; }
 #endif
-static inline unsigned int alarm(unsigned int seconds)
+static inline unsigned int alarm(unsigned int seconds UNUSED)
 { return 0; }
 static inline int fsync(int fd)
 { return _commit(fd); }
@@ -140,9 +140,9 @@ static inline void sync(void)
 {}
 static inline uid_t getuid(void)
 { return 1; }
-static inline struct passwd *getpwnam(const char *name)
+static inline struct passwd *getpwnam(const char *name UNUSED)
 { return NULL; }
-static inline int fcntl(int fd, int cmd, ...)
+static inline int fcntl(int fd UNUSED, int cmd, ...)
 {
 	if (cmd == F_GETFD || cmd == F_SETFD)
 		return 0;
@@ -151,17 +151,17 @@ static inline int fcntl(int fd, int cmd, ...)
 }
 
 #define sigemptyset(x) (void)0
-static inline int sigaddset(sigset_t *set, int signum)
+static inline int sigaddset(sigset_t *set UNUSED, int signum UNUSED)
 { return 0; }
 #define SIG_BLOCK 0
 #define SIG_UNBLOCK 0
-static inline int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
+static inline int sigprocmask(int how UNUSED, const sigset_t *set UNUSED, sigset_t *oldset UNUSED)
 { return 0; }
 static inline pid_t getppid(void)
 { return 1; }
 static inline pid_t getpgid(pid_t pid)
 { return pid == 0 ? getpid() : pid; }
-static inline pid_t tcgetpgrp(int fd)
+static inline pid_t tcgetpgrp(int fd UNUSED)
 { return getpid(); }
 
 /*
diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c
index 2c0ace7..145255d 100644
--- a/compat/nedmalloc/nedmalloc.c
+++ b/compat/nedmalloc/nedmalloc.c
@@ -31,6 +31,8 @@ DEALINGS IN THE SOFTWARE.
 /*#pragma optimize("a", on)*/
 #endif
 
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
 /*#define FULLSANITYCHECKS*/
 
 #include "nedmalloc.h"
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 0bd5c24..f7cc7b3 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -4,6 +4,7 @@
  */
 
 #define PRECOMPOSE_UNICODE_C
+#define USE_THE_REPOSITORY_VARIABLE
 
 #include "git-compat-util.h"
 #include "config.h"
diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c
index 6c5d455..8d93a9b 100644
--- a/compat/regex/regcomp.c
+++ b/compat/regex/regcomp.c
@@ -17,6 +17,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
 #if defined __TANDEM
  /* This is currently duplicated from git-compat-utils.h */
 # ifdef NO_INTPTR_T
diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c
index e92be57..2eeec82 100644
--- a/compat/regex/regexec.c
+++ b/compat/regex/regexec.c
@@ -292,7 +292,7 @@ compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
    concerned.
 
    If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match
-   and all groups is stroed in REGS.  (For the "_2" variants, the offsets are
+   and all groups are stored in REGS.  (For the "_2" variants, the offsets are
    computed relative to the concatenation, not relative to the individual
    strings.)
 
diff --git a/compat/simple-ipc/ipc-shared.c b/compat/simple-ipc/ipc-shared.c
index cb176d9..d1c21b4 100644
--- a/compat/simple-ipc/ipc-shared.c
+++ b/compat/simple-ipc/ipc-shared.c
@@ -16,11 +16,12 @@ int ipc_server_run(const char *path, const struct ipc_server_opts *opts,
 	struct ipc_server_data *server_data = NULL;
 	int ret;
 
-	ret = ipc_server_run_async(&server_data, path, opts,
-				   application_cb, application_data);
+	ret = ipc_server_init_async(&server_data, path, opts,
+				    application_cb, application_data);
 	if (ret)
 		return ret;
 
+	ipc_server_start_async(server_data);
 	ret = ipc_server_await(server_data);
 
 	ipc_server_free(server_data);
diff --git a/compat/simple-ipc/ipc-unix-socket.c b/compat/simple-ipc/ipc-unix-socket.c
index 9b3f2cd..7db3b2a 100644
--- a/compat/simple-ipc/ipc-unix-socket.c
+++ b/compat/simple-ipc/ipc-unix-socket.c
@@ -328,6 +328,7 @@ struct ipc_server_data {
 	int back_pos;
 	int front_pos;
 
+	int started;
 	int shutdown_requested;
 	int is_stopped;
 };
@@ -712,7 +713,7 @@ static int accept_thread__wait_for_connection(
  * Block SIGPIPE in this thread for the life of the thread.  This
  * avoids any stray SIGPIPE signals when closing pipe fds under
  * extremely heavy loads (such as when the fifo queue is full and we
- * drop incomming connections).
+ * drop incoming connections).
  */
 static void *accept_thread_proc(void *_accept_thread_data)
 {
@@ -824,10 +825,10 @@ static int setup_listener_socket(
 /*
  * Start IPC server in a pool of background threads.
  */
-int ipc_server_run_async(struct ipc_server_data **returned_server_data,
-			 const char *path, const struct ipc_server_opts *opts,
-			 ipc_server_application_cb *application_cb,
-			 void *application_data)
+int ipc_server_init_async(struct ipc_server_data **returned_server_data,
+			  const char *path, const struct ipc_server_opts *opts,
+			  ipc_server_application_cb *application_cb,
+			  void *application_data)
 {
 	struct unix_ss_socket *server_socket = NULL;
 	struct ipc_server_data *server_data;
@@ -888,6 +889,12 @@ int ipc_server_run_async(struct ipc_server_data **returned_server_data,
 	server_data->accept_thread->fd_send_shutdown = sv[0];
 	server_data->accept_thread->fd_wait_shutdown = sv[1];
 
+	/*
+	 * Hold work-available mutex so that no work can start until
+	 * we unlock it.
+	 */
+	pthread_mutex_lock(&server_data->work_available_mutex);
+
 	if (pthread_create(&server_data->accept_thread->pthread_id, NULL,
 			   accept_thread_proc, server_data->accept_thread))
 		die_errno(_("could not start accept_thread '%s'"), path);
@@ -918,6 +925,15 @@ int ipc_server_run_async(struct ipc_server_data **returned_server_data,
 	return 0;
 }
 
+void ipc_server_start_async(struct ipc_server_data *server_data)
+{
+	if (!server_data || server_data->started)
+		return;
+
+	server_data->started = 1;
+	pthread_mutex_unlock(&server_data->work_available_mutex);
+}
+
 /*
  * Gently tell the IPC server treads to shutdown.
  * Can be run on any thread.
@@ -933,7 +949,9 @@ int ipc_server_stop_async(struct ipc_server_data *server_data)
 
 	trace2_region_enter("ipc-server", "server-stop-async", NULL);
 
-	pthread_mutex_lock(&server_data->work_available_mutex);
+	/* If we haven't started yet, we are already holding lock. */
+	if (server_data->started)
+		pthread_mutex_lock(&server_data->work_available_mutex);
 
 	server_data->shutdown_requested = 1;
 
diff --git a/compat/simple-ipc/ipc-win32.c b/compat/simple-ipc/ipc-win32.c
index 8bfe512..a8fc812 100644
--- a/compat/simple-ipc/ipc-win32.c
+++ b/compat/simple-ipc/ipc-win32.c
@@ -371,6 +371,9 @@ struct ipc_server_data {
 	HANDLE hEventStopRequested;
 	struct ipc_server_thread_data *thread_list;
 	int is_stopped;
+
+	pthread_mutex_t startup_barrier;
+	int started;
 };
 
 enum connect_result {
@@ -526,6 +529,16 @@ static int use_connection(struct ipc_server_thread_data *server_thread_data)
 	return ret;
 }
 
+static void wait_for_startup_barrier(struct ipc_server_data *server_data)
+{
+	/*
+	 * Temporarily hold the startup_barrier mutex before starting,
+	 * which lets us know that it's OK to start serving requests.
+	 */
+	pthread_mutex_lock(&server_data->startup_barrier);
+	pthread_mutex_unlock(&server_data->startup_barrier);
+}
+
 /*
  * Thread proc for an IPC server worker thread.  It handles a series of
  * connections from clients.  It cleans and reuses the hPipe between each
@@ -550,6 +563,8 @@ static void *server_thread_proc(void *_server_thread_data)
 	memset(&oConnect, 0, sizeof(oConnect));
 	oConnect.hEvent = hEventConnected;
 
+	wait_for_startup_barrier(server_thread_data->server_data);
+
 	for (;;) {
 		cr = wait_for_connection(server_thread_data, &oConnect);
 
@@ -752,10 +767,10 @@ static HANDLE create_new_pipe(wchar_t *wpath, int is_first)
 	return hPipe;
 }
 
-int ipc_server_run_async(struct ipc_server_data **returned_server_data,
-			 const char *path, const struct ipc_server_opts *opts,
-			 ipc_server_application_cb *application_cb,
-			 void *application_data)
+int ipc_server_init_async(struct ipc_server_data **returned_server_data,
+			  const char *path, const struct ipc_server_opts *opts,
+			  ipc_server_application_cb *application_cb,
+			  void *application_data)
 {
 	struct ipc_server_data *server_data;
 	wchar_t wpath[MAX_PATH];
@@ -787,6 +802,13 @@ int ipc_server_run_async(struct ipc_server_data **returned_server_data,
 	strbuf_addstr(&server_data->buf_path, path);
 	wcscpy(server_data->wpath, wpath);
 
+	/*
+	 * Hold the startup_barrier lock so that no threads will progress
+	 * until ipc_server_start_async() is called.
+	 */
+	pthread_mutex_init(&server_data->startup_barrier, NULL);
+	pthread_mutex_lock(&server_data->startup_barrier);
+
 	if (nr_threads < 1)
 		nr_threads = 1;
 
@@ -837,6 +859,15 @@ int ipc_server_run_async(struct ipc_server_data **returned_server_data,
 	return 0;
 }
 
+void ipc_server_start_async(struct ipc_server_data *server_data)
+{
+	if (!server_data || server_data->started)
+		return;
+
+	server_data->started = 1;
+	pthread_mutex_unlock(&server_data->startup_barrier);
+}
+
 int ipc_server_stop_async(struct ipc_server_data *server_data)
 {
 	if (!server_data)
@@ -850,6 +881,13 @@ int ipc_server_stop_async(struct ipc_server_data *server_data)
 	 * We DO NOT attempt to force them to drop an active connection.
 	 */
 	SetEvent(server_data->hEventStopRequested);
+
+	/*
+	 * If we haven't yet told the threads they are allowed to run,
+	 * do so now, so they can receive the shutdown event.
+	 */
+	ipc_server_start_async(server_data);
+
 	return 0;
 }
 
@@ -900,5 +938,7 @@ void ipc_server_free(struct ipc_server_data *server_data)
 		free(std);
 	}
 
+	pthread_mutex_destroy(&server_data->startup_barrier);
+
 	free(server_data);
 }
diff --git a/compat/stub/procinfo.c b/compat/stub/procinfo.c
index 12c0a23..3168cd5 100644
--- a/compat/stub/procinfo.c
+++ b/compat/stub/procinfo.c
@@ -6,6 +6,6 @@
  * Stub. See sample implementations in compat/linux/procinfo.c and
  * compat/win32/trace2_win32_process_info.c.
  */
-void trace2_collect_process_info(enum trace2_process_info_reason reason)
+void trace2_collect_process_info(enum trace2_process_info_reason reason UNUSED)
 {
 }
diff --git a/compat/win32/headless.c b/compat/win32/headless.c
index 8b00dfe..11392a0 100644
--- a/compat/win32/headless.c
+++ b/compat/win32/headless.c
@@ -11,6 +11,8 @@
 #include <stdlib.h>
 #include <wchar.h>
 
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
 /*
  * If `dir` contains the path to a Git exec directory, extend `PATH` to
  * include the corresponding `bin/` directory (which is where all those
diff --git a/compat/win32/path-utils.c b/compat/win32/path-utils.c
index b658ca3..966ef77 100644
--- a/compat/win32/path-utils.c
+++ b/compat/win32/path-utils.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "../../git-compat-util.h"
 #include "../../environment.h"
 
diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c
index 85f8f79..58980a5 100644
--- a/compat/win32/pthread.c
+++ b/compat/win32/pthread.c
@@ -21,7 +21,7 @@ static unsigned __stdcall win32_start_routine(void *arg)
 	return 0;
 }
 
-int pthread_create(pthread_t *thread, const void *unused,
+int pthread_create(pthread_t *thread, const void *attr UNUSED,
 		   void *(*start_routine)(void *), void *arg)
 {
 	thread->arg = arg;
diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h
index cc3221c..e2b5c4f 100644
--- a/compat/win32/pthread.h
+++ b/compat/win32/pthread.h
@@ -18,7 +18,7 @@
  */
 #define pthread_mutex_t CRITICAL_SECTION
 
-static inline int return_0(int i) {
+static inline int return_0(int i UNUSED) {
 	return 0;
 }
 #define pthread_mutex_init(a,b) return_0((InitializeCriticalSection((a)), 0))
@@ -70,7 +70,7 @@ static inline void NORETURN pthread_exit(void *ret)
 }
 
 typedef DWORD pthread_key_t;
-static inline int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *value))
+static inline int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *value) UNUSED)
 {
 	return (*keyp = TlsAlloc()) == TLS_OUT_OF_INDEXES ? EAGAIN : 0;
 }
diff --git a/compat/win32/syslog.c b/compat/win32/syslog.c
index 0af18d8..4e47947 100644
--- a/compat/win32/syslog.c
+++ b/compat/win32/syslog.c
@@ -2,7 +2,7 @@
 
 static HANDLE ms_eventlog;
 
-void openlog(const char *ident, int logopt, int facility)
+void openlog(const char *ident, int logopt UNUSED, int facility UNUSED)
 {
 	if (ms_eventlog)
 		return;
diff --git a/compat/win32mmap.c b/compat/win32mmap.c
index 519d51f..a4ab4cb 100644
--- a/compat/win32mmap.c
+++ b/compat/win32mmap.c
@@ -40,7 +40,7 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of
 	return MAP_FAILED;
 }
 
-int git_munmap(void *start, size_t length)
+int git_munmap(void *start, size_t length UNUSED)
 {
 	return !UnmapViewOfFile(start);
 }
diff --git a/compat/winansi.c b/compat/winansi.c
index 575813b..1b3f916 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -340,7 +340,7 @@ enum {
 	TEXT = 0, ESCAPE = 033, BRACKET = '['
 };
 
-static DWORD WINAPI console_thread(LPVOID unused)
+static DWORD WINAPI console_thread(LPVOID data UNUSED)
 {
 	unsigned char buffer[BUFFER_SIZE];
 	DWORD bytes;
diff --git a/config.c b/config.c
index fb3b86d..8561bbf 100644
--- a/config.c
+++ b/config.c
@@ -300,18 +300,22 @@ static int include_by_gitdir(const struct key_value_info *kvi,
 	return ret;
 }
 
-static int include_by_branch(const char *cond, size_t cond_len)
+static int include_by_branch(struct config_include_data *data,
+			     const char *cond, size_t cond_len)
 {
 	int flags;
 	int ret;
 	struct strbuf pattern = STRBUF_INIT;
-	const char *refname = !the_repository->gitdir ?
-		NULL : refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
-					       "HEAD", 0, NULL, &flags);
-	const char *shortname;
+	const char *refname, *shortname;
 
-	if (!refname || !(flags & REF_ISSYMREF)	||
-			!skip_prefix(refname, "refs/heads/", &shortname))
+	if (!data->repo || data->repo->ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+		return 0;
+
+	refname = refs_resolve_ref_unsafe(get_main_ref_store(data->repo),
+					  "HEAD", 0, NULL, &flags);
+	if (!refname ||
+	    !(flags & REF_ISSYMREF) ||
+	    !skip_prefix(refname, "refs/heads/", &shortname))
 		return 0;
 
 	strbuf_add(&pattern, cond, cond_len);
@@ -406,7 +410,7 @@ static int include_condition_is_true(const struct key_value_info *kvi,
 	else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len))
 		return include_by_gitdir(kvi, opts, cond, cond_len, 1);
 	else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
-		return include_by_branch(cond, cond_len);
+		return include_by_branch(inc, cond, cond_len);
 	else if (skip_prefix_mem(cond, cond_len, "hasconfig:remote.*.url:", &cond,
 				   &cond_len))
 		return include_by_remote_url(inc, cond, cond_len);
@@ -1446,26 +1450,6 @@ static int git_default_core_config(const char *var, const char *value,
 		return 0;
 	}
 
-	if (!strcmp(var, "core.prefersymlinkrefs")) {
-		prefer_symlink_refs = git_config_bool(var, value);
-		return 0;
-	}
-
-	if (!strcmp(var, "core.logallrefupdates")) {
-		if (value && !strcasecmp(value, "always"))
-			log_all_ref_updates = LOG_REFS_ALWAYS;
-		else if (git_config_bool(var, value))
-			log_all_ref_updates = LOG_REFS_NORMAL;
-		else
-			log_all_ref_updates = LOG_REFS_NONE;
-		return 0;
-	}
-
-	if (!strcmp(var, "core.warnambiguousrefs")) {
-		warn_ambiguous_refs = git_config_bool(var, value);
-		return 0;
-	}
-
 	if (!strcmp(var, "core.abbrev")) {
 		if (!value)
 			return config_error_nonbool(var);
@@ -1574,14 +1558,6 @@ static int git_default_core_config(const char *var, const char *value,
 		return git_config_string(&check_roundtrip_encoding, var, value);
 	}
 
-	if (!strcmp(var, "core.notesref")) {
-		if (!value)
-			return config_error_nonbool(var);
-		free(notes_ref_name);
-		notes_ref_name = xstrdup(value);
-		return 0;
-	}
-
 	if (!strcmp(var, "core.editor")) {
 		FREE_AND_NULL(editor_program);
 		return git_config_string(&editor_program, var, value);
@@ -1596,7 +1572,8 @@ static int git_default_core_config(const char *var, const char *value,
 		else if (value[0]) {
 			if (strchr(value, '\n'))
 				return error(_("%s cannot contain newline"), var);
-			comment_line_str = xstrdup(value);
+			comment_line_str = value;
+			FREE_AND_NULL(comment_line_str_to_free);
 			auto_comment_line_char = 0;
 		} else
 			return error(_("%s must have at least one character"), var);
@@ -2202,7 +2179,7 @@ static void configset_iter(struct config_set *set, config_fn_t fn, void *data)
 	}
 }
 
-void read_early_config(config_fn_t cb, void *data)
+void read_early_config(struct repository *repo, config_fn_t cb, void *data)
 {
 	struct config_options opts = {0};
 	struct strbuf commondir = STRBUF_INIT;
@@ -2210,9 +2187,9 @@ void read_early_config(config_fn_t cb, void *data)
 
 	opts.respect_includes = 1;
 
-	if (have_git_dir()) {
-		opts.commondir = get_git_common_dir();
-		opts.git_dir = get_git_dir();
+	if (repo && repo->gitdir) {
+		opts.commondir = repo_get_common_dir(repo);
+		opts.git_dir = repo_get_git_dir(repo);
 	/*
 	 * When setup_git_directory() was not yet asked to discover the
 	 * GIT_DIR, we ask discover_git_directory() to figure out whether there
@@ -2232,10 +2209,6 @@ void read_early_config(config_fn_t cb, void *data)
 	strbuf_release(&gitdir);
 }
 
-/*
- * Read config but only enumerate system and global settings.
- * Omit any repo-local, worktree-local, or command-line settings.
- */
 void read_very_early_config(config_fn_t cb, void *data)
 {
 	struct config_options opts = { 0 };
@@ -2564,7 +2537,7 @@ static void git_config_check_init(struct repository *repo)
 	repo_read_config(repo);
 }
 
-static void repo_config_clear(struct repository *repo)
+void repo_config_clear(struct repository *repo)
 {
 	if (!repo->config || !repo->config->hash_initialized)
 		return;
@@ -2611,7 +2584,7 @@ int repo_config_get_string(struct repository *repo,
 	git_config_check_init(repo);
 	ret = git_configset_get_string(repo->config, key, dest);
 	if (ret < 0)
-		git_die_config(key, NULL);
+		git_die_config(repo, key, NULL);
 	return ret;
 }
 
@@ -2622,7 +2595,7 @@ int repo_config_get_string_tmp(struct repository *repo,
 	git_config_check_init(repo);
 	ret = git_configset_get_string_tmp(repo->config, key, dest);
 	if (ret < 0)
-		git_die_config(key, NULL);
+		git_die_config(repo, key, NULL);
 	return ret;
 }
 
@@ -2668,7 +2641,7 @@ int repo_config_get_pathname(struct repository *repo,
 	git_config_check_init(repo);
 	ret = git_configset_get_pathname(repo->config, key, dest);
 	if (ret < 0)
-		git_die_config(key, NULL);
+		git_die_config(repo, key, NULL);
 	return ret;
 }
 
@@ -2694,98 +2667,28 @@ void git_protected_config(config_fn_t fn, void *data)
 	configset_iter(&protected_config, fn, data);
 }
 
-/* Functions used historically to read configuration from 'the_repository' */
-void git_config(config_fn_t fn, void *data)
+int repo_config_get_expiry(struct repository *r, const char *key, char **output)
 {
-	repo_config(the_repository, fn, data);
-}
+	int ret = repo_config_get_string(r, key, output);
 
-void git_config_clear(void)
-{
-	repo_config_clear(the_repository);
-}
-
-int git_config_get(const char *key)
-{
-	return repo_config_get(the_repository, key);
-}
-
-int git_config_get_value(const char *key, const char **value)
-{
-	return repo_config_get_value(the_repository, key, value);
-}
-
-int git_config_get_value_multi(const char *key, const struct string_list **dest)
-{
-	return repo_config_get_value_multi(the_repository, key, dest);
-}
-
-int git_config_get_string_multi(const char *key,
-				const struct string_list **dest)
-{
-	return repo_config_get_string_multi(the_repository, key, dest);
-}
-
-int git_config_get_string(const char *key, char **dest)
-{
-	return repo_config_get_string(the_repository, key, dest);
-}
-
-int git_config_get_string_tmp(const char *key, const char **dest)
-{
-	return repo_config_get_string_tmp(the_repository, key, dest);
-}
-
-int git_config_get_int(const char *key, int *dest)
-{
-	return repo_config_get_int(the_repository, key, dest);
-}
-
-int git_config_get_ulong(const char *key, unsigned long *dest)
-{
-	return repo_config_get_ulong(the_repository, key, dest);
-}
-
-int git_config_get_bool(const char *key, int *dest)
-{
-	return repo_config_get_bool(the_repository, key, dest);
-}
-
-int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
-{
-	return repo_config_get_bool_or_int(the_repository, key, is_bool, dest);
-}
-
-int git_config_get_maybe_bool(const char *key, int *dest)
-{
-	return repo_config_get_maybe_bool(the_repository, key, dest);
-}
-
-int git_config_get_pathname(const char *key, char **dest)
-{
-	return repo_config_get_pathname(the_repository, key, dest);
-}
-
-int git_config_get_expiry(const char *key, const char **output)
-{
-	int ret = git_config_get_string(key, (char **)output);
 	if (ret)
 		return ret;
 	if (strcmp(*output, "now")) {
 		timestamp_t now = approxidate("now");
 		if (approxidate(*output) >= now)
-			git_die_config(key, _("Invalid %s: '%s'"), key, *output);
+			git_die_config(r, key, _("Invalid %s: '%s'"), key, *output);
 	}
 	return ret;
 }
 
-int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestamp_t now)
+int repo_config_get_expiry_in_days(struct repository *r, const char *key,
+				   timestamp_t *expiry, timestamp_t now)
 {
 	const char *expiry_string;
 	intmax_t days;
 	timestamp_t when;
 
-	if (git_config_get_string_tmp(key, &expiry_string))
+	if (repo_config_get_string_tmp(r, key, &expiry_string))
 		return 1; /* no such thing */
 
 	if (git_parse_signed(expiry_string, &days, maximum_signed_value_of_type(int))) {
@@ -2801,21 +2704,21 @@ int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestam
 	return -1; /* thing exists but cannot be parsed */
 }
 
-int git_config_get_split_index(void)
+int repo_config_get_split_index(struct repository *r)
 {
 	int val;
 
-	if (!git_config_get_maybe_bool("core.splitindex", &val))
+	if (!repo_config_get_maybe_bool(r, "core.splitindex", &val))
 		return val;
 
 	return -1; /* default value */
 }
 
-int git_config_get_max_percent_split_change(void)
+int repo_config_get_max_percent_split_change(struct repository *r)
 {
 	int val = -1;
 
-	if (!git_config_get_int("splitindex.maxpercentchange", &val)) {
+	if (!repo_config_get_int(r, "splitindex.maxpercentchange", &val)) {
 		if (0 <= val && val <= 100)
 			return val;
 
@@ -2826,7 +2729,7 @@ int git_config_get_max_percent_split_change(void)
 	return -1; /* default value */
 }
 
-int git_config_get_index_threads(int *dest)
+int repo_config_get_index_threads(struct repository *r, int *dest)
 {
 	int is_bool, val;
 
@@ -2836,7 +2739,7 @@ int git_config_get_index_threads(int *dest)
 		return 0;
 	}
 
-	if (!git_config_get_bool_or_int("index.threads", &is_bool, &val)) {
+	if (!repo_config_get_bool_or_int(r, "index.threads", &is_bool, &val)) {
 		if (is_bool)
 			*dest = val ? 0 : 1;
 		else
@@ -2857,7 +2760,7 @@ void git_die_config_linenr(const char *key, const char *filename, int linenr)
 		    key, filename, linenr);
 }
 
-void git_die_config(const char *key, const char *err, ...)
+void git_die_config(struct repository *r, const char *key, const char *err, ...)
 {
 	const struct string_list *values;
 	struct key_value_info *kv_info;
@@ -2869,7 +2772,7 @@ void git_die_config(const char *key, const char *err, ...)
 		error_fn(err, params);
 		va_end(params);
 	}
-	if (git_config_get_value_multi(key, &values))
+	if (repo_config_get_value_multi(r, key, &values))
 		BUG("for key '%s' we must have a value to report on", key);
 	kv_info = values->items[values->nr - 1].util;
 	git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
@@ -3178,21 +3081,21 @@ static void maybe_remove_section(struct config_store_data *store,
 		*end_offset = store->parsed[store->parsed_nr - 1].end;
 }
 
-int git_config_set_in_file_gently(const char *config_filename,
-				  const char *key, const char *comment, const char *value)
+int repo_config_set_in_file_gently(struct repository *r, const char *config_filename,
+				   const char *key, const char *comment, const char *value)
 {
-	return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, comment, 0);
+	return repo_config_set_multivar_in_file_gently(r, config_filename, key, value, NULL, comment, 0);
 }
 
-void git_config_set_in_file(const char *config_filename,
-			    const char *key, const char *value)
+void repo_config_set_in_file(struct repository *r, const char *config_filename,
+			     const char *key, const char *value)
 {
-	git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
+	repo_config_set_multivar_in_file(r, config_filename, key, value, NULL, 0);
 }
 
-int git_config_set_gently(const char *key, const char *value)
+int repo_config_set_gently(struct repository *r, const char *key, const char *value)
 {
-	return git_config_set_multivar_gently(key, value, NULL, 0);
+	return repo_config_set_multivar_gently(r, key, value, NULL, 0);
 }
 
 int repo_config_set_worktree_gently(struct repository *r,
@@ -3201,17 +3104,17 @@ int repo_config_set_worktree_gently(struct repository *r,
 	/* Only use worktree-specific config if it is already enabled. */
 	if (r->repository_format_worktree_config) {
 		char *file = repo_git_path(r, "config.worktree");
-		int ret = git_config_set_multivar_in_file_gently(
-					file, key, value, NULL, NULL, 0);
+		int ret = repo_config_set_multivar_in_file_gently(
+					r, file, key, value, NULL, NULL, 0);
 		free(file);
 		return ret;
 	}
 	return repo_config_set_multivar_gently(r, key, value, NULL, 0);
 }
 
-void git_config_set(const char *key, const char *value)
+void repo_config_set(struct repository *r, const char *key, const char *value)
 {
-	git_config_set_multivar(key, value, NULL, 0);
+	repo_config_set_multivar(r, key, value, NULL, 0);
 
 	trace2_cmd_set_config(key, value);
 }
@@ -3293,11 +3196,12 @@ static void validate_comment_string(const char *comment)
  * - the config file is removed and the lock file rename()d to it.
  *
  */
-int git_config_set_multivar_in_file_gently(const char *config_filename,
-					   const char *key, const char *value,
-					   const char *value_pattern,
-					   const char *comment,
-					   unsigned flags)
+int repo_config_set_multivar_in_file_gently(struct repository *r,
+					    const char *config_filename,
+					    const char *key, const char *value,
+					    const char *value_pattern,
+					    const char *comment,
+					    unsigned flags)
 {
 	int fd = -1, in_fd = -1;
 	int ret;
@@ -3317,7 +3221,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
 	store.multi_replace = (flags & CONFIG_FLAGS_MULTI_REPLACE) != 0;
 
 	if (!config_filename)
-		config_filename = filename_buf = git_pathdup("config");
+		config_filename = filename_buf = repo_git_path(r, "config");
 
 	/*
 	 * The lock serves a purpose in addition to locking: the new
@@ -3526,7 +3430,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
 	ret = 0;
 
 	/* Invalidate the config cache */
-	git_config_clear();
+	repo_config_clear(r);
 
 out_free:
 	rollback_lock_file(&lock);
@@ -3543,12 +3447,13 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
 	goto out_free;
 }
 
-void git_config_set_multivar_in_file(const char *config_filename,
-				     const char *key, const char *value,
-				     const char *value_pattern, unsigned flags)
+void repo_config_set_multivar_in_file(struct repository *r,
+				      const char *config_filename,
+				      const char *key, const char *value,
+				      const char *value_pattern, unsigned flags)
 {
-	if (!git_config_set_multivar_in_file_gently(config_filename, key, value,
-						    value_pattern, NULL, flags))
+	if (!repo_config_set_multivar_in_file_gently(r, config_filename, key, value,
+						     value_pattern, NULL, flags))
 		return;
 	if (value)
 		die(_("could not set '%s' to '%s'"), key, value);
@@ -3556,32 +3461,27 @@ void git_config_set_multivar_in_file(const char *config_filename,
 		die(_("could not unset '%s'"), key);
 }
 
-int git_config_set_multivar_gently(const char *key, const char *value,
-				   const char *value_pattern, unsigned flags)
-{
-	return repo_config_set_multivar_gently(the_repository, key, value,
-					       value_pattern, flags);
-}
-
 int repo_config_set_multivar_gently(struct repository *r, const char *key,
 				    const char *value,
 				    const char *value_pattern, unsigned flags)
 {
 	char *file = repo_git_path(r, "config");
-	int res = git_config_set_multivar_in_file_gently(file,
-							 key, value,
-							 value_pattern,
-							 NULL, flags);
+	int res = repo_config_set_multivar_in_file_gently(r, file,
+							  key, value,
+							  value_pattern,
+							  NULL, flags);
 	free(file);
 	return res;
 }
 
-void git_config_set_multivar(const char *key, const char *value,
-			     const char *value_pattern, unsigned flags)
+void repo_config_set_multivar(struct repository *r,
+			      const char *key, const char *value,
+			      const char *value_pattern, unsigned flags)
 {
-	git_config_set_multivar_in_file(git_path("config"),
-					key, value, value_pattern,
-					flags);
+	char *file = repo_git_path(r, "config");
+	repo_config_set_multivar_in_file(r, file, key, value,
+					 value_pattern, flags);
+	free(file);
 }
 
 static size_t section_name_match (const char *buf, const char *name)
@@ -3643,9 +3543,11 @@ static int section_name_is_ok(const char *name)
 #define GIT_CONFIG_MAX_LINE_LEN (512 * 1024)
 
 /* if new_name == NULL, the section is removed instead */
-static int git_config_copy_or_rename_section_in_file(const char *config_filename,
-				      const char *old_name,
-				      const char *new_name, int copy)
+static int repo_config_copy_or_rename_section_in_file(
+	struct repository *r,
+	const char *config_filename,
+	const char *old_name,
+	const char *new_name, int copy)
 {
 	int ret = 0, remove = 0;
 	char *filename_buf = NULL;
@@ -3666,7 +3568,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
 	}
 
 	if (!config_filename)
-		config_filename = filename_buf = git_pathdup("config");
+		config_filename = filename_buf = repo_git_path(r, "config");
 
 	out_fd = hold_lock_file_for_update(&lock, config_filename, 0);
 	if (out_fd < 0) {
@@ -3809,28 +3711,28 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
 	return ret;
 }
 
-int git_config_rename_section_in_file(const char *config_filename,
-				      const char *old_name, const char *new_name)
+int repo_config_rename_section_in_file(struct repository *r, const char *config_filename,
+				       const char *old_name, const char *new_name)
 {
-	return git_config_copy_or_rename_section_in_file(config_filename,
+	return repo_config_copy_or_rename_section_in_file(r, config_filename,
 					 old_name, new_name, 0);
 }
 
-int git_config_rename_section(const char *old_name, const char *new_name)
+int repo_config_rename_section(struct repository *r, const char *old_name, const char *new_name)
 {
-	return git_config_rename_section_in_file(NULL, old_name, new_name);
+	return repo_config_rename_section_in_file(r, NULL, old_name, new_name);
 }
 
-int git_config_copy_section_in_file(const char *config_filename,
-				      const char *old_name, const char *new_name)
+int repo_config_copy_section_in_file(struct repository *r, const char *config_filename,
+				     const char *old_name, const char *new_name)
 {
-	return git_config_copy_or_rename_section_in_file(config_filename,
+	return repo_config_copy_or_rename_section_in_file(r, config_filename,
 					 old_name, new_name, 1);
 }
 
-int git_config_copy_section(const char *old_name, const char *new_name)
+int repo_config_copy_section(struct repository *r, const char *old_name, const char *new_name)
 {
-	return git_config_copy_section_in_file(NULL, old_name, new_name);
+	return repo_config_copy_section_in_file(r, NULL, old_name, new_name);
 }
 
 /*
diff --git a/config.h b/config.h
index 54b47de..5c730c4 100644
--- a/config.h
+++ b/config.h
@@ -26,7 +26,7 @@ struct object_id;
 /* git_config_parse_key() returns these negated: */
 #define CONFIG_INVALID_KEY 1
 #define CONFIG_NO_SECTION_OR_NAME 2
-/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */
+/* repo_config_set_gently(), repo_config_set_multivar_gently() return the above or these: */
 #define CONFIG_NO_LOCK -1
 #define CONFIG_INVALID_FILE 3
 #define CONFIG_NO_WRITE 4
@@ -170,9 +170,9 @@ int git_default_config(const char *, const char *,
 
 /**
  * Read a specific file in git-config format.
- * This function takes the same callback and data parameters as `git_config`.
+ * This function takes the same callback and data parameters as `repo_config`.
  *
- * Unlike git_config(), this function does not respect includes.
+ * Unlike repo_config(), this function does not respect includes.
  */
 int git_config_from_file(config_fn_t fn, const char *, void *);
 
@@ -192,15 +192,26 @@ int git_config_from_blob_oid(config_fn_t fn, const char *name,
 void git_config_push_parameter(const char *text);
 void git_config_push_env(const char *spec);
 int git_config_from_parameters(config_fn_t fn, void *data);
-void read_early_config(config_fn_t cb, void *data);
+
+/*
+ * Read config when the Git directory has not yet been set up. In case
+ * `the_repository` has not yet been set up, try to discover the Git
+ * directory to read the configuration from.
+ */
+void read_early_config(struct repository *repo, config_fn_t cb, void *data);
+
+/*
+ * Read config but only enumerate system and global settings.
+ * Omit any repo-local, worktree-local, or command-line settings.
+ */
 void read_very_early_config(config_fn_t cb, void *data);
 
 /**
  * Most programs will simply want to look up variables in all config files
  * that Git knows about, using the normal precedence rules. To do this,
- * call `git_config` with a callback function and void data pointer.
+ * call `repo_config` with a callback function and void data pointer.
  *
- * `git_config` will read all config sources in order of increasing
+ * `repo_config` will read all config sources in order of increasing
  * priority. Thus a callback should typically overwrite previously-seen
  * entries with new ones (e.g., if both the user-wide `~/.gitconfig` and
  * repo-specific `.git/config` contain `color.ui`, the config machinery
@@ -210,11 +221,11 @@ void read_very_early_config(config_fn_t cb, void *data);
  *
  * Unlike git_config_from_file(), this function respects includes.
  */
-void git_config(config_fn_t fn, void *);
+void repo_config(struct repository *r, config_fn_t fn, void *);
 
 /**
  * Lets the caller examine config while adjusting some of the default
- * behavior of `git_config`. It should almost never be used by "regular"
+ * behavior of `repo_config`. It should almost never be used by "regular"
  * Git code that is looking up configuration variables.
  * It is intended for advanced callers like `git-config`, which are
  * intentionally tweaking the normal config-lookup process.
@@ -223,12 +234,12 @@ void git_config(config_fn_t fn, void *);
  * - `config_source`
  * If this parameter is non-NULL, it specifies the source to parse for
  * configuration, rather than looking in the usual files. See `struct
- * git_config_source` in `config.h` for details. Regular `git_config` defaults
+ * git_config_source` in `config.h` for details. Regular `repo_config` defaults
  * to `NULL`.
  *
  * - `opts`
  * Specify options to adjust the behavior of parsing config files. See `struct
- * config_options` in `config.h` for details. As an example: regular `git_config`
+ * config_options` in `config.h` for details. As an example: regular `repo_config`
  * sets `opts.respect_includes` to `1` by default.
  */
 int config_with_options(config_fn_t fn, void *,
@@ -297,15 +308,16 @@ int git_config_pathname(char **, const char *, const char *);
 
 int git_config_expiry_date(timestamp_t *, const char *, const char *);
 int git_config_color(char *, const char *, const char *);
-int git_config_set_in_file_gently(const char *, const char *, const char *, const char *);
+int repo_config_set_in_file_gently(struct repository *r, const char *config_filename,
+				   const char *key, const char *comment, const char *value);
 
 /**
  * write config values to a specific config file, takes a key/value pair as
  * parameter.
  */
-void git_config_set_in_file(const char *, const char *, const char *);
+void repo_config_set_in_file(struct repository *, const char *, const char *, const char *);
 
-int git_config_set_gently(const char *, const char *);
+int repo_config_set_gently(struct repository *r, const char *, const char *);
 
 /**
  * Write a config value that should apply to the current worktree. If
@@ -317,13 +329,13 @@ int repo_config_set_worktree_gently(struct repository *, const char *, const cha
 /**
  * write config values to `.git/config`, takes a key/value pair as parameter.
  */
-void git_config_set(const char *, const char *);
+void repo_config_set(struct repository *, const char *, const char *);
 
 int git_config_parse_key(const char *, char **, size_t *);
 
 /*
  * The following macros specify flag bits that alter the behavior
- * of the git_config_set_multivar*() methods.
+ * of the repo_config_set_multivar*() methods.
  */
 
 /*
@@ -340,10 +352,9 @@ int git_config_parse_key(const char *, char **, size_t *);
  */
 #define CONFIG_FLAGS_FIXED_VALUE (1 << 1)
 
-int git_config_set_multivar_gently(const char *, const char *, const char *, unsigned);
-void git_config_set_multivar(const char *, const char *, const char *, unsigned);
 int repo_config_set_multivar_gently(struct repository *, const char *, const char *, const char *, unsigned);
-int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, const char *, unsigned);
+void repo_config_set_multivar(struct repository *r, const char *, const char *, const char *, unsigned);
+int repo_config_set_multivar_in_file_gently(struct repository *, const char *, const char *, const char *, const char *, const char *, unsigned);
 
 char *git_config_prepare_comment_string(const char *);
 
@@ -367,11 +378,12 @@ char *git_config_prepare_comment_string(const char *);
  *
  * It returns 0 on success.
  */
-void git_config_set_multivar_in_file(const char *config_filename,
-				     const char *key,
-				     const char *value,
-				     const char *value_pattern,
-				     unsigned flags);
+void repo_config_set_multivar_in_file(struct repository *r,
+				      const char *config_filename,
+				      const char *key,
+				      const char *value,
+				      const char *value_pattern,
+				      unsigned flags);
 
 /**
  * rename or remove sections in the config file
@@ -379,11 +391,11 @@ void git_config_set_multivar_in_file(const char *config_filename,
  * If NULL is passed through `new_name` parameter,
  * the section will be removed from the config file.
  */
-int git_config_rename_section(const char *, const char *);
+int repo_config_rename_section(struct repository *, const char *, const char *);
 
-int git_config_rename_section_in_file(const char *, const char *, const char *);
-int git_config_copy_section(const char *, const char *);
-int git_config_copy_section_in_file(const char *, const char *, const char *);
+int repo_config_rename_section_in_file(struct repository *, const char *, const char *, const char *);
+int repo_config_copy_section(struct repository *, const char *, const char *);
+int repo_config_copy_section_in_file(struct repository *, const char *, const char *, const char *);
 int git_config_system(void);
 int config_error_nonbool(const char *);
 #if defined(__GNUC__)
@@ -550,39 +562,11 @@ int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *i
 int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
 int git_configset_get_pathname(struct config_set *cs, const char *key, char **dest);
 
-/* Functions for reading a repository's config */
-struct repository;
-void repo_config(struct repository *repo, config_fn_t fn, void *data);
-
 /**
  * Run only the discover part of the repo_config_get_*() functions
  * below, in addition to 1 if not found, returns negative values on
  * error (e.g. if the key itself is invalid).
  */
-RESULT_MUST_BE_USED
-int repo_config_get(struct repository *repo, const char *key);
-int repo_config_get_value(struct repository *repo,
-			  const char *key, const char **value);
-RESULT_MUST_BE_USED
-int repo_config_get_value_multi(struct repository *repo, const char *key,
-				const struct string_list **dest);
-RESULT_MUST_BE_USED
-int repo_config_get_string_multi(struct repository *repo, const char *key,
-				 const struct string_list **dest);
-int repo_config_get_string(struct repository *repo,
-			   const char *key, char **dest);
-int repo_config_get_string_tmp(struct repository *repo,
-			       const char *key, const char **dest);
-int repo_config_get_int(struct repository *repo,
-			const char *key, int *dest);
-int repo_config_get_ulong(struct repository *repo,
-			  const char *key, unsigned long *dest);
-int repo_config_get_bool(struct repository *repo,
-			 const char *key, int *dest);
-int repo_config_get_bool_or_int(struct repository *repo,
-				const char *key, int *is_bool, int *dest);
-int repo_config_get_maybe_bool(struct repository *repo,
-			       const char *key, int *dest);
 int repo_config_get_pathname(struct repository *repo,
 			     const char *key, char **dest);
 
@@ -598,17 +582,17 @@ void git_protected_config(config_fn_t fn, void *data);
  * -------------------------------
  *
  * For programs wanting to query for specific variables in a non-callback
- * manner, the config API provides two functions `git_config_get_value`
- * and `git_config_get_value_multi`. They both read values from an internal
+ * manner, the config API provides two functions `repo_config_get_value`
+ * and `repo_config_get_value_multi`. They both read values from an internal
  * cache generated previously from reading the config files.
  *
- * For those git_config_get*() functions that aren't documented,
+ * For those repo_config_get*() functions that aren't documented,
  * consult the corresponding repo_config_get*() function's
  * documentation.
  */
 
 RESULT_MUST_BE_USED
-int git_config_get(const char *key);
+int repo_config_get(struct repository *r, const char *key);
 
 /**
  * Finds the highest-priority value for the configuration variable `key`,
@@ -617,7 +601,7 @@ int git_config_get(const char *key);
  * `value`. The caller should not free or modify `value`, as it is owned
  * by the cache.
  */
-int git_config_get_value(const char *key, const char **value);
+int repo_config_get_value(struct repository *r, const char *key, const char **value);
 
 /**
  * Finds and returns the value list, sorted in order of increasing priority
@@ -628,16 +612,16 @@ int git_config_get_value(const char *key, const char **value);
  * owned by the cache.
  */
 RESULT_MUST_BE_USED
-int git_config_get_value_multi(const char *key,
-			       const struct string_list **dest);
-RESULT_MUST_BE_USED
-int git_config_get_string_multi(const char *key,
+int repo_config_get_value_multi(struct repository *r, const char *key,
 				const struct string_list **dest);
+RESULT_MUST_BE_USED
+int repo_config_get_string_multi(struct repository *r, const char *key,
+				 const struct string_list **dest);
 
 /**
  * Resets and invalidates the config cache.
  */
-void git_config_clear(void);
+void repo_config_clear(struct repository *repo);
 
 /**
  * Allocates and copies the retrieved string into the `dest` parameter for
@@ -645,14 +629,15 @@ void git_config_clear(void);
  * error message and returns -1. When the configuration variable `key` is
  * not found, returns 1 without touching `dest`.
  */
-int git_config_get_string(const char *key, char **dest);
+int repo_config_get_string(struct repository *r, const char *key, char **dest);
 
 /**
- * Similar to `git_config_get_string`, but does not allocate any new
+ * Similar to `repo_config_get_string`, but does not allocate any new
  * memory; on success `dest` will point to memory owned by the config
  * machinery, which could be invalidated if it is discarded and reloaded.
  */
-int git_config_get_string_tmp(const char *key, const char **dest);
+int repo_config_get_string_tmp(struct repository *r,
+			       const char *key, const char **dest);
 
 /**
  * Finds and parses the value to an integer for the configuration variable
@@ -660,12 +645,13 @@ int git_config_get_string_tmp(const char *key, const char **dest);
  * `dest` and returns 0. When the configuration variable `key` is not found,
  * returns 1 without touching `dest`.
  */
-int git_config_get_int(const char *key, int *dest);
+int repo_config_get_int(struct repository *r, const char *key, int *dest);
 
 /**
- * Similar to `git_config_get_int` but for unsigned longs.
+ * Similar to `repo_config_get_int` but for unsigned longs.
  */
-int git_config_get_ulong(const char *key, unsigned long *dest);
+int repo_config_get_ulong(struct repository *r,
+			  const char *key, unsigned long *dest);
 
 /**
  * Finds and parses the value into a boolean value, for the configuration
@@ -676,47 +662,45 @@ int git_config_get_ulong(const char *key, unsigned long *dest);
  * configuration variable `key` is not found, returns 1 without touching
  * `dest`.
  */
-int git_config_get_bool(const char *key, int *dest);
+int repo_config_get_bool(struct repository *r, const char *key, int *dest);
 
 /**
- * Similar to `git_config_get_bool`, except that integers are copied as-is,
+ * Similar to `repo_config_get_bool`, except that integers are copied as-is,
  * and `is_bool` flag is unset.
  */
-int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
+int repo_config_get_bool_or_int(struct repository *r, const char *key,
+				int *is_bool, int *dest);
 
 /**
- * Similar to `git_config_get_bool`, except that it returns -1 on error
+ * Similar to `repo_config_get_bool`, except that it returns -1 on error
  * rather than dying.
  */
-int git_config_get_maybe_bool(const char *key, int *dest);
+int repo_config_get_maybe_bool(struct repository *r,
+			      const char *key, int *dest);
 
-/**
- * Similar to `git_config_get_string`, but expands `~` or `~user` into
- * the user's home directory when found at the beginning of the path.
- */
-int git_config_get_pathname(const char *key, char **dest);
-
-int git_config_get_index_threads(int *dest);
-int git_config_get_split_index(void);
-int git_config_get_max_percent_split_change(void);
+int repo_config_get_index_threads(struct repository *r, int *dest);
+int repo_config_get_split_index(struct repository *r);
+int repo_config_get_max_percent_split_change(struct repository *r);
 
 /* This dies if the configured or default date is in the future */
-int git_config_get_expiry(const char *key, const char **output);
+int repo_config_get_expiry(struct repository *r, const char *key, char **output);
 
 /* parse either "this many days" integer, or "5.days.ago" approxidate */
-int git_config_get_expiry_in_days(const char *key, timestamp_t *, timestamp_t now);
+int repo_config_get_expiry_in_days(struct repository *r, const char *key,
+				   timestamp_t *, timestamp_t now);
 
 /**
  * First prints the error message specified by the caller in `err` and then
  * dies printing the line number and the file name of the highest priority
  * value for the configuration variable `key`.
  */
-NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
+NORETURN void git_die_config(struct repository *r, const char *key, const char *err, ...)
+	__attribute__((format(printf, 3, 4)));
 
 /**
  * Helper function which formats the die error message according to the
  * parameters entered. Used by `git_die_config()`. It can be used by callers
- * handling `git_config_get_value_multi()` to print the correct error message
+ * handling `repo_config_get_value_multi()` to print the correct error message
  * for the desired value.
  */
 NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
@@ -725,4 +709,140 @@ NORETURN void git_die_config_linenr(const char *key, const char *filename, int l
 	lookup_config(mapping, ARRAY_SIZE(mapping), var)
 int lookup_config(const char **mapping, int nr_mapping, const char *var);
 
+# ifdef USE_THE_REPOSITORY_VARIABLE
+static inline void git_config(config_fn_t fn, void *data)
+{
+	repo_config(the_repository, fn, data);
+}
+
+static inline void git_config_clear(void)
+{
+	repo_config_clear(the_repository);
+}
+
+static inline int git_config_get(const char *key)
+{
+	return repo_config_get(the_repository, key);
+}
+
+static inline int git_config_get_value(const char *key, const char **value)
+{
+	return repo_config_get_value(the_repository, key, value);
+}
+
+static inline int git_config_get_value_multi(const char *key, const struct string_list **dest)
+{
+	return repo_config_get_value_multi(the_repository, key, dest);
+}
+
+static inline int git_config_get_string_multi(const char *key,
+				const struct string_list **dest)
+{
+	return repo_config_get_string_multi(the_repository, key, dest);
+}
+
+static inline int git_config_get_string(const char *key, char **dest)
+{
+	return repo_config_get_string(the_repository, key, dest);
+}
+
+static inline int git_config_get_string_tmp(const char *key, const char **dest)
+{
+	return repo_config_get_string_tmp(the_repository, key, dest);
+}
+
+static inline int git_config_get_int(const char *key, int *dest)
+{
+	return repo_config_get_int(the_repository, key, dest);
+}
+
+static inline int git_config_get_ulong(const char *key, unsigned long *dest)
+{
+	return repo_config_get_ulong(the_repository, key, dest);
+}
+
+static inline int git_config_get_bool(const char *key, int *dest)
+{
+	return repo_config_get_bool(the_repository, key, dest);
+}
+
+static inline int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
+{
+	return repo_config_get_bool_or_int(the_repository, key, is_bool, dest);
+}
+
+static inline int git_config_get_maybe_bool(const char *key, int *dest)
+{
+	return repo_config_get_maybe_bool(the_repository, key, dest);
+}
+
+static inline int git_config_get_pathname(const char *key, char **dest)
+{
+	return repo_config_get_pathname(the_repository, key, dest);
+}
+
+static inline void git_config_set_in_file(const char *config_filename,
+					  const char *key, const char *value)
+{
+	repo_config_set_in_file(the_repository, config_filename, key, value);
+}
+
+static inline int git_config_set_gently(const char *key, const char *value)
+{
+	return repo_config_set_gently(the_repository, key, value);
+}
+
+static inline void git_config_set(const char *key, const char *value)
+{
+	repo_config_set(the_repository, key, value);
+}
+
+static inline int git_config_set_in_file_gently(
+	const char *config_filename,
+	const char *key,
+	const char *comment,
+	const char *value)
+{
+	return repo_config_set_in_file_gently(the_repository, config_filename,
+					      key, comment, value);
+}
+
+static inline int git_config_set_multivar_in_file_gently(
+	const char *config_filename,
+	const char *key, const char *value,
+	const char *value_pattern,
+	const char *comment,
+	unsigned flags)
+{
+	return repo_config_set_multivar_in_file_gently(the_repository, config_filename,
+						       key, value, value_pattern,
+						       comment, flags);
+}
+
+static inline void git_config_set_multivar_in_file(
+	const char *config_filename,
+	const char *key,
+	const char *value,
+	const char *value_pattern,
+	unsigned flags)
+{
+	repo_config_set_multivar_in_file(the_repository, config_filename,
+					 key, value, value_pattern, flags);
+}
+
+static inline int git_config_set_multivar_gently(const char *key, const char *value,
+				   const char *value_pattern, unsigned flags)
+{
+	return repo_config_set_multivar_gently(the_repository, key, value,
+					       value_pattern, flags);
+}
+
+static inline void git_config_set_multivar(const char *key, const char *value,
+			     const char *value_pattern, unsigned flags)
+{
+	repo_config_set_multivar(the_repository, key, value,
+				 value_pattern, flags);
+}
+# endif /* USE_THE_REPOSITORY_VARIABLE */
+
 #endif /* CONFIG_H */
diff --git a/config.mak.dev b/config.mak.dev
index 5229c35..8eca7fa 100644
--- a/config.mak.dev
+++ b/config.mak.dev
@@ -54,7 +54,6 @@
 DEVELOPER_CFLAGS += -Wno-empty-body
 DEVELOPER_CFLAGS += -Wno-missing-field-initializers
 DEVELOPER_CFLAGS += -Wno-sign-compare
-DEVELOPER_CFLAGS += -Wno-unused-parameter
 endif
 endif
 
@@ -70,7 +69,7 @@
 endif
 endif
 
-# Old versions of clang complain about initializaing a
+# Old versions of clang complain about initializing a
 # struct-within-a-struct using just "{0}" rather than "{{0}}".  This
 # error is considered a false-positive and not worth fixing, because
 # new clang versions do not, so just disable it.
diff --git a/config.mak.uname b/config.mak.uname
index bbf7744..d511216 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -8,7 +8,6 @@
 uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
 uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
 uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
-uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
 uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
 
 ifneq ($(findstring MINGW,$(uname_S)),)
@@ -650,6 +649,7 @@
 	NO_GECOS_IN_PWENT = YesPlease
 	HAVE_STRINGS_H = YesPlease
 	NEEDS_MODE_TRANSLATION = YesPlease
+	HAVE_ZOS_GET_EXECUTABLE_PATH = YesPlease
 endif
 ifeq ($(uname_S),MINGW)
         ifeq ($(shell expr "$(uname_R)" : '1\.'),2)
diff --git a/connect.c b/connect.c
index cf84e63..58f53d8 100644
--- a/connect.c
+++ b/connect.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "environment.h"
@@ -1483,6 +1485,7 @@ struct child_process *git_connect(int fd[2], const char *url,
 
 				free(hostandport);
 				free(path);
+				child_process_clear(conn);
 				free(conn);
 				strbuf_release(&cmd);
 				return NULL;
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 832f46b..62af7b3 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -970,18 +970,15 @@
 add_executable(test-fake-ssh ${CMAKE_SOURCE_DIR}/t/helper/test-fake-ssh.c)
 target_link_libraries(test-fake-ssh common-main)
 
-#reftable-tests
-parse_makefile_for_sources(test-reftable_SOURCES "REFTABLE_TEST_OBJS")
-list(TRANSFORM test-reftable_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
-
 #unit-tests
-add_library(unit-test-lib OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/test-lib.c)
-add_library(unit-test-lib-oid OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/lib-oid.c)
+parse_makefile_for_sources(unit-test_SOURCES "UNIT_TEST_OBJS")
+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_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 unit-test-lib-oid common-main)
+	target_link_libraries("${unit_test}" unit-test-lib common-main)
 	set_target_properties("${unit_test}"
 		PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
 	if(MSVC)
@@ -1004,12 +1001,65 @@
 	endif()
 endforeach()
 
+parse_makefile_for_scripts(clar_test_SUITES "CLAR_TEST_SUITES" "")
+
+set(clar_decls "")
+set(clar_cbs "")
+set(clar_cbs_count 0)
+set(clar_suites "static struct clar_suite _clar_suites[] = {\n")
+list(LENGTH clar_test_SUITES clar_suites_count)
+foreach(suite ${clar_test_SUITES})
+	file(STRINGS "${CMAKE_SOURCE_DIR}/t/unit-tests/${suite}.c" decls
+		REGEX "^void test_${suite}__[a-zA-Z_0-9][a-zA-Z_0-9]*\\(void\\)$")
+
+	list(LENGTH decls decls_count)
+	string(REGEX REPLACE "void (test_${suite}__([a-zA-Z_0-9]*))\\(void\\)" "    { \"\\2\", &\\1 },\n" cbs ${decls})
+	string(JOIN "" cbs ${cbs})
+	list(TRANSFORM decls PREPEND "extern ")
+	string(JOIN ";\n" decls ${decls})
+
+	string(APPEND clar_decls "${decls};\n")
+	string(APPEND clar_cbs
+		"static const struct clar_func _clar_cb_${suite}[] = {\n"
+		${cbs}
+		"};\n")
+	string(APPEND clar_suites
+		"    {\n"
+		"        \"${suite}\",\n"
+		"        { NULL, NULL },\n"
+		"        { NULL, NULL },\n"
+		"        _clar_cb_${suite}, ${decls_count}, 1\n"
+		"    },\n")
+	math(EXPR clar_cbs_count "${clar_cbs_count}+${decls_count}")
+endforeach()
+string(APPEND clar_suites
+	"};\n"
+	"static const size_t _clar_suite_count = ${clar_suites_count};\n"
+	"static const size_t _clar_callback_count = ${clar_cbs_count};\n")
+file(WRITE "${CMAKE_BINARY_DIR}/t/unit-tests/clar-decls.h" "${clar_decls}")
+file(WRITE "${CMAKE_BINARY_DIR}/t/unit-tests/clar.suite" "${clar_decls}" "${clar_cbs}" "${clar_suites}")
+
+list(TRANSFORM clar_test_SUITES PREPEND "${CMAKE_SOURCE_DIR}/t/unit-tests/")
+list(TRANSFORM clar_test_SUITES APPEND ".c")
+add_library(unit-tests-lib ${clar_test_SUITES} "${CMAKE_SOURCE_DIR}/t/unit-tests/clar/clar.c")
+target_include_directories(unit-tests-lib PRIVATE "${CMAKE_SOURCE_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)
+set_target_properties(unit-tests
+	PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+if(MSVC)
+	set_target_properties(unit-tests
+		PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+	set_target_properties(unit-tests
+		PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+endif()
+
 #test-tool
 parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS")
 add_library(test-lib OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/test-lib.c)
 
 list(TRANSFORM test-tool_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/t/helper/")
-add_executable(test-tool ${CMAKE_SOURCE_DIR}/t/helper/test-tool.c ${test-tool_SOURCES} ${test-reftable_SOURCES})
+add_executable(test-tool ${CMAKE_SOURCE_DIR}/t/helper/test-tool.c ${test-tool_SOURCES})
 target_link_libraries(test-tool test-lib common-main)
 
 set_target_properties(test-fake-ssh test-tool
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 60a22d6..3d4dff3 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -3296,7 +3296,7 @@
 		#       i.e. which are *already* part of their
 		#       sparse-checkout.  Thus, normal file and directory
 		#       completion is always useless for "git
-		#       sparse-checkout add" and is also probelmatic for
+		#       sparse-checkout add" and is also problematic for
 		#       "git sparse-checkout set" unless using it to
 		#       strictly narrow the checkout.
 		COMPREPLY=( "" )
@@ -3698,7 +3698,7 @@
 		# Here we are not completing an --option, it's either the
 		# path or a ref.
 		case "$prev" in
-		-b|-B)	# Complete refs for branch to be created/reseted.
+		-b|-B)	# Complete refs for branch to be created/reset.
 			__git_complete_refs
 			;;
 		-*)	# The previous word is an -o|--option without an
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index 5330e76..6186c47 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -8,8 +8,8 @@
 # To enable:
 #
 #    1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
-#    2) Add the following line to your .bashrc/.zshrc:
-#        source ~/.git-prompt.sh
+#    2) Add the following line to your .bashrc/.zshrc/.profile:
+#        . ~/.git-prompt.sh   # dot path/to/this-file
 #    3a) Change your PS1 to call __git_ps1 as
 #        command-substitution:
 #        Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
@@ -30,6 +30,8 @@
 #        Optionally, you can supply a third argument with a printf
 #        format string to finetune the output of the branch status
 #
+#    See notes below about compatibility with other shells.
+#
 # The repository status will be displayed only if you are currently in a
 # git repository. The %s token is the placeholder for the shown status.
 #
@@ -106,38 +108,78 @@
 # directory is set up to be ignored by git, then set
 # GIT_PS1_HIDE_IF_PWD_IGNORED to a nonempty value. Override this on the
 # repository level by setting bash.hideIfPwdIgnored to "false".
+#
+# Compatibility with other shells (beyond bash/zsh):
+#
+#    We require posix-ish shell plus "local" support, which is most
+#    shells (even pdksh), but excluding ksh93 (because no "local").
+#
+#    Prompt integration might differ between shells, but the gist is
+#    to load it once on shell init with '. path/to/git-prompt.sh',
+#    set GIT_PS1* vars once as needed, and either place $(__git_ps1..)
+#    inside PS1 once (0/1 args), or, before each prompt is displayed,
+#    call __git_ps1 (2/3 args) which sets PS1 with the status embedded.
+#
+#    Many shells support the 1st method of command substitution,
+#    though some might need to first enable cmd substitution in PS1.
+#
+#    When using colors, each escape sequence is wrapped between byte
+#    values 1 and 2 (control chars SOH, STX, respectively), which are
+#    invisible at the output, but for bash/readline they mark 0-width
+#    strings (SGR color sequences) when calculating the on-screen
+#    prompt width, to maintain correct input editing at the prompt.
+#
+#    To replace or disable the 0-width markers, set GIT_PS1_COLOR_PRE
+#    and GIT_PS1_COLOR_POST to other markers, or empty (nul) to not
+#    use markers. For instance, some shells support '\[' and '\]' as
+#    start/end markers in PS1 - when invoking __git_ps1 with 3/4 args,
+#    but it may or may not work in command substitution mode. YMMV.
+#
+#    If the shell doesn't support 0-width markers and editing behaves
+#    incorrectly when using colors in __git_ps1, then, other than
+#    disabling color, it might be solved using multi-line prompt,
+#    where the git status is not at the last line, e.g.:
+#      PS1='\n\w \u@\h$(__git_ps1 " (%s)")\n\$ '
 
 # check whether printf supports -v
 __git_printf_supports_v=
 printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1
 
+# like __git_SOH=$'\001' etc but works also in shells without $'...'
+eval "$(printf '
+	__git_SOH="\001" __git_STX="\002" __git_ESC="\033"
+	__git_LF="\n" __git_CRLF="\r\n"
+')"
+
 # stores the divergence from upstream in $p
 # used by GIT_PS1_SHOWUPSTREAM
 __git_ps1_show_upstream ()
 {
 	local key value
-	local svn_remote svn_url_pattern count n
+	local svn_remotes="" svn_url_pattern="" count n
 	local upstream_type=git legacy="" verbose="" name=""
+	local LF="$__git_LF"
 
-	svn_remote=()
 	# get some config options from git-config
 	local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
 	while read -r key value; do
 		case "$key" in
 		bash.showupstream)
 			GIT_PS1_SHOWUPSTREAM="$value"
-			if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
+			if [ -z "${GIT_PS1_SHOWUPSTREAM}" ]; then
 				p=""
 				return
 			fi
 			;;
 		svn-remote.*.url)
-			svn_remote[$((${#svn_remote[@]} + 1))]="$value"
+			svn_remotes=${svn_remotes}${value}${LF}  # URI\nURI\n...
 			svn_url_pattern="$svn_url_pattern\\|$value"
 			upstream_type=svn+git # default upstream type is SVN if available, else git
 			;;
 		esac
-	done <<< "$output"
+	done <<-OUTPUT
+		$output
+	OUTPUT
 
 	# parse configuration values
 	local option
@@ -154,33 +196,45 @@
 	case "$upstream_type" in
 	git)    upstream_type="@{upstream}" ;;
 	svn*)
-		# get the upstream from the "git-svn-id: ..." in a commit message
-		# (git-svn uses essentially the same procedure internally)
-		local -a svn_upstream
-		svn_upstream=($(git log --first-parent -1 \
-					--grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
-		if [[ 0 -ne ${#svn_upstream[@]} ]]; then
-			svn_upstream=${svn_upstream[${#svn_upstream[@]} - 2]}
-			svn_upstream=${svn_upstream%@*}
-			local n_stop="${#svn_remote[@]}"
-			for ((n=1; n <= n_stop; n++)); do
-				svn_upstream=${svn_upstream#${svn_remote[$n]}}
-			done
+		# successful svn-upstream resolution:
+		# - get the list of configured svn-remotes ($svn_remotes set above)
+		# - get the last commit which seems from one of our svn-remotes
+		# - confirm that it is from one of the svn-remotes
+		# - use $GIT_SVN_ID if set, else "git-svn"
 
-			if [[ -z "$svn_upstream" ]]; then
+		# get upstream from "git-svn-id: UPSTRM@N HASH" in a commit message
+		# (git-svn uses essentially the same procedure internally)
+		local svn_upstream="$(
+			git log --first-parent -1 \
+				--grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null
+		)"
+
+		if [ -n "$svn_upstream" ]; then
+			# extract the URI, assuming --grep matched the last line
+			svn_upstream=${svn_upstream##*$LF}  # last line
+			svn_upstream=${svn_upstream#*: }    # UPSTRM@N HASH
+			svn_upstream=${svn_upstream%@*}     # UPSTRM
+
+			case ${LF}${svn_remotes} in
+			*"${LF}${svn_upstream}${LF}"*)
+				# grep indeed matched the last line - it's our remote
 				# default branch name for checkouts with no layout:
 				upstream_type=${GIT_SVN_ID:-git-svn}
-			else
+				;;
+			*)
+				# the commit message includes one of our remotes, but
+				# it's not at the last line. is $svn_upstream junk?
 				upstream_type=${svn_upstream#/}
-			fi
-		elif [[ "svn+git" = "$upstream_type" ]]; then
+				;;
+			esac
+		elif [ "svn+git" = "$upstream_type" ]; then
 			upstream_type="@{upstream}"
 		fi
 		;;
 	esac
 
 	# Find how many commits we are ahead/behind our upstream
-	if [[ -z "$legacy" ]]; then
+	if [ -z "$legacy" ]; then
 		count="$(git rev-list --count --left-right \
 				"$upstream_type"...HEAD 2>/dev/null)"
 	else
@@ -192,8 +246,8 @@
 			for commit in $commits
 			do
 				case "$commit" in
-				"<"*) ((behind++)) ;;
-				*)    ((ahead++))  ;;
+				"<"*) behind=$((behind+1)) ;;
+				*)    ahead=$((ahead+1))   ;;
 				esac
 			done
 			count="$behind	$ahead"
@@ -203,7 +257,7 @@
 	fi
 
 	# calculate the result
-	if [[ -z "$verbose" ]]; then
+	if [ -z "$verbose" ]; then
 		case "$count" in
 		"") # no upstream
 			p="" ;;
@@ -229,10 +283,10 @@
 		*)	    # diverged from upstream
 			upstream="|u+${count#*	}-${count%	*}" ;;
 		esac
-		if [[ -n "$count" && -n "$name" ]]; then
+		if [ -n "$count" ] && [ -n "$name" ]; then
 			__git_ps1_upstream_name=$(git rev-parse \
 				--abbrev-ref "$upstream_type" 2>/dev/null)
-			if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+			if [ "$pcmode" = yes ] && [ "$ps1_expanded" = yes ]; then
 				upstream="$upstream \${__git_ps1_upstream_name}"
 			else
 				upstream="$upstream ${__git_ps1_upstream_name}"
@@ -251,25 +305,29 @@
 # their own color.
 __git_ps1_colorize_gitstring ()
 {
-	if [[ -n ${ZSH_VERSION-} ]]; then
+	if [ -n "${ZSH_VERSION-}" ]; then
 		local c_red='%F{red}'
 		local c_green='%F{green}'
 		local c_lblue='%F{blue}'
 		local c_clear='%f'
 	else
-		# Using \001 and \002 around colors is necessary to prevent
-		# issues with command line editing/browsing/completion!
-		local c_red=$'\001\e[31m\002'
-		local c_green=$'\001\e[32m\002'
-		local c_lblue=$'\001\e[1;34m\002'
-		local c_clear=$'\001\e[0m\002'
+		# \001 (SOH) and \002 (STX) are 0-width substring markers
+		# which bash/readline identify while calculating the prompt
+		# on-screen width - to exclude 0-screen-width esc sequences.
+		local c_pre="${GIT_PS1_COLOR_PRE-$__git_SOH}${__git_ESC}["
+		local c_post="m${GIT_PS1_COLOR_POST-$__git_STX}"
+
+		local c_red="${c_pre}31${c_post}"
+		local c_green="${c_pre}32${c_post}"
+		local c_lblue="${c_pre}1;34${c_post}"
+		local c_clear="${c_pre}0${c_post}"
 	fi
-	local bad_color=$c_red
-	local ok_color=$c_green
+	local bad_color="$c_red"
+	local ok_color="$c_green"
 	local flags_color="$c_lblue"
 
 	local branch_color=""
-	if [ $detached = no ]; then
+	if [ "$detached" = no ]; then
 		branch_color="$ok_color"
 	else
 		branch_color="$bad_color"
@@ -298,7 +356,7 @@
 # variable, in that order.
 __git_eread ()
 {
-	test -r "$1" && IFS=$'\r\n' read -r "$2" <"$1"
+	test -r "$1" && IFS=$__git_CRLF read -r "$2" <"$1"
 }
 
 # see if a cherry-pick or revert is in progress, if the user has committed a
@@ -346,7 +404,7 @@
 __git_ps1 ()
 {
 	# preserve exit status
-	local exit=$?
+	local exit="$?"
 	local pcmode=no
 	local detached=no
 	local ps1pc_start='\u@\h:\w '
@@ -365,7 +423,7 @@
 		;;
 		0|1)	printf_format="${1:-$printf_format}"
 		;;
-		*)	return $exit
+		*)	return "$exit"
 		;;
 	esac
 
@@ -403,7 +461,7 @@
 	# incorrect.)
 	#
 	local ps1_expanded=yes
-	[ -z "${ZSH_VERSION-}" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no
+	[ -z "${ZSH_VERSION-}" ] || eval '[[ -o PROMPT_SUBST ]]' || ps1_expanded=no
 	[ -z "${BASH_VERSION-}" ] || shopt -q promptvars || ps1_expanded=no
 
 	local repo_info rev_parse_exit_code
@@ -413,29 +471,30 @@
 	rev_parse_exit_code="$?"
 
 	if [ -z "$repo_info" ]; then
-		return $exit
+		return "$exit"
 	fi
 
+	local LF="$__git_LF"
 	local short_sha=""
 	if [ "$rev_parse_exit_code" = "0" ]; then
-		short_sha="${repo_info##*$'\n'}"
-		repo_info="${repo_info%$'\n'*}"
+		short_sha="${repo_info##*$LF}"
+		repo_info="${repo_info%$LF*}"
 	fi
-	local ref_format="${repo_info##*$'\n'}"
-	repo_info="${repo_info%$'\n'*}"
-	local inside_worktree="${repo_info##*$'\n'}"
-	repo_info="${repo_info%$'\n'*}"
-	local bare_repo="${repo_info##*$'\n'}"
-	repo_info="${repo_info%$'\n'*}"
-	local inside_gitdir="${repo_info##*$'\n'}"
-	local g="${repo_info%$'\n'*}"
+	local ref_format="${repo_info##*$LF}"
+	repo_info="${repo_info%$LF*}"
+	local inside_worktree="${repo_info##*$LF}"
+	repo_info="${repo_info%$LF*}"
+	local bare_repo="${repo_info##*$LF}"
+	repo_info="${repo_info%$LF*}"
+	local inside_gitdir="${repo_info##*$LF}"
+	local g="${repo_info%$LF*}"
 
 	if [ "true" = "$inside_worktree" ] &&
 	   [ -n "${GIT_PS1_HIDE_IF_PWD_IGNORED-}" ] &&
 	   [ "$(git config --bool bash.hideIfPwdIgnored)" != "false" ] &&
 	   git check-ignore -q .
 	then
-		return $exit
+		return "$exit"
 	fi
 
 	local sparse=""
@@ -485,14 +544,16 @@
 			case "$ref_format" in
 			files)
 				if ! __git_eread "$g/HEAD" head; then
-					return $exit
+					return "$exit"
 				fi
 
-				if [[ $head == "ref: "* ]]; then
+				case $head in
+				"ref: "*)
 					head="${head#ref: }"
-				else
+					;;
+				*)
 					head=""
-				fi
+				esac
 				;;
 			*)
 				head="$(git symbolic-ref HEAD 2>/dev/null)"
@@ -528,8 +589,8 @@
 	fi
 
 	local conflict="" # state indicator for unresolved conflicts
-	if [[ "${GIT_PS1_SHOWCONFLICTSTATE-}" == "yes" ]] &&
-	   [[ $(git ls-files --unmerged 2>/dev/null) ]]; then
+	if [ "${GIT_PS1_SHOWCONFLICTSTATE-}" = "yes" ] &&
+	   [ "$(git ls-files --unmerged 2>/dev/null)" ]; then
 		conflict="|CONFLICT"
 	fi
 
@@ -581,10 +642,10 @@
 		fi
 	fi
 
-	local z="${GIT_PS1_STATESEPARATOR-" "}"
+	local z="${GIT_PS1_STATESEPARATOR- }"
 
 	b=${b##refs/heads/}
-	if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+	if [ "$pcmode" = yes ] && [ "$ps1_expanded" = yes ]; then
 		__git_ps1_branch_name=$b
 		b="\${__git_ps1_branch_name}"
 	fi
@@ -596,7 +657,7 @@
 	local f="$h$w$i$s$u$p"
 	local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}${conflict}"
 
-	if [ $pcmode = yes ]; then
+	if [ "$pcmode" = yes ]; then
 		if [ "${__git_printf_supports_v-}" != yes ]; then
 			gitstring=$(printf -- "$printf_format" "$gitstring")
 		else
@@ -607,5 +668,5 @@
 		printf -- "$printf_format" "$gitstring"
 	fi
 
-	return $exit
+	return "$exit"
 }
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
index 47e0c55..3f69675 100755
--- a/contrib/git-jump/git-jump
+++ b/contrib/git-jump/git-jump
@@ -44,13 +44,13 @@
 mode_diff() {
 	git diff --no-prefix --relative "$@" |
 	perl -ne '
-	if (m{^\+\+\+ (.*)}) { $file = $1; next }
+	if (m{^\+\+\+ (.*)}) { $file = $1 eq "/dev/null" ? undef : $1; next }
 	defined($file) or next;
 	if (m/^@@ .*?\+(\d+)/) { $line = $1; next }
 	defined($line) or next;
 	if (/^ /) { $line++; next }
 	if (/^[-+]\s*(.*)/) {
-		print "$file:$line: $1\n";
+		print "$file:$line:1: $1\n";
 		$line = undef;
 	}
 	'
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 5dab3f5..15ae86d 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -946,7 +946,7 @@
 		rev=$(git rev-parse -q --verify "$1^{commit}") ||
 			die "fatal: '$1' does not refer to a commit"
 	else
-		die "fatal: you must provide exactly one revision, and optionnally a repository.  Got: '$*'"
+		die "fatal: you must provide exactly one revision, and optionally a repository.  Got: '$*'"
 	fi
 	repository=""
 	if test "$#" = 2
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index c3bd2a5..3c6103f 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -47,7 +47,7 @@
 # pre-2.32.0 versions of 'git subtree' would write the hash of the tag
 # (sub1 below), instead of the commit (sub1^{commit}) in the
 # "git-subtree-split" trailer.
-# We immitate this behaviour below using a replace ref.
+# We imitate this behaviour below using a replace ref.
 # This function creates 3 repositories:
 # - $1
 # - $1-sub (added as subtree "sub" in $1)
diff --git a/convert.c b/convert.c
index c4ddc4d..c9a31eb 100644
--- a/convert.c
+++ b/convert.c
@@ -963,7 +963,7 @@ int async_query_available_blobs(const char *cmd, struct string_list *available_p
 	while ((line = packet_read_line(process->out, NULL))) {
 		const char *path;
 		if (skip_prefix(line, "pathname=", &path))
-			string_list_insert(available_paths, xstrdup(path));
+			string_list_insert(available_paths, path);
 		else
 			; /* ignore unknown keys */
 	}
@@ -1053,14 +1053,20 @@ static int read_convert_config(const char *var, const char *value,
 	 * The command-line will not be interpolated in any way.
 	 */
 
-	if (!strcmp("smudge", key))
+	if (!strcmp("smudge", key)) {
+		FREE_AND_NULL(drv->smudge);
 		return git_config_string(&drv->smudge, var, value);
+	}
 
-	if (!strcmp("clean", key))
+	if (!strcmp("clean", key)) {
+		FREE_AND_NULL(drv->clean);
 		return git_config_string(&drv->clean, var, value);
+	}
 
-	if (!strcmp("process", key))
+	if (!strcmp("process", key)) {
+		FREE_AND_NULL(drv->process);
 		return git_config_string(&drv->process, var, value);
+	}
 
 	if (!strcmp("required", key)) {
 		drv->required = git_config_bool(var, value);
@@ -1365,6 +1371,9 @@ void reset_parsed_attributes(void)
 	for (drv = user_convert; drv; drv = next) {
 		next = drv->next;
 		free((void *)drv->name);
+		free((void *)drv->smudge);
+		free((void *)drv->clean);
+		free((void *)drv->process);
 		free(drv);
 	}
 	user_convert = NULL;
diff --git a/credential.c b/credential.c
index eb0d394..7eca479 100644
--- a/credential.c
+++ b/credential.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "abspath.h"
 #include "config.h"
@@ -11,6 +13,8 @@
 #include "strbuf.h"
 #include "urlmatch.h"
 #include "environment.h"
+#include "trace2.h"
+#include "repository.h"
 
 void credential_init(struct credential *c)
 {
@@ -257,14 +261,36 @@ static char *credential_ask_one(const char *what, struct credential *c,
 	return xstrdup(r);
 }
 
-static void credential_getpass(struct credential *c)
+static int credential_getpass(struct credential *c)
 {
+	int interactive;
+	char *value;
+	if (!git_config_get_maybe_bool("credential.interactive", &interactive) &&
+	    !interactive) {
+		trace2_data_intmax("credential", the_repository,
+				   "interactive/skipped", 1);
+		return -1;
+	}
+	if (!git_config_get_string("credential.interactive", &value)) {
+		int same = !strcmp(value, "never");
+		free(value);
+		if (same) {
+			trace2_data_intmax("credential", the_repository,
+					   "interactive/skipped", 1);
+			return -1;
+		}
+	}
+
+	trace2_region_enter("credential", "interactive", the_repository);
 	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);
+
+	return 0;
 }
 
 int credential_has_capability(const struct credential_capability *capa,
@@ -512,8 +538,8 @@ void credential_fill(struct credential *c, int all_capabilities)
 			    c->helpers.items[i].string);
 	}
 
-	credential_getpass(c);
-	if (!c->username && !c->password && !c->credential)
+	if (credential_getpass(c) ||
+	    (!c->username && !c->password && !c->credential))
 		die("unable to get password from user");
 }
 
diff --git a/csum-file.c b/csum-file.c
index 2131ee6..c203ebf 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -50,13 +50,13 @@ void hashflush(struct hashfile *f)
 
 	if (offset) {
 		if (!f->skip_hash)
-			the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
+			the_hash_algo->unsafe_update_fn(&f->ctx, f->buffer, offset);
 		flush(f, f->buffer, offset);
 		f->offset = 0;
 	}
 }
 
-static void free_hashfile(struct hashfile *f)
+void free_hashfile(struct hashfile *f)
 {
 	free(f->buffer);
 	free(f->check_buffer);
@@ -73,7 +73,7 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result,
 	if (f->skip_hash)
 		hashclr(f->buffer, the_repository->hash_algo);
 	else
-		the_hash_algo->final_fn(f->buffer, &f->ctx);
+		the_hash_algo->unsafe_final_fn(f->buffer, &f->ctx);
 
 	if (result)
 		hashcpy(result, f->buffer, the_repository->hash_algo);
@@ -128,7 +128,7 @@ void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
 			 * f->offset is necessarily zero.
 			 */
 			if (!f->skip_hash)
-				the_hash_algo->update_fn(&f->ctx, buf, nr);
+				the_hash_algo->unsafe_update_fn(&f->ctx, buf, nr);
 			flush(f, buf, nr);
 		} else {
 			/*
@@ -174,7 +174,7 @@ static struct hashfile *hashfd_internal(int fd, const char *name,
 	f->name = name;
 	f->do_crc = 0;
 	f->skip_hash = 0;
-	the_hash_algo->init_fn(&f->ctx);
+	the_hash_algo->unsafe_init_fn(&f->ctx);
 
 	f->buffer_len = buffer_len;
 	f->buffer = xmalloc(buffer_len);
@@ -208,7 +208,7 @@ void hashfile_checkpoint(struct hashfile *f, struct hashfile_checkpoint *checkpo
 {
 	hashflush(f);
 	checkpoint->offset = f->total;
-	the_hash_algo->clone_fn(&checkpoint->ctx, &f->ctx);
+	the_hash_algo->unsafe_clone_fn(&checkpoint->ctx, &f->ctx);
 }
 
 int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
@@ -219,7 +219,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->clone_fn(&f->ctx, &checkpoint->ctx);
+	the_hash_algo->unsafe_clone_fn(&f->ctx, &checkpoint->ctx);
 	f->offset = 0; /* hashflush() was called in checkpoint */
 	return 0;
 }
@@ -245,9 +245,9 @@ int hashfile_checksum_valid(const unsigned char *data, size_t total_len)
 	if (total_len < the_hash_algo->rawsz)
 		return 0; /* say "too short"? */
 
-	the_hash_algo->init_fn(&ctx);
-	the_hash_algo->update_fn(&ctx, data, data_len);
-	the_hash_algo->final_fn(got, &ctx);
+	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);
 
 	return hasheq(got, data + data_len, the_repository->hash_algo);
 }
diff --git a/csum-file.h b/csum-file.h
index 36c7c55..7c73da0 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -46,6 +46,16 @@ int hashfile_truncate(struct hashfile *, struct hashfile_checkpoint *);
 struct hashfile *hashfd(int fd, const char *name);
 struct hashfile *hashfd_check(const char *name);
 struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp);
+
+/*
+ * Free the hashfile without flushing its contents to disk. This only
+ * needs to be called when not calling `finalize_hashfile()`.
+ */
+void free_hashfile(struct hashfile *f);
+
+/*
+ * Finalize the hashfile by flushing data to disk and free'ing it.
+ */
 int finalize_hashfile(struct hashfile *, unsigned char *, enum fsync_component, unsigned int);
 void discard_hashfile(struct hashfile *);
 void hashwrite(struct hashfile *, const void *, unsigned int);
diff --git a/daemon.c b/daemon.c
index 17d331b..cb946e3 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "abspath.h"
 #include "config.h"
@@ -1175,13 +1177,13 @@ static int service_loop(struct socketlist *socklist)
 
 struct credentials;
 
-static void drop_privileges(struct credentials *cred)
+static void drop_privileges(struct credentials *cred UNUSED)
 {
 	/* nothing */
 }
 
-static struct credentials *prepare_credentials(const char *user_name,
-    const char *group_name)
+static struct credentials *prepare_credentials(const char *user_name UNUSED,
+					       const char *group_name UNUSED)
 {
 	die("--user not supported on this platform");
 }
diff --git a/delta-islands.c b/delta-islands.c
index ffe1ca2..8443551 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -390,7 +390,7 @@ static void add_ref_to_island(kh_str_t *remote_islands, const char *island_name,
 	rl->hash += sha_core;
 }
 
-static int find_island_for_ref(const char *refname, const struct object_id *oid,
+static int find_island_for_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			       int flags UNUSED, void *cb)
 {
 	struct island_load_data *ild = cb;
diff --git a/diff-lib.c b/diff-lib.c
index 7a1eb63..6b14b95 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -308,8 +308,7 @@ static void diff_index_show_file(struct rev_info *revs,
 		       oid, oid_valid, ce->name, dirty_submodule);
 }
 
-static int get_stat_data(const struct index_state *istate,
-			 const struct cache_entry *ce,
+static int get_stat_data(const struct cache_entry *ce,
 			 const struct object_id **oidp,
 			 unsigned int *modep,
 			 int cached, int match_missing,
@@ -352,7 +351,6 @@ static void show_new_file(struct rev_info *revs,
 	const struct object_id *oid;
 	unsigned int mode;
 	unsigned dirty_submodule = 0;
-	struct index_state *istate = revs->diffopt.repo->index;
 
 	if (new_file && S_ISSPARSEDIR(new_file->ce_mode)) {
 		diff_tree_oid(NULL, &new_file->oid, new_file->name, &revs->diffopt);
@@ -363,7 +361,7 @@ static void show_new_file(struct rev_info *revs,
 	 * New file in the index: it might actually be different in
 	 * the working tree.
 	 */
-	if (get_stat_data(istate, new_file, &oid, &mode, cached, match_missing,
+	if (get_stat_data(new_file, &oid, &mode, cached, match_missing,
 	    &dirty_submodule, &revs->diffopt) < 0)
 		return;
 
@@ -379,7 +377,6 @@ static int show_modified(struct rev_info *revs,
 	unsigned int mode, oldmode;
 	const struct object_id *oid;
 	unsigned dirty_submodule = 0;
-	struct index_state *istate = revs->diffopt.repo->index;
 
 	assert(S_ISSPARSEDIR(old_entry->ce_mode) ==
 	       S_ISSPARSEDIR(new_entry->ce_mode));
@@ -395,7 +392,7 @@ static int show_modified(struct rev_info *revs,
 		return 0;
 	}
 
-	if (get_stat_data(istate, new_entry, &oid, &mode, cached, match_missing,
+	if (get_stat_data(new_entry, &oid, &mode, cached, match_missing,
 			  &dirty_submodule, &revs->diffopt) < 0) {
 		if (report_missing)
 			diff_index_show_file(revs, "-", old_entry,
@@ -704,7 +701,7 @@ int index_differs_from(struct repository *r,
 	return (has_changes != 0);
 }
 
-static struct strbuf *idiff_prefix_cb(struct diff_options *opt UNUSED, void *data)
+static const char *idiff_prefix_cb(struct diff_options *opt UNUSED, void *data)
 {
 	return data;
 }
@@ -719,7 +716,7 @@ void show_interdiff(const struct object_id *oid1, const struct object_id *oid2,
 	opts.output_format = DIFF_FORMAT_PATCH;
 	opts.output_prefix = idiff_prefix_cb;
 	strbuf_addchars(&prefix, ' ', indent);
-	opts.output_prefix_data = &prefix;
+	opts.output_prefix_data = prefix.buf;
 	diff_setup_done(&opts);
 
 	diff_tree_oid(oid1, oid2, "", &opts);
diff --git a/diff-no-index.c b/diff-no-index.c
index 3a89656..c5fb06e 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -362,7 +362,7 @@ int diff_no_index(struct rev_info *revs,
 	 * The return code for --no-index imitates diff(1):
 	 * 0 = no changes, 1 = changes, else error
 	 */
-	ret = diff_result_code(&revs->diffopt);
+	ret = diff_result_code(revs);
 
 out:
 	for (i = 0; i < ARRAY_SIZE(to_free); i++)
diff --git a/diff.c b/diff.c
index a834099..6c96154 100644
--- a/diff.c
+++ b/diff.c
@@ -12,6 +12,7 @@
 #include "environment.h"
 #include "gettext.h"
 #include "tempfile.h"
+#include "revision.h"
 #include "quote.h"
 #include "diff.h"
 #include "diffcore.h"
@@ -29,6 +30,7 @@
 #include "merge-ll.h"
 #include "string-list.h"
 #include "strvec.h"
+#include "tmp-objdir.h"
 #include "graph.h"
 #include "oid-array.h"
 #include "packfile.h"
@@ -441,8 +443,10 @@ int git_diff_ui_config(const char *var, const char *value,
 	}
 	if (!strcmp(var, "diff.wordregex"))
 		return git_config_string(&diff_word_regex_cfg, var, value);
-	if (!strcmp(var, "diff.orderfile"))
+	if (!strcmp(var, "diff.orderfile")) {
+		FREE_AND_NULL(diff_order_file_cfg);
 		return git_config_pathname(&diff_order_file_cfg, var, value);
+	}
 
 	if (!strcmp(var, "diff.ignoresubmodules")) {
 		if (!value)
@@ -2313,12 +2317,9 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)
 
 const char *diff_line_prefix(struct diff_options *opt)
 {
-	struct strbuf *msgbuf;
-	if (!opt->output_prefix)
-		return "";
-
-	msgbuf = opt->output_prefix(opt, opt->output_prefix_data);
-	return msgbuf->buf;
+	return opt->output_prefix ?
+		opt->output_prefix(opt, opt->output_prefix_data) :
+		"";
 }
 
 static unsigned long sane_truncate_line(char *line, unsigned long len)
@@ -3673,6 +3674,7 @@ static void builtin_diff(const char *name_a,
 			emit_diff_symbol(o, DIFF_SYMBOL_BINARY_FILES,
 					 sb.buf, sb.len, 0);
 			strbuf_release(&sb);
+			o->found_changes = 1;
 			goto free_ab_and_return;
 		}
 		if (fill_mmfile(o->repo, &mf1, one) < 0 ||
@@ -4775,7 +4777,7 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
 	if (diff_indent_heuristic)
 		DIFF_XDL_SET(options, INDENT_HEURISTIC);
 
-	options->orderfile = diff_order_file_cfg;
+	options->orderfile = xstrdup_or_null(diff_order_file_cfg);
 
 	if (!options->flags.ignore_submodule_set)
 		options->flags.ignore_untracked_in_submodules = 1;
@@ -5395,7 +5397,6 @@ static int diff_opt_line_prefix(const struct option *opt,
 
 	BUG_ON_OPT_NEG(unset);
 	options->line_prefix = optarg;
-	options->line_prefix_length = strlen(options->line_prefix);
 	graph_setup_line_prefix(options);
 	return 0;
 }
@@ -5469,9 +5470,13 @@ static int diff_opt_ignore_regex(const struct option *opt,
 	regex_t *regex;
 
 	BUG_ON_OPT_NEG(unset);
+
 	regex = xmalloc(sizeof(*regex));
-	if (regcomp(regex, arg, REG_EXTENDED | REG_NEWLINE))
+	if (regcomp(regex, arg, REG_EXTENDED | REG_NEWLINE)) {
+		free(regex);
 		return error(_("invalid regex given to -I: '%s'"), arg);
+	}
+
 	ALLOC_GROW(options->ignore_regex, options->ignore_regex_nr + 1,
 		   options->ignore_regex_alloc);
 	options->ignore_regex[options->ignore_regex_nr++] = regex;
@@ -6718,6 +6723,17 @@ void diff_free(struct diff_options *options)
 	if (options->no_free)
 		return;
 
+	if (options->objfind) {
+		oidset_clear(options->objfind);
+		FREE_AND_NULL(options->objfind);
+	}
+
+	FREE_AND_NULL(options->orderfile);
+	for (size_t i = 0; i < options->anchors_nr; i++)
+		free(options->anchors[i]);
+	FREE_AND_NULL(options->anchors);
+	options->anchors_nr = options->anchors_alloc = 0;
+
 	diff_free_file(options);
 	diff_free_ignore_regex(options);
 	clear_pathspec(&options->pathspec);
@@ -7074,10 +7090,16 @@ void diffcore_std(struct diff_options *options)
 	options->found_follow = 0;
 }
 
-int diff_result_code(struct diff_options *opt)
+int diff_result_code(struct rev_info *revs)
 {
+	struct diff_options *opt = &revs->diffopt;
 	int result = 0;
 
+	if (revs->remerge_diff) {
+		tmp_objdir_destroy(revs->remerge_objdir);
+		revs->remerge_objdir = NULL;
+	}
+
 	diff_warn_rename_limit("diff.renameLimit",
 			       opt->needed_rename_limit,
 			       opt->degraded_cc_to_c);
diff --git a/diff.h b/diff.h
index 9901c8c..5c8de79 100644
--- a/diff.h
+++ b/diff.h
@@ -94,7 +94,7 @@ typedef void (*add_remove_fn_t)(struct diff_options *options,
 typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
 		struct diff_options *options, void *data);
 
-typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data);
+typedef const char *(*diff_prefix_fn_t)(struct diff_options *opt, void *data);
 
 #define DIFF_FORMAT_RAW		0x0001
 #define DIFF_FORMAT_DIFFSTAT	0x0002
@@ -235,7 +235,7 @@ enum diff_submodule_format {
  * diffcore library with.
  */
 struct diff_options {
-	const char *orderfile;
+	char *orderfile;
 
 	/*
 	 * "--rotate-to=<file>" would start showing at <file> and when
@@ -274,7 +274,6 @@ struct diff_options {
 	const char *single_follow;
 	const char *a_prefix, *b_prefix;
 	const char *line_prefix;
-	size_t line_prefix_length;
 
 	/**
 	 * collection of boolean options that affects the operation, but some do
@@ -648,7 +647,7 @@ 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);
 
-int diff_result_code(struct diff_options *);
+int diff_result_code(struct rev_info *);
 
 int diff_no_index(struct rev_info *,
 		  int implicit_no_index, int, const char **);
diff --git a/diffcore-break.c b/diffcore-break.c
index 831b66b..02735f8 100644
--- a/diffcore-break.c
+++ b/diffcore-break.c
@@ -266,8 +266,8 @@ static void merge_broken(struct diff_filepair *p,
 	 * in the resulting tree.
 	 */
 	d->one->rename_used++;
-	diff_free_filespec_data(d->two);
-	diff_free_filespec_data(c->one);
+	free_filespec(d->two);
+	free_filespec(c->one);
 	free(d);
 	free(c);
 }
diff --git a/diffcore-order.c b/diffcore-order.c
index e7d20eb..912513d 100644
--- a/diffcore-order.c
+++ b/diffcore-order.c
@@ -14,8 +14,7 @@ static void prepare_order(const char *orderfile)
 {
 	int cnt, pass;
 	struct strbuf sb = STRBUF_INIT;
-	void *map;
-	char *cp, *endp;
+	const char *cp, *endp;
 	ssize_t sz;
 
 	if (order)
@@ -24,14 +23,13 @@ static void prepare_order(const char *orderfile)
 	sz = strbuf_read_file(&sb, orderfile, 0);
 	if (sz < 0)
 		die_errno(_("failed to read orderfile '%s'"), orderfile);
-	map = strbuf_detach(&sb, NULL);
-	endp = (char *) map + sz;
+	endp = sb.buf + sz;
 
 	for (pass = 0; pass < 2; pass++) {
 		cnt = 0;
-		cp = map;
+		cp = sb.buf;
 		while (cp < endp) {
-			char *ep;
+			const char *ep;
 			for (ep = cp; ep < endp && *ep != '\n'; ep++)
 				;
 			/* cp to ep has one line */
@@ -40,12 +38,7 @@ static void prepare_order(const char *orderfile)
 			else if (pass == 0)
 				cnt++;
 			else {
-				if (*ep == '\n') {
-					*ep = 0;
-					order[cnt] = cp;
-				} else {
-					order[cnt] = xmemdupz(cp, ep - cp);
-				}
+				order[cnt] = xmemdupz(cp, ep - cp);
 				cnt++;
 			}
 			if (ep < endp)
@@ -57,6 +50,8 @@ static void prepare_order(const char *orderfile)
 			ALLOC_ARRAY(order, cnt);
 		}
 	}
+
+	strbuf_release(&sb);
 }
 
 static int match_order(const char *path)
diff --git a/diffcore-rename.c b/diffcore-rename.c
index fab45b1..3d6826b 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -933,7 +933,7 @@ static int find_basename_matches(struct diff_options *options,
 	 * spend more cycles to find similarities between files, so it may
 	 * be less likely that this heuristic is wanted.  If someone is
 	 * doing break detection, that means they do not want filename
-	 * similarity to imply any form of content similiarity, and thus
+	 * similarity to imply any form of content similarity, and thus
 	 * this heuristic would definitely be incompatible.
 	 */
 
@@ -1534,7 +1534,7 @@ void diffcore_rename_extended(struct diff_options *options,
 		 *   - remove ones not found in relevant_sources
 		 * and
 		 *   - remove ones in relevant_sources which are needed only
-		 *     for directory renames IF no ancestory directory
+		 *     for directory renames IF no ancestry directory
 		 *     actually needs to know any more individual path
 		 *     renames under them
 		 */
diff --git a/dir.c b/dir.c
index 5a23376..e3ddd5b 100644
--- a/dir.c
+++ b/dir.c
@@ -20,6 +20,7 @@
 #include "object-store-ll.h"
 #include "path.h"
 #include "refs.h"
+#include "repository.h"
 #include "wildmatch.h"
 #include "pathspec.h"
 #include "utf8.h"
@@ -2135,8 +2136,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
 			 */
 			state = path_none;
 		} else {
-			int i;
-			for (i = old_ignored_nr + 1; i<dir->ignored_nr; ++i)
+			for (int i = old_ignored_nr; i < dir->ignored_nr; i++)
 				FREE_AND_NULL(dir->ignored[i]);
 			dir->ignored_nr = old_ignored_nr;
 		}
@@ -2148,8 +2148,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
 	 */
 	if ((dir->flags & DIR_SHOW_IGNORED_TOO) &&
 	    !(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) {
-		int i;
-		for (i = old_untracked_nr + 1; i<dir->nr; ++i)
+		for (int i = old_untracked_nr; i < dir->nr; i++)
 			FREE_AND_NULL(dir->entries[i]);
 		dir->nr = old_untracked_nr;
 	}
@@ -2838,7 +2837,7 @@ static const char *get_ident_string(void)
 		return sb.buf;
 	if (uname(&uts) < 0)
 		die_errno(_("failed to get kernel name and information"));
-	strbuf_addf(&sb, "Location %s, system %s", get_git_work_tree(),
+	strbuf_addf(&sb, "Location %s, system %s", repo_get_work_tree(the_repository),
 		    uts.sysname);
 	return sb.buf;
 }
diff --git a/editor.c b/editor.c
index d1ba2d7..6b9ce81 100644
--- a/editor.c
+++ b/editor.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "abspath.h"
 #include "advice.h"
@@ -133,14 +135,17 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
 	return launch_specified_editor(git_sequence_editor(), path, buffer, env);
 }
 
-int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
+int strbuf_edit_interactively(struct repository *r,
+			      struct strbuf *buffer, const char *path,
 			      const char *const *env)
 {
-	char *path2 = NULL;
+	struct strbuf sb = STRBUF_INIT;
 	int fd, res = 0;
 
-	if (!is_absolute_path(path))
-		path = path2 = xstrdup(git_path("%s", path));
+	if (!is_absolute_path(path)) {
+		strbuf_repo_git_path(&sb, r, "%s", path);
+		path = sb.buf;
+	}
 
 	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
 	if (fd < 0)
@@ -157,6 +162,6 @@ int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
 		unlink(path);
 	}
 
-	free(path2);
+	strbuf_release(&sb);
 	return res;
 }
diff --git a/editor.h b/editor.h
index 8016bb5..f1c41df 100644
--- a/editor.h
+++ b/editor.h
@@ -1,6 +1,7 @@
 #ifndef EDITOR_H
 #define EDITOR_H
 
+struct repository;
 struct strbuf;
 
 const char *git_editor(void);
@@ -28,7 +29,7 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
  *
  * If `path` is relative, it refers to a file in the `.git` directory.
  */
-int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
-			      const char *const *env);
+int strbuf_edit_interactively(struct repository *r, struct strbuf *buffer,
+			      const char *path, const char *const *env);
 
 #endif
diff --git a/entry.c b/entry.c
index e7ed440..3143b99 100644
--- a/entry.c
+++ b/entry.c
@@ -191,7 +191,7 @@ int finish_delayed_checkout(struct checkout *state, int show_progress)
 		progress = start_delayed_progress(_("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_NODUP;
+			struct string_list available_paths = STRING_LIST_INIT_DUP;
 
 			if (!async_query_available_blobs(filter->string, &available_paths)) {
 				/* Filter reported an error */
@@ -245,6 +245,8 @@ int finish_delayed_checkout(struct checkout *state, int show_progress)
 				} else
 					errs = 1;
 			}
+
+			string_list_clear(&available_paths, 0);
 		}
 
 		filter_string_list(&dco->filters, 0, string_is_not_null, NULL);
diff --git a/environment.c b/environment.c
index 5cea2c9..a2ce998 100644
--- a/environment.c
+++ b/environment.c
@@ -22,15 +22,9 @@
 #include "fmt-merge-msg.h"
 #include "commit.h"
 #include "strvec.h"
-#include "object-file.h"
-#include "object-store-ll.h"
 #include "path.h"
-#include "replace-object.h"
-#include "tmp-objdir.h"
 #include "chdir-notify.h"
 #include "setup.h"
-#include "shallow.h"
-#include "trace.h"
 #include "write-or-die.h"
 
 int trust_executable_bit = 1;
@@ -40,9 +34,7 @@ int has_symlinks = 1;
 int minimum_abbrev = 4, default_abbrev = -1;
 int ignore_case;
 int assume_unchanged;
-int prefer_symlink_refs;
 int is_bare_repository_cfg = -1; /* unspecified */
-int warn_ambiguous_refs = 1;
 int warn_on_object_refname_ambiguity = 1;
 int repository_format_precious_objects;
 char *git_commit_encoding;
@@ -75,7 +67,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
 #define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
 #endif
 enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
-char *notes_ref_name;
 int grafts_keep_true_parents;
 int core_apply_sparse_checkout;
 int core_sparse_checkout_cone;
@@ -83,7 +74,6 @@ int sparse_expect_files_outside_of_patterns;
 int merge_log_config = -1;
 int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
 unsigned long pack_size_limit_cfg;
-enum log_refs_config log_all_ref_updates = LOG_REFS_UNSET;
 int max_allowed_tree_depth =
 #ifdef _MSC_VER
 	/*
@@ -114,6 +104,7 @@ int protect_ntfs = PROTECT_NTFS_DEFAULT;
  * that is subject to stripspace.
  */
 const char *comment_line_str = "#";
+char *comment_line_str_to_free;
 int auto_comment_line_char;
 
 /* Parallel index stat data preload? */
@@ -122,8 +113,6 @@ int core_preload_index = 1;
 /* This is set by setup_git_dir_gently() and/or git_default_config() */
 char *git_work_tree_cfg;
 
-static char *git_namespace;
-
 /*
  * Repository-local GIT_* environment variables; see environment.h for details.
  */
@@ -146,27 +135,6 @@ const char * const local_repo_env[] = {
 	NULL
 };
 
-static char *expand_namespace(const char *raw_namespace)
-{
-	struct strbuf buf = STRBUF_INIT;
-	struct strbuf **components, **c;
-
-	if (!raw_namespace || !*raw_namespace)
-		return xstrdup("");
-
-	strbuf_addstr(&buf, raw_namespace);
-	components = strbuf_split(&buf, '/');
-	strbuf_reset(&buf);
-	for (c = components; *c; c++)
-		if (strcmp((*c)->buf, "/") != 0)
-			strbuf_addf(&buf, "refs/namespaces/%s", (*c)->buf);
-	strbuf_list_free(components);
-	if (check_refname_format(buf.buf, 0))
-		die(_("bad git namespace path \"%s\""), raw_namespace);
-	strbuf_addch(&buf, '/');
-	return strbuf_detach(&buf, NULL);
-}
-
 const char *getenv_safe(struct strvec *argv, const char *name)
 {
 	const char *value = getenv(name);
@@ -178,47 +146,10 @@ const char *getenv_safe(struct strvec *argv, const char *name)
 	return argv->v[argv->nr - 1];
 }
 
-void setup_git_env(const char *git_dir)
-{
-	char *git_replace_ref_base;
-	const char *shallow_file;
-	const char *replace_ref_base;
-	struct set_gitdir_args args = { NULL };
-	struct strvec to_free = STRVEC_INIT;
-
-	args.commondir = getenv_safe(&to_free, GIT_COMMON_DIR_ENVIRONMENT);
-	args.object_dir = getenv_safe(&to_free, DB_ENVIRONMENT);
-	args.graft_file = getenv_safe(&to_free, GRAFT_ENVIRONMENT);
-	args.index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT);
-	args.alternate_db = getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT);
-	if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
-		args.disable_ref_updates = 1;
-	}
-
-	repo_set_gitdir(the_repository, git_dir, &args);
-	strvec_clear(&to_free);
-
-	if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
-		disable_replace_refs();
-	replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
-	git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
-							  : "refs/replace/");
-	update_ref_namespace(NAMESPACE_REPLACE, git_replace_ref_base);
-
-	free(git_namespace);
-	git_namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
-	shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
-	if (shallow_file)
-		set_alternate_shallow_file(the_repository, shallow_file, 0);
-
-	if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0))
-		fetch_if_missing = 0;
-}
-
 int is_bare_repository(void)
 {
 	/* if core.bare is not 'false', let's see if there is a work tree */
-	return is_bare_repository_cfg && !get_git_work_tree();
+	return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
 }
 
 int have_git_dir(void)
@@ -227,25 +158,37 @@ int have_git_dir(void)
 		|| the_repository->gitdir;
 }
 
-const char *get_git_dir(void)
-{
-	if (!the_repository->gitdir)
-		BUG("git environment hasn't been setup");
-	return the_repository->gitdir;
-}
-
-const char *get_git_common_dir(void)
-{
-	if (!the_repository->commondir)
-		BUG("git environment hasn't been setup");
-	return the_repository->commondir;
-}
-
 const char *get_git_namespace(void)
 {
-	if (!git_namespace)
-		BUG("git environment hasn't been setup");
-	return git_namespace;
+	static const char *namespace;
+
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf **components, **c;
+	const char *raw_namespace;
+
+	if (namespace)
+		return namespace;
+
+	raw_namespace = getenv(GIT_NAMESPACE_ENVIRONMENT);
+	if (!raw_namespace || !*raw_namespace) {
+		namespace = "";
+		return namespace;
+	}
+
+	strbuf_addstr(&buf, raw_namespace);
+	components = strbuf_split(&buf, '/');
+	strbuf_reset(&buf);
+	for (c = components; *c; c++)
+		if (strcmp((*c)->buf, "/") != 0)
+			strbuf_addf(&buf, "refs/namespaces/%s", (*c)->buf);
+	strbuf_list_free(components);
+	if (check_refname_format(buf.buf, 0))
+		die(_("bad git namespace path \"%s\""), raw_namespace);
+	strbuf_addch(&buf, '/');
+
+	namespace = strbuf_detach(&buf, NULL);
+
+	return namespace;
 }
 
 const char *strip_namespace(const char *namespaced_ref)
@@ -256,129 +199,6 @@ const char *strip_namespace(const char *namespaced_ref)
 	return NULL;
 }
 
-static int git_work_tree_initialized;
-
-/*
- * Note.  This works only before you used a work tree.  This was added
- * primarily to support git-clone to work in a new repository it just
- * created, and is not meant to flip between different work trees.
- */
-void set_git_work_tree(const char *new_work_tree)
-{
-	if (git_work_tree_initialized) {
-		struct strbuf realpath = STRBUF_INIT;
-
-		strbuf_realpath(&realpath, new_work_tree, 1);
-		new_work_tree = realpath.buf;
-		if (strcmp(new_work_tree, the_repository->worktree))
-			die("internal error: work tree has already been set\n"
-			    "Current worktree: %s\nNew worktree: %s",
-			    the_repository->worktree, new_work_tree);
-		strbuf_release(&realpath);
-		return;
-	}
-	git_work_tree_initialized = 1;
-	repo_set_worktree(the_repository, new_work_tree);
-}
-
-const char *get_git_work_tree(void)
-{
-	return the_repository->worktree;
-}
-
-const char *get_object_directory(void)
-{
-	if (!the_repository->objects->odb)
-		BUG("git environment hasn't been setup");
-	return the_repository->objects->odb->path;
-}
-
-int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
-{
-	int fd;
-	/*
-	 * we let the umask do its job, don't try to be more
-	 * restrictive except to remove write permission.
-	 */
-	int mode = 0444;
-	git_path_buf(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);
-	safe_create_leading_directories(temp_filename->buf);
-	return xmkstemp_mode(temp_filename->buf, mode);
-}
-
-int odb_pack_keep(const char *name)
-{
-	int fd;
-
-	fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
-	if (0 <= fd)
-		return fd;
-
-	/* slow path */
-	safe_create_leading_directories_const(name);
-	return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
-}
-
-char *get_index_file(void)
-{
-	if (!the_repository->index_file)
-		BUG("git environment hasn't been setup");
-	return the_repository->index_file;
-}
-
-char *get_graft_file(struct repository *r)
-{
-	if (!r->graft_file)
-		BUG("git environment hasn't been setup");
-	return r->graft_file;
-}
-
-static void set_git_dir_1(const char *path)
-{
-	xsetenv(GIT_DIR_ENVIRONMENT, path, 1);
-	setup_git_env(path);
-}
-
-static void update_relative_gitdir(const char *name UNUSED,
-				   const char *old_cwd,
-				   const char *new_cwd,
-				   void *data UNUSED)
-{
-	char *path = reparent_relative_path(old_cwd, new_cwd, get_git_dir());
-	struct tmp_objdir *tmp_objdir = tmp_objdir_unapply_primary_odb();
-
-	trace_printf_key(&trace_setup_key,
-			 "setup: move $GIT_DIR to '%s'",
-			 path);
-	set_git_dir_1(path);
-	if (tmp_objdir)
-		tmp_objdir_reapply_primary_odb(tmp_objdir, old_cwd, new_cwd);
-	free(path);
-}
-
-void set_git_dir(const char *path, int make_realpath)
-{
-	struct strbuf realpath = STRBUF_INIT;
-
-	if (make_realpath) {
-		strbuf_realpath(&realpath, path, 1);
-		path = realpath.buf;
-	}
-
-	set_git_dir_1(path);
-	if (!is_absolute_path(path))
-		chdir_notify_register(NULL, update_relative_gitdir, NULL);
-
-	strbuf_release(&realpath);
-}
-
 const char *get_log_output_encoding(void)
 {
 	return git_log_output_encoding ? git_log_output_encoding
diff --git a/environment.h b/environment.h
index e9f01d4..923e126 100644
--- a/environment.h
+++ b/environment.h
@@ -1,21 +1,7 @@
 #ifndef ENVIRONMENT_H
 #define ENVIRONMENT_H
 
-struct repository;
-struct strvec;
-
-/*
- * The character that begins a commented line in user-editable file
- * that is subject to stripspace.
- */
-extern const char *comment_line_str;
-extern int auto_comment_line_char;
-
-/*
- * Wrapper of getenv() that returns a strdup value. This value is kept
- * in argv to be freed later.
- */
-const char *getenv_safe(struct strvec *argv, const char *name);
+#include "repo-settings.h"
 
 /* Double-check local_repo_env below if you add to this list. */
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
@@ -86,6 +72,8 @@ const char *getenv_safe(struct strvec *argv, const char *name);
  */
 #define GIT_IMPLICIT_WORK_TREE_ENVIRONMENT "GIT_IMPLICIT_WORK_TREE"
 
+#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
+
 /*
  * Repository-local GIT_* environment variables; these will be cleared
  * when git spawns a sub-process that runs inside another repository.
@@ -94,6 +82,50 @@ const char *getenv_safe(struct strvec *argv, const char *name);
  */
 extern const char * const local_repo_env[];
 
+struct strvec;
+
+/*
+ * Wrapper of getenv() that returns a strdup value. This value is kept
+ * in argv to be freed later.
+ */
+const char *getenv_safe(struct strvec *argv, const char *name);
+
+/*
+ * Should we print an ellipsis after an abbreviated SHA-1 value
+ * when doing diff-raw output or indicating a detached HEAD?
+ */
+int print_sha1_ellipsis(void);
+
+/*
+ * Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
+ */
+int use_optional_locks(void);
+
+const char *get_git_namespace(void);
+const char *strip_namespace(const char *namespaced_ref);
+
+/*
+ * TODO: All the below state either explicitly or implicitly relies on
+ * `the_repository`. We should eventually get rid of these and make the
+ * dependency on a repository explicit:
+ *
+ *   - `setup_git_env()` ideally shouldn't exist as it modifies global state,
+ *     namely the environment. The current process shouldn't ever access that
+ *     state via envvars though, but should instead consult a `struct
+ *     repository`. When spawning new processes, we would ideally also pass a
+ *     `struct repository` and then set up the environment variables for the
+ *     child process, only.
+ *
+ *   - `have_git_dir()` should not have to exist at all. Instead, we should
+ *     decide on whether or not we have a `struct repository`.
+ *
+ *   - All the global config variables should become tied to a repository. Like
+ *     this, we'd correctly honor repository-local configuration and be able to
+ *     distinguish configuration values from different repositories.
+ *
+ * Please do not add new global config variables here.
+ */
+# ifdef USE_THE_REPOSITORY_VARIABLE
 void setup_git_env(const char *git_dir);
 
 /*
@@ -102,21 +134,19 @@ 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;
-const char *get_git_dir(void);
-const char *get_git_common_dir(void);
-const char *get_object_directory(void);
-char *get_index_file(void);
-char *get_graft_file(struct repository *r);
-void set_git_dir(const char *path, int make_realpath);
-const char *get_git_namespace(void);
-const char *strip_namespace(const char *namespaced_ref);
-const char *get_git_work_tree(void);
-void set_git_work_tree(const char *tree);
-
-#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
 /* Environment bits from configuration mechanism */
 extern int trust_executable_bit;
@@ -126,8 +156,6 @@ extern int has_symlinks;
 extern int minimum_abbrev, default_abbrev;
 extern int ignore_case;
 extern int assume_unchanged;
-extern int prefer_symlink_refs;
-extern int warn_ambiguous_refs;
 extern int warn_on_object_refname_ambiguity;
 extern char *apply_default_whitespace;
 extern char *apply_default_ignorewhitespace;
@@ -142,16 +170,6 @@ extern unsigned long big_file_threshold;
 extern unsigned long pack_size_limit_cfg;
 extern int max_allowed_tree_depth;
 
-/*
- * 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 core_preload_index;
 extern int precomposed_unicode;
 extern int protect_hfs;
@@ -161,25 +179,13 @@ extern int core_apply_sparse_checkout;
 extern int core_sparse_checkout_cone;
 extern int sparse_expect_files_outside_of_patterns;
 
-/*
- * Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
- */
-int use_optional_locks(void);
-
-enum log_refs_config {
-	LOG_REFS_UNSET = -1,
-	LOG_REFS_NONE = 0,
-	LOG_REFS_NORMAL,
-	LOG_REFS_ALWAYS
-};
-extern enum log_refs_config log_all_ref_updates;
-
 enum rebase_setup_type {
 	AUTOREBASE_NEVER = 0,
 	AUTOREBASE_LOCAL,
 	AUTOREBASE_REMOTE,
 	AUTOREBASE_ALWAYS
 };
+extern enum rebase_setup_type autorebase;
 
 enum push_default_type {
 	PUSH_DEFAULT_NOTHING = 0,
@@ -189,38 +195,18 @@ enum push_default_type {
 	PUSH_DEFAULT_CURRENT,
 	PUSH_DEFAULT_UNSPECIFIED
 };
-
-extern enum rebase_setup_type autorebase;
 extern enum push_default_type push_default;
 
 enum object_creation_mode {
 	OBJECT_CREATION_USES_HARDLINKS = 0,
 	OBJECT_CREATION_USES_RENAMES = 1
 };
-
 extern enum object_creation_mode object_creation_mode;
 
-extern char *notes_ref_name;
-
 extern int grafts_keep_true_parents;
 
 extern int repository_format_precious_objects;
 
-/*
- * Create a temporary file rooted in the object database directory, or
- * die on failure. The filename is taken from "pattern", which should have the
- * usual "XXXXXX" trailer, and the resulting filename is written into the
- * "template" buffer. Returns the open descriptor.
- */
-int odb_mkstemp(struct strbuf *temp_filename, const char *pattern);
-
-/*
- * Create a pack .keep file named "name" (which should generally be the output
- * of odb_pack_name). Returns a file descriptor opened for writing, or -1 on
- * error.
- */
-int odb_pack_keep(const char *name);
-
 const char *get_log_output_encoding(void);
 const char *get_commit_output_encoding(void);
 
@@ -232,9 +218,12 @@ extern char *askpass_program;
 extern char *excludes_file;
 
 /*
- * Should we print an ellipsis after an abbreviated SHA-1 value
- * when doing diff-raw output or indicating a detached HEAD?
+ * The character that begins a commented line in user-editable file
+ * that is subject to stripspace.
  */
-int print_sha1_ellipsis(void);
+extern const char *comment_line_str;
+extern char *comment_line_str_to_free;
+extern int auto_comment_line_char;
 
-#endif
+# endif /* USE_THE_REPOSITORY_VARIABLE */
+#endif /* ENVIRONMENT_H */
diff --git a/exec-cmd.c b/exec-cmd.c
index 909777f..507e67d 100644
--- a/exec-cmd.c
+++ b/exec-cmd.c
@@ -150,6 +150,25 @@ static int git_get_exec_path_darwin(struct strbuf *buf)
 }
 #endif /* HAVE_NS_GET_EXECUTABLE_PATH */
 
+#ifdef HAVE_ZOS_GET_EXECUTABLE_PATH
+/*
+ * Resolves the executable path from current program's directory and name.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int git_get_exec_path_zos(struct strbuf *buf)
+{
+	char *dir = __getprogramdir();
+	char *exe = getprogname();
+	if (dir && exe) {
+		strbuf_addf(buf, "%s/%s", dir, exe);
+		return 0;
+	}
+	return -1;
+}
+
+#endif /* HAVE_ZOS_GET_EXECUTABLE_PATH */
+
 #ifdef HAVE_WPGMPTR
 /*
  * Resolves the executable path by using the global variable _wpgmptr.
@@ -206,6 +225,10 @@ static int git_get_exec_path(struct strbuf *buf, const char *argv0)
 		git_get_exec_path_wpgmptr(buf) &&
 #endif /* HAVE_WPGMPTR */
 
+#ifdef HAVE_ZOS_GET_EXECUTABLE_PATH
+		git_get_exec_path_zos(buf) &&
+#endif /*HAVE_ZOS_GET_EXECUTABLE_PATH */
+
 		git_get_exec_path_from_argv0(buf, argv0)) {
 		return -1;
 	}
diff --git a/fetch-pack.c b/fetch-pack.c
index 7325116..f752da9 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -183,6 +183,7 @@ static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
 }
 
 static int rev_list_insert_ref_oid(const char *refname UNUSED,
+				   const char *referent UNUSED,
 				   const struct object_id *oid,
 				   int flag UNUSED,
 				   void *cb_data)
@@ -610,6 +611,7 @@ static int mark_complete(const struct object_id *oid)
 }
 
 static int mark_complete_oid(const char *refname UNUSED,
+			     const char *referent UNUSED,
 			     const struct object_id *oid,
 			     int flag UNUSED,
 			     void *cb_data UNUSED)
@@ -1612,7 +1614,7 @@ static void receive_packfile_uris(struct packet_reader *reader,
 	while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
 		if (reader->pktlen < the_hash_algo->hexsz ||
 		    reader->line[the_hash_algo->hexsz] != ' ')
-			die("expected '<hash> <uri>', got: %s\n", reader->line);
+			die("expected '<hash> <uri>', got: %s", reader->line);
 
 		string_list_append(uris, reader->line);
 	}
@@ -1837,7 +1839,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
 
 		string_list_append_nodup(pack_lockfiles,
 					 xstrfmt("%s/pack/pack-%s.keep",
-						 get_object_directory(),
+						 repo_get_object_directory(the_repository),
 						 packname));
 	}
 	string_list_clear(&packfile_uris, 0);
@@ -2225,7 +2227,10 @@ void negotiate_using_fetch(const struct oid_array *negotiation_tips,
 	trace2_region_leave("fetch-pack", "negotiate_using_fetch", the_repository);
 	trace2_data_intmax("negotiate_using_fetch", the_repository,
 			   "total_rounds", negotiation_round);
+
 	clear_common_flag(acked_commits);
+	object_array_clear(&nt_object_array);
+	negotiator.release(&negotiator);
 	strbuf_release(&req_buf);
 }
 
diff --git a/fsck.c b/fsck.c
index eea7145..3756f52 100644
--- a/fsck.c
+++ b/fsck.c
@@ -205,7 +205,7 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values)
 		if (!strcmp(buf, "skiplist")) {
 			if (equal == len)
 				die("skiplist requires a path");
-			oidset_parse_file(&options->skiplist, buf + equal + 1,
+			oidset_parse_file(&options->skip_oids, buf + equal + 1,
 					  the_repository->hash_algo);
 			buf += len + 1;
 			continue;
@@ -223,15 +223,18 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values)
 static int object_on_skiplist(struct fsck_options *opts,
 			      const struct object_id *oid)
 {
-	return opts && oid && oidset_contains(&opts->skiplist, oid);
+	return opts && oid && oidset_contains(&opts->skip_oids, oid);
 }
 
-__attribute__((format (printf, 5, 6)))
-static int report(struct fsck_options *options,
-		  const struct object_id *oid, enum object_type object_type,
-		  enum fsck_msg_id msg_id, const char *fmt, ...)
+/*
+ * Provide the common functionality for either fscking refs or objects.
+ * It will get the current msg error type and call the error_func callback
+ * which is registered in the "fsck_options" struct.
+ */
+static int fsck_vreport(struct fsck_options *options,
+			void *fsck_report,
+			enum fsck_msg_id msg_id, const char *fmt, va_list ap)
 {
-	va_list ap;
 	struct strbuf sb = STRBUF_INIT;
 	enum fsck_msg_type msg_type = fsck_msg_type(msg_id, options);
 	int result;
@@ -239,9 +242,6 @@ static int report(struct fsck_options *options,
 	if (msg_type == FSCK_IGNORE)
 		return 0;
 
-	if (object_on_skiplist(options, oid))
-		return 0;
-
 	if (msg_type == FSCK_FATAL)
 		msg_type = FSCK_ERROR;
 	else if (msg_type == FSCK_INFO)
@@ -250,16 +250,49 @@ static int report(struct fsck_options *options,
 	prepare_msg_ids();
 	strbuf_addf(&sb, "%s: ", msg_id_info[msg_id].camelcased);
 
-	va_start(ap, fmt);
 	strbuf_vaddf(&sb, fmt, ap);
-	result = options->error_func(options, oid, object_type,
+	result = options->error_func(options, fsck_report,
 				     msg_type, msg_id, sb.buf);
 	strbuf_release(&sb);
+
+	return result;
+}
+
+__attribute__((format (printf, 5, 6)))
+static int report(struct fsck_options *options,
+		  const struct object_id *oid, enum object_type object_type,
+		  enum fsck_msg_id msg_id, const char *fmt, ...)
+{
+	va_list ap;
+	struct fsck_object_report report = {
+		.oid = oid,
+		.object_type = object_type
+	};
+	int result;
+
+	if (object_on_skiplist(options, oid))
+		return 0;
+
+	va_start(ap, fmt);
+	result = fsck_vreport(options, &report, msg_id, fmt, ap);
 	va_end(ap);
 
 	return result;
 }
 
+int fsck_report_ref(struct fsck_options *options,
+		    struct fsck_ref_report *report,
+		    enum fsck_msg_id msg_id,
+		    const char *fmt, ...)
+{
+	va_list ap;
+	int result;
+	va_start(ap, fmt);
+	result = fsck_vreport(options, report, msg_id, fmt, ap);
+	va_end(ap);
+	return result;
+}
+
 void fsck_enable_object_names(struct fsck_options *options)
 {
 	if (!options->object_names)
@@ -1200,13 +1233,15 @@ int fsck_buffer(const struct object_id *oid, enum object_type type,
 		      type);
 }
 
-int fsck_error_function(struct fsck_options *o,
-			const struct object_id *oid,
-			enum object_type object_type UNUSED,
-			enum fsck_msg_type msg_type,
-			enum fsck_msg_id msg_id UNUSED,
-			const char *message)
+int fsck_objects_error_function(struct fsck_options *o,
+				void *fsck_report,
+				enum fsck_msg_type msg_type,
+				enum fsck_msg_id msg_id UNUSED,
+				const char *message)
 {
+	struct fsck_object_report *report = fsck_report;
+	const struct object_id *oid = report->oid;
+
 	if (msg_type == FSCK_WARN) {
 		warning("object %s: %s", fsck_describe_object(o, oid), message);
 		return 0;
@@ -1215,6 +1250,32 @@ int fsck_error_function(struct fsck_options *o,
 	return 1;
 }
 
+int fsck_refs_error_function(struct fsck_options *options UNUSED,
+			     void *fsck_report,
+			     enum fsck_msg_type msg_type,
+			     enum fsck_msg_id msg_id UNUSED,
+			     const char *message)
+{
+	struct fsck_ref_report *report = fsck_report;
+	struct strbuf sb = STRBUF_INIT;
+	int ret = 0;
+
+	strbuf_addstr(&sb, report->path);
+
+	if (report->oid)
+		strbuf_addf(&sb, " -> (%s)", oid_to_hex(report->oid));
+	else if (report->referent)
+		strbuf_addf(&sb, " -> (%s)", report->referent);
+
+	if (msg_type == FSCK_WARN)
+		warning("%s: %s", sb.buf, message);
+	else
+		ret = error("%s: %s", sb.buf, message);
+
+	strbuf_release(&sb);
+	return ret;
+}
+
 static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,
 		      enum fsck_msg_id msg_missing, enum fsck_msg_id msg_type,
 		      struct fsck_options *options, const char *blob_type)
@@ -1270,6 +1331,17 @@ int fsck_finish(struct fsck_options *options)
 	return ret;
 }
 
+void fsck_options_clear(struct fsck_options *options)
+{
+	free(options->msg_type);
+	oidset_clear(&options->skip_oids);
+	oidset_clear(&options->gitmodules_found);
+	oidset_clear(&options->gitmodules_done);
+	oidset_clear(&options->gitattributes_found);
+	oidset_clear(&options->gitattributes_done);
+	kh_clear_oid_map(options->object_names);
+}
+
 int git_fsck_config(const char *var, const char *value,
 		    const struct config_context *ctx, void *cb)
 {
@@ -1303,16 +1375,17 @@ int git_fsck_config(const char *var, const char *value,
  * Custom error callbacks that are used in more than one place.
  */
 
-int fsck_error_cb_print_missing_gitmodules(struct fsck_options *o,
-					   const struct object_id *oid,
-					   enum object_type object_type,
-					   enum fsck_msg_type msg_type,
-					   enum fsck_msg_id msg_id,
-					   const char *message)
+int fsck_objects_error_cb_print_missing_gitmodules(struct fsck_options *o,
+						   void *fsck_report,
+						   enum fsck_msg_type msg_type,
+						   enum fsck_msg_id msg_id,
+						   const char *message)
 {
 	if (msg_id == FSCK_MSG_GITMODULES_MISSING) {
-		puts(oid_to_hex(oid));
+		struct fsck_object_report *report = fsck_report;
+		puts(oid_to_hex(report->oid));
 		return 0;
 	}
-	return fsck_error_function(o, oid, object_type, msg_type, msg_id, message);
+	return fsck_objects_error_function(o, fsck_report,
+					   msg_type, msg_id, message);
 }
diff --git a/fsck.h b/fsck.h
index 6085a38..500b4c0 100644
--- a/fsck.h
+++ b/fsck.h
@@ -31,6 +31,8 @@ enum fsck_msg_type {
 	FUNC(BAD_NAME, ERROR) \
 	FUNC(BAD_OBJECT_SHA1, ERROR) \
 	FUNC(BAD_PARENT_SHA1, ERROR) \
+	FUNC(BAD_REF_FILETYPE, ERROR) \
+	FUNC(BAD_REF_NAME, ERROR) \
 	FUNC(BAD_TIMEZONE, ERROR) \
 	FUNC(BAD_TREE, ERROR) \
 	FUNC(BAD_TREE_SHA1, ERROR) \
@@ -114,29 +116,49 @@ int is_valid_msg_type(const char *msg_id, const char *msg_type);
 typedef int (*fsck_walk_func)(struct object *obj, enum object_type object_type,
 			      void *data, struct fsck_options *options);
 
-/* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */
+/*
+ * Callback for reporting errors either for objects or refs. The "fsck_report"
+ * is a generic pointer that can be used to pass any information.
+ */
 typedef int (*fsck_error)(struct fsck_options *o,
-			  const struct object_id *oid, enum object_type object_type,
+			  void *fsck_report,
 			  enum fsck_msg_type msg_type, enum fsck_msg_id msg_id,
 			  const char *message);
 
-int fsck_error_function(struct fsck_options *o,
-			const struct object_id *oid, enum object_type object_type,
-			enum fsck_msg_type msg_type, enum fsck_msg_id msg_id,
-			const char *message);
-int fsck_error_cb_print_missing_gitmodules(struct fsck_options *o,
-					   const struct object_id *oid,
-					   enum object_type object_type,
-					   enum fsck_msg_type msg_type,
-					   enum fsck_msg_id msg_id,
-					   const char *message);
+int fsck_objects_error_function(struct fsck_options *o,
+				void *fsck_report,
+				enum fsck_msg_type msg_type, enum fsck_msg_id msg_id,
+				const char *message);
+int fsck_objects_error_cb_print_missing_gitmodules(struct fsck_options *o,
+						   void *fsck_report,
+						   enum fsck_msg_type msg_type,
+						   enum fsck_msg_id msg_id,
+						   const char *message);
+
+int fsck_refs_error_function(struct fsck_options *options,
+			     void *fsck_report,
+			     enum fsck_msg_type msg_type,
+			     enum fsck_msg_id msg_id,
+			     const char *message);
+
+struct fsck_object_report {
+	const struct object_id *oid;
+	enum object_type object_type;
+};
+
+struct fsck_ref_report {
+	const char *path;
+	const struct object_id *oid;
+	const char *referent;
+};
 
 struct fsck_options {
 	fsck_walk_func walk;
 	fsck_error error_func;
-	unsigned strict:1;
+	unsigned strict;
+	unsigned verbose;
 	enum fsck_msg_type *msg_type;
-	struct oidset skiplist;
+	struct oidset skip_oids;
 	struct oidset gitmodules_found;
 	struct oidset gitmodules_done;
 	struct oidset gitattributes_found;
@@ -145,12 +167,12 @@ struct fsck_options {
 };
 
 #define FSCK_OPTIONS_DEFAULT { \
-	.skiplist = OIDSET_INIT, \
+	.skip_oids = OIDSET_INIT, \
 	.gitmodules_found = OIDSET_INIT, \
 	.gitmodules_done = OIDSET_INIT, \
 	.gitattributes_found = OIDSET_INIT, \
 	.gitattributes_done = OIDSET_INIT, \
-	.error_func = fsck_error_function \
+	.error_func = fsck_objects_error_function \
 }
 #define FSCK_OPTIONS_STRICT { \
 	.strict = 1, \
@@ -158,7 +180,7 @@ struct fsck_options {
 	.gitmodules_done = OIDSET_INIT, \
 	.gitattributes_found = OIDSET_INIT, \
 	.gitattributes_done = OIDSET_INIT, \
-	.error_func = fsck_error_function, \
+	.error_func = fsck_objects_error_function, \
 }
 #define FSCK_OPTIONS_MISSING_GITMODULES { \
 	.strict = 1, \
@@ -166,7 +188,10 @@ struct fsck_options {
 	.gitmodules_done = OIDSET_INIT, \
 	.gitattributes_found = OIDSET_INIT, \
 	.gitattributes_done = OIDSET_INIT, \
-	.error_func = fsck_error_cb_print_missing_gitmodules, \
+	.error_func = fsck_objects_error_cb_print_missing_gitmodules, \
+}
+#define FSCK_REFS_OPTIONS_DEFAULT { \
+	.error_func = fsck_refs_error_function, \
 }
 
 /* descend in all linked child objects
@@ -210,6 +235,21 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
 int fsck_finish(struct fsck_options *options);
 
 /*
+ * Clear the fsck_options struct, freeing any allocated memory.
+ */
+void fsck_options_clear(struct fsck_options *options);
+
+/*
+ * Report an error or warning for refs.
+ */
+__attribute__((format (printf, 4, 5)))
+int fsck_report_ref(struct fsck_options *options,
+		    struct fsck_ref_report *report,
+		    enum fsck_msg_id msg_id,
+		    const char *fmt, ...);
+
+
+/*
  * Subsystem for storing human-readable names for each object.
  *
  * If fsck_enable_object_names() has not been called, all other functions are
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index e818583..a6587a8 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -7,7 +7,7 @@
 #include "fsmonitor-path-utils.h"
 
 /*
- * We keep this structure defintion private and have getters
+ * We keep this structure definition private and have getters
  * for all fields so that we can lazy load it as needed.
  */
 struct fsmonitor_settings {
diff --git a/fsmonitor.c b/fsmonitor.c
index 2b17d60..237ca59 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "dir.h"
@@ -6,6 +8,7 @@
 #include "fsmonitor.h"
 #include "fsmonitor-ipc.h"
 #include "name-hash.h"
+#include "repository.h"
 #include "run-command.h"
 #include "strbuf.h"
 #include "trace2.h"
@@ -167,7 +170,7 @@ static int query_fsmonitor_hook(struct repository *r,
 	strvec_pushf(&cp.args, "%d", version);
 	strvec_pushf(&cp.args, "%s", last_update);
 	cp.use_shell = 1;
-	cp.dir = get_git_work_tree();
+	cp.dir = repo_get_work_tree(the_repository);
 
 	trace2_region_enter("fsm_hook", "query", NULL);
 
diff --git a/git-compat-util.h b/git-compat-util.h
index 71b4d23..e4a306d 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -195,6 +195,19 @@ struct strbuf;
 #define _NETBSD_SOURCE 1
 #define _SGI_SOURCE 1
 
+/*
+ * UNUSED marks a function parameter that is always unused.  It also
+ * can be used to annotate a function, a variable, or a type that is
+ * always unused.
+ *
+ * A callback interface may dictate that a function accepts a
+ * parameter at that position, but the implementation of the function
+ * may not need to use the parameter.  In such a case, mark the parameter
+ * with UNUSED.
+ *
+ * When a parameter may be used or unused, depending on conditional
+ * compilation, consider using MAYBE_UNUSED instead.
+ */
 #if GIT_GNUC_PREREQ(4, 5)
 #define UNUSED __attribute__((unused)) \
 	__attribute__((deprecated ("parameter declared as UNUSED")))
@@ -649,6 +662,17 @@ static inline int git_has_dir_sep(const char *path)
 #define RESULT_MUST_BE_USED
 #endif
 
+/*
+ * MAYBE_UNUSED marks a function parameter that may be unused, but
+ * whose use is not an error.  It also can be used to annotate a
+ * function, a variable, or a type that may be unused.
+ *
+ * Depending on a configuration, all uses of such a thing may become
+ * #ifdef'ed away.  Marking it with UNUSED would give a warning in a
+ * compilation where it is indeed used, and not marking it at all
+ * would give a warning in a compilation where it is unused.  In such
+ * a case, MAYBE_UNUSED is the appropriate annotation to use.
+ */
 #define MAYBE_UNUSED __attribute__((__unused__))
 
 #include "compat/bswap.h"
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 994431c..8dbe21d 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -612,7 +612,7 @@
 	ln -sf "$root/static" "$fqgitdir/gitweb/$httpd_only/"
 
 	# generate a standalone 'python http.server' script in $fqgitdir/gitweb
-	# This asumes that python is in user's $PATH
+	# This assumes that python is in user's $PATH
 	# This script is Python 2 and 3 compatible
 	cat > "$fqgitdir/gitweb/gitweb.py" <<EOF
 #!/usr/bin/env python
diff --git a/git-p4.py b/git-p4.py
index f1ab31d..c0ca7be 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -54,7 +54,7 @@
 import zipfile
 import zlib
 
-# On python2.7 where raw_input() and input() are both availble,
+# On python2.7 where raw_input() and input() are both available,
 # we want raw_input's semantics, but aliased to input for python3
 # compatibility
 # support basestring in python3
@@ -1804,7 +1804,7 @@ def __init__(self):
     status from the script will abort the process.
 
     The purpose of the hook is to edit the message file in place, and it is not
-    supressed by the `--no-verify` option. This hook is called even if
+    suppressed by the `--no-verify` option. This hook is called even if
     `--prepare-p4-only` is set.
 
     The `p4-changelist` hook is executed after the changelist message has been
diff --git a/git-send-email.perl b/git-send-email.perl
index 72044e5..c835d4c 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -31,6 +31,7 @@
 git send-email [<options>] <file|directory>
 git send-email [<options>] <format-patch options>
 git send-email --dump-aliases
+git send-email --translate-aliases
 
   Composing:
     --from                  <str>  * Email From:
@@ -46,6 +47,8 @@
     --compose-encoding      <str>  * Encoding to assume for introduction.
     --8bit-encoding         <str>  * Encoding to assume 8bit mails if undeclared
     --transfer-encoding     <str>  * Transfer encoding to use (quoted-printable, 8bit, base64)
+    --[no-]mailmap                 * Use mailmap file to map all email addresses to canonical
+                                     real names and email addresses.
 
   Sending:
     --envelope-sender       <str>  * Email envelope sender.
@@ -99,6 +102,10 @@
 
   Information:
     --dump-aliases                 * Dump configured aliases and exit.
+    --translate-aliases            * Translate aliases read from standard
+                                     input according to the configured email
+                                     alias file(s), outputting the result to
+                                     standard output.
 
 EOT
 	exit(1);
@@ -212,6 +219,7 @@
 my $compose_filename;
 my $force = 0;
 my $dump_aliases = 0;
+my $translate_aliases = 0;
 
 # Variables to prevent short format-patch options from being captured
 # as abbreviated send-email options
@@ -272,12 +280,14 @@
 my ($auto_8bit_encoding);
 my ($compose_encoding);
 my ($sendmail_cmd);
+my ($mailmap_file, $mailmap_blob);
 # Variables with corresponding config settings & hardcoded defaults
 my ($debug_net_smtp) = 0;		# Net::SMTP, see send_message()
 my $thread = 1;
 my $chain_reply_to = 0;
 my $use_xmailer = 1;
 my $validate = 1;
+my $mailmap = 0;
 my $target_xfer_encoding = 'auto';
 my $forbid_sendmail_variables = 1;
 
@@ -294,6 +304,7 @@
     "annotate" => \$annotate,
     "xmailer" => \$use_xmailer,
     "forbidsendmailvariables" => \$forbid_sendmail_variables,
+    "mailmap" => \$mailmap,
 );
 
 my %config_settings = (
@@ -327,6 +338,8 @@
 my %config_path_settings = (
     "aliasesfile" => \@alias_files,
     "smtpsslcertpath" => \$smtp_ssl_cert_path,
+    "mailmap.file" => \$mailmap_file,
+    "mailmap.blob" => \$mailmap_blob,
 );
 
 # Handle Uncouth Termination
@@ -476,11 +489,14 @@
 my %dump_aliases_options = (
 	"h" => \$help,
 	"dump-aliases" => \$dump_aliases,
+	"translate-aliases" => \$translate_aliases,
 );
 $rc = GetOptions(%dump_aliases_options);
 usage() unless $rc;
 die __("--dump-aliases incompatible with other options\n")
-    if !$help and $dump_aliases and @ARGV;
+    if !$help and ($dump_aliases or $translate_aliases) and @ARGV;
+die __("--dump-aliases and --translate-aliases are mutually exclusive\n")
+    if !$help and $dump_aliases and $translate_aliases;
 my %options = (
 		    "sender|from=s" => \$sender,
 		    "in-reply-to=s" => \$initial_in_reply_to,
@@ -524,6 +540,8 @@
 		    "thread!" => \$thread,
 		    "validate!" => \$validate,
 		    "transfer-encoding=s" => \$target_xfer_encoding,
+		    "mailmap!" => \$mailmap,
+		    "use-mailmap!" => \$mailmap,
 		    "format-patch!" => \$format_patch,
 		    "8bit-encoding=s" => \$auto_8bit_encoding,
 		    "compose-encoding=s" => \$compose_encoding,
@@ -724,6 +742,16 @@
     exit(0);
 }
 
+if ($translate_aliases) {
+	while (<STDIN>) {
+		my @addr_list = parse_address_line($_);
+		@addr_list = expand_aliases(@addr_list);
+		@addr_list = sanitize_address_list(@addr_list);
+		print "$_\n" for @addr_list;
+	}
+	exit(0);
+}
+
 # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
 # $f is a revision list specification to be passed to format-patch.
 sub is_format_patch_arg {
@@ -1085,6 +1113,16 @@
 our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
 	$needs_confirm, $message_num, $ask_default);
 
+sub mailmap_address_list {
+	return @_ unless @_ and $mailmap;
+	my @options = ();
+	push(@options, "--mailmap-file=$mailmap_file") if $mailmap_file;
+	push(@options, "--mailmap-blob=$mailmap_blob") if $mailmap_blob;
+	my @addr_list = Git::command('check-mailmap', @options, @_);
+	s/^<(.*)>$/$1/ for @addr_list;
+	return @addr_list;
+}
+
 sub extract_valid_address {
 	my $address = shift;
 	my $local_part_regexp = qr/[^<>"\s@]+/;
@@ -1294,6 +1332,7 @@
 	@addr_list = expand_aliases(@addr_list);
 	@addr_list = sanitize_address_list(@addr_list);
 	@addr_list = validate_address_list(@addr_list);
+	@addr_list = mailmap_address_list(@addr_list);
 	return @addr_list;
 }
 
diff --git a/git-submodule.sh b/git-submodule.sh
index 7f9582d..03c5a22 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -94,6 +94,14 @@
 		--reference=*)
 			reference_path="${1#--reference=}"
 			;;
+		--ref-format)
+			case "$2" in '') usage ;; esac
+			ref_format="--ref-format=$2"
+			shift
+			;;
+		--ref-format=*)
+			ref_format="$1"
+			;;
 		--dissociate)
 			dissociate=1
 			;;
@@ -129,7 +137,18 @@
 		usage
 	fi
 
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add ${quiet:+--quiet} ${force:+--force} ${progress:+"--progress"} ${branch:+--branch "$branch"} ${reference_path:+--reference "$reference_path"} ${dissociate:+--dissociate} ${custom_name:+--name "$custom_name"} ${depth:+"$depth"} -- "$@"
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add \
+		${quiet:+--quiet} \
+		${force:+--force} \
+		${progress:+"--progress"} \
+		${branch:+--branch "$branch"} \
+		${reference_path:+--reference "$reference_path"} \
+		${ref_format:+"$ref_format"} \
+		${dissociate:+--dissociate} \
+		${custom_name:+--name "$custom_name"} \
+		${depth:+"$depth"} \
+		-- \
+		"$@"
 }
 
 #
@@ -160,7 +179,11 @@
 		shift
 	done
 
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach ${quiet:+--quiet} ${recursive:+--recursive} -- "$@"
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach \
+		${quiet:+--quiet} \
+		${recursive:+--recursive} \
+		-- \
+		"$@"
 }
 
 #
@@ -191,7 +214,10 @@
 		shift
 	done
 
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init ${quiet:+--quiet} -- "$@"
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init \
+		${quiet:+--quiet} \
+		-- \
+		"$@"
 }
 
 #
@@ -227,7 +253,12 @@
 		shift
 	done
 
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${quiet:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@"
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \
+		${quiet:+--quiet} \
+		${force:+--force} \
+		${deinit_all:+--all} \
+		-- \
+		"$@"
 }
 
 #
@@ -268,6 +299,14 @@
 		-r|--rebase)
 			rebase=1
 			;;
+		--ref-format)
+			case "$2" in '') usage ;; esac
+			ref_format="--ref-format=$2"
+			shift
+			;;
+		--ref-format=*)
+			ref_format="$1"
+			;;
 		--reference)
 			case "$2" in '') usage ;; esac
 			reference="--reference=$2"
@@ -349,6 +388,7 @@
 		${rebase:+--rebase} \
 		${merge:+--merge} \
 		${checkout:+--checkout} \
+		${ref_format:+"$ref_format"} \
 		${reference:+"$reference"} \
 		${dissociate:+"--dissociate"} \
 		${depth:+"$depth"} \
@@ -399,7 +439,12 @@
 		shift
 	done
 
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch ${quiet:+--quiet} ${branch:+--branch "$branch"} ${default:+--default} -- "$@"
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch \
+		${quiet:+--quiet} \
+		${branch:+--branch "$branch"} \
+		${default:+--default} \
+		-- \
+		"$@"
 }
 
 #
@@ -428,7 +473,10 @@
 		shift
 	done
 
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url ${quiet:+--quiet} -- "$@"
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url \
+		${quiet:+--quiet} \
+		-- \
+		"$@"
 }
 
 #
@@ -480,7 +528,13 @@
 		shift
 	done
 
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary ${files:+--files} ${cached:+--cached} ${for_status:+--for-status} ${summary_limit:+-n $summary_limit} -- "$@"
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary \
+		${files:+--files} \
+		${cached:+--cached} \
+		${for_status:+--for-status} \
+		${summary_limit:+-n $summary_limit} \
+		-- \
+		"$@"
 }
 #
 # List all submodules, prefixed with:
@@ -521,8 +575,14 @@
 		shift
 	done
 
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status ${quiet:+--quiet} ${cached:+--cached} ${recursive:+--recursive} -- "$@"
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status \
+		${quiet:+--quiet} \
+		${cached:+--cached} \
+		${recursive:+--recursive} \
+		-- \
+		"$@"
 }
+
 #
 # Sync remote urls for submodules
 # This makes the value for remote.$remote.url match the value
@@ -554,7 +614,11 @@
 		esac
 	done
 
-	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync ${quiet:+--quiet} ${recursive:+--recursive} -- "$@"
+	git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync \
+		${quiet:+--quiet} \
+		${recursive:+--recursive} \
+		-- \
+		"$@"
 }
 
 cmd_absorbgitdirs()
diff --git a/git-svn.perl b/git-svn.perl
index b0d0a50..01e7a70 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -219,11 +219,11 @@
 	                "Set an SVN repository to a git tree-ish",
 			{ 'stdin' => \$_stdin, %cmt_opts, %fc_opts, } ],
 	'create-ignore' => [ \&cmd_create_ignore,
-			     'Create a .gitignore per svn:ignore',
+			     "Create a .gitignore per directory with SVN ignore properties",
 			     { 'revision|r=i' => \$_revision
 			     } ],
 	'mkdirs' => [ \&cmd_mkdirs ,
-	              "recreate empty directories after a checkout",
+	              "Recreate empty directories after a checkout",
 	              { 'revision|r=i' => \$_revision } ],
         'propget' => [ \&cmd_propget,
 		       'Print the value of a property on a file or directory',
@@ -234,7 +234,7 @@
         'proplist' => [ \&cmd_proplist,
 		       'List all properties of a file or directory',
 		       { 'revision|r=i' => \$_revision } ],
-	'show-ignore' => [ \&cmd_show_ignore, "Show svn:ignore listings",
+	'show-ignore' => [ \&cmd_show_ignore, "Show .gitignore patterns from SVN ignore properties",
 			{ 'revision|r=i' => \$_revision
 			} ],
 	'show-externals' => [ \&cmd_show_externals, "Show svn:externals listings",
@@ -1279,12 +1279,20 @@
 	$gs->prop_walk($gs->path, $r, sub {
 		my ($gs, $path, $props) = @_;
 		print STDOUT "\n# $path\n";
-		my $s = $props->{'svn:ignore'} or return;
-		$s =~ s/[\r\n]+/\n/g;
-		$s =~ s/^\n+//;
-		chomp $s;
-		$s =~ s#^#$path#gm;
-		print STDOUT "$s\n";
+		if (my $s = $props->{'svn:ignore'}) {
+			$s =~ s/[\r\n]+/\n/g;
+			$s =~ s/^\n+//;
+			chomp $s;
+			$s =~ s#^#$path#gm;
+			print STDOUT "$s\n";
+		}
+		if (my $s = $props->{'svn:global-ignores'}) {
+			$s =~ s/[\r\n]+/\n/g;
+			$s =~ s/^\n+//;
+			chomp $s;
+			$s =~ s#^#$path**/#gm;
+			print STDOUT "$s\n";
+		}
 	});
 }
 
@@ -1315,16 +1323,25 @@
 		# which git won't track
 		mkpath([$path]) unless -d $path;
 		my $ignore = $path . '.gitignore';
-		my $s = $props->{'svn:ignore'} or return;
 		open(GITIGNORE, '>', $ignore)
 		  or fatal("Failed to open `$ignore' for writing: $!");
-		$s =~ s/[\r\n]+/\n/g;
-		$s =~ s/^\n+//;
-		chomp $s;
-		# Prefix all patterns so that the ignore doesn't apply
-		# to sub-directories.
-		$s =~ s#^#/#gm;
-		print GITIGNORE "$s\n";
+		if (my $s = $props->{'svn:ignore'}) {
+			$s =~ s/[\r\n]+/\n/g;
+			$s =~ s/^\n+//;
+			chomp $s;
+			# Prefix all patterns so that the ignore doesn't apply
+			# to sub-directories.
+			$s =~ s#^#/#gm;
+			print GITIGNORE "$s\n";
+		}
+		if (my $s = $props->{'svn:global-ignores'}) {
+			$s =~ s/[\r\n]+/\n/g;
+			$s =~ s/^\n+//;
+			chomp $s;
+			# Global ignores apply to sub-directories, so they are
+			# not prefixed.
+			print GITIGNORE "$s\n";
+		}
 		close(GITIGNORE)
 		  or fatal("Failed to close `$ignore': $!");
 		command_noisy('add', '-f', $ignore);
diff --git a/git.c b/git.c
index e35af9b..2a9752c 100644
--- a/git.c
+++ b/git.c
@@ -31,7 +31,7 @@
 
 struct cmd_struct {
 	const char *cmd;
-	int (*fn)(int, const char **, const char *);
+	int (*fn)(int, const char **, const char *, struct repository *);
 	unsigned int option;
 };
 
@@ -143,6 +143,13 @@ void setup_auto_pager(const char *cmd, int def)
 	commit_pager_choice();
 }
 
+static void print_system_path(const char *path)
+{
+	char *s_path = system_path(path);
+	puts(s_path);
+	free(s_path);
+}
+
 static int handle_options(const char ***argv, int *argc, int *envchanged)
 {
 	const char **orig_argv = *argv;
@@ -173,15 +180,15 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 				exit(0);
 			}
 		} else if (!strcmp(cmd, "--html-path")) {
-			puts(system_path(GIT_HTML_PATH));
+			print_system_path(GIT_HTML_PATH);
 			trace2_cmd_name("_query_");
 			exit(0);
 		} else if (!strcmp(cmd, "--man-path")) {
-			puts(system_path(GIT_MAN_PATH));
+			print_system_path(GIT_MAN_PATH);
 			trace2_cmd_name("_query_");
 			exit(0);
 		} else if (!strcmp(cmd, "--info-path")) {
-			puts(system_path(GIT_INFO_PATH));
+			print_system_path(GIT_INFO_PATH);
 			trace2_cmd_name("_query_");
 			exit(0);
 		} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
@@ -434,7 +441,7 @@ static int handle_alias(int *argcp, const char ***argv)
 	return ret;
 }
 
-static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
+static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct repository *repo)
 {
 	int status, help;
 	struct stat st;
@@ -472,9 +479,9 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 	trace_argv_printf(argv, "trace: built-in: git");
 	trace2_cmd_name(p->cmd);
 
-	validate_cache_entries(the_repository->index);
-	status = p->fn(argc, argv, prefix);
-	validate_cache_entries(the_repository->index);
+	validate_cache_entries(repo->index);
+	status = p->fn(argc, argv, prefix, (p->option & RUN_SETUP)? repo : NULL);
+	validate_cache_entries(repo->index);
 
 	if (status)
 		return status;
@@ -704,6 +711,7 @@ static void strip_extension(const char **argv)
 static void handle_builtin(int argc, const char **argv)
 {
 	struct strvec args = STRVEC_INIT;
+	const char **argv_copy = NULL;
 	const char *cmd;
 	struct cmd_struct *builtin;
 
@@ -724,13 +732,28 @@ static void handle_builtin(int argc, const char **argv)
 		}
 
 		argc++;
-		argv = args.v;
+
+		/*
+		 * `run_builtin()` will modify the argv array, so we need to
+		 * create a shallow copy such that we can free all of its
+		 * strings.
+		 */
+		CALLOC_ARRAY(argv_copy, argc + 1);
+		COPY_ARRAY(argv_copy, args.v, argc);
+
+		argv = argv_copy;
 	}
 
 	builtin = get_builtin(cmd);
-	if (builtin)
-		exit(run_builtin(builtin, argc, argv));
+	if (builtin) {
+		int ret = run_builtin(builtin, argc, argv, the_repository);
+		strvec_clear(&args);
+		free(argv_copy);
+		exit(ret);
+	}
+
 	strvec_clear(&args);
+	free(argv_copy);
 }
 
 static void execv_dashed_external(const char **argv)
diff --git a/gpg-interface.c b/gpg-interface.c
index 5c824ae..0733598 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "commit.h"
 #include "config.h"
@@ -43,8 +45,8 @@ struct gpg_format {
 				    size_t signature_size);
 	int (*sign_buffer)(struct strbuf *buffer, struct strbuf *signature,
 			   const char *signing_key);
-	const char *(*get_default_key)(void);
-	const char *(*get_key_id)(void);
+	char *(*get_default_key)(void);
+	char *(*get_key_id)(void);
 };
 
 static const char *openpgp_verify_args[] = {
@@ -84,9 +86,9 @@ static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
 static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
 			   const char *signing_key);
 
-static const char *get_default_ssh_signing_key(void);
+static char *get_default_ssh_signing_key(void);
 
-static const char *get_ssh_key_id(void);
+static char *get_ssh_key_id(void);
 
 static struct gpg_format gpg_format[] = {
 	{
@@ -398,7 +400,7 @@ static void parse_ssh_output(struct signature_check *sigc)
 	 * Note that "PRINCIPAL" can contain whitespace, "RSA" and
 	 * "SHA256" part could be a different token that names of
 	 * the algorithms used, and "FINGERPRINT" is a hexadecimal
-	 * string.  By finding the last occurence of " with ", we can
+	 * string.  By finding the last occurrence of " with ", we can
 	 * reliably parse out the PRINCIPAL.
 	 */
 	sigc->result = 'B';
@@ -845,7 +847,7 @@ static char *get_ssh_key_fingerprint(const char *signing_key)
 }
 
 /* Returns the first public key from an ssh-agent to use for signing */
-static const char *get_default_ssh_signing_key(void)
+static char *get_default_ssh_signing_key(void)
 {
 	struct child_process ssh_default_key = CHILD_PROCESS_INIT;
 	int ret = -1;
@@ -897,12 +899,16 @@ static const char *get_default_ssh_signing_key(void)
 	return default_key;
 }
 
-static const char *get_ssh_key_id(void) {
-	return get_ssh_key_fingerprint(get_signing_key());
+static char *get_ssh_key_id(void)
+{
+	char *signing_key = get_signing_key();
+	char *key_id = get_ssh_key_fingerprint(signing_key);
+	free(signing_key);
+	return key_id;
 }
 
 /* Returns a textual but unique representation of the signing key */
-const char *get_signing_key_id(void)
+char *get_signing_key_id(void)
 {
 	gpg_interface_lazy_init();
 
@@ -914,17 +920,17 @@ const char *get_signing_key_id(void)
 	return get_signing_key();
 }
 
-const char *get_signing_key(void)
+char *get_signing_key(void)
 {
 	gpg_interface_lazy_init();
 
 	if (configured_signing_key)
-		return configured_signing_key;
+		return xstrdup(configured_signing_key);
 	if (use_format->get_default_key) {
 		return use_format->get_default_key();
 	}
 
-	return git_committer_info(IDENT_STRICT | IDENT_NO_DATE);
+	return xstrdup(git_committer_info(IDENT_STRICT | IDENT_NO_DATE));
 }
 
 const char *gpg_trust_level_to_str(enum signature_trust_level level)
diff --git a/gpg-interface.h b/gpg-interface.h
index 7cd9816..e09f12e 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -80,13 +80,13 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
 const char *gpg_trust_level_to_str(enum signature_trust_level level);
 
 void set_signing_key(const char *);
-const char *get_signing_key(void);
+char *get_signing_key(void);
 
 /*
  * Returns a textual unique representation of the signing key in use
  * Either a GPG KeyID or a SSH Key Fingerprint
  */
-const char *get_signing_key_id(void);
+char *get_signing_key_id(void);
 int check_signature(struct signature_check *sigc,
 		    const char *signature, size_t slen);
 void print_signature_buffer(const struct signature_check *sigc,
diff --git a/graph.c b/graph.c
index 1ca3477..bf000fd 100644
--- a/graph.c
+++ b/graph.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "gettext.h"
 #include "config.h"
@@ -74,10 +76,7 @@ static void graph_show_line_prefix(const struct diff_options *diffopt)
 	if (!diffopt || !diffopt->line_prefix)
 		return;
 
-	fwrite(diffopt->line_prefix,
-	       sizeof(char),
-	       diffopt->line_prefix_length,
-	       diffopt->file);
+	fputs(diffopt->line_prefix, diffopt->file);
 }
 
 static const char **column_colors;
@@ -310,22 +309,28 @@ struct git_graph {
 	 * stored as an index into the array column_colors.
 	 */
 	unsigned short default_column_color;
+
+	/*
+	 * Scratch buffer for generating prefixes to be used with
+	 * diff_output_prefix_callback().
+	 */
+	struct strbuf prefix_buf;
 };
 
-static struct strbuf *diff_output_prefix_callback(struct diff_options *opt, void *data)
+static const char *diff_output_prefix_callback(struct diff_options *opt, void *data)
 {
 	struct git_graph *graph = data;
-	static struct strbuf msgbuf = STRBUF_INIT;
 
 	assert(opt);
 
-	strbuf_reset(&msgbuf);
+	if (!graph)
+		return opt->line_prefix;
+
+	strbuf_reset(&graph->prefix_buf);
 	if (opt->line_prefix)
-		strbuf_add(&msgbuf, opt->line_prefix,
-			   opt->line_prefix_length);
-	if (graph)
-		graph_padding_line(graph, &msgbuf);
-	return &msgbuf;
+		strbuf_addstr(&graph->prefix_buf, opt->line_prefix);
+	graph_padding_line(graph, &graph->prefix_buf);
+	return graph->prefix_buf.buf;
 }
 
 static const struct diff_options *default_diffopt;
@@ -395,6 +400,7 @@ struct git_graph *graph_init(struct rev_info *opt)
 	 * The diff output prefix callback, with this we can make
 	 * all the diff output to align with the graph lines.
 	 */
+	strbuf_init(&graph->prefix_buf, 0);
 	opt->diffopt.output_prefix = diff_output_prefix_callback;
 	opt->diffopt.output_prefix_data = graph;
 
@@ -410,6 +416,7 @@ void graph_clear(struct git_graph *graph)
 	free(graph->new_columns);
 	free(graph->mapping);
 	free(graph->old_mapping);
+	strbuf_release(&graph->prefix_buf);
 	free(graph);
 }
 
diff --git a/grep.c b/grep.c
index ac34bfe..701e58d 100644
--- a/grep.c
+++ b/grep.c
@@ -245,7 +245,7 @@ static int is_fixed(const char *s, size_t len)
 #ifdef USE_LIBPCRE2
 #define GREP_PCRE2_DEBUG_MALLOC 0
 
-static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
+static void *pcre2_malloc(PCRE2_SIZE size, void *memory_data UNUSED)
 {
 	void *pointer = malloc(size);
 #if GREP_PCRE2_DEBUG_MALLOC
@@ -255,7 +255,7 @@ static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
 	return pointer;
 }
 
-static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
+static void pcre2_free(void *pointer, void *memory_data UNUSED)
 {
 #if GREP_PCRE2_DEBUG_MALLOC
 	static int count = 1;
@@ -843,11 +843,11 @@ static void free_grep_pat(struct grep_pat *pattern)
 				free_pcre2_pattern(p);
 			else
 				regfree(&p->regexp);
-			free(p->pattern);
 			break;
 		default:
 			break;
 		}
+		free(p->pattern);
 		free(p);
 	}
 }
@@ -1735,7 +1735,8 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
 				peek_eol = end_of_line(peek_bol, &peek_left);
 			}
 
-			if (match_funcname(opt, gs, peek_bol, peek_eol))
+			if (peek_bol >= gs->buf + gs->size ||
+			    match_funcname(opt, gs, peek_bol, peek_eol))
 				show_function = 0;
 		}
 		if (show_function ||
diff --git a/hash.h b/hash.h
index 72ffbc8..756166c 100644
--- a/hash.h
+++ b/hash.h
@@ -15,6 +15,36 @@
 #include "block-sha1/sha1.h"
 #endif
 
+#if defined(SHA1_APPLE_UNSAFE)
+#  include <CommonCrypto/CommonDigest.h>
+#  define platform_SHA_CTX_unsafe CC_SHA1_CTX
+#  define platform_SHA1_Init_unsafe CC_SHA1_Init
+#  define platform_SHA1_Update_unsafe CC_SHA1_Update
+#  define platform_SHA1_Final_unsafe CC_SHA1_Final
+#elif defined(SHA1_OPENSSL_UNSAFE)
+#  include <openssl/sha.h>
+#  if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3
+#    define SHA1_NEEDS_CLONE_HELPER_UNSAFE
+#    include "sha1/openssl.h"
+#    define platform_SHA_CTX_unsafe openssl_SHA1_CTX
+#    define platform_SHA1_Init_unsafe openssl_SHA1_Init
+#    define platform_SHA1_Clone_unsafe openssl_SHA1_Clone
+#    define platform_SHA1_Update_unsafe openssl_SHA1_Update
+#    define platform_SHA1_Final_unsafe openssl_SHA1_Final
+#  else
+#    define platform_SHA_CTX_unsafe SHA_CTX
+#    define platform_SHA1_Init_unsafe SHA1_Init
+#    define platform_SHA1_Update_unsafe SHA1_Update
+#    define platform_SHA1_Final_unsafe SHA1_Final
+#  endif
+#elif defined(SHA1_BLK_UNSAFE)
+#  include "block-sha1/sha1.h"
+#  define platform_SHA_CTX_unsafe blk_SHA_CTX
+#  define platform_SHA1_Init_unsafe blk_SHA1_Init
+#  define platform_SHA1_Update_unsafe blk_SHA1_Update
+#  define platform_SHA1_Final_unsafe blk_SHA1_Final
+#endif
+
 #if defined(SHA256_NETTLE)
 #include "sha256/nettle.h"
 #elif defined(SHA256_GCRYPT)
@@ -44,14 +74,35 @@
 #define platform_SHA1_Final    	SHA1_Final
 #endif
 
+#ifndef platform_SHA_CTX_unsafe
+#  define platform_SHA_CTX_unsafe      platform_SHA_CTX
+#  define platform_SHA1_Init_unsafe    platform_SHA1_Init
+#  define platform_SHA1_Update_unsafe  platform_SHA1_Update
+#  define platform_SHA1_Final_unsafe   platform_SHA1_Final
+#  ifdef platform_SHA1_Clone
+#    define platform_SHA1_Clone_unsafe platform_SHA1_Clone
+#  endif
+#  ifdef SHA1_NEEDS_CLONE_HELPER
+#    define SHA1_NEEDS_CLONE_HELPER_UNSAFE
+#  endif
+#endif
+
 #define git_SHA_CTX		platform_SHA_CTX
 #define git_SHA1_Init		platform_SHA1_Init
 #define git_SHA1_Update		platform_SHA1_Update
 #define git_SHA1_Final		platform_SHA1_Final
 
+#define git_SHA_CTX_unsafe	platform_SHA_CTX_unsafe
+#define git_SHA1_Init_unsafe	platform_SHA1_Init_unsafe
+#define git_SHA1_Update_unsafe	platform_SHA1_Update_unsafe
+#define git_SHA1_Final_unsafe	platform_SHA1_Final_unsafe
+
 #ifdef platform_SHA1_Clone
 #define git_SHA1_Clone	platform_SHA1_Clone
 #endif
+#ifdef platform_SHA1_Clone_unsafe
+#  define git_SHA1_Clone_unsafe platform_SHA1_Clone_unsafe
+#endif
 
 #ifndef platform_SHA256_CTX
 #define platform_SHA256_CTX	SHA256_CTX
@@ -81,6 +132,13 @@ static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
 	memcpy(dst, src, sizeof(*dst));
 }
 #endif
+#ifndef SHA1_NEEDS_CLONE_HELPER_UNSAFE
+static inline void git_SHA1_Clone_unsafe(git_SHA_CTX_unsafe *dst,
+				       const git_SHA_CTX_unsafe *src)
+{
+	memcpy(dst, src, sizeof(*dst));
+}
+#endif
 
 #ifndef SHA256_NEEDS_CLONE_HELPER
 static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
@@ -178,6 +236,8 @@ enum get_oid_result {
 /* 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;
 };
 typedef union git_hash_ctx git_hash_ctx;
@@ -222,6 +282,21 @@ 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;
 
diff --git a/help.c b/help.c
index a6b4d3b..4ad4ebd 100644
--- a/help.c
+++ b/help.c
@@ -16,6 +16,7 @@
 #include "parse-options.h"
 #include "prompt.h"
 #include "fsmonitor-ipc.h"
+#include "repository.h"
 
 #ifndef NO_CURL
 #include "git-curl-compat.h" /* For LIBCURL_VERSION only */
@@ -618,7 +619,7 @@ const char *help_unknown_cmd(const char *cmd)
 	memset(&other_cmds, 0, sizeof(other_cmds));
 	memset(&aliases, 0, sizeof(aliases));
 
-	read_early_config(git_unknown_cmd_config, NULL);
+	read_early_config(the_repository, git_unknown_cmd_config, NULL);
 
 	/*
 	 * Disable autocorrection prompt in a non-interactive session
@@ -775,7 +776,7 @@ void get_version_info(struct strbuf *buf, int show_build_options)
 	}
 }
 
-int cmd_version(int argc, const char **argv, const char *prefix)
+int cmd_version(int argc, const char **argv, const char *prefix, struct repository *repository UNUSED)
 {
 	struct strbuf buf = STRBUF_INIT;
 	int build_options = 0;
@@ -804,7 +805,7 @@ struct similar_ref_cb {
 	struct string_list *similar_refs;
 };
 
-static int append_similar_ref(const char *refname,
+static int append_similar_ref(const char *refname, const char *referent UNUSED,
 			      const struct object_id *oid UNUSED,
 			      int flags UNUSED, void *cb_data)
 {
diff --git a/hook.c b/hook.c
index 7e90787..a9320cb 100644
--- a/hook.c
+++ b/hook.c
@@ -10,14 +10,14 @@
 #include "environment.h"
 #include "setup.h"
 
-const char *find_hook(const char *name)
+const char *find_hook(struct repository *r, const char *name)
 {
 	static struct strbuf path = STRBUF_INIT;
 
 	int found_hook;
 
 	strbuf_reset(&path);
-	strbuf_git_path(&path, "hooks/%s", name);
+	strbuf_repo_git_path(&path, r, "hooks/%s", name);
 	found_hook = access(path.buf, X_OK) >= 0;
 #ifdef STRIP_EXTENSION
 	if (!found_hook) {
@@ -48,9 +48,9 @@ const char *find_hook(const char *name)
 	return path.buf;
 }
 
-int hook_exists(const char *name)
+int hook_exists(struct repository *r, const char *name)
 {
-	return !!find_hook(name);
+	return !!find_hook(r, name);
 }
 
 static int pick_next_hook(struct child_process *cp,
@@ -121,7 +121,8 @@ static void run_hooks_opt_clear(struct run_hooks_opt *options)
 	strvec_clear(&options->args);
 }
 
-int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
+int run_hooks_opt(struct repository *r, const char *hook_name,
+		  struct run_hooks_opt *options)
 {
 	struct strbuf abs_path = STRBUF_INIT;
 	struct hook_cb_data cb_data = {
@@ -129,7 +130,7 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
 		.hook_name = hook_name,
 		.options = options,
 	};
-	const char *const hook_path = find_hook(hook_name);
+	const char *const hook_path = find_hook(r, hook_name);
 	int ret = 0;
 	const struct run_process_parallel_opts opts = {
 		.tr2_category = "hook",
@@ -173,14 +174,14 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
 	return ret;
 }
 
-int run_hooks(const char *hook_name)
+int run_hooks(struct repository *r, const char *hook_name)
 {
 	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
 
-	return run_hooks_opt(hook_name, &opt);
+	return run_hooks_opt(r, hook_name, &opt);
 }
 
-int run_hooks_l(const char *hook_name, ...)
+int run_hooks_l(struct repository *r, const char *hook_name, ...)
 {
 	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
 	va_list ap;
@@ -191,5 +192,5 @@ int run_hooks_l(const char *hook_name, ...)
 		strvec_push(&opt.args, arg);
 	va_end(ap);
 
-	return run_hooks_opt(hook_name, &opt);
+	return run_hooks_opt(r, hook_name, &opt);
 }
diff --git a/hook.h b/hook.h
index 6511525..11863fa 100644
--- a/hook.h
+++ b/hook.h
@@ -2,6 +2,8 @@
 #define HOOK_H
 #include "strvec.h"
 
+struct repository;
+
 struct run_hooks_opt
 {
 	/* Environment vars to be set for each hook */
@@ -55,12 +57,12 @@ struct hook_cb_data {
  * or disabled. Note that this points to static storage that will be
  * overwritten by further calls to find_hook and run_hook_*.
  */
-const char *find_hook(const char *name);
+const char *find_hook(struct repository *r, const char *name);
 
 /**
  * A boolean version of find_hook()
  */
-int hook_exists(const char *hookname);
+int hook_exists(struct repository *r, const char *hookname);
 
 /**
  * Takes a `hook_name`, resolves it to a path with find_hook(), and
@@ -70,13 +72,14 @@ int hook_exists(const char *hookname);
  * Returns the status code of the run hook, or a negative value on
  * error().
  */
-int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
+int run_hooks_opt(struct repository *r, const char *hook_name,
+		  struct run_hooks_opt *options);
 
 /**
  * A wrapper for run_hooks_opt() which provides a dummy "struct
  * run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
  */
-int run_hooks(const char *hook_name);
+int run_hooks(struct repository *r, const char *hook_name);
 
 /**
  * Like run_hooks(), a wrapper for run_hooks_opt().
@@ -87,5 +90,5 @@ int run_hooks(const char *hook_name);
  * hook. This function behaves like the old run_hook_le() API.
  */
 LAST_ARG_MUST_BE_NULL
-int run_hooks_l(const char *hook_name, ...);
+int run_hooks_l(struct repository *r, const char *hook_name, ...);
 #endif
diff --git a/http-backend.c b/http-backend.c
index 4614249..73eec4e 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -512,7 +512,7 @@ static void run_service(const char **argv, int buffer_input)
 		exit(1);
 }
 
-static int show_text_ref(const char *name, const struct object_id *oid,
+static int show_text_ref(const char *name, const char *referent UNUSED, const struct object_id *oid,
 			 int flag UNUSED, void *cb_data)
 {
 	const char *name_nons = strip_namespace(name);
@@ -568,7 +568,7 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)
 	strbuf_release(&buf);
 }
 
-static int show_head_ref(const char *refname, const struct object_id *oid,
+static int show_head_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			 int flag, void *cb_data)
 {
 	struct strbuf *buf = cb_data;
@@ -601,7 +601,7 @@ static void get_head(struct strbuf *hdr, char *arg UNUSED)
 
 static void get_info_packs(struct strbuf *hdr, char *arg UNUSED)
 {
-	size_t objdirlen = strlen(get_object_directory());
+	size_t objdirlen = strlen(repo_get_object_directory(the_repository));
 	struct strbuf buf = STRBUF_INIT;
 	struct packed_git *p;
 	size_t cnt = 0;
diff --git a/http-fetch.c b/http-fetch.c
index d460bb1..02ab805 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -106,6 +106,7 @@ int cmd_main(int argc, const char **argv)
 	int nongit;
 	struct object_id packfile_hash;
 	struct strvec index_pack_args = STRVEC_INIT;
+	int ret;
 
 	setup_git_directory_gently(&nongit);
 
@@ -157,8 +158,8 @@ int cmd_main(int argc, const char **argv)
 
 		fetch_single_packfile(&packfile_hash, argv[arg],
 				      index_pack_args.v);
-
-		return 0;
+		ret = 0;
+		goto out;
 	}
 
 	if (index_pack_args.nr)
@@ -170,7 +171,12 @@ int cmd_main(int argc, const char **argv)
 		commit_id = (char **) &argv[arg++];
 		commits = 1;
 	}
-	return fetch_using_walker(argv[arg], get_verbosely, get_recover,
-				  commits, commit_id, write_ref,
-				  commits_on_stdin);
+
+	ret = fetch_using_walker(argv[arg], get_verbosely, get_recover,
+				 commits, commit_id, write_ref,
+				 commits_on_stdin);
+
+out:
+	strvec_clear(&index_pack_args);
+	return ret;
 }
diff --git a/http-push.c b/http-push.c
index 7315a69..aad89f2 100644
--- a/http-push.c
+++ b/http-push.c
@@ -275,7 +275,7 @@ static void start_fetch_loose(struct transfer_request *request)
 	if (!start_active_slot(slot)) {
 		fprintf(stderr, "Unable to start GET request\n");
 		repo->can_update_info_refs = 0;
-		release_http_object_request(obj_req);
+		release_http_object_request(&obj_req);
 		release_request(request);
 	}
 }
@@ -375,7 +375,7 @@ static void start_put(struct transfer_request *request)
 	/* Set it up */
 	git_deflate_init(&stream, zlib_compression_level);
 	size = git_deflate_bound(&stream, len + hdrlen);
-	strbuf_init(&request->buffer.buf, size);
+	strbuf_grow(&request->buffer.buf, size);
 	request->buffer.posn = 0;
 
 	/* Compress it */
@@ -437,9 +437,11 @@ static void start_move(struct transfer_request *request)
 	if (start_active_slot(slot)) {
 		request->slot = slot;
 		request->state = RUN_MOVE;
+		request->headers = dav_headers;
 	} else {
 		request->state = ABORTED;
 		FREE_AND_NULL(request->url);
+		curl_slist_free_all(dav_headers);
 	}
 }
 
@@ -512,6 +514,8 @@ static void release_request(struct transfer_request *request)
 	}
 
 	free(request->url);
+	free(request->dest);
+	strbuf_release(&request->buffer.buf);
 	free(request);
 }
 
@@ -578,9 +582,10 @@ static void finish_request(struct transfer_request *request)
 			if (obj_req->rename == 0)
 				request->obj->flags |= (LOCAL | REMOTE);
 
+		release_http_object_request(&obj_req);
+
 		/* Try fetching packed if necessary */
 		if (request->obj->flags & LOCAL) {
-			release_http_object_request(obj_req);
 			release_request(request);
 		} else
 			start_fetch_packed(request);
@@ -649,12 +654,10 @@ static void add_fetch_request(struct object *obj)
 		return;
 
 	obj->flags |= FETCHING;
-	request = xmalloc(sizeof(*request));
+	CALLOC_ARRAY(request, 1);
 	request->obj = obj;
-	request->url = NULL;
-	request->lock = NULL;
-	request->headers = NULL;
 	request->state = NEED_FETCH;
+	strbuf_init(&request->buffer.buf, 0);
 	request->next = request_queue_head;
 	request_queue_head = request;
 
@@ -685,12 +688,11 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)
 	}
 
 	obj->flags |= PUSHING;
-	request = xmalloc(sizeof(*request));
+	CALLOC_ARRAY(request, 1);
 	request->obj = obj;
-	request->url = NULL;
 	request->lock = lock;
-	request->headers = NULL;
 	request->state = NEED_PUSH;
+	strbuf_init(&request->buffer.buf, 0);
 	request->next = request_queue_head;
 	request_queue_head = request;
 
@@ -912,6 +914,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
 			result = XML_Parse(parser, in_buffer.buf,
 					   in_buffer.len, 1);
 			free(ctx.name);
+			free(ctx.cdata);
 			if (result != XML_STATUS_OK) {
 				fprintf(stderr, "XML error: %s\n",
 					XML_ErrorString(
@@ -1169,6 +1172,7 @@ static void remote_ls(const char *path, int flags,
 			result = XML_Parse(parser, in_buffer.buf,
 					   in_buffer.len, 1);
 			free(ctx.name);
+			free(ctx.cdata);
 
 			if (result != XML_STATUS_OK) {
 				fprintf(stderr, "XML error: %s\n",
@@ -1182,6 +1186,7 @@ static void remote_ls(const char *path, int flags,
 	}
 
 	free(ls.path);
+	free(ls.dentry_name);
 	free(url);
 	strbuf_release(&out_buffer.buf);
 	strbuf_release(&in_buffer);
@@ -1370,9 +1375,13 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
 	}
 
 	while (objects) {
+		struct object_list *next = objects->next;
+
 		if (!(objects->item->flags & UNINTERESTING))
 			count += add_send_request(objects->item, lock);
-		objects = objects->next;
+
+		free(objects);
+		objects = next;
 	}
 
 	return count;
@@ -1398,6 +1407,7 @@ static int update_remote(const struct object_id *oid, struct remote_lock *lock)
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
 		strbuf_release(&out_buffer.buf);
+		curl_slist_free_all(dav_headers);
 		if (results.curl_result != CURLE_OK) {
 			fprintf(stderr,
 				"PUT error: curl result=%d, HTTP code=%ld\n",
@@ -1407,6 +1417,7 @@ static int update_remote(const struct object_id *oid, struct remote_lock *lock)
 		}
 	} else {
 		strbuf_release(&out_buffer.buf);
+		curl_slist_free_all(dav_headers);
 		fprintf(stderr, "Unable to start PUT request\n");
 		return 0;
 	}
@@ -1516,6 +1527,7 @@ static void update_remote_info_refs(struct remote_lock *lock)
 					results.curl_result, results.http_code);
 			}
 		}
+		curl_slist_free_all(dav_headers);
 	}
 	strbuf_release(&buffer.buf);
 }
@@ -1707,7 +1719,7 @@ int cmd_main(int argc, const char **argv)
 	int rc = 0;
 	int i;
 	int new_refs;
-	struct ref *ref, *local_refs;
+	struct ref *ref, *local_refs = NULL;
 
 	CALLOC_ARRAY(repo, 1);
 
@@ -1972,6 +1984,7 @@ int cmd_main(int argc, const char **argv)
  cleanup:
 	if (info_ref_lock)
 		unlock_remote(info_ref_lock);
+	free(repo->url);
 	free(repo);
 
 	http_cleanup();
@@ -1983,5 +1996,8 @@ int cmd_main(int argc, const char **argv)
 		request = next_request;
 	}
 
+	refspec_clear(&rs);
+	free_refs(local_refs);
+
 	return rc;
 }
diff --git a/http-walker.c b/http-walker.c
index e417a7f..fb2d86d 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -74,7 +74,7 @@ static void start_object_request(struct object_request *obj_req)
 	obj_req->state = ACTIVE;
 	if (!start_active_slot(slot)) {
 		obj_req->state = ABORTED;
-		release_http_object_request(req);
+		release_http_object_request(&req);
 		return;
 	}
 }
@@ -110,7 +110,7 @@ static void process_object_response(void *callback_data)
 		if (obj_req->repo->next) {
 			obj_req->repo =
 				obj_req->repo->next;
-			release_http_object_request(obj_req->req);
+			release_http_object_request(&obj_req->req);
 			start_object_request(obj_req);
 			return;
 		}
@@ -495,7 +495,7 @@ static int fetch_object(struct walker *walker, unsigned char *hash)
 
 	if (repo_has_object_file(the_repository, &obj_req->oid)) {
 		if (obj_req->req)
-			abort_http_object_request(obj_req->req);
+			abort_http_object_request(&obj_req->req);
 		abort_object_request(obj_req);
 		return 0;
 	}
@@ -543,7 +543,7 @@ static int fetch_object(struct walker *walker, unsigned char *hash)
 		strbuf_release(&buf);
 	}
 
-	release_http_object_request(req);
+	release_http_object_request(&obj_req->req);
 	release_object_request(obj_req);
 	return ret;
 }
@@ -579,8 +579,18 @@ static void cleanup(struct walker *walker)
 	if (data) {
 		alt = data->alt;
 		while (alt) {
+			struct packed_git *pack;
+
 			alt_next = alt->next;
 
+			pack = alt->packs;
+			while (pack) {
+				struct packed_git *pack_next = pack->next;
+				close_pack(pack);
+				free(pack);
+				pack = pack_next;
+			}
+
 			free(alt->base);
 			free(alt);
 
diff --git a/http.c b/http.c
index 623ed23..d59e59f 100644
--- a/http.c
+++ b/http.c
@@ -800,6 +800,7 @@ static int redact_sensitive_header(struct strbuf *header, size_t offset)
 
 		strbuf_setlen(header, sensitive_header - header->buf);
 		strbuf_addbuf(header, &redacted_header);
+		strbuf_release(&redacted_header);
 		ret = 1;
 	}
 	return ret;
@@ -1227,6 +1228,8 @@ static CURL *get_curl_handle(void)
 		 */
 		curl_easy_setopt(result, CURLOPT_PROXY, "");
 	} else if (curl_http_proxy) {
+		struct strbuf proxy = STRBUF_INIT;
+
 		if (starts_with(curl_http_proxy, "socks5h"))
 			curl_easy_setopt(result,
 				CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
@@ -1265,7 +1268,27 @@ static CURL *get_curl_handle(void)
 		if (!proxy_auth.host)
 			die("Invalid proxy URL '%s'", curl_http_proxy);
 
-		curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host);
+		strbuf_addstr(&proxy, proxy_auth.host);
+		if (proxy_auth.path) {
+			curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
+
+			if (ver->version_num < 0x075400)
+				die("libcurl 7.84 or later is required to support paths in proxy URLs");
+
+			if (!starts_with(proxy_auth.protocol, "socks"))
+				die("Invalid proxy URL '%s': only SOCKS proxies support paths",
+				    curl_http_proxy);
+
+			if (strcasecmp(proxy_auth.host, "localhost"))
+				die("Invalid proxy URL '%s': host must be localhost if a path is present",
+				    curl_http_proxy);
+
+			strbuf_addch(&proxy, '/');
+			strbuf_add_percentencode(&proxy, proxy_auth.path, 0);
+		}
+		curl_easy_setopt(result, CURLOPT_PROXY, proxy.buf);
+		strbuf_release(&proxy);
+
 		var_override(&curl_no_proxy, getenv("NO_PROXY"));
 		var_override(&curl_no_proxy, getenv("no_proxy"));
 		curl_easy_setopt(result, CURLOPT_NOPROXY, curl_no_proxy);
@@ -1685,7 +1708,7 @@ void run_active_slot(struct active_request_slot *slot)
 	 * The value of slot->finished we set before the loop was used
 	 * to set our "finished" variable when our request completed.
 	 *
-	 * 1. The slot may not have been reused for another requst
+	 * 1. The slot may not have been reused for another request
 	 *    yet, in which case it still has &finished.
 	 *
 	 * 2. The slot may already be in-use to serve another request,
@@ -2452,6 +2475,7 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
 
 cleanup:
 	free(url);
+	strbuf_release(&buf);
 	return ret;
 }
 
@@ -2703,6 +2727,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
 	 * file; also rewind to the beginning of the local file.
 	 */
 	if (prev_read == -1) {
+		git_inflate_end(&freq->stream);
 		memset(&freq->stream, 0, sizeof(freq->stream));
 		git_inflate_init(&freq->stream);
 		the_hash_algo->init_fn(&freq->c);
@@ -2776,7 +2801,6 @@ int finish_http_object_request(struct http_object_request *freq)
 		return -1;
 	}
 
-	git_inflate_end(&freq->stream);
 	the_hash_algo->final_oid_fn(&freq->real_oid, &freq->c);
 	if (freq->zret != Z_STREAM_END) {
 		unlink_or_warn(freq->tmpfile.buf);
@@ -2793,15 +2817,17 @@ int finish_http_object_request(struct http_object_request *freq)
 	return freq->rename;
 }
 
-void abort_http_object_request(struct http_object_request *freq)
+void abort_http_object_request(struct http_object_request **freq_p)
 {
+	struct http_object_request *freq = *freq_p;
 	unlink_or_warn(freq->tmpfile.buf);
 
-	release_http_object_request(freq);
+	release_http_object_request(freq_p);
 }
 
-void release_http_object_request(struct http_object_request *freq)
+void release_http_object_request(struct http_object_request **freq_p)
 {
+	struct http_object_request *freq = *freq_p;
 	if (freq->localfile != -1) {
 		close(freq->localfile);
 		freq->localfile = -1;
@@ -2815,4 +2841,8 @@ void release_http_object_request(struct http_object_request *freq)
 	}
 	curl_slist_free_all(freq->headers);
 	strbuf_release(&freq->tmpfile);
+	git_inflate_end(&freq->stream);
+
+	free(freq);
+	*freq_p = NULL;
 }
diff --git a/http.h b/http.h
index a516ca4..46e334c 100644
--- a/http.h
+++ b/http.h
@@ -240,8 +240,8 @@ struct http_object_request *new_http_object_request(
 	const char *base_url, const struct object_id *oid);
 void process_http_object_request(struct http_object_request *freq);
 int finish_http_object_request(struct http_object_request *freq);
-void abort_http_object_request(struct http_object_request *freq);
-void release_http_object_request(struct http_object_request *freq);
+void abort_http_object_request(struct http_object_request **freq);
+void release_http_object_request(struct http_object_request **freq);
 
 /*
  * Instead of using environment variables to determine if curl tracing happens,
diff --git a/imap-send.c b/imap-send.c
index 01404e5..ec68a06 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -21,6 +21,8 @@
  *  along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "credential.h"
@@ -29,9 +31,6 @@
 #include "parse-options.h"
 #include "setup.h"
 #include "strbuf.h"
-#if defined(NO_OPENSSL) && !defined(HAVE_OPENSSL_CSPRNG)
-typedef void *SSL;
-#endif
 #ifdef USE_CURL_FOR_IMAP_SEND
 #include "http.h"
 #endif
@@ -83,7 +82,11 @@ struct imap_server_conf {
 
 struct imap_socket {
 	int fd[2];
+#if defined(NO_OPENSSL) && !defined(HAVE_OPENSSL_CSPRNG)
+	void *ssl;
+#else
 	SSL *ssl;
+#endif
 };
 
 struct imap_buffer {
@@ -190,7 +193,7 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret)
 
 #ifdef NO_OPENSSL
 static int ssl_socket_connect(struct imap_socket *sock UNUSED,
-			      const struct imap_server_conf *cfg,
+			      const struct imap_server_conf *cfg UNUSED,
 			      int use_tls_only UNUSED)
 {
 	fprintf(stderr, "SSL requested but SSL support not compiled in\n");
diff --git a/line-log.c b/line-log.c
index 67c80b3..63945c4 100644
--- a/line-log.c
+++ b/line-log.c
@@ -897,16 +897,6 @@ static void print_line(const char *prefix, char first,
 		fputs("\\ No newline at end of file\n", file);
 }
 
-static char *output_prefix(struct diff_options *opt)
-{
-	if (opt->output_prefix) {
-		struct strbuf *sb = opt->output_prefix(opt, opt->output_prefix_data);
-		return sb->buf;
-	} else {
-		return xstrdup("");
-	}
-}
-
 static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *range)
 {
 	unsigned int i, j = 0;
@@ -916,7 +906,7 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang
 	struct diff_ranges *diff = &range->diff;
 
 	struct diff_options *opt = &rev->diffopt;
-	char *prefix = output_prefix(opt);
+	const char *prefix = diff_line_prefix(opt);
 	const char *c_reset = diff_get_color(opt->use_color, DIFF_RESET);
 	const char *c_frag = diff_get_color(opt->use_color, DIFF_FRAGINFO);
 	const char *c_meta = diff_get_color(opt->use_color, DIFF_METAINFO);
@@ -1003,7 +993,6 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang
 out:
 	free(p_ends);
 	free(t_ends);
-	free(prefix);
 }
 
 /*
@@ -1012,10 +1001,9 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang
  */
 static void dump_diff_hacky(struct rev_info *rev, struct line_log_data *range)
 {
-	char *prefix = output_prefix(&rev->diffopt);
+	const char *prefix = diff_line_prefix(&rev->diffopt);
 
 	fprintf(rev->diffopt.file, "%s\n", prefix);
-	free(prefix);
 
 	while (range) {
 		dump_diff_hacky_one(rev, range);
diff --git a/log-tree.c b/log-tree.c
index 13524bc..33eb96b 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -146,7 +146,7 @@ static int ref_filter_match(const char *refname,
 	return 1;
 }
 
-static int add_ref_decoration(const char *refname, const struct object_id *oid,
+static int add_ref_decoration(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			      int flags UNUSED,
 			      void *cb_data)
 {
@@ -922,12 +922,7 @@ int log_tree_diff_flush(struct rev_info *opt)
 			 * diff/diffstat output for readability.
 			 */
 			int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
-			if (opt->diffopt.output_prefix) {
-				struct strbuf *msg = NULL;
-				msg = opt->diffopt.output_prefix(&opt->diffopt,
-					opt->diffopt.output_prefix_data);
-				fwrite(msg->buf, msg->len, 1, opt->diffopt.file);
-			}
+			fputs(diff_line_prefix(&opt->diffopt), opt->diffopt.file);
 
 			/*
 			 * We may have shown three-dashes line early
@@ -1015,8 +1010,19 @@ static int do_remerge_diff(struct rev_info *opt,
 	struct strbuf parent1_desc = STRBUF_INIT;
 	struct strbuf parent2_desc = STRBUF_INIT;
 
+	/*
+	 * Lazily prepare a temporary object directory and rotate it
+	 * into the alternative object store list as the primary.
+	 */
+	if (opt->remerge_diff && !opt->remerge_objdir) {
+		opt->remerge_objdir = tmp_objdir_create("remerge-diff");
+		if (!opt->remerge_objdir)
+			return error(_("unable to create temporary object directory"));
+		tmp_objdir_replace_primary_odb(opt->remerge_objdir, 1);
+	}
+
 	/* Setup merge options */
-	init_merge_options(&o, the_repository);
+	init_ui_merge_options(&o, the_repository);
 	o.show_rename_progress = 0;
 	o.record_conflict_msgs_as_headers = 1;
 	o.msg_header_prefix = "remerge";
@@ -1051,10 +1057,7 @@ static int do_remerge_diff(struct rev_info *opt,
 	merge_finalize(&o, &res);
 
 	/* Clean up the contents of the temporary object directory */
-	if (opt->remerge_objdir)
-		tmp_objdir_discard_objects(opt->remerge_objdir);
-	else
-		BUG("did a remerge diff without remerge_objdir?!?");
+	tmp_objdir_discard_objects(opt->remerge_objdir);
 
 	return !opt->loginfo;
 }
diff --git a/loose.c b/loose.c
index a8bf772..897ba38 100644
--- a/loose.c
+++ b/loose.c
@@ -1,10 +1,9 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "hash.h"
 #include "path.h"
 #include "object-store.h"
 #include "hex.h"
+#include "repository.h"
 #include "wrapper.h"
 #include "gettext.h"
 #include "loose.h"
@@ -142,8 +141,8 @@ int repo_write_loose_object_map(struct repository *repo)
 
 	for (; iter != kh_end(map); iter++) {
 		if (kh_exist(map, iter)) {
-			if (oideq(&kh_key(map, iter), the_hash_algo->empty_tree) ||
-			    oideq(&kh_key(map, iter), the_hash_algo->empty_blob))
+			if (oideq(&kh_key(map, iter), repo->hash_algo->empty_tree) ||
+			    oideq(&kh_key(map, iter), repo->hash_algo->empty_blob))
 				continue;
 			strbuf_addf(&buf, "%s %s\n", oid_to_hex(&kh_key(map, iter)), oid_to_hex(kh_value(map, iter)));
 			if (write_in_full(fd, buf.buf, buf.len) < 0)
@@ -162,7 +161,7 @@ int repo_write_loose_object_map(struct repository *repo)
 errout:
 	rollback_lock_file(&lock);
 	strbuf_release(&buf);
-	error_errno(_("failed to write loose object index %s\n"), path.buf);
+	error_errno(_("failed to write loose object index %s"), path.buf);
 	strbuf_release(&path);
 	return -1;
 }
@@ -197,7 +196,7 @@ static int write_one_object(struct repository *repo, const struct object_id *oid
 	strbuf_release(&path);
 	return 0;
 errout:
-	error_errno(_("failed to write loose object index %s\n"), path.buf);
+	error_errno(_("failed to write loose object index %s"), path.buf);
 	close(fd);
 	rollback_lock_file(&lock);
 	strbuf_release(&buf);
diff --git a/ls-refs.c b/ls-refs.c
index 2dd925b..c824aea 100644
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -77,7 +77,7 @@ struct ls_refs_data {
 	unsigned unborn : 1;
 };
 
-static int send_ref(const char *refname, const struct object_id *oid,
+static int send_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 		    int flag, void *cb_data)
 {
 	struct ls_refs_data *data = cb_data;
@@ -135,7 +135,7 @@ static void send_possibly_unborn_head(struct ls_refs_data *data)
 	oid_is_null = is_null_oid(&oid);
 	if (!oid_is_null ||
 	    (data->unborn && data->symrefs && (flag & REF_ISSYMREF)))
-		send_ref(namespaced.buf, oid_is_null ? NULL : &oid, flag, data);
+		send_ref(namespaced.buf, NULL, oid_is_null ? NULL : &oid, flag, data);
 	strbuf_release(&namespaced);
 }
 
diff --git a/mailinfo.c b/mailinfo.c
index 94b9b0a..d1f42bd 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "gettext.h"
@@ -346,9 +348,8 @@ static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)
 	strbuf_trim(subject);
 }
 
-#define MAX_HDR_PARSED 10
-static const char *header[MAX_HDR_PARSED] = {
-	"From","Subject","Date",
+static const char * const header[] = {
+	"From", "Subject", "Date",
 };
 
 static inline int skip_header(const struct strbuf *line, const char *hdr,
@@ -583,7 +584,7 @@ static int check_header(struct mailinfo *mi,
 	struct strbuf sb = STRBUF_INIT;
 
 	/* search for the interesting parts */
-	for (i = 0; header[i]; i++) {
+	for (i = 0; i < ARRAY_SIZE(header); i++) {
 		if ((!hdr_data[i] || overwrite) &&
 		    parse_header(line, header[i], mi, &sb)) {
 			handle_header(&hdr_data[i], &sb);
@@ -625,7 +626,7 @@ static int is_inbody_header(const struct mailinfo *mi,
 {
 	int i;
 	const char *val;
-	for (i = 0; header[i]; i++)
+	for (i = 0; i < ARRAY_SIZE(header); i++)
 		if (!mi->s_hdr_data[i] && skip_header(line, header[i], &val))
 			return 1;
 	return 0;
@@ -772,7 +773,7 @@ static int check_inbody_header(struct mailinfo *mi, const struct strbuf *line)
 		return is_format_patch_separator(line->buf + 1, line->len - 1);
 	if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) {
 		int i;
-		for (i = 0; header[i]; i++)
+		for (i = 0; i < ARRAY_SIZE(header); i++)
 			if (!strcmp("Subject", header[i])) {
 				handle_header(&mi->s_hdr_data[i], line);
 				return 1;
@@ -824,7 +825,7 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line)
 		 * We may have already read "secondary headers"; purge
 		 * them to give ourselves a clean restart.
 		 */
-		for (i = 0; header[i]; i++) {
+		for (i = 0; i < ARRAY_SIZE(header); i++) {
 			if (mi->s_hdr_data[i])
 				strbuf_release(mi->s_hdr_data[i]);
 			FREE_AND_NULL(mi->s_hdr_data[i]);
@@ -1155,7 +1156,7 @@ static void handle_info(struct mailinfo *mi)
 	struct strbuf *hdr;
 	int i;
 
-	for (i = 0; header[i]; i++) {
+	for (i = 0; i < ARRAY_SIZE(header); i++) {
 		/* only print inbody headers if we output a patch file */
 		if (mi->patch_lines && mi->s_hdr_data[i])
 			hdr = mi->s_hdr_data[i];
@@ -1206,8 +1207,8 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
 		return -1;
 	}
 
-	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
-	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
+	mi->p_hdr_data = xcalloc(ARRAY_SIZE(header), sizeof(*(mi->p_hdr_data)));
+	mi->s_hdr_data = xcalloc(ARRAY_SIZE(header), sizeof(*(mi->s_hdr_data)));
 
 	do {
 		peek = fgetc(mi->input);
@@ -1290,8 +1291,21 @@ void clear_mailinfo(struct mailinfo *mi)
 	strbuf_release(&mi->inbody_header_accum);
 	free(mi->message_id);
 
-	strbuf_list_free(mi->p_hdr_data);
-	strbuf_list_free(mi->s_hdr_data);
+	for (size_t i = 0; i < ARRAY_SIZE(header); i++) {
+		if (!mi->p_hdr_data[i])
+			continue;
+		strbuf_release(mi->p_hdr_data[i]);
+		free(mi->p_hdr_data[i]);
+	}
+	free(mi->p_hdr_data);
+
+	for (size_t i = 0; i < ARRAY_SIZE(header); i++) {
+		if (!mi->s_hdr_data[i])
+			continue;
+		strbuf_release(mi->s_hdr_data[i]);
+		free(mi->s_hdr_data[i]);
+	}
+	free(mi->s_hdr_data);
 
 	while (mi->content < mi->content_top) {
 		free(*(mi->content_top));
diff --git a/mailmap.c b/mailmap.c
index 2acf97f..9f9fa31 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -142,11 +142,8 @@ static void read_mailmap_line(struct string_list *map, char *buffer)
 		add_mapping(map, name1, email1, name2, email2);
 }
 
-/* Flags for read_mailmap_file() */
-#define MAILMAP_NOFOLLOW (1<<0)
-
-static int read_mailmap_file(struct string_list *map, const char *filename,
-			     unsigned flags)
+int read_mailmap_file(struct string_list *map, const char *filename,
+		      unsigned flags)
 {
 	char buffer[1024];
 	FILE *f;
@@ -186,7 +183,7 @@ static void read_mailmap_string(struct string_list *map, char *buf)
 	}
 }
 
-static int read_mailmap_blob(struct string_list *map, const char *name)
+int read_mailmap_blob(struct string_list *map, const char *name)
 {
 	struct object_id oid;
 	char *buf;
diff --git a/mailmap.h b/mailmap.h
index cbda9bc..908365e 100644
--- a/mailmap.h
+++ b/mailmap.h
@@ -6,6 +6,13 @@ struct string_list;
 extern char *git_mailmap_file;
 extern char *git_mailmap_blob;
 
+/* Flags for read_mailmap_file() */
+#define MAILMAP_NOFOLLOW (1<<0)
+
+int read_mailmap_file(struct string_list *map, const char *filename,
+		      unsigned flags);
+int read_mailmap_blob(struct string_list *map, const char *name);
+
 int read_mailmap(struct string_list *map);
 void clear_mailmap(struct string_list *map);
 
diff --git a/match-trees.c b/match-trees.c
index f17c74d..147b03a 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -294,18 +294,22 @@ void shift_tree(struct repository *r,
 		unsigned short mode;
 
 		if (!*del_prefix)
-			return;
+			goto out;
 
 		if (get_tree_entry(r, hash2, del_prefix, shifted, &mode))
 			die("cannot find path %s in tree %s",
 			    del_prefix, oid_to_hex(hash2));
-		return;
+		goto out;
 	}
 
 	if (!*add_prefix)
-		return;
+		goto out;
 
 	splice_tree(hash1, add_prefix, hash2, shifted);
+
+out:
+	free(add_prefix);
+	free(del_prefix);
 }
 
 /*
diff --git a/merge-ll.c b/merge-ll.c
index 180c19d..8e63071 100644
--- a/merge-ll.c
+++ b/merge-ll.c
@@ -4,6 +4,8 @@
  * Copyright (c) 2007 Junio C Hamano
  */
 
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "convert.h"
@@ -332,7 +334,7 @@ static int read_merge_config(const char *var, const char *value,
 		 *    %X - the revision for our version
 		 *    %Y - the revision for their version
 		 *
-		 * If the file is not named indentically in all versions, then each
+		 * If the file is not named identically in all versions, then each
 		 * revision is joined with the corresponding path, separated by a colon.
 		 * The external merge driver should write the results in the
 		 * file named by %A, and signal that it has done with zero exit
diff --git a/merge-ort.c b/merge-ort.c
index e9d01ac..8b81153 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -689,8 +689,7 @@ static void clear_or_reinit_internal_opts(struct merge_options_internal *opti,
 	 */
 	strmap_clear_func(&opti->conflicted, 0);
 
-	if (opti->attr_index.cache_nr) /* true iff opt->renormalize */
-		discard_index(&opti->attr_index);
+	discard_index(&opti->attr_index);
 
 	/* Free memory used by various renames maps */
 	for (i = MERGE_SIDE1; i <= MERGE_SIDE2; ++i) {
@@ -1148,7 +1147,7 @@ static void collect_rename_info(struct merge_options *opt,
 	 * Update dir_rename_mask (determines ignore-rename-source validity)
 	 *
 	 * dir_rename_mask helps us keep track of when directory rename
-	 * detection may be relevant.  Basically, whenver a directory is
+	 * detection may be relevant.  Basically, whenever a directory is
 	 * removed on one side of history, and a file is added to that
 	 * directory on the other side of history, directory rename
 	 * detection is relevant (meaning we have to detect renames for all
@@ -2711,7 +2710,7 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
 		struct conflict_info *dir_ci;
 		char *cur_dir = dirs_to_insert.items[i].string;
 
-		CALLOC_ARRAY(dir_ci, 1);
+		dir_ci = mem_pool_calloc(&opt->priv->pool, 1, sizeof(*dir_ci));
 
 		dir_ci->merged.directory_name = parent_name;
 		len = strlen(parent_name);
@@ -2839,6 +2838,8 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
 	 * Finally, record the new location.
 	 */
 	pair->two->path = new_path;
+
+	string_list_clear(&dirs_to_insert, 0);
 }
 
 /*** Function Grouping: functions related to regular rename detection ***/
@@ -3836,7 +3837,7 @@ static int write_completed_directory(struct merge_options *opt,
 	 *     	   src/moduleB  2
 	 *
 	 *     which is used to know that xtract.c & token.txt are from the
-	 *     toplevel dirctory, while umm.c & stuff.h & baz.c are from the
+	 *     toplevel directory, while umm.c & stuff.h & baz.c are from the
 	 *     src/moduleB directory.  Again, following the example above,
 	 *     once we need to process src/moduleB, then info->offsets is
 	 *     updated to
diff --git a/merge-recursive.c b/merge-recursive.c
index 5cc6380..ed64a4c 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -3921,7 +3921,7 @@ int merge_recursive_generic(struct merge_options *opt,
 	return clean ? 0 : 1;
 }
 
-static void merge_recursive_config(struct merge_options *opt)
+static void merge_recursive_config(struct merge_options *opt, int ui)
 {
 	char *value = NULL;
 	int renormalize = 0;
@@ -3950,11 +3950,20 @@ static void merge_recursive_config(struct merge_options *opt)
 		} /* avoid erroring on values from future versions of git */
 		free(value);
 	}
+	if (ui) {
+		if (!git_config_get_string("diff.algorithm", &value)) {
+			long diff_algorithm = parse_algorithm_value(value);
+			if (diff_algorithm < 0)
+				die(_("unknown value for config '%s': %s"), "diff.algorithm", value);
+			opt->xdl_opts = (opt->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;
+			free(value);
+		}
+	}
 	git_config(git_xmerge_config, NULL);
 }
 
-void init_merge_options(struct merge_options *opt,
-			struct repository *repo)
+static void init_merge_options(struct merge_options *opt,
+			struct repository *repo, int ui)
 {
 	const char *merge_verbosity;
 	memset(opt, 0, sizeof(struct merge_options));
@@ -3973,7 +3982,7 @@ void init_merge_options(struct merge_options *opt,
 
 	opt->conflict_style = -1;
 
-	merge_recursive_config(opt);
+	merge_recursive_config(opt, ui);
 	merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
 	if (merge_verbosity)
 		opt->verbosity = strtol(merge_verbosity, NULL, 10);
@@ -3981,6 +3990,18 @@ void init_merge_options(struct merge_options *opt,
 		opt->buffer_output = 0;
 }
 
+void init_ui_merge_options(struct merge_options *opt,
+			struct repository *repo)
+{
+	init_merge_options(opt, repo, 1);
+}
+
+void init_basic_merge_options(struct merge_options *opt,
+			struct repository *repo)
+{
+	init_merge_options(opt, repo, 0);
+}
+
 /*
  * For now, members of merge_options do not need deep copying, but
  * it may change in the future, in which case we would need to update
diff --git a/merge-recursive.h b/merge-recursive.h
index 3136c7c..0b91f28 100644
--- a/merge-recursive.h
+++ b/merge-recursive.h
@@ -54,7 +54,10 @@ struct merge_options {
 	struct merge_options_internal *priv;
 };
 
-void init_merge_options(struct merge_options *opt, struct repository *repo);
+/* for use by porcelain commands */
+void init_ui_merge_options(struct merge_options *opt, struct repository *repo);
+/* for use by plumbing commands */
+void init_basic_merge_options(struct merge_options *opt, struct repository *repo);
 
 void copy_merge_options(struct merge_options *dst, struct merge_options *src);
 void clear_merge_options(struct merge_options *opt);
diff --git a/mergetools/vimdiff b/mergetools/vimdiff
index f8ad6b3..ffc9be8 100644
--- a/mergetools/vimdiff
+++ b/mergetools/vimdiff
@@ -411,7 +411,7 @@
 			-f "$FINAL_CMD" '"$LOCAL"' '"$BASE"' '"$REMOTE"' '"$MERGED"'
 	else
 		# If there is no BASE (example: a merge conflict in a new file
-		# with the same name created in both braches which didn't exist
+		# with the same name created in both branches which didn't exist
 		# before), close all BASE windows using vim's "quit" command
 
 		FINAL_CMD=$(echo "$FINAL_CMD" | \
diff --git a/mergetools/vscode b/mergetools/vscode
new file mode 100644
index 0000000..3b39b45
--- /dev/null
+++ b/mergetools/vscode
@@ -0,0 +1,19 @@
+diff_cmd () {
+	"$merge_tool_path" --wait --diff "$LOCAL" "$REMOTE"
+}
+
+diff_cmd_help () {
+	echo "Use Visual Studio Code (requires a graphical session)"
+}
+
+merge_cmd () {
+	"$merge_tool_path" --wait --merge "$REMOTE" "$LOCAL" "$BASE" "$MERGED"
+}
+
+merge_cmd_help () {
+	echo "Use Visual Studio Code (requires a graphical session)"
+}
+
+translate_merge_tool_path () {
+	echo code
+}
diff --git a/midx-write.c b/midx-write.c
index a77ee73..1ef62c4 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -17,6 +17,8 @@
 #include "refs.h"
 #include "revision.h"
 #include "list-objects.h"
+#include "path.h"
+#include "pack-revindex.h"
 
 #define PACK_EXPIRED UINT_MAX
 #define BITMAP_POS_UNKNOWN (~((uint32_t)0))
@@ -25,7 +27,11 @@
 
 extern int midx_checksum_valid(struct multi_pack_index *m);
 extern void clear_midx_files_ext(const char *object_dir, const char *ext,
-				 unsigned char *keep_hash);
+				 const char *keep_hash);
+extern void clear_incremental_midx_files_ext(const char *object_dir,
+					     const char *ext,
+					     const char **keep_hashes,
+					     uint32_t hashes_nr);
 extern int cmp_idx_or_pack_name(const char *idx_or_pack_name,
 				const char *idx_name);
 
@@ -86,6 +92,7 @@ struct write_midx_context {
 	size_t nr;
 	size_t alloc;
 	struct multi_pack_index *m;
+	struct multi_pack_index *base_midx;
 	struct progress *progress;
 	unsigned pack_paths_checked;
 
@@ -99,6 +106,9 @@ struct write_midx_context {
 
 	int preferred_pack_idx;
 
+	int incremental;
+	uint32_t num_multi_pack_indexes_before;
+
 	struct string_list *to_include;
 };
 
@@ -122,6 +132,9 @@ static int should_include_pack(const struct write_midx_context *ctx,
 	 */
 	if (ctx->m && midx_contains_pack(ctx->m, file_name))
 		return 0;
+	else if (ctx->base_midx && midx_contains_pack(ctx->base_midx,
+						      file_name))
+		return 0;
 	else if (ctx->to_include &&
 		 !string_list_has_string(ctx->to_include, file_name))
 		return 0;
@@ -196,7 +209,7 @@ static int nth_midxed_pack_midx_entry(struct multi_pack_index *m,
 				      struct pack_midx_entry *e,
 				      uint32_t pos)
 {
-	if (pos >= m->num_objects)
+	if (pos >= m->num_objects + m->num_objects_in_base)
 		return 1;
 
 	nth_midxed_object_oid(&e->oid, m, pos);
@@ -247,12 +260,16 @@ static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
 					uint32_t cur_fanout,
 					int preferred_pack)
 {
-	uint32_t start = 0, end;
+	uint32_t start = m->num_objects_in_base, end;
 	uint32_t cur_object;
 
+	if (m->base_midx)
+		midx_fanout_add_midx_fanout(fanout, m->base_midx, cur_fanout,
+					    preferred_pack);
+
 	if (cur_fanout)
-		start = ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
-	end = ntohl(m->chunk_oid_fanout[cur_fanout]);
+		start += ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
+	end = m->num_objects_in_base + ntohl(m->chunk_oid_fanout[cur_fanout]);
 
 	for (cur_object = start; cur_object < end; cur_object++) {
 		if ((preferred_pack > -1) &&
@@ -334,7 +351,7 @@ static void compute_sorted_entries(struct write_midx_context *ctx,
 	for (cur_fanout = 0; cur_fanout < 256; cur_fanout++) {
 		fanout.nr = 0;
 
-		if (ctx->m)
+		if (ctx->m && !ctx->incremental)
 			midx_fanout_add_midx_fanout(&fanout, ctx->m, cur_fanout,
 						    ctx->preferred_pack_idx);
 
@@ -360,6 +377,10 @@ static void compute_sorted_entries(struct write_midx_context *ctx,
 			if (cur_object && oideq(&fanout.entries[cur_object - 1].oid,
 						&fanout.entries[cur_object].oid))
 				continue;
+			if (ctx->incremental && ctx->base_midx &&
+			    midx_has_oid(ctx->base_midx,
+					 &fanout.entries[cur_object].oid))
+				continue;
 
 			ALLOC_GROW(ctx->entries, st_add(ctx->entries_nr, 1),
 				   alloc_objects);
@@ -543,10 +564,16 @@ static int write_midx_revindex(struct hashfile *f,
 			       void *data)
 {
 	struct write_midx_context *ctx = data;
-	uint32_t i;
+	uint32_t i, nr_base;
+
+	if (ctx->incremental && ctx->base_midx)
+		nr_base = ctx->base_midx->num_objects +
+			ctx->base_midx->num_objects_in_base;
+	else
+		nr_base = 0;
 
 	for (i = 0; i < ctx->entries_nr; i++)
-		hashwrite_be32(f, ctx->pack_order[i]);
+		hashwrite_be32(f, ctx->pack_order[i] + nr_base);
 
 	return 0;
 }
@@ -575,12 +602,18 @@ static int midx_pack_order_cmp(const void *va, const void *vb)
 static uint32_t *midx_pack_order(struct write_midx_context *ctx)
 {
 	struct midx_pack_order_data *data;
-	uint32_t *pack_order;
+	uint32_t *pack_order, base_objects = 0;
 	uint32_t i;
 
 	trace2_region_enter("midx", "midx_pack_order", the_repository);
 
+	if (ctx->incremental && ctx->base_midx)
+		base_objects = ctx->base_midx->num_objects +
+			ctx->base_midx->num_objects_in_base;
+
+	ALLOC_ARRAY(pack_order, ctx->entries_nr);
 	ALLOC_ARRAY(data, ctx->entries_nr);
+
 	for (i = 0; i < ctx->entries_nr; i++) {
 		struct pack_midx_entry *e = &ctx->entries[i];
 		data[i].nr = i;
@@ -592,12 +625,11 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx)
 
 	QSORT(data, ctx->entries_nr, midx_pack_order_cmp);
 
-	ALLOC_ARRAY(pack_order, ctx->entries_nr);
 	for (i = 0; i < ctx->entries_nr; i++) {
 		struct pack_midx_entry *e = &ctx->entries[data[i].nr];
 		struct pack_info *pack = &ctx->info[ctx->pack_perm[e->pack_int_id]];
 		if (pack->bitmap_pos == BITMAP_POS_UNKNOWN)
-			pack->bitmap_pos = i;
+			pack->bitmap_pos = i + base_objects;
 		pack->bitmap_nr++;
 		pack_order[i] = data[i].nr;
 	}
@@ -645,7 +677,8 @@ static void prepare_midx_packing_data(struct packing_data *pdata,
 	prepare_packing_data(the_repository, pdata);
 
 	for (i = 0; i < ctx->entries_nr; i++) {
-		struct pack_midx_entry *from = &ctx->entries[ctx->pack_order[i]];
+		uint32_t pos = ctx->pack_order[i];
+		struct pack_midx_entry *from = &ctx->entries[pos];
 		struct object_entry *to = packlist_alloc(pdata, &from->oid);
 
 		oe_set_in_pack(pdata, to,
@@ -655,7 +688,7 @@ static void prepare_midx_packing_data(struct packing_data *pdata,
 	trace2_region_leave("midx", "prepare_midx_packing_data", the_repository);
 }
 
-static int add_ref_to_pending(const char *refname,
+static int add_ref_to_pending(const char *refname, const char *referent UNUSED,
 			      const struct object_id *oid,
 			      int flag, void *cb_data)
 {
@@ -825,10 +858,9 @@ static int write_midx_bitmap(const char *midx_name,
 	for (i = 0; i < pdata->nr_objects; i++)
 		index[i] = &pdata->objects[i].idx;
 
-	bitmap_writer_init(&writer, the_repository);
+	bitmap_writer_init(&writer, the_repository, pdata);
 	bitmap_writer_show_progress(&writer, flags & MIDX_PROGRESS);
-	bitmap_writer_build_type_index(&writer, pdata, index,
-				       pdata->nr_objects);
+	bitmap_writer_build_type_index(&writer, index);
 
 	/*
 	 * bitmap_writer_finish expects objects in lex order, but pack_order
@@ -847,13 +879,12 @@ static int write_midx_bitmap(const char *midx_name,
 		index[pack_order[i]] = &pdata->objects[i].idx;
 
 	bitmap_writer_select_commits(&writer, commits, commits_nr);
-	ret = bitmap_writer_build(&writer, pdata);
+	ret = bitmap_writer_build(&writer);
 	if (ret < 0)
 		goto cleanup;
 
 	bitmap_writer_set_checksum(&writer, midx_hash);
-	bitmap_writer_finish(&writer, index, pdata->nr_objects, bitmap_name,
-			     options);
+	bitmap_writer_finish(&writer, index, bitmap_name, options);
 
 cleanup:
 	free(index);
@@ -893,35 +924,128 @@ static struct multi_pack_index *lookup_multi_pack_index(struct repository *r,
 static int fill_packs_from_midx(struct write_midx_context *ctx,
 				const char *preferred_pack_name, uint32_t flags)
 {
-	uint32_t i;
+	struct multi_pack_index *m;
 
-	for (i = 0; i < ctx->m->num_packs; i++) {
-		ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
+	for (m = ctx->m; m; m = m->base_midx) {
+		uint32_t i;
 
-		if (flags & MIDX_WRITE_REV_INDEX || preferred_pack_name) {
+		for (i = 0; i < m->num_packs; i++) {
+			ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
+
 			/*
 			 * If generating a reverse index, need to have
 			 * packed_git's loaded to compare their
 			 * mtimes and object count.
 			 *
-			 *
 			 * If a preferred pack is specified, need to
 			 * have packed_git's loaded to ensure the chosen
 			 * preferred pack has a non-zero object count.
 			 */
-			if (prepare_midx_pack(the_repository, ctx->m, i))
-				return error(_("could not load pack"));
+			if (flags & MIDX_WRITE_REV_INDEX ||
+			    preferred_pack_name) {
+				if (prepare_midx_pack(the_repository, m,
+						      m->num_packs_in_base + i)) {
+					error(_("could not load pack"));
+					return 1;
+				}
 
-			if (open_pack_index(ctx->m->packs[i]))
-				die(_("could not open index for %s"),
-				    ctx->m->packs[i]->pack_name);
+				if (open_pack_index(m->packs[i]))
+					die(_("could not open index for %s"),
+					    m->packs[i]->pack_name);
+			}
+
+			fill_pack_info(&ctx->info[ctx->nr++], m->packs[i],
+				       m->pack_names[i],
+				       m->num_packs_in_base + i);
 		}
+	}
+	return 0;
+}
 
-		fill_pack_info(&ctx->info[ctx->nr++], ctx->m->packs[i],
-			       ctx->m->pack_names[i], i);
+static struct {
+	const char *non_split;
+	const char *split;
+} midx_exts[] = {
+	{NULL, MIDX_EXT_MIDX},
+	{MIDX_EXT_BITMAP, MIDX_EXT_BITMAP},
+	{MIDX_EXT_REV, MIDX_EXT_REV},
+};
+
+static int link_midx_to_chain(struct multi_pack_index *m)
+{
+	struct strbuf from = STRBUF_INIT;
+	struct strbuf to = STRBUF_INIT;
+	int ret = 0;
+	size_t i;
+
+	if (!m || m->has_chain) {
+		/*
+		 * Either no MIDX previously existed, or it was already
+		 * part of a MIDX chain. In both cases, we have nothing
+		 * to link, so return early.
+		 */
+		goto done;
 	}
 
-	return 0;
+	for (i = 0; i < ARRAY_SIZE(midx_exts); i++) {
+		const unsigned char *hash = get_midx_checksum(m);
+
+		get_midx_filename_ext(&from, m->object_dir, hash,
+				      midx_exts[i].non_split);
+		get_split_midx_filename_ext(&to, m->object_dir, hash,
+					    midx_exts[i].split);
+
+		if (link(from.buf, to.buf) < 0 && errno != ENOENT) {
+			ret = error_errno(_("unable to link '%s' to '%s'"),
+					  from.buf, to.buf);
+			goto done;
+		}
+
+		strbuf_reset(&from);
+		strbuf_reset(&to);
+	}
+
+done:
+	strbuf_release(&from);
+	strbuf_release(&to);
+	return ret;
+}
+
+static void clear_midx_files(const char *object_dir,
+			     const char **hashes,
+			     uint32_t hashes_nr,
+			     unsigned incremental)
+{
+	/*
+	 * if incremental:
+	 *   - remove all non-incremental MIDX files
+	 *   - remove any incremental MIDX files not in the current one
+	 *
+	 * if non-incremental:
+	 *   - remove all incremental MIDX files
+	 *   - remove any non-incremental MIDX files not matching the current
+	 *     hash
+	 */
+	struct strbuf buf = STRBUF_INIT;
+	const char *exts[] = { MIDX_EXT_BITMAP, MIDX_EXT_REV, MIDX_EXT_MIDX };
+	uint32_t i, j;
+
+	for (i = 0; i < ARRAY_SIZE(exts); i++) {
+		clear_incremental_midx_files_ext(object_dir, exts[i],
+						 hashes, hashes_nr);
+		for (j = 0; j < hashes_nr; j++)
+			clear_midx_files_ext(object_dir, exts[i], hashes[j]);
+	}
+
+	if (incremental)
+		get_midx_filename(&buf, object_dir);
+	else
+		get_midx_chain_filename(&buf, object_dir);
+
+	if (unlink(buf.buf) && errno != ENOENT)
+		die_errno(_("failed to clear multi-pack-index at %s"), buf.buf);
+
+	strbuf_release(&buf);
 }
 
 static int write_midx_internal(const char *object_dir,
@@ -936,42 +1060,66 @@ static int write_midx_internal(const char *object_dir,
 	uint32_t i, start_pack;
 	struct hashfile *f = NULL;
 	struct lock_file lk;
+	struct tempfile *incr;
 	struct write_midx_context ctx = { 0 };
 	int bitmapped_packs_concat_len = 0;
 	int pack_name_concat_len = 0;
 	int dropped_packs = 0;
 	int result = 0;
+	const char **keep_hashes = NULL;
 	struct chunkfile *cf;
 
 	trace2_region_enter("midx", "write_midx_internal", the_repository);
 
-	get_midx_filename(&midx_name, object_dir);
+	ctx.incremental = !!(flags & MIDX_WRITE_INCREMENTAL);
+	if (ctx.incremental && (flags & MIDX_WRITE_BITMAP))
+		die(_("cannot write incremental MIDX with bitmap"));
+
+	if (ctx.incremental)
+		strbuf_addf(&midx_name,
+			    "%s/pack/multi-pack-index.d/tmp_midx_XXXXXX",
+			    object_dir);
+	else
+		get_midx_filename(&midx_name, object_dir);
 	if (safe_create_leading_directories(midx_name.buf))
 		die_errno(_("unable to create leading directories of %s"),
 			  midx_name.buf);
 
-	if (!packs_to_include) {
-		/*
-		 * Only reference an existing MIDX when not filtering which
-		 * packs to include, since all packs and objects are copied
-		 * blindly from an existing MIDX if one is present.
-		 */
-		ctx.m = lookup_multi_pack_index(the_repository, object_dir);
-	}
+	if (!packs_to_include || ctx.incremental) {
+		struct multi_pack_index *m = lookup_multi_pack_index(the_repository,
+								     object_dir);
+		if (m && !midx_checksum_valid(m)) {
+			warning(_("ignoring existing multi-pack-index; checksum mismatch"));
+			m = NULL;
+		}
 
-	if (ctx.m && !midx_checksum_valid(ctx.m)) {
-		warning(_("ignoring existing multi-pack-index; checksum mismatch"));
-		ctx.m = NULL;
+		if (m) {
+			/*
+			 * Only reference an existing MIDX when not filtering
+			 * which packs to include, since all packs and objects
+			 * are copied blindly from an existing MIDX if one is
+			 * present.
+			 */
+			if (ctx.incremental)
+				ctx.base_midx = m;
+			else if (!packs_to_include)
+				ctx.m = m;
+		}
 	}
 
 	ctx.nr = 0;
-	ctx.alloc = ctx.m ? ctx.m->num_packs : 16;
+	ctx.alloc = ctx.m ? ctx.m->num_packs + ctx.m->num_packs_in_base : 16;
 	ctx.info = NULL;
 	ALLOC_ARRAY(ctx.info, ctx.alloc);
 
-	if (ctx.m && fill_packs_from_midx(&ctx, preferred_pack_name,
-					  flags) < 0) {
-		result = 1;
+	if (ctx.incremental) {
+		struct multi_pack_index *m = ctx.base_midx;
+		while (m) {
+			ctx.num_multi_pack_indexes_before++;
+			m = m->base_midx;
+		}
+	} else if (ctx.m && fill_packs_from_midx(&ctx, preferred_pack_name,
+						 flags) < 0) {
 		goto cleanup;
 	}
 
@@ -988,7 +1136,8 @@ static int write_midx_internal(const char *object_dir,
 	for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx);
 	stop_progress(&ctx.progress);
 
-	if ((ctx.m && ctx.nr == ctx.m->num_packs) &&
+	if ((ctx.m && ctx.nr == ctx.m->num_packs + ctx.m->num_packs_in_base) &&
+	    !ctx.incremental &&
 	    !(packs_to_include || packs_to_drop)) {
 		struct bitmap_index *bitmap_git;
 		int bitmap_exists;
@@ -1004,12 +1153,14 @@ static int write_midx_internal(const char *object_dir,
 			 * corresponding bitmap (or one wasn't requested).
 			 */
 			if (!want_bitmap)
-				clear_midx_files_ext(object_dir, ".bitmap",
-						     NULL);
+				clear_midx_files_ext(object_dir, "bitmap", NULL);
 			goto cleanup;
 		}
 	}
 
+	if (ctx.incremental && !ctx.nr)
+		goto cleanup; /* nothing to do */
+
 	if (preferred_pack_name) {
 		ctx.preferred_pack_idx = -1;
 
@@ -1155,9 +1306,6 @@ static int write_midx_internal(const char *object_dir,
 		pack_name_concat_len += MIDX_CHUNK_ALIGNMENT -
 					(pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
 
-	hold_lock_file_for_update(&lk, midx_name.buf, LOCK_DIE_ON_ERROR);
-	f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
-
 	if (ctx.nr - dropped_packs == 0) {
 		error(_("no pack files to index."));
 		result = 1;
@@ -1170,6 +1318,31 @@ static int write_midx_internal(const char *object_dir,
 		flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
 	}
 
+	if (ctx.incremental) {
+		struct strbuf lock_name = STRBUF_INIT;
+
+		get_midx_chain_filename(&lock_name, object_dir);
+		hold_lock_file_for_update(&lk, lock_name.buf, LOCK_DIE_ON_ERROR);
+		strbuf_release(&lock_name);
+
+		incr = mks_tempfile_m(midx_name.buf, 0444);
+		if (!incr) {
+			error(_("unable to create temporary MIDX layer"));
+			return -1;
+		}
+
+		if (adjust_shared_perm(get_tempfile_path(incr))) {
+			error(_("unable to adjust shared permissions for '%s'"),
+			      get_tempfile_path(incr));
+			return -1;
+		}
+
+		f = hashfd(get_tempfile_fd(incr), get_tempfile_path(incr));
+	} else {
+		hold_lock_file_for_update(&lk, midx_name.buf, LOCK_DIE_ON_ERROR);
+		f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
+	}
+
 	cf = init_chunkfile(f);
 
 	add_chunk(cf, MIDX_CHUNKID_PACKNAMES, pack_name_concat_len,
@@ -1249,14 +1422,55 @@ static int write_midx_internal(const char *object_dir,
 	 * have been freed in the previous if block.
 	 */
 
-	if (ctx.m)
+	CALLOC_ARRAY(keep_hashes, ctx.num_multi_pack_indexes_before + 1);
+
+	if (ctx.incremental) {
+		FILE *chainf = fdopen_lock_file(&lk, "w");
+		struct strbuf final_midx_name = STRBUF_INIT;
+		struct multi_pack_index *m = ctx.base_midx;
+
+		if (!chainf) {
+			error_errno(_("unable to open multi-pack-index chain file"));
+			return -1;
+		}
+
+		if (link_midx_to_chain(ctx.base_midx) < 0)
+			return -1;
+
+		get_split_midx_filename_ext(&final_midx_name, object_dir,
+					    midx_hash, MIDX_EXT_MIDX);
+
+		if (rename_tempfile(&incr, final_midx_name.buf) < 0) {
+			error_errno(_("unable to rename new multi-pack-index layer"));
+			return -1;
+		}
+
+		keep_hashes[ctx.num_multi_pack_indexes_before] =
+			xstrdup(hash_to_hex(midx_hash));
+
+		for (i = 0; i < ctx.num_multi_pack_indexes_before; i++) {
+			uint32_t j = ctx.num_multi_pack_indexes_before - i - 1;
+
+			keep_hashes[j] = xstrdup(hash_to_hex(get_midx_checksum(m)));
+			m = m->base_midx;
+		}
+
+		for (i = 0; i < ctx.num_multi_pack_indexes_before + 1; i++)
+			fprintf(get_lock_file_fp(&lk), "%s\n", keep_hashes[i]);
+	} else {
+		keep_hashes[ctx.num_multi_pack_indexes_before] =
+			xstrdup(hash_to_hex(midx_hash));
+	}
+
+	if (ctx.m || ctx.base_midx)
 		close_object_store(the_repository->objects);
 
 	if (commit_lock_file(&lk) < 0)
 		die_errno(_("could not write multi-pack-index"));
 
-	clear_midx_files_ext(object_dir, ".bitmap", midx_hash);
-	clear_midx_files_ext(object_dir, ".rev", midx_hash);
+	clear_midx_files(object_dir, keep_hashes,
+			 ctx.num_multi_pack_indexes_before + 1,
+			 ctx.incremental);
 
 cleanup:
 	for (i = 0; i < ctx.nr; i++) {
@@ -1271,6 +1485,11 @@ static int write_midx_internal(const char *object_dir,
 	free(ctx.entries);
 	free(ctx.pack_perm);
 	free(ctx.pack_order);
+	if (keep_hashes) {
+		for (i = 0; i < ctx.num_multi_pack_indexes_before + 1; i++)
+			free((char *)keep_hashes[i]);
+		free(keep_hashes);
+	}
 	strbuf_release(&midx_name);
 
 	trace2_region_leave("midx", "write_midx_internal", the_repository);
@@ -1307,6 +1526,9 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla
 	if (!m)
 		return 0;
 
+	if (m->base_midx)
+		die(_("cannot expire packs from an incremental multi-pack-index"));
+
 	CALLOC_ARRAY(count, m->num_packs);
 
 	if (flags & MIDX_PROGRESS)
@@ -1481,6 +1703,8 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size,
 
 	if (!m)
 		return 0;
+	if (m->base_midx)
+		die(_("cannot repack an incremental multi-pack-index"));
 
 	CALLOC_ARRAY(include_pack, m->num_packs);
 
diff --git a/midx.c b/midx.c
index 3992b05..67e0d64 100644
--- a/midx.c
+++ b/midx.c
@@ -16,7 +16,10 @@
 
 int midx_checksum_valid(struct multi_pack_index *m);
 void clear_midx_files_ext(const char *object_dir, const char *ext,
-			  unsigned char *keep_hash);
+			  const char *keep_hash);
+void clear_incremental_midx_files_ext(const char *object_dir, const char *ext,
+				      char **keep_hashes,
+				      uint32_t hashes_nr);
 int cmp_idx_or_pack_name(const char *idx_or_pack_name,
 			 const char *idx_name);
 
@@ -91,7 +94,9 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,
 
 #define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz)
 
-struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local)
+static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir,
+							  const char *midx_name,
+							  int local)
 {
 	struct multi_pack_index *m = NULL;
 	int fd;
@@ -99,31 +104,26 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
 	size_t midx_size;
 	void *midx_map = NULL;
 	uint32_t hash_version;
-	struct strbuf midx_name = STRBUF_INIT;
 	uint32_t i;
 	const char *cur_pack_name;
 	struct chunkfile *cf = NULL;
 
-	get_midx_filename(&midx_name, object_dir);
-
-	fd = git_open(midx_name.buf);
+	fd = git_open(midx_name);
 
 	if (fd < 0)
 		goto cleanup_fail;
 	if (fstat(fd, &st)) {
-		error_errno(_("failed to read %s"), midx_name.buf);
+		error_errno(_("failed to read %s"), midx_name);
 		goto cleanup_fail;
 	}
 
 	midx_size = xsize_t(st.st_size);
 
 	if (midx_size < MIDX_MIN_SIZE) {
-		error(_("multi-pack-index file %s is too small"), midx_name.buf);
+		error(_("multi-pack-index file %s is too small"), midx_name);
 		goto cleanup_fail;
 	}
 
-	strbuf_release(&midx_name);
-
 	midx_map = xmmap(NULL, midx_size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
 
@@ -213,7 +213,6 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
 
 cleanup_fail:
 	free(m);
-	strbuf_release(&midx_name);
 	free_chunkfile(cf);
 	if (midx_map)
 		munmap(midx_map, midx_size);
@@ -222,6 +221,169 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
 	return NULL;
 }
 
+void get_midx_chain_dirname(struct strbuf *buf, const char *object_dir)
+{
+	strbuf_addf(buf, "%s/pack/multi-pack-index.d", object_dir);
+}
+
+void get_midx_chain_filename(struct strbuf *buf, const char *object_dir)
+{
+	get_midx_chain_dirname(buf, object_dir);
+	strbuf_addstr(buf, "/multi-pack-index-chain");
+}
+
+void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir,
+				 const unsigned char *hash, const char *ext)
+{
+	get_midx_chain_dirname(buf, object_dir);
+	strbuf_addf(buf, "/multi-pack-index-%s.%s", hash_to_hex(hash), ext);
+}
+
+static int open_multi_pack_index_chain(const char *chain_file,
+				       int *fd, struct stat *st)
+{
+	*fd = git_open(chain_file);
+	if (*fd < 0)
+		return 0;
+	if (fstat(*fd, st)) {
+		close(*fd);
+		return 0;
+	}
+	if (st->st_size < the_hash_algo->hexsz) {
+		close(*fd);
+		if (!st->st_size) {
+			/* treat empty files the same as missing */
+			errno = ENOENT;
+		} else {
+			warning(_("multi-pack-index chain file too small"));
+			errno = EINVAL;
+		}
+		return 0;
+	}
+	return 1;
+}
+
+static int add_midx_to_chain(struct multi_pack_index *midx,
+			     struct multi_pack_index *midx_chain)
+{
+	if (midx_chain) {
+		if (unsigned_add_overflows(midx_chain->num_packs,
+					   midx_chain->num_packs_in_base)) {
+			warning(_("pack count in base MIDX too high: %"PRIuMAX),
+				(uintmax_t)midx_chain->num_packs_in_base);
+			return 0;
+		}
+		if (unsigned_add_overflows(midx_chain->num_objects,
+					   midx_chain->num_objects_in_base)) {
+			warning(_("object count in base MIDX too high: %"PRIuMAX),
+				(uintmax_t)midx_chain->num_objects_in_base);
+			return 0;
+		}
+		midx->num_packs_in_base = midx_chain->num_packs +
+			midx_chain->num_packs_in_base;
+		midx->num_objects_in_base = midx_chain->num_objects +
+			midx_chain->num_objects_in_base;
+	}
+
+	midx->base_midx = midx_chain;
+	midx->has_chain = 1;
+
+	return 1;
+}
+
+static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir,
+						      int local,
+						      int fd, struct stat *st,
+						      int *incomplete_chain)
+{
+	struct multi_pack_index *midx_chain = NULL;
+	struct strbuf buf = STRBUF_INIT;
+	int valid = 1;
+	uint32_t i, count;
+	FILE *fp = xfdopen(fd, "r");
+
+	count = st->st_size / (the_hash_algo->hexsz + 1);
+
+	for (i = 0; i < count; i++) {
+		struct multi_pack_index *m;
+		struct object_id layer;
+
+		if (strbuf_getline_lf(&buf, fp) == EOF)
+			break;
+
+		if (get_oid_hex(buf.buf, &layer)) {
+			warning(_("invalid multi-pack-index chain: line '%s' "
+				  "not a hash"),
+				buf.buf);
+			valid = 0;
+			break;
+		}
+
+		valid = 0;
+
+		strbuf_reset(&buf);
+		get_split_midx_filename_ext(&buf, object_dir, layer.hash,
+					    MIDX_EXT_MIDX);
+		m = load_multi_pack_index_one(object_dir, buf.buf, local);
+
+		if (m) {
+			if (add_midx_to_chain(m, midx_chain)) {
+				midx_chain = m;
+				valid = 1;
+			} else {
+				close_midx(m);
+			}
+		}
+		if (!valid) {
+			warning(_("unable to find all multi-pack index files"));
+			break;
+		}
+	}
+
+	fclose(fp);
+	strbuf_release(&buf);
+
+	*incomplete_chain = !valid;
+	return midx_chain;
+}
+
+static struct multi_pack_index *load_multi_pack_index_chain(const char *object_dir,
+							    int local)
+{
+	struct strbuf chain_file = STRBUF_INIT;
+	struct stat st;
+	int fd;
+	struct multi_pack_index *m = NULL;
+
+	get_midx_chain_filename(&chain_file, object_dir);
+	if (open_multi_pack_index_chain(chain_file.buf, &fd, &st)) {
+		int incomplete;
+		/* ownership of fd is taken over by load function */
+		m = load_midx_chain_fd_st(object_dir, local, fd, &st,
+					  &incomplete);
+	}
+
+	strbuf_release(&chain_file);
+	return m;
+}
+
+struct multi_pack_index *load_multi_pack_index(const char *object_dir,
+					       int local)
+{
+	struct strbuf midx_name = STRBUF_INIT;
+	struct multi_pack_index *m;
+
+	get_midx_filename(&midx_name, object_dir);
+
+	m = load_multi_pack_index_one(object_dir, midx_name.buf, local);
+	if (!m)
+		m = load_multi_pack_index_chain(object_dir, local);
+
+	strbuf_release(&midx_name);
+
+	return m;
+}
+
 void close_midx(struct multi_pack_index *m)
 {
 	uint32_t i;
@@ -230,6 +392,7 @@ void close_midx(struct multi_pack_index *m)
 		return;
 
 	close_midx(m->next);
+	close_midx(m->base_midx);
 
 	munmap((unsigned char *)m->data, m->data_len);
 
@@ -242,14 +405,49 @@ void close_midx(struct multi_pack_index *m)
 	free(m);
 }
 
-int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id)
+static uint32_t midx_for_object(struct multi_pack_index **_m, uint32_t pos)
+{
+	struct multi_pack_index *m = *_m;
+	while (m && pos < m->num_objects_in_base)
+		m = m->base_midx;
+
+	if (!m)
+		BUG("NULL multi-pack-index for object position: %"PRIu32, pos);
+
+	if (pos >= m->num_objects + m->num_objects_in_base)
+		die(_("invalid MIDX object position, MIDX is likely corrupt"));
+
+	*_m = m;
+
+	return pos - m->num_objects_in_base;
+}
+
+static uint32_t midx_for_pack(struct multi_pack_index **_m,
+			      uint32_t pack_int_id)
+{
+	struct multi_pack_index *m = *_m;
+	while (m && pack_int_id < m->num_packs_in_base)
+		m = m->base_midx;
+
+	if (!m)
+		BUG("NULL multi-pack-index for pack ID: %"PRIu32, pack_int_id);
+
+	if (pack_int_id >= m->num_packs + m->num_packs_in_base)
+		die(_("bad pack-int-id: %u (%u total packs)"),
+		    pack_int_id, m->num_packs + m->num_packs_in_base);
+
+	*_m = m;
+
+	return pack_int_id - m->num_packs_in_base;
+}
+
+int prepare_midx_pack(struct repository *r, struct multi_pack_index *m,
+		      uint32_t pack_int_id)
 {
 	struct strbuf pack_name = STRBUF_INIT;
 	struct packed_git *p;
 
-	if (pack_int_id >= m->num_packs)
-		die(_("bad pack-int-id: %u (%u total packs)"),
-		    pack_int_id, m->num_packs);
+	pack_int_id = midx_for_pack(&m, pack_int_id);
 
 	if (m->packs[pack_int_id])
 		return 0;
@@ -271,41 +469,72 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t
 	return 0;
 }
 
+struct packed_git *nth_midxed_pack(struct multi_pack_index *m,
+				   uint32_t pack_int_id)
+{
+	uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id);
+	return m->packs[local_pack_int_id];
+}
+
 #define MIDX_CHUNK_BITMAPPED_PACKS_WIDTH (2 * sizeof(uint32_t))
 
 int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m,
 		       struct bitmapped_pack *bp, uint32_t pack_int_id)
 {
+	uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id);
+
 	if (!m->chunk_bitmapped_packs)
 		return error(_("MIDX does not contain the BTMP chunk"));
 
 	if (prepare_midx_pack(r, m, pack_int_id))
 		return error(_("could not load bitmapped pack %"PRIu32), pack_int_id);
 
-	bp->p = m->packs[pack_int_id];
+	bp->p = m->packs[local_pack_int_id];
 	bp->bitmap_pos = get_be32((char *)m->chunk_bitmapped_packs +
-				  MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * pack_int_id);
+				  MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * local_pack_int_id);
 	bp->bitmap_nr = get_be32((char *)m->chunk_bitmapped_packs +
-				 MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * pack_int_id +
+				 MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * local_pack_int_id +
 				 sizeof(uint32_t));
 	bp->pack_int_id = pack_int_id;
+	bp->from_midx = m;
 
 	return 0;
 }
 
-int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result)
+int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m,
+		     uint32_t *result)
 {
-	return bsearch_hash(oid->hash, m->chunk_oid_fanout, m->chunk_oid_lookup,
-			    the_hash_algo->rawsz, result);
+	int ret = bsearch_hash(oid->hash, m->chunk_oid_fanout,
+			       m->chunk_oid_lookup, the_hash_algo->rawsz,
+			       result);
+	if (result)
+		*result += m->num_objects_in_base;
+	return ret;
+}
+
+int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m,
+		 uint32_t *result)
+{
+	for (; m; m = m->base_midx)
+		if (bsearch_one_midx(oid, m, result))
+			return 1;
+	return 0;
+}
+
+int midx_has_oid(struct multi_pack_index *m, const struct object_id *oid)
+{
+	return bsearch_midx(oid, m, NULL);
 }
 
 struct object_id *nth_midxed_object_oid(struct object_id *oid,
 					struct multi_pack_index *m,
 					uint32_t n)
 {
-	if (n >= m->num_objects)
+	if (n >= m->num_objects + m->num_objects_in_base)
 		return NULL;
 
+	n = midx_for_object(&m, n);
+
 	oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n),
 		the_repository->hash_algo);
 	return oid;
@@ -316,6 +545,8 @@ off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
 	const unsigned char *offset_data;
 	uint32_t offset32;
 
+	pos = midx_for_object(&m, pos);
+
 	offset_data = m->chunk_object_offsets + (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH;
 	offset32 = get_be32(offset_data + sizeof(uint32_t));
 
@@ -334,8 +565,10 @@ off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
 
 uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos)
 {
-	return get_be32(m->chunk_object_offsets +
-			(off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
+	pos = midx_for_object(&m, pos);
+
+	return m->num_packs_in_base + get_be32(m->chunk_object_offsets +
+					       (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
 }
 
 int fill_midx_entry(struct repository *r,
@@ -350,14 +583,12 @@ int fill_midx_entry(struct repository *r,
 	if (!bsearch_midx(oid, m, &pos))
 		return 0;
 
-	if (pos >= m->num_objects)
-		return 0;
-
+	midx_for_object(&m, pos);
 	pack_int_id = nth_midxed_pack_int_id(m, pos);
 
 	if (prepare_midx_pack(r, m, pack_int_id))
 		return 0;
-	p = m->packs[pack_int_id];
+	p = m->packs[pack_int_id - m->num_packs_in_base];
 
 	/*
 	* We are about to tell the caller where they can locate the
@@ -411,8 +642,8 @@ int cmp_idx_or_pack_name(const char *idx_or_pack_name,
 	return strcmp(idx_or_pack_name, idx_name);
 }
 
-int midx_locate_pack(struct multi_pack_index *m, const char *idx_or_pack_name,
-		     uint32_t *pos)
+static int midx_contains_pack_1(struct multi_pack_index *m,
+				const char *idx_or_pack_name)
 {
 	uint32_t first = 0, last = m->num_packs;
 
@@ -423,11 +654,8 @@ int midx_locate_pack(struct multi_pack_index *m, const char *idx_or_pack_name,
 
 		current = m->pack_names[mid];
 		cmp = cmp_idx_or_pack_name(idx_or_pack_name, current);
-		if (!cmp) {
-			if (pos)
-				*pos = mid;
+		if (!cmp)
 			return 1;
-		}
 		if (cmp > 0) {
 			first = mid + 1;
 			continue;
@@ -440,19 +668,25 @@ int midx_locate_pack(struct multi_pack_index *m, const char *idx_or_pack_name,
 
 int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name)
 {
-	return midx_locate_pack(m, idx_or_pack_name, NULL);
+	for (; m; m = m->base_midx)
+		if (midx_contains_pack_1(m, idx_or_pack_name))
+			return 1;
+	return 0;
 }
 
 int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id)
 {
 	if (m->preferred_pack_idx == -1) {
+		uint32_t midx_pos;
 		if (load_midx_revindex(m) < 0) {
 			m->preferred_pack_idx = -2;
 			return -1;
 		}
 
-		m->preferred_pack_idx =
-			nth_midxed_pack_int_id(m, pack_pos_to_midx(m, 0));
+		midx_pos = pack_pos_to_midx(m, m->num_objects_in_base);
+
+		m->preferred_pack_idx = nth_midxed_pack_int_id(m, midx_pos);
+
 	} else if (m->preferred_pack_idx == -2)
 		return -1; /* no revindex */
 
@@ -494,7 +728,8 @@ int midx_checksum_valid(struct multi_pack_index *m)
 }
 
 struct clear_midx_data {
-	char *keep;
+	char **keep;
+	uint32_t keep_nr;
 	const char *ext;
 };
 
@@ -502,32 +737,63 @@ static void clear_midx_file_ext(const char *full_path, size_t full_path_len UNUS
 				const char *file_name, void *_data)
 {
 	struct clear_midx_data *data = _data;
+	uint32_t i;
 
 	if (!(starts_with(file_name, "multi-pack-index-") &&
 	      ends_with(file_name, data->ext)))
 		return;
-	if (data->keep && !strcmp(data->keep, file_name))
-		return;
-
+	for (i = 0; i < data->keep_nr; i++) {
+		if (!strcmp(data->keep[i], file_name))
+			return;
+	}
 	if (unlink(full_path))
 		die_errno(_("failed to remove %s"), full_path);
 }
 
 void clear_midx_files_ext(const char *object_dir, const char *ext,
-			  unsigned char *keep_hash)
+			  const char *keep_hash)
 {
 	struct clear_midx_data data;
 	memset(&data, 0, sizeof(struct clear_midx_data));
 
-	if (keep_hash)
-		data.keep = xstrfmt("multi-pack-index-%s%s",
-				    hash_to_hex(keep_hash), ext);
+	if (keep_hash) {
+		ALLOC_ARRAY(data.keep, 1);
+
+		data.keep[0] = xstrfmt("multi-pack-index-%s.%s", keep_hash, ext);
+		data.keep_nr = 1;
+	}
 	data.ext = ext;
 
 	for_each_file_in_pack_dir(object_dir,
 				  clear_midx_file_ext,
 				  &data);
 
+	if (keep_hash)
+		free(data.keep[0]);
+	free(data.keep);
+}
+
+void clear_incremental_midx_files_ext(const char *object_dir, const char *ext,
+				      char **keep_hashes,
+				      uint32_t hashes_nr)
+{
+	struct clear_midx_data data;
+	uint32_t i;
+
+	memset(&data, 0, sizeof(struct clear_midx_data));
+
+	ALLOC_ARRAY(data.keep, hashes_nr);
+	for (i = 0; i < hashes_nr; i++)
+		data.keep[i] = xstrfmt("multi-pack-index-%s.%s", keep_hashes[i],
+				       ext);
+	data.keep_nr = hashes_nr;
+	data.ext = ext;
+
+	for_each_file_in_pack_subdir(object_dir, "multi-pack-index.d",
+				     clear_midx_file_ext, &data);
+
+	for (i = 0; i < hashes_nr; i++)
+		free(data.keep[i]);
 	free(data.keep);
 }
 
@@ -545,8 +811,8 @@ void clear_midx_file(struct repository *r)
 	if (remove_path(midx.buf))
 		die(_("failed to clear multi-pack-index at %s"), midx.buf);
 
-	clear_midx_files_ext(r->objects->odb->path, ".bitmap", NULL);
-	clear_midx_files_ext(r->objects->odb->path, ".rev", NULL);
+	clear_midx_files_ext(r->objects->odb->path, MIDX_EXT_BITMAP, NULL);
+	clear_midx_files_ext(r->objects->odb->path, MIDX_EXT_REV, NULL);
 
 	strbuf_release(&midx);
 }
@@ -596,6 +862,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
 	uint32_t i;
 	struct progress *progress = NULL;
 	struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
+	struct multi_pack_index *curr;
 	verify_midx_error = 0;
 
 	if (!m) {
@@ -618,8 +885,8 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
 
 	if (flags & MIDX_PROGRESS)
 		progress = start_delayed_progress(_("Looking for referenced packfiles"),
-					  m->num_packs);
-	for (i = 0; i < m->num_packs; i++) {
+						  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))
 			midx_report("failed to load pack in position %d", i);
 
@@ -639,17 +906,20 @@ 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"),
 						 m->num_objects - 1);
-	for (i = 0; i < m->num_objects - 1; i++) {
-		struct object_id oid1, oid2;
 
-		nth_midxed_object_oid(&oid1, m, i);
-		nth_midxed_object_oid(&oid2, m, i + 1);
+	for (curr = m; curr; curr = curr->base_midx) {
+		for (i = 0; i < m->num_objects - 1; i++) {
+			struct object_id oid1, oid2;
 
-		if (oidcmp(&oid1, &oid2) >= 0)
-			midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"),
-				    i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1);
+			nth_midxed_object_oid(&oid1, m, m->num_objects_in_base + i);
+			nth_midxed_object_oid(&oid2, m, m->num_objects_in_base + i + 1);
 
-		midx_display_sparse_progress(progress, i + 1);
+			if (oidcmp(&oid1, &oid2) >= 0)
+				midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"),
+					    i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1);
+
+			midx_display_sparse_progress(progress, i + 1);
+		}
 	}
 	stop_progress(&progress);
 
@@ -659,8 +929,8 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
 	 * each of the objects and only require 1 packfile to be open at a
 	 * time.
 	 */
-	ALLOC_ARRAY(pairs, m->num_objects);
-	for (i = 0; i < m->num_objects; i++) {
+	ALLOC_ARRAY(pairs, m->num_objects + m->num_objects_in_base);
+	for (i = 0; i < m->num_objects + m->num_objects_in_base; i++) {
 		pairs[i].pos = i;
 		pairs[i].pack_int_id = nth_midxed_pack_int_id(m, i);
 	}
@@ -674,16 +944,18 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
 
 	if (flags & MIDX_PROGRESS)
 		progress = start_sparse_progress(_("Verifying object offsets"), m->num_objects);
-	for (i = 0; i < m->num_objects; i++) {
+	for (i = 0; i < m->num_objects + m->num_objects_in_base; i++) {
 		struct object_id oid;
 		struct pack_entry e;
 		off_t m_offset, p_offset;
 
 		if (i > 0 && pairs[i-1].pack_int_id != pairs[i].pack_int_id &&
-		    m->packs[pairs[i-1].pack_int_id])
-		{
-			close_pack_fd(m->packs[pairs[i-1].pack_int_id]);
-			close_pack_index(m->packs[pairs[i-1].pack_int_id]);
+		    nth_midxed_pack(m, pairs[i-1].pack_int_id)) {
+			uint32_t pack_int_id = pairs[i-1].pack_int_id;
+			struct packed_git *p = nth_midxed_pack(m, pack_int_id);
+
+			close_pack_fd(p);
+			close_pack_index(p);
 		}
 
 		nth_midxed_object_oid(&oid, m, pairs[i].pos);
diff --git a/midx.h b/midx.h
index 8554f2d..42d4f8d 100644
--- a/midx.h
+++ b/midx.h
@@ -24,12 +24,13 @@ struct bitmapped_pack;
 #define MIDX_CHUNKID_OBJECTOFFSETS 0x4f4f4646 /* "OOFF" */
 #define MIDX_CHUNKID_LARGEOFFSETS 0x4c4f4646 /* "LOFF" */
 #define MIDX_CHUNKID_REVINDEX 0x52494458 /* "RIDX" */
+#define MIDX_CHUNKID_BASE 0x42415345 /* "BASE" */
 #define MIDX_CHUNK_OFFSET_WIDTH (2 * sizeof(uint32_t))
 #define MIDX_LARGE_OFFSET_NEEDED 0x80000000
 
 #define GIT_TEST_MULTI_PACK_INDEX "GIT_TEST_MULTI_PACK_INDEX"
-#define GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP \
-	"GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP"
+#define GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL \
+	"GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL"
 
 struct multi_pack_index {
 	struct multi_pack_index *next;
@@ -50,6 +51,7 @@ struct multi_pack_index {
 	int preferred_pack_idx;
 
 	int local;
+	int has_chain;
 
 	const unsigned char *chunk_pack_names;
 	size_t chunk_pack_names_len;
@@ -63,6 +65,10 @@ struct multi_pack_index {
 	const unsigned char *chunk_revindex;
 	size_t chunk_revindex_len;
 
+	struct multi_pack_index *base_midx;
+	uint32_t num_objects_in_base;
+	uint32_t num_packs_in_base;
+
 	const char **pack_names;
 	struct packed_git **packs;
 	char object_dir[FLEX_ARRAY];
@@ -73,20 +79,32 @@ struct multi_pack_index {
 #define MIDX_WRITE_BITMAP (1 << 2)
 #define MIDX_WRITE_BITMAP_HASH_CACHE (1 << 3)
 #define MIDX_WRITE_BITMAP_LOOKUP_TABLE (1 << 4)
+#define MIDX_WRITE_INCREMENTAL (1 << 5)
 
 #define MIDX_EXT_REV "rev"
 #define MIDX_EXT_BITMAP "bitmap"
+#define MIDX_EXT_MIDX "midx"
 
 const unsigned char *get_midx_checksum(struct multi_pack_index *m);
 void get_midx_filename(struct strbuf *out, const char *object_dir);
 void get_midx_filename_ext(struct strbuf *out, const char *object_dir,
 			   const unsigned char *hash, const char *ext);
+void get_midx_chain_dirname(struct strbuf *buf, const char *object_dir);
+void get_midx_chain_filename(struct strbuf *buf, const char *object_dir);
+void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir,
+				 const unsigned char *hash, const char *ext);
 
 struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local);
 int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id);
+struct packed_git *nth_midxed_pack(struct multi_pack_index *m,
+				   uint32_t pack_int_id);
 int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m,
 		       struct bitmapped_pack *bp, uint32_t pack_int_id);
-int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result);
+int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m,
+		     uint32_t *result);
+int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m,
+		 uint32_t *result);
+int midx_has_oid(struct multi_pack_index *m, const struct object_id *oid);
 off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos);
 uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos);
 struct object_id *nth_midxed_object_oid(struct object_id *oid,
@@ -95,8 +113,6 @@ struct object_id *nth_midxed_object_oid(struct object_id *oid,
 int fill_midx_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e, struct multi_pack_index *m);
 int midx_contains_pack(struct multi_pack_index *m,
 		       const char *idx_or_pack_name);
-int midx_locate_pack(struct multi_pack_index *m, const char *idx_or_pack_name,
-		     uint32_t *pos);
 int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id);
 int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, int local);
 
diff --git a/name-hash.c b/name-hash.c
index 3a58ce0..95528e3 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -5,6 +5,9 @@
  *
  * Copyright (C) 2008 Linus Torvalds
  */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "environment.h"
 #include "gettext.h"
diff --git a/negotiator/default.c b/negotiator/default.c
index e3fa5c3..c479da9 100644
--- a/negotiator/default.c
+++ b/negotiator/default.c
@@ -38,7 +38,7 @@ static void rev_list_push(struct negotiation_state *ns,
 	}
 }
 
-static int clear_marks(const char *refname, const struct object_id *oid,
+static int clear_marks(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 		       int flag UNUSED,
 		       void *cb_data UNUSED)
 {
diff --git a/negotiator/skipping.c b/negotiator/skipping.c
index f109928..abedb70 100644
--- a/negotiator/skipping.c
+++ b/negotiator/skipping.c
@@ -75,7 +75,7 @@ static struct entry *rev_list_push(struct data *data, struct commit *commit, int
 	return entry;
 }
 
-static int clear_marks(const char *refname, const struct object_id *oid,
+static int clear_marks(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 		       int flag UNUSED,
 		       void *cb_data UNUSED)
 {
@@ -239,7 +239,7 @@ static int ack(struct fetch_negotiator *n, struct commit *c)
 {
 	int known_to_be_common = !!(c->object.flags & COMMON);
 	if (!(c->object.flags & SEEN))
-		die("received ack for commit %s not sent as 'have'\n",
+		die("received ack for commit %s not sent as 'have'",
 		    oid_to_hex(&c->object.oid));
 	mark_common(n->data, c);
 	return known_to_be_common;
@@ -247,8 +247,11 @@ static int ack(struct fetch_negotiator *n, struct commit *c)
 
 static void release(struct fetch_negotiator *n)
 {
-	clear_prio_queue(&((struct data *)n->data)->rev_list);
-	FREE_AND_NULL(n->data);
+	struct data *data = n->data;
+	for (int i = 0; i < data->rev_list.nr; i++)
+		free(data->rev_list.array[i].data);
+	clear_prio_queue(&data->rev_list);
+	FREE_AND_NULL(data);
 }
 
 void skipping_negotiator_init(struct fetch_negotiator *negotiator)
diff --git a/notes.c b/notes.c
index 1ba6412..f4f18da 100644
--- a/notes.c
+++ b/notes.c
@@ -932,7 +932,7 @@ int combine_notes_cat_sort_uniq(struct object_id *cur_oid,
 	return ret;
 }
 
-static int string_list_add_one_ref(const char *refname,
+static int string_list_add_one_ref(const char *refname, const char *referent UNUSED,
 				   const struct object_id *oid UNUSED,
 				   int flag UNUSED, void *cb)
 {
@@ -992,15 +992,16 @@ static int notes_display_config(const char *k, const char *v,
 	return 0;
 }
 
-const char *default_notes_ref(void)
+char *default_notes_ref(struct repository *repo)
 {
-	const char *notes_ref = NULL;
+	char *notes_ref = NULL;
+
 	if (!notes_ref)
-		notes_ref = getenv(GIT_NOTES_REF_ENVIRONMENT);
+		notes_ref = xstrdup_or_null(getenv(GIT_NOTES_REF_ENVIRONMENT));
 	if (!notes_ref)
-		notes_ref = notes_ref_name; /* value of core.notesRef config */
+		repo_config_get_string(repo, "core.notesref", &notes_ref);
 	if (!notes_ref)
-		notes_ref = GIT_NOTES_DEFAULT_REF;
+		notes_ref = xstrdup(GIT_NOTES_DEFAULT_REF);
 	return notes_ref;
 }
 
@@ -1010,13 +1011,14 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 	struct object_id oid, object_oid;
 	unsigned short mode;
 	struct leaf_node root_tree;
+	char *to_free = NULL;
 
 	if (!t)
 		t = &default_notes_tree;
 	assert(!t->initialized);
 
 	if (!notes_ref)
-		notes_ref = default_notes_ref();
+		notes_ref = to_free = default_notes_ref(the_repository);
 	update_ref_namespace(NAMESPACE_NOTES, xstrdup(notes_ref));
 
 	if (!combine_notes)
@@ -1033,7 +1035,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 
 	if (flags & NOTES_INIT_EMPTY ||
 	    repo_get_oid_treeish(the_repository, notes_ref, &object_oid))
-		return;
+		goto out;
 	if (flags & NOTES_INIT_WRITABLE && refs_read_ref(get_main_ref_store(the_repository), notes_ref, &object_oid))
 		die("Cannot use notes ref %s", notes_ref);
 	if (get_tree_entry(the_repository, &object_oid, "", &oid, &mode))
@@ -1043,6 +1045,9 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 	oidclr(&root_tree.key_oid, the_repository->hash_algo);
 	oidcpy(&root_tree.val_oid, &oid);
 	load_subtree(t, &root_tree, t->root, 0);
+
+out:
+	free(to_free);
 }
 
 struct notes_tree **load_notes_trees(struct string_list *refs, int flags)
@@ -1105,7 +1110,7 @@ void load_display_notes(struct display_notes_opt *opt)
 
 	if (!opt || opt->use_default_notes > 0 ||
 	    (opt->use_default_notes == -1 && !opt->extra_notes_refs.nr)) {
-		string_list_append(&display_notes_refs, default_notes_ref());
+		string_list_append_nodup(&display_notes_refs, default_notes_ref(the_repository));
 		display_ref_env = getenv(GIT_NOTES_DISPLAY_REF_ENVIRONMENT);
 		if (display_ref_env) {
 			string_list_add_refs_from_colon_sep(&display_notes_refs,
diff --git a/notes.h b/notes.h
index 2352169..6dc6d7b 100644
--- a/notes.h
+++ b/notes.h
@@ -4,6 +4,7 @@
 #include "string-list.h"
 
 struct object_id;
+struct repository;
 struct strbuf;
 
 /*
@@ -70,7 +71,7 @@ extern struct notes_tree {
  * 3. The value of the core.notesRef config variable, if set
  * 4. GIT_NOTES_DEFAULT_REF (i.e. "refs/notes/commits")
  */
-const char *default_notes_ref(void);
+char *default_notes_ref(struct repository *repo);
 
 /*
  * Flags controlling behaviour of notes tree initialization
diff --git a/object-file.c b/object-file.c
index 065103b..b1a3463 100644
--- a/object-file.c
+++ b/object-file.c
@@ -115,6 +115,33 @@ static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)
 	oid->algo = GIT_HASH_SHA1;
 }
 
+static void git_hash_sha1_init_unsafe(git_hash_ctx *ctx)
+{
+	git_SHA1_Init_unsafe(&ctx->sha1_unsafe);
+}
+
+static void git_hash_sha1_clone_unsafe(git_hash_ctx *dst, const git_hash_ctx *src)
+{
+	git_SHA1_Clone_unsafe(&dst->sha1_unsafe, &src->sha1_unsafe);
+}
+
+static void git_hash_sha1_update_unsafe(git_hash_ctx *ctx, const void *data,
+				      size_t len)
+{
+	git_SHA1_Update_unsafe(&ctx->sha1_unsafe, data, len);
+}
+
+static void git_hash_sha1_final_unsafe(unsigned char *hash, git_hash_ctx *ctx)
+{
+	git_SHA1_Final_unsafe(hash, &ctx->sha1_unsafe);
+}
+
+static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, git_hash_ctx *ctx)
+{
+	git_SHA1_Final_unsafe(oid->hash, &ctx->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)
 {
@@ -189,6 +216,11 @@ 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,
@@ -204,6 +236,11 @@ 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,
 		.empty_tree = &empty_tree_oid,
 		.empty_blob = &empty_blob_oid,
 		.null_oid = &null_oid_sha1,
@@ -219,6 +256,11 @@ 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,
@@ -419,6 +461,39 @@ enum scld_error safe_create_leading_directories_const(const char *path)
 	return result;
 }
 
+int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
+{
+	int fd;
+	/*
+	 * we let the umask do its job, don't try to be more
+	 * restrictive except to remove write permission.
+	 */
+	int mode = 0444;
+	git_path_buf(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);
+	safe_create_leading_directories(temp_filename->buf);
+	return xmkstemp_mode(temp_filename->buf, mode);
+}
+
+int odb_pack_keep(const char *name)
+{
+	int fd;
+
+	fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
+	if (0 <= fd)
+		return fd;
+
+	/* slow path */
+	safe_create_leading_directories_const(name);
+	return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
+}
+
 static void fill_loose_path(struct strbuf *buf, const struct object_id *oid)
 {
 	int i;
@@ -1899,17 +1974,77 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo
 	hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen);
 }
 
+static int check_collision(const char *filename_a, const char *filename_b)
+{
+	char buf_a[4096], buf_b[4096];
+	int fd_a = -1, fd_b = -1;
+	int ret = 0;
+
+	fd_a = open(filename_a, O_RDONLY);
+	if (fd_a < 0) {
+		ret = error_errno(_("unable to open %s"), filename_a);
+		goto out;
+	}
+
+	fd_b = open(filename_b, O_RDONLY);
+	if (fd_b < 0) {
+		ret = error_errno(_("unable to open %s"), filename_b);
+		goto out;
+	}
+
+	while (1) {
+		ssize_t sz_a, sz_b;
+
+		sz_a = read_in_full(fd_a, buf_a, sizeof(buf_a));
+		if (sz_a < 0) {
+			ret = error_errno(_("unable to read %s"), filename_a);
+			goto out;
+		}
+
+		sz_b = read_in_full(fd_b, buf_b, sizeof(buf_b));
+		if (sz_b < 0) {
+			ret = error_errno(_("unable to read %s"), filename_b);
+			goto out;
+		}
+
+		if (sz_a != sz_b || memcmp(buf_a, buf_b, sz_a)) {
+			ret = error(_("files '%s' and '%s' differ in contents"),
+				    filename_a, filename_b);
+			goto out;
+		}
+
+		if (sz_a < sizeof(buf_a))
+			break;
+	}
+
+out:
+	if (fd_a > -1)
+		close(fd_a);
+	if (fd_b > -1)
+		close(fd_b);
+	return ret;
+}
+
 /*
  * Move the just written object into its final resting place.
  */
 int finalize_object_file(const char *tmpfile, const char *filename)
 {
+	return finalize_object_file_flags(tmpfile, filename, 0);
+}
+
+int finalize_object_file_flags(const char *tmpfile, const char *filename,
+			       enum finalize_object_file_flags flags)
+{
+	struct stat st;
 	int ret = 0;
 
 	if (object_creation_mode == OBJECT_CREATION_USES_RENAMES)
 		goto try_rename;
 	else if (link(tmpfile, filename))
 		ret = errno;
+	else
+		unlink_or_warn(tmpfile);
 
 	/*
 	 * Coda hack - coda doesn't like cross-directory links,
@@ -1924,16 +2059,24 @@ int finalize_object_file(const char *tmpfile, const char *filename)
 	 */
 	if (ret && ret != EEXIST) {
 	try_rename:
-		if (!rename(tmpfile, filename))
+		if (!stat(filename, &st))
+			ret = EEXIST;
+		else if (!rename(tmpfile, filename))
 			goto out;
-		ret = errno;
+		else
+			ret = errno;
 	}
-	unlink_or_warn(tmpfile);
 	if (ret) {
 		if (ret != EEXIST) {
+			int saved_errno = errno;
+			unlink_or_warn(tmpfile);
+			errno = saved_errno;
 			return error_errno(_("unable to write file %s"), filename);
 		}
-		/* FIXME!!! Collision check here ? */
+		if (!(flags & FOF_SKIP_COLLISION_CHECK) &&
+		    check_collision(tmpfile, filename))
+				return -1;
+		unlink_or_warn(tmpfile);
 	}
 
 out:
@@ -2053,7 +2196,7 @@ static int start_loose_object_common(struct strbuf *tmp_file,
 		else if (errno == EACCES)
 			return error(_("insufficient permission for adding "
 				       "an object to repository database %s"),
-				     get_object_directory());
+				     repo_get_object_directory(the_repository));
 		else
 			return error_errno(
 				_("unable to create temporary file"));
@@ -2186,7 +2329,8 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
 			warning_errno(_("failed utime() on %s"), tmp_file.buf);
 	}
 
-	return finalize_object_file(tmp_file.buf, filename.buf);
+	return finalize_object_file_flags(tmp_file.buf, filename.buf,
+					  FOF_SKIP_COLLISION_CHECK);
 }
 
 static int freshen_loose_object(const struct object_id *oid)
@@ -2228,7 +2372,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
 		prepare_loose_object_bulk_checkin();
 
 	/* Since oid is not determined, save tmp file to odb path. */
-	strbuf_addf(&filename, "%s/", get_object_directory());
+	strbuf_addf(&filename, "%s/", repo_get_object_directory(the_repository));
 	hdrlen = format_object_header(hdr, sizeof(hdr), OBJ_BLOB, len);
 
 	/*
@@ -2275,7 +2419,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
 
 	/*
 	 * Common steps for write_loose_object and stream_loose_object to
-	 * end writing loose oject:
+	 * end writing loose object:
 	 *
 	 *  - End the compression of zlib stream.
 	 *  - Get the calculated oid.
@@ -2308,7 +2452,8 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
 		strbuf_release(&dir);
 	}
 
-	err = finalize_object_file(tmp_file.buf, filename.buf);
+	err = finalize_object_file_flags(tmp_file.buf, filename.buf,
+					 FOF_SKIP_COLLISION_CHECK);
 	if (!err && compat)
 		err = repo_add_loose_object_map(the_repository, oid, &compat_oid);
 cleanup:
@@ -2470,11 +2615,10 @@ int repo_has_object_file(struct repository *r,
  * give more context.
  */
 static int hash_format_check_report(struct fsck_options *opts UNUSED,
-				     const struct object_id *oid UNUSED,
-				     enum object_type object_type UNUSED,
-				     enum fsck_msg_type msg_type UNUSED,
-				     enum fsck_msg_id msg_id UNUSED,
-				     const char *message)
+				    void *fsck_report UNUSED,
+				    enum fsck_msg_type msg_type UNUSED,
+				    enum fsck_msg_id msg_id UNUSED,
+				    const char *message)
 {
 	error(_("object fails fsck: %s"), message);
 	return 1;
@@ -2954,6 +3098,7 @@ int read_loose_object(const char *path,
 	if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr),
 				NULL) != ULHR_OK) {
 		error(_("unable to unpack header of %s"), path);
+		git_inflate_end(&stream);
 		goto out;
 	}
 
diff --git a/object-file.h b/object-file.h
index d641461..81b30d2 100644
--- a/object-file.h
+++ b/object-file.h
@@ -117,7 +117,13 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
  */
 int stream_object_signature(struct repository *r, const struct object_id *oid);
 
+enum finalize_object_file_flags {
+	FOF_SKIP_COLLISION_CHECK = 1,
+};
+
 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);
 
 /* Helper to check and "touch" a file */
 int check_and_freshen_file(const char *fn, int freshen);
diff --git a/object-name.c b/object-name.c
index 527b853..c892fbe 100644
--- a/object-name.c
+++ b/object-name.c
@@ -20,6 +20,7 @@
 #include "pretty.h"
 #include "object-store-ll.h"
 #include "read-cache-ll.h"
+#include "repo-settings.h"
 #include "repository.h"
 #include "setup.h"
 #include "midx.h"
@@ -27,7 +28,8 @@
 #include "date.h"
 #include "object-file-convert.h"
 
-static int get_oid_oneline(struct repository *r, const char *, struct object_id *, struct commit_list *);
+static int get_oid_oneline(struct repository *r, const char *, struct object_id *,
+			   const struct commit_list *);
 
 typedef int (*disambiguate_hint_fn)(struct repository *, const struct object_id *, void *);
 
@@ -134,28 +136,32 @@ static int match_hash(unsigned len, const unsigned char *a, const unsigned char
 static void unique_in_midx(struct multi_pack_index *m,
 			   struct disambiguate_state *ds)
 {
-	uint32_t num, i, first = 0;
-	const struct object_id *current = NULL;
-	int len = ds->len > ds->repo->hash_algo->hexsz ?
-		ds->repo->hash_algo->hexsz : ds->len;
-	num = m->num_objects;
+	for (; m; m = m->base_midx) {
+		uint32_t num, i, first = 0;
+		const struct object_id *current = NULL;
+		int len = ds->len > ds->repo->hash_algo->hexsz ?
+			ds->repo->hash_algo->hexsz : ds->len;
 
-	if (!num)
-		return;
+		if (!m->num_objects)
+			continue;
 
-	bsearch_midx(&ds->bin_pfx, m, &first);
+		num = m->num_objects + m->num_objects_in_base;
 
-	/*
-	 * At this point, "first" is the location of the lowest object
-	 * with an object name that could match "bin_pfx".  See if we have
-	 * 0, 1 or more objects that actually match(es).
-	 */
-	for (i = first; i < num && !ds->ambiguous; i++) {
-		struct object_id oid;
-		current = nth_midxed_object_oid(&oid, m, i);
-		if (!match_hash(len, ds->bin_pfx.hash, current->hash))
-			break;
-		update_candidates(ds, current);
+		bsearch_one_midx(&ds->bin_pfx, m, &first);
+
+		/*
+		 * At this point, "first" is the location of the lowest
+		 * object with an object name that could match
+		 * "bin_pfx".  See if we have 0, 1 or more objects that
+		 * actually match(es).
+		 */
+		for (i = first; i < num && !ds->ambiguous; i++) {
+			struct object_id oid;
+			current = nth_midxed_object_oid(&oid, m, i);
+			if (!match_hash(len, ds->bin_pfx.hash, current->hash))
+				break;
+			update_candidates(ds, current);
+		}
 	}
 }
 
@@ -708,37 +714,40 @@ static int repo_extend_abbrev_len(struct repository *r UNUSED,
 static void find_abbrev_len_for_midx(struct multi_pack_index *m,
 				     struct min_abbrev_data *mad)
 {
-	int match = 0;
-	uint32_t num, first = 0;
-	struct object_id oid;
-	const struct object_id *mad_oid;
+	for (; m; m = m->base_midx) {
+		int match = 0;
+		uint32_t num, first = 0;
+		struct object_id oid;
+		const struct object_id *mad_oid;
 
-	if (!m->num_objects)
-		return;
+		if (!m->num_objects)
+			continue;
 
-	num = m->num_objects;
-	mad_oid = mad->oid;
-	match = bsearch_midx(mad_oid, m, &first);
+		num = m->num_objects + m->num_objects_in_base;
+		mad_oid = mad->oid;
+		match = bsearch_one_midx(mad_oid, m, &first);
 
-	/*
-	 * first is now the position in the packfile where we would insert
-	 * mad->hash if it does not exist (or the position of mad->hash if
-	 * it does exist). Hence, we consider a maximum of two objects
-	 * nearby for the abbreviation length.
-	 */
-	mad->init_len = 0;
-	if (!match) {
-		if (nth_midxed_object_oid(&oid, m, first))
-			extend_abbrev_len(&oid, mad);
-	} else if (first < num - 1) {
-		if (nth_midxed_object_oid(&oid, m, first + 1))
-			extend_abbrev_len(&oid, mad);
+		/*
+		 * first is now the position in the packfile where we
+		 * would insert mad->hash if it does not exist (or the
+		 * position of mad->hash if it does exist). Hence, we
+		 * consider a maximum of two objects nearby for the
+		 * abbreviation length.
+		 */
+		mad->init_len = 0;
+		if (!match) {
+			if (nth_midxed_object_oid(&oid, m, first))
+				extend_abbrev_len(&oid, mad);
+		} else if (first < num - 1) {
+			if (nth_midxed_object_oid(&oid, m, first + 1))
+				extend_abbrev_len(&oid, mad);
+		}
+		if (first > 0) {
+			if (nth_midxed_object_oid(&oid, m, first - 1))
+				extend_abbrev_len(&oid, mad);
+		}
+		mad->init_len = mad->cur_len;
 	}
-	if (first > 0) {
-		if (nth_midxed_object_oid(&oid, m, first - 1))
-			extend_abbrev_len(&oid, mad);
-	}
-	mad->init_len = mad->cur_len;
 }
 
 static void find_abbrev_len_for_pack(struct packed_git *p,
@@ -951,7 +960,7 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
 	int fatal = !(flags & GET_OID_QUIETLY);
 
 	if (len == r->hash_algo->hexsz && !get_oid_hex(str, oid)) {
-		if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) {
+		if (repo_settings_get_warn_ambiguous_refs(r) && warn_on_object_refname_ambiguity) {
 			refs_found = repo_dwim_ref(r, str, len, &tmp_oid, &real_ref, 0);
 			if (refs_found > 0) {
 				warning(warn_msg, len, str);
@@ -1012,7 +1021,7 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
 	if (!refs_found)
 		return -1;
 
-	if (warn_ambiguous_refs && !(flags & GET_OID_QUIETLY) &&
+	if (repo_settings_get_warn_ambiguous_refs(r) && !(flags & GET_OID_QUIETLY) &&
 	    (refs_found > 1 ||
 	     !get_short_oid(r, str, len, &tmp_oid, GET_OID_QUIETLY)))
 		warning(warn_msg, len, str);
@@ -1254,6 +1263,8 @@ static int peel_onion(struct repository *r, const char *name, int len,
 		prefix = xstrndup(sp + 1, name + len - 1 - (sp + 1));
 		commit_list_insert((struct commit *)o, &list);
 		ret = get_oid_oneline(r, prefix, oid, list);
+
+		free_commit_list(list);
 		free(prefix);
 		return ret;
 	}
@@ -1365,7 +1376,7 @@ struct handle_one_ref_cb {
 	struct commit_list **list;
 };
 
-static int handle_one_ref(const char *path, const struct object_id *oid,
+static int handle_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
 			  int flag UNUSED,
 			  void *cb_data)
 {
@@ -1388,9 +1399,10 @@ static int handle_one_ref(const char *path, const struct object_id *oid,
 
 static int get_oid_oneline(struct repository *r,
 			   const char *prefix, struct object_id *oid,
-			   struct commit_list *list)
+			   const struct commit_list *list)
 {
-	struct commit_list *backup = NULL, *l;
+	struct commit_list *copy = NULL;
+	const struct commit_list *l;
 	int found = 0;
 	int negative = 0;
 	regex_t regex;
@@ -1411,14 +1423,14 @@ static int get_oid_oneline(struct repository *r,
 
 	for (l = list; l; l = l->next) {
 		l->item->object.flags |= ONELINE_SEEN;
-		commit_list_insert(l->item, &backup);
+		commit_list_insert(l->item, &copy);
 	}
-	while (list) {
+	while (copy) {
 		const char *p, *buf;
 		struct commit *commit;
 		int matches;
 
-		commit = pop_most_recent_commit(&list, ONELINE_SEEN);
+		commit = pop_most_recent_commit(&copy, ONELINE_SEEN);
 		if (!parse_object(r, &commit->object.oid))
 			continue;
 		buf = repo_get_commit_buffer(r, commit, NULL);
@@ -1433,10 +1445,9 @@ static int get_oid_oneline(struct repository *r,
 		}
 	}
 	regfree(&regex);
-	free_commit_list(list);
-	for (l = backup; l; l = l->next)
+	for (l = list; l; l = l->next)
 		clear_commit_marks(l->item, ONELINE_SEEN);
-	free_commit_list(backup);
+	free_commit_list(copy);
 	return found ? 0 : -1;
 }
 
@@ -1762,6 +1773,7 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
 void object_context_release(struct object_context *ctx)
 {
 	free(ctx->path);
+	strbuf_release(&ctx->symlink_path);
 }
 
 /*
@@ -2024,7 +2036,10 @@ static enum get_oid_result get_oid_with_context_1(struct repository *repo,
 			refs_for_each_ref(get_main_ref_store(repo), handle_one_ref, &cb);
 			refs_head_ref(get_main_ref_store(repo), handle_one_ref, &cb);
 			commit_list_sort_by_date(&list);
-			return get_oid_oneline(repo, name + 2, oid, list);
+			ret = get_oid_oneline(repo, name + 2, oid, list);
+
+			free_commit_list(list);
+			return ret;
 		}
 		if (namelen < 3 ||
 		    name[2] != ':' ||
diff --git a/object-store-ll.h b/object-store-ll.h
index c5f2bb2..53b8e69 100644
--- a/object-store-ll.h
+++ b/object-store-ll.h
@@ -232,6 +232,21 @@ struct raw_object_store *raw_object_store_new(void);
 void raw_object_store_clear(struct raw_object_store *o);
 
 /*
+ * Create a temporary file rooted in the object database directory, or
+ * die on failure. The filename is taken from "pattern", which should have the
+ * usual "XXXXXX" trailer, and the resulting filename is written into the
+ * "template" buffer. Returns the open descriptor.
+ */
+int odb_mkstemp(struct strbuf *temp_filename, const char *pattern);
+
+/*
+ * Create a pack .keep file named "name" (which should generally be the output
+ * of odb_pack_name). Returns a file descriptor opened for writing, or -1 on
+ * error.
+ */
+int odb_pack_keep(const char *name);
+
+/*
  * Put in `buf` the name of the file in the local object database that
  * would be used to store a loose object with the specified oid.
  */
diff --git a/object.c b/object.c
index 0c0fcb7..94ea8fb 100644
--- a/object.c
+++ b/object.c
@@ -545,11 +545,12 @@ void repo_clear_commit_marks(struct repository *r, unsigned int flags)
 	}
 }
 
-struct parsed_object_pool *parsed_object_pool_new(void)
+struct parsed_object_pool *parsed_object_pool_new(struct repository *repo)
 {
 	struct parsed_object_pool *o = xmalloc(sizeof(*o));
 	memset(o, 0, sizeof(*o));
 
+	o->repo = repo;
 	o->blob_state = allocate_alloc_state();
 	o->tree_state = allocate_alloc_state();
 	o->commit_state = allocate_alloc_state();
@@ -614,11 +615,30 @@ void raw_object_store_clear(struct raw_object_store *o)
 
 	INIT_LIST_HEAD(&o->packed_git_mru);
 	close_object_store(o);
+
+	/*
+	 * `close_object_store()` only closes the packfiles, but doesn't free
+	 * them. We thus have to do this manually.
+	 */
+	for (struct packed_git *p = o->packed_git, *next; p; p = next) {
+		next = p->next;
+		free(p);
+	}
 	o->packed_git = NULL;
 
 	hashmap_clear(&o->pack_map);
 }
 
+void parsed_object_pool_reset_commit_grafts(struct parsed_object_pool *o)
+{
+	for (int i = 0; i < o->grafts_nr; i++) {
+		unparse_commit(o->repo, &o->grafts[i]->oid);
+		free(o->grafts[i]);
+	}
+	o->grafts_nr = 0;
+	o->commit_graft_prepared = 0;
+}
+
 void parsed_object_pool_clear(struct parsed_object_pool *o)
 {
 	/*
@@ -650,6 +670,7 @@ void parsed_object_pool_clear(struct parsed_object_pool *o)
 	free_commit_buffer_slab(o->buffer_slab);
 	o->buffer_slab = NULL;
 
+	parsed_object_pool_reset_commit_grafts(o);
 	clear_alloc_state(o->blob_state);
 	clear_alloc_state(o->tree_state);
 	clear_alloc_state(o->commit_state);
diff --git a/object.h b/object.h
index 0569148..17f32f1 100644
--- a/object.h
+++ b/object.h
@@ -7,6 +7,7 @@ struct buffer_slab;
 struct repository;
 
 struct parsed_object_pool {
+	struct repository *repo;
 	struct object **obj_hash;
 	int nr_objs, obj_hash_size;
 
@@ -31,8 +32,9 @@ struct parsed_object_pool {
 	struct buffer_slab *buffer_slab;
 };
 
-struct parsed_object_pool *parsed_object_pool_new(void);
+struct parsed_object_pool *parsed_object_pool_new(struct repository *repo);
 void parsed_object_pool_clear(struct parsed_object_pool *o);
+void parsed_object_pool_reset_commit_grafts(struct parsed_object_pool *o);
 
 struct object_list {
 	struct object *item;
diff --git a/oss-fuzz/dummy-cmd-main.c b/oss-fuzz/dummy-cmd-main.c
index 071cb23..8ef776d 100644
--- a/oss-fuzz/dummy-cmd-main.c
+++ b/oss-fuzz/dummy-cmd-main.c
@@ -8,7 +8,7 @@
  * executed.
  */
 
-int cmd_main(int argc, const char **argv) {
+int cmd_main(int argc UNUSED, const char **argv UNUSED) {
 	BUG("We should not execute cmd_main() from a fuzz target");
 	return 1;
 }
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
index bf96c80..4dc0fe8 100644
--- a/pack-bitmap-write.c
+++ b/pack-bitmap-write.c
@@ -41,17 +41,19 @@ static inline int bitmap_writer_nr_selected_commits(struct bitmap_writer *writer
 	return writer->selected_nr - writer->pseudo_merges_nr;
 }
 
-void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r)
+void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r,
+			struct packing_data *pdata)
 {
 	memset(writer, 0, sizeof(struct bitmap_writer));
 	if (writer->bitmaps)
 		BUG("bitmap writer already initialized");
 	writer->bitmaps = kh_init_oid_map();
 	writer->pseudo_merge_commits = kh_init_oid_map();
+	writer->to_pack = pdata;
 
 	string_list_init_dup(&writer->pseudo_merge_groups);
 
-	load_pseudo_merges_from_config(&writer->pseudo_merge_groups);
+	load_pseudo_merges_from_config(r, &writer->pseudo_merge_groups);
 }
 
 static void free_pseudo_merge_commit_idx(struct pseudo_merge_commit_idx *idx)
@@ -99,9 +101,7 @@ void bitmap_writer_show_progress(struct bitmap_writer *writer, int show)
  * Build the initial type index for the packfile or multi-pack-index
  */
 void bitmap_writer_build_type_index(struct bitmap_writer *writer,
-				    struct packing_data *to_pack,
-				    struct pack_idx_entry **index,
-				    uint32_t index_nr)
+				    struct pack_idx_entry **index)
 {
 	uint32_t i;
 
@@ -109,13 +109,13 @@ void bitmap_writer_build_type_index(struct bitmap_writer *writer,
 	writer->trees = ewah_new();
 	writer->blobs = ewah_new();
 	writer->tags = ewah_new();
-	ALLOC_ARRAY(to_pack->in_pack_pos, to_pack->nr_objects);
+	ALLOC_ARRAY(writer->to_pack->in_pack_pos, writer->to_pack->nr_objects);
 
-	for (i = 0; i < index_nr; ++i) {
+	for (i = 0; i < writer->to_pack->nr_objects; ++i) {
 		struct object_entry *entry = (struct object_entry *)index[i];
 		enum object_type real_type;
 
-		oe_set_in_pack_pos(to_pack, entry, i);
+		oe_set_in_pack_pos(writer->to_pack, entry, i);
 
 		switch (oe_type(entry)) {
 		case OBJ_COMMIT:
@@ -126,7 +126,7 @@ void bitmap_writer_build_type_index(struct bitmap_writer *writer,
 			break;
 
 		default:
-			real_type = oid_object_info(to_pack->repo,
+			real_type = oid_object_info(writer->to_pack->repo,
 						    &entry->idx.oid, NULL);
 			break;
 		}
@@ -569,8 +569,7 @@ static void store_selected(struct bitmap_writer *writer,
 	kh_value(writer->bitmaps, hash_pos) = stored;
 }
 
-int bitmap_writer_build(struct bitmap_writer *writer,
-			struct packing_data *to_pack)
+int bitmap_writer_build(struct bitmap_writer *writer)
 {
 	struct bitmap_builder bb;
 	size_t i;
@@ -581,17 +580,15 @@ int bitmap_writer_build(struct bitmap_writer *writer,
 	uint32_t *mapping;
 	int closed = 1; /* until proven otherwise */
 
-	writer->to_pack = to_pack;
-
 	if (writer->show_progress)
 		writer->progress = start_progress("Building bitmaps",
 						  writer->selected_nr);
 	trace2_region_enter("pack-bitmap-write", "building_bitmaps_total",
 			    the_repository);
 
-	old_bitmap = prepare_bitmap_git(to_pack->repo);
+	old_bitmap = prepare_bitmap_git(writer->to_pack->repo);
 	if (old_bitmap)
-		mapping = create_bitmap_mapping(old_bitmap, to_pack);
+		mapping = create_bitmap_mapping(old_bitmap, writer->to_pack);
 	else
 		mapping = NULL;
 
@@ -697,6 +694,9 @@ void bitmap_writer_select_commits(struct bitmap_writer *writer,
 	if (indexed_commits_nr < 100) {
 		for (i = 0; i < indexed_commits_nr; ++i)
 			bitmap_writer_push_commit(writer, indexed_commits[i], 0);
+
+		select_pseudo_merges(writer);
+
 		return;
 	}
 
@@ -737,7 +737,7 @@ void bitmap_writer_select_commits(struct bitmap_writer *writer,
 
 	stop_progress(&writer->progress);
 
-	select_pseudo_merges(writer, indexed_commits, indexed_commits_nr);
+	select_pseudo_merges(writer);
 }
 
 
@@ -1001,7 +1001,6 @@ void bitmap_writer_set_checksum(struct bitmap_writer *writer,
 
 void bitmap_writer_finish(struct bitmap_writer *writer,
 			  struct pack_idx_entry **index,
-			  uint32_t index_nr,
 			  const char *filename,
 			  uint16_t options)
 {
@@ -1034,12 +1033,13 @@ void bitmap_writer_finish(struct bitmap_writer *writer,
 	dump_bitmap(f, writer->tags);
 
 	if (options & BITMAP_OPT_LOOKUP_TABLE)
-		CALLOC_ARRAY(offsets, index_nr);
+		CALLOC_ARRAY(offsets, writer->to_pack->nr_objects);
 
 	for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) {
 		struct bitmapped_commit *stored = &writer->selected[i];
 		int commit_pos = oid_pos(&stored->commit->object.oid, index,
-					 index_nr, oid_access);
+					 writer->to_pack->nr_objects,
+					 oid_access);
 
 		if (commit_pos < 0)
 			BUG(_("trying to write commit not in index"));
@@ -1055,7 +1055,7 @@ void bitmap_writer_finish(struct bitmap_writer *writer,
 		write_lookup_table(writer, f, offsets);
 
 	if (options & BITMAP_OPT_HASH_CACHE)
-		write_hash_cache(f, index, index_nr);
+		write_hash_cache(f, index, writer->to_pack->nr_objects);
 
 	finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,
 			  CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 2e657a2..9d9b8c4 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -2055,17 +2055,18 @@ static int try_partial_reuse(struct bitmap_index *bitmap_git,
 			     struct bitmapped_pack *pack,
 			     size_t bitmap_pos,
 			     uint32_t pack_pos,
+			     off_t offset,
 			     struct bitmap *reuse,
 			     struct pack_window **w_curs)
 {
-	off_t offset, delta_obj_offset;
+	off_t delta_obj_offset;
 	enum object_type type;
 	unsigned long size;
 
 	if (pack_pos >= pack->p->num_objects)
 		return -1; /* not actually in the pack */
 
-	offset = delta_obj_offset = pack_pos_to_offset(pack->p, pack_pos);
+	delta_obj_offset = offset;
 	type = unpack_object_header(pack->p, w_curs, &offset, &size);
 	if (type < 0)
 		return -1; /* broken packfile, punt */
@@ -2184,6 +2185,7 @@ static void reuse_partial_packfile_from_bitmap_1(struct bitmap_index *bitmap_git
 		for (offset = 0; offset < BITS_IN_EWORD; offset++) {
 			size_t bit_pos;
 			uint32_t pack_pos;
+			off_t ofs;
 
 			if (word >> offset == 0)
 				break;
@@ -2198,7 +2200,6 @@ static void reuse_partial_packfile_from_bitmap_1(struct bitmap_index *bitmap_git
 
 			if (bitmap_is_midx(bitmap_git)) {
 				uint32_t midx_pos;
-				off_t ofs;
 
 				midx_pos = pack_pos_to_midx(bitmap_git->midx, bit_pos);
 				ofs = nth_midxed_offset(bitmap_git->midx, midx_pos);
@@ -2213,10 +2214,12 @@ static void reuse_partial_packfile_from_bitmap_1(struct bitmap_index *bitmap_git
 					BUG("advanced beyond the end of pack %s (%"PRIuMAX" > %"PRIu32")",
 					    pack_basename(pack->p), (uintmax_t)pack_pos,
 					    pack->p->num_objects);
+
+				ofs = pack_pos_to_offset(pack->p, pack_pos);
 			}
 
 			if (try_partial_reuse(bitmap_git, pack, bit_pos,
-					      pack_pos, reuse, &w_curs) < 0) {
+					      pack_pos, ofs, reuse, &w_curs) < 0) {
 				/*
 				 * try_partial_reuse indicated we couldn't reuse
 				 * any bits, so there is no point in trying more
@@ -2322,6 +2325,7 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
 		packs[packs_nr].pack_int_id = pack_int_id;
 		packs[packs_nr].bitmap_nr = pack->num_objects;
 		packs[packs_nr].bitmap_pos = 0;
+		packs[packs_nr].from_midx = bitmap_git->midx;
 
 		objects_nr = packs[packs_nr++].bitmap_nr;
 	}
diff --git a/pack-bitmap.h b/pack-bitmap.h
index 1171e6d..d7f4b8b 100644
--- a/pack-bitmap.h
+++ b/pack-bitmap.h
@@ -60,6 +60,7 @@ struct bitmapped_pack {
 	uint32_t bitmap_pos;
 	uint32_t bitmap_nr;
 
+	struct multi_pack_index *from_midx; /* MIDX only */
 	uint32_t pack_int_id; /* MIDX only */
 };
 
@@ -123,14 +124,13 @@ struct bitmap_writer {
 	unsigned char pack_checksum[GIT_MAX_RAWSZ];
 };
 
-void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r);
+void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r,
+			struct packing_data *pdata);
 void bitmap_writer_show_progress(struct bitmap_writer *writer, int show);
 void bitmap_writer_set_checksum(struct bitmap_writer *writer,
 				const unsigned char *sha1);
 void bitmap_writer_build_type_index(struct bitmap_writer *writer,
-				    struct packing_data *to_pack,
-				    struct pack_idx_entry **index,
-				    uint32_t index_nr);
+				    struct pack_idx_entry **index);
 int bitmap_writer_has_bitmapped_object_id(struct bitmap_writer *writer,
 					  const struct object_id *oid);
 void bitmap_writer_push_commit(struct bitmap_writer *writer,
@@ -147,11 +147,9 @@ struct ewah_bitmap *pseudo_merge_bitmap_for_commit(struct bitmap_index *bitmap_g
 void bitmap_writer_select_commits(struct bitmap_writer *writer,
 				  struct commit **indexed_commits,
 				  unsigned int indexed_commits_nr);
-int bitmap_writer_build(struct bitmap_writer *writer,
-			struct packing_data *to_pack);
+int bitmap_writer_build(struct bitmap_writer *writer);
 void bitmap_writer_finish(struct bitmap_writer *writer,
 			  struct pack_idx_entry **index,
-			  uint32_t index_nr,
 			  const char *filename,
 			  uint16_t options);
 void bitmap_writer_free(struct bitmap_writer *writer);
diff --git a/pack-write.c b/pack-write.c
index d07f03d..f415604 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -8,10 +8,12 @@
 #include "csum-file.h"
 #include "remote.h"
 #include "chunk-format.h"
+#include "object-file.h"
 #include "pack-mtimes.h"
 #include "pack-objects.h"
 #include "pack-revindex.h"
 #include "path.h"
+#include "repository.h"
 #include "strbuf.h"
 
 void reset_pack_idx_option(struct pack_idx_option *opts)
@@ -473,7 +475,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",
-				       get_object_directory(), name);
+				       repo_get_object_directory(the_repository), name);
 		return NULL;
 	}
 	if (is_well_formed)
@@ -527,9 +529,9 @@ static void rename_tmp_packfile(struct strbuf *name_prefix, const char *source,
 	size_t name_prefix_len = name_prefix->len;
 
 	strbuf_addstr(name_prefix, ext);
-	if (rename(source, name_prefix->buf))
-		die_errno("unable to rename temporary file to '%s'",
-			  name_prefix->buf);
+	if (finalize_object_file(source, name_prefix->buf))
+		die("unable to rename temporary file to '%s'",
+		    name_prefix->buf);
 	strbuf_setlen(name_prefix, name_prefix_len);
 }
 
diff --git a/packfile.c b/packfile.c
index 8135846..df4ba67 100644
--- a/packfile.c
+++ b/packfile.c
@@ -30,7 +30,7 @@ char *odb_pack_name(struct strbuf *buf,
 		    const char *ext)
 {
 	strbuf_reset(buf);
-	strbuf_addf(buf, "%s/pack/pack-%s.%s", get_object_directory(),
+	strbuf_addf(buf, "%s/pack/pack-%s.%s", repo_get_object_directory(the_repository),
 		    hash_to_hex(hash), ext);
 	return buf->buf;
 }
@@ -815,9 +815,10 @@ static void report_pack_garbage(struct string_list *list)
 	report_helper(list, seen_bits, first, list->nr);
 }
 
-void for_each_file_in_pack_dir(const char *objdir,
-			       each_file_in_pack_dir_fn fn,
-			       void *data)
+void for_each_file_in_pack_subdir(const char *objdir,
+				  const char *subdir,
+				  each_file_in_pack_dir_fn fn,
+				  void *data)
 {
 	struct strbuf path = STRBUF_INIT;
 	size_t dirnamelen;
@@ -826,6 +827,8 @@ void for_each_file_in_pack_dir(const char *objdir,
 
 	strbuf_addstr(&path, objdir);
 	strbuf_addstr(&path, "/pack");
+	if (subdir)
+		strbuf_addf(&path, "/%s", subdir);
 	dir = opendir(path.buf);
 	if (!dir) {
 		if (errno != ENOENT)
@@ -847,6 +850,13 @@ void for_each_file_in_pack_dir(const char *objdir,
 	strbuf_release(&path);
 }
 
+void for_each_file_in_pack_dir(const char *objdir,
+			       each_file_in_pack_dir_fn fn,
+			       void *data)
+{
+	for_each_file_in_pack_subdir(objdir, NULL, fn, data);
+}
+
 struct prepare_pack_data {
 	struct repository *r;
 	struct string_list *garbage;
@@ -880,7 +890,8 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
 	if (!report_garbage)
 		return;
 
-	if (!strcmp(file_name, "multi-pack-index"))
+	if (!strcmp(file_name, "multi-pack-index") ||
+	    !strcmp(file_name, "multi-pack-index.d"))
 		return;
 	if (starts_with(file_name, "multi-pack-index") &&
 	    (ends_with(file_name, ".bitmap") || ends_with(file_name, ".rev")))
@@ -1064,7 +1075,7 @@ struct packed_git *get_all_packs(struct repository *r)
 	prepare_packed_git(r);
 	for (m = r->objects->multi_pack_index; m; m = m->next) {
 		uint32_t i;
-		for (i = 0; i < m->num_packs; i++)
+		for (i = 0; i < m->num_packs + m->num_packs_in_base; i++)
 			prepare_midx_pack(r, m, i);
 	}
 
diff --git a/packfile.h b/packfile.h
index eb18ec1..0f78658 100644
--- a/packfile.h
+++ b/packfile.h
@@ -55,6 +55,10 @@ struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
 
 typedef void each_file_in_pack_dir_fn(const char *full_path, size_t full_path_len,
 				      const char *file_name, void *data);
+void for_each_file_in_pack_subdir(const char *objdir,
+				  const char *subdir,
+				  each_file_in_pack_dir_fn fn,
+				  void *data);
 void for_each_file_in_pack_dir(const char *objdir,
 			       each_file_in_pack_dir_fn fn,
 			       void *data);
diff --git a/pager.c b/pager.c
index be6f4ee..40b664f 100644
--- a/pager.c
+++ b/pager.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "editor.h"
@@ -14,6 +16,7 @@ int pager_use_color = 1;
 
 static struct child_process pager_process;
 static char *pager_program;
+static int old_fd1 = -1, old_fd2 = -1;
 
 /* Is the value coming back from term_columns() just a guess? */
 static int term_columns_guessed;
@@ -23,10 +26,11 @@ static void close_pager_fds(void)
 {
 	/* signal EOF to pager */
 	close(1);
-	close(2);
+	if (old_fd2 != -1)
+		close(2);
 }
 
-static void wait_for_pager_atexit(void)
+static void finish_pager(void)
 {
 	fflush(stdout);
 	fflush(stderr);
@@ -34,8 +38,37 @@ static void wait_for_pager_atexit(void)
 	finish_command(&pager_process);
 }
 
+static void wait_for_pager_atexit(void)
+{
+	if (old_fd1 == -1)
+		return;
+
+	finish_pager();
+}
+
+void wait_for_pager(void)
+{
+	if (old_fd1 == -1)
+		return;
+
+	finish_pager();
+	sigchain_pop_common();
+	unsetenv("GIT_PAGER_IN_USE");
+	dup2(old_fd1, 1);
+	close(old_fd1);
+	old_fd1 = -1;
+	if (old_fd2 != -1) {
+		dup2(old_fd2, 2);
+		close(old_fd2);
+		old_fd2 = -1;
+	}
+}
+
 static void wait_for_pager_signal(int signo)
 {
+	if (old_fd1 == -1)
+		return;
+
 	close_pager_fds();
 	finish_command_in_signal(&pager_process);
 	sigchain_pop(signo);
@@ -61,7 +94,8 @@ const char *git_pager(int stdout_is_tty)
 	pager = getenv("GIT_PAGER");
 	if (!pager) {
 		if (!pager_program)
-			read_early_config(core_pager_config, NULL);
+			read_early_config(the_repository,
+					  core_pager_config, NULL);
 		pager = pager_program;
 	}
 	if (!pager)
@@ -111,6 +145,7 @@ void prepare_pager_args(struct child_process *pager_process, const char *pager)
 
 void setup_pager(void)
 {
+	static int once = 0;
 	const char *pager = git_pager(isatty(1));
 
 	if (!pager)
@@ -140,14 +175,20 @@ void setup_pager(void)
 		die("unable to execute pager '%s'", pager);
 
 	/* original process continues, but writes to the pipe */
+	old_fd1 = dup(1);
 	dup2(pager_process.in, 1);
-	if (isatty(2))
+	if (isatty(2)) {
+		old_fd2 = dup(2);
 		dup2(pager_process.in, 2);
+	}
 	close(pager_process.in);
 
-	/* this makes sure that the parent terminates after the pager */
 	sigchain_push_common(wait_for_pager_signal);
-	atexit(wait_for_pager_atexit);
+
+	if (!once) {
+		once++;
+		atexit(wait_for_pager_atexit);
+	}
 }
 
 int pager_in_use(void)
@@ -196,6 +237,8 @@ int term_columns(void)
  */
 void term_clear_line(void)
 {
+	if (!isatty(2))
+		return;
 	if (is_terminal_dumb())
 		/*
 		 * Fall back to print a terminal width worth of space
@@ -258,7 +301,7 @@ int check_pager_config(const char *cmd)
 	data.want = -1;
 	data.value = NULL;
 
-	read_early_config(pager_command_config, &data);
+	read_early_config(the_repository, pager_command_config, &data);
 
 	if (data.value)
 		pager_program = data.value;
diff --git a/pager.h b/pager.h
index b774330..103ecac 100644
--- a/pager.h
+++ b/pager.h
@@ -5,6 +5,7 @@ struct child_process;
 
 const char *git_pager(int stdout_is_tty);
 void setup_pager(void);
+void wait_for_pager(void);
 int pager_in_use(void);
 int term_columns(void);
 void term_clear_line(void);
diff --git a/parallel-checkout.c b/parallel-checkout.c
index 08b960a..01736f1 100644
--- a/parallel-checkout.c
+++ b/parallel-checkout.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "entry.h"
diff --git a/parse-options.c b/parse-options.c
index 30b9e68..33bfba0 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -60,12 +60,12 @@ static enum parse_opt_result get_arg(struct parse_opt_ctx_t *p,
 	return 0;
 }
 
-static void fix_filename(const char *prefix, char **file)
+static char *fix_filename(const char *prefix, const char *file)
 {
 	if (!file || !*file)
-		; /* leave as NULL */
+		return NULL;
 	else
-		*file = prefix_filename_except_for_dash(prefix, *file);
+		return prefix_filename_except_for_dash(prefix, file);
 }
 
 static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
@@ -129,18 +129,24 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
 		return 0;
 
 	case OPTION_FILENAME:
+	{
+		const char *value;
+
+		FREE_AND_NULL(*(char **)opt->value);
+
 		err = 0;
+
 		if (unset)
-			*(const char **)opt->value = NULL;
+			value = NULL;
 		else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
-			*(const char **)opt->value = (const char *)opt->defval;
+			value = (const char *) opt->defval;
 		else
-			err = get_arg(p, opt, flags, (const char **)opt->value);
+			err = get_arg(p, opt, flags, &value);
 
 		if (!err)
-			fix_filename(p->prefix, (char **)opt->value);
+			*(char **)opt->value = fix_filename(p->prefix, value);
 		return err;
-
+	}
 	case OPTION_CALLBACK:
 	{
 		const char *p_arg = NULL;
diff --git a/path.c b/path.c
index 19f7684..93491ba 100644
--- a/path.c
+++ b/path.c
@@ -30,7 +30,7 @@ static int get_st_mode_bits(const char *path, int *mode)
 	return 0;
 }
 
-static struct strbuf *get_pathname(void)
+struct strbuf *get_pathname(void)
 {
 	static struct strbuf pathname_array[4] = {
 		STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
@@ -365,15 +365,15 @@ static void update_common_dir(struct strbuf *buf, int git_dir_len,
 		strbuf_addstr(buf, LOCK_SUFFIX);
 }
 
-void report_linked_checkout_garbage(void)
+void report_linked_checkout_garbage(struct repository *r)
 {
 	struct strbuf sb = STRBUF_INIT;
 	const struct common_dir *p;
 	int len;
 
-	if (!the_repository->different_commondir)
+	if (!r->different_commondir)
 		return;
-	strbuf_addf(&sb, "%s/", get_git_dir());
+	strbuf_addf(&sb, "%s/", r->gitdir);
 	len = sb.len;
 	for (p = common_list; p->path; p++) {
 		const char *path = p->path;
@@ -417,9 +417,9 @@ static void strbuf_worktree_gitdir(struct strbuf *buf,
 		strbuf_git_common_path(buf, repo, "worktrees/%s", wt->id);
 }
 
-static void do_git_path(const struct repository *repo,
-			const struct worktree *wt, struct strbuf *buf,
-			const char *fmt, va_list args)
+void repo_git_pathv(const 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);
@@ -438,7 +438,7 @@ char *repo_git_path(const struct repository *repo,
 	struct strbuf path = STRBUF_INIT;
 	va_list args;
 	va_start(args, fmt);
-	do_git_path(repo, NULL, &path, fmt, args);
+	repo_git_pathv(repo, NULL, &path, fmt, args);
 	va_end(args);
 	return strbuf_detach(&path, NULL);
 }
@@ -449,48 +449,10 @@ void strbuf_repo_git_path(struct strbuf *sb,
 {
 	va_list args;
 	va_start(args, fmt);
-	do_git_path(repo, NULL, sb, fmt, args);
+	repo_git_pathv(repo, NULL, sb, fmt, args);
 	va_end(args);
 }
 
-char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
-{
-	va_list args;
-	strbuf_reset(buf);
-	va_start(args, fmt);
-	do_git_path(the_repository, NULL, buf, fmt, args);
-	va_end(args);
-	return buf->buf;
-}
-
-void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
-{
-	va_list args;
-	va_start(args, fmt);
-	do_git_path(the_repository, NULL, sb, fmt, args);
-	va_end(args);
-}
-
-const char *git_path(const char *fmt, ...)
-{
-	struct strbuf *pathname = get_pathname();
-	va_list args;
-	va_start(args, fmt);
-	do_git_path(the_repository, NULL, pathname, fmt, args);
-	va_end(args);
-	return pathname->buf;
-}
-
-char *git_pathdup(const char *fmt, ...)
-{
-	struct strbuf path = STRBUF_INIT;
-	va_list args;
-	va_start(args, fmt);
-	do_git_path(the_repository, NULL, &path, fmt, args);
-	va_end(args);
-	return strbuf_detach(&path, NULL);
-}
-
 char *mkpathdup(const char *fmt, ...)
 {
 	struct strbuf sb = STRBUF_INIT;
@@ -512,12 +474,17 @@ const char *mkpath(const char *fmt, ...)
 	return cleanup_path(pathname->buf);
 }
 
-const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)
+const char *worktree_git_path(struct repository *r,
+			      const struct worktree *wt, const char *fmt, ...)
 {
 	struct strbuf *pathname = get_pathname();
 	va_list args;
+
+	if (wt && wt->repo != r)
+		BUG("worktree not connected to expected repository");
+
 	va_start(args, fmt);
-	do_git_path(the_repository, wt, pathname, fmt, args);
+	repo_git_pathv(r, wt, pathname, fmt, args);
 	va_end(args);
 	return pathname->buf;
 }
@@ -617,26 +584,16 @@ int strbuf_git_path_submodule(struct strbuf *buf, const char *path,
 	return err;
 }
 
-static void do_git_common_path(const struct repository *repo,
-			       struct strbuf *buf,
-			       const char *fmt,
-			       va_list args)
+void repo_common_pathv(const struct repository *repo,
+		       struct strbuf *sb,
+		       const char *fmt,
+		       va_list args)
 {
-	strbuf_addstr(buf, repo->commondir);
-	if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
-		strbuf_addch(buf, '/');
-	strbuf_vaddf(buf, fmt, args);
-	strbuf_cleanup_path(buf);
-}
-
-const char *git_common_path(const char *fmt, ...)
-{
-	struct strbuf *pathname = get_pathname();
-	va_list args;
-	va_start(args, fmt);
-	do_git_common_path(the_repository, pathname, fmt, args);
-	va_end(args);
-	return pathname->buf;
+	strbuf_addstr(sb, repo->commondir);
+	if (sb->len && !is_dir_sep(sb->buf[sb->len - 1]))
+		strbuf_addch(sb, '/');
+	strbuf_vaddf(sb, fmt, args);
+	strbuf_cleanup_path(sb);
 }
 
 void strbuf_git_common_path(struct strbuf *sb,
@@ -645,7 +602,7 @@ void strbuf_git_common_path(struct strbuf *sb,
 {
 	va_list args;
 	va_start(args, fmt);
-	do_git_common_path(repo, sb, fmt, args);
+	repo_common_pathv(repo, sb, fmt, args);
 	va_end(args);
 }
 
diff --git a/path.h b/path.h
index a6f0b70..e91d19f 100644
--- a/path.h
+++ b/path.h
@@ -25,7 +25,7 @@ char *mkpathdup(const char *fmt, ...)
 	__attribute__((format (printf, 1, 2)));
 
 /*
- * The `git_common_path` family of functions will construct a path into a
+ * The `strbuf_git_common_path` family of functions will construct a path into a
  * repository's common git directory, which is shared by all worktrees.
  */
 
@@ -37,17 +37,13 @@ void strbuf_git_common_path(struct strbuf *sb,
 			    const struct repository *repo,
 			    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);
 
 /*
- * Return a statically allocated path into the main repository's
- * (the_repository) common git directory.
- */
-const char *git_common_path(const char *fmt, ...)
-	__attribute__((format (printf, 1, 2)));
-
-
-/*
- * The `git_path` family of functions will construct a path into a repository's
+ * The `repo_git_path` family of functions will construct a path into a repository's
  * git directory.
  *
  * These functions will perform adjustments to the resultant path to account
@@ -67,6 +63,14 @@ char *repo_git_path(const struct repository *repo,
 	__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`.
  */
@@ -76,40 +80,14 @@ void strbuf_repo_git_path(struct strbuf *sb,
 	__attribute__((format (printf, 3, 4)));
 
 /*
- * Return a statically allocated path into the main repository's
- * (the_repository) git directory.
+ * Similar to repo_git_path() but can produce paths for a specified
+ * worktree instead of current one. When no worktree is given, then the path is
+ * computed relative to main worktree of the given repository.
  */
-const char *git_path(const char *fmt, ...)
-	__attribute__((format (printf, 1, 2)));
-
-/*
- * Similar to git_path() but can produce paths for a specified
- * worktree instead of current one
- */
-const char *worktree_git_path(const struct worktree *wt,
+const char *worktree_git_path(struct repository *r,
+			      const struct worktree *wt,
 			      const char *fmt, ...)
-	__attribute__((format (printf, 2, 3)));
-
-/*
- * Return a path into the main repository's (the_repository) git directory.
- */
-char *git_pathdup(const char *fmt, ...)
-	__attribute__((format (printf, 1, 2)));
-
-/*
- * 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.
- */
-char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
-	__attribute__((format (printf, 2, 3)));
-
-/*
- * Construct a path into the main repository's (the_repository) git directory
- * and append it to the provided buffer `sb`.
- */
-void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
-	__attribute__((format (printf, 2, 3)));
+	__attribute__((format (printf, 3, 4)));
 
 /*
  * Return a path into the worktree of repository `repo`.
@@ -147,24 +125,15 @@ int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
 				     const char *fmt, ...)
 	__attribute__((format (printf, 3, 4)));
 
-void report_linked_checkout_garbage(void);
+void report_linked_checkout_garbage(struct repository *r);
 
 /*
  * You can define a static memoized git path like:
  *
- *    static GIT_PATH_FUNC(git_path_foo, "FOO")
+ *    static REPO_GIT_PATH_FUNC(git_path_foo, "FOO")
  *
  * or use one of the global ones below.
  */
-#define GIT_PATH_FUNC(func, filename) \
-	const char *func(void) \
-	{ \
-		static char *ret; \
-		if (!ret) \
-			ret = git_pathdup(filename); \
-		return ret; \
-	}
-
 #define REPO_GIT_PATH_FUNC(var, filename) \
 	const char *git_path_##var(struct repository *r) \
 	{ \
@@ -248,4 +217,99 @@ char *xdg_cache_home(const char *filename);
  */
 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);
+
+# 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); \
+		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/pathspec.c b/pathspec.c
index fe1f0f4..0fc6f84 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -495,9 +495,9 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
 			if (!have_git_dir())
 				die(_("'%s' is outside the directory tree"),
 				    copyfrom);
-			hint_path = get_git_work_tree();
+			hint_path = repo_get_work_tree(the_repository);
 			if (!hint_path)
-				hint_path = get_git_dir();
+				hint_path = repo_get_git_dir(the_repository);
 			die(_("%s: '%s' is outside repository at '%s'"), elt,
 			    copyfrom, absolute_path(hint_path));
 		}
diff --git a/perl/Git.pm b/perl/Git.pm
index aebfe0c..667152c 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -187,7 +187,7 @@
 		try {
 		  # Note that "--is-bare-repository" must come first, as
 		  # --git-dir output could contain newlines.
-		  $out = $search->command([qw(rev-parse --is-bare-repository --git-dir)],
+		  $out = $search->command([qw(rev-parse --is-bare-repository --absolute-git-dir)],
 			                  STDERR => 0);
 		} catch Git::Error::Command with {
 			throw Error::Simple("fatal: not a git repository: $opts{Directory}");
@@ -196,12 +196,12 @@
 		chomp $out;
 		my ($bare, $dir) = split /\n/, $out, 2;
 
-		require Cwd;
-		if ($bare ne 'true') {
-			require File::Spec;
-			File::Spec->file_name_is_absolute($dir) or $dir = $opts{Directory} . '/' . $dir;
-			$opts{Repository} = Cwd::abs_path($dir);
+		# We know this is an absolute path, because we used
+		# --absolute-git-dir above.
+		$opts{Repository} = $dir;
 
+		if ($bare ne 'true') {
+			require Cwd;
 			# If --git-dir went ok, this shouldn't die either.
 			my $prefix = $search->command_oneline('rev-parse', '--show-prefix');
 			$dir = Cwd::abs_path($opts{Directory}) . '/';
@@ -214,8 +214,6 @@
 			$opts{WorkingCopy} = $dir;
 			$opts{WorkingSubdir} = $prefix;
 
-		} else {
-			$opts{Repository} = Cwd::abs_path($dir);
 		}
 
 		delete $opts{Directory};
diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm
index 5454c3a..475e90a 100644
--- a/perl/Git/I18N.pm
+++ b/perl/Git/I18N.pm
@@ -111,7 +111,7 @@
 =head2 N__($)
 
 No-operation that only returns its argument. Use this if you want xgettext to
-extract the text to the pot template but do not want to trigger retrival of the
+extract the text to the pot template but do not want to trigger retrieval of the
 translation at run time.
 
 =head1 AUTHOR
diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
index 7721708..b0913ca 100644
--- a/perl/Git/SVN.pm
+++ b/perl/Git/SVN.pm
@@ -763,7 +763,7 @@
 		# this needs to be updated.
 		++$interesting_props if /^svn:(?:ignore|keywords|executable
 		                                 |eol-style|mime-type
-						 |externals|needs-lock)$/x;
+						 |externals|needs-lock|global-ignores)$/x;
 	}
 	&$sub($self, $p, $props) if $interesting_props;
 
diff --git a/po/TEAMS b/po/TEAMS
index 2775a97..9a6a15c 100644
--- a/po/TEAMS
+++ b/po/TEAMS
@@ -7,8 +7,8 @@
 
 Language:	ca (Catalan)
 Repository:	https://github.com/Softcatala/git-po
-Leader:		Jordi Mas <jmas@softcatala.org>
-Members:	Alex Henrie <alexhenrie24@gmail.com>
+Leader:		Mikel Forcada <mikel.forcada@gmail.com>
+Members:	Jordi Mas <jmas@softcatala.org>
 
 Language:	de (German)
 Repository:	https://github.com/ralfth/git
diff --git a/po/bg.po b/po/bg.po
index 9e1ae61..1f7222d 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -222,7 +222,9 @@
 # reftable таблица с указатели
 # its referent '%s' сочещия го „%s“
 # dry run пробно изпълнение
-#
+# mailmap файл за съответствията на имената и адресите на е-поща
+# unit test поединичен тест
+# test suite група тестове
 #
 # ------------------------
 # „$var“ - може да не сработва за shell има gettext и eval_gettext - проверка - намират се лесно по „$
@@ -251,8 +253,8 @@
 msgstr ""
 "Project-Id-Version: git 2.45\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-07-20 07:37+0200\n"
-"PO-Revision-Date: 2024-07-21 22:27+0300\n"
+"POT-Creation-Date: 2024-10-05 01:20+0000\n"
+"PO-Revision-Date: 2024-10-05 13:20+0200\n"
 "Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
 "Language-Team: Bulgarian <dict@fsa-bg.org>\n"
 "Language: bg\n"
@@ -808,7 +810,7 @@
 "/ - search for a hunk matching the given regex\n"
 "s - split the current hunk into smaller hunks\n"
 "e - manually edit the current hunk\n"
-"p - print the current hunk\n"
+"p - print the current hunk, 'P' to use the pager\n"
 "? - print help\n"
 msgstr ""
 "j — без решение за парчето, към следващото парче без решение\n"
@@ -820,6 +822,7 @@
 "s — разделяне на текущото парче на по-малки\n"
 "e — ръчно редактиране на текущото парче\n"
 "p — извеждане на текущото парче\n"
+"P — извеждане на текущото парче през програма за прелистване\n"
 "? — извеждане на помощта\n"
 
 #, c-format
@@ -1516,6 +1519,15 @@
 "пробване с тройно сливане, ако това не сработи — стандартно прилагане на "
 "кръпка"
 
+msgid "for conflicts, use our version"
+msgstr "при конфликти да се ползва локалната версия"
+
+msgid "for conflicts, use their version"
+msgstr "при конфликти да се ползва чуждата версия"
+
+msgid "for conflicts, use a union version"
+msgstr "при конфликти да се ползва обединена версия"
+
 msgid "build a temporary index based on embedded index information"
 msgstr ""
 "създаване на временен индекс на база на включената информация за индекса"
@@ -1563,6 +1575,9 @@
 msgid "don't return error for empty patches"
 msgstr "да не се връща грешка при празни кръпки"
 
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "опциите „--ours“, „--theirs“ и „--union“ изискват опцията „--3way“"
+
 #, c-format
 msgid "cannot stream blob %s"
 msgstr "обектът-BLOB „%s“ не може да се обработи"
@@ -1635,6 +1650,10 @@
 msgstr "не е обект-дърво: %s"
 
 #, c-format
+msgid "failed to unpack tree object %s"
+msgstr "неуспешно разпакетиране на обект-дърво „%s“"
+
+#, c-format
 msgid "File not found: %s"
 msgstr "Файлът „%s“ липсва"
 
@@ -2771,9 +2790,6 @@
 "на „git bisect terms“ е подаден неправилен аргумент „%s“\n"
 "Поддържат се опциите „--term-good“/„--term-old“ и „--term-bad„/„--term-new“."
 
-msgid "revision walk setup failed\n"
-msgstr "неуспешно настройване на обхождането на версиите\n"
-
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "файлът „%s“ не може да се отвори за добавяне"
@@ -3789,9 +3805,17 @@
 msgid "also read contacts from stdin"
 msgstr "четене на контакти и от стандартния вход"
 
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "контактът не може да бъде анализиран: %s"
+msgid "read additional mailmap entries from file"
+msgstr ""
+"изчитане на допълнителните съответствия на имена и адреси на е-поща от ФАЙЛ"
+
+msgid "blob"
+msgstr "обект-BLOB"
+
+msgid "read additional mailmap entries from blob"
+msgstr ""
+"изчитане на допълнителните съответствия на имена и адреси на е-поща от обект-"
+"BLOB"
 
 msgid "no contacts specified"
 msgstr "не са указани контакти"
@@ -4146,6 +4170,10 @@
 msgstr "опцията „%s“ е несъвместима с преминаването от един клон към друг"
 
 #, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "„%s“ изисква пътища, които да се изтеглят"
+
+#, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr "опцията „%s“ е несъвместима с „%s“"
 
@@ -4426,7 +4454,9 @@
 msgstr "изтриване само на игнорирани файлове"
 
 msgid "clean.requireForce is true and -f not given: refusing to clean"
-msgstr "Настройката „clean.requireForce“ е зададена, което изисква опцията „-f“.  Няма да се извърши изчистване"
+msgstr ""
+"Настройката „clean.requireForce“ е зададена, което изисква опцията „-f“.  "
+"Няма да се извърши изчистване"
 
 msgid "git clone [<options>] [--] <repo> [<dir>]"
 msgstr "git clone [ОПЦИЯ…] [--] ХРАНИЛИЩЕ [ДИРЕКТОРИЯ]"
@@ -4939,7 +4969,7 @@
 msgid ""
 "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 <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
@@ -4949,11 +4979,11 @@
 msgstr ""
 "git commit [-a|--interactive|--patch] [-s] [-v] [-u РЕЖИМ] [--amend]\n"
 "           [--dry-run] [(-c|-C|--squash) ПОДАВАНЕ |--fixup [(amend|"
-"reword):]ПОДАВАНЕ)]\n"
+"reword):]ПОДАВАНЕ]\n"
 "           [-F ФАЙЛ|-m СЪОБЩЕНИЕ] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=АВТОР]\n"
 "           [--date=ДАТА] [--cleanup=РЕЖИМ] [--[no-]status]\n"
-"           [-i|-o] [--pathspec-from-file=ФАЙЛ> [--pathspec-file-nul]]\n"
+"           [-i|-o] [--pathspec-from-file=ФАЙЛ [--pathspec-file-nul]]\n"
 "           [(--trailer ЛЕКСЕМА[(=|:)СТОЙНОСТ])…] [-"
 "S[ИДЕНТИФИКАТОР_НА_КЛЮЧ]]\n"
 "           [--] [ПЪТ…]"
@@ -5465,11 +5495,10 @@
 
 msgid ""
 "git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
-"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
-"<name>"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
 msgstr ""
 "git config get [ОПЦИЯ_ЗА_ФАЙЛ] [ОПЦИЯ_ЗА_ИЗВЕЖДАНЕ] [--includes] [--all] [--"
-"regexp=РЕГ_ИЗР][--value=СТОЙНОСТ] [--fixed-value] [--default=СТАНДАРТНО] ИМЕ"
+"regexp] [--value=СТОЙНОСТ] [--fixed-value] [--default=СТАНДАРТНО] ИМЕ"
 
 msgid ""
 "git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
@@ -5498,6 +5527,14 @@
 "git config [ОПЦИЯ_ЗА_ФАЙЛ] --get-colorbool ИМЕ [СТАНД_ИЗХОД_НА_ТЕРМИНАЛ]"
 
 msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [ОПЦИЯ_ЗА_ФАЙЛ] [ОПЦИЯ_ЗА_ИЗВЕЖДАНЕ] [--includes] [--all] [--"
+"regexp=РЕГ_ИЗР][--value=СТОЙНОСТ] [--fixed-value] [--default=СТАНДАРТНО] ИМЕ"
+
+msgid ""
 "git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
 "[--value=<value>] [--fixed-value] <name> <value>"
 msgstr ""
@@ -6326,8 +6363,8 @@
 "    git config fetch.showForcedUpdates false\n"
 
 #, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "хранилището „%s“ не изпрати всички необходими обекти\n"
+msgid "%s did not send all necessary objects"
+msgstr "хранилището „%s“ не изпрати всички необходими обекти"
 
 #, c-format
 msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -6366,8 +6403,8 @@
 msgstr "стойността „%2$s“ за опцията „%1$s“ не е съвместима с „%3$s“"
 
 #, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "опцията „%s“ се прескача при „%s“\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "опцията „%s“ се прескача при „%s“"
 
 #, c-format
 msgid "%s is not a valid object"
@@ -6672,7 +6709,8 @@
 msgstr "настройка, която съдържа списък с пътища към хранилища"
 
 msgid "keep going even if command fails in a repository"
-msgstr "продължаване на действието дори и командата да е неуспешна в някое хранилище"
+msgstr ""
+"продължаване на действието дори и командата да е неуспешна в някое хранилище"
 
 msgid "missing --config=<config>"
 msgstr "липсва --config=НАСТРОЙКА"
@@ -7046,6 +7084,9 @@
 msgid "enable auto-gc mode"
 msgstr "включване на автоматичното събиране на боклука (auto-gc)"
 
+msgid "perform garbage collection in the background"
+msgstr "събиране на боклука във фонов режим"
+
 msgid "force running gc even if there may be another gc running"
 msgstr ""
 "изрично стартиране на събирането на боклука, дори и ако вече работи друго "
@@ -7150,6 +7191,9 @@
 msgid "run tasks based on the state of the repository"
 msgstr "изпълняване на задачи според състоянието на хранилището"
 
+msgid "perform maintenance in the background"
+msgstr "извършване на дейностите по поддръжка на заден фон"
+
 msgid "frequency"
 msgstr "честота"
 
@@ -8029,9 +8073,6 @@
 msgid "Final output: %d %s\n"
 msgstr "Резултат: %d %s\n"
 
-msgid "unable to create temporary object directory"
-msgstr "не може да бъде създадена директория за временни обекти"
-
 #, c-format
 msgid "git show %s: bad file"
 msgstr "git show %s: повреден файл"
@@ -8622,15 +8663,6 @@
 msgid "use a zealous diff3 based merge"
 msgstr "засилено сливане на базата на „diff3“"
 
-msgid "for conflicts, use our version"
-msgstr "при конфликти да се ползва локалната версия"
-
-msgid "for conflicts, use their version"
-msgstr "при конфликти да се ползва чуждата версия"
-
-msgid "for conflicts, use a union version"
-msgstr "при конфликти да се ползва обединена версия"
-
 msgid "<algorithm>"
 msgstr "АЛГОРИТЪМ"
 
@@ -9110,6 +9142,9 @@
 msgid "write multi-pack bitmap"
 msgstr "запазване на многопакетната битова маска"
 
+msgid "write a new incremental MIDX"
+msgstr "запазване на нов файл с нарастващ индекс за множество пакети"
+
 msgid "write multi-pack index containing only given indexes"
 msgstr ""
 "запазване на битовата маска за множество пакети, съдържаща само дадените "
@@ -11196,6 +11231,9 @@
 msgid "git refs migrate --ref-format=<format> [--dry-run]"
 msgstr "git refs migrate --ref-format=ФОРМАТ [--dry-run]"
 
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
 msgid "specify the reference format to convert to"
 msgstr "указване на форма̀та за указател, към който да се конвертира"
 
@@ -11209,6 +11247,12 @@
 msgid "repository already uses '%s' format"
 msgstr "хранилището вече ползва форма̀та „%s“"
 
+msgid "enable strict checking"
+msgstr "строги проверки"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "командата „git refs verify“ не приема аргументи"
+
 msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
 "mirror=<fetch|push>] <name> <url>"
@@ -12668,10 +12712,10 @@
 msgid "failed to look up reference"
 msgstr "соченото от указателя липсва"
 
-msgid "only show tags (can be combined with branches)"
+msgid "only show tags (can be combined with --branches)"
 msgstr "извеждане на етикетите (може да се комбинира с „--branches“ за клони)"
 
-msgid "only show branches (can be combined with tags)"
+msgid "only show branches (can be combined with --tags)"
 msgstr "извеждане на клоните (може да се комбинира с „--tags“ за етикети)"
 
 msgid "check for reference existence without resolving"
@@ -12727,6 +12771,10 @@
 msgid "failed to create directory for sparse-checkout file"
 msgstr "директорията за частично изтегляне „%s“ не може да бъде създадена"
 
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "обектът „%s“ не може да бъде отворен с „fdopen“"
+
 msgid "failed to initialize worktree config"
 msgstr "настройките на работното дърво не може да се инициализират"
 
@@ -13185,8 +13233,8 @@
 msgstr "неуспешно изчисляване на контролната сума на обект от „%s“"
 
 #, c-format
-msgid "unexpected mode %o\n"
-msgstr "неочакван режим „%o“\n"
+msgid "unexpected mode %o"
+msgstr "неочакван режим „%o“"
 
 msgid "use the commit stored in the index instead of the submodule HEAD"
 msgstr ""
@@ -17918,13 +17966,16 @@
 msgid "Unable to create '%s.lock': %s"
 msgstr "Файлът-ключалка „%s.lock“ не може да бъде създаден: %s"
 
+msgid "unable to create temporary object directory"
+msgstr "не може да бъде създадена директория за временни обекти"
+
 #, c-format
 msgid "could not write loose object index %s"
 msgstr "индексът с непакетирани обекти не може да се запише: %s"
 
 #, c-format
-msgid "failed to write loose object index %s\n"
-msgstr "грешка при записа на индекса с непакетирани обекти %s\n"
+msgid "failed to write loose object index %s"
+msgstr "грешка при записа на индекса с непакетирани обекти „%s“"
 
 #, c-format
 msgid "unexpected line: '%s'"
@@ -18486,6 +18537,18 @@
 msgid "could not open index for %s"
 msgstr "индексът за „%s“ не може да се отвори"
 
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "не може да се създаде връзка „%s“, която да сочи към „%s“"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "индексът за множество пакети не може да бъде изчистен при „%s“"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr ""
+"нарастващият индекс за множество пакети с битова маска не може да се запише"
+
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr ""
 "индексът за множество пакети се прескача, защото сумата за проверка не "
@@ -18518,11 +18581,25 @@
 msgstr ""
 "многопакетната битова маска без никакви обекти не може да бъде запазена"
 
+msgid "unable to create temporary MIDX layer"
+msgstr "не може да се създаде временен слой за индекса за множество пакети"
+
 msgid "could not write multi-pack bitmap"
 msgstr "многопакетната битова маска не може да бъде запазена"
 
+msgid "unable to open multi-pack-index chain file"
+msgstr "файлът с веригата на гра̀фа с подаванията не може да се отвори"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "слой в индекса за множество пакети не може да се преименува"
+
 msgid "could not write multi-pack-index"
-msgstr "индексът за множество пакети не може да бъде запазен"
+msgstr "индексът за множество пакети не може да се запази"
+
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr ""
+"пакети за нарастващия индекс за множество пакети не може да се обявят за "
+"остарели"
 
 msgid "Counting referenced objects"
 msgstr "Преброяване на свързаните обекти"
@@ -18530,6 +18607,9 @@
 msgid "Finding and deleting unreferenced packfiles"
 msgstr "Търсене и изтриване на несвързаните пакетни файлове"
 
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "нарастващият индекс за множество пакети не може да се препакетира"
+
 msgid "could not start pack-objects"
 msgstr "командата „pack-objects“ не може да бъде стартирана"
 
@@ -18598,6 +18678,35 @@
 "неправилна подредба на имената в индекс за множество пакети: „%s“ се появи "
 "преди „%s“"
 
+msgid "multi-pack-index chain file too small"
+msgstr "файлът с веригата за индекса за множество пакети е твърде малък"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr ""
+"броят подавания в основния индекс за множество пакети е прекалено голям: "
+"%<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr ""
+"броят обекти в основния индекс за множество пакети е прекалено голям: "
+"%<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr ""
+"грешка във веригата на индекса за множество пакети: ред „%s“ не е контролна "
+"сума"
+
+msgid "unable to find all multi-pack index files"
+msgstr "някои файлове на индекса за множество пакети не може да бъдат открити"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr ""
+"неправилна позиция на обект в индекса за множество пакети.  Вероятно "
+"индексът е повреден"
+
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
 msgstr ""
@@ -18620,10 +18729,6 @@
 msgstr ""
 "стойността на отместването в индекса за множество пакети е извън диапазона"
 
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "индексът за множество пакети не може да бъде изчистен при „%s“"
-
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr ""
 "файлът с индекса за множество пакети съществува, но не може да бъде "
@@ -18849,6 +18954,14 @@
 msgstr "липсва съответствие на „%s“ към „%s“"
 
 #, c-format
+msgid "unable to open %s"
+msgstr "обектът „%s“ не може да бъде отворен"
+
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "съдържанието на файловете „%s“ и „%s“ е различно"
+
+#, c-format
 msgid "unable to write file %s"
 msgstr "файлът „%s“ не може да бъде записан"
 
@@ -18934,10 +19047,6 @@
 msgstr "„%s“ е неправилен обект от вид „%s“"
 
 #, c-format
-msgid "unable to open %s"
-msgstr "обектът „%s“ не може да бъде отворен"
-
-#, c-format
 msgid "hash mismatch for %s (expected %s)"
 msgstr "неправилна контролна сума за „%s“ (трябва да е %s)"
 
@@ -20212,6 +20321,10 @@
 msgstr "очакван формат: %%(ahead-behind:ПОДАВАНЕ)"
 
 #, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "очакван формат: %%(is-base:ПОДАВАНЕ)"
+
+#, c-format
 msgid "malformed field name: %.*s"
 msgstr "неправилно име на обект: „%.*s“"
 
@@ -20349,7 +20462,8 @@
 "\n"
 "\tgit branch -m <name>\n"
 msgstr ""
-"Първоначалният клон ще се казва „%s“.  Това може да се променѝ.  Може да зададете\n"
+"Първоначалният клон ще се казва „%s“.  Това може да се променѝ.  Може да "
+"зададете\n"
 "настройката и да спрете това съобщение.  За това изпълнете:\n"
 "\n"
 "    git config --global init.defaultBranch ИМЕ\n"
@@ -20446,6 +20560,13 @@
 "„%s“, но вместо това е обикновен указател"
 
 #, c-format
+msgid "cannot open directory %s"
+msgstr "директорията „%s“ не може да бъде отворена"
+
+msgid "Checking references consistency"
+msgstr "Проверка на валидността на указателите"
+
+#, c-format
 msgid "refname is dangerous: %s"
 msgstr "опасно име на указател: %s"
 
@@ -20993,7 +21114,9 @@
 msgid ""
 "--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
 "REVERT_HEAD or REBASE_HEAD"
-msgstr "„--merge“ изисква някой от псевдо указателите „MERGE_HEAD“, „CHERRY_PICK_HEAD“, „REVERT_HEAD“ или „REBASE_HEAD“"
+msgstr ""
+"„--merge“ изисква някой от псевдо указателите „MERGE_HEAD“, "
+"„CHERRY_PICK_HEAD“, „REVERT_HEAD“ или „REBASE_HEAD“"
 
 #, c-format
 msgid "could not get commit for --ancestry-path argument %s"
@@ -21097,12 +21220,15 @@
 msgid "create repository within 'src' directory"
 msgstr "създаване на хранилище в директория „src“"
 
+msgid "specify if tags should be fetched during clone"
+msgstr "указва дали етикетите да се доставят при клониране"
+
 msgid ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 msgstr ""
 "scalar clone [--single-branch] [--branch ОСНОВЕН_КЛОН] [--full-clone]\n"
-"    [--[no-]src] АДРЕС [ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]"
+"    [--[no-]src] [--[no-]tags] АДРЕС [ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]"
 
 #, c-format
 msgid "cannot deduce worktree name from '%s'"
@@ -21121,6 +21247,10 @@
 msgstr "отдалеченото хранилище в „%s“ не може да се настрои"
 
 #, c-format
+msgid "could not disable tags in '%s'"
+msgstr "етикетите в „%s“ не може са се изключат"
+
+#, c-format
 msgid "could not configure '%s'"
 msgstr "„%s“ не може да се настрои"
 
@@ -22241,6 +22371,10 @@
 msgstr "не може да бъде получена информация чрез „stat“ за „%*s%s%s“"
 
 #, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "пътят за безопасна директория (safe.directory) „%s“ не е абсолютен"
+
+#, c-format
 msgid ""
 "detected dubious ownership in repository at '%s'\n"
 "%sTo add an exception for this directory, call:\n"
@@ -22715,6 +22849,24 @@
 msgid "command token to send to the server"
 msgstr "командна лексема за пращане"
 
+msgid "unit-test [<options>]"
+msgstr "unit-test [ОПЦИЯ…]"
+
+msgid "immediately exit upon the first failed test"
+msgstr "незабавен изход след първия неуспешен тест"
+
+msgid "suite[::test]"
+msgstr "ГРУПА[::ТЕСТ]"
+
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "изпълнение на тази ГРУПА или конкретен тест с име ГРУПА::ТЕСТ"
+
+msgid "suite"
+msgstr "ГРУПА"
+
+msgid "exclude test suite <suite>"
+msgstr "прескачане на тази ГРУПА тестове"
+
 #, c-format
 msgid "running trailer command '%s' failed"
 msgstr "неуспешно изпълнение на завършващата команда „%s“"
@@ -22963,7 +23115,9 @@
 msgstr "операцията „bundle-uri“ (адреси на пратки) не се поддържа от протокола"
 
 msgid "could not retrieve server-advertised bundle-uri list"
-msgstr "списъкът с адреси на пратки обявени за налични от сървъра не може да се получи "
+msgstr ""
+"списъкът с адреси на пратки обявени за налични от сървъра не може да се "
+"получи "
 
 msgid "operation not supported by protocol"
 msgstr "опцията не се поддържа от протокола"
@@ -23915,6 +24069,9 @@
 msgid "--dump-aliases incompatible with other options\n"
 msgstr "опцията „--dump-aliases“ е несъвместима с другите опции\n"
 
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "опциите „--dump-aliases“ и „--translate-aliases“ са несъвместими\n"
+
 msgid ""
 "fatal: found configuration options for 'sendmail'\n"
 "git-send-email is configured with the sendemail.* options - note the 'e'.\n"
diff --git a/po/ca.po b/po/ca.po
index bcb4da8..ace9b3c 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -77,186 +77,238 @@
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-02-16 07:14+0100\n"
-"PO-Revision-Date: 2024-02-16 07:16+0100\n"
-"Last-Translator: Jordi Mas i Hernàndez <jmas@softcatala.org>\n"
+"POT-Creation-Date: 2024-10-05 01:20+0000\n"
+"PO-Revision-Date: 2024-10-05 09:03+0200\n"
+"Last-Translator: Mikel Forcada <mikel.forcada@gmail.com>\n"
 "Language-Team: Catalan\n"
 "Language: ca\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 2.3.1\n"
+"X-Generator: Poedit 3.2.2\n"
 
+#: add-interactive.c
 #, c-format
 msgid "Huh (%s)?"
 msgstr "Perdó (%s)?"
 
+#: add-interactive.c builtin/merge.c builtin/rebase.c reset.c sequencer.c
 msgid "could not read index"
 msgstr "no s'ha pogut llegir l'índex"
 
+#: add-interactive.c
 msgid "binary"
 msgstr "binari"
 
+#: add-interactive.c
 msgid "nothing"
 msgstr "res"
 
+#: add-interactive.c
 msgid "unchanged"
 msgstr "sense canvis"
 
+#: add-interactive.c
 msgid "Update"
 msgstr "Actualitza"
 
+#: add-interactive.c
 #, c-format
 msgid "could not stage '%s'"
 msgstr "no s'ha pogut fer «stage» «%s»"
 
+#: add-interactive.c builtin/stash.c reset.c sequencer.c
 msgid "could not write index"
 msgstr "no s'ha pogut escriure l'índex"
 
+#: add-interactive.c
 #, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "actualitzat %d camí\n"
 msgstr[1] "actualitzats %d camins\n"
 
+#: add-interactive.c
 #, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "nota: %s està ara sense seguiment.\n"
 
+#: add-interactive.c apply.c builtin/checkout.c builtin/reset.c
 #, c-format
 msgid "make_cache_entry failed for path '%s'"
 msgstr "make_cache_entry ha fallat per al camí «%s»"
 
+#: add-interactive.c
 msgid "Revert"
 msgstr "Reverteix"
 
+#: add-interactive.c
 msgid "Could not parse HEAD^{tree}"
 msgstr "No s'ha pogut analitzar HEAD^{tree}"
 
+#: add-interactive.c
 #, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "revertit %d camí\n"
 msgstr[1] "revertits %d camins\n"
 
+#: add-interactive.c
 #, c-format
 msgid "No untracked files.\n"
 msgstr "Sense fitxers no seguits.\n"
 
+#: add-interactive.c
 msgid "Add untracked"
 msgstr "Afegeix sense seguiment"
 
+#: add-interactive.c
 #, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "afegit %d camí\n"
 msgstr[1] "afegits %d camins\n"
 
+#: add-interactive.c
 #, c-format
 msgid "ignoring unmerged: %s"
 msgstr "s'està ignorant allò no fusionat: %s"
 
+#: add-interactive.c
 #, c-format
 msgid "Only binary files changed.\n"
 msgstr "Només han canviat fitxers binaris.\n"
 
+#: add-interactive.c
 #, c-format
 msgid "No changes.\n"
 msgstr "Sense canvis.\n"
 
+#: add-interactive.c
 msgid "Patch update"
 msgstr "Actualització del pedaç"
 
+#: add-interactive.c
 msgid "Review diff"
 msgstr "Reviseu les diferències"
 
+#: add-interactive.c
 msgid "show paths with changes"
 msgstr "mostra els camins amb canvis"
 
+#: add-interactive.c
 msgid "add working tree state to the staged set of changes"
 msgstr "afegeix l'estat de l'arbre de treball al conjunt de canvis «staged»"
 
+#: add-interactive.c
 msgid "revert staged set of changes back to the HEAD version"
 msgstr "reverteix el conjunt de canvis «staged» a la versió HEAD"
 
+#: add-interactive.c
 msgid "pick hunks and update selectively"
 msgstr "selecciona els trossos i actualitza selectivament"
 
+#: add-interactive.c
 msgid "view diff between HEAD and index"
 msgstr "visualitza les diferències entre HEAD i l'índex"
 
+#: add-interactive.c
 msgid "add contents of untracked files to the staged set of changes"
 msgstr "afegeix contingut de fitxers no seguits al conjunt de canvis «staged»"
 
+#: add-interactive.c
 msgid "Prompt help:"
 msgstr "Mostra ajuda:"
 
+#: add-interactive.c
 msgid "select a single item"
 msgstr "seleccioneu un únic ítem"
 
+#: add-interactive.c
 msgid "select a range of items"
 msgstr "seleccioneu un rang d'ítems"
 
+#: add-interactive.c
 msgid "select multiple ranges"
 msgstr "seleccioneu rangs múltiples"
 
+#: add-interactive.c
 msgid "select item based on unique prefix"
 msgstr "seleccioneu un ítem basant-se en un prefix únic"
 
+#: add-interactive.c
 msgid "unselect specified items"
 msgstr "desselecciona els ítems especificats"
 
+#: add-interactive.c
 msgid "choose all items"
 msgstr "trieu tots els ítems"
 
+#: add-interactive.c
 msgid "(empty) finish selecting"
 msgstr "(buit) finalitza la selecció"
 
+#: add-interactive.c
 msgid "select a numbered item"
 msgstr "seleccioneu un ítem numerat"
 
+#: add-interactive.c
 msgid "(empty) select nothing"
 msgstr "(buit) no seleccionis res"
 
+#: add-interactive.c builtin/clean.c
 msgid "*** Commands ***"
 msgstr "*** Ordres ***"
 
+#: add-interactive.c builtin/clean.c
 msgid "What now"
 msgstr "I ara què"
 
+#: add-interactive.c
 msgid "staged"
 msgstr "staged"
 
+#: add-interactive.c
 msgid "unstaged"
 msgstr "unstaged"
 
+#: add-interactive.c apply.c builtin/am.c builtin/bugreport.c builtin/clone.c
+#: builtin/diagnose.c builtin/fetch.c builtin/hook.c builtin/merge.c
+#: builtin/pull.c builtin/submodule--helper.c
 msgid "path"
 msgstr "camí"
 
+#: add-interactive.c
 msgid "could not refresh index"
 msgstr "no s'ha pogut actualitzar l'índex"
 
+#: add-interactive.c builtin/clean.c
 #, c-format
 msgid "Bye.\n"
 msgstr "Adeu.\n"
 
+#: add-patch.c
 #, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "Canvia el mode de «stage» [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "Suprimeix «stage» [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "Afegeix a «stage» [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Fer un «stage» d'aquest tros [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
 "staging."
@@ -264,6 +316,7 @@
 "Si el pedaç s'aplica netament, el tros editat es marcarà immediatament per a "
 "«staging»."
 
+#: add-patch.c
 msgid ""
 "y - stage this hunk\n"
 "n - do not stage this hunk\n"
@@ -275,24 +328,30 @@
 "n - no facis «stage» d'aquest tros\n"
 "q - surt; no facis «stage» d'aquest tros ni de cap altre restant\n"
 "a - fes «stage» d'aquest tros i de tota la resta de trossos del fitxer\n"
-"d - no facis «stage» d'aquest tros ni de cap altre restant del fitxer\n"
+"d - no facis «stage» d'aquest tros ni de cap altre tros posterior del "
+"fitxer\n"
 
+#: add-patch.c
 #, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "Canvia el mode de «stash» [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "Suprimeix «stash» [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "Afegeix a «stash» [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "Fer un «stash» d'aquest tros [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
 "stashing."
@@ -300,6 +359,7 @@
 "Si el pedaç s'aplica de forma neta, el tros editat es marcarà immediatament "
 "per a «stashing»."
 
+#: add-patch.c
 msgid ""
 "y - stash this hunk\n"
 "n - do not stash this hunk\n"
@@ -311,24 +371,30 @@
 "n - no facis «stash» d'aquest tros\n"
 "q - surt; no facis «stash» d'aquest tros ni de cap altre restant\n"
 "a - fes «stash» d'aquest tros i de tota la resta de trossos del fitxer\n"
-"d - no facis «stash» d'aquest tros ni de cap altre restant del fitxer\n"
+"d - no facis «stash» d'aquest tros ni de cap altre tros posterior del "
+"fitxer\n"
 
+#: add-patch.c
 #, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "Canvia el mode de «unstage» [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "Suprimeix «Unstage» [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "Afegeix a «unstage» [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Fer un «unstage» d'aquest tros [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
 "unstaging."
@@ -336,6 +402,7 @@
 "Si el pedaç s'aplica netament, el tros editat es marcarà immediatament per a "
 "«unstaging»."
 
+#: add-patch.c
 msgid ""
 "y - unstage this hunk\n"
 "n - do not unstage this hunk\n"
@@ -349,22 +416,27 @@
 "a - fes «unstage» d'aquest tros i de tota la resta de trossos del fitxer\n"
 "d - no facis «unstage» d'aquest tros ni de cap altre restant del fitxer\n"
 
+#: add-patch.c
 #, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr "Aplica el canvi de mode a l'índex [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "Aplica la supressió a l'índex [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "Aplica l'addició a l'índex [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "Aplica aquest tros a l'índex [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
 "applying."
@@ -372,6 +444,7 @@
 "Si el pedaç s'aplica netament, el tros editat es marcarà immediatament per a "
 "aplicar-lo."
 
+#: add-patch.c
 msgid ""
 "y - apply this hunk to index\n"
 "n - do not apply this hunk to index\n"
@@ -385,22 +458,27 @@
 "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
 
+#: add-patch.c
 #, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr "Descarta el canvi de mode de l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "Descarta suprimir de l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "Descarta l'addició de l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
 msgstr "Descarta aquest tros de l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
 "discarding."
@@ -408,6 +486,7 @@
 "Si el pedaç s'aplica netament, el tros editat es marcarà immediatament per a "
 "ser descartat."
 
+#: add-patch.c
 msgid ""
 "y - discard this hunk from worktree\n"
 "n - do not discard this hunk from worktree\n"
@@ -421,26 +500,31 @@
 "a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer\n"
 
+#: add-patch.c
 #, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Descarta el canvi de mode de l'índex i de l'arbre de treball [y,n,q,a,"
 "d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Descarta suprimir de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Descarta l'addició de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Descarta aquest tros de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 msgid ""
 "y - discard this hunk from index and worktree\n"
 "n - do not discard this hunk from index and worktree\n"
@@ -454,23 +538,28 @@
 "a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer\n"
 
+#: add-patch.c
 #, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
 "Aplica el canvi de mode a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica la supressió a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica l'addició a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica aquest tros a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 msgid ""
 "y - apply this hunk to index and worktree\n"
 "n - do not apply this hunk to index and worktree\n"
@@ -484,22 +573,27 @@
 "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
 
+#: add-patch.c
 #, c-format
 msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica el canvi de mode a l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica la supressió a l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica l'addició a l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 #, c-format
 msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
 msgstr "Aplica aquest tros a l'arbre de treball [y,n,q,a,d%s,?]? "
 
+#: add-patch.c
 msgid ""
 "y - apply this hunk to worktree\n"
 "n - do not apply this hunk to worktree\n"
@@ -513,23 +607,29 @@
 "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
 
+#: add-patch.c
 #, c-format
 msgid "could not parse hunk header '%.*s'"
 msgstr "no s'ha pogut analitzar la capçalera del tros «%.*s»"
 
+#: add-patch.c
 msgid "could not parse diff"
 msgstr "no s'ha pogut analitzar el diff"
 
+#: add-patch.c
 msgid "could not parse colored diff"
 msgstr "no s'ha pogut analitzar el diff acolorit"
 
+#: add-patch.c
 #, c-format
 msgid "failed to run '%s'"
 msgstr "no s'ha pogut executar «%s»"
 
+#: add-patch.c
 msgid "mismatched output from interactive.diffFilter"
 msgstr "sortida no coincident des d'interactive.diffFilter"
 
+#: add-patch.c
 msgid ""
 "Your filter must maintain a one-to-one correspondence\n"
 "between its input and output lines."
@@ -537,6 +637,7 @@
 "El filtre ha de mantenir una correspondència d'un a un\n"
 "entre les línies d'entrada i sortida."
 
+#: add-patch.c
 #, c-format
 msgid ""
 "expected context line #%d in\n"
@@ -545,6 +646,7 @@
 "s'esperava la línia amb contingut #%d a\n"
 "%.*s"
 
+#: add-patch.c
 #, c-format
 msgid ""
 "hunks do not overlap:\n"
@@ -557,22 +659,25 @@
 "\tno acaben amb:\n"
 "%.*s"
 
+#: add-patch.c
 msgid "Manual hunk edit mode -- see bottom for a quick guide.\n"
 msgstr ""
 "Mode d'edició de trossos manual - vegeu més avall per a una guia ràpida.\n"
 
+#: add-patch.c
 #, c-format
 msgid ""
 "---\n"
 "To remove '%c' lines, make them ' ' lines (context).\n"
 "To remove '%c' lines, delete them.\n"
-"Lines starting with %c will be removed.\n"
+"Lines starting with %s will be removed.\n"
 msgstr ""
 "---\n"
 "Per a eliminar les línies «%c», convertiu-les en línies ' ' (context).\n"
 "Per a eliminar les línies «%c», suprimiu-les.\n"
-"Les línies que comencin per %c s'eliminaran.\n"
+"Les línies que comencin per %s s'eliminaran.\n"
 
+#: add-patch.c
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
 "edit again.  If all lines of the hunk are removed, then the edit is\n"
@@ -582,9 +687,11 @@
 "de nou. Si s'eliminen totes les línies del tros, llavors l'edició s'avorta\n"
 "i el tros es deixa sense cap canvi.\n"
 
+#: add-patch.c
 msgid "could not parse hunk header"
 msgstr "no s'ha pogut analitzar la capçalera del tros"
 
+#: add-patch.c
 msgid "'git apply --cached' failed"
 msgstr "«git apply --cached» ha fallat"
 
@@ -594,21 +701,26 @@
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
+#: add-patch.c
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr ""
 "El tros editat no s'aplica. Editeu-lo de nou (si responeu «no» es "
 "descartarà) [y/n]? "
 
+#: add-patch.c
 msgid "The selected hunks do not apply to the index!"
 msgstr "Els trossos seleccionats no s'apliquen a l'índex!"
 
+#: add-patch.c
 msgid "Apply them to the worktree anyway? "
 msgstr "Voleu aplicar-los igualment a l'arbre de treball? "
 
+#: add-patch.c
 msgid "Nothing was applied.\n"
 msgstr "No s'ha aplicat res.\n"
 
+#: add-patch.c
 msgid ""
 "j - leave this hunk undecided, see next undecided hunk\n"
 "J - leave this hunk undecided, see next hunk\n"
@@ -618,69 +730,105 @@
 "/ - search for a hunk matching the given regex\n"
 "s - split the current hunk into smaller hunks\n"
 "e - manually edit the current hunk\n"
+"p - print the current hunk, 'P' to use the pager\n"
 "? - print help\n"
 msgstr ""
-"j - deixa aquest tros sense decidir, veure el tros sense decidir següent\n"
-"J - deixa aquest tros sense decidir, veure el tros següent\n"
-"k - deixa aquest tros sense decidir, veure el tros sense decidir anterior\n"
-"K - deixa aquest tros sense decidir, veure el tros anterior\n"
-"g - selecciona el tros on voleu anar\n"
-"/ - cerca un tros que coincideixi amb l'expressió regular donada\n"
-"s - divideix el tros actual en trossos més petits\n"
+"j - deixa aquest tros sense decidir, veges el tros següent no decidit \n"
+"J - deixa aquest tros sense decidir, veges el tros següent\n"
+"k - deixa aquest tros sense decidir, veges el tros anterior no decidit ºn\n"
+"K - deixa aquest tros sense decidir, veges el tros anterior\n"
+"g - selecciona un tros a on anar\n"
+"/ - cerca un tros que concorde amb l'expressió regular donada\n"
+"s - divideix el tros actual en trossos més menuts\n"
 "e - edita manualment el tros actual\n"
-"? - mostra l'ajuda\n"
+"p - imprimeix el tros actual, «P» per a usar el paginador\n"
+"? - imprimeix l'ajuda\n"
 
+#: add-patch.c
+#, c-format
+msgid "Only one letter is expected, got '%s'"
+msgstr "S'espera una lletra, s'ha obtingut «%s»"
+
+#: add-patch.c
 msgid "No previous hunk"
 msgstr "Sense tros previ"
 
+#: add-patch.c
 msgid "No next hunk"
 msgstr "No hi ha tros següent"
 
+#: add-patch.c
 msgid "No other hunks to goto"
 msgstr "No hi ha altres trossos on anar-hi"
 
+#: add-patch.c
 msgid "go to which hunk (<ret> to see more)? "
-msgstr "ves a quin tros (<ret> per a veure'n més)? "
+msgstr "ves a quin tros (<intro> per a veure'n més)? "
 
+#: add-patch.c
 msgid "go to which hunk? "
 msgstr "ves a quin tros? "
 
+#: add-patch.c
 #, c-format
 msgid "Invalid number: '%s'"
 msgstr "Número no vàlid: «%s»"
 
+#: add-patch.c
 #, c-format
 msgid "Sorry, only %d hunk available."
 msgid_plural "Sorry, only %d hunks available."
 msgstr[0] "Només %d tros disponible."
 msgstr[1] "Només %d trossos disponibles."
 
+#: add-patch.c
 msgid "No other hunks to search"
 msgstr "No hi ha cap altre tros a cercar"
 
+#: add-patch.c
 msgid "search for regex? "
 msgstr "cerca per expressió regular? "
 
+#: add-patch.c
 #, c-format
 msgid "Malformed search regexp %s: %s"
 msgstr "Expressió regular de cerca mal formada %s: %s"
 
+#: add-patch.c
 msgid "No hunk matches the given pattern"
 msgstr "No hi ha trossos que coincideixin amb el patró donat"
 
+#: add-patch.c
 msgid "Sorry, cannot split this hunk"
 msgstr "No es pot dividir aquest tros"
 
+#: add-patch.c
 #, c-format
 msgid "Split into %d hunks."
 msgstr "Divideix en %d trossos."
 
+#: add-patch.c
 msgid "Sorry, cannot edit this hunk"
 msgstr "No es pot editar aquest tros"
 
+#: add-patch.c
+#, c-format
+msgid "Unknown command '%s' (use '?' for help)"
+msgstr "Ordre desconeguda: «%s» (useu «?» per a obtenir ajuda)"
+
+#: add-patch.c
 msgid "'git apply' failed"
 msgstr "«git apply» ha fallat"
 
+#: add-patch.c
+msgid "No changes."
+msgstr "No hi ha canvis."
+
+#: add-patch.c
+msgid "Only binary files changed."
+msgstr "Només han canviat els fitxers binaris."
+
+#: advice.c
 #, c-format
 msgid ""
 "\n"
@@ -689,28 +837,36 @@
 "\n"
 "Desactiva aquest missatge amb «git config advice.%s false»"
 
+#: advice.c
 #, c-format
-msgid "%shint: %.*s%s\n"
-msgstr "%sconsell: %.*s%s\n"
+msgid "%shint:%s%.*s%s\n"
+msgstr "%sconsell:%s%.*s%s\n"
 
+#: advice.c
 msgid "Cherry-picking is not possible because you have unmerged files."
 msgstr "Fer «cherry pick» no és possible perquè teniu fitxers sense fusionar."
 
+#: advice.c
 msgid "Committing is not possible because you have unmerged files."
 msgstr "Cometre no és possible perquè teniu fitxers sense fusionar."
 
+#: advice.c
 msgid "Merging is not possible because you have unmerged files."
 msgstr "Fusionar no és possible perquè teniu fitxers sense fusionar."
 
+#: advice.c
 msgid "Pulling is not possible because you have unmerged files."
 msgstr "Baixar no és possible perquè teniu fitxers sense fusionar."
 
+#: advice.c
 msgid "Reverting is not possible because you have unmerged files."
 msgstr "Revertir no és possible perquè teniu fitxers sense fusionar."
 
+#: advice.c
 msgid "Rebasing is not possible because you have unmerged files."
 msgstr "Fer «rebase» no és possible perquè teniu fitxers sense fusionar."
 
+#: advice.c
 msgid ""
 "Fix them up in the work tree, and then use 'git add/rm <file>'\n"
 "as appropriate to mark resolution and make a commit."
@@ -719,18 +875,23 @@
 "«git add/rm <fitxer>» segons sigui apropiat per a\n"
 "marcar la resolució i feu una comissió."
 
+#: advice.c
 msgid "Exiting because of an unresolved conflict."
 msgstr "S'està sortint a causa d'un conflicte no resolt."
 
+#: advice.c builtin/merge.c
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr "No heu conclòs la vostra fusió (MERGE_HEAD existeix)."
 
+#: advice.c
 msgid "Please, commit your changes before merging."
 msgstr "Cometeu els vostres canvis abans de fusionar."
 
+#: advice.c
 msgid "Exiting because of unfinished merge."
 msgstr "S'està sortint a causa d'una fusió no terminada."
 
+#: advice.c
 msgid ""
 "Diverging branches can't be fast-forwarded, you need to either:\n"
 "\n"
@@ -748,9 +909,11 @@
 "\n"
 "\tgit rebase\n"
 
+#: advice.c
 msgid "Not possible to fast-forward, aborting."
 msgstr "No és possible avançar ràpidament, s'està avortant."
 
+#: advice.c
 #, c-format
 msgid ""
 "The following paths and/or pathspecs matched paths that exist\n"
@@ -761,6 +924,7 @@
 "amb camins que existeixen fora de la vostra definició de\n"
 "«sparse-checkout», així que no serà actualitzaran en l'índex:\n"
 
+#: advice.c
 msgid ""
 "If you intend to update such entries, try one of the following:\n"
 "* Use the --sparse option.\n"
@@ -770,6 +934,7 @@
 "* Utilitzeu l'opció --sparse.\n"
 "* Inhabiliteu o modifiqueu les regles de dispersió."
 
+#: advice.c
 #, c-format
 msgid ""
 "Note: switching to '%s'.\n"
@@ -810,6 +975,7 @@
 "«false»\n"
 "\n"
 
+#: advice.c
 #, c-format
 msgid ""
 "The following paths have been moved outside the\n"
@@ -820,6 +986,7 @@
 "definició de sparse-checkout però no són dispersos\n"
 "a causa de modificacions en local.\n"
 
+#: advice.c
 msgid ""
 "To correct the sparsity of these paths, do the following:\n"
 "* Use \"git add --sparse <paths>\" to update the index\n"
@@ -829,79 +996,108 @@
 "* Useu «git add --sparse <paths>» per a actualitzar l'índex\n"
 "* Useu «git sparse-checkout reapply» per a aplicar les regles de dispersió"
 
+#: alias.c
 msgid "cmdline ends with \\"
 msgstr "la línia d'ordres acaba amb \\"
 
+#: alias.c
 msgid "unclosed quote"
 msgstr "cometes no tancades"
 
+#: alias.c builtin/cat-file.c builtin/notes.c builtin/prune-packed.c
+#: builtin/receive-pack.c builtin/refs.c builtin/tag.c t/helper/test-pkt-line.c
 msgid "too many arguments"
 msgstr "hi ha massa arguments"
 
+#: apply.c
 #, c-format
 msgid "unrecognized whitespace option '%s'"
 msgstr "opció d'espai en blanc «%s» no reconeguda"
 
+#: apply.c
 #, c-format
 msgid "unrecognized whitespace ignore option '%s'"
 msgstr "opció ignora l'espai en blanc «%s» no reconeguda"
 
+#: apply.c archive.c builtin/add.c builtin/branch.c builtin/checkout-index.c
+#: builtin/checkout.c builtin/clean.c builtin/clone.c builtin/commit.c
+#: builtin/describe.c builtin/diff-tree.c builtin/difftool.c
+#: builtin/fast-export.c builtin/fetch.c builtin/help.c builtin/index-pack.c
+#: builtin/init-db.c builtin/log.c builtin/ls-files.c builtin/merge-base.c
+#: builtin/merge-tree.c builtin/merge.c builtin/pack-objects.c builtin/rebase.c
+#: builtin/repack.c builtin/replay.c builtin/reset.c builtin/rev-list.c
+#: builtin/rev-parse.c builtin/show-branch.c builtin/stash.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/worktree.c parse-options.c
+#: range-diff.c revision.c
 #, c-format
 msgid "options '%s' and '%s' cannot be used together"
 msgstr "les opcions «%s» i «%s» no es poden usar juntes"
 
+#: apply.c
 #, c-format
 msgid "'%s' outside a repository"
 msgstr "«%s» fora d'un repositori"
 
+#: apply.c
 msgid "failed to read patch"
 msgstr "s'ha produït un error en llegir el pedaç"
 
+#: apply.c
 msgid "patch too large"
 msgstr "el pedaç és massa gran"
 
+#: apply.c
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr "No es pot preparar l'expressió regular de marca de temps %s"
 
+#: apply.c
 #, c-format
 msgid "regexec returned %d for input: %s"
 msgstr "regexec ha retornat %d per a l'entrada: %s"
 
+#: apply.c
 #, c-format
 msgid "unable to find filename in patch at line %d"
 msgstr "no s'ha pogut trobar el nom de fitxer en el pedaç a la línia %d"
 
+#: apply.c
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
 msgstr ""
 "git apply: git-diff incorrecte - s'esperava /dev/null, s'ha rebut %s en la "
 "línia %d"
 
+#: apply.c
 #, c-format
 msgid "git apply: bad git-diff - inconsistent new filename on line %d"
 msgstr ""
 "git apply: git-diff incorrecte - nom de fitxer nou inconsistent en la línia "
 "%d"
 
+#: apply.c
 #, c-format
 msgid "git apply: bad git-diff - inconsistent old filename on line %d"
 msgstr ""
 "git apply: git-diff incorrecte - nom de fitxer antic inconsistent en la "
 "línia %d"
 
+#: apply.c
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null on line %d"
 msgstr "git apply: git-diff incorrecte - s'esperava /dev/null en la línia %d"
 
+#: apply.c
 #, c-format
 msgid "invalid mode on line %d: %s"
 msgstr "mode no vàlid en la línia %d: %s"
 
+#: apply.c
 #, c-format
 msgid "inconsistent header lines %d and %d"
 msgstr "línies de capçalera %d i %d inconsistents"
 
+#: apply.c
 #, c-format
 msgid ""
 "git diff header lacks filename information when removing %d leading pathname "
@@ -916,75 +1112,93 @@
 "a la capçalera de git diff li manca informació de nom de fitxer en eliminar "
 "%d components de nom de camí inicial (línia %d)"
 
+#: apply.c
 #, c-format
 msgid "git diff header lacks filename information (line %d)"
 msgstr ""
 "a la capçalera de git diff li manca informació de nom de fitxer (línia %d)"
 
+#: apply.c
 #, c-format
 msgid "recount: unexpected line: %.*s"
 msgstr "recompte: línia inesperada: %.*s"
 
+#: apply.c
 #, c-format
 msgid "patch fragment without header at line %d: %.*s"
 msgstr "fragment de pedaç sense capçalera a la línia %d: %.*s"
 
+#: apply.c
 msgid "new file depends on old contents"
 msgstr "el fitxer nou depèn dels continguts antics"
 
+#: apply.c
 msgid "deleted file still has contents"
 msgstr "el fitxer suprimit encara té continguts"
 
+#: apply.c
 #, c-format
 msgid "corrupt patch at line %d"
 msgstr "pedaç malmès a la línia %d"
 
+#: apply.c
 #, c-format
 msgid "new file %s depends on old contents"
 msgstr "el fitxer nou %s depèn dels continguts antics"
 
+#: apply.c
 #, c-format
 msgid "deleted file %s still has contents"
 msgstr "el fitxer suprimit %s encara té continguts"
 
+#: apply.c
 #, c-format
 msgid "** warning: file %s becomes empty but is not deleted"
 msgstr "** advertència: el fitxer %s queda buit però no se suprimeix"
 
+#: apply.c
 #, c-format
 msgid "corrupt binary patch at line %d: %.*s"
 msgstr "pedaç binari malmès a la línia %d: %.*s"
 
+#: apply.c
 #, c-format
 msgid "unrecognized binary patch at line %d"
 msgstr "pedaç binari no reconegut a la línia %d"
 
+#: apply.c
 #, c-format
 msgid "patch with only garbage at line %d"
 msgstr "pedaç amb només escombraries a la línia %d"
 
+#: apply.c
 #, c-format
 msgid "unable to read symlink %s"
 msgstr "no s'ha pogut llegir l'enllaç simbòlic %s"
 
+#: apply.c
 #, c-format
 msgid "unable to open or read %s"
 msgstr "no s'ha pogut obrir o llegir %s"
 
+#: apply.c
 #, c-format
 msgid "invalid start of line: '%c'"
 msgstr "inici de línia no vàlid: «%c»"
 
+#: apply.c
 #, c-format
 msgid "Hunk #%d succeeded at %d (offset %d line)."
 msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
 msgstr[0] "El tros #%d ha tingut èxit a %d (desplaçament d'%d línia)."
 msgstr[1] "El tros #%d ha tingut èxit a %d (desplaçament de %d línies)."
 
+#: apply.c
 #, c-format
 msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
 msgstr "El context s'ha reduït a (%ld/%ld) per a aplicar el fragment a %d"
 
+#: apply.c
 #, c-format
 msgid ""
 "while searching for:\n"
@@ -993,19 +1207,23 @@
 "tot cercant:\n"
 "%.*s"
 
+#: apply.c
 #, c-format
 msgid "missing binary patch data for '%s'"
 msgstr "manquen les dades de pedaç binari de «%s»"
 
+#: apply.c
 #, c-format
 msgid "cannot reverse-apply a binary patch without the reverse hunk to '%s'"
 msgstr "no es pot aplicar al revés un pedaç binari sense el tros revés a «%s»"
 
+#: apply.c
 #, c-format
 msgid "cannot apply binary patch to '%s' without full index line"
 msgstr ""
 "no es pot aplicar un pedaç binari a «%s» sense la línia d'índex completa"
 
+#: apply.c
 #, c-format
 msgid ""
 "the patch applies to '%s' (%s), which does not match the current contents."
@@ -1013,235 +1231,287 @@
 "el pedaç s'aplica a «%s» (%s), el qual no coincideix amb els continguts "
 "actuals."
 
+#: apply.c
 #, c-format
 msgid "the patch applies to an empty '%s' but it is not empty"
 msgstr "el pedaç s'aplica a un «%s» buit però no és buit"
 
+#: apply.c
 #, c-format
 msgid "the necessary postimage %s for '%s' cannot be read"
 msgstr "no es pot llegir la postimatge %s necessària per a «%s»"
 
+#: apply.c
 #, c-format
 msgid "binary patch does not apply to '%s'"
 msgstr "el pedaç binari no s'aplica a «%s»"
 
+#: apply.c
 #, c-format
 msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
 msgstr ""
 "el pedaç binari a «%s» crea un resultat incorrecte (s'esperava %s, s'ha "
 "rebut %s)"
 
+#: apply.c
 #, c-format
 msgid "patch failed: %s:%ld"
 msgstr "el pedaç ha fallat: %s:%ld"
 
+#: apply.c builtin/mv.c
 #, c-format
 msgid "cannot checkout %s"
 msgstr "no es pot agafar %s"
 
+#: apply.c midx.c pack-mtimes.c pack-revindex.c setup.c
 #, c-format
 msgid "failed to read %s"
 msgstr "s'ha produït un error en llegir %s"
 
+#: apply.c
 #, c-format
 msgid "reading from '%s' beyond a symbolic link"
 msgstr "s'està llegint de «%s» més enllà d'un enllaç simbòlic"
 
+#: apply.c
 #, c-format
 msgid "path %s has been renamed/deleted"
 msgstr "el camí %s s'ha canviat de nom / s'ha suprimit"
 
+#: apply.c
 #, c-format
 msgid "%s: does not exist in index"
 msgstr "%s: no existeix en l'índex"
 
+#: apply.c
 #, c-format
 msgid "%s: does not match index"
 msgstr "%s: no coincideix amb l'índex"
 
+#: apply.c
 msgid "repository lacks the necessary blob to perform 3-way merge."
 msgstr ""
 "al repositori li manca el blob necessari per a fer a una fusió de 3 vies."
 
+#: apply.c
 #, c-format
 msgid "Performing three-way merge...\n"
 msgstr "S'està fent una fusió de 3 vies...\n"
 
+#: apply.c
 #, c-format
 msgid "cannot read the current contents of '%s'"
 msgstr "no es poden llegir els continguts actuals de «%s»"
 
+#: apply.c
 #, c-format
 msgid "Failed to perform three-way merge...\n"
 msgstr "S'ha produït un error en fer una fusió de tres vies...\n"
 
+#: apply.c
 #, c-format
 msgid "Applied patch to '%s' with conflicts.\n"
 msgstr "S'ha aplicat el pedaç a «%s» amb conflictes.\n"
 
+#: apply.c
 #, c-format
 msgid "Applied patch to '%s' cleanly.\n"
 msgstr "S'ha aplicat el pedaç a «%s» netament.\n"
 
+#: apply.c
 #, c-format
 msgid "Falling back to direct application...\n"
 msgstr "S'està usant alternativament l'aplicació directa...\n"
 
+#: apply.c
 msgid "removal patch leaves file contents"
 msgstr "el pedaç d'eliminació deixa els continguts dels fitxers"
 
+#: apply.c
 #, c-format
 msgid "%s: wrong type"
 msgstr "%s: tipus erroni"
 
+#: apply.c
 #, c-format
 msgid "%s has type %o, expected %o"
 msgstr "%s és del tipus %o, s'esperava %o"
 
+#: apply.c read-cache.c
 #, c-format
 msgid "invalid path '%s'"
 msgstr "camí no vàlid: «%s»"
 
+#: apply.c
 #, c-format
 msgid "%s: already exists in index"
 msgstr "%s: ja existeix en l'índex"
 
+#: apply.c
 #, c-format
 msgid "%s: already exists in working directory"
 msgstr "%s: ja existeix en el directori de treball"
 
+#: apply.c
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o)"
 msgstr "el mode nou (%o) de %s no coincideix amb el mode antic (%o)"
 
+#: apply.c
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o) of %s"
 msgstr "el mode nou (%o) de %s no coincideix amb el mode antic (%o) de %s"
 
+#: apply.c
 #, c-format
 msgid "affected file '%s' is beyond a symbolic link"
 msgstr "el fitxer afectat «%s» és més enllà d'un enllaç simbòlic"
 
+#: apply.c
 #, c-format
 msgid "%s: patch does not apply"
 msgstr "%s: el pedaç no s'aplica"
 
+#: apply.c
 #, c-format
 msgid "Checking patch %s..."
 msgstr "S'està comprovant el pedaç %s..."
 
+#: apply.c
 #, c-format
 msgid "sha1 information is lacking or useless for submodule %s"
 msgstr "falta la informació sha1 o és inútil per al submòdul %s"
 
+#: apply.c
 #, c-format
 msgid "mode change for %s, which is not in current HEAD"
 msgstr "canvi de mode per a %s, el qual no està en la HEAD actual"
 
+#: apply.c
 #, c-format
 msgid "sha1 information is lacking or useless (%s)."
 msgstr "falta informació sha1 o és inútil (%s)."
 
+#: apply.c
 #, c-format
 msgid "could not add %s to temporary index"
 msgstr "no s'ha pogut afegir %s a l'índex temporal"
 
+#: apply.c
 #, c-format
 msgid "could not write temporary index to %s"
 msgstr "no s'ha pogut escriure l'índex temporal a %s"
 
+#: apply.c
 #, c-format
 msgid "unable to remove %s from index"
 msgstr "no s'ha pogut eliminar %s de l'índex"
 
+#: apply.c
 #, c-format
 msgid "corrupt patch for submodule %s"
 msgstr "pedaç malmès per al submòdul %s"
 
+#: apply.c
 #, c-format
 msgid "unable to stat newly created file '%s'"
 msgstr "no s'ha pogut fer stat al fitxer novament creat «%s»"
 
+#: apply.c
 #, c-format
 msgid "unable to create backing store for newly created file %s"
 msgstr ""
 "no s'ha pogut crear un magatzem de suport per al fitxer novament creat %s"
 
+#: apply.c
 #, c-format
 msgid "unable to add cache entry for %s"
 msgstr "no s'ha pogut afegir una entrada de cau per a %s"
 
+#: apply.c builtin/bisect.c builtin/gc.c
 #, c-format
 msgid "failed to write to '%s'"
 msgstr "no s'ha pogut escriure a «%s»"
 
+#: apply.c
 #, c-format
 msgid "closing file '%s'"
 msgstr "s'està tancant el fitxer «%s»"
 
+#: apply.c
 #, c-format
 msgid "unable to write file '%s' mode %o"
 msgstr "no s'ha pogut escriure el fitxer «%s» mode %o"
 
+#: apply.c
 #, c-format
 msgid "Applied patch %s cleanly."
 msgstr "El pedaç %s s'ha aplicat netament."
 
+#: apply.c
 msgid "internal error"
 msgstr "error intern"
 
+#: apply.c
 #, c-format
 msgid "Applying patch %%s with %d reject..."
 msgid_plural "Applying patch %%s with %d rejects..."
 msgstr[0] "S'està aplicant el pedaç %%s amb %d rebuig..."
 msgstr[1] "S'està aplicant el pedaç %%s amb %d rebutjos..."
 
-#, c-format
-msgid "truncating .rej filename to %.*s.rej"
-msgstr "s'està truncant el nom del fitxer .rej a %.*s.rej"
-
+#: apply.c
 #, c-format
 msgid "cannot open %s"
 msgstr "no es pot obrir %s"
 
+#: apply.c rerere.c
 #, c-format
 msgid "cannot unlink '%s'"
 msgstr "no es pot fer «unlink» de «%s»"
 
+#: apply.c
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "El tros #%d s'ha aplicat netament."
 
+#: apply.c
 #, c-format
 msgid "Rejected hunk #%d."
 msgstr "S'ha rebutjat el tros #%d."
 
+#: apply.c
 #, c-format
 msgid "Skipped patch '%s'."
 msgstr "S'ha omès el pedaç «%s»."
 
+#: apply.c
 msgid "No valid patches in input (allow with \"--allow-empty\")"
 msgstr "No hi ha pedaços vàlids a l'entrada (permeteu-los amb «--allow-empty»)"
 
+#: apply.c t/helper/test-cache-tree.c
 msgid "unable to read index file"
 msgstr "no es pot llegir el fitxer d'índex"
 
+#: apply.c
 #, c-format
 msgid "can't open patch '%s': %s"
 msgstr "no es pot obrir el pedaç «%s»: %s"
 
+#: apply.c
 #, c-format
 msgid "squelched %d whitespace error"
 msgid_plural "squelched %d whitespace errors"
 msgstr[0] "s'ha silenciat %d error d'espai en blanc"
 msgstr[1] "s'han silenciat %d errors d'espai en blanc"
 
+#: apply.c
 #, c-format
 msgid "%d line adds whitespace errors."
 msgid_plural "%d lines add whitespace errors."
 msgstr[0] "%d línia afegeix errors d'espai en blanc."
 msgstr[1] "%d línies afegeixen errors d'espai en blanc."
 
+#: apply.c
 #, c-format
 msgid "%d line applied after fixing whitespace errors."
 msgid_plural "%d lines applied after fixing whitespace errors."
@@ -1250,287 +1520,398 @@
 msgstr[1] ""
 "S'han aplicat %d línies després d'arreglar els errors d'espai en blanc."
 
+#: apply.c builtin/mv.c builtin/rm.c
 msgid "Unable to write new index file"
 msgstr "No s'ha pogut escriure un fitxer d'índex nou"
 
+#: apply.c
 msgid "don't apply changes matching the given path"
 msgstr "no apliquis els canvis que coincideixin amb el camí donat"
 
+#: apply.c
 msgid "apply changes matching the given path"
 msgstr "aplica els canvis que coincideixin amb el camí donat"
 
+#: apply.c builtin/am.c
 msgid "num"
 msgstr "nombre"
 
+#: apply.c
 msgid "remove <num> leading slashes from traditional diff paths"
 msgstr ""
 "elimina <nombre> barres obliqües inicials dels camins de diferència "
 "tradicionals"
 
+#: apply.c
 msgid "ignore additions made by the patch"
 msgstr "ignora afegiments fets pel pedaç"
 
+#: apply.c
 msgid "instead of applying the patch, output diffstat for the input"
 msgstr ""
 "en lloc d'aplicar el pedaç, emet les estadístiques de diferència de l'entrada"
 
+#: apply.c
 msgid "show number of added and deleted lines in decimal notation"
 msgstr "mostra el nombre de línies afegides i suprimides en notació decimal"
 
+#: apply.c
 msgid "instead of applying the patch, output a summary for the input"
 msgstr "en lloc d'aplicar el pedaç, emet un resum de l'entrada"
 
+#: apply.c
 msgid "instead of applying the patch, see if the patch is applicable"
 msgstr "en lloc d'aplicar el pedaç, determina si el pedaç és aplicable"
 
+#: apply.c
 msgid "make sure the patch is applicable to the current index"
 msgstr "assegura que el pedaç sigui aplicable a l'índex actual"
 
+#: apply.c
 msgid "mark new files with `git add --intent-to-add`"
 msgstr "marca els fitxers nous amb «git add --intent-to-add»"
 
+#: apply.c
 msgid "apply a patch without touching the working tree"
 msgstr "aplica un pedaç sense tocar l'arbre de treball"
 
+#: apply.c
 msgid "accept a patch that touches outside the working area"
 msgstr "accepta un pedaç que toqui fora de l'àrea de treball"
 
+#: apply.c
 msgid "also apply the patch (use with --stat/--summary/--check)"
 msgstr "aplica el pedaç també (useu amb --stat/--summary/--check)"
 
+#: apply.c
 msgid "attempt three-way merge, fall back on normal patch if that fails"
 msgstr ""
 "intenta una fusió de tres vies, si falla intenta llavors un pedaç normal"
 
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use our version"
+msgstr "en conflictes, usa la nostra versió"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use their version"
+msgstr "en conflictes, usa la seva versió"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use a union version"
+msgstr "en conflictes, usa una versió d'unió"
+
+#: apply.c
 msgid "build a temporary index based on embedded index information"
 msgstr "construeix un índex temporal basat en la informació d'índex incrustada"
 
+#: apply.c builtin/checkout-index.c
 msgid "paths are separated with NUL character"
 msgstr "els camins se separen amb el caràcter NUL"
 
+#: apply.c
 msgid "ensure at least <n> lines of context match"
 msgstr "assegura't que almenys <n> línies de context coincideixin"
 
+#: apply.c builtin/am.c builtin/interpret-trailers.c builtin/pack-objects.c
+#: builtin/rebase.c
 msgid "action"
 msgstr "acció"
 
+#: apply.c
 msgid "detect new or modified lines that have whitespace errors"
 msgstr ""
 "detecta les línies noves o modificades que tinguin errors d'espai en blanc"
 
+#: apply.c
 msgid "ignore changes in whitespace when finding context"
 msgstr "ignora els canvis d'espai en blanc en cercar context"
 
+#: apply.c
 msgid "apply the patch in reverse"
 msgstr "aplica el pedaç al revés"
 
+#: apply.c
 msgid "don't expect at least one line of context"
 msgstr "no esperis almenys una línia de context"
 
+#: apply.c
 msgid "leave the rejected hunks in corresponding *.rej files"
 msgstr "deixa els trossos rebutjats en fitxers *.rej corresponents"
 
+#: apply.c
 msgid "allow overlapping hunks"
 msgstr "permet trossos superposats"
 
+#: apply.c
 msgid "tolerate incorrectly detected missing new-line at the end of file"
 msgstr "tolera una línia nova incorrectament detectada al final del fitxer"
 
+#: apply.c
 msgid "do not trust the line counts in the hunk headers"
 msgstr "no confiïs en els recomptes de línia en les capçaleres dels trossos"
 
+#: apply.c builtin/am.c
 msgid "root"
 msgstr "arrel"
 
+#: apply.c
 msgid "prepend <root> to all filenames"
 msgstr "anteposa <arrel> a tots els noms de fitxer"
 
+#: apply.c
 msgid "don't return error for empty patches"
 msgstr "no retornis l'error per als pedaços buits"
 
+#: apply.c
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs, i --union requereixen --3way"
+
+#: archive-tar.c archive-zip.c
 #, c-format
 msgid "cannot stream blob %s"
 msgstr "no es pot transmetre el blob %s"
 
+#: archive-tar.c archive-zip.c
 #, c-format
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "mode de fitxer no compatible: 0%o (SHA1: %s)"
 
+#: archive-tar.c archive-zip.c builtin/pack-objects.c
 #, c-format
 msgid "deflate error (%d)"
 msgstr "error de deflació (%d)"
 
+#: archive-tar.c
 #, c-format
 msgid "unable to start '%s' filter"
 msgstr "no s'ha pogut iniciar el filtre «%s»"
 
+#: archive-tar.c
 msgid "unable to redirect descriptor"
 msgstr "no s'ha pogut redirigir el descriptor"
 
+#: archive-tar.c
 #, c-format
 msgid "'%s' filter reported error"
 msgstr "«%s» error reportat pel filtre"
 
+#: archive-zip.c
 #, c-format
 msgid "path is not valid UTF-8: %s"
 msgstr "el camí no és vàlid en UTF-8: %s"
 
+#: archive-zip.c
 #, c-format
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "el camí és massa llarg (%d caràcters, SHA1: %s): %s"
 
+#: archive-zip.c
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
 msgstr "marca de temps massa gran per a aquest sistema: %<PRIuMAX>"
 
+#: archive.c
 msgid "git archive [<options>] <tree-ish> [<path>...]"
 msgstr "git archive [<opcions>] <arbre> [<camí>...]"
 
+#: archive.c
 msgid ""
 "git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"
 msgstr ""
 "git archive --remote <repositori> [--exec <ordre>] [<opcions>] <arbre> "
 "[<camí>...]"
 
+#: archive.c
 msgid "git archive --remote <repo> [--exec <cmd>] --list"
 msgstr "git archive --remote <repositori> [--exec <ordre>] --list"
 
+#: archive.c builtin/gc.c builtin/notes.c builtin/tag.c
 #, c-format
 msgid "cannot read '%s'"
 msgstr "no es pot llegir «%s»"
 
+#: archive.c
 #, c-format
 msgid "pathspec '%s' matches files outside the current directory"
 msgstr ""
 "l'especificació de camí «%s» coincideix amb fitxers fora del directori actual"
 
+#: archive.c builtin/add.c builtin/rm.c
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "l'especificació de camí «%s» no ha coincidit amb cap fitxer"
 
+#: archive.c
 #, c-format
 msgid "no such ref: %.*s"
 msgstr "no existeix la referència: %.*s"
 
+#: archive.c
 #, c-format
 msgid "not a valid object name: %s"
 msgstr "no és un nom d'objecte vàlid: %s"
 
+#: archive.c t/helper/test-cache-tree.c
 #, c-format
 msgid "not a tree object: %s"
 msgstr "no és un objecte d'arbre: %s"
 
+#: archive.c
+#, c-format
+msgid "failed to unpack tree object %s"
+msgstr "s'ha produït un error en desempaquetar l'objecte d'arbre %s"
+
+#: archive.c
 #, c-format
 msgid "File not found: %s"
 msgstr "Fitxer no trobat: %s"
 
+#: archive.c
 #, c-format
 msgid "Not a regular file: %s"
 msgstr "No és un fitxer normal: %s"
 
+#: archive.c
 #, c-format
 msgid "unclosed quote: '%s'"
 msgstr "cometes no tancades: «%s»"
 
+#: archive.c
 #, c-format
 msgid "missing colon: '%s'"
 msgstr "falten els dos punts: «%s»"
 
+#: archive.c
 #, c-format
 msgid "empty file name: '%s'"
 msgstr "nom de fitxer buit: «%s»"
 
+#: archive.c
 msgid "fmt"
 msgstr "format"
 
+#: archive.c
 msgid "archive format"
 msgstr "format d'arxiu"
 
+#: archive.c builtin/log.c parse-options.h
 msgid "prefix"
 msgstr "prefix"
 
+#: archive.c
 msgid "prepend prefix to each pathname in the archive"
 msgstr "anteposa el prefix a cada nom de camí en l'arxiu"
 
+#: archive.c builtin/blame.c builtin/commit-tree.c builtin/config.c
+#: builtin/fast-export.c builtin/gc.c builtin/grep.c builtin/hash-object.c
+#: builtin/ls-files.c builtin/notes.c builtin/read-tree.c parse-options.h
 msgid "file"
 msgstr "fitxer"
 
+#: archive.c
 msgid "add untracked file to archive"
 msgstr "inclou els fitxers no seguits a l'arxiu"
 
+#: archive.c
 msgid "path:content"
 msgstr "camí: contingut"
 
+#: archive.c builtin/archive.c
 msgid "write the archive to this file"
 msgstr "escriu l'arxiu a aquest fitxer"
 
+#: archive.c
 msgid "read .gitattributes in working directory"
 msgstr "llegeix .gitattributes en el directori de treball"
 
+#: archive.c
 msgid "report archived files on stderr"
 msgstr "informa de fitxers arxivats en stderr"
 
+#: archive.c builtin/clone.c builtin/fetch.c builtin/pack-objects.c
+#: builtin/pull.c
 msgid "time"
 msgstr "data"
 
+#: archive.c
 msgid "set modification time of archive entries"
 msgstr "estableix l'hora de modificació de les entrades de l'arxiu"
 
+#: archive.c
 msgid "set compression level"
 msgstr "estableix el nivell de compressió"
 
+#: archive.c
 msgid "list supported archive formats"
 msgstr "llista els formats d'arxiu admesos"
 
+#: archive.c builtin/archive.c builtin/clone.c builtin/submodule--helper.c
 msgid "repo"
 msgstr "repositori"
 
+#: archive.c builtin/archive.c
 msgid "retrieve the archive from remote repository <repo>"
 msgstr "recupera l'arxiu del repositori remot <repositori>"
 
+#: archive.c builtin/archive.c builtin/difftool.c builtin/notes.c
 msgid "command"
 msgstr "ordre"
 
+#: archive.c builtin/archive.c
 msgid "path to the remote git-upload-archive command"
 msgstr "camí a l'ordre git-upload-archive remota"
 
+#: archive.c
 msgid "Unexpected option --remote"
 msgstr "Opció inesperada --remote"
 
+#: archive.c builtin/add.c builtin/checkout.c builtin/clone.c builtin/commit.c
+#: builtin/fast-export.c builtin/index-pack.c builtin/log.c builtin/reset.c
+#: builtin/rm.c builtin/stash.c builtin/worktree.c fetch-pack.c http-fetch.c
+#: revision.c
 #, c-format
 msgid "the option '%s' requires '%s'"
 msgstr "l'opció «%s» requereix «%s»"
 
+#: archive.c
 msgid "Unexpected option --output"
 msgstr "Opció inesperada --output"
 
+#: archive.c t/unit-tests/unit-test.c
 #, c-format
 msgid "extra command line parameter '%s'"
 msgstr "paràmetre extra de la línia d'ordres «%s»"
 
+#: archive.c
 #, c-format
 msgid "Unknown archive format '%s'"
 msgstr "Format d'arxiu desconegut «%s»"
 
+#: archive.c
 #, c-format
 msgid "Argument not supported for format '%s': -%d"
 msgstr "Argument no admès per al format «%s»: -%d"
 
+#: attr.c
 #, c-format
 msgid "%.*s is not a valid attribute name"
 msgstr "%.*s no és un nom d'atribut vàlid"
 
+#: attr.c
 msgid "unable to add additional attribute"
 msgstr "no s'ha pogut afegir l'atribut addicional"
 
+#: attr.c
 #, c-format
 msgid "ignoring overly long attributes line %d"
 msgstr "s'ignorarà la línia d'atributs massa llarga %d"
 
+#: attr.c
 #, c-format
 msgid "%s not allowed: %s:%d"
 msgstr "%s no està permès: %s:%d"
 
+#: attr.c
 msgid ""
 "Negative patterns are ignored in git attributes\n"
 "Use '\\!' for literal leading exclamation."
@@ -1538,41 +1919,56 @@
 "Els patrons negatius s'ignoren en els atributs de git\n"
 "Useu «\\!» per exclamació capdavantera literal."
 
+#: attr.c
 #, c-format
 msgid "cannot fstat gitattributes file '%s'"
 msgstr "no es pot fer fstat gitattributes al fitxer «%s»"
 
+#: attr.c
 #, c-format
 msgid "ignoring overly large gitattributes file '%s'"
 msgstr "s'ignorarà el fitxer «%s» gitattributes per a ser massa gran"
 
+#: attr.c
 #, c-format
 msgid "ignoring overly large gitattributes blob '%s'"
 msgstr "s'ignorarà el blob «%s» gitattributes per a ser massa gran"
 
+#: attr.c
+msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo"
+msgstr "no es pot usar --attr-source o GIT_ATTR_SOURCE sense repository"
+
+#: attr.c
 msgid "bad --attr-source or GIT_ATTR_SOURCE"
 msgstr "--attr-source incorrecte o GIT_ATTR_SOURCE"
 
+#: attr.c read-cache.c
 #, c-format
 msgid "unable to stat '%s'"
 msgstr "no s'ha pogut fer «stat» a «%s»"
 
+#: bisect.c builtin/cat-file.c builtin/index-pack.c builtin/notes.c
+#: builtin/pack-objects.c combine-diff.c object-file.c rerere.c
 #, c-format
 msgid "unable to read %s"
 msgstr "no s'ha pogut llegir %s"
 
+#: bisect.c
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Comentari amb cometes errònies en el fitxer «%s»: %s"
 
+#: bisect.c
 #, c-format
 msgid "We cannot bisect more!\n"
 msgstr "No podem bisecar més!\n"
 
+#: bisect.c
 #, c-format
 msgid "Not a valid commit name %s"
 msgstr "No és un nom de comissió vàlid %s"
 
+#: bisect.c
 #, c-format
 msgid ""
 "The merge base %s is bad.\n"
@@ -1581,6 +1977,7 @@
 "La base de fusió %s és errònia.\n"
 "Això vol dir que el defecte s'ha arreglat entre %s i [%s].\n"
 
+#: bisect.c
 #, c-format
 msgid ""
 "The merge base %s is new.\n"
@@ -1589,6 +1986,7 @@
 "La base de fusió %s és nova.\n"
 "La propietat s'ha canviat entre %s i [%s].\n"
 
+#: bisect.c
 #, c-format
 msgid ""
 "The merge base %s is %s.\n"
@@ -1597,6 +1995,7 @@
 "La base de fusió %s és %s.\n"
 "Això vol dir que la primera comissió «%s» és entre %s i [%s].\n"
 
+#: bisect.c
 #, c-format
 msgid ""
 "Some %s revs are not ancestors of the %s rev.\n"
@@ -1607,6 +2006,7 @@
 "git bisect no pot funcionar correctament en aquest cas.\n"
 "Potser heu confós les revisions %s i %s?\n"
 
+#: bisect.c
 #, c-format
 msgid ""
 "the merge base between %s and [%s] must be skipped.\n"
@@ -1618,29 +2018,41 @@
 "%s.\n"
 "Continuem de totes maneres."
 
+#: bisect.c
 #, c-format
 msgid "Bisecting: a merge base must be tested\n"
 msgstr "Bisecant: s'ha de provar una base de fusió\n"
 
+#: bisect.c
 #, c-format
 msgid "a %s revision is needed"
 msgstr "es necessita una revisió %s"
 
+#: bisect.c
 #, c-format
 msgid "could not create file '%s'"
 msgstr "no s'ha pogut crear el fitxer «%s»"
 
+#: bisect.c builtin/notes.c
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "no s'ha pogut iniciar «show» per a l'objecte «%s»"
+
+#: bisect.c builtin/merge.c
 #, c-format
 msgid "could not read file '%s'"
 msgstr "no s'ha pogut llegir el fitxer «%s»"
 
+#: bisect.c
 msgid "reading bisect refs failed"
 msgstr "la lectura de les referències de bisecció ha fallat"
 
+#: bisect.c
 #, c-format
 msgid "%s was both %s and %s\n"
 msgstr "%s era ambdós %s i %s\n"
 
+#: bisect.c
 #, c-format
 msgid ""
 "No testable commit found.\n"
@@ -1649,6 +2061,7 @@
 "No s'ha trobat cap comissió comprovable.\n"
 "Potser heu començat amb paràmetres de camí incorrectes?\n"
 
+#: bisect.c
 #, c-format
 msgid "(roughly %d step)"
 msgid_plural "(roughly %d steps)"
@@ -1658,36 +2071,46 @@
 #. TRANSLATORS: the last %s will be replaced with "(roughly %d
 #. steps)" translation.
 #.
+#: bisect.c
 #, 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] "Bisecant: manca %d revisió a provar després d'aquesta %s\n"
 msgstr[1] "Bisecant: manquen %d revisions a provar després d'aquesta %s\n"
 
+#: blame.c
 msgid "--contents and --reverse do not blend well."
 msgstr "--contents i --reverse no funcionen bé juntes."
 
+#: blame.c
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr ""
 "--reverse i --first-parent junts requereixen una última comissió especificada"
 
+#: blame.c builtin/bisect.c builtin/commit.c builtin/log.c builtin/merge.c
+#: builtin/pack-objects.c builtin/shortlog.c midx-write.c pack-bitmap.c
+#: remote.c sequencer.c submodule.c
 msgid "revision walk setup failed"
 msgstr "la configuració del recorregut de revisions ha fallat"
 
+#: blame.c
 msgid ""
 "--reverse --first-parent together require range along first-parent chain"
 msgstr ""
 "--reverse --first-parent junts requereixen un rang de la cadena de pares "
 "primers"
 
+#: blame.c
 #, c-format
 msgid "no such path %s in %s"
 msgstr "no hi ha tal camí %s en %s"
 
+#: blame.c
 #, c-format
 msgid "cannot read blob %s for path %s"
 msgstr "no es pot llegir el blob %s per al camí %s"
 
+#: branch.c
 msgid ""
 "cannot inherit upstream tracking configuration of multiple refs when "
 "rebasing is requested"
@@ -1695,25 +2118,31 @@
 "no es pot heretar la configuració del seguiment de la font de múltiples "
 "referències quan es demana fer «rebase»"
 
+#: branch.c
 #, c-format
 msgid "not setting branch '%s' as its own upstream"
 msgstr "no s'està establert la branca «%s» com a la seva pròpia font"
 
+#: branch.c
 #, c-format
 msgid "branch '%s' set up to track '%s' by rebasing."
 msgstr "la branca «%s» està configurada per a seguir «%s» fent «rebase»."
 
+#: branch.c
 #, c-format
 msgid "branch '%s' set up to track '%s'."
 msgstr "la branca «%s» està configurada per a seguir «%s»."
 
+#: branch.c
 #, c-format
 msgid "branch '%s' set up to track:"
 msgstr "la branca «%s» està configurada per a seguir:"
 
+#: branch.c
 msgid "unable to write upstream branch configuration"
 msgstr "no es pot escriure la configuració de la branca font"
 
+#: branch.c
 msgid ""
 "\n"
 "After fixing the error cause you may try to fix up\n"
@@ -1723,18 +2152,21 @@
 "Després de corregir la causa de l'error, podeu intentar\n"
 "corregir la informació de seguiment remot executant:"
 
+#: branch.c
 #, c-format
 msgid "asked to inherit tracking from '%s', but no remote is set"
 msgstr ""
 "s'ha demanat que hereti el seguiment de «%s», però no s'ha establert cap "
 "remot"
 
+#: branch.c
 #, c-format
 msgid "asked to inherit tracking from '%s', but no merge configuration is set"
 msgstr ""
 "s'ha demanat que hereti el seguiment de «%s», però no s'ha establert cap "
 "configuració de fusionat"
 
+#: branch.c
 #, c-format
 msgid "not tracking: ambiguous information for ref '%s'"
 msgstr "no s'està seguint: informació ambigua per a la referència «%s»"
@@ -1750,6 +2182,7 @@
 #. you'll probably want to swap the "%s" and leading " " space
 #. around.
 #.
+#: branch.c object-name.c
 #, c-format
 msgid "  %s\n"
 msgstr "  %s\n"
@@ -1757,6 +2190,7 @@
 #. TRANSLATORS: The second argument is a \n-delimited list of
 #. duplicate refspecs, composed above.
 #.
+#: branch.c
 #, c-format
 msgid ""
 "There are multiple remotes whose fetch refspecs map to the remote\n"
@@ -1777,30 +2211,40 @@
 "els diferents refspecs remots s'assignen a diferents espais de noms\n"
 "de seguiment."
 
+#: branch.c
 #, c-format
 msgid "'%s' is not a valid branch name"
 msgstr "«%s» no és un nom de branca vàlid"
 
+#: branch.c builtin/branch.c
+msgid "See `man git check-ref-format`"
+msgstr "Vegeu `man git check-ref-format`"
+
+#: branch.c
 #, c-format
 msgid "a branch named '%s' already exists"
 msgstr "ja existeix una branca amb nom «%s»"
 
+#: branch.c
 #, c-format
 msgid "cannot force update the branch '%s' used by worktree at '%s'"
 msgstr ""
 "no es pot forçar l'actualització de la branca «%s» utilitzada per l'arbre de "
 "treball a «%s»"
 
+#: branch.c
 #, c-format
 msgid "cannot set up tracking information; starting point '%s' is not a branch"
 msgstr ""
 "no es pot configurar la informació de seguiment; el punt inicial «%s» no és "
 "una branca"
 
+#: branch.c
 #, c-format
 msgid "the requested upstream branch '%s' does not exist"
 msgstr "la branca font demanada «%s» no existeix"
 
+#: branch.c
 msgid ""
 "\n"
 "If you are planning on basing your work on an upstream\n"
@@ -1821,22 +2265,27 @@
 "«git push -u» per a establir la configuració font\n"
 "mentre pugeu."
 
+#: branch.c builtin/replace.c
 #, c-format
 msgid "not a valid object name: '%s'"
 msgstr "no és un nom d'objecte vàlid: «%s»"
 
+#: branch.c
 #, c-format
 msgid "ambiguous object name: '%s'"
 msgstr "nom d'objecte ambigu: «%s»"
 
+#: branch.c
 #, c-format
 msgid "not a valid branch point: '%s'"
 msgstr "no és un punt de ramificació vàlid: «%s»"
 
+#: branch.c
 #, c-format
 msgid "submodule '%s': unable to find submodule"
 msgstr "submòdul «%s»: no es pot trobar el submòdul"
 
+#: branch.c
 #, c-format
 msgid ""
 "You may try updating the submodules using 'git checkout --no-recurse-"
@@ -1845,105 +2294,131 @@
 "Podeu provar d'actualitzar els submòduls utilitzant «git checkout --no-"
 "recurse-submodules %s && git submodule update --init»"
 
+#: branch.c
 #, c-format
 msgid "submodule '%s': cannot create branch '%s'"
 msgstr "submòdul «%s»: no es pot crear la branca: «%s»"
 
+#: branch.c
 #, c-format
 msgid "'%s' is already used by worktree at '%s'"
 msgstr "«%s» ja s'utilitza en l'arbre de treball a «%s»"
 
+#: builtin/add.c
 msgid "git add [<options>] [--] <pathspec>..."
-msgstr "git add [<opcions>] [--] <especificació-de-camí>..."
+msgstr "git add [<opcions>] [--] <especificació-camí>..."
 
+#: builtin/add.c
 #, c-format
 msgid "cannot chmod %cx '%s'"
 msgstr "no es pot fer chmod %cx «%s»"
 
+#: builtin/add.c
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Canvis «unstaged» després d'actualitzar l'índex:"
 
-msgid ""
-"the add.interactive.useBuiltin setting has been removed!\n"
-"See its entry in 'git help config' for details."
-msgstr ""
-"s'ha eliminat la configuració add.interactive.useBuiltin\n"
-"Per a més detalls, vegeu la seva entrada a «git help config»."
-
+#: builtin/add.c
 msgid "could not read the index"
 msgstr "no s'ha pogut llegir l'índex"
 
+#: builtin/add.c
 msgid "editing patch failed"
 msgstr "l'edició del pedaç ha fallat"
 
+#: builtin/add.c read-cache.c
 #, c-format
 msgid "could not stat '%s'"
 msgstr "no s'ha pogut fer stat a «%s»"
 
+#: builtin/add.c
 msgid "empty patch. aborted"
 msgstr "pedaç buit. interromput"
 
+#: builtin/add.c
 #, c-format
 msgid "could not apply '%s'"
 msgstr "no s'ha pogut aplicar «%s»"
 
+#: builtin/add.c
 msgid "The following paths are ignored by one of your .gitignore files:\n"
 msgstr ""
 "Els camins següents s'ignoren per un dels vostres fitxers .gitignore:\n"
 
+#: builtin/add.c builtin/clean.c builtin/fetch.c builtin/mv.c
+#: builtin/prune-packed.c builtin/pull.c builtin/push.c builtin/remote.c
+#: builtin/rm.c builtin/send-pack.c
 msgid "dry run"
 msgstr "fes una prova"
 
+#: builtin/add.c builtin/check-ignore.c builtin/commit.c
+#: builtin/count-objects.c builtin/fsck.c builtin/log.c builtin/mv.c
+#: builtin/read-tree.c builtin/refs.c
 msgid "be verbose"
 msgstr "sigues detallat"
 
+#: builtin/add.c
 msgid "interactive picking"
 msgstr "selecció interactiva"
 
+#: builtin/add.c builtin/checkout.c builtin/reset.c
 msgid "select hunks interactively"
 msgstr "selecciona els trossos interactivament"
 
+#: builtin/add.c
 msgid "edit current diff and apply"
 msgstr "edita la diferència actual i aplica-la"
 
+#: builtin/add.c
 msgid "allow adding otherwise ignored files"
 msgstr "permet afegir fitxers que d'altra manera s'ignoren"
 
+#: builtin/add.c
 msgid "update tracked files"
 msgstr "actualitza els fitxers seguits"
 
+#: builtin/add.c
 msgid "renormalize EOL of tracked files (implies -u)"
 msgstr "torna a normalitzar EOL dels fitxers seguits (implica -u)"
 
+#: builtin/add.c
 msgid "record only the fact that the path will be added later"
 msgstr "registra només el fet que el camí s'afegirà més tard"
 
+#: builtin/add.c
 msgid "add changes from all tracked and untracked files"
 msgstr "afegeix els canvis de tots els fitxers seguits i no seguits"
 
+#: builtin/add.c
 msgid "ignore paths removed in the working tree (same as --no-all)"
 msgstr ""
 "ignora els camins eliminats en l'arbre de treball (el mateix que --no-all)"
 
+#: builtin/add.c
 msgid "don't add, only refresh the index"
 msgstr "no afegeixis, només actualitza l'índex"
 
+#: builtin/add.c
 msgid "just skip files which cannot be added because of errors"
 msgstr "només omet els fitxers que no es poden afegir a causa d'errors"
 
+#: builtin/add.c
 msgid "check if - even missing - files are ignored in dry run"
 msgstr ""
 "comprova si els fitxers, fins i tot els absents, s'ignoren en fer una prova"
 
+#: builtin/add.c builtin/mv.c builtin/rm.c
 msgid "allow updating entries outside of the sparse-checkout cone"
 msgstr "permet actualitzar les entrades fora del con del «sparse-checkout»"
 
+#: builtin/add.c builtin/update-index.c
 msgid "override the executable bit of the listed files"
 msgstr "sobreescriu el bit executable dels fitxers llistats"
 
+#: builtin/add.c
 msgid "warn when adding an embedded repository"
 msgstr "avisa'm quan s'afegeixi un repositori incrustat"
 
+#: builtin/add.c
 #, c-format
 msgid ""
 "You've added another git repository inside your current repository.\n"
@@ -1974,161 +2449,197 @@
 "\n"
 "Vegeu «git help submodule» per a més informació."
 
+#: builtin/add.c
 #, c-format
 msgid "adding embedded git repository: %s"
 msgstr "s'està afegint un repositori incrustat: %s"
 
-msgid ""
-"Use -f if you really want to add them.\n"
-"Turn this message off by running\n"
-"\"git config advice.addIgnoredFile false\""
-msgstr ""
-"Utilitzeu -f si realment voleu afegir-los.\n"
-"Desactiveu aquest missatge executant\n"
-"«git config advice.addIgnoredFile false»"
+#: builtin/add.c
+msgid "Use -f if you really want to add them."
+msgstr "\"Useu -f si realment voleu afegir-los."
 
+#: builtin/add.c
 msgid "adding files failed"
 msgstr "l'afegiment de fitxers ha fallat"
 
+#: builtin/add.c
 #, c-format
 msgid "--chmod param '%s' must be either -x or +x"
 msgstr "el paràmetre --chmod «%s» ha de ser o -x o +x"
 
+#: builtin/add.c builtin/checkout.c builtin/commit.c builtin/reset.c
+#: builtin/rm.c builtin/stash.c
 #, c-format
 msgid "'%s' and pathspec arguments cannot be used together"
 msgstr "«%s» i l'especificació de camí no es poden usar juntes"
 
+#: builtin/add.c
 #, c-format
 msgid "Nothing specified, nothing added.\n"
 msgstr "No s'ha especificat res, no s'ha afegit res.\n"
 
-msgid ""
-"Maybe you wanted to say 'git add .'?\n"
-"Turn this message off by running\n"
-"\"git config advice.addEmptyPathspec false\""
-msgstr ""
-"Potser voleu dir «git add .»?\n"
-"Desactiveu aquest missatge executant\n"
-"«git config advice.addEmptyPathspec false»"
+#: builtin/add.c
+msgid "Maybe you wanted to say 'git add .'?"
+msgstr "Que potser volíeu dir «git add.»?"
 
+#: builtin/add.c builtin/check-ignore.c builtin/checkout.c builtin/clean.c
+#: builtin/commit.c builtin/diff-tree.c builtin/grep.c builtin/mv.c
+#: builtin/reset.c builtin/rm.c builtin/submodule--helper.c read-cache.c
+#: rerere.c submodule.c
 msgid "index file corrupt"
 msgstr "fitxer d'índex malmès"
 
+#: builtin/add.c builtin/am.c builtin/checkout.c builtin/clone.c
+#: builtin/commit.c builtin/stash.c merge.c rerere.c
 msgid "unable to write new index file"
 msgstr "no s'ha pogut escriure un fitxer d'índex nou"
 
+#: builtin/am.c builtin/mailinfo.c mailinfo.c
 #, c-format
 msgid "bad action '%s' for '%s'"
 msgstr "acció «%s» incorrecta per a «%s»"
 
+#: builtin/am.c builtin/blame.c builtin/fetch.c builtin/pack-objects.c
+#: builtin/pull.c builtin/revert.c config.c diff-merges.c gpg-interface.c
+#: ls-refs.c parallel-checkout.c sequencer.c setup.c
 #, c-format
 msgid "invalid value for '%s': '%s'"
 msgstr "valor no vàlid per a «%s»: «%s»"
 
+#: builtin/am.c builtin/commit.c builtin/merge.c sequencer.c
 #, c-format
 msgid "could not read '%s'"
 msgstr "no s'ha pogut llegir «%s»"
 
+#: builtin/am.c
 msgid "could not parse author script"
 msgstr "no s'ha pogut analitzar l'script d'autor"
 
+#: builtin/am.c builtin/replace.c commit.c sequencer.c
 #, c-format
 msgid "could not parse %s"
 msgstr "no s'ha pogut analitzar %s"
 
+#: builtin/am.c
 #, c-format
 msgid "'%s' was deleted by the applypatch-msg hook"
 msgstr "s'ha suprimit «%s» pel lligam applypatch-msg"
 
+#: builtin/am.c
 #, c-format
 msgid "Malformed input line: '%s'."
 msgstr "Línia d'entrada mal formada: «%s»."
 
+#: builtin/am.c
 #, c-format
 msgid "Failed to copy notes from '%s' to '%s'"
 msgstr "S'ha produït un error en copiar les notes de «%s» a «%s»"
 
+#: builtin/am.c
 msgid "fseek failed"
 msgstr "fseek ha fallat"
 
+#: builtin/am.c builtin/rebase.c sequencer.c wrapper.c
 #, c-format
 msgid "could not open '%s' for reading"
 msgstr "no s'ha pogut obrir «%s» per a lectura"
 
+#: builtin/am.c builtin/rebase.c editor.c sequencer.c wrapper.c
 #, c-format
 msgid "could not open '%s' for writing"
 msgstr "no s'ha pogut obrir «%s» per a escriptura"
 
+#: builtin/am.c
 #, c-format
 msgid "could not parse patch '%s'"
 msgstr "no s'ha pogut analitzar el pedaç «%s»"
 
+#: builtin/am.c
 msgid "Only one StGIT patch series can be applied at once"
 msgstr "Només una sèrie de pedaços StGIT es pot aplicar a la vegada"
 
+#: builtin/am.c
 msgid "invalid timestamp"
 msgstr "marca de temps no vàlida"
 
+#: builtin/am.c
 msgid "invalid Date line"
 msgstr "línia Date no vàlida"
 
+#: builtin/am.c
 msgid "invalid timezone offset"
 msgstr "desplaçament del fus horari no vàlid"
 
+#: builtin/am.c
 msgid "Patch format detection failed."
 msgstr "La detecció de format de pedaç ha fallat."
 
+#: builtin/am.c builtin/clone.c
 #, c-format
 msgid "failed to create directory '%s'"
 msgstr "s'ha produït un error en crear el directori «%s»"
 
+#: builtin/am.c
 msgid "Failed to split patches."
 msgstr "S'ha produït un error en dividir els pedaços."
 
+#: builtin/am.c
 #, c-format
-msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "Quan hàgiu resolt aquest problema, executeu «%s --continue»."
+msgid "When you have resolved this problem, run \"%s --continue\".\n"
+msgstr "Quan hàgiu resolt aquest problema, executeu «%s --continue».\n"
 
+#: builtin/am.c
 #, c-format
-msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
-msgstr "Si preferiu ometre aquest pedaç, executeu «%s --skip» en lloc d'això."
+msgid "If you prefer to skip this patch, run \"%s --skip\" instead.\n"
+msgstr ""
+"Si preferiu ometre aquest pedaç, executeu «%s --skip» en lloc d'això.\n"
 
+#: builtin/am.c
 #, c-format
-msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
+msgid ""
+"To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"
 msgstr ""
 "Per a enregistrar un pedaç buit com a comissió buida, executeu «%s --allow-"
-"empty»."
+"empty».\n"
 
+#: builtin/am.c
 #, c-format
 msgid "To restore the original branch and stop patching, run \"%s --abort\"."
 msgstr ""
 "Per a restaurar la branca original i deixar d'apedaçar, executeu «%s --"
 "abort»."
 
+#: builtin/am.c
 msgid "Patch sent with format=flowed; space at the end of lines might be lost."
 msgstr ""
 "Pedaç enviat amb format=flowed; es pot perdre l'espai al final de les línies."
 
+#: builtin/am.c
 #, c-format
 msgid "missing author line in commit %s"
 msgstr "manca la línia d'autor en la comissió %s"
 
+#: builtin/am.c
 #, c-format
 msgid "invalid ident line: %.*s"
 msgstr "línia d'identitat no vàlida: %.*s"
 
+#: builtin/am.c builtin/checkout.c builtin/clone.c commit-graph.c
 #, c-format
 msgid "unable to parse commit %s"
 msgstr "no s'ha pogut analitzar la comissió %s"
 
+#: builtin/am.c
 msgid "Repository lacks necessary blobs to fall back on 3-way merge."
 msgstr ""
 "Al repositori li manquen els blobs necessaris per a retrocedir a una fusió "
 "de 3 vies."
 
+#: builtin/am.c
 msgid "Using index info to reconstruct a base tree..."
 msgstr "S'està usant la informació d'índex per a reconstruir un arbre base..."
 
+#: builtin/am.c
 msgid ""
 "Did you hand edit your patch?\n"
 "It does not apply to blobs recorded in its index."
@@ -2136,25 +2647,32 @@
 "Heu editat el vostre pedaç a mà?\n"
 "No s'aplica als blobs recordats en el seu índex."
 
+#: builtin/am.c
 msgid "Falling back to patching base and 3-way merge..."
 msgstr "S'està retrocedint a apedaçar la base i una fusió de 3 vies..."
 
+#: builtin/am.c
 msgid "Failed to merge in the changes."
 msgstr "S'ha produït un error en fusionar els canvis."
 
+#: builtin/am.c builtin/merge.c sequencer.c
 msgid "git write-tree failed to write a tree"
 msgstr "git write-tree ha fallat en escriure un arbre"
 
+#: builtin/am.c
 msgid "applying to an empty history"
 msgstr "s'està aplicant a una història buida"
 
+#: builtin/am.c builtin/commit.c builtin/merge.c builtin/replay.c sequencer.c
 msgid "failed to write commit object"
 msgstr "s'ha produït un error en escriure l'objecte de comissió"
 
+#: builtin/am.c
 #, c-format
 msgid "cannot resume: %s does not exist."
 msgstr "no es pot reprendre: %s no existeix."
 
+#: builtin/am.c
 msgid "Commit Body is:"
 msgstr "El cos de la comissió és:"
 
@@ -2162,48 +2680,60 @@
 #. in your translation. The program will only accept English
 #. input at this point.
 #.
+#: builtin/am.c
 #, c-format
 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "
 msgstr ""
 "Voleu aplicar-lo? [y]es/[n]o/[e]dita/[v]isualitza el pedaç/[a]ccepta'ls "
 "tots: "
 
+#: builtin/am.c builtin/commit.c
 msgid "unable to write index file"
 msgstr "no s'ha pogut escriure el fitxer d'índex"
 
+#: builtin/am.c
 #, c-format
 msgid "Dirty index: cannot apply patches (dirty: %s)"
 msgstr "Índex brut: no es poden aplicar pedaços (bruts: %s)"
 
+#: builtin/am.c
 #, c-format
 msgid "Skipping: %.*s"
 msgstr "S'està ometent: %.*s"
 
+#: builtin/am.c
 #, c-format
 msgid "Creating an empty commit: %.*s"
 msgstr "S'està creant una comissió buida: %.*s"
 
+#: builtin/am.c
 msgid "Patch is empty."
 msgstr "El pedaç està buit."
 
+#: builtin/am.c
 #, c-format
 msgid "Applying: %.*s"
 msgstr "S'està aplicant: %.*s"
 
+#: builtin/am.c
 msgid "No changes -- Patch already applied."
 msgstr "Sense canvis -- El pedaç ja s'ha aplicat."
 
+#: builtin/am.c
 #, c-format
 msgid "Patch failed at %s %.*s"
 msgstr "El pedaç ha fallat a %s %.*s"
 
+#: builtin/am.c
 msgid "Use 'git am --show-current-patch=diff' to see the failed patch"
 msgstr ""
 "Useu «git am --show-current-patch=diff» per a veure el pedaç que ha fallat"
 
+#: builtin/am.c
 msgid "No changes - recorded it as an empty commit."
 msgstr "No hi ha canvis - enregistrat com una comissió buida."
 
+#: builtin/am.c
 msgid ""
 "No changes - did you forget to use 'git add'?\n"
 "If there is nothing left to stage, chances are that something else\n"
@@ -2213,6 +2743,7 @@
 "Si no hi ha res per a fer «stage», probablement alguna altra cosa ja ha\n"
 "introduït els mateixos canvis; potser voleu ometre aquest pedaç."
 
+#: builtin/am.c
 msgid ""
 "You still have unmerged paths in your index.\n"
 "You should 'git add' each file with resolved conflicts to mark them as "
@@ -2225,13 +2756,16 @@
 "Podeu executar «git rm» en un fitxer per a acceptar «suprimit per ells» pel "
 "fitxer."
 
+#: builtin/am.c builtin/reset.c
 #, c-format
 msgid "Could not parse object '%s'."
 msgstr "No s'ha pogut analitzar l'objecte «%s»."
 
+#: builtin/am.c
 msgid "failed to clean index"
 msgstr "s'ha produït un error en netejar l'índex"
 
+#: builtin/am.c
 msgid ""
 "You seem to have moved HEAD since the last 'am' failure.\n"
 "Not rewinding to ORIG_HEAD"
@@ -2239,109 +2773,155 @@
 "Sembla que heu mogut HEAD després de l'última fallada de «am».\n"
 "No s'està rebobinant a ORIG_HEAD"
 
+#: builtin/am.c builtin/bisect.c builtin/tag.c worktree.c
 #, c-format
 msgid "failed to read '%s'"
 msgstr "s'ha produït un error en llegir «%s»"
 
+#: builtin/am.c
 msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
 msgstr "git am [<opcions>] [(<bústia> | <directori-de-correu>)...]"
 
+#: builtin/am.c
 msgid "git am [<options>] (--continue | --skip | --abort)"
 msgstr "git am [<opcions>] (--continue | --skip | --abort)"
 
+#: builtin/am.c
 msgid "run interactively"
 msgstr "executa interactivament"
 
+#: builtin/am.c
 msgid "bypass pre-applypatch and applypatch-msg hooks"
 msgstr "evita els lligams pre-applypatch i applypatch-msg"
 
+#: builtin/am.c
 msgid "historical option -- no-op"
 msgstr "opció històrica -- no-op"
 
+#: builtin/am.c
 msgid "allow fall back on 3way merging if needed"
 msgstr "permet retrocedir a una fusió de 3 vies si és necessari"
 
+#: builtin/am.c builtin/init-db.c builtin/prune-packed.c builtin/repack.c
+#: builtin/stash.c
 msgid "be quiet"
 msgstr "silenciós"
 
+#: builtin/am.c
 msgid "add a Signed-off-by trailer to the commit message"
 msgstr "afegeix un «trailer» tipus «Signed-off-by» al missatge de comissió"
 
+#: builtin/am.c
 msgid "recode into utf8 (default)"
 msgstr "recodifica en utf8 (per defecte)"
 
+#: builtin/am.c
 msgid "pass -k flag to git-mailinfo"
 msgstr "passa l'indicador -k a git-mailinfo"
 
+#: builtin/am.c
 msgid "pass -b flag to git-mailinfo"
 msgstr "passa l'indicador -b a git-mailinfo"
 
+#: builtin/am.c
 msgid "pass -m flag to git-mailinfo"
 msgstr "passa l'indicador -m a git-mailinfo"
 
+#: builtin/am.c
 msgid "pass --keep-cr flag to git-mailsplit for mbox format"
 msgstr "passa l'indicador --keep-cr a git-mailsplit per al format mbox"
 
+#: builtin/am.c
 msgid "strip everything before a scissors line"
 msgstr "elimina tot abans d'una línia de tisores"
 
+#: builtin/am.c
 msgid "pass it through git-mailinfo"
 msgstr "passa-ho a través del git-mailinfo"
 
+#: builtin/am.c
 msgid "pass it through git-apply"
 msgstr "passa-ho a través de git-apply"
 
+#: builtin/am.c builtin/commit.c builtin/fmt-merge-msg.c builtin/grep.c
+#: builtin/merge.c builtin/pull.c builtin/rebase.c builtin/repack.c
+#: builtin/show-branch.c builtin/show-ref.c builtin/tag.c parse-options.h
 msgid "n"
 msgstr "n"
 
+#: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
+#: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c
+#: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/verify-tag.c
 msgid "format"
 msgstr "format"
 
+#: builtin/am.c
 msgid "format the patch(es) are in"
 msgstr "el format en el qual estan els pedaços"
 
+#: builtin/am.c
 msgid "override error message when patch failure occurs"
 msgstr "sobreescriu el missatge d'error si falla l'aplicació del pedaç"
 
+#: builtin/am.c
 msgid "continue applying patches after resolving a conflict"
 msgstr "segueix aplicant pedaços després de resoldre un conflicte"
 
+#: builtin/am.c
 msgid "synonyms for --continue"
 msgstr "sinònims de --continue"
 
+#: builtin/am.c
 msgid "skip the current patch"
 msgstr "omet el pedaç actual"
 
+#: builtin/am.c
 msgid "restore the original branch and abort the patching operation"
 msgstr "restaura la branca original i interromp l'operació d'apedaçament"
 
+#: builtin/am.c
 msgid "abort the patching operation but keep HEAD where it is"
 msgstr "interromp l'operació d'apedaçament però manté HEAD on és"
 
+#: builtin/am.c
 msgid "show the patch being applied"
 msgstr "mostra el pedaç que s'està aplicant"
 
+#: builtin/am.c
+msgid "try to apply current patch again"
+msgstr "intenta aplicar el pedaç actual de nou"
+
+#: builtin/am.c
 msgid "record the empty patch as an empty commit"
 msgstr "registra el pedaç buit com una comissió buida"
 
+#: builtin/am.c
 msgid "lie about committer date"
 msgstr "menteix sobre la data del comitent"
 
+#: builtin/am.c
 msgid "use current timestamp for author date"
 msgstr "usa la marca de temps actual per a la data d'autor"
 
+#: builtin/am.c builtin/commit-tree.c builtin/commit.c builtin/merge.c
+#: builtin/pull.c builtin/rebase.c builtin/revert.c builtin/tag.c
 msgid "key-id"
 msgstr "ID de clau"
 
+#: builtin/am.c builtin/rebase.c
 msgid "GPG-sign commits"
 msgstr "signa les comissions amb GPG"
 
+#: builtin/am.c
 msgid "how to handle empty patches"
 msgstr "com gestionar les comissions buides"
 
+#: builtin/am.c
 msgid "(internal use for git-rebase)"
 msgstr "(ús intern per a git-rebase)"
 
+#: builtin/am.c
 msgid ""
 "The -b/--binary option has been a no-op for long time, and\n"
 "it will be removed. Please do not use it anymore."
@@ -2349,15 +2929,18 @@
 "Fa molt que l'opció -b/--binary no fa res, i\n"
 "s'eliminarà. No l'useu més."
 
+#: builtin/am.c
 msgid "failed to read the index"
 msgstr "s'ha produït un error en llegir l'índex"
 
+#: builtin/am.c
 #, c-format
 msgid "previous rebase directory %s still exists but mbox given."
 msgstr ""
 "un directori de «rebase» anterior %s encara existeix però s'ha donat una "
 "bústia."
 
+#: builtin/am.c
 #, c-format
 msgid ""
 "Stray %s directory found.\n"
@@ -2366,34 +2949,40 @@
 "S'ha trobat un directori %s extraviat.\n"
 "Useu «git am --abort» per a eliminar-lo."
 
+#: builtin/am.c
 msgid "Resolve operation not in progress, we are not resuming."
 msgstr "Una operació de resolució no està en curs; no reprenem."
 
+#: builtin/am.c
 msgid "interactive mode requires patches on the command line"
 msgstr "el mode interactiu requereix pedaços a la línia d'ordres"
 
+#: builtin/apply.c
 msgid "git apply [<options>] [<patch>...]"
 msgstr "git apply [<opcions>] [<pedaç>...]"
 
+#: builtin/archive.c diagnose.c
 msgid "could not redirect output"
 msgstr "no s'ha pogut redirigir la sortida"
 
-msgid "git archive: Remote with no URL"
-msgstr "git archive: Remot sense URL"
-
+#: builtin/archive.c
 msgid "git archive: expected ACK/NAK, got a flush packet"
 msgstr "git archive: s'esperava ACK/NAK, s'ha rebut un paquet de buidatge"
 
+#: builtin/archive.c
 #, c-format
 msgid "git archive: NACK %s"
 msgstr "git archive: %s NACK"
 
+#: builtin/archive.c
 msgid "git archive: protocol error"
 msgstr "git archive: error de protocol"
 
+#: builtin/archive.c
 msgid "git archive: expected a flush"
 msgstr "git archive: s'esperava una neteja"
 
+#: builtin/bisect.c
 msgid ""
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
 "checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
@@ -2401,56 +2990,71 @@
 "git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]    [--no-"
 "checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 
+#: builtin/bisect.c
 msgid "git bisect (good|bad) [<rev>...]"
-msgstr "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<revisió>...]"
 
+#: builtin/bisect.c
 msgid "git bisect skip [(<rev>|<range>)...]"
-msgstr "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<revisió>|<rang>)...]"
 
+#: builtin/bisect.c
 msgid "git bisect reset [<commit>]"
 msgstr "git bisect reset [<comissió>]"
 
+#: builtin/bisect.c
 msgid "git bisect replay <logfile>"
-msgstr "git bisect replay <logfile>"
+msgstr "git bisect replay "
 
+#: builtin/bisect.c
 msgid "git bisect run <cmd> [<arg>...]"
-msgstr "git bisect run <cmd> [<arg>...]"
+msgstr "git bisect run <ordre> [<arg>...]"
 
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' in mode '%s'"
 msgstr "no es pot obrir el fitxer «%s» en mode «%s»"
 
+#: builtin/bisect.c
 #, c-format
 msgid "could not write to file '%s'"
 msgstr "no s'ha pogut escriure el fitxer «%s»"
 
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' for reading"
 msgstr "no es pot obrir «%s» per a lectura"
 
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' is not a valid term"
 msgstr "«%s» no és un terme vàlid"
 
+#: builtin/bisect.c
 #, c-format
 msgid "can't use the builtin command '%s' as a term"
 msgstr "no es pot usar l'ordre interna «%s» com a terme"
 
+#: builtin/bisect.c
 #, c-format
 msgid "can't change the meaning of the term '%s'"
 msgstr "no es pot canviar el significat del terme «%s»"
 
+#: builtin/bisect.c
 msgid "please use two different terms"
 msgstr "useu dos termes diferents"
 
+#: builtin/bisect.c
 #, c-format
 msgid "We are not bisecting.\n"
 msgstr "No estem bisecant.\n"
 
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' is not a valid commit"
 msgstr "«%s» no és una comissió vàlida"
 
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "could not check out original HEAD '%s'. Try 'git bisect reset <commit>'."
@@ -2458,22 +3062,27 @@
 "no s'ha pogut agafar la HEAD original «%s». Proveu «git bisect reset "
 "<comissió>»."
 
+#: builtin/bisect.c
 #, c-format
 msgid "Bad bisect_write argument: %s"
 msgstr "Argument «bisect_write» incorrecte: %s"
 
+#: builtin/bisect.c
 #, c-format
 msgid "couldn't get the oid of the rev '%s'"
 msgstr "no s'ha pogut obtenir l'oid de la revisió «%s»"
 
+#: builtin/bisect.c
 #, c-format
 msgid "couldn't open the file '%s'"
 msgstr "no s'ha pogut obrir el fitxer «%s»"
 
+#: builtin/bisect.c
 #, c-format
 msgid "Invalid command: you're currently in a %s/%s bisect"
 msgstr "Ordre no vàlida: esteu actualment en una bisecció %s/%s"
 
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "You need to give me at least one %s and %s revision.\n"
@@ -2482,6 +3091,7 @@
 "Heu de donar com a mínim un %s i una revisió %s.\n"
 "Podeu usar «git bisect %s» i «git bisect %s» per a això."
 
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "You need to start by \"git bisect start\".\n"
@@ -2492,6 +3102,7 @@
 "Heu de donar com a mínim un %s i una revisió %s.\n"
 "Podeu usar «git bisect %s» i «git bisect %s» per a això."
 
+#: builtin/bisect.c
 #, c-format
 msgid "bisecting only with a %s commit"
 msgstr "bisecant amb només una comissió %s"
@@ -2500,12 +3111,15 @@
 #. translation. The program will only accept English input
 #. at this point.
 #.
+#: builtin/bisect.c
 msgid "Are you sure [Y/n]? "
 msgstr "N'esteu segur [Y/n]? "
 
+#: builtin/bisect.c
 msgid "status: waiting for both good and bad commits\n"
 msgstr "estat: s'estan esperant les comissions bones i dolentes\n"
 
+#: builtin/bisect.c
 #, c-format
 msgid "status: waiting for bad commit, %d good commit known\n"
 msgid_plural "status: waiting for bad commit, %d good commits known\n"
@@ -2515,13 +3129,16 @@
 "estat: s'està esperant una comissió incorrecta, es coneixen %d comissions "
 "bones\n"
 
+#: builtin/bisect.c
 msgid "status: waiting for good commit(s), bad commit known\n"
 msgstr ""
 "estat: s'està esperant comissions bones, es coneix una comissió incorrecta\n"
 
+#: builtin/bisect.c
 msgid "no terms defined"
 msgstr "cap terme definit"
 
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "Your current terms are %s for the old state\n"
@@ -2530,6 +3147,7 @@
 "Els termes actuals són %s per a l'estat antic\n"
 "i %s per al nou estat.\n"
 
+#: builtin/bisect.c
 #, c-format
 msgid ""
 "invalid argument %s for 'git bisect terms'.\n"
@@ -2538,39 +3156,45 @@
 "argument no vàlid %s per a «git bisect terms».\n"
 "Les opcions admeses són: --term-good|--term-old i --term-bad|--term-new."
 
-msgid "revision walk setup failed\n"
-msgstr "la configuració del recorregut de revisions ha fallat\n"
-
+#: builtin/bisect.c
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "no s'ha pogut obrir «%s» per a afegir-hi"
 
+#: builtin/bisect.c
 msgid "'' is not a valid term"
 msgstr "«%s» no és un terme vàlid"
 
+#: builtin/bisect.c
 #, c-format
 msgid "unrecognized option: '%s'"
 msgstr "opció no reconeguda: «%s»"
 
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' does not appear to be a valid revision"
 msgstr "«%s» no sembla ser una revisió vàlida"
 
+#: builtin/bisect.c
 msgid "bad HEAD - I need a HEAD"
 msgstr "HEAD incorrecte - cal una HEAD"
 
+#: builtin/bisect.c
 #, c-format
 msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
 msgstr ""
 "l'agafament de «%s» ha fallat. Proveu «git bisect start <branca-vàlida>»."
 
+#: builtin/bisect.c
 msgid "bad HEAD - strange symbolic ref"
 msgstr "HEAD incorrecte - referència simbòlica estranya"
 
+#: builtin/bisect.c
 #, c-format
 msgid "invalid ref: '%s'"
 msgstr "referència no és vàlida: «%s»"
 
+#: builtin/bisect.c
 msgid "You need to start by \"git bisect start\"\n"
 msgstr "Cal començar per «git bisect start»\n"
 
@@ -2578,215 +3202,278 @@
 #. translation. The program will only accept English input
 #. at this point.
 #.
+#: builtin/bisect.c
 msgid "Do you want me to do it for you [Y/n]? "
 msgstr "Voleu que ho faci per vostè [Y/n]? "
 
+#: builtin/bisect.c
 msgid "Please call `--bisect-state` with at least one argument"
 msgstr "Executeu «--bisect-state» amb almenys un argument"
 
+#: builtin/bisect.c
 #, c-format
 msgid "'git bisect %s' can take only one argument."
 msgstr "«git bisect %s» només pot acceptar un argument."
 
+#: builtin/bisect.c
 #, c-format
 msgid "Bad rev input: %s"
 msgstr "Entrada amb revisió errònia: %s"
 
+#: builtin/bisect.c
 #, c-format
 msgid "Bad rev input (not a commit): %s"
 msgstr "Entrada de revisió errònia (no és una comissió): %s"
 
+#: builtin/bisect.c
 msgid "We are not bisecting."
 msgstr "No estem bisecant."
 
+#: builtin/bisect.c
 #, c-format
 msgid "'%s'?? what are you talking about?"
 msgstr "«%s»? Què voleu dir?"
 
+#: builtin/bisect.c
 #, c-format
 msgid "cannot read file '%s' for replaying"
 msgstr "no es pot llegir «%s» per a reproducció"
 
+#: builtin/bisect.c
 #, c-format
 msgid "running %s\n"
 msgstr "s'està executant %s\n"
 
+#: builtin/bisect.c
 msgid "bisect run failed: no command provided."
 msgstr "ha fallat l'execució de bisect: no s'ha proporcionat cap ordre."
 
+#: builtin/bisect.c
 #, c-format
 msgid "unable to verify %s on good revision"
 msgstr "no s'ha pogut verificar «%s» en una bona revisió"
 
+#: builtin/bisect.c
 #, c-format
 msgid "bogus exit code %d for good revision"
 msgstr "codi d'error de sortida %d per a una bona revisió"
 
+#: builtin/bisect.c
 #, c-format
 msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
 msgstr ""
 "l'execució de la de bisecció ha fallat: codi de sortida %d de %s és < 0 o >= "
 "128"
 
+#: builtin/bisect.c
 #, c-format
 msgid "cannot open file '%s' for writing"
 msgstr "no es pot obrir «%s» per a escriptura"
 
+#: builtin/bisect.c
 msgid "bisect run cannot continue any more"
 msgstr "l'execució de la bisecció no pot continuar més"
 
+#: builtin/bisect.c
 msgid "bisect run success"
 msgstr "execució de bisecció amb èxit"
 
+#: builtin/bisect.c
 msgid "bisect found first bad commit"
 msgstr "la bisecció ha trobat una primera comissió errònia"
 
+#: builtin/bisect.c
 #, c-format
 msgid "bisect run failed: 'git bisect %s' exited with error code %d"
 msgstr ""
 "ha fallat l'execució del bisect: «git bisect %s» ha sortit amb el codi "
 "d'error %d"
 
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' requires either no argument or a commit"
 msgstr "«%s» no requereix cap argument ni comissió"
 
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' requires 0 or 1 argument"
 msgstr "%s requereix 0 o 1 arguments"
 
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' requires 0 arguments"
 msgstr "«%s» requereix 0 arguments"
 
+#: builtin/bisect.c
 msgid "no logfile given"
 msgstr "no s'ha donat cap fitxer de registre"
 
+#: builtin/bisect.c
 #, c-format
 msgid "'%s' failed: no command provided."
 msgstr "«%s» ha fallat: no s'ha proporcionat cap ordre."
 
+#: builtin/bisect.c
 msgid "need a command"
 msgstr "cal una subordre"
 
+#: builtin/bisect.c builtin/cat-file.c
 #, c-format
 msgid "unknown command: '%s'"
 msgstr "ordre desconeguda: «%s»"
 
+#: builtin/blame.c
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
-msgstr "git blame [<opcions>] [<opcions-de-revisió>] [<revisió>] [--] fitxer"
+msgstr "git blame [<opcions>] [<opcions-revisió>] [<revisió>] [--] fitxer"
 
+#: builtin/blame.c
 msgid "git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>"
-msgstr "git annotate [<opcions>] [<rev-opts>] [<rev>] [--] <fitxer>"
+msgstr "git annotate [<opcions>] [<opcions-revisió>] [<rev>] [--] <fitxer>"
 
+#: builtin/blame.c
 msgid "<rev-opts> are documented in git-rev-list(1)"
-msgstr "es documenten les <opcions-de-revisió> en git-rev-list(1)"
+msgstr "es documenten les <opcions-revisió> en git-rev-list(1)"
 
+#: builtin/blame.c
 #, c-format
 msgid "expecting a color: %s"
 msgstr "s'esperava un color: %s"
 
+#: builtin/blame.c
 msgid "must end with a color"
 msgstr "ha d'acabar amb un color"
 
+#: builtin/blame.c
 #, c-format
 msgid "cannot find revision %s to ignore"
 msgstr "no s'ha pogut trobar la revisió %s a ignorar"
 
+#: builtin/blame.c
 msgid "show blame entries as we find them, incrementally"
 msgstr "mostra les entrades «blame» mentre les trobem, incrementalment"
 
+#: builtin/blame.c
 msgid "do not show object names of boundary commits (Default: off)"
 msgstr ""
 "no mostris els noms d'objectes de les comissions de frontera (per defecte: "
 "desactivat)"
 
+#: builtin/blame.c
 msgid "do not treat root commits as boundaries (Default: off)"
 msgstr ""
 "no tractis les comissions arrel com de frontera (per defecte: desactivat)"
 
+#: builtin/blame.c
 msgid "show work cost statistics"
 msgstr "mostra les estadístiques del cost de treball"
 
+#: builtin/blame.c builtin/checkout.c builtin/clone.c builtin/commit-graph.c
+#: builtin/fetch.c builtin/merge.c builtin/multi-pack-index.c builtin/pull.c
+#: builtin/push.c builtin/remote.c builtin/send-pack.c
 msgid "force progress reporting"
 msgstr "força l'informe de progrés"
 
+#: builtin/blame.c
 msgid "show output score for blame entries"
 msgstr "mostra la puntuació de sortida de les entrades «blame»"
 
+#: builtin/blame.c
 msgid "show original filename (Default: auto)"
 msgstr "mostra el nom de fitxer original (per defecte: automàtic)"
 
+#: builtin/blame.c
 msgid "show original linenumber (Default: off)"
 msgstr "mostra el número de línia original (per defecte: desactivat)"
 
+#: builtin/blame.c
 msgid "show in a format designed for machine consumption"
 msgstr "presenta en un format dissenyat per a ser consumit per una màquina"
 
+#: builtin/blame.c
 msgid "show porcelain format with per-line commit information"
 msgstr "mostra en format de porcellana amb informació de comissió per línia"
 
+#: builtin/blame.c
 msgid "use the same output mode as git-annotate (Default: off)"
 msgstr ""
 "usa el mateix mode de sortida que git-annotate (per defecte: desactivat)"
 
+#: builtin/blame.c
 msgid "show raw timestamp (Default: off)"
 msgstr "mostra la marca de temps en cru (per defecte: desactivat)"
 
+#: builtin/blame.c
 msgid "show long commit SHA1 (Default: off)"
 msgstr "mostra l'SHA1 de la comissió en format llarg (per defecte: desactivat)"
 
+#: builtin/blame.c
 msgid "suppress author name and timestamp (Default: off)"
 msgstr "omet el nom d'autor i la marca de temps (per defecte: desactivat)"
 
+#: builtin/blame.c
 msgid "show author email instead of name (Default: off)"
 msgstr ""
 "mostra el correu electrònic de l'autor en comptes del nom (per defecte: "
 "desactivat)"
 
+#: builtin/blame.c
 msgid "ignore whitespace differences"
 msgstr "ignora les diferències d'espai en blanc"
 
+#: builtin/blame.c builtin/log.c
 msgid "rev"
 msgstr "rev"
 
+#: builtin/blame.c
 msgid "ignore <rev> when blaming"
-msgstr "ignora <rev> en fer «blame»"
+msgstr "ignora ñ- en fer «blame»"
 
+#: builtin/blame.c
 msgid "ignore revisions from <file>"
 msgstr "ignora les revisions de <fitxer>"
 
+#: builtin/blame.c
 msgid "color redundant metadata from previous line differently"
 msgstr ""
 "acoloreix les metadades redundants de la línia anterior de manera diferent"
 
+#: builtin/blame.c
 msgid "color lines by age"
 msgstr "acoloreix les línies per antiguitat"
 
+#: builtin/blame.c
 msgid "spend extra cycles to find better match"
 msgstr "gasta cicles extres per a trobar una coincidència millor"
 
+#: builtin/blame.c
 msgid "use revisions from <file> instead of calling git-rev-list"
 msgstr "usa les revisions de <fitxer> en lloc d'invocar git-rev-list"
 
+#: builtin/blame.c
 msgid "use <file>'s contents as the final image"
 msgstr "usa els continguts de <fitxer> com a la imatge final"
 
+#: builtin/blame.c
 msgid "score"
 msgstr "puntuació"
 
+#: builtin/blame.c
 msgid "find line copies within and across files"
 msgstr "troba còpies de línia dins i a través dels fitxers"
 
+#: builtin/blame.c
 msgid "find line movements within and across files"
 msgstr "troba moviments de línia dins i a través dels fitxers"
 
+#: builtin/blame.c
 msgid "range"
 msgstr "rang"
 
+#: builtin/blame.c
 msgid "process only line range <start>,<end> or function :<funcname>"
-msgstr "processa només el rang <start>,<end> o la funció :<funcname>"
+msgstr "processa només el rang <inici>,<final> o la funció :<nom-funció>"
 
+#: builtin/blame.c
 msgid "--progress can't be used with --incremental or porcelain formats"
 msgstr ""
 "no es pot usar --progress amb els formats --incremental o de porcellana"
@@ -2799,21 +3486,26 @@
 #. your language may need more or fewer display
 #. columns.
 #.
+#: builtin/blame.c
 msgid "4 years, 11 months ago"
 msgstr "fa 4 anys i 11 mesos"
 
+#: builtin/blame.c
 #, c-format
 msgid "file %s has only %lu line"
 msgid_plural "file %s has only %lu lines"
 msgstr[0] "el fitxer %s té només %lu línia"
 msgstr[1] "el fitxer %s té només %lu línies"
 
+#: builtin/blame.c
 msgid "Blaming lines"
 msgstr "S'està fent un «blame»"
 
+#: builtin/branch.c
 msgid "git branch [<options>] [-r | -a] [--merged] [--no-merged]"
 msgstr "git branch [<opcions>] [-r | -a] [--merged | --no-merged]"
 
+#: builtin/branch.c
 msgid ""
 "git branch [<options>] [-f] [--recurse-submodules] <branch-name> [<start-"
 "point>]"
@@ -2821,24 +3513,31 @@
 "git branch [<opcions>] [-f] [--recurse-submodules] <branch-name> [<start-"
 "point>]"
 
+#: builtin/branch.c
 msgid "git branch [<options>] [-l] [<pattern>...]"
 msgstr "git branch [<opcions>] [-l] [<patró>...]"
 
+#: builtin/branch.c
 msgid "git branch [<options>] [-r] (-d | -D) <branch-name>..."
 msgstr "git branch [<opcions>] [-r] (-d | -D) <nom-de-branca>..."
 
+#: builtin/branch.c
 msgid "git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"
 msgstr "git branch [<opcions>] (-m | -M) [<branca-antiga>] <branca-nova>"
 
+#: builtin/branch.c
 msgid "git branch [<options>] (-c | -C) [<old-branch>] <new-branch>"
 msgstr "git branch [<opcions>] (-c | -C) [<branca-antiga>] <branca-nova>"
 
+#: builtin/branch.c
 msgid "git branch [<options>] [-r | -a] [--points-at]"
 msgstr "git branch [<opcions>] [-r | -a] [--points-at]"
 
+#: builtin/branch.c
 msgid "git branch [<options>] [-r | -a] [--format]"
 msgstr "git branch [<opcions>] [-r | -a] [--format]"
 
+#: builtin/branch.c
 #, c-format
 msgid ""
 "deleting branch '%s' that has been merged to\n"
@@ -2847,6 +3546,7 @@
 "s'està suprimint la branca «%s» que s'ha fusionat a\n"
 "         «%s», però encara no s'ha fusionat a HEAD"
 
+#: builtin/branch.c
 #, c-format
 msgid ""
 "not deleting branch '%s' that is not yet merged to\n"
@@ -2855,33 +3555,41 @@
 "no s'està suprimint la branca «%s» que encara no s'ha fusionat a\n"
 "         «%s», encara que s'hagi fusionat a HEAD"
 
+#: builtin/branch.c
 #, c-format
 msgid "couldn't look up commit object for '%s'"
 msgstr "no s'ha pogut cercar l'objecte de comissió per a «%s»"
 
+#: builtin/branch.c
 #, c-format
 msgid "the branch '%s' is not fully merged"
 msgstr "la branca «%s» no està completament fusionada"
 
+#: builtin/branch.c
 #, c-format
 msgid "If you are sure you want to delete it, run 'git branch -D %s'"
 msgstr "Si esteu segur que voleu suprimir-la, executeu «git branch -D %s»"
 
+#: builtin/branch.c
 msgid "update of config-file failed"
 msgstr "ha fallat l'actualització del fitxer de configuració"
 
+#: builtin/branch.c
 msgid "cannot use -a with -d"
 msgstr "no es pot usar -a amb -d"
 
+#: builtin/branch.c
 #, c-format
 msgid "cannot delete branch '%s' used by worktree at '%s'"
 msgstr ""
 "no es pot suprimir la branca «%s» utilitzada per l'arbre de treball a «%s»"
 
+#: builtin/branch.c
 #, c-format
 msgid "remote-tracking branch '%s' not found"
 msgstr "no s'ha trobat la branca de seguiment remot «%s»"
 
+#: builtin/branch.c
 #, c-format
 msgid ""
 "branch '%s' not found.\n"
@@ -2890,198 +3598,257 @@
 "no s'ha trobat la branca «%s».\n"
 "Us heu oblidat de --remote?"
 
+#: builtin/branch.c
 #, c-format
 msgid "branch '%s' not found"
 msgstr "no s'ha trobat la branca «%s»"
 
+#: builtin/branch.c
 #, c-format
 msgid "Deleted remote-tracking branch %s (was %s).\n"
 msgstr "S'ha suprimit la branca amb seguiment remot %s (era %s).\n"
 
+#: builtin/branch.c
 #, c-format
 msgid "Deleted branch %s (was %s).\n"
 msgstr "S'ha suprimit la branca %s (era %s).\n"
 
+#: builtin/branch.c builtin/tag.c
 msgid "unable to parse format string"
 msgstr "no s'ha pogut analitzar la cadena de format"
 
+#: builtin/branch.c
 msgid "could not resolve HEAD"
 msgstr "no s'ha pogut resoldre HEAD"
 
+#: builtin/branch.c
 #, c-format
 msgid "HEAD (%s) points outside of refs/heads/"
 msgstr "HEAD (%s) apunta fora de refs/heads/"
 
+#: builtin/branch.c
 #, c-format
 msgid "branch %s is being rebased at %s"
 msgstr "a la branca %s se li està fent a «rebase» a %s"
 
+#: builtin/branch.c
 #, c-format
 msgid "branch %s is being bisected at %s"
 msgstr "la branca %s s'està bisecant a %s"
 
+#: builtin/branch.c
 #, c-format
 msgid "HEAD of working tree %s is not updated"
 msgstr "HEAD de l'arbre de treball %s no està actualitzat"
 
+#: builtin/branch.c
 #, c-format
 msgid "invalid branch name: '%s'"
 msgstr "el nom de la branca no és vàlid: «%s»"
 
+#: builtin/branch.c
 #, c-format
 msgid "no commit on branch '%s' yet"
 msgstr "encara no hi ha cap comissió a la branca «%s»"
 
+#: builtin/branch.c
 #, c-format
 msgid "no branch named '%s'"
 msgstr "no hi ha cap branca anomenada «%s»"
 
+#: builtin/branch.c
 msgid "branch rename failed"
 msgstr "ha fallat el canvi de nom de la branca"
 
+#: builtin/branch.c
 msgid "branch copy failed"
 msgstr "ha fallat la còpia de la branca"
 
+#: builtin/branch.c
 #, c-format
 msgid "created a copy of a misnamed branch '%s'"
 msgstr "s'ha creat una còpia d'una branca mal anomenada «%s»"
 
+#: builtin/branch.c
 #, c-format
 msgid "renamed a misnamed branch '%s' away"
 msgstr "s'ha canviat el nom d'una branca «%s» mal anomenada"
 
+#: builtin/branch.c
 #, c-format
 msgid "branch renamed to %s, but HEAD is not updated"
 msgstr "s'ha canviat el nom de la branca a %s, però HEAD no s'ha actualitzat"
 
+#: builtin/branch.c
 msgid "branch is renamed, but update of config-file failed"
 msgstr ""
 "s'ha canviat el nom de la branca, però ha fallat l'actualització del fitxer "
 "de configuració"
 
+#: builtin/branch.c
 msgid "branch is copied, but update of config-file failed"
 msgstr ""
 "s'ha copiat la branca, però ha fallat l'actualització del fitxer de "
 "configuració"
 
+#: builtin/branch.c
 #, c-format
 msgid ""
 "Please edit the description for the branch\n"
 "  %s\n"
-"Lines starting with '%c' will be stripped.\n"
+"Lines starting with '%s' will be stripped.\n"
 msgstr ""
 "Editeu la descripció de la branca\n"
 "  %s\n"
-"S'eliminaran les línies que comencin amb «%c».\n"
+"S'eliminaran les línies que comencin amb «%s».\n"
+"\"\n"
 
+#: builtin/branch.c
 msgid "Generic options"
 msgstr "Opcions genèriques"
 
+#: builtin/branch.c
 msgid "show hash and subject, give twice for upstream branch"
 msgstr "mostra el hash i l'assumpte, useu-lo dues vegades per a la branca font"
 
+#: builtin/branch.c
 msgid "suppress informational messages"
 msgstr "omet els missatges informatius"
 
+#: builtin/branch.c builtin/checkout.c builtin/submodule--helper.c
 msgid "set branch tracking configuration"
 msgstr "estableix la configuració del seguiment de la branca"
 
+#: builtin/branch.c
 msgid "do not use"
 msgstr "no usar"
 
+#: builtin/branch.c
 msgid "upstream"
 msgstr "font"
 
+#: builtin/branch.c
 msgid "change the upstream info"
 msgstr "canvia la informació de font"
 
+#: builtin/branch.c
 msgid "unset the upstream info"
 msgstr "treu la informació de la font"
 
+#: builtin/branch.c
 msgid "use colored output"
 msgstr "usa sortida amb colors"
 
+#: builtin/branch.c
 msgid "act on remote-tracking branches"
 msgstr "actua en branques amb seguiment remot"
 
+#: builtin/branch.c
 msgid "print only branches that contain the commit"
 msgstr "imprimeix només les branques que continguin la comissió"
 
+#: builtin/branch.c
 msgid "print only branches that don't contain the commit"
 msgstr "imprimeix només les branques que no continguin la comissió"
 
+#: builtin/branch.c
 msgid "Specific git-branch actions:"
 msgstr "Accions de git-branch específiques:"
 
+#: builtin/branch.c
 msgid "list both remote-tracking and local branches"
 msgstr "llista les branques amb seguiment remot i les locals"
 
+#: builtin/branch.c
 msgid "delete fully merged branch"
 msgstr "suprimeix la branca si està completament fusionada"
 
+#: builtin/branch.c
 msgid "delete branch (even if not merged)"
 msgstr "suprimeix la branca (encara que no estigui fusionada)"
 
+#: builtin/branch.c
 msgid "move/rename a branch and its reflog"
-msgstr "mou/canvia de nom una branca i el seu registre de referència"
+msgstr "mou/canvia de nom una branca i el seu registre de referències"
 
+#: builtin/branch.c
 msgid "move/rename a branch, even if target exists"
 msgstr "mou/canvia de nom una branca, encara que el destí existeixi"
 
+#: builtin/branch.c builtin/for-each-ref.c builtin/tag.c
 msgid "do not output a newline after empty formatted refs"
 msgstr "no emetis cap línia nova després de refs amb format buit"
 
+#: builtin/branch.c
 msgid "copy a branch and its reflog"
-msgstr "copia una branca i el seu registre de referència"
+msgstr "copia una branca i el seu registre de referències"
 
+#: builtin/branch.c
 msgid "copy a branch, even if target exists"
 msgstr "copia una branca, encara que el destí existeixi"
 
+#: builtin/branch.c
 msgid "list branch names"
 msgstr "llista els noms de branca"
 
+#: builtin/branch.c
 msgid "show current branch name"
 msgstr "mostra el nom de la branca actual"
 
+#: builtin/branch.c builtin/submodule--helper.c
 msgid "create the branch's reflog"
-msgstr "crea el registre de referència de la branca"
+msgstr "crea el registre de referències de la branca"
 
+#: builtin/branch.c
 msgid "edit the description for the branch"
 msgstr "edita la descripció de la branca"
 
+#: builtin/branch.c
 msgid "force creation, move/rename, deletion"
 msgstr "força creació, moviment/canvi de nom, supressió"
 
+#: builtin/branch.c
 msgid "print only branches that are merged"
 msgstr "imprimeix només les branques que s'han fusionat"
 
+#: builtin/branch.c
 msgid "print only branches that are not merged"
 msgstr "imprimeix només les branques que no s'han fusionat"
 
+#: builtin/branch.c
 msgid "list branches in columns"
 msgstr "llista les branques en columnes"
 
+#: builtin/branch.c builtin/for-each-ref.c builtin/notes.c builtin/tag.c
 msgid "object"
 msgstr "objecte"
 
+#: builtin/branch.c
 msgid "print only branches of the object"
 msgstr "imprimeix només les branques de l'objecte"
 
+#: builtin/branch.c builtin/for-each-ref.c builtin/tag.c
 msgid "sorting and filtering are case insensitive"
 msgstr "ordenació i filtratge distingeixen entre majúscules i minúscules"
 
+#: builtin/branch.c builtin/ls-files.c
 msgid "recurse through submodules"
 msgstr "inclou recursivament els submòduls"
 
+#: builtin/branch.c builtin/for-each-ref.c builtin/ls-files.c builtin/ls-tree.c
+#: builtin/tag.c builtin/verify-tag.c
 msgid "format to use for the output"
 msgstr "format a usar en la sortida"
 
+#: builtin/branch.c
 msgid "failed to resolve HEAD as a valid ref"
 msgstr "no s'ha pogut resoldre HEAD com a referència vàlida"
 
+#: builtin/branch.c builtin/clone.c
 msgid "HEAD not found below refs/heads!"
 msgstr "HEAD no trobat sota refs/heads!"
 
+#: builtin/branch.c
 msgid ""
 "branch with --recurse-submodules can only be used if submodule."
 "propagateBranches is enabled"
@@ -3089,58 +3856,74 @@
 "la branca amb --recurse-submodules només es pot utilitzar si submodule."
 "propagateBranches està habilitat"
 
+#: builtin/branch.c
 msgid "--recurse-submodules can only be used to create branches"
 msgstr "--recurse-submodules només es pot utilitzar per a crear branques"
 
+#: builtin/branch.c
 msgid "branch name required"
 msgstr "cal el nom de branca"
 
+#: builtin/branch.c
 msgid "cannot give description to detached HEAD"
 msgstr "no s'ha pogut donar la descripció al HEAD separat"
 
+#: builtin/branch.c
 msgid "cannot edit description of more than one branch"
 msgstr "no es pot editar la descripció de més d'una branca"
 
+#: builtin/branch.c
 msgid "cannot copy the current branch while not on any"
 msgstr "no es pot copiar la branca actual mentre no pertanyi a cap"
 
+#: builtin/branch.c
 msgid "cannot rename the current branch while not on any"
 msgstr ""
 "no s'ha pogut canviar el nom de la branca actual mentre no pertanyi a cap"
 
+#: builtin/branch.c
 msgid "too many branches for a copy operation"
 msgstr "hi ha massa branques per a una operació de còpia"
 
+#: builtin/branch.c
 msgid "too many arguments for a rename operation"
 msgstr "hi ha massa arguments per a una operació de canvi de nom"
 
+#: builtin/branch.c
 msgid "too many arguments to set new upstream"
 msgstr "hi ha massa arguments per a establir una nova font"
 
+#: builtin/branch.c
 #, c-format
 msgid ""
 "could not set upstream of HEAD to %s when it does not point to any branch"
 msgstr ""
 "no s'ha pogut configurar la font de HEAD a %s quan no apunta a cap branca"
 
+#: builtin/branch.c
 #, c-format
 msgid "no such branch '%s'"
 msgstr "no existeix la branca «%s»"
 
+#: builtin/branch.c
 #, c-format
 msgid "branch '%s' does not exist"
 msgstr "la branca «%s» no existeix"
 
+#: builtin/branch.c
 msgid "too many arguments to unset upstream"
 msgstr "hi ha massa arguments per a desassignar la font"
 
+#: builtin/branch.c
 msgid "could not unset upstream of HEAD when it does not point to any branch"
 msgstr "no s'ha pogut desassignar la font del HEAD quan no apunta a cap branca"
 
+#: builtin/branch.c
 #, c-format
 msgid "branch '%s' has no upstream information"
 msgstr "la branca «%s» no té informació de la font"
 
+#: builtin/branch.c
 msgid ""
 "the -a, and -r, options to 'git branch' do not take a branch name.\n"
 "Did you mean to use: -a|-r --list <pattern>?"
@@ -3148,6 +3931,7 @@
 "les opcions -a, i -r, a «git branch» no prenen un nom de branca.\n"
 "Volíeu utilitzar: -a|-r --list <patró>?"
 
+#: builtin/branch.c
 msgid ""
 "the '--set-upstream' option is no longer supported. Please use '--track' or "
 "'--set-upstream-to' instead"
@@ -3155,30 +3939,39 @@
 "l'opció «--set-upstream» ja no és admesa. Utilitzeu en comptes «--track» o "
 "«--set-upstream-to»"
 
+#: builtin/bugreport.c
 msgid "git version:\n"
 msgstr "versió de git:\n"
 
+#: builtin/bugreport.c
 #, c-format
 msgid "uname() failed with error '%s' (%d)\n"
 msgstr "uname() ha fallat amb l'error «%s» (%d)\n"
 
+#: builtin/bugreport.c
 msgid "compiler info: "
 msgstr "informació del compilador: "
 
+#: builtin/bugreport.c
 msgid "libc info: "
 msgstr "informació de la libc: "
 
+#: builtin/bugreport.c
 msgid "not run from a git repository - no hooks to show\n"
 msgstr ""
 "no s'està executant en un repositori de git - no hi ha lligams a mostrar\n"
 
+#: builtin/bugreport.c
 msgid ""
-"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+"              [(-s | --suffix) <format> | --no-suffix]\n"
 "              [--diagnose[=<mode>]]"
 msgstr ""
-"git bugreport [(-o | --output-directory) <camí>] [(-s | --suffix) <format>]\n"
+"git bugreport [(-o | --output-directory) <path>]\n"
+"              [(-s | --suffix) <format> | --no-suffix]\n"
 "              [--diagnose[=<mode>]]"
 
+#: builtin/bugreport.c
 msgid ""
 "Thank you for filling out a Git bug report!\n"
 "Please answer the following questions to help us understand your issue.\n"
@@ -3212,46 +4005,59 @@
 "Reviseu la resta de l'informe d'error de sota.\n"
 "Podeu eliminar qualsevol línia que vulgueu.\n"
 
+#: builtin/bugreport.c builtin/commit.c builtin/fast-export.c builtin/rebase.c
+#: parse-options.h
 msgid "mode"
 msgstr "mode"
 
+#: builtin/bugreport.c
 msgid ""
 "create an additional zip archive of detailed diagnostics (default 'stats')"
 msgstr ""
 "crea un arxiu zip addicional amb diagnòstics detallats (per defecte «stats»)"
 
+#: builtin/bugreport.c
 msgid "specify a destination for the bugreport file(s)"
 msgstr "especifiqueu una destinació per al fitxer de l'informe d'error"
 
+#: builtin/bugreport.c
 msgid "specify a strftime format suffix for the filename(s)"
 msgstr "especifiqueu un sufix en format strftime per al nom de fitxer"
 
+#: builtin/bugreport.c
 #, c-format
 msgid "unknown argument `%s'"
 msgstr "argument desconegut «%s»"
 
+#: builtin/bugreport.c builtin/diagnose.c
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr "no s'han pogut crear els directoris principals de «%s»"
 
+#: builtin/bugreport.c builtin/diagnose.c
 #, c-format
 msgid "unable to create diagnostics archive %s"
 msgstr "no s'ha pogut crear l'arxiu de diagnòstic %s"
 
+#: builtin/bugreport.c
 msgid "System Info"
 msgstr "Informació del sistema"
 
+#: builtin/bugreport.c
 msgid "Enabled Hooks"
 msgstr "Habilita els lligams"
 
+#: builtin/bugreport.c
 #, c-format
 msgid "unable to write to %s"
 msgstr "no s'ha pogut escriure a %s"
 
+#: builtin/bugreport.c
 #, c-format
 msgid "Created new report at '%s'.\n"
 msgstr "S'ha creat un nou informe a «%s».\n"
 
+#: builtin/bundle.c
 msgid ""
 "git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
@@ -3259,83 +4065,112 @@
 "git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<versió>] <fitxer> <git-rev-list-args>"
 
+#: builtin/bundle.c
 msgid "git bundle verify [-q | --quiet] <file>"
 msgstr "git bundle verify [-q | --quiet] <fitxer>"
 
+#: builtin/bundle.c
 msgid "git bundle list-heads <file> [<refname>...]"
-msgstr "git bundle list-heads <fitxer> [<refname>...]"
+msgstr "git bundle list-heads <fitxer> [<nom-referència>...]"
 
+#: builtin/bundle.c
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
-msgstr "git bundle unbundle [--progress] <fitxer> [<refname>...]"
+msgstr "git bundle unbundle [--progress] <fitxer> [<nom-referència>...]"
 
+#: builtin/bundle.c
 msgid "need a <file> argument"
 msgstr "necessita un argument <fitxer>"
 
+#: builtin/bundle.c builtin/pack-objects.c
 msgid "do not show progress meter"
 msgstr "no mostris l'indicador de progrés"
 
+#: builtin/bundle.c builtin/pack-objects.c
 msgid "show progress meter"
 msgstr "mostra l'indicador de progrés"
 
+#: builtin/bundle.c
 msgid "historical; same as --progress"
 msgstr "històric; el mateix que --progress"
 
+#: builtin/bundle.c
 msgid "historical; does nothing"
 msgstr "històric; no fa res"
 
+#: builtin/bundle.c
 msgid "specify bundle format version"
 msgstr "especifica la versió del format del farcell"
 
+#: builtin/bundle.c
 msgid "Need a repository to create a bundle."
 msgstr "Cal un repositori per a crear un farcell."
 
+#: builtin/bundle.c
 msgid "do not show bundle details"
 msgstr "no mostris els detalls del farcell"
 
+#: builtin/bundle.c bundle.c
+msgid "need a repository to verify a bundle"
+msgstr "cal un repositori per a verificar un farcell"
+
+#: builtin/bundle.c
 #, c-format
 msgid "%s is okay\n"
 msgstr "%s està bé\n"
 
+#: builtin/bundle.c
 msgid "Need a repository to unbundle."
 msgstr "Cal un repositori per a desfer un farcell."
 
+#: builtin/bundle.c
 msgid "Unbundling objects"
 msgstr "S'estan desagrupant objectes"
 
+#: builtin/cat-file.c merge-recursive.c
 #, c-format
 msgid "cannot read object %s '%s'"
 msgstr "no es pot llegir l'objecte %s «%s»"
 
+#: builtin/cat-file.c
 msgid "flush is only for --buffer mode"
 msgstr "flush només és per al mode --buffer"
 
+#: builtin/cat-file.c
 msgid "empty command in input"
 msgstr "ordre buida en l'entrada"
 
+#: builtin/cat-file.c
 #, c-format
 msgid "whitespace before command: '%s'"
 msgstr "espai en blanc abans de l'ordre: «%s»"
 
+#: builtin/cat-file.c
 #, c-format
 msgid "%s requires arguments"
 msgstr "%s requereix arguments"
 
+#: builtin/cat-file.c
 #, c-format
 msgid "%s takes no arguments"
-msgstr "%s no accepta cap valor"
+msgstr "%s no accepta arguments"
 
+#: builtin/cat-file.c
 msgid "only one batch option may be specified"
 msgstr "només es pot especificar una opció per lots"
 
+#: builtin/cat-file.c
 msgid "git cat-file <type> <object>"
 msgstr "git cat-file <tipus> <objecte>"
 
+#: builtin/cat-file.c
 msgid "git cat-file (-e | -p) <object>"
 msgstr "git cat-file (-e | -p) <objecte>"
 
+#: builtin/cat-file.c
 msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
 msgstr "git cat-file (-t | -s) [--allow-unknown-type] <objecte>"
 
+#: builtin/cat-file.c
 msgid ""
 "git cat-file (--textconv | --filters)\n"
 "             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
@@ -3343,6 +4178,7 @@
 "git cat-file (--textconv | --filters)\n"
 "             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
 
+#: builtin/cat-file.c
 msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
@@ -3354,114 +4190,147 @@
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
 "             [--textconv | --filters] [-Z]"
 
+#: builtin/cat-file.c
 msgid "Check object existence or emit object contents"
 msgstr "Comprova l'existència de l'objecte o emet el contingut de l'objecte"
 
+#: builtin/cat-file.c
 msgid "check if <object> exists"
 msgstr "comprova si <objecte> existeix"
 
+#: builtin/cat-file.c
 msgid "pretty-print <object> content"
 msgstr "impressió embellida del contingut de l'<objecte>"
 
+#: builtin/cat-file.c
 msgid "Emit [broken] object attributes"
 msgstr "Emet els atributs [broken] de l'objecte"
 
+#: builtin/cat-file.c
 msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"
 msgstr ""
 "mostra el tipus d'objecte (un dels següents: «blob», «tree», «commit», "
 "«tag», ...)"
 
+#: builtin/cat-file.c
 msgid "show object size"
 msgstr "mostra la mida de l'objecte"
 
+#: builtin/cat-file.c
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "permet que -s i -t funcionin amb objectes trencats/malmesos"
 
+#: builtin/cat-file.c builtin/log.c
 msgid "use mail map file"
 msgstr "usa el fitxer de mapa de correu"
 
+#: builtin/cat-file.c
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
 msgstr "Objectes de lots sol·licitats a stdin (o --batch-all-objects)"
 
+#: builtin/cat-file.c
 msgid "show full <object> or <rev> contents"
 msgstr "mostra el contingut complet de <objecte> o <rev>"
 
+#: builtin/cat-file.c
 msgid "like --batch, but don't emit <contents>"
 msgstr "com a --batch, però no emetis <contents>"
 
+#: builtin/cat-file.c
 msgid "stdin is NUL-terminated"
 msgstr "l'entrada és acabada amb NUL"
 
+#: builtin/cat-file.c
 msgid "stdin and stdout is NUL-terminated"
 msgstr "stdin i stdout estan terminats amb NUL"
 
+#: builtin/cat-file.c
 msgid "read commands from stdin"
 msgstr "llegeix les ordres de stdin"
 
+#: builtin/cat-file.c
 msgid "with --batch[-check]: ignores stdin, batches all known objects"
 msgstr ""
 "amb --batch[-check]: ignora stdin, posa en lots tots els objectes coneguts"
 
+#: builtin/cat-file.c
 msgid "Change or optimize batch output"
 msgstr "Canvia o optimitza la sortida per lots"
 
+#: builtin/cat-file.c
 msgid "buffer --batch output"
 msgstr "posa la sortida de --batch en memòria intermèdia"
 
+#: builtin/cat-file.c
 msgid "follow in-tree symlinks"
 msgstr "segueix els enllaços simbòlics en l'arbre"
 
+#: builtin/cat-file.c
 msgid "do not order objects before emitting them"
 msgstr "no ordenis els objectes abans d'emetre'ls"
 
+#: builtin/cat-file.c
 msgid ""
 "Emit object (blob or tree) with conversion or filter (stand-alone, or with "
 "batch)"
 msgstr ""
 "Emet l'objecte (blob o arbre) amb conversió o filtre (stand-alone, o amb lot)"
 
+#: builtin/cat-file.c
 msgid "run textconv on object's content"
 msgstr "executar textconv al contingut de l'objecte"
 
+#: builtin/cat-file.c
 msgid "run filters on object's content"
 msgstr "executa els filtres al contingut de l'objecte"
 
+#: builtin/cat-file.c
 msgid "blob|tree"
 msgstr "blob|tree"
 
+#: builtin/cat-file.c
 msgid "use a <path> for (--textconv | --filters); Not with 'batch'"
 msgstr "useu un <camí> per a (--textconv | --filters); no amb «batch»"
 
+#: builtin/cat-file.c
 #, c-format
 msgid "'%s=<%s>' needs '%s' or '%s'"
 msgstr "«%s=<%s>» necessita «%s» o «%s»"
 
+#: builtin/cat-file.c
 msgid "path|tree-ish"
 msgstr "path|tree-ish"
 
+#: builtin/cat-file.c
 #, c-format
 msgid "'%s' requires a batch mode"
 msgstr "«%s» requereix un mode batch"
 
+#: builtin/cat-file.c
 #, c-format
 msgid "'-%c' is incompatible with batch mode"
 msgstr "«-%c» és incompatible amb el model batch"
 
+#: builtin/cat-file.c
 msgid "batch modes take no arguments"
 msgstr "el mode batch no accepta cap argument"
 
+#: builtin/cat-file.c
 #, c-format
 msgid "<rev> required with '%s'"
 msgstr "<rev> requerida amb «%s»"
 
+#: builtin/cat-file.c
 #, c-format
 msgid "<object> required with '-%c'"
 msgstr "<objecte> requerit amb «-%c»"
 
+#: builtin/cat-file.c
 #, c-format
 msgid "only two arguments allowed in <type> <object> mode, not %d"
 msgstr "només es permeten dos arguments en el mode <tipus> <objecte>, no %d"
 
+#: builtin/check-attr.c
 msgid ""
 "git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
 "<pathname>..."
@@ -3469,198 +4338,269 @@
 "git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
 "<pathname>..."
 
+#: builtin/check-attr.c
 msgid ""
 "git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
 msgstr ""
 "git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
 
+#: builtin/check-attr.c
 msgid "report all attributes set on file"
 msgstr "informa de tots els atributs establerts en el fitxer"
 
+#: builtin/check-attr.c
 msgid "use .gitattributes only from the index"
 msgstr "usa .gitattributes només des de l'índex"
 
+#: builtin/check-attr.c builtin/check-ignore.c builtin/hash-object.c
 msgid "read file names from stdin"
 msgstr "llegeix els noms de fitxer de stdin"
 
+#: builtin/check-attr.c builtin/check-ignore.c
 msgid "terminate input and output records by a NUL character"
 msgstr "acaba els registres d'entrada i de sortida amb un caràcter NUL"
 
+#: builtin/check-attr.c
 msgid "<tree-ish>"
 msgstr "<tree-ish>"
 
+#: builtin/check-attr.c
 msgid "which tree-ish to check attributes at"
 msgstr "a quin tree-ish s'han de comprovar els atributs"
 
+#: builtin/check-ignore.c builtin/checkout.c builtin/gc.c builtin/worktree.c
 msgid "suppress progress reporting"
 msgstr "omet els informes de progrés"
 
+#: builtin/check-ignore.c
 msgid "show non-matching input paths"
 msgstr "mostra els camins d'entrada que no coincideixin"
 
+#: builtin/check-ignore.c
 msgid "ignore index when checking"
 msgstr "ignora l'índex en comprovar"
 
+#: builtin/check-ignore.c
 msgid "cannot specify pathnames with --stdin"
 msgstr "no es poden especificar noms de camí amb --stdin"
 
+#: builtin/check-ignore.c
 msgid "-z only makes sense with --stdin"
 msgstr "-z només té sentit amb --stdin"
 
+#: builtin/check-ignore.c
 msgid "no path specified"
 msgstr "cap camí especificat"
 
+#: builtin/check-ignore.c
 msgid "--quiet is only valid with a single pathname"
 msgstr "--quiet només és vàlid amb un sol nom de camí"
 
+#: builtin/check-ignore.c
 msgid "cannot have both --quiet and --verbose"
 msgstr "no es poden especificar --quiet i --verbose alhora"
 
+#: builtin/check-ignore.c
 msgid "--non-matching is only valid with --verbose"
 msgstr "--non-matching és vàlid només amb --verbose"
 
+#: builtin/check-mailmap.c
 msgid "git check-mailmap [<options>] <contact>..."
 msgstr "git check-mailmap [<opcions>] <contacte>..."
 
+#: builtin/check-mailmap.c
 msgid "also read contacts from stdin"
 msgstr "també llegeix els contactes des de stdin"
 
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "no s'ha pogut analitzar el contacte: %s"
+# no traduïsc mailmap
+#: builtin/check-mailmap.c
+msgid "read additional mailmap entries from file"
+msgstr "llegeix les entrades mailmap addicionals del fitxer"
 
+#: builtin/check-mailmap.c
+msgid "blob"
+msgstr "blob"
+
+#: builtin/check-mailmap.c
+msgid "read additional mailmap entries from blob"
+msgstr "llegeix entrades mailmap addicionals del blob"
+
+#: builtin/check-mailmap.c
 msgid "no contacts specified"
 msgstr "no hi ha contactes especificats"
 
+#: builtin/checkout--worker.c
 msgid "git checkout--worker [<options>]"
 msgstr "git checkout--worker [<opcions>]"
 
+#: builtin/checkout--worker.c builtin/checkout-index.c builtin/column.c
+#: builtin/submodule--helper.c builtin/worktree.c
 msgid "string"
 msgstr "cadena"
 
+#: builtin/checkout--worker.c builtin/checkout-index.c
 msgid "when creating files, prepend <string>"
 msgstr "en crear fitxers, anteposa <cadena>"
 
+#: builtin/checkout-index.c
 msgid "git checkout-index [<options>] [--] [<file>...]"
 msgstr "git checkout-index [<opcions>] [--] [<fitxer>...]"
 
+#: builtin/checkout-index.c
 msgid "stage should be between 1 and 3 or all"
 msgstr "«stage» ha de ser entre 1 i 3 o all"
 
+#: builtin/checkout-index.c
 msgid "check out all files in the index"
 msgstr "agafa tots els fitxers en l'índex"
 
+#: builtin/checkout-index.c
 msgid "do not skip files with skip-worktree set"
 msgstr "no ometis els fitxers amb skip-worktree establert"
 
+#: builtin/checkout-index.c
 msgid "force overwrite of existing files"
 msgstr "força la sobreescriptura de fitxers existents"
 
+#: builtin/checkout-index.c
 msgid "no warning for existing files and files not in index"
 msgstr ""
 "cap advertència per a fitxers existents i fitxers que no siguin a l'índex"
 
+#: builtin/checkout-index.c
 msgid "don't checkout new files"
 msgstr "no agafis fitxers nous"
 
+#: builtin/checkout-index.c
 msgid "update stat information in the index file"
 msgstr "actualitza la informació d'estadístiques en el fitxer d'índex"
 
+#: builtin/checkout-index.c
 msgid "read list of paths from the standard input"
 msgstr "llegeix la llista de camins des de l'entrada estàndard"
 
+#: builtin/checkout-index.c
 msgid "write the content to temporary files"
 msgstr "escriu el contingut a fitxers temporals"
 
+#: builtin/checkout-index.c
 msgid "copy out the files from named stage"
 msgstr "copia els fitxers des de «stage» amb nom"
 
+#: builtin/checkout.c
 msgid "git checkout [<options>] <branch>"
 msgstr "git checkout [<opcions>] <branca>"
 
+#: builtin/checkout.c
 msgid "git checkout [<options>] [<branch>] -- <file>..."
 msgstr "git checkout [<opcions>] [<branca>] -- <fitxer>..."
 
+#: builtin/checkout.c
 msgid "git switch [<options>] [<branch>]"
 msgstr "git switch [<opcions>] [<branca>]"
 
+#: builtin/checkout.c
 msgid "git restore [<options>] [--source=<branch>] <file>..."
 msgstr "git restore [<opcions>] [--source=<branca>] <fitxer>..."
 
+#: builtin/checkout.c
 #, c-format
 msgid "path '%s' does not have our version"
 msgstr "el camí «%s» no té la nostra versió"
 
+#: builtin/checkout.c
 #, c-format
 msgid "path '%s' does not have their version"
 msgstr "el camí «%s» no té la seva versió"
 
+#: builtin/checkout.c
 #, c-format
 msgid "path '%s' does not have all necessary versions"
 msgstr "el camí «%s» no té totes les versions necessàries"
 
+#: builtin/checkout.c
 #, c-format
 msgid "path '%s' does not have necessary versions"
 msgstr "el camí «%s» no té les versions necessàries"
 
+#: builtin/checkout.c
 #, c-format
 msgid "path '%s': cannot merge"
 msgstr "camí «%s»: no es pot fusionar"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Unable to add merge result for '%s'"
 msgstr "No s'ha pogut afegir el resultat de fusió per a «%s»"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Recreated %d merge conflict"
 msgid_plural "Recreated %d merge conflicts"
 msgstr[0] "Recreat un conflicte de fusió"
 msgstr[1] "Recreats %d conflictes de fusió"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Updated %d path from %s"
 msgid_plural "Updated %d paths from %s"
-msgstr[0] "S'ha actualitzat %d camí des de %s"
-msgstr[1] "S'han actualitzat %d camins des de %s"
+msgstr[0] "S'ha actualitzat %d camí a partir de %s"
+msgstr[1] "S'han actualitzat %d camins a partir de %s"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Updated %d path from the index"
 msgid_plural "Updated %d paths from the index"
-msgstr[0] "S'ha actualitzat un camí des de l'índex"
-msgstr[1] "S'ha actualitzat %d camins des de l'índex"
+msgstr[0] "S'ha actualitzat %d camí a partir de l'índex"
+msgstr[1] "S'han actualitzat %d camins a partir de l'índex"
 
+#: builtin/checkout.c
 #, c-format
 msgid "'%s' cannot be used with updating paths"
 msgstr "«%s» no es pot usar amb actualització de camins"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Cannot update paths and switch to branch '%s' at the same time."
 msgstr ""
 "No es poden actualitzar els camins i canviar a la branca «%s» a la vegada."
 
+#: builtin/checkout.c
 #, c-format
 msgid "neither '%s' or '%s' is specified"
 msgstr "no s'ha especificat ni «%s» ni «%s»"
 
+#: builtin/checkout.c
 #, c-format
 msgid "'%s' must be used when '%s' is not specified"
 msgstr "«%s» s'ha d'utilitzar quan no s'especifica «%s»"
 
+#: builtin/checkout.c
 #, c-format
 msgid "'%s' or '%s' cannot be used with %s"
 msgstr "«%s» o «%s» no poden utilitzar-se amb %s"
 
+#: builtin/checkout.c
 #, c-format
 msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree"
 msgstr "«%s», «%s» o «%s» no es poden utilitzar en agafar un arbre"
 
+#: builtin/checkout.c
 #, c-format
 msgid "path '%s' is unmerged"
 msgstr "el camí «%s» està sense fusionar"
 
+#: builtin/checkout.c builtin/grep.c builtin/merge-tree.c builtin/reset.c
+#: merge-ort.c reset.c sequencer.c tree-walk.c
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "no s'ha pogut llegir l'arbre (%s)"
+
+#: builtin/checkout.c
 msgid "you need to resolve your current index first"
 msgstr "heu de primer resoldre el vostre índex actual"
 
+#: builtin/checkout.c
 #, c-format
 msgid ""
 "cannot continue with staged changes in the following files:\n"
@@ -3669,40 +4609,50 @@
 "no es pot continuar amb els canvis «staged» als fitxers següents:\n"
 "%s"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Can not do reflog for '%s': %s\n"
-msgstr "No es pot fer reflog per a «%s»: %s\n"
+msgstr "No es pot fer «reflog» per a «%s»: %s\n"
 
+#: builtin/checkout.c
 msgid "HEAD is now at"
 msgstr "HEAD ara és a"
 
+#: builtin/checkout.c builtin/clone.c
 msgid "unable to update HEAD"
 msgstr "no s'ha pogut actualitzar HEAD"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Reset branch '%s'\n"
 msgstr "Restableix la branca «%s»\n"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Already on '%s'\n"
 msgstr "Ja esteu en «%s»\n"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Switched to and reset branch '%s'\n"
 msgstr "S'ha canviat i restablert a la branca «%s»\n"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Switched to a new branch '%s'\n"
 msgstr "S'ha canviat a la branca nova «%s»\n"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Switched to branch '%s'\n"
 msgstr "S'ha canviat a la branca «%s»\n"
 
+#: builtin/checkout.c
 #, c-format
 msgid " ... and %d more.\n"
 msgstr " ... i %d més.\n"
 
+#: builtin/checkout.c
 #, c-format
 msgid ""
 "Warning: you are leaving %d commit behind, not connected to\n"
@@ -3725,6 +4675,7 @@
 "\n"
 "%s\n"
 
+#: builtin/checkout.c
 #, c-format
 msgid ""
 "If you want to keep it by creating a new branch, this may be a good time\n"
@@ -3751,15 +4702,19 @@
 " git branch <nom-de-branca-nova> %s\n"
 "\n"
 
+#: builtin/checkout.c
 msgid "internal error in revision walk"
 msgstr "error intern en el passeig per revisions"
 
+#: builtin/checkout.c
 msgid "Previous HEAD position was"
 msgstr "La posició de HEAD anterior era"
 
+#: builtin/checkout.c
 msgid "You are on a branch yet to be born"
 msgstr "Sou en una branca que encara ha de néixer"
 
+#: builtin/checkout.c
 #, c-format
 msgid ""
 "'%s' could be both a local file and a tracking branch.\n"
@@ -3768,6 +4723,7 @@
 "«%s» podria ser tant un fitxer local com una branca de seguiment.\n"
 "Useu -- (i opcionalment --no-guess) per a desambiguar-ho"
 
+#: builtin/checkout.c
 msgid ""
 "If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
 "you can do so by fully qualifying the name with the --track option:\n"
@@ -3787,47 +4743,58 @@
 "remota, p. ex. «origin» al remot, considereu configurar l'opció\n"
 "checkout.defaultRemote=origin en la vostra configuració."
 
+#: builtin/checkout.c
 #, c-format
 msgid "'%s' matched multiple (%d) remote tracking branches"
 msgstr "«%s» coincideixen múltiples (%d) branques de seguiment remotes"
 
+#: builtin/checkout.c
 msgid "only one reference expected"
 msgstr "només s'esperava una referència"
 
+#: builtin/checkout.c
 #, c-format
 msgid "only one reference expected, %d given."
 msgstr "s'esperava només una referència, s'han donat %d."
 
+#: builtin/checkout.c builtin/worktree.c
 #, c-format
 msgid "invalid reference: %s"
 msgstr "referència no vàlida: %s"
 
+#: builtin/checkout.c
 #, c-format
 msgid "reference is not a tree: %s"
 msgstr "la referència no és un arbre: %s"
 
+#: builtin/checkout.c
 #, c-format
 msgid "a branch is expected, got tag '%s'"
 msgstr "s'espera una branca, s'ha obtingut l'etiqueta «%s»"
 
+#: builtin/checkout.c
 #, c-format
 msgid "a branch is expected, got remote branch '%s'"
 msgstr "s'espera una branca, s'ha obtingut la branca remota «%s»"
 
+#: builtin/checkout.c
 #, c-format
 msgid "a branch is expected, got '%s'"
 msgstr "s'espera una branca, s'ha obtingut «%s»"
 
+#: builtin/checkout.c
 #, c-format
 msgid "a branch is expected, got commit '%s'"
 msgstr "s'espera una branca, s'ha obtingut la comissió «%s»"
 
+#: builtin/checkout.c
 msgid ""
 "If you want to detach HEAD at the commit, try again with the --detach option."
 msgstr ""
 "Si voleu desacoblar HEAD a la comissió, torneu-ho a provar amb l'opció --"
 "detach."
 
+#: builtin/checkout.c
 msgid ""
 "cannot switch branch while merging\n"
 "Consider \"git merge --quit\" or \"git worktree add\"."
@@ -3835,6 +4802,7 @@
 "no es pot canviar de branca mentre es fusiona\n"
 "Considereu usar «git merge --quit» o «git worktree add»."
 
+#: builtin/checkout.c
 msgid ""
 "cannot switch branch in the middle of an am session\n"
 "Consider \"git am --quit\" or \"git worktree add\"."
@@ -3842,6 +4810,7 @@
 "no es pot canviar de branca en mig d'una sessió «am»\n"
 "Considereu usar «git am --quit» o «git worktree add»."
 
+#: builtin/checkout.c
 msgid ""
 "cannot switch branch while rebasing\n"
 "Consider \"git rebase --quit\" or \"git worktree add\"."
@@ -3849,6 +4818,7 @@
 "no es pot canviar de branca mentre es fa «rebase»\n"
 "Considereu usar «git rebase --quit» o «git worktree add»."
 
+#: builtin/checkout.c
 msgid ""
 "cannot switch branch while cherry-picking\n"
 "Consider \"git cherry-pick --quit\" or \"git worktree add\"."
@@ -3856,6 +4826,7 @@
 "no es pot canviar de branca mentre es fa «cherry-pick»\n"
 "Considereu usar «git cherry-pick --quit» o «git worktree add»."
 
+#: builtin/checkout.c
 msgid ""
 "cannot switch branch while reverting\n"
 "Consider \"git revert --quit\" or \"git worktree add\"."
@@ -3863,95 +4834,133 @@
 "no es pot canviar de branca mentre s'està revertint\n"
 "Considereu «git revert --quit» o «git worktree add»."
 
+#: builtin/checkout.c
 msgid "you are switching branch while bisecting"
 msgstr "s'està canviant la branca mentre es fa una bisecció"
 
+#: builtin/checkout.c
 msgid "paths cannot be used with switching branches"
 msgstr "els camins no es poden usar amb canvi de branca"
 
+#: builtin/checkout.c
 #, c-format
 msgid "'%s' cannot be used with switching branches"
 msgstr "«%s» no es pot usar amb canvi de branca"
 
+# és com si faltara un objecte directe per a agafar
+#: builtin/checkout.c
+#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "«%s» necessita els camins per a agafar"
+
+#: builtin/checkout.c
 #, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr "«%s» no es pot usar amb «%s»"
 
+#: builtin/checkout.c
 #, c-format
 msgid "'%s' cannot take <start-point>"
 msgstr "«%s» no pot prendre <start-point>"
 
+#: builtin/checkout.c
 #, c-format
 msgid "Cannot switch branch to a non-commit '%s'"
 msgstr "No es pot canviar la branca a la no comissió «%s»"
 
+#: builtin/checkout.c
 msgid "missing branch or commit argument"
 msgstr "manca branca o argument de comissió"
 
+#: builtin/checkout.c
+#, c-format
+msgid "unknown conflict style '%s'"
+msgstr "estil de conflicte desconegut «%s»"
+
+#: builtin/checkout.c
 msgid "perform a 3-way merge with the new branch"
 msgstr "realitza una fusió de 3 vies amb la branca nova"
 
+#: builtin/checkout.c builtin/log.c parse-options.h
 msgid "style"
 msgstr "estil"
 
+#: builtin/checkout.c
 msgid "conflict style (merge, diff3, or zdiff3)"
 msgstr "estil de conflicte (merge, diff3, o zdiff3)"
 
+#: builtin/checkout.c builtin/worktree.c
 msgid "detach HEAD at named commit"
 msgstr "separa HEAD a la comissió anomenada"
 
+#: builtin/checkout.c
 msgid "force checkout (throw away local modifications)"
 msgstr "agafa a la força (descarta qualsevol modificació local)"
 
+#: builtin/checkout.c
 msgid "new-branch"
 msgstr "branca-nova"
 
+#: builtin/checkout.c
 msgid "new unborn branch"
 msgstr "branca no nascuda nova"
 
+#: builtin/checkout.c builtin/merge.c
 msgid "update ignored files (default)"
 msgstr "actualitza els fitxers ignorats (per defecte)"
 
+#: builtin/checkout.c
 msgid "do not check if another worktree is holding the given ref"
 msgstr "no comprovis si un altre arbre de treball té la referència donada"
 
+#: builtin/checkout.c
 msgid "checkout our version for unmerged files"
 msgstr "agafa la versió nostra dels fitxers sense fusionar"
 
+#: builtin/checkout.c
 msgid "checkout their version for unmerged files"
 msgstr "agafa la versió seva dels fitxers sense fusionar"
 
+#: builtin/checkout.c
 msgid "do not limit pathspecs to sparse entries only"
 msgstr "no limitis les especificacions de camí només a entrades disperses"
 
+#: builtin/checkout.c
 #, c-format
 msgid "options '-%c', '-%c', and '%s' cannot be used together"
 msgstr "les opcions «-%c», «-%c», i «%s» no es poden usar juntes"
 
+#: builtin/checkout.c
 msgid "--track needs a branch name"
 msgstr "--track necessita un nom de branca"
 
+#: builtin/checkout.c
 #, c-format
 msgid "missing branch name; try -%c"
 msgstr "falta el nom de la branca; proveu -%c"
 
+#: builtin/checkout.c
 #, c-format
 msgid "could not resolve %s"
 msgstr "no es pot resoldre %s"
 
+#: builtin/checkout.c
 msgid "invalid path specification"
 msgstr "especificació de camí no vàlida"
 
+#: builtin/checkout.c
 #, c-format
 msgid "'%s' is not a commit and a branch '%s' cannot be created from it"
 msgstr ""
 "«%s» no és una comissió i la branca «%s» no es pot crear a partir d'aquesta "
 "comissió"
 
+#: builtin/checkout.c
 #, c-format
 msgid "git checkout: --detach does not take a path argument '%s'"
 msgstr "git checkout: --detach no accepta un argument de camí «%s»"
 
+#: builtin/checkout.c
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 "checking out of the index."
@@ -3959,54 +4968,72 @@
 "git checkout: --ours/--theirs, --force i --merge són incompatibles en\n"
 "agafar de l'índex."
 
+#: builtin/checkout.c
 msgid "you must specify path(s) to restore"
 msgstr "heu d'especificar el camí o camins a restaurar"
 
+#: builtin/checkout.c builtin/clone.c builtin/remote.c builtin/replay.c
+#: builtin/submodule--helper.c builtin/worktree.c
 msgid "branch"
 msgstr "branca"
 
+#: builtin/checkout.c
 msgid "create and checkout a new branch"
 msgstr "crea i agafa una branca nova"
 
+#: builtin/checkout.c
 msgid "create/reset and checkout a branch"
 msgstr "crea/restableix i agafa una branca"
 
+#: builtin/checkout.c
 msgid "create reflog for new branch"
-msgstr "crea un registre de referència per a la branca nova"
+msgstr "crea un registre de referències per a la branca nova"
 
+#: builtin/checkout.c
 msgid "second guess 'git checkout <no-such-branch>' (default)"
 msgstr "segona deducció «git checkout <no-such-branch>» (per defecte)"
 
+#: builtin/checkout.c
 msgid "use overlay mode (default)"
 msgstr "utilitza el mode de superposició (per defecte)"
 
+#: builtin/checkout.c
 msgid "create and switch to a new branch"
 msgstr "crea i canvia a una branca nova"
 
+#: builtin/checkout.c
 msgid "create/reset and switch to a branch"
 msgstr "crea/restableix i canvia a una branca"
 
+#: builtin/checkout.c
 msgid "second guess 'git switch <no-such-branch>'"
 msgstr "segona deducció «git switch <no-such-branch>»"
 
+#: builtin/checkout.c
 msgid "throw away local modifications"
 msgstr "descarta les modificacions locals"
 
+#: builtin/checkout.c
 msgid "which tree-ish to checkout from"
 msgstr "des de quin arbre agafar"
 
+#: builtin/checkout.c
 msgid "restore the index"
 msgstr "restaura l'índex"
 
+#: builtin/checkout.c
 msgid "restore the working tree (default)"
 msgstr "restaura l'arbre de treball (per defecte)"
 
+#: builtin/checkout.c
 msgid "ignore unmerged entries"
 msgstr "ignora les entrades sense fusionar"
 
+#: builtin/checkout.c
 msgid "use overlay mode"
 msgstr "utilitza el mode de superposició"
 
+#: builtin/clean.c
 msgid ""
 "git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] "
 "[<pathspec>...]"
@@ -4014,36 +5041,45 @@
 "git clean [-d] [-f] [-i] [-n] [-q] [-e <patró>] [-x | -X] [--] "
 "[<pathspec>...]"
 
+#: builtin/clean.c
 #, c-format
 msgid "Removing %s\n"
 msgstr "S'està eliminant %s\n"
 
+#: builtin/clean.c
 #, c-format
 msgid "Would remove %s\n"
 msgstr "Eliminaria %s\n"
 
+#: builtin/clean.c
 #, c-format
 msgid "Skipping repository %s\n"
 msgstr "S'està ometent el repositori %s\n"
 
+#: builtin/clean.c
 #, c-format
 msgid "Would skip repository %s\n"
 msgstr "Ometria el repositori %s\n"
 
+#: builtin/clean.c midx.c
 #, c-format
 msgid "failed to remove %s"
 msgstr "s'ha produït un error en eliminar %s"
 
+#: builtin/clean.c
 #, c-format
 msgid "could not lstat %s\n"
 msgstr "no s'ha pogut fer lstat %s\n"
 
+#: builtin/clean.c
 msgid "Refusing to remove current working directory\n"
 msgstr "S'ha rebutjat suprimir el directori de treball actual\n"
 
+#: builtin/clean.c
 msgid "Would refuse to remove current working directory\n"
 msgstr "Es rebutjarà eliminar el directori de treball actual\n"
 
+#: builtin/clean.c
 #, c-format
 msgid ""
 "Prompt help:\n"
@@ -4056,6 +5092,7 @@
 "foo        - selecciona un ítem basat en un prefix únic\n"
 "           - (buit) no seleccionis res\n"
 
+#: builtin/clean.c
 #, c-format
 msgid ""
 "Prompt help:\n"
@@ -4076,26 +5113,32 @@
 "*          - tria tots els ítems\n"
 "           - (buit) finalitza la selecció\n"
 
+#: builtin/clean.c
 #, c-format
 msgid "Huh (%s)?\n"
 msgstr "Perdó (%s)?\n"
 
+#: builtin/clean.c
 #, c-format
 msgid "Input ignore patterns>> "
 msgstr "Introduïu els patrons a ignorar>> "
 
+#: builtin/clean.c
 #, c-format
 msgid "WARNING: Cannot find items matched by: %s"
 msgstr "ADVERTÈNCIA: No es poden trobar ítems que coincideixin amb: %s"
 
+#: builtin/clean.c
 msgid "Select items to delete"
 msgstr "Selecciona els ítems a suprimir"
 
 #. TRANSLATORS: Make sure to keep [y/N] as is
+#: builtin/clean.c
 #, c-format
 msgid "Remove %s [y/N]? "
 msgstr "Voleu eliminar %s [y/N]? "
 
+#: builtin/clean.c
 msgid ""
 "clean               - start cleaning\n"
 "filter by pattern   - exclude items from deletion\n"
@@ -4113,216 +5156,286 @@
 "help                - aquesta pantalla\n"
 "?                   - ajuda de selecció manual"
 
+#: builtin/clean.c
 msgid "Would remove the following item:"
 msgid_plural "Would remove the following items:"
 msgstr[0] "Eliminaria l'ítem següent:"
 msgstr[1] "Eliminaria els ítems següents:"
 
+#: builtin/clean.c
 msgid "No more files to clean, exiting."
 msgstr "No hi ha més fitxers a netejar; s'està sortint."
 
+#: builtin/clean.c
 msgid "do not print names of files removed"
 msgstr "no imprimeixis els noms dels fitxers eliminats"
 
+#: builtin/clean.c
 msgid "force"
 msgstr "força"
 
+#: builtin/clean.c
 msgid "interactive cleaning"
 msgstr "neteja interactiva"
 
+#: builtin/clean.c
 msgid "remove whole directories"
 msgstr "elimina directoris sencers"
 
+#: builtin/clean.c builtin/config.c builtin/describe.c builtin/grep.c
+#: builtin/log.c builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c
+#: builtin/show-ref.c ref-filter.h
 msgid "pattern"
 msgstr "patró"
 
+#: builtin/clean.c
 msgid "add <pattern> to ignore rules"
 msgstr "afegiu <patró> per a ignorar les regles"
 
+#: builtin/clean.c
 msgid "remove ignored files, too"
 msgstr "elimina els fitxers ignorats, també"
 
+#: builtin/clean.c
 msgid "remove only ignored files"
 msgstr "elimina només els fitxers ignorats"
 
-msgid ""
-"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
-"clean"
+#: builtin/clean.c
+msgid "clean.requireForce is true and -f not given: refusing to clean"
 msgstr ""
-"clean.requireForce està establerta en cert i ni -i, -n ni -f s'han indicat; "
-"refusant netejar"
+"clean.requireForce està establert a cert i no s'ha indicat -f : es rebutja "
+"netejar"
 
-msgid ""
-"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
-"refusing to clean"
-msgstr ""
-"clean.requireForce és per defecte cert i ni -i, -n ni -f s'han indicat; "
-"refusant netejar"
-
+#: builtin/clone.c
 msgid "git clone [<options>] [--] <repo> [<dir>]"
 msgstr "git clone [<opcions>] [--] <repositori> [<directori>]"
 
+#: builtin/clone.c
 msgid "don't clone shallow repository"
 msgstr "no clonis un repositori superficial"
 
+#: builtin/clone.c
 msgid "don't create a checkout"
 msgstr "no facis cap agafament"
 
+#: builtin/clone.c builtin/init-db.c
 msgid "create a bare repository"
 msgstr "crea un repositori nu"
 
-msgid "create a mirror repository (implies bare)"
-msgstr "crea un repositori mirall (implica bare)"
+#: builtin/clone.c
+msgid "create a mirror repository (implies --bare)"
+msgstr "crear un repositori mirall (implica --bare)"
 
+#: builtin/clone.c
 msgid "to clone from a local repository"
 msgstr "per a clonar des d'un repositori local"
 
+#: builtin/clone.c
 msgid "don't use local hardlinks, always copy"
 msgstr "no usis enllaços durs locals, sempre copia"
 
+#: builtin/clone.c
 msgid "setup as shared repository"
 msgstr "configura com a repositori compartit"
 
+#: builtin/clone.c
 msgid "pathspec"
 msgstr "especificació de camí"
 
+#: builtin/clone.c
 msgid "initialize submodules in the clone"
 msgstr "inicialitza els submòduls en el clon"
 
+#: builtin/clone.c
 msgid "number of submodules cloned in parallel"
 msgstr "nombre de submòduls clonats en paral·lel"
 
+#: builtin/clone.c builtin/init-db.c
 msgid "template-directory"
 msgstr "directori-de-plantilla"
 
+#: builtin/clone.c builtin/init-db.c
 msgid "directory from which templates will be used"
 msgstr "directori des del qual s'usaran les plantilles"
 
+#: builtin/clone.c builtin/submodule--helper.c
 msgid "reference repository"
 msgstr "repositori de referència"
 
+#: builtin/clone.c builtin/submodule--helper.c
 msgid "use --reference only while cloning"
 msgstr "usa --reference només en clonar"
 
+#: 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 "nom"
 
+#: builtin/clone.c
 msgid "use <name> instead of 'origin' to track upstream"
 msgstr "usa <nom> en lloc d'«origin» per a seguir la font"
 
+#: builtin/clone.c
 msgid "checkout <branch> instead of the remote's HEAD"
 msgstr "agafa <branca> en lloc de la HEAD del remot"
 
+#: builtin/clone.c
 msgid "path to git-upload-pack on the remote"
 msgstr "camí a git-upload-pack en el remot"
 
+#: builtin/clone.c builtin/fetch.c builtin/pull.c
 msgid "depth"
 msgstr "profunditat"
 
+#: builtin/clone.c
 msgid "create a shallow clone of that depth"
 msgstr "crea un clon superficial d'aquesta profunditat"
 
+#: builtin/clone.c
 msgid "create a shallow clone since a specific time"
 msgstr "crea un clon superficial des d'una data específica"
 
+#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/rebase.c
+#: builtin/replay.c
 msgid "revision"
 msgstr "revisió"
 
+#: builtin/clone.c builtin/fetch.c builtin/pull.c
 msgid "deepen history of shallow clone, excluding rev"
 msgstr "aprofundeix la història d'un clon superficial, excloent una revisió"
 
+#: builtin/clone.c builtin/submodule--helper.c
 msgid "clone only one branch, HEAD or --branch"
 msgstr "clona només una branca, HEAD o --branch"
 
+#: builtin/clone.c
 msgid "don't clone any tags, and make later fetches not to follow them"
 msgstr ""
 "no cloneu cap etiqueta, i feu que els «fetch» següents no les segueixin"
 
+#: builtin/clone.c
 msgid "any cloned submodules will be shallow"
 msgstr "qualsevol submòdul clonat serà superficial"
 
+#: builtin/clone.c builtin/init-db.c
 msgid "gitdir"
 msgstr "directori de git"
 
+#: builtin/clone.c builtin/init-db.c
 msgid "separate git dir from working tree"
 msgstr "separa el directori de git de l'arbre de treball"
 
+#: builtin/clone.c builtin/init-db.c builtin/submodule--helper.c
 msgid "specify the reference format to use"
 msgstr "especifiqueu el format de referència a usar"
 
+#: builtin/clone.c
 msgid "key=value"
 msgstr "clau=valor"
 
+#: builtin/clone.c
 msgid "set config inside the new repository"
 msgstr "estableix la configuració dins del repositori nou"
 
+#: builtin/clone.c builtin/fetch.c builtin/ls-remote.c builtin/pull.c
+#: builtin/push.c builtin/send-pack.c
 msgid "server-specific"
 msgstr "específic al servidor"
 
+#: 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 "opció a transmetre"
 
+#: builtin/clone.c
 msgid "apply partial clone filters to submodules"
 msgstr "aplica els filtres de clonatge parcial als submòduls"
 
+#: builtin/clone.c
 msgid "any cloned submodules will use their remote-tracking branch"
 msgstr "qualsevol submòdul clonat utilitzarà la seva branca de seguiment remot"
 
+#: builtin/clone.c
 msgid "initialize sparse-checkout file to include only files at root"
 msgstr ""
 "inicialitza el fitxer «sparse-checkout» per a incloure només els fitxers a "
 "l'arrel"
 
+#: builtin/clone.c
 msgid "uri"
 msgstr "uri"
 
+#: builtin/clone.c
 msgid "a URI for downloading bundles before fetching from origin remote"
 msgstr "un URI per a baixar paquets abans d'obtenir des del remot origen"
 
+#: builtin/clone.c
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info: No s'ha pogut afegir un alternatiu per a «%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'ha produït un error en fer stat a «%s»"
 
+#: builtin/clone.c
 #, c-format
 msgid "%s exists and is not a directory"
 msgstr "%s existeix i no és directori"
 
+#: builtin/clone.c
 #, c-format
 msgid "'%s' is a symlink, refusing to clone with --local"
 msgstr "«%s» és un enllaç simbòlic, es rebutja clonar amb --local"
 
+#: builtin/clone.c
 #, c-format
 msgid "failed to start iterator over '%s'"
 msgstr "no s'ha pogut iniciar l'iterador sobre «%s»"
 
+#: builtin/clone.c
 #, c-format
 msgid "symlink '%s' exists, refusing to clone with --local"
 msgstr "l'enllaç simbòlic «%s» existeix, es rebutja a clonar amb --local"
 
+#: builtin/clone.c compat/precompose_utf8.c
 #, c-format
 msgid "failed to unlink '%s'"
 msgstr "s'ha produït un error en desenllaçar «%s»"
 
+#: builtin/clone.c
+#, c-format
+msgid "hardlink cannot be checked at '%s'"
+msgstr "no es pot comprovar l'enllaç físic en «%s»"
+
+#: builtin/clone.c
+#, c-format
+msgid "hardlink different from source at '%s'"
+msgstr "l'enllaç físic és diferent de la font en «%s»"
+
+#: builtin/clone.c
 #, c-format
 msgid "failed to create link '%s'"
 msgstr "s'ha produït un error en crear l'enllaç «%s»"
 
+#: builtin/clone.c
 #, c-format
 msgid "failed to copy file to '%s'"
 msgstr "s'ha produït un error en copiar el fitxer a «%s»"
 
+#: builtin/clone.c refs/files-backend.c
 #, c-format
 msgid "failed to iterate over '%s'"
 msgstr "no s'ha pogut iterar sobre «%s»"
 
+#: builtin/clone.c
 #, c-format
 msgid "done.\n"
 msgstr "fet.\n"
 
+#: builtin/clone.c
 msgid ""
 "Clone succeeded, but checkout failed.\n"
 "You can inspect what was checked out with 'git status'\n"
@@ -4332,83 +5445,106 @@
 "Podeu inspeccionar el que s'ha agafat amb «git status»\n"
 "i tornar-ho a provar amb «git restore --source=HEAD :/»\n"
 
+#: builtin/clone.c
 #, c-format
 msgid "Could not find remote branch %s to clone."
 msgstr "No s'ha pogut trobar la branca remota %s per a clonar."
 
+#: builtin/clone.c fetch-pack.c
 msgid "remote did not send all necessary objects"
 msgstr "el remot no ha enviat tots els objectes necessaris"
 
+#: builtin/clone.c
 #, c-format
 msgid "unable to update %s"
 msgstr "no s'ha pogut actualitzar %s"
 
+#: builtin/clone.c
 msgid "failed to initialize sparse-checkout"
 msgstr "no s'ha pogut inicialitzar «sparse-checkout»"
 
+#: builtin/clone.c
 msgid "remote HEAD refers to nonexistent ref, unable to checkout"
 msgstr ""
-"la HEAD remot es refereix a una referència que no existeix, no s'ha pogut "
+"el HEAD remot es refereix a una referència que no existeix, no s'ha pogut "
 "agafar"
 
+#: builtin/clone.c
 msgid "unable to checkout working tree"
 msgstr "no s'ha pogut agafar l'arbre de treball"
 
+#: builtin/clone.c
 msgid "unable to write parameters to config file"
 msgstr "no s'han pogut escriure els paràmetres al fitxer de configuració"
 
+#: builtin/clone.c
 msgid "cannot repack to clean up"
 msgstr "no es pot reempaquetar per a netejar"
 
+#: builtin/clone.c
 msgid "cannot unlink temporary alternates file"
 msgstr "no es pot desenllaçar el fitxer d'alternatives temporal"
 
+#: builtin/clone.c
 msgid "Too many arguments."
 msgstr "Hi ha massa arguments."
 
+#: builtin/clone.c scalar.c
 msgid "You must specify a repository to clone."
 msgstr "Heu d'especificar un repositori per a clonar."
 
+#: builtin/clone.c builtin/init-db.c builtin/refs.c builtin/submodule--helper.c
+#: setup.c
 #, c-format
 msgid "unknown ref storage format '%s'"
 msgstr "el format d'emmagatzematge de referència «%s» és desconegut"
 
+#: builtin/clone.c
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "el repositori «%s» no existeix"
 
+#: builtin/clone.c builtin/fetch.c
 #, c-format
 msgid "depth %s is not a positive number"
 msgstr "la profunditat %s no és un nombre positiu"
 
+#: builtin/clone.c
 #, c-format
 msgid "destination path '%s' already exists and is not an empty directory."
 msgstr "el camí destí «%s» ja existeix i no és un directori buit."
 
+#: builtin/clone.c
 #, c-format
 msgid "repository path '%s' already exists and is not an empty directory."
 msgstr "el camí destí «%s» ja existeix i no és un directori buit."
 
+#: builtin/clone.c
 #, c-format
 msgid "working tree '%s' already exists."
 msgstr "l'arbre de treball «%s» ja existeix."
 
+#: builtin/clone.c builtin/difftool.c builtin/log.c builtin/worktree.c
 #, c-format
 msgid "could not create leading directories of '%s'"
 msgstr "no s'han pogut crear els directoris inicials de «%s»"
 
+#: builtin/clone.c
 #, c-format
 msgid "could not create work tree dir '%s'"
 msgstr "no s'ha pogut crear el directori d'arbre de treball «%s»"
 
+#: builtin/clone.c
 #, c-format
 msgid "Cloning into bare repository '%s'...\n"
 msgstr "S'està clonant al repositori nu «%s»...\n"
 
+#: builtin/clone.c
 #, c-format
 msgid "Cloning into '%s'...\n"
 msgstr "S'està clonant a «%s»...\n"
 
+#: builtin/clone.c
 msgid ""
 "clone --recursive is not compatible with both --reference and --reference-if-"
 "able"
@@ -4416,85 +5552,115 @@
 "clone --recursive no és compatible amb ambdós --reference i --reference-if-"
 "able"
 
+#: builtin/clone.c builtin/remote.c
 #, c-format
 msgid "'%s' is not a valid remote name"
 msgstr "«%s» no és un nom de remot vàlid"
 
+#: builtin/clone.c
 msgid "--depth is ignored in local clones; use file:// instead."
 msgstr "--depth s'ignora en els clons locals; useu file:// en lloc d'això."
 
+#: builtin/clone.c
 msgid "--shallow-since is ignored in local clones; use file:// instead."
 msgstr ""
 "--shallow-since s'ignora en els clons locals; useu file:// en lloc d'això."
 
+#: builtin/clone.c
 msgid "--shallow-exclude is ignored in local clones; use file:// instead."
 msgstr ""
 "--shallow-exclude s'ignora en els clons locals; useu file:// en lloc d'això."
 
+#: builtin/clone.c
 msgid "--filter is ignored in local clones; use file:// instead."
 msgstr "--filter s'ignora en els clons locals; useu file:// en lloc d'això."
 
+#: builtin/clone.c fetch-pack.c
 msgid "source repository is shallow, reject to clone."
 msgstr "el repositori font és superficial, es rebutja clonar-ho."
 
+#: builtin/clone.c
 msgid "source repository is shallow, ignoring --local"
 msgstr "el repositori font és superficial, s'està ignorant --local"
 
+#: builtin/clone.c
 msgid "--local is ignored"
 msgstr "--local s'ignora"
 
+#: builtin/clone.c
 msgid "cannot clone from filtered bundle"
 msgstr "no es pot clonar des del farell filtrat"
 
+#: builtin/clone.c
 msgid "failed to initialize the repo, skipping bundle URI"
 msgstr "no s'ha pogut inicialitzar el repositori, s'omet l'URI del paquet"
 
+#: builtin/clone.c
 #, c-format
 msgid "failed to fetch objects from bundle URI '%s'"
 msgstr "no s'han pogut obtenir els objectes de l'URI del paquet «%s»"
 
+#: builtin/clone.c
 msgid "failed to fetch advertised bundles"
 msgstr "no s'han pogut obtenir els paquets anunciats"
 
+#: builtin/clone.c
 msgid "remote transport reported error"
 msgstr "el transport remot ha informat d'un error"
 
+#: builtin/clone.c
 #, c-format
 msgid "Remote branch %s not found in upstream %s"
 msgstr "La branca remota %s no es troba en la font %s"
 
+#: builtin/clone.c
 msgid "You appear to have cloned an empty repository."
 msgstr "Sembla que heu clonat un repositori buit."
 
+#: builtin/column.c
 msgid "git column [<options>]"
 msgstr "git column [<opcions>]"
 
+#: builtin/column.c
 msgid "lookup config vars"
 msgstr "cerca les variables de configuració"
 
+#: builtin/column.c
 msgid "layout to use"
 msgstr "disposició a usar"
 
+#: builtin/column.c
 msgid "maximum width"
 msgstr "amplada màxima"
 
+#: builtin/column.c
 msgid "padding space on left border"
 msgstr "espai de farciment al marge esquerre"
 
+#: builtin/column.c
 msgid "padding space on right border"
 msgstr "espai de farciment al marge dret"
 
+#: builtin/column.c
 msgid "padding space between columns"
 msgstr "espai de farciment entre columnes"
 
+#: builtin/column.c
+#, c-format
+msgid "%s must be non-negative"
+msgstr "%s ha de ser no negatiu"
+
+#: builtin/column.c
 msgid "--command must be the first argument"
 msgstr "--command ha de ser el primer argument"
 
+#: builtin/commit-graph.c
 msgid ""
 "git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]"
 msgstr ""
 "git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]"
 
+#: builtin/commit-graph.c
 msgid ""
 "git commit-graph write [--object-dir <dir>] [--append]\n"
 "                       [--split[=<strategy>]] [--reachable | --stdin-packs | "
@@ -4510,131 +5676,169 @@
 "[no-]progress]\n"
 "                       <split-options>"
 
+#: builtin/commit-graph.c builtin/fetch.c builtin/log.c builtin/repack.c
 msgid "dir"
 msgstr "directori"
 
+#: builtin/commit-graph.c
 msgid "the object directory to store the graph"
 msgstr "el directori d'objectes a emmagatzemar al graf"
 
+#: builtin/commit-graph.c
 msgid "if the commit-graph is split, only verify the tip file"
 msgstr ""
 "si el graf de comissions està dividit només, verifica el fitxer de consell"
 
+#: builtin/commit-graph.c
 #, c-format
 msgid "Could not open commit-graph '%s'"
 msgstr "No s'ha pogut obrir el graf de comissions «%s»"
 
+#: builtin/commit-graph.c
 #, c-format
 msgid "could not open commit-graph chain '%s'"
 msgstr "no s'ha pogut obrir la cadena «%s» del graf de comissions"
 
+#: builtin/commit-graph.c
 #, c-format
 msgid "unrecognized --split argument, %s"
 msgstr "argument --split no reconegut, %s"
 
+#: builtin/commit-graph.c
 #, c-format
 msgid "unexpected non-hex object ID: %s"
 msgstr "ID de l'objecte no hexadecimal inesperat: %s"
 
+#: builtin/commit-graph.c
 #, c-format
 msgid "invalid object: %s"
 msgstr "no és un objecte vàlid: %s"
 
+#: builtin/commit-graph.c parse-options-cb.c
 #, c-format
 msgid "option `%s' expects a numerical value"
 msgstr "l'opció «%s» espera un valor numèric"
 
+#: builtin/commit-graph.c
 msgid "start walk at all refs"
 msgstr "comença el recorregut en totes les referències"
 
+#: builtin/commit-graph.c
 msgid "scan pack-indexes listed by stdin for commits"
 msgstr "explora els índexs del paquet llistats per a stdin per a comissions"
 
+#: builtin/commit-graph.c
 msgid "start walk at commits listed by stdin"
 msgstr "comença el recorregut per les comissions llistades per stdin"
 
+#: builtin/commit-graph.c
 msgid "include all commits already in the commit-graph file"
 msgstr "inclou ja totes les comissions al fitxer del graf de comissions"
 
+#: builtin/commit-graph.c
 msgid "enable computation for changed paths"
 msgstr "habilita la computació per als camins canviats"
 
+#: builtin/commit-graph.c
 msgid "allow writing an incremental commit-graph file"
 msgstr "permet escriure un fitxer de graf de comissions incrementals"
 
+#: builtin/commit-graph.c
 msgid "maximum number of commits in a non-base split commit-graph"
 msgstr ""
 "nombre màxim de comissions en un graf de comissions separades sense base"
 
+#: builtin/commit-graph.c
 msgid "maximum ratio between two levels of a split commit-graph"
 msgstr "ràtio màxima entre dos nivells d'un graf de comissions dividit"
 
+#: builtin/commit-graph.c
 msgid "only expire files older than a given date-time"
 msgstr "fes caducar només els objectes més antics que l'hora i data donades"
 
+#: builtin/commit-graph.c
 msgid "maximum number of changed-path Bloom filters to compute"
-msgstr "nombre màxim de canvis de camí en filtres Bloom a calcular"
+msgstr "nombre màxim de canvis de camí en filtres de Bloom a calcular"
 
+#: builtin/commit-graph.c
 msgid "use at most one of --reachable, --stdin-commits, or --stdin-packs"
-msgstr "usa com a màxim un --reachable, --stdin-commits, o --stdin-packs"
+msgstr "usa com a màxim un entre --reachable, --stdin-commits, o --stdin-packs"
 
+#: builtin/commit-graph.c
 msgid "Collecting commits from input"
 msgstr "S'estan recollint les comissions de l'entrada"
 
+#: builtin/commit-tree.c
 msgid "git commit-tree <tree> [(-p <parent>)...]"
-msgstr "git commit-tree <tree> [(-p <pare>)...]"
+msgstr "git commit-tree <arbre> [(-p <pare>)...]"
 
+#: builtin/commit-tree.c
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]\n"
 "                [(-F <file>)...] <tree>"
 msgstr ""
 "git commit-tree [(-p <pare>)...] [-S[<keyid>]] [(-m <missatge>)...]\n"
-"                [(-F <fitxer>)...] <tree>"
+"                [(-F <fitxer>)...] <arbre>"
 
+#: builtin/commit-tree.c
 #, c-format
 msgid "duplicate parent %s ignored"
 msgstr "s'han ignorat el pare %s duplicat"
 
+#: builtin/commit-tree.c builtin/log.c
 #, c-format
 msgid "not a valid object name %s"
 msgstr "no és un nom d'objecte vàlid %s"
 
+#: builtin/commit-tree.c
 #, c-format
 msgid "git commit-tree: failed to read '%s'"
 msgstr "git commit-tree: ha fallat en llegir «%s»"
 
+#: builtin/commit-tree.c
 #, c-format
 msgid "git commit-tree: failed to close '%s'"
 msgstr "git commit-tree: ha fallat en tancar «%s»"
 
+#: builtin/commit-tree.c
 msgid "parent"
 msgstr "pare"
 
+#: builtin/commit-tree.c
 msgid "id of a parent commit object"
 msgstr "id d'un objecte de comissió pare"
 
+#: builtin/commit-tree.c builtin/commit.c builtin/merge.c builtin/notes.c
+#: builtin/stash.c builtin/tag.c
 msgid "message"
 msgstr "missatge"
 
+#: builtin/commit-tree.c builtin/commit.c
 msgid "commit message"
 msgstr "missatge de comissió"
 
+#: builtin/commit-tree.c
 msgid "read commit log message from file"
 msgstr "llegeix el missatge de registre de comissió des d'un fitxer"
 
+#: builtin/commit-tree.c builtin/commit.c builtin/merge.c builtin/pull.c
+#: builtin/revert.c
 msgid "GPG sign commit"
 msgstr "signa la comissió amb GPG"
 
+#: builtin/commit-tree.c
 msgid "must give exactly one tree"
 msgstr "ha de donar exactament un arbre"
 
+#: builtin/commit-tree.c
 msgid "git commit-tree: failed to read"
 msgstr "git commit-tree: ha fallat en llegir"
 
+#: 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"
+"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"
@@ -4644,17 +5848,19 @@
 msgstr ""
 "git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <comissió> | --fixup [(amend|"
-"reword):]<comissió>)]\n"
+"reword):]<comissió>]\n"
 "           [-F <fitxer> | -m <msg>] [--reset-author] [--allow-empty]\n"
-"           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
-"           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
+"           [--allow-empty-message] [--no-verify] [-e] [--author=<autor>]\n"
+"           [--date=<data>] [--cleanup=<mode>] [--[no-]status]\n"
 "           [-i | -o] [--pathspec-from-file=<fitxer> [--pathspec-file-nul]]\n"
-"           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
-"           [--] [<pathspec>...]"
+"           [(--trailer <token>[(=|:)<valor>])...] [-S[<id-clau>]]\n"
+"           [--] [<especificació-camí>...]"
 
+#: builtin/commit.c
 msgid "git status [<options>] [--] [<pathspec>...]"
 msgstr "git status [<opcions>] [--] [<pathspec>...]"
 
+#: builtin/commit.c
 msgid ""
 "You asked to amend the most recent commit, but doing so would make\n"
 "it empty. You can repeat your command with --allow-empty, or you can\n"
@@ -4664,6 +5870,7 @@
 "deixaria buida. Podeu repetir la vostra ordre amb --allow-empty, o\n"
 "podeu eliminar la comissió per complet amb «git reset HEAD^».\n"
 
+#: builtin/commit.c
 msgid ""
 "The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
 "If you wish to commit it anyway, use:\n"
@@ -4678,12 +5885,15 @@
 "    git commit --allow-empty\n"
 "\n"
 
+#: builtin/commit.c
 msgid "Otherwise, please use 'git rebase --skip'\n"
 msgstr "Altrament, si us plau useu «git rebase --skip»\n"
 
+#: builtin/commit.c
 msgid "Otherwise, please use 'git cherry-pick --skip'\n"
 msgstr "Altrament, si us plau useu «git cherry-pick --skip»\n"
 
+#: builtin/commit.c
 msgid ""
 "and then use:\n"
 "\n"
@@ -4705,57 +5915,74 @@
 "    git cherry-pick --skip\n"
 "\n"
 
+#: builtin/commit.c read-cache.c
 msgid "updating files failed"
 msgstr "s'ha produït un error en actualitzar els fitxers"
 
+#: builtin/commit.c
 msgid "failed to unpack HEAD tree object"
 msgstr "s'ha produït un error en desempaquetar l'objecte d'arbre HEAD"
 
+#: builtin/commit.c
 msgid "No paths with --include/--only does not make sense."
 msgstr "--include/--only no té sentit sense camí."
 
+#: builtin/commit.c
 msgid "unable to create temporary index"
 msgstr "no s'ha pogut crear un índex temporal"
 
+#: builtin/commit.c
 msgid "interactive add failed"
 msgstr "l'afegiment interactiu ha fallat"
 
+#: builtin/commit.c
 msgid "unable to update temporary index"
 msgstr "no s'ha pogut actualitzar l'índex temporal"
 
+#: builtin/commit.c
 msgid "Failed to update main cache tree"
 msgstr "S'ha produït un error en actualitzar l'arbre principal de memòria cau"
 
+#: builtin/commit.c
 msgid "cannot do a partial commit during a merge."
 msgstr "no es pot fer una comissió parcial durant una fusió."
 
+#: builtin/commit.c
 msgid "cannot do a partial commit during a cherry-pick."
 msgstr "no es pot fer una comissió parcial durant un «cherry pick»."
 
+#: builtin/commit.c
 msgid "cannot do a partial commit during a rebase."
 msgstr "no es pot fer una comissió parcial durant un «rebase»."
 
+#: builtin/commit.c
 msgid "cannot read the index"
 msgstr "no es pot llegir l'índex"
 
+#: builtin/commit.c
 msgid "unable to write temporary index file"
 msgstr "no s'ha pogut escriure un fitxer d'índex temporal"
 
+#: builtin/commit.c
 #, c-format
 msgid "commit '%s' lacks author header"
 msgstr "a la comissió «%s» li manca la capçalera d'autor"
 
+#: builtin/commit.c
 #, c-format
 msgid "commit '%s' has malformed author line"
 msgstr "la comissió «%s» té una línia d'autor mal formada"
 
+#: builtin/commit.c
 msgid "malformed --author parameter"
 msgstr "paràmetre --author mal format"
 
+#: builtin/commit.c ident.c
 #, c-format
 msgid "invalid date format: %s"
 msgstr "format de data no vàlid: %s"
 
+#: builtin/commit.c
 msgid ""
 "unable to select a comment character that is not used\n"
 "in the current commit message"
@@ -4763,74 +5990,88 @@
 "no es pot seleccionar un caràcter de comentari que\n"
 "no sigui usat en el missatge de comissió actual"
 
+#: builtin/commit.c
 #, c-format
 msgid "could not lookup commit '%s'"
 msgstr "no s'ha pogut cercar la comissió «%s»"
 
+#: builtin/commit.c builtin/shortlog.c
 #, c-format
 msgid "(reading log message from standard input)\n"
 msgstr "(s'està llegint el missatge de registre des de l'entrada estàndard)\n"
 
+#: builtin/commit.c
 msgid "could not read log from standard input"
 msgstr "no s'ha pogut llegir el registre des de l'entrada estàndard"
 
+#: builtin/commit.c
 #, c-format
 msgid "could not read log file '%s'"
 msgstr "no s'ha pogut llegir el fitxer de registre «%s»"
 
+#: builtin/commit.c
 #, c-format
 msgid "options '%s' and '%s:%s' cannot be used together"
 msgstr "les opcions «%s» i «%s:%s» no es poden usar juntes"
 
+#: builtin/commit.c
 msgid "could not read SQUASH_MSG"
 msgstr "no s'ha pogut llegir SQUASH_MSG"
 
+#: builtin/commit.c
 msgid "could not read MERGE_MSG"
 msgstr "no s'ha pogut llegir MERGE_MSG"
 
+#: builtin/commit.c bundle.c rerere.c sequencer.c
 #, c-format
 msgid "could not open '%s'"
 msgstr "no s'ha pogut obrir «%s»"
 
+#: builtin/commit.c
 msgid "could not write commit template"
 msgstr "no s'ha pogut escriure la plantilla de comissió"
 
+#: builtin/commit.c
 #, c-format
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored.\n"
+"with '%s' will be ignored.\n"
 msgstr ""
-"Introduïu el missatge de comissió per als vostres canvis.\n"
-"S'ignoraran les línies que comencin amb «%c».\n"
+"Introduïu el missatge de comissió per als vostres canvis. \n"
+"S'ignoraran les línies que comencin amb «%s».\n"
 
+#: builtin/commit.c
 #, c-format
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be ignored, and an empty message aborts the commit.\n"
+"with '%s' will be ignored, and an empty message aborts the commit.\n"
 msgstr ""
 "Introduïu el missatge de comissió dels vostres canvis.\n"
-"S'ignoraran les línies que comencin amb «%c». Un missatge de\n"
+"S'ignoraran les línies que comencin amb «%s». Un missatge de\n"
 "comissió buit avorta la comissió.\n"
 
+#: builtin/commit.c
 #, c-format
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be kept; you may remove them yourself if you want to.\n"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
 msgstr ""
 "Introduïu el missatge de comissió pels vostres canvis. Es mantindran\n"
-"les línies que comencin amb «%c»; podeu eliminar-les si voleu.\n"
+"les línies que comencin amb «%s»; podeu eliminar-les vosaltres mateixos\n"
+"si voleu.\n"
 
+#: builtin/commit.c
 #, c-format
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
-"with '%c' will be kept; you may remove them yourself if you want to.\n"
+"with '%s' will be kept; you may remove them yourself if you want to.\n"
 "An empty message aborts the commit.\n"
 msgstr ""
 "Introduïu el missatge de comissió dels vostres canvis.\n"
-"Es mantindran les línies que comencin amb «%c»; podeu eliminar-les "
-"vosaltres\n"
-"mateixos si voleu. Un missatge buit avorta la comissió.\n"
+"Es mantindran les línies que comencin amb «%s»; podeu eliminar-les \n"
+"vosaltres mateixos si voleu. Un missatge buit avorta la comissió.\n"
 
+#: builtin/commit.c
 msgid ""
 "\n"
 "It looks like you may be committing a merge.\n"
@@ -4844,6 +6085,7 @@
 "\tgit update-ref -d MERGE_HEAD\n"
 "i intenteu-ho de nou.\n"
 
+#: builtin/commit.c
 msgid ""
 "\n"
 "It looks like you may be committing a cherry-pick.\n"
@@ -4857,111 +6099,142 @@
 "\tgit update-ref -d CHERRY_PICK_HEAD\n"
 "i intenteu-ho de nou.\n"
 
+#: builtin/commit.c
 #, c-format
 msgid "%sAuthor:    %.*s <%.*s>"
 msgstr "%sAutor:    %.*s <%.*s>"
 
+#: builtin/commit.c
 #, c-format
 msgid "%sDate:      %s"
 msgstr "%sData:      %s"
 
+#: builtin/commit.c
 #, c-format
 msgid "%sCommitter: %.*s <%.*s>"
 msgstr "%sComitent: %.*s <%.*s>"
 
+#: builtin/commit.c
 msgid "Cannot read index"
 msgstr "No es pot llegir l'índex"
 
+#: builtin/commit.c builtin/tag.c
 msgid "unable to pass trailers to --trailers"
 msgstr "no s'han pogut passar els «trailers» a --trailers"
 
+#: builtin/commit.c
 msgid "Error building trees"
 msgstr "Error en construir els arbres"
 
+#: builtin/commit.c builtin/tag.c
 #, c-format
 msgid "Please supply the message using either -m or -F option.\n"
 msgstr "Especifiqueu el missatge usant l'opció -m o l'opció -F.\n"
 
+#: builtin/commit.c
 #, c-format
 msgid "--author '%s' is not 'Name <email>' and matches no existing author"
 msgstr ""
 "--author «%s» no és «Nom <adreça-electrònica>» i no coincideix amb\n"
 "cap autor existent"
 
+#: builtin/commit.c
 #, c-format
 msgid "Invalid ignored mode '%s'"
 msgstr "Mode d'ignorància no vàlid «%s»"
 
+#: builtin/commit.c
 #, c-format
 msgid "Invalid untracked files mode '%s'"
 msgstr "Mode de fitxers no seguits no vàlid «%s»"
 
+#: builtin/commit.c
 msgid "You are in the middle of a merge -- cannot reword."
 msgstr "Esteu enmig d'una fusió -- no es pot fer «reword»."
 
+#: builtin/commit.c
 msgid "You are in the middle of a cherry-pick -- cannot reword."
 msgstr "Esteu enmig d'un «cherry pick» -- no es pot fer «reword»."
 
+#: builtin/commit.c
 #, c-format
 msgid "reword option of '%s' and path '%s' cannot be used together"
 msgstr "les opcions de «reword» «%s» i camí «%s» no es poden usar juntes"
 
+#: builtin/commit.c
 #, c-format
 msgid "reword option of '%s' and '%s' cannot be used together"
 msgstr "les opcions de «reword» «%s» i «%s» no es poden usar juntes"
 
+#: builtin/commit.c
 msgid "You have nothing to amend."
 msgstr "No teniu res a esmenar."
 
+#: builtin/commit.c
 msgid "You are in the middle of a merge -- cannot amend."
 msgstr "Esteu enmig d'una fusió -- no es pot esmenar."
 
+#: builtin/commit.c
 msgid "You are in the middle of a cherry-pick -- cannot amend."
 msgstr "Esteu enmig d'un «cherry pick» -- no es pot esmenar."
 
+#: builtin/commit.c
 msgid "You are in the middle of a rebase -- cannot amend."
 msgstr "Esteu enmig d'un «rebase» -- no es pot esmenar."
 
+#: builtin/commit.c
 msgid "--reset-author can be used only with -C, -c or --amend."
 msgstr "--reset-author només es pot usar amb -C, -c o --amend."
 
+#: builtin/commit.c
 #, c-format
 msgid "unknown option: --fixup=%s:%s"
 msgstr "opció desconeguda: --fixup=%s:%s"
 
+#: builtin/commit.c
 #, c-format
 msgid "paths '%s ...' with -a does not make sense"
 msgstr "els camins «%s ...» amb -a no tenen sentit"
 
+#: builtin/commit.c
 msgid "show status concisely"
 msgstr "mostra l'estat concisament"
 
+#: builtin/commit.c
 msgid "show branch information"
 msgstr "mostra la informació de branca"
 
+#: builtin/commit.c
 msgid "show stash information"
 msgstr "mostra la informació de «stash»"
 
+#: builtin/commit.c
 msgid "compute full ahead/behind values"
 msgstr "calcula els valors complets endavant/darrere"
 
+#: builtin/commit.c
 msgid "version"
 msgstr "versió"
 
+#: builtin/commit.c builtin/fetch.c builtin/push.c builtin/worktree.c
 msgid "machine-readable output"
 msgstr "sortida llegible per una màquina"
 
+#: builtin/commit.c
 msgid "show status in long format (default)"
 msgstr "mostra l'estat en format llarg (per defecte)"
 
+#: builtin/commit.c
 msgid "terminate entries with NUL"
 msgstr "acaba les entrades amb NUL"
 
+#: builtin/commit.c
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 "mostra els fitxers no seguits, modes opcionals: all, normal, no. (Per "
 "defecte: all)"
 
+#: builtin/commit.c
 msgid ""
 "show ignored files, optional modes: traditional, matching, no. (Default: "
 "traditional)"
@@ -4969,9 +6242,11 @@
 "mostra els fitxers ignorats, modes opcionals: traditional, matching, no. "
 "(Per defecte: traditional, matching, no.)"
 
+#: builtin/commit.c parse-options.h
 msgid "when"
 msgstr "quan"
 
+#: builtin/commit.c
 msgid ""
 "ignore changes to submodules, optional when: all, dirty, untracked. "
 "(Default: all)"
@@ -4979,153 +6254,199 @@
 "ignora els canvis als submòduls, opcional quan: all, dirty, untracked. (Per "
 "defecte: all)"
 
+#: builtin/commit.c
 msgid "list untracked files in columns"
 msgstr "mostra els fitxers no seguits en columnes"
 
+#: builtin/commit.c
 msgid "do not detect renames"
 msgstr "no detectis canvis de noms"
 
+#: builtin/commit.c
 msgid "detect renames, optionally set similarity index"
 msgstr "detecta canvis de noms, i opcionalment estableix un índex de semblança"
 
+#: builtin/commit.c
 msgid "Unsupported combination of ignored and untracked-files arguments"
 msgstr ""
 "No s'admet la combinació d'arguments d'ignorància i de fitxers no seguits"
 
+#: builtin/commit.c
 msgid "suppress summary after successful commit"
 msgstr "omet el resum després d'una comissió reeixida"
 
+#: builtin/commit.c
 msgid "show diff in commit message template"
 msgstr "mostra la diferència en la plantilla de missatge de comissió"
 
+#: builtin/commit.c
 msgid "Commit message options"
 msgstr "Opcions de missatge de comissió"
 
+#: builtin/commit.c builtin/merge.c builtin/tag.c
 msgid "read message from file"
 msgstr "llegeix el missatge des d'un fitxer"
 
+#: builtin/commit.c
 msgid "author"
 msgstr "autor"
 
+#: builtin/commit.c
 msgid "override author for commit"
 msgstr "sobreescriu l'autor de la comissió"
 
+#: builtin/commit.c builtin/gc.c
 msgid "date"
 msgstr "data"
 
+#: builtin/commit.c
 msgid "override date for commit"
 msgstr "sobreescriu la data de la comissió"
 
+#: builtin/commit.c parse-options.h ref-filter.h
 msgid "commit"
 msgstr "comissió"
 
+#: builtin/commit.c
 msgid "reuse and edit message from specified commit"
 msgstr "reusa i edita el missatge de la comissió especificada"
 
+#: builtin/commit.c
 msgid "reuse message from specified commit"
 msgstr "reusa el missatge de la comissió especificada"
 
 #. TRANSLATORS: Leave "[(amend|reword):]" as-is,
 #. and only translate <commit>.
 #.
+#: builtin/commit.c
 msgid "[(amend|reword):]commit"
 msgstr "[(amend|reword):]commit"
 
+#: builtin/commit.c
 msgid ""
 "use autosquash formatted message to fixup or amend/reword specified commit"
 msgstr ""
-"usa un missatge amb format de «squash» automàtic per a esmenar la comissió "
-"especificada"
+"usa un missatge amb format de «squash» automàtic per a fer amend/reword de "
+"la comissió especificada"
 
+#: builtin/commit.c
 msgid "use autosquash formatted message to squash specified commit"
 msgstr ""
 "usa un missatge amb format de «squash» automàtic per a fer «squash» de la "
 "comissió especificada"
 
+#: builtin/commit.c
 msgid "the commit is authored by me now (used with -C/-c/--amend)"
 msgstr "l'autor de la comissió soc jo ara (s'usa amb -C/-c/--amend)"
 
+#: builtin/commit.c builtin/interpret-trailers.c builtin/tag.c
 msgid "trailer"
 msgstr "remolc"
 
+#: builtin/commit.c builtin/tag.c
 msgid "add custom trailer(s)"
 msgstr "afegeix un «trailer» personalitzat"
 
+#: builtin/commit.c builtin/log.c builtin/merge.c builtin/pull.c
+#: builtin/revert.c
 msgid "add a Signed-off-by trailer"
 msgstr "afegeix un «trailer» tipus «Signed-off-by»"
 
+#: builtin/commit.c
 msgid "use specified template file"
 msgstr "usa el fitxer de plantilla especificat"
 
+#: builtin/commit.c
 msgid "force edit of commit"
 msgstr "força l'edició de la comissió"
 
+#: builtin/commit.c
 msgid "include status in commit message template"
 msgstr "inclou l'estat en la plantilla de missatge de comissió"
 
+#: builtin/commit.c
 msgid "Commit contents options"
 msgstr "Opcions per al contingut de les comissions"
 
+#: builtin/commit.c
 msgid "commit all changed files"
 msgstr "comet tots els fitxers canviats"
 
+#: builtin/commit.c
 msgid "add specified files to index for commit"
 msgstr "afegeix els fitxers especificats a l'índex per a cometre"
 
+#: builtin/commit.c
 msgid "interactively add files"
 msgstr "afegeix els fitxers interactivament"
 
+#: builtin/commit.c
 msgid "interactively add changes"
 msgstr "afegeix els canvis interactivament"
 
+#: builtin/commit.c
 msgid "commit only specified files"
 msgstr "comet només els fitxers especificats"
 
+#: builtin/commit.c
 msgid "bypass pre-commit and commit-msg hooks"
 msgstr "evita els lligams de precomissió i missatge de comissió"
 
+#: builtin/commit.c
 msgid "show what would be committed"
 msgstr "mostra què es cometria"
 
+#: builtin/commit.c
 msgid "amend previous commit"
 msgstr "esmena la comissió anterior"
 
+#: builtin/commit.c
 msgid "bypass post-rewrite hook"
 msgstr "evita el lligam de post escriptura"
 
+#: builtin/commit.c
 msgid "ok to record an empty change"
 msgstr "està bé registrar un canvi buit"
 
+#: builtin/commit.c
 msgid "ok to record a change with an empty message"
 msgstr "està bé registrar un canvi amb missatge buit"
 
+#: builtin/commit.c sequencer.c
 msgid "could not parse HEAD commit"
 msgstr "no s'ha pogut analitzar la comissió HEAD"
 
+#: builtin/commit.c
 #, c-format
 msgid "Corrupt MERGE_HEAD file (%s)"
 msgstr "Fitxer MERGE_HEAD malmès (%s)"
 
+#: builtin/commit.c
 msgid "could not read MERGE_MODE"
 msgstr "no s'ha pogut llegir MERGE_MODE"
 
+#: builtin/commit.c
 #, c-format
 msgid "could not read commit message: %s"
 msgstr "no s'ha pogut llegir el missatge de comissió: %s"
 
+#: builtin/commit.c
 #, c-format
 msgid "Aborting commit due to empty commit message.\n"
 msgstr "S'està avortant la comissió a causa d'un missatge de comissió buit.\n"
 
+#: builtin/commit.c
 #, c-format
 msgid "Aborting commit; you did not edit the message.\n"
 msgstr "S'està avortant la comissió; no heu editat el missatge.\n"
 
+#: builtin/commit.c
 #, c-format
 msgid "Aborting commit due to empty commit message body.\n"
 msgstr ""
 "S'està interrompent la comissió a causa d'un missatge de comissió buit.\n"
 
+#: builtin/commit.c
 msgid ""
 "repository has been updated, but unable to write\n"
 "new index file. Check that disk is not full and quota is\n"
@@ -5136,183 +6457,230 @@
 "la quota no s'ha excedit, i després feu «git restore --staged :/n»\n"
 "per a recuperar-ho."
 
-msgid "git config [<options>]"
-msgstr "git config [<opcions>]"
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid "git config list [<file-option>] [<display-option>] [--includes]"
+msgstr "git config list [<opció-fitxer>] [<opció-presentació>] [--includes]"
 
-#, c-format
-msgid "unrecognized --type argument, %s"
-msgstr "argument --type no reconegut, %s"
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
+msgstr ""
+"git config get [<opció-fitxer>] [<opció-presentació>] [--includes] [--all] "
+"[--regexp] [--value=<valor>] [--fixed-value] [--default=<default>] <nom>"
 
-msgid "only one type at a time"
-msgstr "només un tipus cada cop"
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
+"fixed-value] <name> <value>"
+msgstr ""
+"git config set [<opció-fitxer>] [--type=<tipus>] [--all] [--value=<valor>] "
+"[--fixed-value] <nom> <valor>"
 
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid ""
+"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] "
+"<name> <value>"
+msgstr ""
+"git config unset [<opció-fitxer>] [--all] [--value=<valor>] [--fixed-value] "
+"<name> <valor>"
+
+#: builtin/config.c
+msgid "git config rename-section [<file-option>] <old-name> <new-name>"
+msgstr "git config rename-section [<opció-fitxer>] <nom-vell> <nom-nou>"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid "git config remove-section [<file-option>] <name>"
+msgstr "git config remove-section [<opció-fitxer>] <nom>"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid "git config edit [<file-option>]"
+msgstr "git config edit [<opció-fitxer>]"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"
+msgstr "git config [<opció-fitxer>] --get-colorbool <nom> [<stdout-is-tty>]"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<opció-fitxer>] [<opció-presentació>] [--includes] [--all] "
+"[--regexp=<expr-reg>] [--value=<valor>] [--fixed-value] [--"
+"default=<default>] <nom>"
+
+# Cal traduir els paràmetres amb <...>?
+#: builtin/config.c
+msgid ""
+"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
+"[--value=<value>] [--fixed-value] <name> <value>"
+msgstr ""
+"git config set [<opció-fitxer>] [--type=<tipus>] [--comment=<missatge>] [--"
+"all] [--value=<valor>] [--fixed-value] <nom> <valor>"
+
+#: builtin/config.c
 msgid "Config file location"
 msgstr "Ubicació del fitxer de configuració"
 
+#: builtin/config.c
 msgid "use global config file"
 msgstr "usa el fitxer de configuració global"
 
+#: builtin/config.c
 msgid "use system config file"
 msgstr "usa el fitxer de configuració del sistema"
 
+#: builtin/config.c
 msgid "use repository config file"
 msgstr "usa el fitxer de configuració del repositori"
 
+#: builtin/config.c
 msgid "use per-worktree config file"
 msgstr "usa un fitxer de configuració per repositori"
 
+#: builtin/config.c builtin/gc.c
 msgid "use given config file"
 msgstr "usa el fitxer de configuració donat"
 
+#: builtin/config.c
 msgid "blob-id"
 msgstr "ID de blob"
 
+#: builtin/config.c
 msgid "read config from given blob object"
 msgstr "llegeix la configuració de l'objecte de blob donat"
 
-msgid "Action"
-msgstr "Acció"
-
-msgid "get value: name [value-pattern]"
-msgstr "obtén valor: nom [value-pattern]"
-
-msgid "get all values: key [value-pattern]"
-msgstr "obtén tots els valors: clau [value-pattern]"
-
-msgid "get values for regexp: name-regex [value-pattern]"
-msgstr "obtén valors de regexp: name-regex [value-pattern]"
-
-msgid "get value specific for the URL: section[.var] URL"
-msgstr "obtén el valor específic per a l'URL: secció[.variable] URL"
-
-msgid "replace all matching variables: name value [value-pattern]"
-msgstr ""
-"reemplaça totes les variables que coincideixen: nom valor [value-pattern]"
-
-msgid "add a new variable: name value"
-msgstr "afegeix una variable nova: nom valor"
-
-msgid "remove a variable: name [value-pattern]"
-msgstr "elimina una variable: nom [value-pattern]"
-
-msgid "remove all matches: name [value-pattern]"
-msgstr "elimina totes les coincidències: nom [value-pattern]"
-
-msgid "rename section: old-name new-name"
-msgstr "canvia el nom de secció: nom-antic nom-nou"
-
-msgid "remove a section: name"
-msgstr "elimina una secció: nom"
-
-msgid "list all"
-msgstr "llista'ls tots"
-
-msgid "use string equality when comparing values to 'value-pattern'"
-msgstr ""
-"usa la igualtat de les cadenes quan es comparen els valors amb «value-"
-"pattern»"
-
-msgid "open an editor"
-msgstr "obre un editor"
-
-msgid "find the color configured: slot [default]"
-msgstr "troba el color configurat: ranura [per defecte]"
-
-msgid "find the color setting: slot [stdout-is-tty]"
-msgstr "troba el paràmetre de color: ranura [stdout-és-tty]"
-
+#: builtin/config.c
 msgid "Type"
 msgstr "Tipus"
 
+#: builtin/config.c builtin/hash-object.c
 msgid "type"
 msgstr "tipus"
 
+#: builtin/config.c
 msgid "value is given this type"
 msgstr "el valor és d'aquest tipus que s'ha donat"
 
+#: builtin/config.c
 msgid "value is \"true\" or \"false\""
 msgstr "el valor és «true» o «false»"
 
+#: builtin/config.c
 msgid "value is decimal number"
 msgstr "el valor és un nombre decimal"
 
+#: builtin/config.c
 msgid "value is --bool or --int"
 msgstr "el valor és --bool o --int"
 
+#: builtin/config.c
 msgid "value is --bool or string"
 msgstr "el valor és --bool o string"
 
+#: builtin/config.c
 msgid "value is a path (file or directory name)"
 msgstr "el valor és un camí (nom de fitxer o directori)"
 
+#: builtin/config.c
 msgid "value is an expiry date"
 msgstr "el valor és una data de venciment"
 
-msgid "Other"
-msgstr "Altre"
+#: builtin/config.c
+msgid "Display options"
+msgstr "Opcions de visualització"
 
+#: builtin/config.c
 msgid "terminate values with NUL byte"
 msgstr "acaba els valors amb un octet NUL"
 
+#: builtin/config.c
 msgid "show variable names only"
 msgstr "mostra només els noms de variable"
 
-msgid "respect include directives on lookup"
-msgstr "respecta les directives d'inclusió en cercar"
-
+#: builtin/config.c
 msgid "show origin of config (file, standard input, blob, command line)"
 msgstr ""
 "mostra l'origen de la configuració (fitxer, entrada estàndard, blob, línia "
 "d'ordres)"
 
+#: builtin/config.c
 msgid "show scope of config (worktree, local, global, system, command)"
 msgstr ""
 "mostra l'abast de la configuració («worktree», «local», «global», «system», "
 "«command»)"
 
-msgid "value"
-msgstr "valor"
+#: builtin/config.c
+msgid "show config keys in addition to their values"
+msgstr "mostra les claus de configuració a més dels seus valors"
 
-msgid "with --get, use default value when missing entry"
-msgstr "amb --get utilitza el valor per defecte quan falti una entrada"
+#: builtin/config.c
+#, c-format
+msgid "unrecognized --type argument, %s"
+msgstr "argument --type no reconegut, %s"
 
+#: builtin/config.c
+msgid "only one type at a time"
+msgstr "només un tipus cada cop"
+
+#: builtin/config.c
 #, c-format
 msgid "wrong number of arguments, should be %d"
 msgstr "nombre d'arguments erroni, ha de ser %d"
 
+#: builtin/config.c
 #, c-format
 msgid "wrong number of arguments, should be from %d to %d"
 msgstr "nombre d'arguments erroni, ha de ser %d a %d"
 
+#: builtin/config.c
 #, c-format
 msgid "invalid key pattern: %s"
 msgstr "patró de la clau no vàlid: %s"
 
+#: builtin/config.c config.c
 #, c-format
 msgid "invalid pattern: %s"
 msgstr "patró no vàlid: %s"
 
+#: builtin/config.c
 #, c-format
 msgid "failed to format default config value: %s"
 msgstr ""
 "s'ha produït un error en formatar el valor per defecte de la configuració: %s"
 
+#: builtin/config.c
 #, c-format
 msgid "cannot parse color '%s'"
 msgstr "no es pot analitzar el color «%s»"
 
+#: builtin/config.c
 msgid "unable to parse default color value"
 msgstr "no s'ha pogut analitzar el valor de color per defecte"
 
+#: builtin/config.c
 msgid "not in a git directory"
 msgstr "no és en un directori git"
 
+#: builtin/config.c
 msgid "writing to stdin is not supported"
 msgstr "no s'admet escriure a stdin"
 
+#: builtin/config.c
 msgid "writing config blobs is not supported"
 msgstr "no s'admet l'escriptura de blobs de configuració"
 
+#: builtin/config.c
 #, c-format
 msgid ""
 "# This is Git's per-user configuration file.\n"
@@ -5327,21 +6695,27 @@
 "#\tname = %s\n"
 "#\temail = %s\n"
 
+#: builtin/config.c
 msgid "only one config file at a time"
 msgstr "només un fitxer de configuració cada cop"
 
+#: builtin/config.c
 msgid "--local can only be used inside a git repository"
 msgstr "--local només es pot usar dins d'un repositori git"
 
+#: builtin/config.c
 msgid "--blob can only be used inside a git repository"
 msgstr "--blob només es pot usar dins d'un repositori git"
 
+#: builtin/config.c
 msgid "--worktree can only be used inside a git repository"
 msgstr "--worktree només es pot usar dins d'un repositori git"
 
+#: builtin/config.c builtin/gc.c
 msgid "$HOME not set"
 msgstr "$HOME no està establerta"
 
+#: builtin/config.c
 msgid ""
 "--worktree cannot be used with multiple working trees unless the config\n"
 "extension worktreeConfig is enabled. Please read \"CONFIGURATION FILE\"\n"
@@ -5351,44 +6725,102 @@
 "l'extensió de configuració worktreeConfig estigui habilitada. Llegiu la "
 "secció «CONFIGURATION FILE» a «git help worktree» per a més detalls"
 
-msgid "--get-color and variable type are incoherent"
-msgstr "--get-color i el tipus de variable són incoherents"
+#: builtin/config.c
+msgid "Other"
+msgstr "Altre"
 
-msgid "only one action at a time"
-msgstr "només una acció cada cop"
+#: builtin/config.c
+msgid "respect include directives on lookup"
+msgstr "respecta les directives d'inclusió en cercar"
 
-msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr "--name-only només és aplicable a --list o --get-regexp"
-
-msgid ""
-"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
-"list"
-msgstr ""
-"--show-origin només és aplicable a --get, --get-all, --get-regexp, i --list"
-
-msgid "--default is only applicable to --get"
-msgstr "--default només és aplicable a --get"
-
-msgid "--fixed-value only applies with 'value-pattern'"
-msgstr "--fixed-value només s'aplica amb «value-pattern»"
-
+#: builtin/config.c
 #, c-format
 msgid "unable to read config file '%s'"
 msgstr "no s'ha pogut llegir el fitxer de configuració «%s»"
 
+#: builtin/config.c
 msgid "error processing config file(s)"
 msgstr "s'ha produït un error en processar els fitxers de configuració"
 
-msgid "editing stdin is not supported"
-msgstr "no hi ha compatibilitat per a l'edició a stdin"
+#: builtin/config.c
+msgid "Filter options"
+msgstr "Opcions de filtre"
 
-msgid "editing blobs is not supported"
-msgstr "no hi ha compatibilitat per l'edició de blobs"
+# multi-valued → multivalor?
+#: builtin/config.c
+msgid "return all values for multi-valued config options"
+msgstr "retorna tots els valors per a les opcions de configuració multivalor"
 
-#, c-format
-msgid "cannot create configuration file %s"
-msgstr "no es pot crear el fitxer de configuració %s"
+#: builtin/config.c
+msgid "interpret the name as a regular expression"
+msgstr "interpreta el nom com una expressió regular"
 
+#: builtin/config.c
+msgid "show config with values matching the pattern"
+msgstr "mostra la configuració amb els valors coincidents amb el patró"
+
+#: builtin/config.c
+msgid "use string equality when comparing values to value pattern"
+msgstr ""
+"usa la igualtat de cadenes quan es comparen els valors amb el patró de valor"
+
+#: builtin/config.c
+msgid "URL"
+msgstr "URL"
+
+#: builtin/config.c
+msgid "show config matching the given URL"
+msgstr "mostra la configuració coincident amb l'URL indicat"
+
+#: builtin/config.c
+msgid "value"
+msgstr "valor"
+
+#: builtin/config.c
+msgid "use default value when missing entry"
+msgstr "utilitza el valor per defecte quan falti una entrada"
+
+#: builtin/config.c
+msgid "--fixed-value only applies with 'value-pattern'"
+msgstr "--fixed-value només s'aplica amb «value-pattern»"
+
+#: builtin/config.c
+msgid "--default= cannot be used with --all or --url="
+msgstr "--default= no es pot utilitzar amb --all o --url="
+
+#: builtin/config.c
+msgid "--url= cannot be used with --all, --regexp or --value"
+msgstr "--url= no es pot usar amb --all, --regexp o --value"
+
+#: builtin/config.c
+msgid "Filter"
+msgstr "Filtra"
+
+# multi-valued → multivalor?
+#: builtin/config.c
+msgid "replace multi-valued config option with new value"
+msgstr "reemplaça l'opció de configuració multivalor amb el valor nou"
+
+#: builtin/config.c
+msgid "human-readable comment string (# will be prepended as needed)"
+msgstr ""
+"cadena de comentari llegible per humans (es farà que comence per\n"
+"# si cal)"
+
+#: builtin/config.c
+msgid "add a new line without altering any existing values"
+msgstr "afegeix una línia nova sense alterar cap dels valors existents"
+
+# only applies → només funciona?
+#: builtin/config.c
+msgid "--fixed-value only applies with --value=<pattern>"
+msgstr "--fixed-value només s'aplica amb --value=<patró>"
+
+#: builtin/config.c
+msgid "--append cannot be used with --value=<pattern>"
+msgstr "no es pot utilitzar --append amb --value=<patró>"
+
+#: builtin/config.c
 #, c-format
 msgid ""
 "cannot overwrite multiple values with a single value\n"
@@ -5397,13 +6829,128 @@
 "no es poden sobreescriure múltiples valors amb un sol valor\n"
 "       Useu una expressió regular, --add o --replace-all per a canviar %s."
 
+#: builtin/config.c
 #, c-format
 msgid "no such section: %s"
 msgstr "no existeix la secció: %s"
 
+#: builtin/config.c
+msgid "editing stdin is not supported"
+msgstr "no hi ha compatibilitat per a l'edició a stdin"
+
+#: builtin/config.c
+msgid "editing blobs is not supported"
+msgstr "no hi ha compatibilitat per l'edició de blobs"
+
+#: builtin/config.c
+#, c-format
+msgid "cannot create configuration file %s"
+msgstr "no es pot crear el fitxer de configuració %s"
+
+#: builtin/config.c
+msgid "Action"
+msgstr "Acció"
+
+#: builtin/config.c
+msgid "get value: name [<value-pattern>]"
+msgstr "get value: nom [<patró-valors>]"
+
+#: builtin/config.c
+msgid "get all values: key [<value-pattern>]"
+msgstr "obté tots els valors: clau [<patró-valors>]"
+
+# he traduit el nom del paràmetre
+#: builtin/config.c
+msgid "get values for regexp: name-regex [<value-pattern>]"
+msgstr ""
+"obté els valors per a l'expressió regular: expressio-regular-nom [<patró-"
+"valors>]"
+
+#: builtin/config.c
+msgid "get value specific for the URL: section[.var] URL"
+msgstr "obtén el valor específic per a l'URL: secció[.variable] URL"
+
+# he traduït els noms dels paràmetres
+#: builtin/config.c
+msgid "replace all matching variables: name value [<value-pattern>]"
+msgstr ""
+"reemplaça totes les variables que coincideixin: nom valor [<patró-valors>]"
+
+#: builtin/config.c
+msgid "add a new variable: name value"
+msgstr "afegeix una variable nova: nom valor"
+
+# cal traduir name?
+#: builtin/config.c
+msgid "remove a variable: name [<value-pattern>]"
+msgstr "elimina una variable: nom [<patró-valors>]"
+
+#: builtin/config.c
+msgid "remove all matches: name [<value-pattern>]"
+msgstr "elimina totes les coincidències: nom [<patró-valors>]"
+
+#: builtin/config.c
+msgid "rename section: old-name new-name"
+msgstr "canvia el nom de secció: nom-antic nom-nou"
+
+#: builtin/config.c
+msgid "remove a section: name"
+msgstr "elimina una secció: nom"
+
+#: builtin/config.c
+msgid "list all"
+msgstr "llista'ls tots"
+
+#: builtin/config.c
+msgid "open an editor"
+msgstr "obre un editor"
+
+# slot → ??? ; <default> → ???
+#: builtin/config.c
+msgid "find the color configured: slot [<default>]"
+msgstr "troba el color configurat: slot [<default>]"
+
+#: builtin/config.c
+msgid "find the color setting: slot [<stdout-is-tty>]"
+msgstr "troba la configuració de color: slot [<stdout-is-tty>]"
+
+#: builtin/config.c
+msgid "with --get, use default value when missing entry"
+msgstr "amb --get utilitza el valor per defecte quan falti una entrada"
+
+#: builtin/config.c
+msgid "--get-color and variable type are incoherent"
+msgstr "--get-color i el tipus de variable són incoherents"
+
+#: builtin/config.c
+msgid "no action specified"
+msgstr "no s'ha especificat cap acció"
+
+#: builtin/config.c
+msgid "--name-only is only applicable to --list or --get-regexp"
+msgstr "--name-only només és aplicable a --list o --get-regexp"
+
+#: builtin/config.c
+msgid ""
+"--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
+"list"
+msgstr ""
+"--show-origin només és aplicable a --get, --get-all, --get-regexp, i --list"
+
+#: builtin/config.c
+msgid "--default is only applicable to --get"
+msgstr "--default només és aplicable a --get"
+
+# add/set/replace sense traduir, entenc
+#: builtin/config.c
+msgid "--comment is only applicable to add/set/replace operations"
+msgstr "--comment només es pot aplicar a operacions add/set/replace"
+
+#: builtin/count-objects.c
 msgid "print sizes in human readable format"
 msgstr "imprimeix les mides en un format llegible pels humans"
 
+#: builtin/credential-cache--daemon.c
 #, c-format
 msgid ""
 "The permissions on your socket directory are too loose; other\n"
@@ -5417,67 +6964,83 @@
 "\n"
 "\tchmod 0700 %s"
 
+#: builtin/credential-cache--daemon.c
 msgid "print debugging messages to stderr"
 msgstr "imprimeix els missatges de depuració a stderr"
 
+#: builtin/credential-cache--daemon.c
 msgid "credential-cache--daemon unavailable; no unix socket support"
 msgstr ""
 "credential-cache--daemon no disponible; no hi ha compatibilitat amb sòcols "
 "d'unix"
 
+#: builtin/credential-cache.c
 msgid "credential-cache unavailable; no unix socket support"
 msgstr ""
 "credencial-cache no disponible; no hi ha compatibilitat amb els sòcols d'unix"
 
+#: builtin/credential-store.c
 #, c-format
 msgid "unable to get credential storage lock in %d ms"
 msgstr ""
 "no s'ha pogut obtenir el bloqueig de l'emmagatzematge de credencials en %d ms"
 
+#: builtin/describe.c
 msgid ""
 "git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"
 msgstr ""
 "git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"
 
+#: builtin/describe.c
 msgid ""
 "git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"
 msgstr ""
 "git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"
 
+#: builtin/describe.c
 msgid "git describe <blob>"
 msgstr "git describe <blob>"
 
+#: builtin/describe.c
 msgid "head"
 msgstr "davant per"
 
+#: builtin/describe.c
 msgid "lightweight"
 msgstr "lleuger"
 
+#: builtin/describe.c
 msgid "annotated"
 msgstr "anotat"
 
+#: builtin/describe.c
 #, c-format
 msgid "annotated tag %s not available"
 msgstr "l'etiqueta anotada %s no és disponible"
 
+#: builtin/describe.c
 #, c-format
 msgid "tag '%s' is externally known as '%s'"
 msgstr "l'etiqueta «%s» es coneix externament com a «%s»"
 
+#: builtin/describe.c
 #, c-format
 msgid "no tag exactly matches '%s'"
 msgstr "cap etiqueta coincideix exactament amb «%s»"
 
+#: builtin/describe.c
 #, c-format
 msgid "No exact match on refs or tags, searching to describe\n"
 msgstr ""
 "No hi ha cap coincidència exacta en la cerca de referències o etiquetes per "
 "a descriure\n"
 
+#: builtin/describe.c
 #, c-format
 msgid "finished search at %s\n"
 msgstr "s'ha finalitzat la cerca a %s\n"
 
+#: builtin/describe.c
 #, c-format
 msgid ""
 "No annotated tags can describe '%s'.\n"
@@ -5486,6 +7049,7 @@
 "Cap etiqueta anotada pot descriure «%s».\n"
 "No obstant això, hi havia etiquetes no anotades: proveu --tags."
 
+#: builtin/describe.c
 #, c-format
 msgid ""
 "No tags can describe '%s'.\n"
@@ -5494,10 +7058,12 @@
 "Cap etiqueta pot descriure «%s».\n"
 "Proveu --always, o creeu algunes etiquetes."
 
+#: builtin/describe.c
 #, c-format
 msgid "traversed %lu commits\n"
 msgstr "%lu comissions recorregudes\n"
 
+#: builtin/describe.c
 #, c-format
 msgid ""
 "more than %i tags found; listed %i most recent\n"
@@ -5506,67 +7072,87 @@
 "s'han trobat més de %i etiquetes: s'han llistat les %i més recents\n"
 "s'ha renunciat la cerca a %s\n"
 
+#: builtin/describe.c
 #, c-format
 msgid "describe %s\n"
 msgstr "descriu %s\n"
 
+#: builtin/describe.c
 #, c-format
 msgid "Not a valid object name %s"
 msgstr "%s no és un nom d'objecte vàlid"
 
+#: builtin/describe.c
 #, c-format
 msgid "%s is neither a commit nor blob"
 msgstr "%s no és una comissió o un blob"
 
+#: builtin/describe.c
 msgid "find the tag that comes after the commit"
 msgstr "troba l'etiqueta que vingui després de la comissió"
 
+#: builtin/describe.c
 msgid "debug search strategy on stderr"
 msgstr "estratègia de cerca de depuració en stderr"
 
+#: builtin/describe.c
 msgid "use any ref"
 msgstr "usa qualsevol referència"
 
+#: builtin/describe.c
 msgid "use any tag, even unannotated"
 msgstr "usa qualsevol etiqueta, fins i tot aquelles sense anotar"
 
+#: builtin/describe.c
 msgid "always use long format"
 msgstr "sempre usa el format llarg"
 
+#: builtin/describe.c
 msgid "only follow first parent"
 msgstr "només segueix el primer pare"
 
+#: builtin/describe.c
 msgid "only output exact matches"
 msgstr "emet només coincidències exactes"
 
+#: builtin/describe.c
 msgid "consider <n> most recent tags (default: 10)"
 msgstr "considera les <n> etiquetes més recents (per defecte: 10)"
 
+#: builtin/describe.c
 msgid "only consider tags matching <pattern>"
 msgstr "només considera les etiquetes que coincideixen amb <patró>"
 
+#: builtin/describe.c
 msgid "do not consider tags matching <pattern>"
 msgstr "no consideris les etiquetes que no coincideixen amb <patró>"
 
+#: builtin/describe.c builtin/name-rev.c
 msgid "show abbreviated commit object as fallback"
 msgstr "mostra l'objecte de comissió abreviat com a sistema alternatiu"
 
+#: builtin/describe.c
 msgid "mark"
 msgstr "marca"
 
+#: builtin/describe.c
 msgid "append <mark> on dirty working tree (default: \"-dirty\")"
 msgstr "annexa <marca> en l'arbre de treball brut (per defecte: «-dirty»)"
 
+#: builtin/describe.c
 msgid "append <mark> on broken working tree (default: \"-broken\")"
 msgstr "annexa <marca> en l'arbre de treball brut (per defecte: «-broken»)"
 
+#: builtin/describe.c
 msgid "No names found, cannot describe anything."
 msgstr "No s'ha trobat cap nom, no es pot descriure res."
 
+#: builtin/describe.c
 #, c-format
 msgid "option '%s' and commit-ishes cannot be used together"
 msgstr "opció «%s» i les de comissió no es poden usar juntes"
 
+#: builtin/diagnose.c
 msgid ""
 "git diagnose [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
 "             [--mode=<mode>]"
@@ -5574,67 +7160,85 @@
 "git diagnose [(-o | --output-directory) <camí>] [(-s | --suffix) <format>]\n"
 "             [--mode=<mode>]"
 
+#: builtin/diagnose.c
 msgid "specify a destination for the diagnostics archive"
 msgstr "especifiqueu una destinació per a l'arxiu de diagnòstic"
 
+#: builtin/diagnose.c
 msgid "specify a strftime format suffix for the filename"
 msgstr "especifiqueu un sufix en format strftime per al nom de fitxer"
 
+#: builtin/diagnose.c
 msgid "specify the content of the diagnostic archive"
 msgstr "especifica el contingut de l'arxiu de diagnòstic"
 
+#: builtin/diff-tree.c
 msgid "--merge-base only works with two commits"
 msgstr "--merge-base només funciona amb dues comissions"
 
+#: builtin/diff.c
 #, c-format
 msgid "'%s': not a regular file or symlink"
 msgstr "«%s»: no és ni fitxer regular ni enllaç simbòlic"
 
+#: builtin/diff.c
 msgid "no merge given, only parents."
 msgstr "no s'ha donat cap fusió, només els pares."
 
+#: builtin/diff.c
 #, c-format
 msgid "invalid option: %s"
 msgstr "opció no vàlida: %s"
 
+#: builtin/diff.c
 #, c-format
 msgid "%s...%s: no merge base"
 msgstr "%s...%s: sense una base de fusió"
 
+#: builtin/diff.c
 msgid "Not a git repository"
 msgstr "No és un repositori de git"
 
+#: builtin/diff.c builtin/grep.c
 #, c-format
 msgid "invalid object '%s' given."
 msgstr "s'ha donat un objecte no vàlid «%s»."
 
+#: builtin/diff.c
 #, c-format
 msgid "more than two blobs given: '%s'"
 msgstr "s'ha donat més de dos blobs: «%s»"
 
+#: builtin/diff.c
 #, c-format
 msgid "unhandled object '%s' given."
 msgstr "s'ha donat l'objecte no gestionat «%s»."
 
+#: builtin/diff.c
 #, c-format
 msgid "%s...%s: multiple merge bases, using %s"
 msgstr "%s...%s: múltiples bases de fusió, utilitzant %s"
 
+#: builtin/difftool.c
 msgid "git difftool [<options>] [<commit> [<commit>]] [--] [<path>...]"
 msgstr "git difftool [<opcions>] [<comissió> [<comissió>]] [--] [<camí>...]"
 
+#: builtin/difftool.c
 #, c-format
 msgid "could not read symlink %s"
 msgstr "no s'ha pogut llegir l'enllaç simbòlic %s"
 
+#: builtin/difftool.c
 #, c-format
 msgid "could not read symlink file %s"
 msgstr "no s'ha pogut llegir el fitxer d'enllaç simbòlic %s"
 
+#: builtin/difftool.c
 #, c-format
 msgid "could not read object %s for symlink %s"
 msgstr "no es pot llegir l'objecte %s per l'enllaç simbòlic %s"
 
+#: builtin/difftool.c
 msgid ""
 "combined diff formats ('-c' and '--cc') are not supported in\n"
 "directory diff mode ('-d' and '--dir-diff')."
@@ -5642,50 +7246,64 @@
 "els formats de diff combinats («-c» i «--cc») no s'admeten\n"
 "en el mode diff de directoris («-d» i «--dir-diff»)."
 
+#: builtin/difftool.c
 #, c-format
 msgid "both files modified: '%s' and '%s'."
 msgstr "s'han modificat ambdós fitxers: «%s» i «%s»."
 
+#: builtin/difftool.c
 msgid "working tree file has been left."
 msgstr "s'ha deixat un fitxer de l'arbre de treball."
 
+#: builtin/difftool.c sequencer.c
 #, c-format
 msgid "could not copy '%s' to '%s'"
 msgstr "no s'ha pogut copiar «%s» a «%s»"
 
+#: builtin/difftool.c
 #, c-format
 msgid "temporary files exist in '%s'."
 msgstr "existeix un fitxer temporal a «%s»."
 
+#: builtin/difftool.c
 msgid "you may want to cleanup or recover these."
 msgstr "podeu netejar o recuperar-los."
 
+#: builtin/difftool.c
 #, c-format
 msgid "failed: %d"
 msgstr "ha fallat: %d"
 
+#: builtin/difftool.c
 msgid "use `diff.guitool` instead of `diff.tool`"
 msgstr "usa «diff.guitool» en lloc de «diff.tool»"
 
+#: builtin/difftool.c
 msgid "perform a full-directory diff"
 msgstr "fes un diff de tot el directori"
 
+#: builtin/difftool.c
 msgid "do not prompt before launching a diff tool"
 msgstr "no preguntis abans d'executar l'eina diff"
 
+#: builtin/difftool.c
 msgid "use symlinks in dir-diff mode"
 msgstr "utilitza enllaços simbòlics en mode dir-diff"
 
+#: builtin/difftool.c
 msgid "tool"
 msgstr "eina"
 
+#: builtin/difftool.c
 msgid "use the specified diff tool"
 msgstr "utilitza l'eina de diff especificada"
 
+#: builtin/difftool.c
 msgid "print a list of diff tools that may be used with `--tool`"
 msgstr ""
 "imprimeix una llista de totes les eines diff que podeu usar amb «--tool»"
 
+#: builtin/difftool.c
 msgid ""
 "make 'git-difftool' exit when an invoked diff tool returns a non-zero exit "
 "code"
@@ -5693,187 +7311,241 @@
 "fes que «git-difftool» surti quan l'eina de diff invocada torna un codi de "
 "sortida diferent de zero"
 
+#: builtin/difftool.c
 msgid "specify a custom command for viewing diffs"
 msgstr "especifiqueu una ordre personalitzada per a veure diffs"
 
+#: builtin/difftool.c
 msgid "passed to `diff`"
 msgstr "passa-ho a «diff»"
 
+#: builtin/difftool.c
 msgid "difftool requires worktree or --no-index"
 msgstr "difftool requereix worktree o --no-index"
 
+#: builtin/difftool.c
 msgid "no <tool> given for --tool=<tool>"
 msgstr "no s'ha proporcionat l'<eina> per a --tool=<eina>"
 
+#: builtin/difftool.c
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "no s'ha proporcionat l'<ordre> per a --extcmd=<ordre>"
 
+#: builtin/fast-export.c
 msgid "git fast-export [<rev-list-opts>]"
 msgstr "git fast-export [<rev-list-opts>]"
 
+#: builtin/fast-export.c
 msgid "Error: Cannot export nested tags unless --mark-tags is specified."
 msgstr ""
 "Error: no es poden exportar les etiquetes imbricades a menys que "
 "s'especifiqui --mark-tags."
 
+#: builtin/fast-export.c
 msgid "--anonymize-map token cannot be empty"
 msgstr "el testimoni de --anonymize-map no pot estar buit"
 
+#: builtin/fast-export.c
 msgid "show progress after <n> objects"
 msgstr "mostra el progrés després de <n> objectes"
 
+#: builtin/fast-export.c
 msgid "select handling of signed tags"
 msgstr "selecciona la gestió de les etiquetes signades"
 
+#: builtin/fast-export.c
 msgid "select handling of tags that tag filtered objects"
 msgstr "selecciona la gestió de les etiquetes que etiquetin objectes filtrats"
 
+#: builtin/fast-export.c
 msgid "select handling of commit messages in an alternate encoding"
 msgstr ""
 "selecciona la gestió dels missatges de comissió en una codificació "
 "alternativa"
 
+#: builtin/fast-export.c
 msgid "dump marks to this file"
 msgstr "bolca les marques a aquest fitxer"
 
+#: builtin/fast-export.c
 msgid "import marks from this file"
 msgstr "importa les marques d'aquest fitxer"
 
+#: builtin/fast-export.c
 msgid "import marks from this file if it exists"
 msgstr "importa marques d'aquest fitxer si existeix"
 
+#: builtin/fast-export.c
 msgid "fake a tagger when tags lack one"
 msgstr "fingeix un etiquetador quan en falti un a les etiquetes"
 
+#: builtin/fast-export.c
 msgid "output full tree for each commit"
 msgstr "imprimeix l'arbre complet de per a cada comissió"
 
+#: builtin/fast-export.c
 msgid "use the done feature to terminate the stream"
 msgstr "usa la característica fet per a acabar el flux"
 
+#: builtin/fast-export.c
 msgid "skip output of blob data"
 msgstr "omet la sortida de dades de blob"
 
+#: builtin/fast-export.c builtin/log.c
 msgid "refspec"
 msgstr "especificació de referència"
 
+#: builtin/fast-export.c
 msgid "apply refspec to exported refs"
 msgstr "aplica l'especificació de referència a les referències exportades"
 
+#: builtin/fast-export.c
 msgid "anonymize output"
 msgstr "anonimitza la sortida"
 
+#: builtin/fast-export.c
 msgid "from:to"
 msgstr "des de:a"
 
+#: builtin/fast-export.c
 msgid "convert <from> to <to> in anonymized output"
 msgstr "converteix <from> a <to> en una sortida anònima"
 
+#: builtin/fast-export.c
 msgid "reference parents which are not in fast-export stream by object id"
 msgstr ""
 "referència els pares que no estan en flux d'exportació ràpida per "
 "identificador d'objecte"
 
+#: builtin/fast-export.c
 msgid "show original object ids of blobs/commits"
 msgstr "mostra els ID dels objectes originals dels blobs i comissions"
 
+#: builtin/fast-export.c
 msgid "label tags with mark ids"
 msgstr "marca les etiquetes amb els identificadors de marca"
 
+#: builtin/fast-import.c
 #, c-format
 msgid "Missing from marks for submodule '%s'"
 msgstr "Falten les marques «from» per al submòdul «%s»"
 
+#: builtin/fast-import.c
 #, c-format
 msgid "Missing to marks for submodule '%s'"
 msgstr "Falten les marques per al submòdul «%s»"
 
+#: builtin/fast-import.c
 #, c-format
 msgid "Expected 'mark' command, got %s"
 msgstr "S'esperava l'ordre «mark», s'ha rebut %s"
 
+#: builtin/fast-import.c
 #, c-format
 msgid "Expected 'to' command, got %s"
 msgstr "S'esperava l'ordre «to», s'ha rebut «%s»"
 
+#: builtin/fast-import.c
 msgid "Expected format name:filename for submodule rewrite option"
 msgstr ""
 "S'esperava el format «nom:nom de fitxer» per a l'opció de reescriptura de "
 "submòdul"
 
+#: builtin/fast-import.c
 #, c-format
 msgid "feature '%s' forbidden in input without --allow-unsafe-features"
 msgstr ""
 "característica «%s» prohibida a l'entrada sense --allow-unsafe-features"
 
+#: builtin/fetch-pack.c
 #, c-format
 msgid "Lockfile created but not reported: %s"
 msgstr "S'ha creat el fitxer de bloqueig però no s'ha informat: %s"
 
+#: builtin/fetch.c
 msgid "git fetch [<options>] [<repository> [<refspec>...]]"
-msgstr ""
-"git fetch [<opcions>] [<repositori> [<especificació-de-referència>...]]"
+msgstr "git fetch [<opcions>] [<repositori> [<especificació-referència>...]]"
 
+#: builtin/fetch.c
 msgid "git fetch [<options>] <group>"
 msgstr "git fetch [<opcions>] <grup>"
 
+#: builtin/fetch.c
 msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
 msgstr "git fetch --multiple [<opcions>] [(<repositori> | <grup>)...]"
 
+#: builtin/fetch.c
 msgid "git fetch --all [<options>]"
 msgstr "git fetch --all [<opcions>]"
 
+#: builtin/fetch.c
 msgid "fetch.parallel cannot be negative"
 msgstr "fetch.parallel no pot ser negatiu"
 
+#: builtin/fetch.c
 msgid "couldn't find remote ref HEAD"
 msgstr "no s'ha pogut trobar la referència HEAD remota"
 
+#: builtin/fetch.c
 #, c-format
 msgid "From %.*s\n"
 msgstr "De %.*s\n"
 
+#: builtin/fetch.c
 #, c-format
 msgid "object %s not found"
 msgstr "objecte %s no trobat"
 
+#: builtin/fetch.c
 msgid "[up to date]"
 msgstr "[al dia]"
 
+#: builtin/fetch.c
 msgid "[rejected]"
 msgstr "[rebutjat]"
 
+#: builtin/fetch.c
 msgid "can't fetch into checked-out branch"
 msgstr "no es pot obtenir en la branca actual"
 
+#: builtin/fetch.c
 msgid "[tag update]"
 msgstr "[actualització d'etiqueta]"
 
+#: builtin/fetch.c
 msgid "unable to update local ref"
 msgstr "no s'ha pogut actualitzar la referència local"
 
+#: builtin/fetch.c
 msgid "would clobber existing tag"
 msgstr "s'adjuntaria l'etiqueta existent"
 
+#: builtin/fetch.c
 msgid "[new tag]"
 msgstr "[etiqueta nova]"
 
+#: builtin/fetch.c
 msgid "[new branch]"
 msgstr "[branca nova]"
 
+#: builtin/fetch.c
 msgid "[new ref]"
 msgstr "[referència nova]"
 
+#: builtin/fetch.c
 msgid "forced update"
 msgstr "actualització forçada"
 
+#: builtin/fetch.c
 msgid "non-fast-forward"
 msgstr "sense avanç ràpid"
 
+#: builtin/fetch.c builtin/grep.c sequencer.c
 #, c-format
 msgid "cannot open '%s'"
 msgstr "no es pot obrir «%s»"
 
+#: builtin/fetch.c
 msgid ""
 "fetch normally indicates which branches had a forced update,\n"
 "but that check has been disabled; to re-enable, use '--show-forced-updates'\n"
@@ -5885,6 +7557,7 @@
 "utilitzeu\n"
 "«--show-forced-updates» o executeu «git config fetch.showForcedUpdates true»"
 
+#: builtin/fetch.c
 #, c-format
 msgid ""
 "it took %.2f seconds to check forced updates; you can use\n"
@@ -5896,15 +7569,18 @@
 "utilitzar «--no-show-forced-updates» o executar «git config \n"
 "fetch.showForcedUpdates false» per a evitar aquesta comprovació.\n"
 
+#: builtin/fetch.c
 #, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s no ha enviat tots els objectes necessaris\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s no ha enviat tot els objectes necessaris"
 
+#: builtin/fetch.c
 #, c-format
 msgid "rejected %s because shallow roots are not allowed to be updated"
 msgstr ""
 "s'ha rebutjat %s perquè no es permeten actualitzar les arrels superficials"
 
+#: builtin/fetch.c
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
@@ -5914,43 +7590,54 @@
 " intenteu executar «git remote prune %s» per a eliminar\n"
 " qualsevol branca antiga o conflictiva"
 
+#: builtin/fetch.c
 #, c-format
 msgid "   (%s will become dangling)"
-msgstr "   (%s es tornarà penjant)"
+msgstr "   (%s es tornarà despenjat)"
 
+#: builtin/fetch.c
 #, c-format
 msgid "   (%s has become dangling)"
-msgstr "   (%s s'ha tornat penjant)"
+msgstr "   (%s s'ha quedat despenjat)"
 
+#: builtin/fetch.c
 msgid "[deleted]"
 msgstr "[suprimit]"
 
+#: builtin/fetch.c builtin/remote.c
 msgid "(none)"
 msgstr "(cap)"
 
+#: builtin/fetch.c
 #, c-format
 msgid "refusing to fetch into branch '%s' checked out at '%s'"
 msgstr "s'ha rebutjat l'obtenció en la branca «%s» agafada a «%s»"
 
+#: builtin/fetch.c
 #, c-format
 msgid "option \"%s\" value \"%s\" is not valid for %s"
 msgstr "l'opció «%s» amb valor «%s» no és vàlida per a %s"
 
+#: builtin/fetch.c
 #, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "s'ignora l'opció «%s» per a %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "l'opció «%s» s'ignora per a «%s»"
 
+#: builtin/fetch.c object-file.c
 #, c-format
 msgid "%s is not a valid object"
 msgstr "%s no és un objecte vàlid"
 
+#: builtin/fetch.c
 #, c-format
 msgid "the object %s does not exist"
 msgstr "l'objecte %s no existeix"
 
+#: builtin/fetch.c
 msgid "multiple branches detected, incompatible with --set-upstream"
 msgstr "s'han detectat múltiples branques, incompatible amb --set-upstream"
 
+#: builtin/fetch.c
 #, c-format
 msgid ""
 "could not set upstream of HEAD to '%s' from '%s' when it does not point to "
@@ -5959,16 +7646,20 @@
 "no s'ha pogut establir la font de HEAD a «%s» des de «%s» quan no assenyala "
 "cap branca."
 
+#: builtin/fetch.c
 msgid "not setting upstream for a remote remote-tracking branch"
 msgstr ""
 "no s'està configurant la font per a una branca remota amb seguiment remot"
 
+#: builtin/fetch.c
 msgid "not setting upstream for a remote tag"
 msgstr "no s'està configurant la font d'una etiqueta remota"
 
+#: builtin/fetch.c
 msgid "unknown branch type"
 msgstr "tipus de branca desconegut"
 
+#: builtin/fetch.c
 msgid ""
 "no source branch found;\n"
 "you need to specify exactly one branch with the --set-upstream option"
@@ -5976,18 +7667,22 @@
 "no s'ha trobat cap branca d'origen.\n"
 "heu d'especificar exactament una branca amb l'opció --set-upstream"
 
+#: builtin/fetch.c
 #, c-format
 msgid "Fetching %s\n"
 msgstr "S'està obtenint %s\n"
 
+#: builtin/fetch.c
 #, c-format
 msgid "could not fetch %s"
 msgstr "no s'ha pogut obtenir %s"
 
+#: builtin/fetch.c
 #, c-format
 msgid "could not fetch '%s' (exit code: %d)\n"
 msgstr "no s'ha pogut obtenir «%s» (codi de sortida: %d)\n"
 
+#: builtin/fetch.c
 msgid ""
 "no remote repository specified; please specify either a URL or a\n"
 "remote name from which new revisions should be fetched"
@@ -5995,82 +7690,107 @@
 "no s'ha especificat cap repositori remot. Especifiqueu un URL o\n"
 "un nom remot del qual s'han d'obtenir les revisions noves"
 
+#: builtin/fetch.c
 msgid "you need to specify a tag name"
 msgstr "necessiteu especificar un nom d'etiqueta"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "fetch from all remotes"
 msgstr "obtén de tots els remots"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "set upstream for git pull/fetch"
 msgstr "estableix la font per a git pull/fetch"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "append to .git/FETCH_HEAD instead of overwriting"
 msgstr "annexa a .git/FETCH_HEAD en lloc de sobreescriure'l"
 
+#: builtin/fetch.c
 msgid "use atomic transaction to update references"
 msgstr "usa una transacció atòmica per a actualitzar les referències"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "path to upload pack on remote end"
 msgstr "camí al qual pujar el paquet al costat remot"
 
+#: builtin/fetch.c
 msgid "force overwrite of local reference"
 msgstr "força la sobreescriptura de la referència local"
 
+#: builtin/fetch.c
 msgid "fetch from multiple remotes"
 msgstr "obtén de múltiples remots"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "fetch all tags and associated objects"
 msgstr "obtén totes les etiquetes i tots els objectes associats"
 
+#: builtin/fetch.c
 msgid "do not fetch all tags (--no-tags)"
 msgstr "no obtinguis les etiquetes (--no-tags)"
 
+#: builtin/fetch.c
 msgid "number of submodules fetched in parallel"
 msgstr "nombre de submòduls obtinguts en paral·lel"
 
+#: builtin/fetch.c
 msgid "modify the refspec to place all refs within refs/prefetch/"
 msgstr ""
 "modifica l'especificació de referència per a col·locar totes les referències "
 "dins de refs/prefetch/"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "prune remote-tracking branches no longer on remote"
 msgstr "poda les branques amb seguiment remot que ja no estiguin en el remot"
 
+#: builtin/fetch.c
 msgid "prune local tags no longer on remote and clobber changed tags"
 msgstr ""
 "poda les etiquetes locals que ja no existeixen al remot i adjunta les "
 "etiquetes que han canviat"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "on-demand"
 msgstr "sota demanda"
 
+#: builtin/fetch.c
 msgid "control recursive fetching of submodules"
 msgstr "controla l'obtenció recursiva de submòduls"
 
+#: builtin/fetch.c
 msgid "write fetched references to the FETCH_HEAD file"
 msgstr "escriu les referències obtingudes al fitxer FETCH_HEAD"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "keep downloaded pack"
 msgstr "retén el paquet baixat"
 
+#: builtin/fetch.c
 msgid "allow updating of HEAD ref"
 msgstr "permet l'actualització de la referència HEAD"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "deepen history of shallow clone"
 msgstr "aprofundeix la història d'un clon superficial"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "deepen history of shallow repository based on time"
 msgstr "aprofundeix la història d'un clon superficial basat en una data"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "convert to a complete repository"
 msgstr "converteix en un repositori complet"
 
+#: builtin/fetch.c
 msgid "re-fetch without negotiating common commits"
 msgstr "tornar a obtenir sense negociar comissions comunes"
 
+#: builtin/fetch.c
 msgid "prepend this to submodule path output"
 msgstr "anteposa això a la sortida de camí del submòdul"
 
+#: builtin/fetch.c
 msgid ""
 "default for recursive fetching of submodules (lower priority than config "
 "files)"
@@ -6078,68 +7798,88 @@
 "per defecte per a l'obtenció recursiva de submòduls (prioritat més baixa que "
 "els fitxers de configuració)"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "accept refs that update .git/shallow"
 msgstr "accepta les referències que actualitzin .git/shallow"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "refmap"
 msgstr "mapa de referències"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "specify fetch refmap"
 msgstr "específica l'obtenció del mapa de referències"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "report that we have only objects reachable from this object"
 msgstr "informa que només hi ha objectes abastables des d'aquest objecte"
 
+#: builtin/fetch.c
 msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
 msgstr ""
 "no obtinguis un fitxer de paquet; en canvi, mostra els avantpassats dels "
 "consells de negociació"
 
+#: builtin/fetch.c
 msgid "run 'maintenance --auto' after fetching"
 msgstr "executa «maintenance --auto» després d'obtenir"
 
+#: builtin/fetch.c builtin/pull.c
 msgid "check for forced-updates on all updated branches"
 msgstr ""
 "comprova si hi ha actualitzacions forçades a totes les branques actualitzades"
 
+#: builtin/fetch.c
 msgid "write the commit-graph after fetching"
 msgstr "escriu el graf de comissions després de recollir"
 
+#: builtin/fetch.c
 msgid "accept refspecs from stdin"
 msgstr "llegeix les especificacions de referència des de stdin"
 
+#: builtin/fetch.c
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
 msgstr "--negotiate-only necessita un o més --negotiation-tip=*"
 
+#: builtin/fetch.c
 msgid "negative depth in --deepen is not supported"
 msgstr "no s'admet una profunditat negativa en --deepen"
 
+#: builtin/fetch.c
 msgid "--unshallow on a complete repository does not make sense"
 msgstr "--unshallow en un repositori complet no té sentit"
 
+#: builtin/fetch.c
 #, c-format
 msgid "failed to fetch bundles from '%s'"
 msgstr "no s'han pogut obtenir els paquets de «%s»"
 
+#: builtin/fetch.c
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all no accepta un argument de repositori"
 
+#: builtin/fetch.c
 msgid "fetch --all does not make sense with refspecs"
 msgstr "fetch --all no té sentit amb especificacions de referència"
 
+#: builtin/fetch.c
 #, c-format
 msgid "no such remote or remote group: %s"
 msgstr "no existeix un remot ni un grup remot: %s"
 
+#: builtin/fetch.c
 msgid "fetching a group and specifying refspecs does not make sense"
 msgstr "obtenir un grup i especificar referències no té sentit"
 
+#: builtin/fetch.c
 msgid "must supply remote when using --negotiate-only"
 msgstr "s'ha de subministrar el remot en usar --negotiate-only"
 
+#: builtin/fetch.c
 msgid "protocol does not support --negotiate-only, exiting"
 msgstr "el protocol no admet --negotiate-only, se surt"
 
+#: builtin/fetch.c
 msgid ""
 "--filter can only be used with the remote configured in extensions."
 "partialclone"
@@ -6147,125 +7887,170 @@
 "--filter només es pot utilitzar amb el remot configurat en extensions."
 "partialclone"
 
+#: builtin/fetch.c
 msgid "--atomic can only be used when fetching from one remote"
 msgstr "l'opció --atomic només es pot usar quan s'obté des d'un remot"
 
+#: builtin/fetch.c
 msgid "--stdin can only be used when fetching from one remote"
 msgstr "l'opció --stdin només es pot usar quan s'obté des d'un remot"
 
+#: builtin/fmt-merge-msg.c
 msgid ""
 "git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"
 msgstr ""
 "git fmt-merge-msg [-m <missatge>] [--log[=<n>] | --no-log] [--file <fitxer>]"
 
+#: builtin/fmt-merge-msg.c
 msgid "populate log with at most <n> entries from shortlog"
 msgstr "emplena el registre amb <n> entrades del registre curt com a màxim"
 
+#: builtin/fmt-merge-msg.c
 msgid "alias for --log (deprecated)"
 msgstr "àlies per a --log (en desús)"
 
+#: builtin/fmt-merge-msg.c
 msgid "text"
 msgstr "text"
 
+#: builtin/fmt-merge-msg.c
 msgid "use <text> as start of message"
 msgstr "usa <text> com a inici de missatge"
 
+#: builtin/fmt-merge-msg.c
 msgid "use <name> instead of the real target branch"
 msgstr "usa <nom> en lloc de la branca de destí real"
 
+#: builtin/fmt-merge-msg.c
 msgid "file to read from"
 msgstr "fitxer del qual llegir"
 
+#: builtin/for-each-ref.c
 msgid "git for-each-ref [<options>] [<pattern>]"
 msgstr "git for-each-ref [<opcions>] [<patró>]"
 
+#: builtin/for-each-ref.c
 msgid "git for-each-ref [--points-at <object>]"
 msgstr "git for-each-ref [--points-at <objecte>]"
 
+#: builtin/for-each-ref.c
 msgid "git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"
 msgstr "git for-each-ref [--merged [<comissió>]] [--no-merged [<comissió>]]"
 
+#: builtin/for-each-ref.c
 msgid "git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"
 msgstr ""
 "git for-each-ref [--contains [<comissió>]] [--no-contains [<comissió>]]"
 
+#: builtin/for-each-ref.c
 msgid "quote placeholders suitably for shells"
 msgstr ""
 "posa els marcadors de posició entre cometes adequades per a intèrprets "
 "d'ordres"
 
+#: builtin/for-each-ref.c
 msgid "quote placeholders suitably for perl"
 msgstr "posa els marcadors de posició entre cometes adequades per al perl"
 
+#: builtin/for-each-ref.c
 msgid "quote placeholders suitably for python"
 msgstr "posa els marcadors de posició entre cometes adequades per al python"
 
+#: builtin/for-each-ref.c
 msgid "quote placeholders suitably for Tcl"
 msgstr "posa els marcadors de posició entre cometes adequades per al Tcl"
 
+#: builtin/for-each-ref.c
 msgid "show only <n> matched refs"
 msgstr "mostra només <n> referències coincidents"
 
+#: builtin/for-each-ref.c builtin/tag.c
 msgid "respect format colors"
 msgstr "respecta els colors del format"
 
+#: builtin/for-each-ref.c
 msgid "print only refs which points at the given object"
 msgstr "imprimeix només les referències que assenyalin l'objecte donat"
 
+#: builtin/for-each-ref.c
 msgid "print only refs that are merged"
 msgstr "imprimeix només les referències que s'han fusionat"
 
+#: builtin/for-each-ref.c
 msgid "print only refs that are not merged"
 msgstr "imprimeix només les referències que no s'han fusionat"
 
+#: builtin/for-each-ref.c
 msgid "print only refs which contain the commit"
 msgstr "imprimeix només les referències que continguin la comissió"
 
+#: builtin/for-each-ref.c
 msgid "print only refs which don't contain the commit"
 msgstr "imprimeix només les referències que no continguin la comissió"
 
+#: builtin/for-each-ref.c
 msgid "read reference patterns from stdin"
 msgstr "llegeix els patrons de referència de l'entrada estàndard"
 
+#: builtin/for-each-ref.c
+msgid "also include HEAD ref and pseudorefs"
+msgstr "inclou també la referència HEAD i les pseudoreferències"
+
+#: builtin/for-each-ref.c
 msgid "unknown arguments supplied with --stdin"
 msgstr "s'han proporcionat arguments desconeguts amb --stdin"
 
+#: builtin/for-each-repo.c
 msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr "git for-each-repo --config=<config> [--] <arguments>"
 
+#: builtin/for-each-repo.c
 msgid "config"
 msgstr "config"
 
+#: builtin/for-each-repo.c
 msgid "config key storing a list of repository paths"
 msgstr "clau de configuració emmagatzemant una llista de camins de repositori"
 
+#: builtin/for-each-repo.c
+msgid "keep going even if command fails in a repository"
+msgstr "continua fins i tot si l'ordre falla en un repositori"
+
+#: builtin/for-each-repo.c
 msgid "missing --config=<config>"
 msgstr "falta --config=<config>"
 
+#: builtin/for-each-repo.c
 #, c-format
 msgid "got bad config --config=%s"
 msgstr "s'ha obtingut una configuració incorrecta --config=%s"
 
+#: builtin/fsck.c
 msgid "unknown"
 msgstr "desconegut"
 
 #. TRANSLATORS: e.g. error in tree 01bfda: <more explanation>
+#: builtin/fsck.c
 #, c-format
 msgid "error in %s %s: %s"
 msgstr "error en %s %s: %s"
 
 #. TRANSLATORS: e.g. warning in tree 01bfda: <more explanation>
+#: builtin/fsck.c
 #, c-format
 msgid "warning in %s %s: %s"
 msgstr "avís en %s %s: %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "broken link from %7s %s"
 msgstr "enllaç trencat de %7s %s"
 
+#: builtin/fsck.c
 msgid "wrong object type in link"
 msgstr "tipus d'objecte incorrecte en l'enllaç"
 
+#: builtin/fsck.c
 #, c-format
 msgid ""
 "broken link from %7s %s\n"
@@ -6274,147 +8059,186 @@
 "enllaç trencat des de %7s %s\n"
 "               fins a %7s %s"
 
+#: builtin/fsck.c builtin/prune.c connected.c
 msgid "Checking connectivity"
 msgstr "S'està comprovant la connectivitat"
 
+#: builtin/fsck.c
 #, c-format
 msgid "missing %s %s"
 msgstr "%s %s manca"
 
+#: builtin/fsck.c
 #, c-format
 msgid "unreachable %s %s"
 msgstr "%s %s inabastable"
 
+#: builtin/fsck.c
 #, c-format
 msgid "dangling %s %s"
 msgstr "%s %s sense assignació"
 
+#: builtin/fsck.c
 msgid "could not create lost-found"
 msgstr "no s'ha pogut crear el trobat-perdut"
 
+#: builtin/fsck.c builtin/gc.c builtin/rebase.c rebase-interactive.c rerere.c
+#: sequencer.c
 #, c-format
 msgid "could not write '%s'"
 msgstr "no s'ha pogut escriure «%s»"
 
+#: builtin/fsck.c
 #, c-format
 msgid "could not finish '%s'"
 msgstr "no s'ha pogut finalitzar «%s»"
 
+#: builtin/fsck.c
 #, c-format
 msgid "Checking %s"
 msgstr "S'està comprovant %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "Checking connectivity (%d objects)"
 msgstr "S'està comprovant la connectivitat (%d objectes)"
 
+#: builtin/fsck.c
 #, c-format
 msgid "Checking %s %s"
 msgstr "S'està comprovant %s %s"
 
+#: builtin/fsck.c
 msgid "broken links"
 msgstr "enllaços trencats"
 
+#: builtin/fsck.c
 #, c-format
 msgid "root %s"
 msgstr "arrel %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "tagged %s %s (%s) in %s"
 msgstr "marcat %s %s (%s) a %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: object corrupt or missing"
 msgstr "%s: objecte corrupte o no trobat"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: invalid reflog entry %s"
-msgstr "%s: entrada de referència no vàlida %s"
+msgstr "%s: entrada de registre de referències no vàlida %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "Checking reflog %s->%s"
-msgstr "S'està comprovant reflog %s->%s"
+msgstr "S'està comprovant el registre de referències %s->%s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: invalid sha1 pointer %s"
 msgstr "%s: punter %s sha1 no vàlid"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: not a commit"
 msgstr "%s: no és una comissió"
 
+#: builtin/fsck.c
 msgid "notice: No default references"
 msgstr "avís: no hi ha referències per defecte"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: hash-path mismatch, found at: %s"
 msgstr "%s: el resum del camí no coincideix, trobat a: %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: object corrupt or missing: %s"
 msgstr "%s: objecte corrupte o no trobat: %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: object is of unknown type '%s': %s"
 msgstr "%s: l'objecte és de tipus desconegut «%s»: %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: object could not be parsed: %s"
 msgstr "%s: no s'ha pogut analitzar l'objecte: %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "bad sha1 file: %s"
 msgstr "fitxer sha1 malmès: %s"
 
+#: builtin/fsck.c
 msgid "Checking object directory"
 msgstr "S'està comprovant el directori d'objecte"
 
+#: builtin/fsck.c
 msgid "Checking object directories"
 msgstr "S'estan comprovant els directoris d'objecte"
 
+#: builtin/fsck.c
 #, c-format
 msgid "Checking %s link"
 msgstr "S'està comprovant l'enllaç %s"
 
+#: builtin/fsck.c builtin/index-pack.c
 #, c-format
 msgid "invalid %s"
 msgstr "%s no vàlid"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s points to something strange (%s)"
 msgstr "%s apunta a una cosa estranya (%s)"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: detached HEAD points at nothing"
 msgstr "%s: la HEAD separada no apunta a res"
 
+#: builtin/fsck.c
 #, c-format
 msgid "notice: %s points to an unborn branch (%s)"
 msgstr "avís: %s apunta a una branca no nascuda (%s)"
 
+#: builtin/fsck.c
 #, c-format
 msgid "Checking cache tree of %s"
 msgstr "S'està comprovant l'arbre de la memòria cau %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: invalid sha1 pointer in cache-tree of %s"
 msgstr "%s: punter sha1 no vàlid a l'arbre de la memòria cau %s"
 
+#: builtin/fsck.c
 msgid "non-tree in cache-tree"
 msgstr "un no arbre en l'arbre de la memòria cau"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: invalid sha1 pointer in resolve-undo of %s"
 msgstr "%s: punter sha1 no vàlid a «resolve-undo» de %s"
 
+#: builtin/fsck.c
 #, c-format
 msgid "unable to load rev-index for pack '%s'"
 msgstr "no s'ha pogut carregar l'índex de reversió per al paquet «%s»"
 
+#: builtin/fsck.c
 #, c-format
 msgid "invalid rev-index for pack '%s'"
 msgstr "rev-index no vàlid per al paquet «%s»"
 
+#: builtin/fsck.c
 msgid ""
 "git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
 "         [--[no-]full] [--strict] [--verbose] [--lost-found]\n"
@@ -6426,159 +8250,205 @@
 "         [--[no-]dangling] [--[no-]progress] [--connectivity-only]\n"
 "         [--[no-]name-objects] [<objecte>...]"
 
+#: builtin/fsck.c
 msgid "show unreachable objects"
 msgstr "mostra els objectes inabastables"
 
+#: builtin/fsck.c
 msgid "show dangling objects"
-msgstr "mostra els objectes penjants"
+msgstr "mostra els objectes despenjats"
 
+#: builtin/fsck.c
 msgid "report tags"
 msgstr "informa de les etiquetes"
 
+#: builtin/fsck.c
 msgid "report root nodes"
 msgstr "informa dels nodes d'arrel"
 
+#: builtin/fsck.c
 msgid "make index objects head nodes"
-msgstr "fes dels objectes d'índex nodes cap"
+msgstr "fes dels objectes d'índex nodes HEAD"
 
+#: builtin/fsck.c
 msgid "make reflogs head nodes (default)"
-msgstr "fes que els registres de referències siguin nodes cap (per defecte)"
+msgstr "fes que els registres de referències siguin nodes HEAD (per defecte)"
 
+#: builtin/fsck.c
 msgid "also consider packs and alternate objects"
 msgstr "també considera els paquets i els objectes alternatius"
 
+#: builtin/fsck.c
 msgid "check only connectivity"
 msgstr "comprova només la connectivitat"
 
+#: builtin/fsck.c builtin/mktag.c
 msgid "enable more strict checking"
 msgstr "habilita la comprovació més estricta"
 
+#: builtin/fsck.c
 msgid "write dangling objects in .git/lost-found"
-msgstr "escriu objectes penjants a .git/lost-found"
+msgstr "escriu objectes despenjats a .git/lost-found"
 
+#: builtin/fsck.c builtin/prune.c
 msgid "show progress"
 msgstr "mostra el progrés"
 
+#: builtin/fsck.c
 msgid "show verbose names for reachable objects"
 msgstr "mostra els noms detallats dels objectes abastables"
 
+#: builtin/fsck.c builtin/index-pack.c
 msgid "Checking objects"
 msgstr "S'estan comprovant els objectes"
 
+#: builtin/fsck.c
 #, c-format
 msgid "%s: object missing"
 msgstr "%s: falta l'objecte"
 
+#: builtin/fsck.c
 #, c-format
 msgid "invalid parameter: expected sha1, got '%s'"
 msgstr "paràmetre no vàlid: s'esperava sha1, s'ha obtingut «%s»"
 
+#: builtin/fsmonitor--daemon.c
 msgid "git fsmonitor--daemon start [<options>]"
 msgstr "git fsmonitor--daemon start [<opcions>]"
 
+#: builtin/fsmonitor--daemon.c
 msgid "git fsmonitor--daemon run [<options>]"
 msgstr "git fsmonitor--daemon run [<opcions>]"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "value of '%s' out of range: %d"
 msgstr "el valor de «%s» està fora de rang: %d"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "value of '%s' not bool or int: %d"
 msgstr "valor de «%s» no és booleà ni enter: %d"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "fsmonitor-daemon is watching '%s'\n"
 msgstr "fsmonitor-daemon està veient «%s»\n"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "fsmonitor-daemon is not watching '%s'\n"
 msgstr "fsmonitor-daemon no està vigilant «%s»\n"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "could not create fsmonitor cookie '%s'"
 msgstr "no s'ha pogut crear la galeta fsmonitor «%s»"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "fsmonitor: cookie_result '%d' != SEEN"
 msgstr "fsmonitor: cookie_result «%d» != SEEN"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "could not start IPC thread pool on '%s'"
 msgstr "no s'ha pogut iniciar el grup de fils IPC a «%s»"
 
+#: builtin/fsmonitor--daemon.c
 msgid "could not start fsmonitor listener thread"
 msgstr "no s'ha pogut iniciar el fil receptor del fsmonitor"
 
+#: builtin/fsmonitor--daemon.c
 msgid "could not start fsmonitor health thread"
 msgstr "no s'ha pogut iniciar el fil de salut del fsmonitor"
 
+#: builtin/fsmonitor--daemon.c
 msgid "could not initialize listener thread"
 msgstr "no s'ha pogut inicialitzar el fil receptor"
 
+#: builtin/fsmonitor--daemon.c
 msgid "could not initialize health thread"
 msgstr "no s'ha pogut inicialitzar el fil de salut"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "could not cd home '%s'"
 msgstr "no s'ha pogut fer cd home «%s»"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "fsmonitor--daemon is already running '%s'"
 msgstr "fsmonitor--daemon is already running «%s»"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "running fsmonitor-daemon in '%s'\n"
 msgstr "s'està executant fsmonitor-daemon en «%s»\n"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "starting fsmonitor-daemon in '%s'\n"
 msgstr "s'està iniciant fsmonitor-daemon a «%s»\n"
 
+#: builtin/fsmonitor--daemon.c
 msgid "daemon failed to start"
 msgstr "el dimoni ha fallat en iniciar"
 
+#: builtin/fsmonitor--daemon.c
 msgid "daemon not online yet"
 msgstr "el dimoni encara no està en línia"
 
+#: builtin/fsmonitor--daemon.c
 msgid "daemon terminated"
 msgstr "s'ha finalitzat el dimoni"
 
+#: builtin/fsmonitor--daemon.c
 msgid "detach from console"
 msgstr "separat de la consola"
 
+#: builtin/fsmonitor--daemon.c
 msgid "use <n> ipc worker threads"
 msgstr "usa <n> fils de treball ipc"
 
+#: builtin/fsmonitor--daemon.c
 msgid "max seconds to wait for background daemon startup"
 msgstr "màxim de segons a esperar a l'inici del dimoni en segon pla"
 
+#: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "invalid 'ipc-threads' value (%d)"
 msgstr "valor «ipc-threads» no vàlid (%d)"
 
+#: builtin/fsmonitor--daemon.c t/helper/test-cache-tree.c
 #, c-format
 msgid "Unhandled subcommand '%s'"
 msgstr "Subordre no gestionada «%s»"
 
+#: builtin/fsmonitor--daemon.c
 msgid "fsmonitor--daemon not supported on this platform"
 msgstr "fsmonitor--daemon no és compatible amb aquesta plataforma"
 
+#: builtin/gc.c
 msgid "git gc [<options>]"
 msgstr "git gc [<opcions>]"
 
+#: builtin/gc.c
 #, c-format
 msgid "Failed to fstat %s: %s"
 msgstr "S'ha produït un error en fer fstat %s: %s"
 
+#: builtin/gc.c
 #, c-format
 msgid "failed to parse '%s' value '%s'"
 msgstr "no s'ha pogut analitzar «%s» valor «%s»"
 
+#: builtin/gc.c setup.c
 #, c-format
 msgid "cannot stat '%s'"
 msgstr "no es pot fer stat en «%s»"
 
+#: builtin/gc.c
 #, c-format
 msgid ""
 "The last gc run reported the following. Please correct the root cause\n"
@@ -6593,246 +8463,322 @@
 "\n"
 "%s"
 
+#: builtin/gc.c
 msgid "prune unreferenced objects"
 msgstr "poda objectes sense referència"
 
+#: builtin/gc.c
 msgid "pack unreferenced objects separately"
 msgstr "empaqueta els objectes no referenciats de forma separada"
 
+#: builtin/gc.c builtin/repack.c
 msgid "with --cruft, limit the size of new cruft packs"
 msgstr "amb --cruft, limiteu la mida dels paquets cruft nous"
 
+#: builtin/gc.c
 msgid "be more thorough (increased runtime)"
 msgstr "sigues més exhaustiu (el temps d'execució augmenta)"
 
+#: builtin/gc.c
 msgid "enable auto-gc mode"
 msgstr "habilita el mode de recollida d'escombraries automàtica"
 
+#: builtin/gc.c
+msgid "perform garbage collection in the background"
+msgstr "fes la recollida de memòria brossa en segon pla"
+
+#: builtin/gc.c
 msgid "force running gc even if there may be another gc running"
 msgstr ""
 "força l'execució de gc encara que hi pugui haver un altre gc executant-se"
 
+#: builtin/gc.c
 msgid "repack all other packs except the largest pack"
 msgstr "reempaqueta tots els altres paquets excepte el paquet més gran"
 
+#: builtin/gc.c
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
 msgstr "no s'ha pogut analitzar el valor %s de gc.logExpiry"
 
+#: builtin/gc.c
 #, c-format
 msgid "failed to parse prune expiry value %s"
 msgstr "no s'ha pogut analitzar el valor de venciment de la poda %s"
 
+#: builtin/gc.c
 #, c-format
 msgid "Auto packing the repository in background for optimum performance.\n"
 msgstr ""
 "S'està empaquetant el repositori automàticament en el rerefons per a un "
 "rendiment òptim.\n"
 
+#: builtin/gc.c
 #, c-format
 msgid "Auto packing the repository for optimum performance.\n"
 msgstr ""
 "S'està empaquetant automàticament el repositori per a un rendiment òptim.\n"
 
+#: builtin/gc.c
 #, c-format
 msgid "See \"git help gc\" for manual housekeeping.\n"
 msgstr "Vegeu «git help gc» per a neteja manual.\n"
 
+#: builtin/gc.c
 #, c-format
 msgid ""
 "gc is already running on machine '%s' pid %<PRIuMAX> (use --force if not)"
 msgstr ""
 "gc ja s'està executant en la màquina «%s» pid %<PRIuMAX> (useu --force si no)"
 
+#: builtin/gc.c
 msgid ""
 "There are too many unreachable loose objects; run 'git prune' to remove them."
 msgstr ""
 "Hi ha massa objectes solts inabastables; executeu «git prune» per a eliminar-"
 "los."
 
+#: builtin/gc.c
 msgid ""
 "git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"
 msgstr ""
 "git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"
 
+#: builtin/gc.c
 msgid "--no-schedule is not allowed"
 msgstr "--no-schedule no està permès"
 
+#: builtin/gc.c
 #, c-format
 msgid "unrecognized --schedule argument '%s'"
 msgstr "argument --schedule no reconegut, «%s»"
 
+#: builtin/gc.c
 msgid "failed to write commit-graph"
 msgstr "s'ha produït un error en escriure el graf de comissions"
 
+#: builtin/gc.c
 msgid "failed to prefetch remotes"
 msgstr "s'ha produït un error en preobtenir els remots"
 
+#: builtin/gc.c
 msgid "failed to start 'git pack-objects' process"
 msgstr "no s'ha pogut iniciar el procés «git pack-objects»"
 
+#: builtin/gc.c
 msgid "failed to finish 'git pack-objects' process"
 msgstr "no s'ha pogut finalitzar el procés «git pack-objects»"
 
+#: builtin/gc.c
 msgid "failed to write multi-pack-index"
 msgstr "no s'ha pogut escriure l'índex del multipaquet"
 
+#: builtin/gc.c
 msgid "'git multi-pack-index expire' failed"
 msgstr "ha fallat el venciment de «git multi-pack-index expire»"
 
+#: builtin/gc.c
 msgid "'git multi-pack-index repack' failed"
 msgstr "ha fallat l'execució de «git multi-pack-index repack»"
 
+#: builtin/gc.c
 msgid ""
 "skipping incremental-repack task because core.multiPackIndex is disabled"
 msgstr ""
 "s'està ometent la tasca incremental-repack perquè core.multiPackIndex està "
 "desactivat"
 
+#: builtin/gc.c
 #, c-format
 msgid "lock file '%s' exists, skipping maintenance"
 msgstr "el fitxer de bloqueig «%s» existeix, s'omet el manteniment"
 
+#: builtin/gc.c
 #, c-format
 msgid "task '%s' failed"
 msgstr "la tasca «%s» ha fallat"
 
+#: builtin/gc.c
 #, c-format
 msgid "'%s' is not a valid task"
 msgstr "«%s» no és una tasca vàlida"
 
+#: builtin/gc.c
 #, c-format
 msgid "task '%s' cannot be selected multiple times"
 msgstr "la tasca «%s» no es pot seleccionar múltiples vegades"
 
+#: builtin/gc.c
 msgid "run tasks based on the state of the repository"
 msgstr "executa les tasques basades en l'estat del repositori"
 
+#: builtin/gc.c
+msgid "perform maintenance in the background"
+msgstr "fes el manteniment en segon pla"
+
+#: builtin/gc.c
 msgid "frequency"
 msgstr "freqüència"
 
+#: builtin/gc.c
 msgid "run tasks based on frequency"
 msgstr "executa les tasques basant-se en freqüència"
 
+#: builtin/gc.c
 msgid "do not report progress or other information over stderr"
-msgstr "no informeu sobre el progrés o altra informació as stderr"
+msgstr "no informeu sobre el progrés o altra informació a stderr"
 
+#: builtin/gc.c
 msgid "task"
 msgstr "tasca"
 
+#: builtin/gc.c
 msgid "run a specific task"
 msgstr "executa una tasca específica"
 
+#: builtin/gc.c
 msgid "use at most one of --auto and --schedule=<frequency>"
-msgstr "usa com a màxim un entre --auto i --schedule=<frequency>"
+msgstr "usa com a màxim un entre --auto i --schedule=<freqüència>"
 
+#: builtin/gc.c
 #, c-format
 msgid "unable to add '%s' value of '%s'"
 msgstr "no es pot afegir el valor «%s» de «%s»"
 
+#: builtin/gc.c
 msgid "return success even if repository was not registered"
 msgstr "retorna èxit encara que el repositori no estigui registrat"
 
+#: builtin/gc.c
 #, c-format
 msgid "unable to unset '%s' value of '%s'"
 msgstr "no es pot desassignar el valor «%s» de «%s»"
 
+#: builtin/gc.c
 #, c-format
 msgid "repository '%s' is not registered"
 msgstr "el repositori «%s» no està registrat"
 
+#: builtin/gc.c
 #, c-format
 msgid "failed to expand path '%s'"
 msgstr "s'ha produït un error en expandir el camí «%s»"
 
+#: builtin/gc.c
 msgid "failed to start launchctl"
 msgstr "s'ha produït un error en iniciar launchctl"
 
+#: builtin/gc.c
 #, c-format
 msgid "failed to create directories for '%s'"
 msgstr "s'ha produït un error en crear els directoris per a «%s»"
 
+#: builtin/gc.c
 #, c-format
 msgid "failed to bootstrap service %s"
 msgstr "s'ha produït un error en arrencar el servei %s"
 
+#: builtin/gc.c
 msgid "failed to create temp xml file"
 msgstr "no s'han pogut crear un fitxer xml temporal"
 
+#: builtin/gc.c
 msgid "failed to start schtasks"
 msgstr "s'ha produït un error en iniciar schtasks"
 
+#: builtin/gc.c
 msgid "failed to run 'crontab -l'; your system might not support 'cron'"
 msgstr ""
 "no s'ha pogut executar «crontab -l»; el vostre sistema podria no admetre "
 "«cron»"
 
+#: builtin/gc.c
 msgid "failed to create crontab temporary file"
 msgstr "no s'ha pogut crear un fitxer temporal crontab"
 
+#: builtin/gc.c
 msgid "failed to open temporary file"
 msgstr "no s'ha pogut obrir el fitxer temporal"
 
+#: builtin/gc.c
 msgid "failed to run 'crontab'; your system might not support 'cron'"
 msgstr ""
 "no s'ha pogut executar «crontab»; el vostre sistema podria no admetre «cron»"
 
+#: builtin/gc.c
 msgid "'crontab' died"
 msgstr "«crontab» ha mort"
 
+#: builtin/gc.c builtin/worktree.c
 #, c-format
 msgid "failed to delete '%s'"
 msgstr "s'ha produït un error en suprimir «%s»"
 
+#: builtin/gc.c rerere.c
 #, c-format
 msgid "failed to flush '%s'"
 msgstr "no s'ha pogut buidar «%s»"
 
+#: builtin/gc.c
 msgid "failed to start systemctl"
 msgstr "s'ha produït un error en iniciar systemctl"
 
+#: builtin/gc.c
 msgid "failed to run systemctl"
 msgstr "s'ha produït un error en executar systemctl"
 
+#: builtin/gc.c
 #, c-format
 msgid "unrecognized --scheduler argument '%s'"
 msgstr "l'argument --scheduler no reconegut «%s»"
 
+#: builtin/gc.c
 msgid "neither systemd timers nor crontab are available"
 msgstr "ni els temporitzadors de systemd ni de crontab estan disponibles"
 
+#: builtin/gc.c
 #, c-format
 msgid "%s scheduler is not available"
 msgstr "el planificador %s no està disponible"
 
+#: builtin/gc.c
 msgid "another process is scheduling background maintenance"
 msgstr "un altre procés està planificant un manteniment en segon pla"
 
+#: builtin/gc.c
 msgid "git maintenance start [--scheduler=<scheduler>]"
 msgstr "git maintenance start [--scheduler=<scheduler>]"
 
+#: builtin/gc.c
 msgid "scheduler"
 msgstr "planificador"
 
+#: builtin/gc.c
 msgid "scheduler to trigger git maintenance run"
 msgstr "planificador per a activar l'execució de manteniment del git"
 
+#: builtin/gc.c
 msgid "failed to set up maintenance schedule"
 msgstr "no s'ha pogut configurar la planificació del manteniment"
 
+#: builtin/gc.c
 msgid "failed to add repo to global config"
 msgstr "no s'ha pogut afegir un repositori a la configuració global"
 
+#: builtin/gc.c
 msgid "git maintenance <subcommand> [<options>]"
-msgstr "git maintenance <subcommand> [<opcions>]"
+msgstr "git maintenance <subordre> [<opcions>]"
 
+#: builtin/grep.c
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<opcions>] [-e] <patró> [<revisió>...] [[--] <camí>...]"
 
+#: builtin/grep.c
 #, c-format
 msgid "grep: failed to create thread: %s"
 msgstr "grep: s'ha produït un error en crear fil: %s"
 
+#: builtin/grep.c
 #, c-format
 msgid "invalid number of threads specified (%d) for %s"
 msgstr "s'ha especificat un nombre de fils no vàlid (%d) per a %s"
@@ -6842,203 +8788,261 @@
 #. variable for tweaking threads, currently
 #. grep.threads
 #.
+#: builtin/grep.c builtin/index-pack.c builtin/pack-objects.c
 #, c-format
 msgid "no threads support, ignoring %s"
 msgstr "no s'admeten fils, s'ignorarà %s"
 
-#, c-format
-msgid "unable to read tree (%s)"
-msgstr "no s'ha pogut llegir l'arbre (%s)"
-
+#: builtin/grep.c
 #, c-format
 msgid "unable to read tree %s"
 msgstr "no s'ha pogut llegir l'arbre %s"
 
+#: builtin/grep.c
 #, c-format
 msgid "unable to grep from object of type %s"
 msgstr "no es pot fer grep des d'un objecte de tipus %s"
 
+#: builtin/grep.c
 #, c-format
 msgid "switch `%c' expects a numerical value"
 msgstr "l'opció «%c» espera un valor numèric"
 
+#: builtin/grep.c
 msgid "search in index instead of in the work tree"
 msgstr "cerca en l'índex en lloc de l'arbre de treball"
 
+#: builtin/grep.c
 msgid "find in contents not managed by git"
 msgstr "cerca en continguts no gestionats per git"
 
+#: builtin/grep.c
 msgid "search in both tracked and untracked files"
 msgstr "cerca tant en fitxers seguits com en no seguits"
 
+#: builtin/grep.c
 msgid "ignore files specified via '.gitignore'"
 msgstr "ignora els fitxers especificats mitjançant «.gitignore»"
 
+#: builtin/grep.c
 msgid "recursively search in each submodule"
 msgstr "cerca recursivament a cada submòdul"
 
+#: builtin/grep.c
 msgid "show non-matching lines"
 msgstr "mostra les línies no coincidents"
 
+#: builtin/grep.c
 msgid "case insensitive matching"
 msgstr "coincidència no distingeix entre majúscules i minúscules"
 
+#: builtin/grep.c
 msgid "match patterns only at word boundaries"
 msgstr "coincideix amb els patrons només als límits de paraula"
 
+#: builtin/grep.c
 msgid "process binary files as text"
 msgstr "processa els fitxers binaris com a text"
 
+#: builtin/grep.c
 msgid "don't match patterns in binary files"
 msgstr "no cerquis els patrons en els fitxers binaris"
 
+#: builtin/grep.c
 msgid "process binary files with textconv filters"
 msgstr "processa els fitxers binaris amb filtres de textconv"
 
+#: builtin/grep.c
 msgid "search in subdirectories (default)"
 msgstr "cerca als subdirectoris (per defecte)"
 
+#: builtin/grep.c
 msgid "descend at most <n> levels"
 msgstr "descendeix com a màxim <n> nivells"
 
+#: builtin/grep.c
 msgid "use extended POSIX regular expressions"
 msgstr "usa les expressions regulars POSIX ampliades"
 
+#: builtin/grep.c
 msgid "use basic POSIX regular expressions (default)"
 msgstr "usa les expressions regulars POSIX bàsiques (per defecte)"
 
+#: builtin/grep.c
 msgid "interpret patterns as fixed strings"
 msgstr "interpreta els patrons com a cadenes fixes"
 
+#: builtin/grep.c
 msgid "use Perl-compatible regular expressions"
 msgstr "usa les expressions regulars compatibles amb Perl"
 
+#: builtin/grep.c
 msgid "show line numbers"
 msgstr "mostra els números de línia"
 
+#: builtin/grep.c
 msgid "show column number of first match"
 msgstr "mostra el nombre de columna de la primera coincidència"
 
+#: builtin/grep.c
 msgid "don't show filenames"
 msgstr "no mostris els noms de fitxer"
 
+#: builtin/grep.c
 msgid "show filenames"
 msgstr "mostra els noms de fitxer"
 
+#: builtin/grep.c
 msgid "show filenames relative to top directory"
 msgstr "mostra els noms de fitxer relatius al directori superior"
 
+#: builtin/grep.c
 msgid "show only filenames instead of matching lines"
 msgstr "mostra només els noms de fitxer en lloc de les línies coincidents"
 
+#: builtin/grep.c
 msgid "synonym for --files-with-matches"
 msgstr "sinònim de --files-with-matches"
 
+#: builtin/grep.c
 msgid "show only the names of files without match"
 msgstr "mostra només els noms dels fitxers sense coincidència"
 
+#: builtin/grep.c
 msgid "print NUL after filenames"
 msgstr "imprimeix NUL després dels noms de fitxer"
 
+#: builtin/grep.c
 msgid "show only matching parts of a line"
 msgstr "mostra només les parts de coincidents de la línia"
 
+#: builtin/grep.c
 msgid "show the number of matches instead of matching lines"
 msgstr "mostra el nombre de coincidències en lloc de les línies coincidents"
 
+#: builtin/grep.c
 msgid "highlight matches"
 msgstr "ressalta les coincidències"
 
+#: builtin/grep.c
 msgid "print empty line between matches from different files"
 msgstr "imprimeix una línia buida entre coincidències de fitxers distints"
 
+#: builtin/grep.c
 msgid "show filename only once above matches from same file"
 msgstr ""
 "mostra el nom de fitxer només una vegada a dalt de les coincidències del "
 "mateix fitxer"
 
+#: builtin/grep.c
 msgid "show <n> context lines before and after matches"
 msgstr "mostra <n> línies de context abans i després d'una coincidència"
 
+#: builtin/grep.c
 msgid "show <n> context lines before matches"
 msgstr "mostra <n> línies de context abans d'una coincidència"
 
+#: builtin/grep.c
 msgid "show <n> context lines after matches"
 msgstr "mostra <n> línies de context després d'una coincidència"
 
+#: builtin/grep.c
 msgid "use <n> worker threads"
 msgstr "usa <n> fils de treball"
 
+#: builtin/grep.c
 msgid "shortcut for -C NUM"
 msgstr "drecera per a -C NUM"
 
+#: builtin/grep.c
 msgid "show a line with the function name before matches"
 msgstr "mostra una línia amb el nom de funció abans de les coincidències"
 
+#: builtin/grep.c
 msgid "show the surrounding function"
 msgstr "mostra la funció circumdant"
 
+#: builtin/grep.c
 msgid "read patterns from file"
 msgstr "llegeix els patrons des d'un fitxer"
 
+#: builtin/grep.c
 msgid "match <pattern>"
 msgstr "coincideix amb <patró>"
 
+#: builtin/grep.c
 msgid "combine patterns specified with -e"
 msgstr "combina els patrons especificats amb -e"
 
+#: builtin/grep.c
 msgid "indicate hit with exit status without output"
 msgstr "indica coincidència amb estat de sortida sense sortida textual"
 
+#: builtin/grep.c
 msgid "show only matches from files that match all patterns"
 msgstr ""
 "mostra només les coincidències dels fitxers que coincideixin amb tots els "
 "patrons"
 
+#: builtin/grep.c
 msgid "pager"
 msgstr "paginador"
 
+#: builtin/grep.c
 msgid "show matching files in the pager"
 msgstr "mostra els fitxers coincidents en el paginador"
 
+#: builtin/grep.c
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "permet la invocació de grep(1) (ignorat per aquesta compilació)"
 
+#: builtin/grep.c
 msgid "maximum number of results per file"
 msgstr "nombre màxim de resultats per fitxer"
 
+#: builtin/grep.c
 msgid "no pattern given"
 msgstr "no s'ha donat cap patró"
 
+#: builtin/grep.c
 msgid "--no-index or --untracked cannot be used with revs"
 msgstr "--no-index o --untracked no es pot usar amb revisions"
 
+#: builtin/grep.c
 #, c-format
 msgid "unable to resolve revision: %s"
 msgstr "no s'ha pogut resoldre la revisió: %s"
 
+#: builtin/grep.c
 msgid "--untracked not supported with --recurse-submodules"
 msgstr "--untracked no s'admet amb --recurse-submodules"
 
+#: builtin/grep.c
 msgid "invalid option combination, ignoring --threads"
 msgstr "combinació d'opcions no vàlida, s'està ignorant --threads"
 
+#: builtin/grep.c builtin/pack-objects.c
 msgid "no threads support, ignoring --threads"
 msgstr "no s'admeten fils, s'ignorarà --threads"
 
+#: builtin/grep.c builtin/index-pack.c builtin/pack-objects.c
 #, c-format
 msgid "invalid number of threads specified (%d)"
 msgstr "s'ha especificat un nombre de fils no vàlid (%d)"
 
+#: builtin/grep.c
 msgid "--open-files-in-pager only works on the worktree"
 msgstr "--open-files-in-pager només funciona en l'arbre de treball"
 
+#: builtin/grep.c
 msgid "--[no-]exclude-standard cannot be used for tracked contents"
 msgstr "--[no-]exclude-standard no es pot utilitzar per als continguts seguits"
 
+#: builtin/grep.c
 msgid "both --cached and trees are given"
 msgstr "ambdós --cached i arbres venen donats"
 
+#: builtin/hash-object.c
 msgid ""
 "git hash-object [-t <type>] [-w] [--path=<file> | --no-filters]\n"
 "                [--stdin [--literally]] [--] <file>..."
@@ -7046,91 +9050,117 @@
 "git hash-object [-t <tipus>] [-w] [--path=<fitxer> | --no-filters]\n"
 "                [--stdin [--literally]] [--] <fitxer>..."
 
+#: builtin/hash-object.c
 msgid "git hash-object [-t <type>] [-w] --stdin-paths [--no-filters]"
 msgstr "git hash-object [-t <tipus>] [-w] --stdin-paths [--no-filters]"
 
+#: builtin/hash-object.c
 msgid "object type"
 msgstr "tipus d'objecte"
 
+#: builtin/hash-object.c
 msgid "write the object into the object database"
 msgstr "escriu l'objecte a la base de dades d'objectes"
 
+#: builtin/hash-object.c
 msgid "read the object from stdin"
 msgstr "llegeix l'objecte des de stdin"
 
+#: builtin/hash-object.c
 msgid "store file as is without filters"
 msgstr "emmagatzema el fitxer tal com és sense filtres"
 
+#: builtin/hash-object.c
 msgid ""
 "just hash any random garbage to create corrupt objects for debugging Git"
 msgstr ""
 "només suma qualsevol brossa aleatòria per a crear objectes malmesos per a "
 "depurar al Git"
 
+#: builtin/hash-object.c
 msgid "process file as it were from this path"
 msgstr "processa el fitxer com si fos d'aquest camí"
 
+#: builtin/help.c
 msgid "print all available commands"
 msgstr "imprimeix totes les ordres disponibles"
 
+#: builtin/help.c
 msgid "show external commands in --all"
 msgstr "mostra les ordres externes a --all"
 
+#: builtin/help.c
 msgid "show aliases in --all"
 msgstr "mostra els àlies a --all"
 
+#: builtin/help.c
 msgid "exclude guides"
 msgstr "exclou guies"
 
+#: builtin/help.c
 msgid "show man page"
 msgstr "mostra la pàgina de manual"
 
+#: builtin/help.c
 msgid "show manual in web browser"
 msgstr "mostra la pàgina de manual en el navegador web"
 
+#: builtin/help.c
 msgid "show info page"
 msgstr "mostra la pàgina d'informació"
 
+#: builtin/help.c
 msgid "print command description"
 msgstr "imprimeix la descripció de l'ordre"
 
+#: builtin/help.c
 msgid "print list of useful guides"
 msgstr "imprimeix la llista de guies útils"
 
+#: builtin/help.c
 msgid "print list of user-facing repository, command and file interfaces"
 msgstr ""
 "imprimeix la llista de repositoris, ordres i interfícies de fitxers que veu "
 "l'usuari"
 
+#: builtin/help.c
 msgid "print list of file formats, protocols and other developer interfaces"
 msgstr ""
 "mostra la llista de formats de fitxer, protocols i altres interfícies de "
 "desenvolupador"
 
+#: builtin/help.c
 msgid "print all configuration variable names"
 msgstr "imprimeix tots els noms de les variables de configuració"
 
+#: builtin/help.c
 msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<ordre>|<doc>]"
 
+#: builtin/help.c
 #, c-format
 msgid "unrecognized help format '%s'"
 msgstr "format d'ajuda no reconegut «%s»"
 
+#: builtin/help.c
 msgid "Failed to start emacsclient."
 msgstr "S'ha produït un error en iniciar emacsclient."
 
+#: builtin/help.c
 msgid "Failed to parse emacsclient version."
 msgstr "S'ha produït un error en analitzar la versió d'emacsclient."
 
+#: builtin/help.c
 #, c-format
 msgid "emacsclient version '%d' too old (< 22)."
 msgstr "la versió d'emacsclient «%d» és massa vella (< 22)."
 
+#: builtin/help.c
 #, c-format
 msgid "failed to exec '%s'"
 msgstr "s'ha produït un error en executar «%s»"
 
+#: builtin/help.c
 #, c-format
 msgid ""
 "'%s': path for unsupported man viewer.\n"
@@ -7139,6 +9169,7 @@
 "«%s»: camí a un visualitzador de manuals no compatible.\n"
 "Considereu usar «man.<eina>.cmd» en lloc d'això."
 
+#: builtin/help.c
 #, c-format
 msgid ""
 "'%s': cmd for supported man viewer.\n"
@@ -7147,41 +9178,51 @@
 "«%s»: ordre per a un visualitzador de manuals compatible.\n"
 "Considereu usar «man.<eina>.path» en lloc d'això."
 
+#: builtin/help.c
 #, c-format
 msgid "'%s': unknown man viewer."
 msgstr "«%s»: visualitzador de manuals desconegut."
 
+#: builtin/help.c
 msgid "no man viewer handled the request"
 msgstr "cap visualitzador de manuals ha gestionat la sol·licitud"
 
+#: builtin/help.c
 msgid "no info viewer handled the request"
 msgstr "cap visualitzador d'informació ha gestionat la sol·licitud"
 
+#: builtin/help.c git.c
 #, c-format
 msgid "'%s' is aliased to '%s'"
 msgstr "«%s» és un àlies de «%s»"
 
+#: builtin/help.c git.c
 #, c-format
 msgid "bad alias.%s string: %s"
 msgstr "cadena «alias.%s» incorrecte: %s"
 
+#: builtin/help.c
 #, c-format
 msgid "the '%s' option doesn't take any non-option arguments"
 msgstr "l'opció «%s» no pren cap argument que no sigui una opció"
 
+#: builtin/help.c
 msgid ""
 "the '--no-[external-commands|aliases]' options can only be used with '--all'"
 msgstr ""
 "les opcions «--no-[external-commands|aliases]» només es poden utilitzar amb "
 "«--all»"
 
+#: builtin/help.c
 #, c-format
 msgid "usage: %s%s"
 msgstr "ús: %s%s"
 
+#: builtin/help.c
 msgid "'git help config' for more information"
 msgstr "«git help config» per a més informació"
 
+#: builtin/hook.c
 msgid ""
 "git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
 "args>]"
@@ -7189,75 +9230,95 @@
 "git hook run [--ignore-missing] [--to-stdin=<camí>] <hook-name> [-- <hook-"
 "args>]"
 
+#: builtin/hook.c
 msgid "silently ignore missing requested <hook-name>"
 msgstr "ignora silenciosament la sol·licitud <hook-name> perduda"
 
+#: builtin/hook.c
 msgid "file to read into hooks' stdin"
 msgstr "fitxer per a llegir a l'entrada estàndard dels lligams"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "hi ha una discordança de tipus d'objecte a %s"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "did not receive expected object %s"
 msgstr "no s'ha rebut l'objecte esperat %s"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "object %s: expected type %s, found %s"
 msgstr "objecte %s: s'esperava el tipus %s, s'ha trobat %s"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "cannot fill %d byte"
 msgid_plural "cannot fill %d bytes"
 msgstr[0] "no es pot omplir %d octet"
 msgstr[1] "no es poden omplir %d octets"
 
+#: builtin/index-pack.c
 msgid "early EOF"
 msgstr "EOF prematur"
 
+#: builtin/index-pack.c
 msgid "read error on input"
 msgstr "error de lectura d'entrada"
 
+#: builtin/index-pack.c
 msgid "used more bytes than were available"
 msgstr "s'han usat més octets que hi havia disponibles"
 
+#: builtin/index-pack.c builtin/pack-objects.c
 msgid "pack too large for current definition of off_t"
 msgstr "paquet massa gran per a la definició actual d'off_t"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "pack exceeds maximum allowed size (%s)"
 msgstr "el paquet supera la mida màxima permesa (%s)"
 
+#: builtin/index-pack.c
 msgid "pack signature mismatch"
 msgstr "hi ha una discordança de signatura de paquet"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "pack version %<PRIu32> unsupported"
 msgstr "la versió de paquet %<PRIu32> no és compatible"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "pack has bad object at offset %<PRIuMAX>: %s"
 msgstr "el paquet té un objecte incorrecte a la posició %<PRIuMAX>: %s"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "inflate returned %d"
 msgstr "la inflació ha retornat %d"
 
+#: builtin/index-pack.c
 msgid "offset value overflow for delta base object"
 msgstr ""
 "desbordament de valor de desplaçament per a l'objecte base de diferències"
 
+#: builtin/index-pack.c
 msgid "delta base offset is out of bound"
 msgstr "el desplaçament de base de diferències està fora de límits"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "unknown object type %d"
 msgstr "tipus d'objecte desconegut %d"
 
+#: builtin/index-pack.c
 msgid "cannot pread pack file"
 msgstr "no es pot fer pread en el fitxer empaquetat"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "premature end of pack file, %<PRIuMAX> byte missing"
 msgid_plural "premature end of pack file, %<PRIuMAX> bytes missing"
@@ -7265,150 +9326,189 @@
 msgstr[1] ""
 "el final del fitxer empaquetat és prematur, manquen %<PRIuMAX> octets"
 
+#: builtin/index-pack.c
 msgid "serious inflate inconsistency"
 msgstr "hi ha una inconsistència seriosa d'inflació"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "SHA1 COLLISION FOUND WITH %s !"
 msgstr "S'HA TROBAT UNA COL·LISIÓ SHA1 AMB %s !"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "cannot read existing object info %s"
 msgstr "no es pot llegir la informació d'objecte existent %s"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "cannot read existing object %s"
 msgstr "no es pot llegir l'objecte existent %s"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "invalid blob object %s"
 msgstr "objecte de blob no vàlid %s"
 
+#: builtin/index-pack.c
 msgid "fsck error in packed object"
 msgstr "fsck error en un objecte empaquetat"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "Not all child objects of %s are reachable"
 msgstr "No tots els objectes fills de %s són abastables"
 
+#: builtin/index-pack.c
 msgid "failed to apply delta"
 msgstr "s'ha produït un error en aplicar la diferència"
 
+#: builtin/index-pack.c
 msgid "Receiving objects"
 msgstr "S'estan rebent objectes"
 
+#: builtin/index-pack.c
 msgid "Indexing objects"
 msgstr "S'estan indexant objectes"
 
+#: builtin/index-pack.c
 msgid "pack is corrupted (SHA1 mismatch)"
 msgstr "el paquet és malmès (discordança SHA1)"
 
+#: builtin/index-pack.c
 msgid "cannot fstat packfile"
 msgstr "no es pot fer fstat en el fitxer de paquet"
 
+#: builtin/index-pack.c
 msgid "pack has junk at the end"
 msgstr "el paquet té brossa al seu final"
 
+#: builtin/index-pack.c
 msgid "confusion beyond insanity in parse_pack_objects()"
 msgstr "confusió més enllà de la bogeria en parse_pack_objects()"
 
+#: builtin/index-pack.c
 msgid "Resolving deltas"
 msgstr "S'estan resolent les diferències"
 
+#: builtin/index-pack.c builtin/pack-objects.c
 #, c-format
 msgid "unable to create thread: %s"
 msgstr "no s'ha pogut crear fil: %s"
 
+#: builtin/index-pack.c
 msgid "confusion beyond insanity"
 msgstr "confusió més enllà de la bogeria"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "completed with %d local object"
 msgid_plural "completed with %d local objects"
 msgstr[0] "s'ha completat amb %d objecte local"
 msgstr[1] "s'ha completat amb %d objectes locals"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "Unexpected tail checksum for %s (disk corruption?)"
 msgstr "Suma de verificació final no esperada per a %s (corrupció de disc?)"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "pack has %d unresolved delta"
 msgid_plural "pack has %d unresolved deltas"
 msgstr[0] "el paquet té %d diferència no resolta"
 msgstr[1] "el paquet té %d diferències no resoltes"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "unable to deflate appended object (%d)"
 msgstr "no s'ha pogut desinflar l'objecte annexat (%d)"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "local object %s is corrupt"
 msgstr "l'objecte local %s és malmès"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "packfile name '%s' does not end with '.%s'"
 msgstr "el nom del fitxer de paquet «%s» no acaba amb «.%s»"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "cannot write %s file '%s'"
 msgstr "no es pot escriure «%s» al fitxer «%s»"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "cannot close written %s file '%s'"
 msgstr "no s'ha pogut tancar el fitxer %s escrit «%s»"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "unable to rename temporary '*.%s' file to '%s'"
 msgstr "no s'ha pogut canviar el nom del fitxer temporal «*.%s» a «%s»"
 
+#: builtin/index-pack.c
 msgid "error while closing pack file"
 msgstr "error en tancar el fitxer empaquetat"
 
+#: builtin/index-pack.c builtin/pack-objects.c
 #, c-format
 msgid "bad pack.indexVersion=%<PRIu32>"
 msgstr "bad pack.indexVersion=%<PRIu32>"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "Cannot open existing pack file '%s'"
 msgstr "No es pot obrir el fitxer empaquetat existent «%s»"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "Cannot open existing pack idx file for '%s'"
 msgstr "No es pot obrir el fitxer d'índex de paquets existent de «%s»"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "non delta: %d object"
 msgid_plural "non delta: %d objects"
 msgstr[0] "sense diferències: %d objecte"
 msgstr[1] "sense diferències: %d objectes"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "chain length = %d: %lu object"
 msgid_plural "chain length = %d: %lu objects"
 msgstr[0] "longitud de cadena = %d: %lu objecte"
 msgstr[1] "longitud de cadena = %d: %lu objectes"
 
+#: builtin/index-pack.c
 msgid "Cannot come back to cwd"
 msgstr "No es pot tornar al directori de treball actual"
 
+#: builtin/index-pack.c
 #, c-format
 msgid "bad %s"
 msgstr "%s incorrecte"
 
+#: builtin/index-pack.c builtin/init-db.c setup.c
 #, c-format
 msgid "unknown hash algorithm '%s'"
 msgstr "algorisme de resum desconegut «%s»"
 
+#: builtin/index-pack.c
 msgid "--stdin requires a git repository"
 msgstr "--stdin requereix un repositori git"
 
+#: builtin/index-pack.c
 msgid "--verify with no packfile name given"
 msgstr "s'ha donat --verify sense nom de fitxer de paquet"
 
+#: builtin/index-pack.c builtin/unpack-objects.c
 msgid "fsck error in pack objects"
 msgstr "error fsck als objectes del paquet"
 
+#: builtin/init-db.c
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
 "         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
@@ -7420,32 +9520,40 @@
 "         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
 "         [--ref-format=<format>]\n"
 "         [-b <branch-name> | --initial-branch=<branch-name>]\n"
-"         [--shared[=<permissions>]] [<directory>]"
+"         [--shared[=<permissions>]] [<directori>]"
 
+#: builtin/init-db.c
 msgid "permissions"
 msgstr "permisos"
 
+#: builtin/init-db.c
 msgid "specify that the git repository is to be shared amongst several users"
 msgstr ""
 "especifica que el repositori de git es compartirà entre diversos usuaris"
 
+#: builtin/init-db.c
 msgid "override the name of the initial branch"
 msgstr "sobreescriu el nom de la branca inicial"
 
+#: builtin/init-db.c builtin/verify-pack.c
 msgid "hash"
 msgstr "resum"
 
+#: builtin/init-db.c builtin/show-index.c builtin/verify-pack.c
 msgid "specify the hash algorithm to use"
 msgstr "especifiqueu l'algorisme de resum a usar"
 
+#: builtin/init-db.c
 #, c-format
 msgid "cannot mkdir %s"
 msgstr "no es pot mkdir %s"
 
+#: builtin/init-db.c
 #, c-format
 msgid "cannot chdir to %s"
 msgstr "no es pot canviar de directori a %s"
 
+#: builtin/init-db.c
 #, c-format
 msgid ""
 "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -7454,174 +9562,252 @@
 "no es permet %s (o --work-tree=<directori>) sense especificar %s (o --git-"
 "dir=<directori>)"
 
+#: builtin/init-db.c
 #, c-format
 msgid "Cannot access work tree '%s'"
 msgstr "No es pot accedir a l'arbre de treball «%s»"
 
+#: builtin/init-db.c
 msgid "--separate-git-dir incompatible with bare repository"
 msgstr "--separate-git-dir és incompatible amb un repositori nu"
 
+#: builtin/interpret-trailers.c
 msgid ""
 "git interpret-trailers [--in-place] [--trim-empty]\n"
-"                       [(--trailer (<key>|<keyAlias>)[(=|:)<value>])...]\n"
+"                       [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
 "                       [--parse] [<file>...]"
 msgstr ""
 "git interpret-trailers [--in-place] [--trim-empty]\n"
-"                       [(--trailer (<key>|<keyAlias>)[(=|:)<value>])...]\n"
-"                       [--parse] [<file>...]"
+"                       [(--trailer (<clau>|<alies-clau>)[(=|:)<valor>])...]\n"
+"                       [--parse] [<fitxer>...]"
 
+#: builtin/interpret-trailers.c wrapper.c
+#, c-format
+msgid "could not stat %s"
+msgstr "no s'ha pogut fer stat a %s"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "file %s is not a regular file"
+msgstr "el fitxer %s no és un fitxer regular"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "file %s is not writable by user"
+msgstr "el fitxer %s no és gravable per l'usuari"
+
+#: builtin/interpret-trailers.c
+msgid "could not open temporary file"
+msgstr "no s'ha pogut obrir el fitxer temporal"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "could not read input file '%s'"
+msgstr "no s'ha pogut llegir el fitxer d'entrada «%s»"
+
+#: builtin/interpret-trailers.c builtin/mktag.c imap-send.c
+msgid "could not read from stdin"
+msgstr "no s'ha pogut llegir des de stdin"
+
+#: builtin/interpret-trailers.c
+#, c-format
+msgid "could not rename temporary file to %s"
+msgstr "no s'ha pogut canviar el nom del fitxer temporal a %s"
+
+#: builtin/interpret-trailers.c
 msgid "edit files in place"
 msgstr "edita els fitxers in situ"
 
+#: builtin/interpret-trailers.c
 msgid "trim empty trailers"
 msgstr "escurça els remolcs buits"
 
+#: builtin/interpret-trailers.c
 msgid "placement"
 msgstr "posicionament"
 
+#: builtin/interpret-trailers.c
 msgid "where to place the new trailer"
 msgstr "on ubicar el «trailer» nou"
 
+#: builtin/interpret-trailers.c
 msgid "action if trailer already exists"
 msgstr "acció si el «trailer» ja existeix"
 
+#: builtin/interpret-trailers.c
 msgid "action if trailer is missing"
 msgstr "acció si el «trailer» falta"
 
+#: builtin/interpret-trailers.c
 msgid "output only the trailers"
 msgstr "mostra només els «trailer»"
 
+#: builtin/interpret-trailers.c
 msgid "do not apply trailer.* configuration variables"
 msgstr "no apliquis les variables de configuració trailer.*"
 
+#: builtin/interpret-trailers.c
 msgid "reformat multiline trailer values as single-line values"
 msgstr ""
 "reformata els valors del tràiler multilínia com a valors de línia única"
 
+#: builtin/interpret-trailers.c
 msgid "alias for --only-trailers --only-input --unfold"
 msgstr "àlies per a --only-trailers --only-input --unfold"
 
+#: builtin/interpret-trailers.c
 msgid "do not treat \"---\" as the end of input"
 msgstr "no tractis «---» com el final de l'entrada"
 
+#: builtin/interpret-trailers.c
 msgid "trailer(s) to add"
 msgstr "remolcs a afegir"
 
+#: builtin/interpret-trailers.c
 msgid "--trailer with --only-input does not make sense"
 msgstr "--trailer amb --only-input no té sentit"
 
+#: builtin/interpret-trailers.c
 msgid "no input file given for in-place editing"
 msgstr "no s'ha donat cap fitxer d'entrada per a edició in situ"
 
+#: builtin/log.c
 msgid "git log [<options>] [<revision-range>] [[--] <path>...]"
 msgstr "git log [<opcions>] [<rang-de-revisions>] [[--] <camí>...]"
 
+#: builtin/log.c
 msgid "git show [<options>] <object>..."
 msgstr "git show [<opcions>] <objecte>..."
 
+#: builtin/log.c
 #, c-format
 msgid "invalid --decorate option: %s"
 msgstr "opció --decorate no vàlida: %s"
 
+#: builtin/log.c diff.c
 msgid "suppress diff output"
 msgstr "omet la sortida de diferències"
 
+#: builtin/log.c
 msgid "show source"
 msgstr "mostra la font"
 
+#: builtin/log.c
 msgid "clear all previously-defined decoration filters"
 msgstr "neteja tots els filtres de decoració prèviament definits"
 
+#: builtin/log.c
 msgid "only decorate refs that match <pattern>"
 msgstr "només decora les referències que coincideixin amb <patró>"
 
+#: builtin/log.c
 msgid "do not decorate refs that match <pattern>"
 msgstr "no decoris les referències que coincideixen amb <patró>"
 
+#: builtin/log.c
 msgid "decorate options"
 msgstr "opcions de decoració"
 
+#: builtin/log.c
 msgid ""
 "trace the evolution of line range <start>,<end> or function :<funcname> in "
 "<file>"
 msgstr ""
-"traça l'evolució del rang de línia <start>,<end> o funcions :<funcname> a "
-"<fitxer>"
+"traça l'evolució del rang de línia <inici>,<final> o funcions :<nom-funció> "
+"a <fitxer>"
 
+#: builtin/log.c builtin/replay.c builtin/shortlog.c bundle.c
 #, c-format
 msgid "unrecognized argument: %s"
 msgstr "argument no reconegut: %s"
 
+#: builtin/log.c
 msgid "-L<range>:<file> cannot be used with pathspec"
-msgstr "-L<range>:<fitxer> no es pot usar amb una especificació de camí"
+msgstr "-L<rang>:<fitxer> no es pot usar amb una especificació de camí"
 
+#: builtin/log.c
 #, c-format
 msgid "Final output: %d %s\n"
 msgstr "Sortida final: %d %s\n"
 
-msgid "unable to create temporary object directory"
-msgstr "no s'ha pogut crear el directori temporal de l'objecte"
-
+#: builtin/log.c
 #, c-format
 msgid "git show %s: bad file"
 msgstr "git show %s: fitxer incorrecte"
 
+#: builtin/log.c
 #, c-format
 msgid "could not read object %s"
 msgstr "no s'ha pogut llegir l'objecte %s"
 
+#: builtin/log.c
 #, c-format
 msgid "unknown type: %d"
 msgstr "tipus desconegut: %d"
 
+#: builtin/log.c
 #, c-format
 msgid "%s: invalid cover from description mode"
 msgstr "%s: cobertura no vàlida des del mode descripció"
 
+#: builtin/log.c
 msgid "format.headers without value"
 msgstr "format.headers sense valor"
 
+#: builtin/log.c
 #, c-format
 msgid "cannot open patch file %s"
 msgstr "no s'ha pogut obrir el fitxer de pedaç %s"
 
+#: builtin/log.c
 msgid "need exactly one range"
 msgstr "necessita exactament un interval"
 
+#: builtin/log.c
 msgid "not a range"
 msgstr "no és un interval"
 
+#: builtin/log.c
 #, c-format
 msgid "unable to read branch description file '%s'"
 msgstr "no es pot llegir el fitxer de descripció de la branca «%s»"
 
+#: builtin/log.c
 msgid "cover letter needs email format"
 msgstr "la carta de presentació necessita un format de correu electrònic"
 
+#: builtin/log.c
 msgid "failed to create cover-letter file"
 msgstr "s'ha produït un error en crear el fitxer de carta de presentació"
 
+#: builtin/log.c
 #, c-format
 msgid "insane in-reply-to: %s"
 msgstr "in-reply-to boig: %s"
 
+#: builtin/log.c
 msgid "git format-patch [<options>] [<since> | <revision-range>]"
 msgstr "git format-patch [<opcions>] [<des-de> | <rang-de-revisions>]"
 
+#: builtin/log.c
 msgid "two output directories?"
 msgstr "dos directoris de sortida?"
 
+#: builtin/log.c
 #, c-format
 msgid "unknown commit %s"
 msgstr "comissió desconeguda %s"
 
+#: builtin/log.c builtin/replace.c
 #, c-format
 msgid "failed to resolve '%s' as a valid ref"
 msgstr "s'ha produït un error en resoldre «%s» com a referència vàlida"
 
+#: builtin/log.c
 msgid "could not find exact merge base"
 msgstr "no s'ha pogut trobar la base exacta de la fusió"
 
+#: builtin/log.c
 msgid ""
 "failed to get upstream, if you want to record base commit automatically,\n"
 "please use git branch --set-upstream-to to track a remote branch.\n"
@@ -7632,228 +9818,302 @@
 "branca remota. També podeu especificar la comissió base amb --base=<base-"
 "commit-id> manualment"
 
+#: builtin/log.c
 msgid "failed to find exact merge base"
 msgstr "no s'ha pogut trobar la base exacta de la fusió"
 
+#: builtin/log.c
 msgid "base commit should be the ancestor of revision list"
 msgstr "la comissió base ha de ser l'avantpassat de la llista de revisions"
 
+#: builtin/log.c
 msgid "base commit shouldn't be in revision list"
 msgstr "la comissió base no ha de ser en la llista de revisions"
 
+#: builtin/log.c
 msgid "cannot get patch id"
 msgstr "no es pot obtenir l'id del pedaç"
 
+#: builtin/log.c
 msgid "failed to infer range-diff origin of current series"
 msgstr ""
 "no s'ha pogut inferir el rang de diferències d'origen de les sèries actuals"
 
+#: builtin/log.c
 #, c-format
 msgid "using '%s' as range-diff origin of current series"
 msgstr "utilitzant «%s» com a origen de rang de diferències de la sèrie actual"
 
+#: builtin/log.c
 msgid "use [PATCH n/m] even with a single patch"
 msgstr "usa [PATCH n/m] fins i tot amb un sol pedaç"
 
+#: builtin/log.c
 msgid "use [PATCH] even with multiple patches"
 msgstr "usa [PATCH] fins i tot amb múltiples pedaços"
 
+#: builtin/log.c
 msgid "print patches to standard out"
 msgstr "imprimeix els pedaços a la sortida estàndard"
 
+#: builtin/log.c
 msgid "generate a cover letter"
 msgstr "genera una carta de presentació"
 
+#: builtin/log.c
 msgid "use simple number sequence for output file names"
 msgstr "usa una seqüència de números per als noms dels fitxers de sortida"
 
+#: builtin/log.c
 msgid "sfx"
 msgstr "sufix"
 
+#: builtin/log.c
 msgid "use <sfx> instead of '.patch'"
 msgstr "usa <sufix> en lloc de «.patch»"
 
+#: builtin/log.c
 msgid "start numbering patches at <n> instead of 1"
 msgstr "comença numerant els pedaços a <n> en lloc d'1"
 
+#: builtin/log.c
 msgid "reroll-count"
 msgstr "reroll-count"
 
+#: builtin/log.c
 msgid "mark the series as Nth re-roll"
 msgstr "marca la sèrie com a l'enèsima llançada"
 
+#: builtin/log.c
 msgid "max length of output filename"
 msgstr "mida màxima del nom del fitxer de sortida"
 
-msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr "useu [RFC PATCH] en comptes de [PATCH]"
+#: builtin/log.c
+msgid "rfc"
+msgstr "rfc"
 
+#: builtin/log.c
+msgid "add <rfc> (default 'RFC') before 'PATCH'"
+msgstr "afig <rfc> (per defecte «RFC») abans de «PATCH»"
+
+#: builtin/log.c
 msgid "cover-from-description-mode"
 msgstr "cover-from-description-mode"
 
+#: builtin/log.c
 msgid "generate parts of a cover letter based on a branch's description"
 msgstr ""
 "genera parts d'una carta de presentació basant-se en la descripció d'una "
 "branca"
 
+#: builtin/log.c
 msgid "use branch description from file"
 msgstr "utilitza la descripció de la branca des del fitxer"
 
+#: builtin/log.c
 msgid "use [<prefix>] instead of [PATCH]"
 msgstr "useu [<prefix>] en comptes de [PATCH]"
 
+#: builtin/log.c
 msgid "store resulting files in <dir>"
 msgstr "emmagatzema els fitxers resultants a <directori>"
 
+#: builtin/log.c
 msgid "don't strip/add [PATCH]"
 msgstr "no despullis/afegeixis [PATCH]"
 
+#: builtin/log.c
 msgid "don't output binary diffs"
 msgstr "no emetis diferències binàries"
 
+#: builtin/log.c
 msgid "output all-zero hash in From header"
 msgstr "emet un resum de tots zeros en la capçalera From"
 
+#: builtin/log.c
 msgid "don't include a patch matching a commit upstream"
 msgstr "no incloguis pedaços que coincideixin amb comissions a la font"
 
+#: builtin/log.c
 msgid "show patch format instead of default (patch + stat)"
 msgstr ""
 "mostra el format de pedaç en lloc del per defecte (pedaç + estadístiques)"
 
+#: builtin/log.c
 msgid "Messaging"
 msgstr "Missatgeria"
 
+#: builtin/log.c
 msgid "header"
 msgstr "capçalera"
 
+#: builtin/log.c
 msgid "add email header"
 msgstr "afegeix una capçalera de correu electrònic"
 
+#: builtin/log.c
 msgid "email"
 msgstr "correu electrònic"
 
+#: builtin/log.c
 msgid "add To: header"
 msgstr "afegeix la capçalera To:"
 
+#: builtin/log.c
 msgid "add Cc: header"
 msgstr "afegeix la capçalera Cc:"
 
+#: builtin/log.c
 msgid "ident"
 msgstr "identitat"
 
+#: builtin/log.c
 msgid "set From address to <ident> (or committer ident if absent)"
 msgstr ""
 "estableix l'adreça From a <identitat> (o la identitat del comitent si manca)"
 
+#: builtin/log.c
 msgid "message-id"
 msgstr "ID de missatge"
 
+#: builtin/log.c
 msgid "make first mail a reply to <message-id>"
 msgstr "fes que el primer missatge sigui una resposta a <ID de missatge>"
 
+#: builtin/log.c
 msgid "boundary"
 msgstr "límit"
 
+#: builtin/log.c
 msgid "attach the patch"
 msgstr "adjunta el pedaç"
 
+#: builtin/log.c
 msgid "inline the patch"
 msgstr "posa el pedaç en el cos"
 
+#: builtin/log.c
 msgid "enable message threading, styles: shallow, deep"
 msgstr "habilita l'enfilada de missatges, estils: shallow, deep"
 
+#: builtin/log.c
 msgid "signature"
 msgstr "signatura"
 
+#: builtin/log.c
 msgid "add a signature"
 msgstr "afegeix una signatura"
 
+#: builtin/log.c
 msgid "base-commit"
 msgstr "comissió base"
 
+#: builtin/log.c
 msgid "add prerequisite tree info to the patch series"
 msgstr "afegeix la informació d'arbre requerida a la sèrie de pedaços"
 
+#: builtin/log.c
 msgid "add a signature from a file"
 msgstr "afegeix una signatura des d'un fitxer"
 
+#: builtin/log.c
 msgid "don't print the patch filenames"
 msgstr "no imprimeixis els noms de fitxer del pedaç"
 
+#: builtin/log.c
 msgid "show progress while generating patches"
 msgstr "mostra el progrés durant la generació de pedaços"
 
+#: builtin/log.c
 msgid "show changes against <rev> in cover letter or single patch"
 msgstr ""
-"mostra els canvis contra <rev> a la carta de presentació o a un sol pedaç"
+"mostra els canvis contra <revisió> a la carta de presentació o a un sol pedaç"
 
+#: builtin/log.c
 msgid "show changes against <refspec> in cover letter or single patch"
 msgstr ""
 "mostra els canvis contra <refspec> a la carta de presentació o a un sol pedaç"
 
+#: builtin/log.c builtin/range-diff.c
 msgid "percentage by which creation is weighted"
 msgstr "percentatge pel qual la creació és ponderada"
 
+#: builtin/log.c
 msgid "show in-body From: even if identical to the e-mail header"
 msgstr ""
 "mostra en el cos el remitent: encara que sigui idèntic a la capçalera del "
 "correu electrònic"
 
+#: builtin/log.c
 #, c-format
 msgid "invalid ident line: %s"
 msgstr "línia d'identitat no vàlida: %s"
 
+#: builtin/log.c
 msgid "--name-only does not make sense"
 msgstr "--name-only no té sentit"
 
+#: builtin/log.c
 msgid "--name-status does not make sense"
 msgstr "--name-status no té sentit"
 
+#: builtin/log.c
 msgid "--check does not make sense"
 msgstr "--check no té sentit"
 
+#: builtin/log.c
 msgid "--remerge-diff does not make sense"
 msgstr "--remerge-diff no té sentit"
 
+#: builtin/log.c builtin/submodule--helper.c rerere.c submodule.c
 #, c-format
 msgid "could not create directory '%s'"
 msgstr "no s'ha pogut crear el directori «%s»"
 
+#: builtin/log.c
 msgid "--interdiff requires --cover-letter or single patch"
 msgstr "--interdiff requereix --cover-letter o un sol pedaç"
 
+#: builtin/log.c
 msgid "Interdiff:"
 msgstr "Interdiff:"
 
+#: builtin/log.c
 #, c-format
 msgid "Interdiff against v%d:"
 msgstr "Interdiff contra v%d:"
 
+#: builtin/log.c
 msgid "--range-diff requires --cover-letter or single patch"
 msgstr "--range-diff requereix --cover-letter o un sol pedaç"
 
+#: builtin/log.c
 msgid "Range-diff:"
 msgstr "Diferència de l'interval:"
 
+#: builtin/log.c
 #, c-format
 msgid "Range-diff against v%d:"
 msgstr "Diferència de l'interval contra el v%d:"
 
+#: builtin/log.c
 #, c-format
 msgid "unable to read signature file '%s'"
 msgstr "no s'ha pogut llegir el fitxer de signatura «%s»"
 
+#: builtin/log.c
 msgid "Generating patches"
 msgstr "S'estan generant els pedaços"
 
+#: builtin/log.c
 msgid "failed to create output files"
 msgstr "no s'han pogut crear els fitxers de sortida"
 
+#: builtin/log.c
 msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
 msgstr "git cherry [-v] [<font> [<cap> [<límit>]]]"
 
+#: builtin/log.c
 #, c-format
 msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
@@ -7861,108 +10121,126 @@
 "No s'ha pogut trobar una branca remota seguida. Especifiqueu <font> "
 "manualment.\n"
 
+#: builtin/ls-files.c builtin/ls-tree.c
 #, c-format
 msgid "could not get object info about '%s'"
 msgstr "no s'ha pogut obtenir la informació sobre l'objecte «%s»"
 
-#, c-format
-msgid "bad ls-files format: element '%s' does not start with '('"
-msgstr "format incorrecte del ls-files: l'element «%s» no comença amb «(»"
-
-#, c-format
-msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "format incorrecte del ls-files: l'element «%s» no acaba amb «)»"
-
-#, c-format
-msgid "bad ls-files format: %%%.*s"
-msgstr "format incorrecte de ls-files: %%%.*s"
-
+#: builtin/ls-files.c
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<opcions>] [<fitxer>...]"
 
+#: builtin/ls-files.c builtin/merge-tree.c
 msgid "separate paths with the NUL character"
 msgstr "separa els camins amb el caràcter NUL"
 
+#: builtin/ls-files.c
 msgid "identify the file status with tags"
 msgstr "identifica l'estat de fitxer amb etiquetes"
 
+#: builtin/ls-files.c
 msgid "use lowercase letters for 'assume unchanged' files"
 msgstr "usa lletres minúscules per als fitxers «assume unchanged»"
 
+#: builtin/ls-files.c
 msgid "use lowercase letters for 'fsmonitor clean' files"
 msgstr "usa lletres minúscules per als fitxers «fsmonitor clean»"
 
+#: builtin/ls-files.c
 msgid "show cached files in the output (default)"
 msgstr ""
 "mostra en la sortida els fitxers desats en la memòria cau (per defecte)"
 
+#: builtin/ls-files.c
 msgid "show deleted files in the output"
 msgstr "mostra en la sortida els fitxers suprimits"
 
+#: builtin/ls-files.c
 msgid "show modified files in the output"
 msgstr "mostra en la sortida els fitxers modificats"
 
+#: builtin/ls-files.c
 msgid "show other files in the output"
 msgstr "mostra en la sortida els altres fitxers"
 
+#: builtin/ls-files.c
 msgid "show ignored files in the output"
 msgstr "mostra en la sortida els fitxers ignorats"
 
+#: builtin/ls-files.c
 msgid "show staged contents' object name in the output"
 msgstr "mostra en la sortida el nom d'objecte dels continguts «stage»"
 
+#: builtin/ls-files.c
 msgid "show files on the filesystem that need to be removed"
 msgstr "mostra els fitxers en el sistema de fitxers que s'han d'eliminar"
 
+#: builtin/ls-files.c
 msgid "show 'other' directories' names only"
 msgstr "mostra només els noms dels directoris «other»"
 
+#: builtin/ls-files.c
 msgid "show line endings of files"
 msgstr "mostra els terminadors de línia dels fitxers"
 
+#: builtin/ls-files.c
 msgid "don't show empty directories"
 msgstr "no mostris els directoris buits"
 
+#: builtin/ls-files.c
 msgid "show unmerged files in the output"
 msgstr "mostra en la sortida els fitxers sense fusionar"
 
+#: builtin/ls-files.c
 msgid "show resolve-undo information"
 msgstr "mostra la informació de resolució de desfet"
 
+#: builtin/ls-files.c
 msgid "skip files matching pattern"
 msgstr "omet els fitxers coincidents amb el patró"
 
+#: builtin/ls-files.c
 msgid "read exclude patterns from <file>"
 msgstr "llegeix els patrons des de <fitxer>"
 
+#: builtin/ls-files.c
 msgid "read additional per-directory exclude patterns in <file>"
 msgstr "llegeix els patrons addicionals d'exclusió per directori en <fitxer>"
 
+#: builtin/ls-files.c
 msgid "add the standard git exclusions"
 msgstr "afegeix les exclusions estàndards de git"
 
+#: builtin/ls-files.c
 msgid "make the output relative to the project top directory"
 msgstr "fes que la sortida sigui relativa al directori superior del projecte"
 
+#: builtin/ls-files.c
 msgid "if any <file> is not in the index, treat this as an error"
 msgstr "si qualsevol <fitxer> no és en l'índex, tracta-ho com a error"
 
+#: builtin/ls-files.c builtin/merge-tree.c
 msgid "tree-ish"
 msgstr "arbre"
 
+#: builtin/ls-files.c
 msgid "pretend that paths removed since <tree-ish> are still present"
 msgstr ""
 "pretén que els camins eliminats després de <arbre> encara siguin presents"
 
+#: builtin/ls-files.c
 msgid "show debugging data"
 msgstr "mostra les dades de depuració"
 
+#: builtin/ls-files.c
 msgid "suppress duplicate entries"
 msgstr "suprimeix les entrades duplicades"
 
+#: builtin/ls-files.c
 msgid "show sparse directories in the presence of a sparse index"
 msgstr "mostra els directoris dispersos en presència d'un índex dispers"
 
+#: builtin/ls-files.c
 msgid ""
 "--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
 "--eol"
@@ -7970,163 +10248,202 @@
 "--format no es pot usar amb -s, -o, -k, -t, --resolve-undo, --deduplicate, --"
 "eol"
 
+#: builtin/ls-remote.c
 msgid ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
 "              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
-"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
-"              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-"              [--symref] [<repository> [<patterns>...]]"
+"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
+"              [-q | --quiet] [--exit-code] [--get-url] [--sort=<clau>]\n"
+"              [--symref] [<repositori> [<patrons>...]]"
 
+#: builtin/ls-remote.c
 msgid "do not print remote URL"
 msgstr "no imprimeixis l'URL remot"
 
+#: builtin/ls-remote.c builtin/rebase.c
 msgid "exec"
 msgstr "executable"
 
+#: builtin/ls-remote.c
 msgid "path of git-upload-pack on the remote host"
 msgstr "camí a git-upload-pack en la màquina remota"
 
+#: builtin/ls-remote.c
 msgid "limit to tags"
 msgstr "limita a etiquetes"
 
-msgid "limit to heads"
-msgstr "limita a «heads»"
+# limita-ho?
+#: builtin/ls-remote.c
+msgid "limit to branches"
+msgstr "limita a les branques"
 
+#: builtin/ls-remote.c builtin/show-ref.c
+msgid "deprecated synonym for --branches"
+msgstr "sinònim de «--branches» en desús"
+
+#: builtin/ls-remote.c
 msgid "do not show peeled tags"
 msgstr "no mostris les etiquetes pelades"
 
+#: builtin/ls-remote.c
 msgid "take url.<base>.insteadOf into account"
 msgstr "tingues en compte url.<base>.insteadOf"
 
+#: builtin/ls-remote.c
 msgid "exit with exit code 2 if no matching refs are found"
 msgstr "surt amb codi de sortida 2 si no es troba cap referència coincident"
 
+#: builtin/ls-remote.c
 msgid "show underlying ref in addition to the object pointed by it"
 msgstr "mostra la referència subjacent a més de l'objecte que assenyali"
 
+#: builtin/ls-tree.c
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<opcions>] <arbre> [<camí>...]"
 
-#, c-format
-msgid "bad ls-tree format: element '%s' does not start with '('"
-msgstr "format incorrecte del ls-tree: l'element '%s' no comença amb «(»"
-
-#, c-format
-msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "format incorrecte del ls-tree: l'element '%s' no acaba en «(»"
-
-#, c-format
-msgid "bad ls-tree format: %%%.*s"
-msgstr "format incorrecte de ls-tree: %%%.*s"
-
+#: builtin/ls-tree.c
 msgid "only show trees"
 msgstr "mostra només els arbres"
 
+#: builtin/ls-tree.c
 msgid "recurse into subtrees"
 msgstr "inclou recursivament als subarbres"
 
+#: builtin/ls-tree.c
 msgid "show trees when recursing"
 msgstr "mostra els arbres quan es treballa recursivament"
 
+#: builtin/ls-tree.c
 msgid "terminate entries with NUL byte"
 msgstr "acaba les entrades amb un octet NUL"
 
+#: builtin/ls-tree.c
 msgid "include object size"
 msgstr "mida de l'objecte d'inclusió"
 
+#: builtin/ls-tree.c
 msgid "list only filenames"
 msgstr "llista només els noms de fitxer"
 
+#: builtin/ls-tree.c
 msgid "list only objects"
 msgstr "llista només els objectes"
 
+#: builtin/ls-tree.c
 msgid "use full path names"
 msgstr "usa els noms de camí complets"
 
+#: builtin/ls-tree.c
 msgid "list entire tree; not just current directory (implies --full-name)"
 msgstr ""
 "llista l'arbre sencer; no només el directori actual (implica --full-name)"
 
+#: builtin/ls-tree.c
 msgid "--format can't be combined with other format-altering options"
 msgstr "--format no es pot combinar amb altres opcions d'alteració de format"
 
 #. TRANSLATORS: keep <> in "<" mail ">" info.
+#: builtin/mailinfo.c
 msgid "git mailinfo [<options>] <msg> <patch> < mail >info"
 msgstr "git mailinfo [<opcions>] <msg> <pedaç> < mail >info"
 
+#: builtin/mailinfo.c
 msgid "keep subject"
 msgstr "mantén l'assumpte"
 
+#: builtin/mailinfo.c
 msgid "keep non patch brackets in subject"
 msgstr "mantén els parèntesis que no són del pedaç en l'assumpte"
 
+#: builtin/mailinfo.c
 msgid "copy Message-ID to the end of commit message"
 msgstr "copia el Message-ID al final del missatge de comissió"
 
+#: builtin/mailinfo.c
 msgid "re-code metadata to i18n.commitEncoding"
 msgstr "torna a codificar les metadades a i18n.commitEncoding"
 
+#: builtin/mailinfo.c
 msgid "disable charset re-coding of metadata"
 msgstr "inhabilita la recodificació del joc de caràcters de les metadades"
 
+#: builtin/mailinfo.c
 msgid "encoding"
 msgstr "codificació"
 
+#: builtin/mailinfo.c
 msgid "re-code metadata to this encoding"
 msgstr "recodifica les metadades en aquesta codificació"
 
+#: builtin/mailinfo.c
 msgid "use scissors"
 msgstr "usa les tisores"
 
+#: builtin/mailinfo.c
 msgid "<action>"
 msgstr "<acció>"
 
+#: builtin/mailinfo.c
 msgid "action when quoted CR is found"
 msgstr "acció quan es troba un CR entre cometes"
 
+#: builtin/mailinfo.c
 msgid "use headers in message's body"
 msgstr "utilitza les capçaleres en el cos del missatge"
 
+#: builtin/mailsplit.c
 msgid "reading patches from stdin/tty..."
 msgstr "s'estan llegint pedaços de stdin/tty..."
 
+#: builtin/mailsplit.c
 #, c-format
 msgid "empty mbox: '%s'"
 msgstr "mbox buit: «%s»"
 
+#: builtin/merge-base.c
 msgid "git merge-base [-a | --all] <commit> <commit>..."
 msgstr "git merge-base [-a | --all] <comissió> <comissió>..."
 
+#: builtin/merge-base.c
 msgid "git merge-base [-a | --all] --octopus <commit>..."
 msgstr "git merge-base [-a | --all] --octopus <comissió>..."
 
+#: builtin/merge-base.c
 msgid "git merge-base --is-ancestor <commit> <commit>"
 msgstr "git merge-base --is-ancestor <comissió> <comissió>"
 
+#: builtin/merge-base.c
 msgid "git merge-base --independent <commit>..."
 msgstr "git merge-base --independent <comissió>..."
 
+#: builtin/merge-base.c
 msgid "git merge-base --fork-point <ref> [<commit>]"
 msgstr "git merge-base --fork-point <referència> [<comissió>]"
 
+#: builtin/merge-base.c
 msgid "output all common ancestors"
 msgstr "emet tots els avantpassats comuns"
 
+#: builtin/merge-base.c
 msgid "find ancestors for a single n-way merge"
 msgstr "troba els avantpassats per a una sola fusió d'n vies"
 
+#: builtin/merge-base.c
 msgid "list revs not reachable from others"
 msgstr "llista les revisions no abastables d'altres"
 
+#: builtin/merge-base.c
 msgid "is the first one ancestor of the other?"
 msgstr "és la primera un avantpassat de l'altre?"
 
+#: builtin/merge-base.c
 msgid "find where <commit> forked from reflog of <ref>"
 msgstr ""
 "troba on <comissió> s'ha bifurcat del registre de referències de <referència>"
 
+#: builtin/merge-file.c
 msgid ""
 "git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> "
 "<orig-file> <file2>"
@@ -8134,269 +10451,342 @@
 "git merge-file [<opcions>] [-L <nom1> [-L <original> [-L <nom2>]]] <fitxer1> "
 "<fitxer-original> <fitxer2>"
 
+#: builtin/merge-file.c diff.c
 msgid ""
 "option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
 "\"histogram\""
 msgstr ""
 "l'opció diff-algorithm accepta «myers», «minimal», «patience» i «histogram»"
 
+#: builtin/merge-file.c
 msgid "send results to standard output"
 msgstr "envia els resultats a la sortida estàndard"
 
+#: builtin/merge-file.c
 msgid "use object IDs instead of filenames"
 msgstr "utilitza els ID dels objectes en comptes dels noms de fitxer"
 
+#: builtin/merge-file.c
 msgid "use a diff3 based merge"
 msgstr "usa una fusió basada en diff3"
 
+#: builtin/merge-file.c
 msgid "use a zealous diff3 based merge"
 msgstr "usa una fusió basada en zealous diff3"
 
-msgid "for conflicts, use our version"
-msgstr "en conflictes, usa la nostra versió"
-
-msgid "for conflicts, use their version"
-msgstr "en conflictes, usa la seva versió"
-
-msgid "for conflicts, use a union version"
-msgstr "en conflictes, usa una versió d'unió"
-
+#: builtin/merge-file.c diff.c
 msgid "<algorithm>"
 msgstr "<algorisme>"
 
+#: builtin/merge-file.c diff.c
 msgid "choose a diff algorithm"
 msgstr "trieu un algorisme per al diff"
 
+#: builtin/merge-file.c
 msgid "for conflicts, use this marker size"
 msgstr "en conflictes, usa aquesta mida de marcador"
 
+#: builtin/merge-file.c
 msgid "do not warn about conflicts"
 msgstr "no avisis de conflictes"
 
+#: builtin/merge-file.c
 msgid "set labels for file1/orig-file/file2"
 msgstr "estableix les etiquetes per a fitxer1/fitxer-original/fitxer2"
 
+#: builtin/merge-file.c
 #, c-format
 msgid "object '%s' does not exist"
 msgstr "l'objecte «%s» no existeix"
 
+#: builtin/merge-file.c
 msgid "Could not write object file"
 msgstr "No s'ha pogut escriure el fitxer de l'objecte"
 
+#: builtin/merge-recursive.c
 #, c-format
 msgid "unknown option %s"
 msgstr "opció desconeguda %s"
 
+#: builtin/merge-recursive.c
 #, c-format
 msgid "could not parse object '%s'"
 msgstr "no s'ha pogut analitzar l'objecte «%s»"
 
+#: builtin/merge-recursive.c
 #, c-format
 msgid "cannot handle more than %d base. Ignoring %s."
 msgid_plural "cannot handle more than %d bases. Ignoring %s."
 msgstr[0] "no es pot gestionar més d'%d base. S'està ignorant %s."
 msgstr[1] "no es poden gestionar més de %d bases. S'està ignorant %s."
 
+#: builtin/merge-recursive.c
 msgid "not handling anything other than two heads merge."
 msgstr "no s'està gestionant res a part de la fusió de dos caps."
 
+#: builtin/merge-recursive.c
 #, c-format
 msgid "could not resolve ref '%s'"
 msgstr "no s'ha pogut resoldre la referència «%s»"
 
+#: builtin/merge-recursive.c
 #, c-format
 msgid "Merging %s with %s\n"
 msgstr "S'està fusionant %s amb %s\n"
 
+#: builtin/merge-tree.c
+#, c-format
+msgid "could not parse as tree '%s'"
+msgstr "no s'ha pogut analitzar com a arbre «%s»"
+
+#: builtin/merge-tree.c builtin/merge.c
 msgid "not something we can merge"
 msgstr "no és quelcom que puguem fusionar"
 
+#: builtin/merge-tree.c builtin/merge.c
 msgid "refusing to merge unrelated histories"
 msgstr "s'està refusant fusionar històries no relacionades"
 
+#: builtin/merge-tree.c
 msgid "failure to merge"
 msgstr "s'ha produït un error en fusionar"
 
+#: builtin/merge-tree.c
 msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
-msgstr "git merge-tree [--write-tree] [<opcions>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<opcions>] <branca1> <branca2>"
 
+#: builtin/merge-tree.c
 msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
-msgstr "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <base-tree> <branca1> <branca2>"
 
+#: builtin/merge-tree.c
 msgid "do a real merge instead of a trivial merge"
 msgstr "fes una fusió real en lloc d'una fusió trivial"
 
+#: builtin/merge-tree.c
 msgid "do a trivial merge only"
 msgstr "fes només una fusió trivial"
 
+#: builtin/merge-tree.c
 msgid "also show informational/conflict messages"
 msgstr "també mostra missatges informatius i de conflictes"
 
+#: builtin/merge-tree.c
 msgid "list filenames without modes/oids/stages"
 msgstr "llista els noms de fitxer sense modes/oids/stages"
 
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
 msgid "allow merging unrelated histories"
 msgstr "permet fusionar històries no relacionades"
 
+#: builtin/merge-tree.c
 msgid "perform multiple merges, one per line of input"
 msgstr "realitza múltiples fusions, una per línia d'entrada"
 
+#: builtin/merge-tree.c
 msgid "specify a merge-base for the merge"
 msgstr "cal especificar una referència base per a la fusió"
 
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
 msgid "option=value"
 msgstr "opció=valor"
 
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
 msgid "option for selected merge strategy"
 msgstr "opció per a l'estratègia de fusió seleccionada"
 
+#: builtin/merge-tree.c
 msgid "--trivial-merge is incompatible with all other options"
 msgstr "--trivial-merge és incompatible amb totes les altres opcions"
 
+#: builtin/merge-tree.c builtin/merge.c
 #, c-format
 msgid "unknown strategy option: -X%s"
 msgstr "opció d'estratègia desconeguda: -X%s"
 
+#: builtin/merge-tree.c builtin/notes.c
 #, c-format
 msgid "malformed input line: '%s'."
 msgstr "línia d'entrada mal formada: «%s»."
 
+#: builtin/merge-tree.c
 #, c-format
 msgid "merging cannot continue; got unclean result of %d"
 msgstr "la fusió no pot continuar; s'ha obtingut un resultat no net de %d"
 
+#: builtin/merge.c
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<opcions>] [<comissió>...]"
 
+#: builtin/merge.c
 msgid "switch `m' requires a value"
 msgstr "l'opció «m» requereix un valor"
 
+#: builtin/merge.c
 #, c-format
 msgid "option `%s' requires a value"
 msgstr "l'opció «%s» requereix un valor"
 
+#: builtin/merge.c
 #, c-format
 msgid "Could not find merge strategy '%s'.\n"
 msgstr "No s'ha pogut trobar l'estratègia de fusió «%s».\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "Available strategies are:"
 msgstr "Les estratègies disponibles són:"
 
+#: builtin/merge.c
 #, c-format
 msgid "Available custom strategies are:"
 msgstr "Les estratègies personalitzades disponibles són:"
 
+#: builtin/merge.c builtin/pull.c
 msgid "do not show a diffstat at the end of the merge"
 msgstr "no mostris les estadístiques de diferència al final de la fusió"
 
+#: builtin/merge.c builtin/pull.c
 msgid "show a diffstat at the end of the merge"
 msgstr "mostra les estadístiques de diferència al final de la fusió"
 
+#: builtin/merge.c builtin/pull.c
 msgid "(synonym to --stat)"
 msgstr "(sinònim de --stat)"
 
+#: builtin/merge.c builtin/pull.c
 msgid "add (at most <n>) entries from shortlog to merge commit message"
 msgstr ""
 "afegeix (com a màxim <n>) entrades del registre curt al missatge de comissió "
 "de fusió"
 
+#: builtin/merge.c builtin/pull.c
 msgid "create a single commit instead of doing a merge"
 msgstr "crea una única comissió en lloc de fusionar"
 
+#: builtin/merge.c builtin/pull.c
 msgid "perform a commit if the merge succeeds (default)"
 msgstr "realitza una comissió si la fusió té èxit (per defecte)"
 
+#: builtin/merge.c builtin/pull.c
 msgid "edit message before committing"
 msgstr "edita el missatge abans de cometre"
 
+#: builtin/merge.c
 msgid "allow fast-forward (default)"
 msgstr "permet l'avanç ràpid (per defecte)"
 
+#: builtin/merge.c builtin/pull.c
 msgid "abort if fast-forward is not possible"
 msgstr "avorta si l'avanç ràpid no és possible"
 
+#: builtin/merge.c builtin/pull.c
 msgid "verify that the named commit has a valid GPG signature"
 msgstr "verifica que la comissió anomenada tingui una signatura GPG vàlida"
 
+#: builtin/merge.c builtin/notes.c builtin/pull.c builtin/rebase.c
+#: builtin/revert.c
 msgid "strategy"
 msgstr "estratègia"
 
+#: builtin/merge.c builtin/pull.c
 msgid "merge strategy to use"
 msgstr "estratègia de fusió a usar"
 
+#: builtin/merge.c
 msgid "merge commit message (for a non-fast-forward merge)"
 msgstr "missatge de comissió de fusió (per a una fusió no d'avanç ràpid)"
 
+#: builtin/merge.c
 msgid "use <name> instead of the real target"
 msgstr "usa <nom> en lloc de destí real"
 
+#: builtin/merge.c
 msgid "abort the current in-progress merge"
 msgstr "avorta la fusió en curs actual"
 
+#: builtin/merge.c
 msgid "--abort but leave index and working tree alone"
 msgstr "--abort però deixa l'índex i l'arbre de treball intactes"
 
+#: builtin/merge.c
 msgid "continue the current in-progress merge"
 msgstr "continua la fusió actual en curs"
 
+#: builtin/merge.c
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr "evita els lligams pre-merge-commit i commit-msg"
 
+#: builtin/merge.c
 msgid "could not run stash."
 msgstr "no s'ha pogut executar «stash»."
 
+#: builtin/merge.c
 msgid "stash failed"
 msgstr "l'«stash» ha fallat"
 
+#: builtin/merge.c
 #, c-format
 msgid "not a valid object: %s"
 msgstr "no és un objecte vàlid: %s"
 
+#: builtin/merge.c
 msgid "read-tree failed"
 msgstr "read-tree ha fallat"
 
+#: builtin/merge.c
 msgid "Already up to date. (nothing to squash)"
 msgstr "Ja està actualitzat. (res a fer «squash»)"
 
+#: builtin/merge.c merge-ort-wrappers.c merge-recursive.c
 msgid "Already up to date."
 msgstr "Ja està al dia."
 
+#: builtin/merge.c
 #, c-format
 msgid "Squash commit -- not updating HEAD\n"
 msgstr "Comissió «squash» -- no s'està actualitzant HEAD\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "No merge message -- not updating HEAD\n"
 msgstr "Cap missatge de fusió -- no s'està actualitzant HEAD\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "'%s' does not point to a commit"
 msgstr "«%s» no assenyala una comissió"
 
+#: builtin/merge.c
 #, c-format
 msgid "Bad branch.%s.mergeoptions string: %s"
 msgstr "Cadena branch.%s.mergeoptions incorrecta: %s"
 
+#: builtin/merge.c merge-recursive.c
 msgid "Unable to write index."
 msgstr "No s'ha pogut escriure l'índex."
 
+#: builtin/merge.c
 msgid "Not handling anything other than two heads merge."
 msgstr "No s'està gestionant res a part de la fusió de dos caps."
 
+#: builtin/merge.c builtin/sparse-checkout.c
 #, c-format
 msgid "unable to write %s"
 msgstr "no s'ha pogut escriure %s"
 
+#: builtin/merge.c
 #, c-format
 msgid "Could not read from '%s'"
 msgstr "No s'ha pogut llegir de «%s»"
 
+#: builtin/merge.c
 #, c-format
 msgid "Not committing merge; use 'git commit' to complete the merge.\n"
 msgstr ""
 "No s'està cometent la fusió; useu «git commit» per a completar la fusió.\n"
 
+#: builtin/merge.c
 msgid ""
 "Please enter a commit message to explain why this merge is necessary,\n"
 "especially if it merges an updated upstream into a topic branch.\n"
@@ -8406,70 +10796,89 @@
 "necessària, especialment si es fusiona una branca amb funcionalitat nova.\n"
 "\n"
 
+#: builtin/merge.c
 msgid "An empty message aborts the commit.\n"
 msgstr "Un missatge buit interromp la comissió.\n"
 
+# will be ignored → es descartaran?
+#: builtin/merge.c
 #, c-format
 msgid ""
-"Lines starting with '%c' will be ignored, and an empty message aborts\n"
+"Lines starting with '%s' will be ignored, and an empty message aborts\n"
 "the commit.\n"
 msgstr ""
-"Les línies que comencen amb «%c» seran ignorades i un missatge buit "
-"interromp la comissió.\n"
+"Les línies que comencin amb «%s» s'ignoraran, i un missatge buit\n"
+"avorta la comissió.\n"
 
+#: builtin/merge.c
 msgid "Empty commit message."
 msgstr "El missatge de comissió és buit."
 
+#: builtin/merge.c
 #, c-format
 msgid "Wonderful.\n"
 msgstr "Meravellós.\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
 msgstr ""
 "La fusió automàtica ha fallat; arregleu els conflictes i després cometeu el "
 "resultat.\n"
 
+#: builtin/merge.c
 msgid "No current branch."
 msgstr "No hi ha cap branca actual."
 
+#: builtin/merge.c
 msgid "No remote for the current branch."
 msgstr "No hi ha cap remot per a la branca actual."
 
+#: builtin/merge.c
 msgid "No default upstream defined for the current branch."
 msgstr "No hi ha cap font per defecte definida per a la branca actual."
 
+#: builtin/merge.c
 #, c-format
 msgid "No remote-tracking branch for %s from %s"
 msgstr "No hi ha cap branca amb seguiment remot per a %s de %s"
 
+#: builtin/merge.c
 #, c-format
 msgid "Bad value '%s' in environment '%s'"
 msgstr "Valor incorrecte «%s» en l'entorn «%s»"
 
+#: builtin/merge.c editor.c read-cache.c wrapper.c
 #, c-format
 msgid "could not close '%s'"
 msgstr "no s'ha pogut tancar «%s»"
 
+#: builtin/merge.c
 #, c-format
 msgid "not something we can merge in %s: %s"
 msgstr "no és quelcom que puguem fusionar en %s: %s"
 
+#: builtin/merge.c
 msgid "--abort expects no arguments"
 msgstr "--abort no espera cap argument"
 
+#: builtin/merge.c
 msgid "There is no merge to abort (MERGE_HEAD missing)."
 msgstr "No hi ha fusió a avortar (manca MERGE_HEAD)."
 
+#: builtin/merge.c
 msgid "--quit expects no arguments"
 msgstr "--quit no espera cap argument"
 
+#: builtin/merge.c
 msgid "--continue expects no arguments"
 msgstr "--continue no espera cap argument"
 
+#: builtin/merge.c
 msgid "There is no merge in progress (MERGE_HEAD missing)."
 msgstr "No hi ha cap fusió en curs (manca MERGE_HEAD)."
 
+#: builtin/merge.c
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you merge."
@@ -8477,6 +10886,7 @@
 "No heu conclòs la vostra fusió (MERGE_HEAD existeix).\n"
 "Cometeu els vostres canvis abans de fusionar."
 
+#: builtin/merge.c
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you merge."
@@ -8484,31 +10894,39 @@
 "No heu conclòs el vostre «cherry pick» (CHERRY_PICK_HEAD existeix).\n"
 "Cometeu els vostres canvis abans de fusionar."
 
+#: builtin/merge.c
 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
 msgstr "No heu conclòs el vostre «cherry pick» (CHERRY_PICK_HEAD existeix)."
 
+#: builtin/merge.c
 msgid "No commit specified and merge.defaultToUpstream not set."
 msgstr ""
 "No hi ha una comissió especificada i merge.defaultToUpstream no està "
 "establert."
 
+#: builtin/merge.c
 msgid "Squash commit into empty head not supported yet"
 msgstr "Una comissió «squash» a una HEAD buida encara no es permet"
 
+#: builtin/merge.c
 msgid "Non-fast-forward commit does not make sense into an empty head"
 msgstr "Una comissió no d'avanç ràpid no té sentit a una HEAD buida"
 
+#: builtin/merge.c
 #, c-format
 msgid "%s - not something we can merge"
 msgstr "%s - no és una cosa que puguem fusionar"
 
+#: builtin/merge.c
 msgid "Can merge only exactly one commit into empty head"
 msgstr "Es pot fusionar només una comissió a una HEAD buida"
 
+#: builtin/merge.c
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "S'estan actualitzant %s..%s\n"
 
+#: builtin/merge.c merge-ort-wrappers.c merge-recursive.c
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by merge:\n"
@@ -8517,126 +10935,159 @@
 "Els canvis locals als fitxers següents se sobreescriuran per la fusió:\n"
 "  %s"
 
+#: builtin/merge.c
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "S'està intentant una fusió molt trivial en l'índex...\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "Nope.\n"
 msgstr "No.\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
 msgstr "S'està rebobinant l'arbre a la pristina...\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "Trying merge strategy %s...\n"
 msgstr "S'està intentant l'estratègia de fusió %s...\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "No merge strategy handled the merge.\n"
 msgstr "Cap estratègia de fusió ha gestionat la fusió.\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "Merge with strategy %s failed.\n"
 msgstr "L'estratègia de fusió %s ha fallat.\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "Using the %s strategy to prepare resolving by hand.\n"
 msgstr "S'està usant l'estratègia %s per a preparar la resolució a mà.\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
 "La fusió automàtica ha sortit bé; s'ha aturat abans de cometre com s'havia "
 "demanat\n"
 
+#: builtin/merge.c
 #, c-format
 msgid "When finished, apply stashed changes with `git stash pop`\n"
 msgstr "Quan acabi, aplica els canvis «stashed» amb «git stash pop»\n"
 
+#: builtin/mktag.c
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
 msgstr "avís: l'entrada d'etiqueta no passa fsck: %s"
 
+#: builtin/mktag.c
 #, c-format
 msgid "error: tag input does not pass fsck: %s"
 msgstr "error: l'entrada d'etiqueta no passa fsck: %s"
 
+#: builtin/mktag.c
 #, c-format
 msgid "%d (FSCK_IGNORE?) should never trigger this callback"
 msgstr "%d (FSCK_IGNORE?) no hauria d'activar mai aquesta crida de retorn"
 
+#: builtin/mktag.c
 #, c-format
 msgid "could not read tagged object '%s'"
 msgstr "no s'ha pogut llegir l'objecte etiquetat «%s»"
 
+#: builtin/mktag.c
 #, c-format
 msgid "object '%s' tagged as '%s', but is a '%s' type"
 msgstr "l'objecte «%s» s'ha etiquetat com a «%s», però és del tipus «%s»"
 
-msgid "could not read from stdin"
-msgstr "no s'ha pogut llegir des de stdin"
-
+#: builtin/mktag.c
 msgid "tag on stdin did not pass our strict fsck check"
 msgstr "l'etiqueta a stdin no ha passat la comprovació estricta del fsck"
 
+#: builtin/mktag.c
 msgid "tag on stdin did not refer to a valid object"
 msgstr "l'etiqueta a stdin no apunta a un objecte vàlid"
 
+#: builtin/mktag.c builtin/tag.c
 msgid "unable to write tag file"
 msgstr "no s'ha pogut escriure el fitxer d'etiqueta"
 
+#: builtin/mktree.c
 msgid "input is NUL terminated"
 msgstr "l'entrada és acabada amb NUL"
 
+#: builtin/mktree.c builtin/write-tree.c
 msgid "allow missing objects"
 msgstr "permet els objectes absents"
 
+#: builtin/mktree.c
 msgid "allow creation of more than one tree"
 msgstr "permet la creació de més d'un arbre"
 
+#: builtin/multi-pack-index.c
 msgid ""
 "git multi-pack-index [<options>] write [--preferred-pack=<pack>][--refs-"
 "snapshot=<path>]"
 msgstr ""
-"git multi-pack-index [<opcions>] write [--preferred-pack=<pack>][--refs-"
+"git multi-pack-index [<opcions>] write [--preferred-pack=<paquet>][--refs-"
 "snapshot=<camí>]"
 
+#: builtin/multi-pack-index.c
 msgid "git multi-pack-index [<options>] verify"
 msgstr "git multi-pack-index [<opcions>] verify"
 
+#: builtin/multi-pack-index.c
 msgid "git multi-pack-index [<options>] expire"
 msgstr "git multi-pack-index [<opcions>] expire"
 
+#: builtin/multi-pack-index.c
 msgid "git multi-pack-index [<options>] repack [--batch-size=<size>]"
 msgstr "git multi-pack-index [<opcions>] repack [--batch-size=<mida>]"
 
+#: builtin/multi-pack-index.c
 msgid "directory"
 msgstr "directori"
 
+#: builtin/multi-pack-index.c
 msgid "object directory containing set of packfile and pack-index pairs"
 msgstr ""
 "directori de l'objecte que conté el conjunt de parells de fitxers i índexs "
 "de paquets"
 
+#: builtin/multi-pack-index.c
 msgid "preferred-pack"
 msgstr "paquet preferit"
 
+#: builtin/multi-pack-index.c
 msgid "pack for reuse when computing a multi-pack bitmap"
 msgstr ""
 "empaqueta per a reutilitzar quan es calcula un mapa de bits multipaquet"
 
+#: builtin/multi-pack-index.c
 msgid "write multi-pack bitmap"
 msgstr "escriu un map de bits multipaquet"
 
+#: builtin/multi-pack-index.c
+msgid "write a new incremental MIDX"
+msgstr "escriu un nou MIDX incremental"
+
+#: builtin/multi-pack-index.c
 msgid "write multi-pack index containing only given indexes"
 msgstr "escriu un índex multipaquet que contingui només els índexs donats"
 
+#: builtin/multi-pack-index.c
 msgid "refs snapshot for selecting bitmap commits"
 msgstr ""
 "instantània de referències per a seleccionar les comissions de mapa de bits"
 
+#: builtin/multi-pack-index.c
 msgid ""
 "during repack, collect pack-files of smaller size into a batch that is "
 "larger than this size"
@@ -8644,245 +11095,309 @@
 "durant el reempaquetament, recull els fitxers de paquets de mida més petita "
 "en un lot que és més gran que aquesta mida"
 
+#: builtin/mv.c
 msgid "git mv [<options>] <source>... <destination>"
 msgstr "git mv [<opcions>] <origen>... <destí>"
 
+#: builtin/mv.c
 #, c-format
 msgid "Directory %s is in index and no submodule?"
 msgstr "El directori %s és en l'índex i no hi ha cap submòdul?"
 
+#: builtin/mv.c
 msgid "Please stage your changes to .gitmodules or stash them to proceed"
 msgstr ""
 "Feu «stage» dels vostres canvis a .gitmodules o feu «stash» dels mateixos "
 "per a procedir"
 
+#: builtin/mv.c
 #, c-format
 msgid "%.*s is in index"
 msgstr "%.*s és en l'índex"
 
+#: builtin/mv.c
 msgid "force move/rename even if target exists"
 msgstr "força el moviment / canvi de nom encara que el destí existeixi"
 
+#: builtin/mv.c
 msgid "skip move/rename errors"
 msgstr "omet els errors de moviment / canvi de nom"
 
+#: builtin/mv.c
 #, c-format
 msgid "destination '%s' is not a directory"
 msgstr "el destí «%s» no és un directori"
 
+#: builtin/mv.c
 #, c-format
 msgid "Checking rename of '%s' to '%s'\n"
 msgstr "S'està comprovant el canvi de nom de «%s» a «%s»\n"
 
+#: builtin/mv.c
 msgid "bad source"
 msgstr "origen incorrecte"
 
+#: builtin/mv.c
 msgid "destination exists"
 msgstr "el destí existeix"
 
+#: builtin/mv.c
 msgid "can not move directory into itself"
 msgstr "no es pot moure un directori a dins d'ell mateix"
 
+#: builtin/mv.c
 msgid "destination already exists"
 msgstr "la destinació ja existeix"
 
+#: builtin/mv.c
 msgid "source directory is empty"
 msgstr "el directori d'origen està buit"
 
+#: builtin/mv.c
 msgid "not under version control"
 msgstr "no està sota control de versions"
 
+#: builtin/mv.c
 msgid "conflicted"
 msgstr "en conflicte"
 
+#: builtin/mv.c
 #, c-format
 msgid "overwriting '%s'"
 msgstr "s'està sobreescrivint «%s»"
 
+#: builtin/mv.c
 msgid "Cannot overwrite"
 msgstr "No es pot sobreescriure"
 
+#: builtin/mv.c
 msgid "multiple sources for the same target"
 msgstr "múltiples orígens per al mateix destí"
 
+#: builtin/mv.c
 msgid "destination directory does not exist"
 msgstr "el directori destí no existeix"
 
+#: builtin/mv.c
 msgid "destination exists in the index"
 msgstr "el destí existeix a l'índex"
 
+#: builtin/mv.c
 #, c-format
 msgid "%s, source=%s, destination=%s"
 msgstr "%s, origen=%s, destí=%s"
 
+#: builtin/mv.c
 #, c-format
 msgid "Renaming %s to %s\n"
 msgstr "S'està canviant el nom de %s a %s\n"
 
+#: builtin/mv.c builtin/remote.c
 #, c-format
 msgid "renaming '%s' failed"
 msgstr "el canvi del nom de «%s» ha fallat"
 
+#: builtin/name-rev.c
 msgid "git name-rev [<options>] <commit>..."
 msgstr "git name-rev [<opcions>] <comissió>..."
 
+#: builtin/name-rev.c
 msgid "git name-rev [<options>] --all"
 msgstr "git name-rev [<opcions>] --all"
 
+#: builtin/name-rev.c
 msgid "git name-rev [<options>] --annotate-stdin"
 msgstr "git name-rev [<opcions>] --annotate-stdin"
 
+#: builtin/name-rev.c
 msgid "print only ref-based names (no object names)"
 msgstr "imprimeix només els noms basats en referències (no els noms d'objecte)"
 
+#: builtin/name-rev.c
 msgid "only use tags to name the commits"
 msgstr "només usa les etiquetes per a anomenar les comissions"
 
+#: builtin/name-rev.c
 msgid "only use refs matching <pattern>"
 msgstr "només usa les referències que coincideixin amb <patró>"
 
+#: builtin/name-rev.c
 msgid "ignore refs matching <pattern>"
 msgstr "ignora les referències que coincideixin amb <patró>"
 
+#: builtin/name-rev.c
 msgid "list all commits reachable from all refs"
 msgstr "llista totes les comissions abastables de totes les referències"
 
+#: builtin/name-rev.c
 msgid "deprecated: use --annotate-stdin instead"
 msgstr "obsolet: useu en comptes --annotate-stdin"
 
+#: builtin/name-rev.c
 msgid "annotate text from stdin"
 msgstr "anota el text de stdin"
 
+#: builtin/name-rev.c
 msgid "allow to print `undefined` names (default)"
 msgstr "permet imprimir els noms «undefined» (per defecte)"
 
+#: builtin/name-rev.c
 msgid "dereference tags in the input (internal use)"
 msgstr "desreferencia les etiquetes en l'entrada (ús intern)"
 
+#: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] [list [<object>]]"
 msgstr "git notes [--ref <referència-de-notes>] [llista [<objecte>]]"
 
+#: builtin/notes.c
 msgid ""
 "git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
 "separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
 "| -C) <object>] [<object>]"
 msgstr ""
 "git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
-"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
-"| -C) <object>] [<object>]"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <fitxer> | (-"
+"c | -C) <object>] [<object>]"
 
+#: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
 msgstr ""
-"git notes [--ref <referència-de-notes>] copy [-f] <d'objecte> <a-objecte>"
+"git notes [--ref <referència-de-notes>] copy [-f] <objecte-de> <objecte-a>"
 
+#: builtin/notes.c
 msgid ""
 "git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
 "separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
 "| -C) <object>] [<object>]"
 msgstr ""
 "git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
-"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
-"| -C) <object>] [<object>]"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <fitxer> | (-"
+"c | -C) <objecte>] [<objecte>]"
 
+#: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
 msgstr ""
 "git notes [--ref <referència-de-notes>] edit [--allow-empty] [<objecte>]"
 
+#: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] show [<object>]"
 msgstr "git notes [--ref <referència-de-notes>] show [<objecte>]"
 
+#: builtin/notes.c
 msgid ""
 "git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"
 msgstr ""
 "git notes [--ref <referència-de-notes>] merge [-v | -q] [-s <estratègia>] "
 "<referència-de-notes>"
 
+#: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] remove [<object>...]"
 msgstr "git notes [--ref <referència-de-notes>] remove [<objecte>...]"
 
+#: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] prune [-n] [-v]"
 msgstr "git notes [--ref <referència-de-notes>] prune [-n] [-v]"
 
+#: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] get-ref"
 msgstr "git notes [--ref <referència-de-notes>] get-ref"
 
+#: builtin/notes.c
 msgid "git notes [list [<object>]]"
 msgstr "git notes [llista [<objecte>]]"
 
+#: builtin/notes.c
 msgid "git notes add [<options>] [<object>]"
 msgstr "git notes add [<opcions>] [<objecte>]"
 
+#: builtin/notes.c
 msgid "git notes copy [<options>] <from-object> <to-object>"
-msgstr "git notes copy [<opcions>] <d'objecte> <a-objecte>"
+msgstr "git notes copy [<opcions>] <objecte-de> <objecte-a>"
 
+#: builtin/notes.c
 msgid "git notes copy --stdin [<from-object> <to-object>]..."
-msgstr "git notes copy --stdin [<d'objecte> <a-objecte>]..."
+msgstr "git notes copy --stdin [<objecte-de> <objecte-a>]..."
 
+#: builtin/notes.c
 msgid "git notes append [<options>] [<object>]"
 msgstr "git notes append [<opcions>] [<objecte>]"
 
+#: builtin/notes.c
 msgid "git notes edit [<object>]"
 msgstr "git notes edit [<objecte>]"
 
+#: builtin/notes.c
 msgid "git notes show [<object>]"
 msgstr "git notes show [<objecte>]"
 
+#: builtin/notes.c
 msgid "git notes merge [<options>] <notes-ref>"
 msgstr "git notes merge [<opcions>] <referència-de-notes>"
 
+#: builtin/notes.c
 msgid "git notes merge --commit [<options>]"
 msgstr "git notes merge --commit [<opcions>]"
 
+#: builtin/notes.c
 msgid "git notes merge --abort [<options>]"
 msgstr "git notes merge --abort [<opcions>]"
 
+#: builtin/notes.c
 msgid "git notes remove [<object>]"
 msgstr "git notes remove [<objecte>]"
 
+#: builtin/notes.c
 msgid "git notes prune [<options>]"
 msgstr "git notes prune [<opcions>]"
 
+#: builtin/notes.c
 msgid "Write/edit the notes for the following object:"
 msgstr "Escriviu/editeu les notes per l'objecte següent:"
 
-#, c-format
-msgid "unable to start 'show' for object '%s'"
-msgstr "no s'ha pogut iniciar «show» per a l'objecte «%s»"
-
+#: builtin/notes.c
 msgid "could not read 'show' output"
 msgstr "no s'ha pogut llegir la sortida de «show»"
 
+#: builtin/notes.c
 #, c-format
 msgid "failed to finish 'show' for object '%s'"
 msgstr "s'ha produït un error en finalitzar «show» per a l'objecte «%s»"
 
+#: builtin/notes.c
 msgid "please supply the note contents using either -m or -F option"
 msgstr ""
 "especifiqueu el contingut de la nota fent servir l'opció -m o l'opció -F"
 
+#: builtin/notes.c
 msgid "unable to write note object"
 msgstr "no s'ha pogut escriure l'objecte de nota"
 
+#: builtin/notes.c
 #, c-format
 msgid "the note contents have been left in %s"
 msgstr "s'han deixat els continguts de la nota en %s"
 
+#: builtin/notes.c builtin/tag.c
 #, c-format
 msgid "could not open or read '%s'"
 msgstr "no s'ha pogut obrir o llegir «%s»"
 
+#: builtin/notes.c
 #, c-format
 msgid "failed to resolve '%s' as a valid ref."
 msgstr "s'ha produït un error en resoldre «%s» com a referència vàlida."
 
+#: builtin/notes.c
 #, c-format
 msgid "failed to read object '%s'."
 msgstr "s'ha produït un error en llegir l'objecte «%s»."
 
+#: builtin/notes.c
 #, c-format
 msgid "cannot read note data from non-blob object '%s'."
 msgstr "no es poden llegir les dades de node de l'objecte no de blob «%s»."
 
+#: builtin/notes.c
 #, c-format
 msgid "failed to copy notes from '%s' to '%s'"
 msgstr "s'ha produït un error en copiar les notes de «%s» a «%s»"
@@ -8890,41 +11405,53 @@
 #. TRANSLATORS: the first %s will be replaced by a git
 #. notes command: 'add', 'merge', 'remove', etc.
 #.
+#: builtin/notes.c
 #, c-format
 msgid "refusing to %s notes in %s (outside of refs/notes/)"
 msgstr "s'està refusant %s les notes en %s (fora de refs/notes/)"
 
+#: builtin/notes.c
 #, c-format
 msgid "no note found for object %s."
 msgstr "no s'ha trobat cap nota per a l'objecte %s."
 
+#: builtin/notes.c
 msgid "note contents as a string"
 msgstr "anota els continguts com a cadena"
 
+#: builtin/notes.c
 msgid "note contents in a file"
 msgstr "anota els continguts en un fitxer"
 
+#: builtin/notes.c
 msgid "reuse and edit specified note object"
 msgstr "reusa i edita l'objecte de nota especificat"
 
+#: builtin/notes.c
 msgid "reuse specified note object"
 msgstr "reusa l'objecte de nota especificat"
 
+#: builtin/notes.c
 msgid "allow storing empty note"
 msgstr "permet l'emmagatzematge d'una nota buida"
 
+#: builtin/notes.c
 msgid "replace existing notes"
 msgstr "reemplaça les notes existents"
 
+#: builtin/notes.c
 msgid "<paragraph-break>"
 msgstr "<paragraph-break>"
 
+#: builtin/notes.c
 msgid "insert <paragraph-break> between paragraphs"
 msgstr "insereix <paragraph-break> entre paràgrafs"
 
+#: builtin/notes.c
 msgid "remove unnecessary whitespace"
 msgstr "elimina l'espai en blanc innecessari"
 
+#: builtin/notes.c
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -8933,24 +11460,30 @@
 "No es poden afegir les notes. S'han trobat notes existents de l'objecte %s. "
 "Useu «-f» per a sobreescriure les notes existents"
 
+#: builtin/notes.c
 #, c-format
 msgid "Overwriting existing notes for object %s\n"
 msgstr "S'estan sobreescrivint les notes existents de l'objecte %s\n"
 
+#: builtin/notes.c
 #, c-format
 msgid "Removing note for object %s\n"
 msgstr "S'està eliminant la nota de l'objecte %s\n"
 
+#: builtin/notes.c
 msgid "read objects from stdin"
 msgstr "llegeix els objectes des de stdin"
 
+#: builtin/notes.c
 msgid "load rewriting config for <command> (implies --stdin)"
 msgstr ""
 "carrega la configuració de reescriptura per a <ordre> (implica --stdin)"
 
+#: builtin/notes.c
 msgid "too few arguments"
 msgstr "massa pocs arguments"
 
+#: builtin/notes.c
 #, c-format
 msgid ""
 "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -8959,10 +11492,12 @@
 "No es poden copiar les notes. S'han trobat notes existents de l'objecte %s. "
 "Useu «-f» per a sobreescriure les notes existents"
 
+#: builtin/notes.c
 #, c-format
 msgid "missing notes on source object %s. Cannot copy."
 msgstr "manquen notes a l'objecte font %s. No es pot copiar."
 
+#: builtin/notes.c
 #, c-format
 msgid ""
 "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
@@ -8971,41 +11506,53 @@
 "Es desaconsellen les opcions -m/-F/-c/-C en favor de la subordre «edit».\n"
 "Useu «git notes add -f -m/-F/-c/-C» en lloc d'això.\n"
 
+#: builtin/notes.c
 msgid "failed to delete ref NOTES_MERGE_PARTIAL"
 msgstr "s'ha produït un error en suprimir la referència NOTES_MERGE_PARTIAL"
 
+#: builtin/notes.c
 msgid "failed to delete ref NOTES_MERGE_REF"
 msgstr "s'ha produït un error en suprimir la referència NOTES_MERGE_REF"
 
+#: builtin/notes.c
 msgid "failed to remove 'git notes merge' worktree"
 msgstr ""
 "s'ha produït un error en eliminar l'arbre de treball de «git notes merge»"
 
+#: builtin/notes.c
 msgid "failed to read ref NOTES_MERGE_PARTIAL"
 msgstr "s'ha produït un error en llegir la referència NOTES_MERGE_PARTIAL"
 
+#: builtin/notes.c
 msgid "could not find commit from NOTES_MERGE_PARTIAL."
 msgstr "no s'ha pogut trobar cap comissió de NOTES_MERGE_PARTIAL."
 
+#: builtin/notes.c
 msgid "could not parse commit from NOTES_MERGE_PARTIAL."
 msgstr "no s'ha pogut analitzar la comissió de NOTES_MERGE_PARTIAL."
 
+#: builtin/notes.c
 msgid "failed to resolve NOTES_MERGE_REF"
 msgstr "s'ha produït un error en resoldre NOTES_MERGE_REF"
 
+#: builtin/notes.c
 msgid "failed to finalize notes merge"
 msgstr "s'ha produït un error en finalitzar la fusió de notes"
 
+#: builtin/notes.c
 #, c-format
 msgid "unknown notes merge strategy %s"
 msgstr "estratègia de fusió de notes desconeguda %s"
 
+#: builtin/notes.c
 msgid "General options"
 msgstr "Opcions generals"
 
+#: builtin/notes.c
 msgid "Merge options"
 msgstr "Opcions de fusió"
 
+#: builtin/notes.c
 msgid ""
 "resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
 "cat_sort_uniq)"
@@ -9013,38 +11560,48 @@
 "resol els conflictes de nota usant l'estratègia donada (manual/ours/theirs/"
 "union/cat_sort_uniq)"
 
+#: builtin/notes.c
 msgid "Committing unmerged notes"
 msgstr "S'estan cometent les notes sense fusionar"
 
+#: builtin/notes.c
 msgid "finalize notes merge by committing unmerged notes"
 msgstr "finalitza la fusió de notes cometent les notes sense fusionar"
 
+#: builtin/notes.c
 msgid "Aborting notes merge resolution"
 msgstr "S'està avortant la resolució de fusió de notes"
 
+#: builtin/notes.c
 msgid "abort notes merge"
 msgstr "avorta la fusió de notes"
 
+#: builtin/notes.c
 msgid "cannot mix --commit, --abort or -s/--strategy"
 msgstr "no es pot combinar --commit, --abort i -s/--strategy"
 
+#: builtin/notes.c
 msgid "must specify a notes ref to merge"
 msgstr "cal especificar una referència de notes a fusionar"
 
+#: builtin/notes.c
 #, c-format
 msgid "unknown -s/--strategy: %s"
 msgstr "-s/--strategy desconeguda: %s"
 
+#: builtin/notes.c
 #, c-format
 msgid "a notes merge into %s is already in-progress at %s"
 msgstr "una fusió de notes a %s ja està en curs a %s"
 
+#: builtin/notes.c
 #, c-format
 msgid "failed to store link to current notes ref (%s)"
 msgstr ""
 "s'ha produït un error en emmagatzemar l'enllaç a la referència de notes "
 "actual (%s)"
 
+#: builtin/notes.c
 #, c-format
 msgid ""
 "Automatic notes merge failed. Fix conflicts in %s and commit the result with "
@@ -9055,44 +11612,56 @@
 "cometeu el resultat amb «git notes merge --commit», o avorteu la fusió amb "
 "«git notes merge --abort».\n"
 
+#: builtin/notes.c builtin/tag.c
 #, c-format
 msgid "Failed to resolve '%s' as a valid ref."
 msgstr "S'ha produït un error en resoldre «%s» com a referència vàlida."
 
+#: builtin/notes.c
 #, c-format
 msgid "Object %s has no note\n"
 msgstr "L'objecte %s no té cap nota\n"
 
+#: builtin/notes.c
 msgid "attempt to remove non-existent note is not an error"
 msgstr "l'intent d'eliminar una nota no existent no és un error"
 
+#: builtin/notes.c
 msgid "read object names from the standard input"
 msgstr "llegeix els noms d'objecte des de l'entrada estàndard"
 
+#: builtin/notes.c builtin/prune.c builtin/worktree.c
 msgid "do not remove, show only"
 msgstr "no eliminis, només mostra"
 
+#: builtin/notes.c
 msgid "report pruned notes"
 msgstr "informa de notes podades"
 
+#: builtin/notes.c
 msgid "notes-ref"
 msgstr "referència de notes"
 
+#: builtin/notes.c
 msgid "use notes from <notes-ref>"
 msgstr "usa les notes de <referència-de-notes>"
 
+#: builtin/notes.c builtin/remote.c parse-options.c
 #, c-format
 msgid "unknown subcommand: `%s'"
 msgstr "subordre desconeguda: «%s»"
 
+#: builtin/pack-objects.c
 msgid "git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]"
 msgstr "git pack-objects --stdout [<opcions>] [< <ref-list> | < <object-list>]"
 
+#: builtin/pack-objects.c
 msgid ""
 "git pack-objects [<options>] <base-name> [< <ref-list> | < <object-list>]"
 msgstr ""
 "git pack-objects [<opcions>] <base-name> [< <ref-list> | < <object-list>]"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
@@ -9101,108 +11670,135 @@
 "write_reuse_object: no s'ha pogut localitzar %s, s'esperava a la posició "
 "%<PRIuMAX> al paquet %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "bad packed object CRC for %s"
 msgstr "CRC de l'objecte empaquetat malmès per a %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "corrupt packed object for %s"
 msgstr "objecte empaquetat corrupte per a %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "recursive delta detected for object %s"
 msgstr "diferència recursiva detectada per a l'objecte  %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "ordered %u objects, expected %<PRIu32>"
 msgstr "ordenats %u objectes, s'esperaven %<PRIu32>"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "expected object at offset %<PRIuMAX> in pack %s"
 msgstr "objecte esperat a la posició %<PRIuMAX> al paquet %s"
 
+#: builtin/pack-objects.c
 msgid "disabling bitmap writing, packs are split due to pack.packSizeLimit"
 msgstr ""
 "s'està inhabilitant l'escriptura de mapes de bits, es divideixen els paquets "
 "a causa de pack.packSizeLimit"
 
+#: builtin/pack-objects.c
 msgid "Writing objects"
 msgstr "S'estan escrivint els objectes"
 
+#: builtin/pack-objects.c builtin/update-index.c
 #, c-format
 msgid "failed to stat %s"
 msgstr "s'ha produït un error en fer stat a %s"
 
+#: builtin/pack-objects.c object-file.c
 #, c-format
 msgid "failed utime() on %s"
 msgstr "ha fallat utime() a %s"
 
+#: builtin/pack-objects.c
 msgid "failed to write bitmap index"
 msgstr "s'ha produït un error en escriure l'índex de mapa de bits"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "wrote %<PRIu32> objects while expecting %<PRIu32>"
 msgstr "escrits %<PRIu32> objectes mentre s'esperaven %<PRIu32>"
 
+#: builtin/pack-objects.c builtin/repack.c
 msgid "disabling bitmap writing, as some objects are not being packed"
 msgstr ""
 "s'està inhabilitant l'escriptura de mapes de bits, perquè alguns objectes no "
 "s'empaqueten"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "delta base offset overflow in pack for %s"
 msgstr "desbordament del desplaçament base de diferències en paquet per a %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "delta base offset out of bound for %s"
 msgstr "desplaçament base de diferències fora dels límits per a %s"
 
+#: builtin/pack-objects.c
 msgid "Counting objects"
 msgstr "S'estan comptant els objectes"
 
+#: builtin/pack-objects.c pack-bitmap.c
 #, c-format
 msgid "unable to get size of %s"
 msgstr "no s'ha pogut obtenir la mida de %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "unable to parse object header of %s"
 msgstr "no s'ha pogut analitzar la capçalera de l'objecte de %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "object %s cannot be read"
 msgstr "no es pot llegir l'objecte %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "object %s inconsistent object length (%<PRIuMAX> vs %<PRIuMAX>)"
 msgstr ""
 "l'objecte %s té una longitud d'objecte inconsistent (%<PRIuMAX> vs "
 "%<PRIuMAX>)"
 
+#: builtin/pack-objects.c
 msgid "suboptimal pack - out of memory"
 msgstr "paquet subòptim - sense memòria"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "Delta compression using up to %d threads"
 msgstr "Compressió de diferències usant fins a %d fils"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "unable to pack objects reachable from tag %s"
 msgstr "no s'han pogut empaquetar els objectes abastables des de l'etiqueta %s"
 
+#: builtin/pack-objects.c commit-graph.c
 #, c-format
 msgid "unable to get type of object %s"
 msgstr "no s'ha pogut obtenir el tipus de l'objecte: %s"
 
+#: builtin/pack-objects.c
 msgid "Compressing objects"
 msgstr "S'estan comprimint els objectes"
 
+#: builtin/pack-objects.c
 msgid "inconsistency with delta count"
 msgstr "inconsistència amb el comptador de diferències"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "invalid pack.allowPackReuse value: '%s'"
 msgstr "valor pack.allowPackReuse value no vàlid: «%s»"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid ""
 "value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
@@ -9211,6 +11807,7 @@
 "el valor de uploadpack.blobpackfileuri ha de tenir la forma «<object-hash> "
 "<pack-hash> <uri>» (s'ha rebut «%s»)"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid ""
 "object already configured in another uploadpack.blobpackfileuri (got '%s')"
@@ -9218,27 +11815,34 @@
 "l'objecte ja està configurat en un altre uploadpack.blobpackfileuri (s'ha "
 "rebut «%s»)"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "could not get type of object %s in pack %s"
 msgstr "no s'ha pogut obtenir el tipus de l'objecte %s al paquet %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "could not find pack '%s'"
 msgstr "no s'ha pogut trobar el paquet «%s»"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "packfile %s cannot be accessed"
 msgstr "no es pot accedir al fitxer de paquet %s"
 
+#: builtin/pack-objects.c
 msgid "Enumerating cruft objects"
 msgstr "S'estan enumerant els objectes superflus"
 
+#: builtin/pack-objects.c
 msgid "unable to add cruft objects"
 msgstr "no s'han pogut afegir els objectes superflus"
 
+#: builtin/pack-objects.c
 msgid "Traversing cruft objects"
 msgstr "S'estan recorrent els objectes superflus"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid ""
 "expected edge object ID, got garbage:\n"
@@ -9247,6 +11851,7 @@
 "s'esperava un identificador vora de l'objecte, s'ha rebut brossa:\n"
 " %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid ""
 "expected object ID, got garbage:\n"
@@ -9255,216 +11860,280 @@
 "s'esperava un identificador d'objecte, s'ha rebut brossa:\n"
 " %s"
 
+#: builtin/pack-objects.c reachable.c
 msgid "could not load cruft pack .mtimes"
 msgstr "no s'ha pogut carregar superflus del paquet superflu"
 
+#: builtin/pack-objects.c
 msgid "cannot open pack index"
 msgstr "no s'ha pogut obrir l'índex del paquet"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "loose object at %s could not be examined"
 msgstr "no s'ha pogut examinar l'objecte solt a %s"
 
+#: builtin/pack-objects.c
 msgid "unable to force loose object"
 msgstr "no s'ha pogut forçar l'objecte solt"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "not a rev '%s'"
 msgstr "«%s» no és una revisió"
 
+#: builtin/pack-objects.c builtin/rev-parse.c
 #, c-format
 msgid "bad revision '%s'"
 msgstr "revisió incorrecta «%s»"
 
+#: builtin/pack-objects.c
 msgid "unable to add recent objects"
 msgstr "no s'han pogut afegir els objectes recents"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "unsupported index version %s"
 msgstr "versió d'índex no compatible %s"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "bad index version '%s'"
 msgstr "versió d'índex incorrecta «%s»"
 
+#: builtin/pack-objects.c
 msgid "show progress meter during object writing phase"
 msgstr "mostra l'indicador de progrés durant la fase d'escriptura d'objectes"
 
+#: builtin/pack-objects.c
 msgid "similar to --all-progress when progress meter is shown"
 msgstr "similar a --all-progress quan l'indicador de progrés es mostra"
 
+#: builtin/pack-objects.c
 msgid "<version>[,<offset>]"
 msgstr "<versió>[,<desplaçament>]"
 
+#: builtin/pack-objects.c
 msgid "write the pack index file in the specified idx format version"
 msgstr ""
 "escriu el fitxer d'índex de paquet en la versió de format d'índex "
 "especificada"
 
+#: builtin/pack-objects.c
 msgid "maximum size of each output pack file"
 msgstr "mida màxima de cada fitxer empaquetat de sortida"
 
+#: builtin/pack-objects.c
 msgid "ignore borrowed objects from alternate object store"
 msgstr ""
 "ignora els objectes manllevats d'un emmagatzematge d'objectes alternatiu"
 
+#: builtin/pack-objects.c
 msgid "ignore packed objects"
 msgstr "ignora els objectes empaquetats"
 
+#: builtin/pack-objects.c
 msgid "limit pack window by objects"
 msgstr "limita la finestra d'empaquetament per objectes"
 
+#: builtin/pack-objects.c
 msgid "limit pack window by memory in addition to object limit"
 msgstr ""
 "limita la finestra d'empaquetament per memòria a més del límit d'objectes"
 
+#: builtin/pack-objects.c
 msgid "maximum length of delta chain allowed in the resulting pack"
 msgstr ""
 "longitud màxima de la cadena de diferències permesa en el paquet resultant"
 
+#: builtin/pack-objects.c
 msgid "reuse existing deltas"
 msgstr "reusa les diferències existents"
 
+#: builtin/pack-objects.c
 msgid "reuse existing objects"
 msgstr "reusa els objectes existents"
 
+#: builtin/pack-objects.c
 msgid "use OFS_DELTA objects"
 msgstr "usa objectes OFS_DELTA"
 
+#: builtin/pack-objects.c
 msgid "use threads when searching for best delta matches"
 msgstr "usa fils en cercar les millors coincidències de diferències"
 
+#: builtin/pack-objects.c
 msgid "do not create an empty pack output"
 msgstr "no creïs una emissió de paquet buit"
 
+#: builtin/pack-objects.c
 msgid "read revision arguments from standard input"
 msgstr "llegeix els arguments de revisió des de l'entrada estàndard"
 
+#: builtin/pack-objects.c
 msgid "limit the objects to those that are not yet packed"
 msgstr "limita els objectes a aquells que encara no estan empaquetats"
 
+#: builtin/pack-objects.c
 msgid "include objects reachable from any reference"
 msgstr "inclou els objectes abastables de qualsevol referència"
 
+#: builtin/pack-objects.c
 msgid "include objects referred by reflog entries"
 msgstr ""
 "inclou els objectes als quals facin referència les entrades del registre de "
 "referències"
 
+#: builtin/pack-objects.c
 msgid "include objects referred to by the index"
 msgstr "inclou els objectes als quals faci referència l'índex"
 
+#: builtin/pack-objects.c
 msgid "read packs from stdin"
 msgstr "llegeix els paquets des de stdin"
 
+#: builtin/pack-objects.c
 msgid "output pack to stdout"
 msgstr "emet el paquet a stdout"
 
+#: builtin/pack-objects.c
 msgid "include tag objects that refer to objects to be packed"
 msgstr ""
 "inclou els objectes d'etiqueta que facin referència als objectes a empaquetar"
 
+#: builtin/pack-objects.c
 msgid "keep unreachable objects"
 msgstr "retén els objectes inabastables"
 
+#: builtin/pack-objects.c
 msgid "pack loose unreachable objects"
 msgstr "empaqueta els objectes inabastables solts"
 
+#: builtin/pack-objects.c
 msgid "unpack unreachable objects newer than <time>"
 msgstr "desempaqueta els objectes inabastables més nous que <data>"
 
+#: builtin/pack-objects.c
 msgid "create a cruft pack"
 msgstr "crea un paquet superflu"
 
+#: builtin/pack-objects.c
 msgid "expire cruft objects older than <time>"
 msgstr "fes caducar els objectes superflus més antics que <data>"
 
+#: builtin/pack-objects.c
 msgid "use the sparse reachability algorithm"
 msgstr "utilitza l'algorisme d'accessibilitat dispers"
 
+#: builtin/pack-objects.c
 msgid "create thin packs"
 msgstr "crea paquets prims"
 
+#: builtin/pack-objects.c
 msgid "create packs suitable for shallow fetches"
 msgstr "crea paquets adequats per a les obtencions superficials"
 
+#: builtin/pack-objects.c
 msgid "ignore packs that have companion .keep file"
 msgstr "ignora els paquets que tinguin un fitxer .keep corresponent"
 
+#: builtin/pack-objects.c
 msgid "ignore this pack"
 msgstr "ignora aquest paquet"
 
+#: builtin/pack-objects.c
 msgid "pack compression level"
 msgstr "nivell de compressió de paquet"
 
+#: builtin/pack-objects.c
 msgid "do not hide commits by grafts"
 msgstr "no amaguis les comissions per empelt"
 
+#: builtin/pack-objects.c
 msgid "use a bitmap index if available to speed up counting objects"
 msgstr ""
 "usa un índex de mapa de bits, si està disponible, per a accelerar el "
 "recompte d'objectes"
 
+#: builtin/pack-objects.c
 msgid "write a bitmap index together with the pack index"
 msgstr "escriu un índex de mapa de bits juntament amb l'índex de paquet"
 
+#: builtin/pack-objects.c
 msgid "write a bitmap index if possible"
 msgstr "escriu un índex de mapa de bits si és possible"
 
+#: builtin/pack-objects.c
 msgid "handling for missing objects"
 msgstr "gestió dels objectes absents"
 
+#: builtin/pack-objects.c
 msgid "do not pack objects in promisor packfiles"
 msgstr "no empaquetis els objectes als fitxers de paquet «promisor»"
 
+#: builtin/pack-objects.c
 msgid "respect islands during delta compression"
 msgstr "respecta les illes durant la compressió delta"
 
+#: builtin/pack-objects.c
 msgid "protocol"
 msgstr "protocol"
 
+#: builtin/pack-objects.c
 msgid "exclude any configured uploadpack.blobpackfileuri with this protocol"
 msgstr ""
 "exclou qualsevol uploadpack.blobpackfileuri configurat amb aquest protocol"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
 msgstr "la profunditat de la cadena delta %d és massa profunda, forçant %d"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid "pack.deltaCacheLimit is too high, forcing %d"
 msgstr "pack.deltaCacheLimit és massa alt, forçant %d"
 
+#: builtin/pack-objects.c config.c
 #, c-format
 msgid "bad pack compression level %d"
 msgstr "nivell de compressió de paquet %d erroni"
 
+#: builtin/pack-objects.c
 msgid "--max-pack-size cannot be used to build a pack for transfer"
 msgstr ""
 "--max-pack-size no es pot utilitzar per a construir un paquet per a la "
 "transferència"
 
+#: builtin/pack-objects.c
 msgid "minimum pack size limit is 1 MiB"
 msgstr "el límit mínim de mida del paquet és 1 MiB"
 
+#: builtin/pack-objects.c
 msgid "--thin cannot be used to build an indexable pack"
 msgstr "--thin no es pot utilitzar per a construir un paquet indexable"
 
+#: builtin/pack-objects.c
 msgid "cannot use --filter with --stdin-packs"
 msgstr "no es pot utilitzar --filter sense --stdin-packs"
 
+#: builtin/pack-objects.c
 msgid "cannot use internal rev list with --stdin-packs"
 msgstr "no es pot utilitzar la llista de revisió interna amb --stdin-packs"
 
+#: builtin/pack-objects.c
 msgid "cannot use internal rev list with --cruft"
 msgstr "no es pot utilitzar la llista de revisió interna amb --cruft"
 
+#: builtin/pack-objects.c
 msgid "cannot use --stdin-packs with --cruft"
 msgstr "no es pot --stdin-packs amb --cruft"
 
+#: builtin/pack-objects.c
 msgid "Enumerating objects"
 msgstr "S'estan enumerant els objectes"
 
+#: builtin/pack-objects.c
 #, c-format
 msgid ""
 "Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
@@ -9473,6 +12142,7 @@
 "Total %<PRIu32> (%<PRIu32> diferències), reusats %<PRIu32> (%<PRIu32> "
 "diferències), paquets reusats %<PRIu32> (de %<PRIuMAX>)"
 
+#: builtin/pack-redundant.c
 msgid ""
 "'git pack-redundant' is nominated for removal.\n"
 "If you still use this command, please add an extra\n"
@@ -9486,91 +12156,124 @@
 "i feu-nos saber que encara l'useu enviant un correu electrònic\n"
 "a <git@vger.kernel.org>.  Gràcies.\n"
 
+#: builtin/pack-redundant.c
 msgid "refusing to run without --i-still-use-this"
 msgstr "es rebutja a executar sense --i-still-use-this"
 
+#: builtin/pack-refs.c
 msgid ""
-"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude "
 "<pattern>]"
 msgstr ""
-"git pack-refs [--all] [--no-prune] [--include <patró>] [--exclude <patró>]"
+"git pack-refs [--all] [--no-prune] [--auto] [--include <patró>] [--exclude "
+"<patró>]"
 
+#: builtin/pack-refs.c
 msgid "pack everything"
 msgstr "empaqueta-ho tot"
 
+#: builtin/pack-refs.c
 msgid "prune loose refs (default)"
 msgstr "poda les referències soltes (per defecte)"
 
+#: builtin/pack-refs.c
+msgid "auto-pack refs as needed"
+msgstr "auto-empaqueta referències si cal"
+
+#: builtin/pack-refs.c
 msgid "references to include"
 msgstr "referències a incloure"
 
+#: builtin/pack-refs.c
 msgid "references to exclude"
 msgstr "referències a excloure"
 
+#: builtin/patch-id.c
 msgid "git patch-id [--stable | --unstable | --verbatim]"
 msgstr "git patch-id [--stable | --unstable | --verbatim]"
 
+#: builtin/patch-id.c
 msgid "use the unstable patch-id algorithm"
 msgstr "utilitza l'algorisme inestable de patch-id"
 
+#: builtin/patch-id.c
 msgid "use the stable patch-id algorithm"
 msgstr "utilitza l'algorisme estable de patch-id"
 
+#: builtin/patch-id.c
 msgid "don't strip whitespace from the patch"
 msgstr "no eliminis els espais en blanc del pedaç"
 
+#: builtin/prune.c
 msgid "git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"
-msgstr "git prune [-n] [-v] [--progress] [--expire <data>] [--] [<head>...]"
+msgstr "git prune [-n] [-v] [--progress] [--expire <data>] [--] [<cap>...]"
 
+#: builtin/prune.c
 msgid "report pruned objects"
 msgstr "informa d'objectes podats"
 
+#: builtin/prune.c
 msgid "expire objects older than <time>"
 msgstr "fes caducar els objectes més antics que <data>"
 
+#: builtin/prune.c
 msgid "limit traversal to objects outside promisor packfiles"
 msgstr ""
 "limita el recorregut als objectes fora dels fitxers de paquet «promisor»"
 
+#: builtin/prune.c
 msgid "cannot prune in a precious-objects repo"
 msgstr "no es pot podar en un repositori d'objectes preciosos"
 
+#: builtin/pull.c
 msgid "git pull [<options>] [<repository> [<refspec>...]]"
-msgstr "git pull [<opcions>] [<repositori> [<especificació-de-referència>...]]"
+msgstr "git pull [<opcions>] [<repositori> [<especificació-referència>...]]"
 
+#: builtin/pull.c
 msgid "control for recursive fetching of submodules"
 msgstr "controla l'obtenció recursiva de submòduls"
 
+#: builtin/pull.c
 msgid "Options related to merging"
 msgstr "Opcions relacionades amb fusionar"
 
+#: builtin/pull.c
 msgid "incorporate changes by rebasing rather than merging"
 msgstr "incorpora els canvis fent «rebase» en lloc de fusionar"
 
+#: builtin/pull.c builtin/revert.c
 msgid "allow fast-forward"
 msgstr "permet l'avanç ràpid"
 
+#: builtin/pull.c
 msgid "control use of pre-merge-commit and commit-msg hooks"
 msgstr "controla l'ús dels lligams pre-merge-commit i commit-msg"
 
+#: builtin/pull.c parse-options.h
 msgid "automatically stash/stash pop before and after"
 msgstr "fes «stash» i «stash pop» automàticament abans i després"
 
+#: builtin/pull.c
 msgid "Options related to fetching"
 msgstr "Opcions relacionades amb obtenir"
 
+#: builtin/pull.c
 msgid "force overwrite of local branch"
 msgstr "força la sobreescriptura de la branca local"
 
+#: builtin/pull.c
 msgid "number of submodules pulled in parallel"
 msgstr "nombre de submòduls baixats en paral·lel"
 
+#: builtin/pull.c parse-options.h
 msgid "use IPv4 addresses only"
 msgstr "usa només adreces IPv4"
 
+#: builtin/pull.c parse-options.h
 msgid "use IPv6 addresses only"
 msgstr "usa només adreces IPv6"
 
+#: builtin/pull.c
 msgid ""
 "There is no candidate for rebasing against among the refs that you just "
 "fetched."
@@ -9578,11 +12281,13 @@
 "No hi ha cap candidat sobre el qual fer «rebase» entre les referències que "
 "acabeu d'obtenir."
 
+#: builtin/pull.c
 msgid ""
 "There are no candidates for merging among the refs that you just fetched."
 msgstr ""
 "No hi ha candidats per a fusionar entre les referències que acabeu d'obtenir."
 
+#: builtin/pull.c
 msgid ""
 "Generally this means that you provided a wildcard refspec which had no\n"
 "matches on the remote end."
@@ -9590,6 +12295,7 @@
 "Generalment això vol dir que heu proveït una especificació de\n"
 "referència de comodí que no tenia cap coincidència en el costat remot."
 
+#: builtin/pull.c
 #, c-format
 msgid ""
 "You asked to pull from the remote '%s', but did not specify\n"
@@ -9600,33 +12306,42 @@
 "Perquè aquest no és el remot configurat per defecte per a la vostra\n"
 "branca actual, heu d'especificar una branca en la línia d'ordres."
 
+#: builtin/pull.c builtin/rebase.c
 msgid "You are not currently on a branch."
 msgstr "Actualment no sou en cap branca."
 
+#: builtin/pull.c
 msgid "Please specify which branch you want to rebase against."
 msgstr "Especifiqueu sobre quina branca voleu fer «rebase»."
 
+#: builtin/pull.c
 msgid "Please specify which branch you want to merge with."
 msgstr "Especifiqueu amb quina branca voleu fusionar."
 
+#: builtin/pull.c
 msgid "See git-pull(1) for details."
 msgstr "Vegeu git-pull(1) per a més informació."
 
+#: builtin/pull.c builtin/rebase.c
 msgid "<remote>"
 msgstr "<remot>"
 
+#: builtin/pull.c scalar.c
 msgid "<branch>"
 msgstr "<branca>"
 
+#: builtin/pull.c builtin/rebase.c
 msgid "There is no tracking information for the current branch."
 msgstr "No hi ha cap informació de seguiment per a la branca actual."
 
+#: builtin/pull.c
 msgid ""
 "If you wish to set tracking information for this branch you can do so with:"
 msgstr ""
 "Si voleu establir la informació de seguiment per a aquesta branca, podeu fer-"
 "ho amb:"
 
+#: builtin/pull.c
 #, c-format
 msgid ""
 "Your configuration specifies to merge with the ref '%s'\n"
@@ -9635,13 +12350,16 @@
 "La vostra configuració especifica fusionar amb la referència «%s»\n"
 "del remot, però no s'ha obtingut tal referència."
 
+#: builtin/pull.c
 #, c-format
 msgid "unable to access commit %s"
 msgstr "no s'ha pogut accedir a la comissió %s"
 
+#: builtin/pull.c
 msgid "ignoring --verify-signatures for rebase"
 msgstr "s'està ignorant --verify-signatures en fer «rebase»"
 
+#: builtin/pull.c
 msgid ""
 "You have divergent branches and need to specify how to reconcile them.\n"
 "You can do so by running one of the following commands sometime before\n"
@@ -9671,26 +12389,31 @@
 "--no-rebase o --ff-only en la línia d'ordres per a sobreescriure el valor\n"
 "per defecte de la configuració en aquesta execució.\n"
 
+#: builtin/pull.c
 msgid "Updating an unborn branch with changes added to the index."
 msgstr ""
 "S'està actualitzant una branca no nascuda amb canvis afegits a l'índex."
 
+#: builtin/pull.c
 msgid "pull with rebase"
 msgstr "baixar fent «rebase»"
 
+#: builtin/pull.c builtin/rebase.c
 msgid "Please commit or stash them."
 msgstr "Cometeu-los o emmagatzemeu-los."
 
+#: builtin/pull.c
 #, c-format
 msgid ""
 "fetch updated the current branch head.\n"
 "fast-forwarding your working tree from\n"
 "commit %s."
 msgstr ""
-"l'obtenció ha actualitzat HEAD de la branca actual.\n"
+"l'obtenció ha actualitzat el HEAD de la branca actual.\n"
 "s'està avançant ràpidament el vostre arbre de treball des de\n"
 "la comissió %s."
 
+#: builtin/pull.c
 #, c-format
 msgid ""
 "Cannot fast-forward your working tree.\n"
@@ -9708,32 +12431,41 @@
 "$ git reset --hard\n"
 "per a recuperar."
 
+#: builtin/pull.c
 msgid "Cannot merge multiple branches into empty head."
 msgstr "No es poden fusionar múltiples branques a una HEAD buida."
 
+#: builtin/pull.c
 msgid "Cannot rebase onto multiple branches."
 msgstr "No es pot fer «rebase» sobre múltiples branques."
 
+#: builtin/pull.c
 msgid "Cannot fast-forward to multiple branches."
 msgstr "No es pot fer un avançament ràpid a branques múltiples."
 
+#: builtin/pull.c
 msgid "Need to specify how to reconcile divergent branches."
 msgstr "Cal especificar com reconciliar les branques divergents."
 
+#: builtin/pull.c
 msgid "cannot rebase with locally recorded submodule modifications"
 msgstr ""
 "no es pot fer «rebase» amb modificacions als submòduls enregistrades "
 "localment"
 
+#: builtin/push.c
 msgid "git push [<options>] [<repository> [<refspec>...]]"
-msgstr "git push [<opcions>] [<repositori> [<especificació-de-referència>...]]"
+msgstr "git push [<opcions>] [<repositori> [<especificació-referència>...]]"
 
+#: builtin/push.c
 msgid "tag shorthand without <tag>"
-msgstr "abreviatura d'etiqueta sense <tag>"
+msgstr "abreviatura d'etiqueta sense <etiqueta>"
 
+#: builtin/push.c
 msgid "--delete only accepts plain target ref names"
 msgstr "--delete només accepta noms de referència de destí senzills"
 
+#: builtin/push.c
 msgid ""
 "\n"
 "To choose either option permanently, see push.default in 'git help config'.\n"
@@ -9742,6 +12474,7 @@
 "Per a triar qualsevol de les opcions permanentment, vegeu push.default a "
 "«git help config».\n"
 
+#: builtin/push.c
 msgid ""
 "\n"
 "To avoid automatically configuring an upstream branch when its name\n"
@@ -9753,6 +12486,7 @@
 "no coincideix amb el de la branca local, vegeu l'opció «simple» de\n"
 "«branch.autoSetupMerge» a «git help config».\n"
 
+#: builtin/push.c
 #, c-format
 msgid ""
 "The upstream branch of your current branch does not match\n"
@@ -9777,6 +12511,7 @@
 "    git push %s HEAD\n"
 "%s%s"
 
+#: builtin/push.c
 #, c-format
 msgid ""
 "You are not currently on a branch.\n"
@@ -9791,6 +12526,7 @@
 "\n"
 "    git push %s HEAD:<nom-de-branca-remota>\n"
 
+#: builtin/push.c
 msgid ""
 "\n"
 "To have this happen automatically for branches without a tracking\n"
@@ -9801,6 +12537,7 @@
 "seguiment\n"
 "font, vegeu «push.autoSetupRemote» a «git help config».\n"
 
+#: builtin/push.c
 #, c-format
 msgid ""
 "The current branch %s has no upstream branch.\n"
@@ -9815,17 +12552,20 @@
 "    git push --set-upstream %s %s\n"
 "%s"
 
+#: builtin/push.c
 #, c-format
 msgid "The current branch %s has multiple upstream branches, refusing to push."
 msgstr ""
 "La branca actual %s té múltiples branques fonts, s'està refusant pujar."
 
+#: builtin/push.c
 msgid ""
 "You didn't specify any refspecs to push, and push.default is \"nothing\"."
 msgstr ""
 "No heu especificat cap especificació de referència a pujar, i push.default "
 "és «nothing»."
 
+#: builtin/push.c
 #, c-format
 msgid ""
 "You are pushing to remote '%s', which is not the upstream of\n"
@@ -9836,6 +12576,7 @@
 "branca actual «%s», sense dir-me què pujar per a actualitzar\n"
 "quina branca remota."
 
+#: builtin/push.c
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
 "its remote counterpart. If you want to integrate the remote changes,\n"
@@ -9847,6 +12588,7 @@
 "remots useu «git pull» abans de tornar a pujar.\n"
 "Vegeu «Note about fast-forwards» a «git push --help» per a més detalls."
 
+#: builtin/push.c
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
 "counterpart. If you want to integrate the remote changes, use 'git pull'\n"
@@ -9858,6 +12600,7 @@
 "utilitzeu «git pull» abans de tornar a pujar.\n"
 "Vegeu «Note about fast-forwards» a «git push --help» per a més detalls."
 
+#: builtin/push.c
 msgid ""
 "Updates were rejected because the remote contains work that you do not\n"
 "have locally. This is usually caused by another repository pushing to\n"
@@ -9867,15 +12610,17 @@
 msgstr ""
 "Les actualitzacions s'han rebutjat perquè el remot conté canvis que no "
 "teniu\n"
-"localment. Això sol ser causat per un altre repositori que a pujat a\n"
+"localment. Això sol ser causat per un altre repositori que ha pujat a\n"
 "la mateixa referència. Si voleu integrar els canvis remots, utilitzeu\n"
 "«git pull» abans de tornar a pujar.\n"
 "Vegeu «Note about fast-forwards» a «git push --help» per a més detalls."
 
+#: builtin/push.c
 msgid "Updates were rejected because the tag already exists in the remote."
 msgstr ""
 "S'han rebutjat les actualitzacions perquè l'etiqueta ja existeix en el remot."
 
+#: builtin/push.c
 msgid ""
 "You cannot update a remote ref that points at a non-commit object,\n"
 "or update a remote ref to make it point at a non-commit object,\n"
@@ -9886,6 +12631,7 @@
 "a fer que assenyali un objecte no de comissió, sense usar l'opció\n"
 "«--force».\n"
 
+#: builtin/push.c
 msgid ""
 "Updates were rejected because the tip of the remote-tracking branch has\n"
 "been updated since the last checkout. If you want to integrate the\n"
@@ -9897,14 +12643,17 @@
 "canvis remots, utilitzeu «git pull» abans de tornar a pujar.\n"
 "Vegeu «Note about fast-forwards» a «git push --help» per a més detalls."
 
+#: builtin/push.c
 #, c-format
 msgid "Pushing to %s\n"
 msgstr "S'està pujant a %s\n"
 
+#: builtin/push.c
 #, c-format
 msgid "failed to push some refs to '%s'"
 msgstr "s'ha produït un error en pujar algunes referències a «%s»"
 
+#: builtin/push.c
 msgid ""
 "recursing into submodule with push.recurseSubmodules=only; using on-demand "
 "instead"
@@ -9912,71 +12661,93 @@
 "cerca recursivament en el submòdul amb push.recurseSubmodules=only; "
 "utilitzant «on-demand» en el seu lloc"
 
+#: builtin/push.c builtin/send-pack.c submodule-config.c
 #, c-format
 msgid "invalid value for '%s'"
 msgstr "valor no vàlid per a «%s»"
 
+#: builtin/push.c builtin/submodule--helper.c
 msgid "repository"
 msgstr "repositori"
 
+#: builtin/push.c
 msgid "push all branches"
 msgstr "puja totes les referències"
 
+#: builtin/push.c builtin/send-pack.c
 msgid "mirror all refs"
 msgstr "reflecteix totes les referències"
 
+#: builtin/push.c
 msgid "delete refs"
 msgstr "suprimeix les referències"
 
+#: builtin/push.c
 msgid "push tags (can't be used with --all or --branches or --mirror)"
 msgstr "puja les etiquetes (no es pot usar amb --all, --branches o --mirror)"
 
+#: builtin/push.c builtin/send-pack.c
 msgid "force updates"
 msgstr "força les actualitzacions"
 
+#: builtin/push.c builtin/send-pack.c
 msgid "<refname>:<expect>"
-msgstr "<nom-de-referència>:<esperat>"
+msgstr "<nom-referència>:<esperat>"
 
+#: builtin/push.c builtin/send-pack.c
 msgid "require old value of ref to be at this value"
 msgstr "requereix que el valor antic de la referència sigui d'aquest valor"
 
+#: builtin/push.c builtin/send-pack.c
 msgid "require remote updates to be integrated locally"
 msgstr "requereix que les actualitzacions remotes s'integrin localment"
 
+#: builtin/push.c
 msgid "control recursive pushing of submodules"
 msgstr "controla la pujada recursiva dels submòduls"
 
+#: builtin/push.c builtin/send-pack.c
 msgid "use thin pack"
 msgstr "usa el paquet prim"
 
+#: builtin/push.c builtin/send-pack.c
 msgid "receive pack program"
 msgstr "programa que rep els paquets"
 
+#: builtin/push.c
 msgid "set upstream for git pull/status"
 msgstr "estableix la font per a git pull/status"
 
+#: builtin/push.c
 msgid "prune locally removed refs"
 msgstr "poda les referències eliminades localment"
 
+#: builtin/push.c
 msgid "bypass pre-push hook"
 msgstr "evita el lligam de prepujada"
 
+#: builtin/push.c
 msgid "push missing but relevant tags"
 msgstr "puja les etiquetes absents però rellevants"
 
+#: builtin/push.c builtin/send-pack.c
 msgid "GPG sign the push"
 msgstr "signa la pujada amb GPG"
 
+#: builtin/push.c builtin/send-pack.c
 msgid "request atomic transaction on remote side"
 msgstr "demana una transacció atòmica al costat remot"
 
+#: builtin/push.c
 msgid "--delete doesn't make sense without any refs"
 msgstr "--delete no té sentit sense referències"
 
+#: builtin/push.c t/helper/test-bundle-uri.c
 #, c-format
 msgid "bad repository '%s'"
 msgstr "repositori incorrecte «%s»"
 
+#: builtin/push.c
 msgid ""
 "No configured push destination.\n"
 "Either specify the URL from the command-line or configure a remote "
@@ -9998,54 +12769,70 @@
 "\n"
 "    git push <nom>\n"
 
+#: builtin/push.c
 msgid "--all can't be combined with refspecs"
 msgstr "--all no es pot combinar amb especificacions de referència"
 
+#: builtin/push.c
 msgid "--mirror can't be combined with refspecs"
 msgstr "--mirror no es pot combinar amb especificacions de referència"
 
+#: builtin/push.c
 msgid "push options must not have new line characters"
 msgstr "les opcions de pujada no han de tenir caràcters de línia nova"
 
+#: builtin/range-diff.c
 msgid "git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"
 msgstr "git range-diff [<opcions>] <old-base>..<old-tip> <new-base>..<new-tip>"
 
+#: builtin/range-diff.c
 msgid "git range-diff [<options>] <old-tip>...<new-tip>"
 msgstr "git range-diff [<opcions>] <old-tip>...<new-tip>"
 
+#: builtin/range-diff.c
 msgid "git range-diff [<options>] <base> <old-tip> <new-tip>"
 msgstr "git range-diff [<opcions>] <base> <old-tip> <new-tip>"
 
+#: builtin/range-diff.c
 msgid "use simple diff colors"
 msgstr "utilitza colors simples de diff"
 
+#: builtin/range-diff.c
 msgid "notes"
 msgstr "notes"
 
+#: builtin/range-diff.c
 msgid "passed to 'git log'"
 msgstr "passa-ho a «git log»"
 
+#: builtin/range-diff.c
 msgid "only emit output related to the first range"
 msgstr "emet només la sortida relacionada amb el primer interval"
 
+#: builtin/range-diff.c
 msgid "only emit output related to the second range"
 msgstr "emet només la sortida relacionada amb el segon interval"
 
+#: builtin/range-diff.c
 #, c-format
 msgid "not a revision: '%s'"
 msgstr "«%s» no és una revisió"
 
+#: builtin/range-diff.c
 #, c-format
 msgid "not a commit range: '%s'"
 msgstr "no és un rang de comissions: «%s»"
 
+#: builtin/range-diff.c
 #, c-format
 msgid "not a symmetric range: '%s'"
 msgstr "no és un rang simètric: «%s»"
 
+#: builtin/range-diff.c
 msgid "need two commit ranges"
 msgstr "calen dos rangs de comissió"
 
+#: builtin/read-tree.c
 msgid ""
 "git read-tree [(-m [--trivial] [--aggressive] | --reset | --"
 "prefix=<prefix>)\n"
@@ -10057,60 +12844,79 @@
 "              [-u | -i]] [--index-output=<fitxer>] [--no-sparse-checkout]\n"
 "              (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
 
+#: builtin/read-tree.c
 msgid "write resulting index to <file>"
 msgstr "escriu l'índex resultant al <fitxer>"
 
+#: builtin/read-tree.c
 msgid "only empty the index"
 msgstr "només buida l'índex"
 
+#: builtin/read-tree.c
 msgid "Merging"
 msgstr "S'està fusionant"
 
+#: builtin/read-tree.c
 msgid "perform a merge in addition to a read"
 msgstr "realitza una fusió a més d'una lectura"
 
+#: builtin/read-tree.c
 msgid "3-way merge if no file level merging required"
 msgstr "fusió de 3 vies si no cal fusió a nivell de fitxers"
 
+#: builtin/read-tree.c
 msgid "3-way merge in presence of adds and removes"
 msgstr "fusió de 3 vies en presència d'afegiments i eliminacions"
 
+#: builtin/read-tree.c
 msgid "same as -m, but discard unmerged entries"
 msgstr "el mateix que -m, però descarta les entrades no fusionades"
 
+#: builtin/read-tree.c
 msgid "<subdirectory>/"
 msgstr "<subdirectori>/"
 
+#: builtin/read-tree.c
 msgid "read the tree into the index under <subdirectory>/"
 msgstr "llegeix l'arbre a l'índex sota <subdirectori>/"
 
+#: builtin/read-tree.c
 msgid "update working tree with merge result"
 msgstr "actualitza l'arbre de treball amb el resultat de fusió"
 
+#: builtin/read-tree.c
 msgid "gitignore"
 msgstr "gitignore"
 
+#: builtin/read-tree.c
 msgid "allow explicitly ignored files to be overwritten"
 msgstr "permet que els fitxers explícitament ignorats se sobreescriguin"
 
+#: builtin/read-tree.c
 msgid "don't check the working tree after merging"
 msgstr "no comprovis l'arbre de treball després de fusionar"
 
+#: builtin/read-tree.c
 msgid "don't update the index or the work tree"
 msgstr "no actualitzis l'índex ni l'arbre de treball"
 
+#: builtin/read-tree.c
 msgid "skip applying sparse checkout filter"
 msgstr "omet l'aplicació del filtre d'agafament parcial"
 
+#: builtin/read-tree.c
 msgid "debug unpack-trees"
 msgstr "depura unpack-trees"
 
+#: builtin/read-tree.c
 msgid "suppress feedback messages"
 msgstr "suprimeix els missatges de retroacció"
 
+#: builtin/read-tree.c
 msgid "You need to resolve your current index first"
 msgstr "Primer heu de resoldre el vostre índex actual"
 
+#: builtin/rebase.c
 msgid ""
 "git rebase [-i] [options] [--exec <cmd>] [--onto <newbase> | --keep-base] "
 "[<upstream> [<branch>]]"
@@ -10118,64 +12924,61 @@
 "git rebase [-i] [options] [--exec <ordre>] [--onto <newbase> | --keep-base] "
 "[<upstream> [<branca>]]"
 
+#: builtin/rebase.c
 msgid ""
 "git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]"
 msgstr ""
 "git rebase [-i] [options] [--exec <ordre>] [--onto <newbase>] --root "
 "[<branca>]"
 
+#: builtin/rebase.c sequencer.c
 #, c-format
 msgid "could not read '%s'."
 msgstr "no s'ha pogut llegir «%s»."
 
+#: builtin/rebase.c
 #, c-format
 msgid "could not create temporary %s"
 msgstr "no s'ha pogut crear el fitxer temporal %s"
 
+#: builtin/rebase.c
 msgid "could not mark as interactive"
 msgstr "no s'ha pogut marcar com a interactiu"
 
+#: builtin/rebase.c
 msgid "could not generate todo list"
 msgstr "no s'ha pogut generar la llista per a fer"
 
+#: builtin/rebase.c
 msgid "a base commit must be provided with --upstream or --onto"
 msgstr "s'ha de proporcionar una comissió base amb --upstream o --onto"
 
+#: builtin/rebase.c
 #, c-format
 msgid "%s requires the merge backend"
 msgstr "%s requereix un rerefons de fusió"
 
+#: builtin/rebase.c
 #, c-format
 msgid "invalid onto: '%s'"
 msgstr "no vàlid a: «%s»"
 
+#: builtin/rebase.c
 #, c-format
 msgid "invalid orig-head: '%s'"
 msgstr "orig-head no és vàlid: «%s»"
 
+#: builtin/rebase.c
 #, c-format
 msgid "ignoring invalid allow_rerere_autoupdate: '%s'"
 msgstr "s'ignora allow_rerere_autoupdate no vàlid: «%s»"
 
+#: builtin/rebase.c builtin/rm.c sequencer.c
 #, c-format
 msgid "could not remove '%s'"
 msgstr "no s'ha pogut eliminar «%s»"
 
-msgid ""
-"Resolve all conflicts manually, mark them as resolved with\n"
-"\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n"
-"You can instead skip this commit: run \"git rebase --skip\".\n"
-"To abort and get back to the state before \"git rebase\", run \"git rebase --"
-"abort\"."
-msgstr ""
-"Resoleu tots els conflictes manualment, marqueu-los com a resolts amb\n"
-"«git add/rm <fitxers_amb_conflicte>», llavors executeu «git rebase --"
-"continue».\n"
-"Alternativament podeu ometre aquesta comissió: executeu «git rebase --"
-"skip».\n"
-"Per a avortar i tornar a l'estat anterior abans de l'ordre «git rebase», "
-"executeu «git rebase --abort»."
-
+#: builtin/rebase.c
 #, c-format
 msgid ""
 "\n"
@@ -10194,24 +12997,34 @@
 "\n"
 "Com a resultat, git no pot fer un «rebase» d'elles."
 
+#: builtin/rebase.c
 #, c-format
 msgid "Unknown rebase-merges mode: %s"
 msgstr "Mode de fusió de rebase desconegut: %s"
 
+#: builtin/rebase.c
 #, c-format
 msgid "could not switch to %s"
 msgstr "no s'ha pogut commutar a %s"
 
+#: builtin/rebase.c
 msgid "apply options and merge options cannot be used together"
 msgstr "les opcions apply i merge no es poden usar juntes"
 
+#: builtin/rebase.c
+msgid "--empty=ask is deprecated; use '--empty=stop' instead."
+msgstr "--empty=ask és obslolet; utilitzeu '--empty=stop' en el seu lloc."
+
+#: builtin/rebase.c
 #, c-format
 msgid ""
 "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
+"\"stop\"."
 msgstr ""
-"tipus buit no reconegut «%s»; els valors vàlids són «drop», «keep» i «ask»."
+"tipus buit «%s» no reconegut; els valors vàlids són \"drop\", \"keep\" i "
+"\"stop\"."
 
+#: builtin/rebase.c
 msgid ""
 "--rebase-merges with an empty string argument is deprecated and will stop "
 "working in a future version of Git. Use --rebase-merges without an argument "
@@ -10221,6 +13034,7 @@
 "funcionar en una versió futura del Git. Utilitzeu --rebase-merges sense un "
 "argument, que fa el mateix."
 
+#: builtin/rebase.c
 #, c-format
 msgid ""
 "%s\n"
@@ -10237,6 +13051,7 @@
 "    git rebase '<branca>'\n"
 "\n"
 
+#: builtin/rebase.c
 #, c-format
 msgid ""
 "If you wish to set tracking information for this branch you can do so with:\n"
@@ -10250,128 +13065,169 @@
 "    git branch --set-upstream-to=%s/<branca> %s\n"
 "\n"
 
+#: builtin/rebase.c
 msgid "exec commands cannot contain newlines"
 msgstr "les ordres exec no poden contenir línies noves"
 
+#: builtin/rebase.c
 msgid "empty exec command"
 msgstr "ordre exec buida"
 
+#: builtin/rebase.c
 msgid "rebase onto given branch instead of upstream"
 msgstr "fes un «rebase» en la branca donada en comptes de la font"
 
+#: builtin/rebase.c
 msgid "use the merge-base of upstream and branch as the current base"
 msgstr "utilitza la base de fusió de la font i la branca com a base actual"
 
+#: builtin/rebase.c
 msgid "allow pre-rebase hook to run"
 msgstr "permet al lligam pre-rebase executar-se"
 
+#: builtin/rebase.c
 msgid "be quiet. implies --no-stat"
 msgstr "silenciós. Implica --no-stat"
 
+#: builtin/rebase.c
 msgid "display a diffstat of what changed upstream"
 msgstr "mostra un «diffstat» del que ha canviat a la font"
 
+#: builtin/rebase.c
 msgid "do not show diffstat of what changed upstream"
 msgstr "no mostris «diffstat» del que ha canviat a la font"
 
+#: builtin/rebase.c
 msgid "add a Signed-off-by trailer to each commit"
 msgstr "afegeix un «trailer» tipus «Signed-off-by» a cada comissió"
 
+#: builtin/rebase.c
 msgid "make committer date match author date"
 msgstr "fes que la data del «committer» coincideixi amb la data de l'autor"
 
+#: builtin/rebase.c
 msgid "ignore author date and use current date"
 msgstr "ignora la data de l'autor i utilitza la data actual"
 
+#: builtin/rebase.c
 msgid "synonym of --reset-author-date"
 msgstr "sinònim de --reset-author-date"
 
+#: builtin/rebase.c
 msgid "passed to 'git apply'"
 msgstr "passa-ho a «git apply»"
 
+#: builtin/rebase.c
 msgid "ignore changes in whitespace"
 msgstr "ignora els canvis d'espais en blanc"
 
+#: builtin/rebase.c
 msgid "cherry-pick all commits, even if unchanged"
 msgstr "«cherry pick» totes les comissions, inclús les no canviades"
 
+#: builtin/rebase.c
 msgid "continue"
 msgstr "continua"
 
+#: builtin/rebase.c
 msgid "skip current patch and continue"
 msgstr "omet el pedaç actual i continua"
 
+#: builtin/rebase.c
 msgid "abort and check out the original branch"
 msgstr "interromp i agafa la branca original"
 
+#: builtin/rebase.c
 msgid "abort but keep HEAD where it is"
 msgstr "interromp però manté HEAD on és"
 
+#: builtin/rebase.c
 msgid "edit the todo list during an interactive rebase"
 msgstr "edita la llista de coses a fer durant un «rebase» interactiu"
 
+#: builtin/rebase.c
 msgid "show the patch file being applied or merged"
 msgstr "mostra el pedaç que s'està aplicant o fusionant"
 
+#: builtin/rebase.c
 msgid "use apply strategies to rebase"
 msgstr "utilitza estratègies d'aplicació per a fer «rebase»"
 
+#: builtin/rebase.c
 msgid "use merging strategies to rebase"
 msgstr "utilitza estratègies de fusió per a fer «rebase»"
 
+#: builtin/rebase.c
 msgid "let the user edit the list of commits to rebase"
 msgstr "permet a l'usuari editar la llista de comissions a fer «rebase»"
 
+#: builtin/rebase.c
 msgid "(REMOVED) was: try to recreate merges instead of ignoring them"
 msgstr "(SUPRIMIT) era: intenta recrear fusions en lloc d'ignorar-les"
 
+#: builtin/rebase.c builtin/revert.c
 msgid "how to handle commits that become empty"
 msgstr "com gestionar les comissions que queden buides"
 
+#: builtin/rebase.c
 msgid "keep commits which start empty"
 msgstr "manté les comissions que comencen en blanc"
 
+#: builtin/rebase.c
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr "mou les comissions que comencen amb squash!/fixup! sota -i"
 
+#: builtin/rebase.c
 msgid "update branches that point to commits that are being rebased"
 msgstr ""
 "actualitza les branques que apunten a comissions a les quals se'ls està fent "
 "«rebase»"
 
+#: builtin/rebase.c
 msgid "add exec lines after each commit of the editable list"
 msgstr "afegeix línies d'exec després de cada comissió de la llista editable"
 
+#: builtin/rebase.c
 msgid "allow rebasing commits with empty messages"
 msgstr "permet fer «rebase» de les comissions amb missatges buits"
 
+#: builtin/rebase.c
 msgid "try to rebase merges instead of skipping them"
 msgstr "intenta fer «rebase» de les fusions en comptes d'ometre-les"
 
+#: builtin/rebase.c
 msgid "use 'merge-base --fork-point' to refine upstream"
 msgstr "usa «merge-base --fork-point» per a refinar la font"
 
+#: builtin/rebase.c
 msgid "use the given merge strategy"
 msgstr "utilitza l'estratègia de fusió donada"
 
+#: builtin/rebase.c builtin/revert.c
 msgid "option"
 msgstr "opció"
 
+#: builtin/rebase.c
 msgid "pass the argument through to the merge strategy"
 msgstr "passa l'argument a l'estratègia de fusió"
 
+#: builtin/rebase.c
 msgid "rebase all reachable commits up to the root(s)"
 msgstr "fes «rebase» de totes les comissions accessibles fins a l'arrel"
 
+#: builtin/rebase.c
 msgid "automatically re-schedule any `exec` that fails"
 msgstr "torna a planificar automàticament qualsevol «exec» que falli"
 
+#: builtin/rebase.c
 msgid "apply all changes, even those already present upstream"
 msgstr "aplica tots els canvis, fins i tot els que ja estan a la font"
 
+#: builtin/rebase.c
 msgid "It looks like 'git am' is in progress. Cannot rebase."
 msgstr "Sembla que «git am» està en curs. No es pot fer «rebase»."
 
+#: builtin/rebase.c
 msgid ""
 "`rebase --preserve-merges` (-p) is no longer supported.\n"
 "Use `git rebase --abort` to terminate current rebase.\n"
@@ -10381,6 +13237,7 @@
 "Utilitzeu «git rebase --abort» per a finalitzar el «rebase» actual.\n"
 "O bé baixeu a la versió v2.33, o anterior, per a completar el «rebase»."
 
+#: builtin/rebase.c
 msgid ""
 "--preserve-merges was replaced by --rebase-merges\n"
 "Note: Your `pull.rebase` configuration may also be set to 'preserve',\n"
@@ -10390,15 +13247,19 @@
 "Nota: la configuració «pull.rebase» també podria estar establerta a\n"
 "+-«preserve», que ja no s'admet; utilitzeu «merge» en el seu lloc"
 
-msgid "No rebase in progress?"
-msgstr "No hi ha un «rebase» en curs?"
+#: builtin/rebase.c
+msgid "no rebase in progress"
+msgstr "no hi ha cap «rebase» en curs"
 
+#: builtin/rebase.c
 msgid "The --edit-todo action can only be used during interactive rebase."
 msgstr "L'acció --edit-todo només es pot usar durant un «rebase» interactiu."
 
+#: builtin/rebase.c
 msgid "Cannot read HEAD"
 msgstr "No es pot llegir HEAD"
 
+#: builtin/rebase.c
 msgid ""
 "You must edit all merge conflicts and then\n"
 "mark them as resolved using git add"
@@ -10406,13 +13267,16 @@
 "Heu d'editar tots els conflictes de fusió i després\n"
 "marcar-los com a resolts fent servir git add"
 
+#: builtin/rebase.c
 msgid "could not discard worktree changes"
 msgstr "no s'han pogut descartar els canvis de l'arbre de treball"
 
+#: builtin/rebase.c
 #, c-format
 msgid "could not move back to %s"
 msgstr "no s'ha pogut tornar a %s"
 
+#: builtin/rebase.c
 #, c-format
 msgid ""
 "It seems that there is already a %s directory, and\n"
@@ -10432,9 +13296,11 @@
 "i després executeu aquesta ordre de nou. S'atura l'operació en cas que\n"
 "tingueu quelcom valuós.\n"
 
+#: builtin/rebase.c
 msgid "switch `C' expects a numerical value"
 msgstr "«switch» «c» espera un valor numèric"
 
+#: builtin/rebase.c
 msgid ""
 "apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
 "no-rebase-merges"
@@ -10442,6 +13308,7 @@
 "les opcions «apply» són incompatibles amb rebase.rebaseMerges. Considereu "
 "afegir-hi --no-rebase-merges"
 
+#: builtin/rebase.c
 msgid ""
 "apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
 "update-refs"
@@ -10449,84 +13316,106 @@
 "les opcions «apply» són incompatibles amb rebase.updateRefs. Considereu "
 "afegir-hi --no-update-refs"
 
+#: builtin/rebase.c
 #, c-format
 msgid "Unknown rebase backend: %s"
 msgstr "Rerefons de «rebase» desconegut: %s"
 
+#: builtin/rebase.c
 msgid "--reschedule-failed-exec requires --exec or --interactive"
 msgstr "--reschedule-failed-exec requereix --exec o --interactive"
 
+#: builtin/rebase.c
 #, c-format
 msgid "invalid upstream '%s'"
 msgstr "font no vàlida: «%s»"
 
+#: builtin/rebase.c
 msgid "Could not create new root commit"
 msgstr "No s'ha pogut crear una comissió arrel nova"
 
+#: builtin/rebase.c
 #, c-format
 msgid "no such branch/commit '%s'"
 msgstr "no existeix aquesta branca o comissió «%s»"
 
+#: builtin/rebase.c builtin/submodule--helper.c
 #, c-format
 msgid "No such ref: %s"
 msgstr "No hi ha tal referència: %s"
 
+#: builtin/rebase.c
 msgid "Could not resolve HEAD to a commit"
 msgstr "No s'ha pogut resoldre HEAD com a una comissió"
 
+#: builtin/rebase.c
 #, c-format
 msgid "'%s': need exactly one merge base with branch"
 msgstr "«%s»: necessita exactament una base de fusió amb branca"
 
+#: builtin/rebase.c
 #, c-format
 msgid "'%s': need exactly one merge base"
 msgstr "«%s»: necessita exactament una base de fusió"
 
+#: builtin/rebase.c
 #, c-format
 msgid "Does not point to a valid commit '%s'"
 msgstr "No apunta a una comissió vàlida «%s»"
 
+#: builtin/rebase.c
 msgid "HEAD is up to date."
 msgstr "HEAD està al dia."
 
+#: builtin/rebase.c
 #, c-format
 msgid "Current branch %s is up to date.\n"
 msgstr "La branca actual %s està al dia.\n"
 
+#: builtin/rebase.c
 msgid "HEAD is up to date, rebase forced."
 msgstr "La branca actual està al dia, «rebase» forçat."
 
+#: builtin/rebase.c
 #, c-format
 msgid "Current branch %s is up to date, rebase forced.\n"
 msgstr "La branca actual %s està al dia; «rebase» forçat.\n"
 
+#: builtin/rebase.c
 msgid "The pre-rebase hook refused to rebase."
 msgstr "El lligam pre-rebase ha refusat a fer «rebase»."
 
+#: builtin/rebase.c
 #, c-format
 msgid "Changes to %s:\n"
 msgstr "Canvis a %s:\n"
 
+#: builtin/rebase.c
 #, c-format
 msgid "Changes from %s to %s:\n"
 msgstr "Canvis de %s a %s:\n"
 
+#: builtin/rebase.c
 #, c-format
 msgid "First, rewinding head to replay your work on top of it...\n"
 msgstr ""
 "Primer, s'està rebobinant HEAD per a reproduir el vostre treball al "
 "damunt...\n"
 
+#: builtin/rebase.c
 msgid "Could not detach HEAD"
 msgstr "No s'ha pogut separar HEAD"
 
+#: builtin/rebase.c
 #, c-format
 msgid "Fast-forwarded %s to %s.\n"
 msgstr "Avanç ràpid %s a %s.\n"
 
+#: builtin/receive-pack.c
 msgid "git receive-pack <git-dir>"
 msgstr "git receive-pack <git-dir>"
 
+#: builtin/receive-pack.c
 msgid ""
 "By default, updating the current branch in a non-bare repository\n"
 "is denied, because it will make the index and work tree inconsistent\n"
@@ -10557,6 +13446,7 @@
 "per defecte, establiu la variable de configuració\n"
 "«receive.denyCurrentBranch» a «refuse»."
 
+#: builtin/receive-pack.c
 msgid ""
 "By default, deleting the current branch is denied, because the next\n"
 "'git clone' won't result in any file checked out, causing confusion.\n"
@@ -10578,15 +13468,23 @@
 "\n"
 "Per a silenciar aquest missatge, podeu establir-la a «refuse»."
 
+#: builtin/receive-pack.c
 msgid "quiet"
 msgstr "silenciós"
 
+#: builtin/receive-pack.c
 msgid "you must specify a directory"
 msgstr "heu d'especificar un directori"
 
+#: builtin/reflog.c
 msgid "git reflog [show] [<log-options>] [<ref>]"
-msgstr "git reflog [show] [<log-options>] [<ref>]"
+msgstr "git reflog [show] [<opcions-registre>] [<referència>]"
 
+#: builtin/reflog.c
+msgid "git reflog list"
+msgstr "git reflog list"
+
+#: builtin/reflog.c
 msgid ""
 "git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
 "                  [--rewrite] [--updateref] [--stale-fix]\n"
@@ -10598,39 +13496,57 @@
 "                  [--dry-run | -n] [--verbose] [--all [--single-worktree] | "
 "<refs>...]"
 
+#: builtin/reflog.c
 msgid ""
 "git reflog delete [--rewrite] [--updateref]\n"
 "                  [--dry-run | -n] [--verbose] <ref>@{<specifier>}..."
 msgstr ""
 "git reflog delete [--rewrite] [--updateref]\n"
-"                  [--dry-run | -n] [--verbose] <ref>@{<specifier>}..."
+"                  [--dry-run | -n] [--verbose] "
+"<referència>@{<especificador>}..."
 
+#: builtin/reflog.c
 msgid "git reflog exists <ref>"
 msgstr "git reflog exists <referència>"
 
+#: builtin/reflog.c
 #, c-format
 msgid "invalid timestamp '%s' given to '--%s'"
 msgstr "marca de temps «%s» donada a «--%s» no és vàlida"
 
+#: builtin/reflog.c sequencer.c
+#, c-format
+msgid "%s does not accept arguments: '%s'"
+msgstr "%s no accepta arguments: «%s»"
+
+#: builtin/reflog.c
 msgid "do not actually prune any entries"
 msgstr "no eliminis cap entrada"
 
+#: builtin/reflog.c
 msgid ""
 "rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"
 msgstr "reescriu l'antic SHA1 amb el nou SHA1 de l'entrada que ara precedeix"
 
+#: builtin/reflog.c
 msgid "update the reference to the value of the top reflog entry"
-msgstr "actualitza la referència al valor de l'entrada de reflog superior"
+msgstr ""
+"actualitza la referència al valor de l'entrada de registre de referència "
+"superior"
 
+#: builtin/reflog.c
 msgid "print extra information on screen"
 msgstr "imprimeix informació extra a la pantalla"
 
+#: builtin/reflog.c
 msgid "timestamp"
 msgstr "marca de temps"
 
+#: builtin/reflog.c
 msgid "prune entries older than the specified time"
 msgstr "poda les entrades més antigues que el temps especificat"
 
+#: builtin/reflog.c
 msgid ""
 "prune entries older than <time> that are not reachable from the current tip "
 "of the branch"
@@ -10638,30 +13554,75 @@
 "poda les entrades més antigues de <data> que no es poden accedir des de la "
 "punta actual de la branca"
 
+#: builtin/reflog.c
 msgid "prune any reflog entries that point to broken commits"
-msgstr "poda qualsevol entrada de reflog que apunti a comissions trencades"
+msgstr ""
+"poda qualsevol entrada del registre de referències que apunti a comissions "
+"trencades"
 
+#: builtin/reflog.c
 msgid "process the reflogs of all references"
-msgstr "processa els reflogs de totes les referències"
+msgstr "processa els registres de referències de totes les referències"
 
+#: builtin/reflog.c
 msgid "limits processing to reflogs from the current worktree only"
-msgstr "limita el processament a reflogs només de l'arbre de treball actual"
+msgstr ""
+"limita el processament només a registres de referències de l'arbre de "
+"treball actual"
 
+#: builtin/reflog.c
 #, c-format
 msgid "Marking reachable objects..."
 msgstr "S'estan marcant els objectes abastables..."
 
+#: builtin/reflog.c
 #, c-format
 msgid "%s points nowhere!"
 msgstr "%s no apunta a enlloc"
 
+#: builtin/reflog.c
 msgid "no reflog specified to delete"
-msgstr "no s'ha especificat cap registre de referència per a suprimir"
+msgstr "no s'ha especificat cap registre de referències per a suprimir"
 
+#: builtin/reflog.c
 #, c-format
 msgid "invalid ref format: %s"
 msgstr "format de referència no vàlid: %s"
 
+#: builtin/refs.c
+msgid "git refs migrate --ref-format=<format> [--dry-run]"
+msgstr "git refs migrate --ref-format=<format> [--dry-run]"
+
+#: builtin/refs.c
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+#: builtin/refs.c
+msgid "specify the reference format to convert to"
+msgstr "especifiqueu el format de referència al qual voleu convertir"
+
+#: builtin/refs.c
+msgid "perform a non-destructive dry-run"
+msgstr "fes una prova no destructiva"
+
+#: builtin/refs.c
+msgid "missing --ref-format=<format>"
+msgstr "falta --ref-format=<format>"
+
+#: builtin/refs.c
+#, c-format
+msgid "repository already uses '%s' format"
+msgstr "el repositori ja usa el format «%s»"
+
+#: builtin/refs.c
+msgid "enable strict checking"
+msgstr "habilita la comprovació estricta"
+
+#: builtin/refs.c
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' no accepta arguments"
+
+#: builtin/remote.c
 msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
 "mirror=<fetch|push>] <name> <url>"
@@ -10669,67 +13630,87 @@
 "git remote add [-t <branca>] [-m <master>] [-f] [--tags | --no-tags] [--"
 "mirror=<fetch|push>] <nom> <url>"
 
+#: builtin/remote.c
 msgid "git remote rename [--[no-]progress] <old> <new>"
-msgstr "git remote rename [--[no-]progress] <old> <new>"
+msgstr "git remote rename [--[no-]progress] <vell> <nou>"
 
+#: builtin/remote.c
 msgid "git remote remove <name>"
 msgstr "git remote remove <nom>"
 
+#: builtin/remote.c
 msgid "git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"
 msgstr "git remote set-head <nom> (-a | --auto | -d | --delete | <branca>)"
 
+#: builtin/remote.c
 msgid "git remote [-v | --verbose] show [-n] <name>"
 msgstr "git remote [-v | --verbose] show [-n] <nom>"
 
+#: builtin/remote.c
 msgid "git remote prune [-n | --dry-run] <name>"
 msgstr "git remote prune [-n | --dry-run] <nom>"
 
+#: builtin/remote.c
 msgid ""
 "git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
 msgstr ""
 "git remote [-v | --verbose] update [-p | --prune] [(<grup> | <remot>)...]"
 
+#: builtin/remote.c
 msgid "git remote set-branches [--add] <name> <branch>..."
 msgstr "git remote set-branches [--add] <nom> <branca>..."
 
+#: builtin/remote.c
 msgid "git remote get-url [--push] [--all] <name>"
 msgstr "git remote get-url [--push] [--all] <nom>"
 
+#: builtin/remote.c
 msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
-msgstr "git remote set-url [--push] <nom> <url-nou> [<url-antic>]"
+msgstr "<git remote set-url [--push] <nom> <url-nou> [<url-vell>]"
 
+#: builtin/remote.c
 msgid "git remote set-url --add <name> <newurl>"
 msgstr "git remote set-url --add <nom> <url-nou>"
 
+#: builtin/remote.c
 msgid "git remote set-url --delete <name> <url>"
 msgstr "git remote set-url --delete <nom> <url>"
 
+#: builtin/remote.c
 msgid "git remote add [<options>] <name> <url>"
 msgstr "git remote add [<opcions>] <nom> <url>"
 
+#: builtin/remote.c
 msgid "git remote set-branches <name> <branch>..."
 msgstr "git remote set-branches <nom> <branca>..."
 
+#: builtin/remote.c
 msgid "git remote set-branches --add <name> <branch>..."
 msgstr "git remote set-branches --add <nom> <branca>..."
 
+#: builtin/remote.c
 msgid "git remote show [<options>] <name>"
 msgstr "git remote show [<opcions>] <nom>"
 
+#: builtin/remote.c
 msgid "git remote prune [<options>] <name>"
 msgstr "git remote prune [<opcions>] <nom>"
 
+#: builtin/remote.c
 msgid "git remote update [<options>] [<group> | <remote>]..."
 msgstr "git remote update [<opcions>] [<grup> | <remot>]..."
 
+#: builtin/remote.c
 #, c-format
 msgid "Updating %s"
 msgstr "S'està actualitzant %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "Could not fetch %s"
 msgstr "No s'ha pogut obtenir %s"
 
+#: builtin/remote.c
 msgid ""
 "--mirror is dangerous and deprecated; please\n"
 "\t use --mirror=fetch or --mirror=push instead"
@@ -10738,13 +13719,16 @@
 "\t useu --mirror=fetch o\n"
 "\t --mirror=push en lloc d'això"
 
+#: builtin/remote.c
 #, c-format
-msgid "unknown mirror argument: %s"
-msgstr "argument de «mirror» desconegut: %s"
+msgid "unknown --mirror argument: %s"
+msgstr "argument de «--mirror» desconegut: %s"
 
+#: builtin/remote.c
 msgid "fetch the remote branches"
 msgstr "obtén les branques remotes"
 
+#: builtin/remote.c
 msgid ""
 "import all tags and associated objects when fetching\n"
 "or do not fetch any tag at all (--no-tags)"
@@ -10752,57 +13736,72 @@
 "importa totes les etiquetes i objectes associats en obtenir\n"
 "o no obtingueu cap etiqueta (--no-tags)"
 
+#: builtin/remote.c
 msgid "branch(es) to track"
 msgstr "branques a seguir"
 
+#: builtin/remote.c
 msgid "master branch"
 msgstr "branca mestra"
 
+#: builtin/remote.c
 msgid "set up remote as a mirror to push to or fetch from"
 msgstr "estableix el remot com a mirall al qual pujar o del qual obtenir"
 
+#: builtin/remote.c
 msgid "specifying a master branch makes no sense with --mirror"
 msgstr "especificar una branca mestra no té sentit amb --mirror"
 
+#: builtin/remote.c
 msgid "specifying branches to track makes sense only with fetch mirrors"
 msgstr ""
 "especificar les branques a seguir té sentit només amb miralls d'obtenció"
 
+#: builtin/remote.c
 #, c-format
 msgid "remote %s already exists."
 msgstr "el remot %s ja existeix."
 
+#: builtin/remote.c
 #, c-format
 msgid "Could not setup master '%s'"
 msgstr "No s'ha pogut configurar la mestra «%s»"
 
+#: builtin/remote.c trailer.c
 #, c-format
 msgid "more than one %s"
 msgstr "més d'un %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "unhandled branch.%s.rebase=%s; assuming 'true'"
 msgstr "no s'ha gestionat branch.%s.rebase=%s; assumint «true»"
 
+#: builtin/remote.c
 #, c-format
 msgid "Could not get fetch map for refspec %s"
 msgstr ""
 "No s'ha pogut obtenir el mapa d'obtenció de l'especificació de referència %s"
 
+#: builtin/remote.c
 msgid "(matching)"
 msgstr "(coincident)"
 
+#: builtin/remote.c
 msgid "(delete)"
 msgstr "(suprimir)"
 
+#: builtin/remote.c
 #, c-format
 msgid "could not set '%s'"
 msgstr "no s'ha pogut establir «%s»"
 
+#: builtin/remote.c config.c
 #, c-format
 msgid "could not unset '%s'"
 msgstr "no s'ha pogut desassignar «%s»"
 
+#: builtin/remote.c
 #, c-format
 msgid ""
 "The %s configuration remote.pushDefault in:\n"
@@ -10813,14 +13812,17 @@
 "\t%s:%d\n"
 "ara anomena un remot no existent «%s»"
 
+#: builtin/remote.c
 #, c-format
 msgid "No such remote: '%s'"
 msgstr "No existeix el remot «%s»"
 
+#: builtin/remote.c
 #, c-format
 msgid "Could not rename config section '%s' to '%s'"
 msgstr "No s'ha pogut canviar el nom de la secció de configuració «%s» a «%s»"
 
+#: builtin/remote.c
 #, c-format
 msgid ""
 "Not updating non-default fetch refspec\n"
@@ -10832,17 +13834,21 @@
 "\t%s\n"
 "\tActualitzeu la configuració manualment si és necessari."
 
+#: builtin/remote.c
 msgid "Renaming remote references"
 msgstr "S'està canviant el nom de les referències remotes"
 
+#: builtin/remote.c
 #, c-format
 msgid "deleting '%s' failed"
 msgstr "la supressió de «%s» ha fallat"
 
+#: builtin/remote.c
 #, c-format
 msgid "creating '%s' failed"
 msgstr "la creació de «%s» ha fallat"
 
+#: builtin/remote.c
 msgid ""
 "Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
 "to delete it, use:"
@@ -10857,246 +13863,307 @@
 "eliminat;\n"
 "per a suprimir-les, useu:"
 
+#: builtin/remote.c
 #, c-format
 msgid "Could not remove config section '%s'"
 msgstr "No s'ha pogut eliminar la secció de configuració «%s»"
 
+#: builtin/remote.c
 #, c-format
 msgid " new (next fetch will store in remotes/%s)"
 msgstr " nou (la pròxima obtenció emmagatzemarà a remotes/%s)"
 
+#: builtin/remote.c
 msgid " tracked"
 msgstr " seguit"
 
+#: builtin/remote.c
 msgid " skipped"
 msgstr " omès"
 
+#: builtin/remote.c
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " estancat (useu «git remote prune» per a eliminar)"
 
+#: builtin/remote.c
 msgid " ???"
 msgstr " ???"
 
+#: builtin/remote.c
 #, c-format
 msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
 msgstr "branch.%s.merge no vàlid; no es pot fer «rebase» sobre > 1 branca"
 
+#: builtin/remote.c
 #, c-format
 msgid "rebases interactively onto remote %s"
 msgstr "es fa «rebase» interactivament sobre el remot %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "rebases interactively (with merges) onto remote %s"
 msgstr "es fa «rebase» interactivament (amb fusions) sobre el remot %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "rebases onto remote %s"
 msgstr "es fa «rebase» sobre el remot %s"
 
+#: builtin/remote.c
 #, c-format
 msgid " merges with remote %s"
 msgstr " es fusiona amb el remot %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "merges with remote %s"
 msgstr "es fusiona amb el remot %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "%-*s    and with remote %s\n"
 msgstr "%-*s    i amb el remot %s\n"
 
+#: builtin/remote.c
 msgid "create"
 msgstr "crea"
 
+#: builtin/remote.c
 msgid "delete"
 msgstr "suprimeix"
 
+#: builtin/remote.c
 msgid "up to date"
 msgstr "al dia"
 
+#: builtin/remote.c
 msgid "fast-forwardable"
 msgstr "avanç ràpid possible"
 
+#: builtin/remote.c
 msgid "local out of date"
 msgstr "local no actualitzat"
 
+#: builtin/remote.c
 #, c-format
 msgid "    %-*s forces to %-*s (%s)"
 msgstr "    %-*s força a %-*s (%s)"
 
+#: builtin/remote.c
 #, c-format
 msgid "    %-*s pushes to %-*s (%s)"
 msgstr "    %-*s puja a %-*s (%s)"
 
+#: builtin/remote.c
 #, c-format
 msgid "    %-*s forces to %s"
 msgstr "    %-*s força a %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "    %-*s pushes to %s"
 msgstr "    %-*s puja a %s"
 
+#: builtin/remote.c
 msgid "do not query remotes"
 msgstr "no consultis els remots"
 
+#: builtin/remote.c
 #, c-format
 msgid "* remote %s"
 msgstr "* remot %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "  Fetch URL: %s"
 msgstr "  URL d'obtenció: %s"
 
-msgid "(no URL)"
-msgstr "(sense URL)"
-
 #. TRANSLATORS: the colon ':' should align
 #. with the one in " Fetch URL: %s"
 #. translation.
 #.
+#: builtin/remote.c
 #, c-format
 msgid "  Push  URL: %s"
 msgstr "  URL de pujada: %s"
 
+#: builtin/remote.c
+msgid "(no URL)"
+msgstr "(sense URL)"
+
+#: builtin/remote.c
 #, c-format
 msgid "  HEAD branch: %s"
 msgstr "  Branca de HEAD: %s"
 
+#: builtin/remote.c
 msgid "(not queried)"
 msgstr "(no consultat)"
 
+#: builtin/remote.c
 msgid "(unknown)"
 msgstr "(desconegut)"
 
+#: builtin/remote.c
 #, c-format
 msgid ""
 "  HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
 msgstr ""
 "  Branca de HEAD (la HEAD remot és ambigua, pot ser un dels següents):\n"
 
+#: builtin/remote.c
 #, c-format
 msgid "  Remote branch:%s"
 msgid_plural "  Remote branches:%s"
 msgstr[0] "  Branca remota:%s"
 msgstr[1] "  Branques remotes:%s"
 
+#: builtin/remote.c
 msgid " (status not queried)"
 msgstr " (estat no consultat)"
 
+#: builtin/remote.c
 msgid "  Local branch configured for 'git pull':"
 msgid_plural "  Local branches configured for 'git pull':"
 msgstr[0] "  Branca local configurada per a «git pull»:"
 msgstr[1] "  Branques locals configurades per a «git pull»:"
 
+#: builtin/remote.c
 msgid "  Local refs will be mirrored by 'git push'"
 msgstr "  «git push» reflectirà les referències locals"
 
+#: builtin/remote.c
 #, c-format
 msgid "  Local ref configured for 'git push'%s:"
 msgid_plural "  Local refs configured for 'git push'%s:"
 msgstr[0] "  Referència local configurada per a «git push»%s:"
 msgstr[1] "  Referències locals configurades per a «git push»%s:"
 
+#: builtin/remote.c
 msgid "set refs/remotes/<name>/HEAD according to remote"
 msgstr "estableix refs/remotes/<nom>/HEAD segons el remot"
 
+#: builtin/remote.c
 msgid "delete refs/remotes/<name>/HEAD"
 msgstr "suprimeix refs/remotes/<nom>/HEAD"
 
+#: builtin/remote.c
 msgid "Cannot determine remote HEAD"
 msgstr "No es pot determinar la HEAD remota"
 
+#: builtin/remote.c
 msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
 msgstr "Múltiples branques de HEAD remotes. Trieu-ne una explícitament amb:"
 
+#: builtin/remote.c
 #, c-format
 msgid "Could not delete %s"
 msgstr "No s'ha pogut suprimir %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "Not a valid ref: %s"
 msgstr "No és una referència vàlida: %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "Could not setup %s"
 msgstr "No s'ha pogut configurar %s"
 
+#: builtin/remote.c
 #, c-format
 msgid " %s will become dangling!"
-msgstr " %s es tornarà penjant!"
+msgstr " %s es quedara despenjat!"
 
+#: builtin/remote.c
 #, c-format
 msgid " %s has become dangling!"
-msgstr " %s s'ha tornat penjant!"
+msgstr " %s s'ha quedat despenjat!"
 
+#: builtin/remote.c
 #, c-format
 msgid "Pruning %s"
 msgstr "S'està podant %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "URL: %s"
 msgstr "URL: %s"
 
+#: builtin/remote.c
 #, c-format
 msgid " * [would prune] %s"
 msgstr " * [podaria] %s"
 
+#: builtin/remote.c
 #, c-format
 msgid " * [pruned] %s"
 msgstr " * [podat] %s"
 
+#: builtin/remote.c
 msgid "prune remotes after fetching"
 msgstr "poda els remots després d'obtenir-los"
 
+#: builtin/remote.c
 #, c-format
 msgid "No such remote '%s'"
 msgstr "No hi ha tal remot «%s»"
 
+#: builtin/remote.c
 msgid "add branch"
 msgstr "afegeix branca"
 
+#: builtin/remote.c
 msgid "no remote specified"
 msgstr "cap remot especificat"
 
+#: builtin/remote.c
 msgid "query push URLs rather than fetch URLs"
 msgstr "consulta els URL de pujada en lloc dels URL d'obtenció"
 
+#: builtin/remote.c
 msgid "return all URLs"
 msgstr "retorna tots els URL"
 
-#, c-format
-msgid "no URLs configured for remote '%s'"
-msgstr "cap URL configurat per al remot «%s»"
-
+#: builtin/remote.c
 msgid "manipulate push URLs"
 msgstr "manipula els URL de pujada"
 
+#: builtin/remote.c
 msgid "add URL"
 msgstr "afegeix URL"
 
+#: builtin/remote.c
 msgid "delete URLs"
 msgstr "suprimeix els URL"
 
+#: builtin/remote.c
 msgid "--add --delete doesn't make sense"
 msgstr "--add --delete no té sentit"
 
+#: builtin/remote.c
 #, c-format
 msgid "Invalid old URL pattern: %s"
 msgstr "Patró d'URL antic no vàlid: %s"
 
+#: builtin/remote.c
 #, c-format
 msgid "No such URL found: %s"
 msgstr "No s'ha trobat tal URL: %s"
 
+#: builtin/remote.c
 msgid "Will not delete all non-push URLs"
 msgstr "No se suprimiran tots els URL no de pujada"
 
+#: builtin/remote.c
 msgid "be verbose; must be placed before a subcommand"
 msgstr "sigues detallat; s'ha de col·locar abans d'una subordre"
 
+#: builtin/repack.c
 msgid "git repack [<options>]"
 msgstr "git repack [<opcions>]"
 
+#: builtin/repack.c
 msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
 "--no-write-bitmap-index or disable the pack.writeBitmaps configuration."
@@ -11106,173 +14173,225 @@
 "--no-write-bitmap-index o inhabiliteu el paràmetre de configuració pack."
 "writeBitmaps."
 
+#: builtin/repack.c
 msgid "could not start pack-objects to repack promisor objects"
 msgstr ""
 "no s'ha pogut iniciar pack-objects per a tornar a empaquetar els objectes "
 "«promisor»"
 
+#: builtin/repack.c
+msgid "failed to feed promisor objects to pack-objects"
+msgstr "no s'ha pogut alimentar pack-objects amb objectes «promisor»"
+
+#: builtin/repack.c
 msgid "repack: Expecting full hex object ID lines only from pack-objects."
 msgstr ""
 "repack: s'esperen només línies amb l'id d'objecte hexadecimal complet des de "
 "pack-objects."
 
+#: builtin/repack.c
 msgid "could not finish pack-objects to repack promisor objects"
 msgstr ""
 "no s'ha pogut finalitzar pack-objects per a tornar a empaquetar els objectes "
 "«promisor»"
 
+#: builtin/repack.c
 #, c-format
 msgid "cannot open index for %s"
 msgstr "no s'ha pogut obrir l'índex per a %s"
 
+#: builtin/repack.c
 #, c-format
 msgid "pack %s too large to consider in geometric progression"
 msgstr ""
 "el paquet %s és massa gran per a considerar-ho en progressió geomètrica"
 
+#: builtin/repack.c
 #, c-format
 msgid "pack %s too large to roll up"
 msgstr "el paquet %s és massa gran per a enrotllar-lo"
 
+#: builtin/repack.c
 #, c-format
 msgid "could not open tempfile %s for writing"
 msgstr "no s'ha pogut obrir el fitxer temporal «%s» per a escriptura"
 
+#: builtin/repack.c
 msgid "could not close refs snapshot tempfile"
 msgstr ""
 "no s'ha pogut tancar el fitxer temporal amb la instantània de referències"
 
+#: builtin/repack.c
 #, c-format
 msgid "could not remove stale bitmap: %s"
 msgstr "no s'ha pogut eliminar el mapa de bits estancat: %s"
 
+#: builtin/repack.c
 #, c-format
 msgid "pack prefix %s does not begin with objdir %s"
 msgstr "el prefix de paquet %s no comença amb objdir %s"
 
+#: builtin/repack.c
 msgid "pack everything in a single pack"
 msgstr "empaqueta-ho tot en un únic paquet"
 
+#: builtin/repack.c
 msgid "same as -a, and turn unreachable objects loose"
 msgstr "el mateix que -a, i solta els objectes inabastables"
 
+#: builtin/repack.c
 msgid "same as -a, pack unreachable cruft objects separately"
 msgstr ""
 "el mateix que -a, empaqueta els objectes superflus inabastables de forma "
 "separada"
 
+#: builtin/repack.c
 msgid "approxidate"
 msgstr "data aproximada"
 
+#: builtin/repack.c
 msgid "with --cruft, expire objects older than this"
 msgstr "amb --cruft, vencen els objectes més antics que aquest"
 
+#: builtin/repack.c
 msgid "remove redundant packs, and run git-prune-packed"
 msgstr "elimina els paquets redundants, i executeu git-prune-packed"
 
+#: builtin/repack.c
 msgid "pass --no-reuse-delta to git-pack-objects"
 msgstr "passa --no-reuse-delta a git-pack-objects"
 
+#: builtin/repack.c
 msgid "pass --no-reuse-object to git-pack-objects"
 msgstr "passa --no-reuse-object a git-pack-objects"
 
+#: builtin/repack.c
 msgid "do not run git-update-server-info"
 msgstr "no executis git-update-server-info"
 
+#: builtin/repack.c
 msgid "pass --local to git-pack-objects"
 msgstr "passa --local a git-pack-objects"
 
+#: builtin/repack.c
 msgid "write bitmap index"
 msgstr "escriu índex de mapa de bits"
 
+#: builtin/repack.c
 msgid "pass --delta-islands to git-pack-objects"
 msgstr "passa --delta-islands a git-pack-objects"
 
+#: builtin/repack.c
 msgid "with -A, do not loosen objects older than this"
 msgstr "amb -A, no soltis els objectes més antics que aquest"
 
+#: builtin/repack.c
 msgid "with -a, repack unreachable objects"
 msgstr "amb -a, reempaqueta els objectes inabastables"
 
+#: builtin/repack.c
 msgid "size of the window used for delta compression"
 msgstr "mida de la finestra que s'usa per a compressió de diferències"
 
+#: builtin/repack.c
 msgid "bytes"
 msgstr "octets"
 
+#: builtin/repack.c
 msgid "same as the above, but limit memory size instead of entries count"
 msgstr ""
 "el mateix que l'anterior, però limita la mida de memòria en lloc del nombre "
 "d'entrades"
 
+#: builtin/repack.c
 msgid "limits the maximum delta depth"
 msgstr "limita la profunditat màxima de les diferències"
 
+#: builtin/repack.c
 msgid "limits the maximum number of threads"
 msgstr "limita el nombre màxim de fils"
 
+#: builtin/repack.c
 msgid "maximum size of each packfile"
 msgstr "mida màxima de cada fitxer de paquet"
 
+#: builtin/repack.c
 msgid "repack objects in packs marked with .keep"
 msgstr "reempaqueta els objectes en paquets marcats amb .keep"
 
+#: builtin/repack.c
 msgid "do not repack this pack"
 msgstr "no reempaquetis aquest paquet"
 
+#: builtin/repack.c
 msgid "find a geometric progression with factor <N>"
 msgstr "troba una progressió geomètrica amb el factor <N>"
 
+#: builtin/repack.c
 msgid "write a multi-pack index of the resulting packs"
 msgstr "escriu un índex multipaquet dels paquets resultants"
 
+#: builtin/repack.c
 msgid "pack prefix to store a pack containing pruned objects"
 msgstr ""
 "prefix del paquet per a emmagatzemar un paquet que contingui objectes podats"
 
+#: builtin/repack.c
 msgid "pack prefix to store a pack containing filtered out objects"
 msgstr ""
 "prefix del paquet per a emmagatzemar un paquet que contingui objectes "
 "filtrats"
 
+#: builtin/repack.c
 msgid "cannot delete packs in a precious-objects repo"
 msgstr "no es poden suprimir paquets en un repositori d'objectes preciosos"
 
+#: builtin/repack.c
 #, c-format
 msgid "option '%s' can only be used along with '%s'"
 msgstr "l'opció «%s» només es pot utilitzar juntament amb «%s»"
 
+#: builtin/repack.c
 msgid "Nothing new to pack."
 msgstr "Res nou a empaquetar."
 
+#: builtin/repack.c
 #, c-format
 msgid "renaming pack to '%s' failed"
 msgstr "el canvi del nom a «%s» ha fallat"
 
+#: builtin/repack.c
 #, c-format
 msgid "pack-objects did not write a '%s' file for pack %s-%s"
 msgstr ""
 "els objectes de paquet no han escrit a un fitxer «%s» per al paquet %s-%s"
 
+#: builtin/repack.c sequencer.c
 #, c-format
 msgid "could not unlink: %s"
 msgstr "no s'ha pogut desenllaçar: «%s»"
 
+#: builtin/replace.c
 msgid "git replace [-f] <object> <replacement>"
 msgstr "git replace [-f] <objecte> <reemplaçament>"
 
+#: builtin/replace.c
 msgid "git replace [-f] --edit <object>"
 msgstr "git replace [-f] --edit <objecte>"
 
+#: builtin/replace.c
 msgid "git replace [-f] --graft <commit> [<parent>...]"
 msgstr "git replace [-f] --graft <comissió> [<pare>...]"
 
+#: builtin/replace.c
 msgid "git replace -d <object>..."
 msgstr "git replace -d <objecte>..."
 
+#: builtin/replace.c
 msgid "git replace [--format=<format>] [-l [<pattern>]]"
 msgstr "git replace [--format=<format>] [-l [<patró>]]"
 
+#: builtin/replace.c
 #, c-format
 msgid ""
 "invalid replace format '%s'\n"
@@ -11281,22 +14400,27 @@
 "format de reemplaçament no vàlid «%s»\n"
 "els formats vàlids són «short» «medium» i «long»"
 
+#: builtin/replace.c
 #, c-format
 msgid "replace ref '%s' not found"
 msgstr "no s'ha trobat la referència de reemplaçament '«%s»"
 
+#: builtin/replace.c
 #, c-format
 msgid "Deleted replace ref '%s'"
 msgstr "S'ha suprimit la referència «%s»"
 
+#: builtin/replace.c
 #, c-format
 msgid "'%s' is not a valid ref name"
 msgstr "«%s» no és un nom de referència vàlid"
 
+#: builtin/replace.c
 #, c-format
 msgid "replace ref '%s' already exists"
 msgstr "la referència de reemplaçament «%s» ja existeix"
 
+#: builtin/replace.c
 #, c-format
 msgid ""
 "Objects must be of the same type.\n"
@@ -11307,59 +14431,75 @@
 "«%s» apunta a un objecte substituït del tipus «%s»\n"
 "mentre que «%s» apunta a un objecte de substitució del tipus «%s»."
 
+#: builtin/replace.c
 #, c-format
 msgid "unable to open %s for writing"
 msgstr "no s'ha pogut obrir %s per a escriptura"
 
+#: builtin/replace.c
 msgid "cat-file reported failure"
 msgstr "cat-file ha informat d'un error"
 
+#: builtin/replace.c
 #, c-format
 msgid "unable to open %s for reading"
 msgstr "no s'ha pogut obrir %s per a lectura"
 
+#: builtin/replace.c
 msgid "unable to spawn mktree"
 msgstr "no s'ha pogut engendrar el mktree"
 
+#: builtin/replace.c
 msgid "unable to read from mktree"
 msgstr "no s'ha pogut llegir des de mktree"
 
+#: builtin/replace.c
 msgid "mktree reported failure"
 msgstr "mktree ha informat d'una fallada"
 
+#: builtin/replace.c
 msgid "mktree did not return an object name"
 msgstr "mktree no ha retornat un nom d'objecte"
 
+#: builtin/replace.c
 #, c-format
 msgid "unable to fstat %s"
 msgstr "no s'ha pogut fer fstat %s"
 
+#: builtin/replace.c
 msgid "unable to write object to database"
 msgstr "no s'ha pogut escriure l'objecte a la base de dades"
 
+#: builtin/replace.c
 #, c-format
 msgid "unable to get object type for %s"
 msgstr "no s'ha pogut obtenir el tipus d'objecte per a %s"
 
+#: builtin/replace.c
 msgid "editing object file failed"
 msgstr "l'edició del fitxer d'objecte ha fallat"
 
+#: builtin/replace.c
 #, c-format
 msgid "new object is the same as the old one: '%s'"
 msgstr "l'objecte nou és el mateix que l'antic: «%s»"
 
+#: builtin/replace.c
 #, c-format
 msgid "could not parse %s as a commit"
 msgstr "no s'ha pogut analitzar %s com a comissió"
 
+#: builtin/replace.c
 #, c-format
 msgid "bad mergetag in commit '%s'"
 msgstr "etiqueta de fusió incorrecta en la comissió «%s»"
 
+#: builtin/replace.c
 #, c-format
 msgid "malformed mergetag in commit '%s'"
 msgstr "etiqueta de fusió mal formada en la comissió «%s»"
 
+#: builtin/replace.c
 #, c-format
 msgid ""
 "original commit '%s' contains mergetag '%s' that is discarded; use --edit "
@@ -11368,25 +14508,31 @@
 "la comissió original «%s» conté l'etiqueta de fusió «%s» que es descarta; "
 "useu --edit en lloc de --graft"
 
+#: builtin/replace.c
 #, c-format
 msgid "the original commit '%s' has a gpg signature"
 msgstr "la comissió original «%s» té una signatura gpg"
 
+#: builtin/replace.c
 msgid "the signature will be removed in the replacement commit!"
 msgstr "s'eliminarà la signatura en la comissió de reemplaçament!"
 
+#: builtin/replace.c
 #, c-format
 msgid "could not write replacement commit for: '%s'"
 msgstr "no s'ha pogut escriure la comissió de reemplaçament per a: «%s»"
 
+#: builtin/replace.c
 #, c-format
 msgid "graft for '%s' unnecessary"
 msgstr "«graft» per a «%s» innecessari"
 
+#: builtin/replace.c
 #, c-format
 msgid "new commit is the same as the old one: '%s'"
 msgstr "la comissió nova és la mateixa que l'antiga: «%s»"
 
+#: builtin/replace.c
 #, c-format
 msgid ""
 "could not convert the following graft(s):\n"
@@ -11395,69 +14541,91 @@
 "no s'han pogut convertir els següents «grafts»:\n"
 "%s"
 
+#: builtin/replace.c
 msgid "list replace refs"
 msgstr "llista les referències de reemplaçament"
 
+#: builtin/replace.c
 msgid "delete replace refs"
 msgstr "suprimeix les referències de reemplaçament"
 
+#: builtin/replace.c
 msgid "edit existing object"
 msgstr "edita un objecte existent"
 
+#: builtin/replace.c
 msgid "change a commit's parents"
 msgstr "canvia els pares d'una comissió"
 
+#: builtin/replace.c
 msgid "convert existing graft file"
 msgstr "converteix el fitxer «graft» existent"
 
+#: builtin/replace.c
 msgid "replace the ref if it exists"
 msgstr "reemplaça la referència si existeix"
 
+#: builtin/replace.c
 msgid "do not pretty-print contents for --edit"
 msgstr "no imprimeixis bellament els continguts per a --edit"
 
+#: builtin/replace.c
 msgid "use this format"
 msgstr "usa aquest format"
 
+#: builtin/replace.c
 msgid "--format cannot be used when not listing"
 msgstr "no es pot utilitzar «--format» quan no s'està llistant"
 
+#: builtin/replace.c
 msgid "-f only makes sense when writing a replacement"
 msgstr "-f només té sentit quan s'escriu un reemplaçament"
 
+#: builtin/replace.c
 msgid "--raw only makes sense with --edit"
 msgstr "--raw només té sentit amb --edit"
 
+#: builtin/replace.c
 msgid "-d needs at least one argument"
 msgstr "-d necessita almenys un argument"
 
+#: builtin/replace.c
 msgid "bad number of arguments"
 msgstr "nombre incorrecte d'arguments"
 
+#: builtin/replace.c
 msgid "-e needs exactly one argument"
 msgstr "-e necessita exactament un argument"
 
+#: builtin/replace.c
 msgid "-g needs at least one argument"
 msgstr "-g necessita almenys un argument"
 
+#: builtin/replace.c
 msgid "--convert-graft-file takes no argument"
 msgstr "--convert-graft-file arguments"
 
+#: builtin/replace.c
 msgid "only one pattern can be given with -l"
 msgstr "només es pot especificar un patró amb -l"
 
+#: builtin/replay.c
 msgid "need some commits to replay"
 msgstr "calen algunes comissions per tornar a reproduir"
 
+#: builtin/replay.c
 msgid "--onto and --advance are incompatible"
 msgstr "--onto i --advance són incompatibles"
 
+#: builtin/replay.c
 msgid "all positive revisions given must be references"
 msgstr "totes les revisions positives que s'han donat han de ser referències"
 
+#: builtin/replay.c
 msgid "argument to --advance must be a reference"
 msgstr "l'argument per a --advance ha de ser una referència"
 
+#: builtin/replay.c
 msgid ""
 "cannot advance target with multiple sources because ordering would be ill-"
 "defined"
@@ -11465,12 +14633,14 @@
 "no es pot avançar l'objectiu amb múltiples fonts perquè l'ordenació no "
 "estaria definida correctament"
 
+#: builtin/replay.c
 msgid ""
 "cannot implicitly determine whether this is an --advance or --onto operation"
 msgstr ""
 "no es pot determinar implícitament si aquesta és una operació --advance o --"
 "onto"
 
+#: builtin/replay.c
 msgid ""
 "cannot advance target with multiple source branches because ordering would "
 "be ill-defined"
@@ -11478,9 +14648,11 @@
 "no es pot avançar l'objectiu amb múltiples branques d'origen perquè "
 "l'ordenació no estaria definida correctament"
 
+#: builtin/replay.c
 msgid "cannot implicitly determine correct base for --onto"
 msgstr "no es pot determinar implícitament la base correcta per a --onto"
 
+#: builtin/replay.c
 msgid ""
 "(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
 "<branch>) <revision-range>..."
@@ -11488,18 +14660,23 @@
 "(EXPERIMENTAL!) git replay ([--contained] --onto <newbase> | --advance "
 "<branch>) <revision-range>..."
 
+#: builtin/replay.c
 msgid "make replay advance given branch"
 msgstr "fes avançar la repetició de la branca donada"
 
+#: builtin/replay.c
 msgid "replay onto given commit"
 msgstr "torna a reproduir a la comissió donada"
 
+#: builtin/replay.c
 msgid "advance all branches contained in revision-range"
 msgstr "avança totes les branques contingudes a l'interval de revisions"
 
+#: builtin/replay.c
 msgid "option --onto or --advance is mandatory"
 msgstr "l'opció --onto o --advance és obligatòria"
 
+#: builtin/replay.c
 #, c-format
 msgid ""
 "some rev walking options will be overridden as '%s' bit in 'struct rev_info' "
@@ -11508,124 +14685,159 @@
 "algunes opcions de referència se sobreescriuran de forma forçada com a «%s» "
 "bits a «struct rev_info»"
 
+#: builtin/replay.c
 msgid "error preparing revisions"
 msgstr "s'ha produït un error en preparar les revisions"
 
+#: builtin/replay.c
 msgid "replaying down to root commit is not supported yet!"
 msgstr "encara no s'admet la reproducció cap avall en una comissió arrel"
 
+#: builtin/replay.c
 msgid "replaying merge commits is not supported yet!"
-msgstr "encara no s'admet la repetició de les comissió de fusió"
+msgstr "encara no s'admet la repetició de les comissions de fusió"
 
+#: builtin/rerere.c
 msgid ""
 "git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
 msgstr ""
 "git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
 
+#: builtin/rerere.c
 msgid "register clean resolutions in index"
 msgstr "registra les resolucions netes en l'índex"
 
+#: builtin/rerere.c
 msgid "'git rerere forget' without paths is deprecated"
 msgstr "«git rerere forget» sense camins està en desús"
 
+#: builtin/rerere.c
 #, c-format
 msgid "unable to generate diff for '%s'"
 msgstr "no s'ha pogut generar el diff per a «%s»"
 
+#: builtin/reset.c
 msgid ""
 "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
 msgstr ""
 "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<comissió>]"
 
+#: builtin/reset.c
 msgid "git reset [-q] [<tree-ish>] [--] <pathspec>..."
 msgstr "git reset [-q] [<tree-ish>] [--] <pathspec>..."
 
+#: builtin/reset.c
 msgid ""
 "git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"
 msgstr ""
 "git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"
 
+#: builtin/reset.c
 msgid "git reset --patch [<tree-ish>] [--] [<pathspec>...]"
 msgstr "git reset --patch [<tree-ish>] [--] [<pathspec>...]"
 
+#: builtin/reset.c
 msgid "mixed"
 msgstr "mixt"
 
+#: builtin/reset.c
 msgid "soft"
 msgstr "suau"
 
+#: builtin/reset.c
 msgid "hard"
 msgstr "dur"
 
+#: builtin/reset.c
 msgid "merge"
 msgstr "fusió"
 
+#: builtin/reset.c
 msgid "keep"
 msgstr "reteniment"
 
+#: builtin/reset.c
 msgid "You do not have a valid HEAD."
 msgstr "No teniu una HEAD vàlida."
 
+#: builtin/reset.c
 msgid "Failed to find tree of HEAD."
 msgstr "S'ha produït un error en trobar l'arbre de HEAD."
 
+#: builtin/reset.c
 #, c-format
 msgid "Failed to find tree of %s."
 msgstr "S'ha produït un error en cercar l'arbre de %s."
 
+#: builtin/reset.c
 #, c-format
 msgid "HEAD is now at %s"
 msgstr "HEAD ara és a %s"
 
+#: builtin/reset.c
 #, c-format
 msgid "Cannot do a %s reset in the middle of a merge."
 msgstr "No es pot fer un restabliment de %s enmig d'una fusió."
 
+#: builtin/reset.c builtin/stash.c
 msgid "be quiet, only report errors"
 msgstr "sigues silenciós, només informa d'errors"
 
+#: builtin/reset.c
 msgid "skip refreshing the index after reset"
 msgstr "omet l'actualització de l'índex després de reiniciar"
 
+#: builtin/reset.c
 msgid "reset HEAD and index"
 msgstr "restableix HEAD i l'índex"
 
+#: builtin/reset.c
 msgid "reset only HEAD"
 msgstr "restableix només HEAD"
 
+#: builtin/reset.c
 msgid "reset HEAD, index and working tree"
 msgstr "restableix HEAD, l'índex i l'arbre de treball"
 
+#: builtin/reset.c
 msgid "reset HEAD but keep local changes"
 msgstr "restableix HEAD però retén els canvis locals"
 
+#: builtin/reset.c
 msgid "record only the fact that removed paths will be added later"
 msgstr "registra només el fet que els camins eliminats s'afegiran després"
 
+#: builtin/reset.c
 #, c-format
 msgid "Failed to resolve '%s' as a valid revision."
 msgstr "S'ha produït un error en resoldre «%s» com a revisió vàlida."
 
+#: builtin/reset.c
 #, c-format
 msgid "Failed to resolve '%s' as a valid tree."
 msgstr "S'ha produït un error en resoldre «%s» com a arbre vàlid."
 
+#: builtin/reset.c
 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
 msgstr ""
 "--mixed amb camins està en desús; useu «git reset -- <camins>» en lloc "
 "d'això."
 
+#: builtin/reset.c
 #, c-format
 msgid "Cannot do %s reset with paths."
 msgstr "No es pot restablir de %s amb camins."
 
+#: builtin/reset.c
 #, c-format
 msgid "%s reset is not allowed in a bare repository"
 msgstr "el restabliment de %s no es permet en un repositori nu"
 
+#: builtin/reset.c
 msgid "Unstaged changes after reset:"
 msgstr "Canvis «unstaged» després del restabliment:"
 
+#: builtin/reset.c
 #, c-format
 msgid ""
 "It took %.2f seconds to refresh the index after reset.  You can use\n"
@@ -11635,52 +14847,67 @@
 "usar\n"
 ".--no-refresh' per a evitar això."
 
+#: builtin/reset.c
 #, c-format
 msgid "Could not reset index file to revision '%s'."
 msgstr "No s'ha pogut restablir el fitxer d'índex a la revisió «%s»."
 
+#: builtin/reset.c
 msgid "Could not write new index file."
 msgstr "No s'ha pogut escriure el fitxer d'índex nou."
 
+#: builtin/rev-list.c
 #, c-format
 msgid "unable to get disk usage of %s"
 msgstr "no s'ha pogut obtenir l'ús del disc de %s"
 
+#: builtin/rev-list.c
 #, c-format
 msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
 msgstr "valor no vàlid per a «%s»: «%s», l'únic format permès és «%s»"
 
+#: builtin/rev-list.c
 msgid "rev-list does not support display of notes"
 msgstr "el rev-list no permet mostrar notes"
 
+#: builtin/rev-list.c
 #, c-format
 msgid "marked counting and '%s' cannot be used together"
 msgstr "«marked counting» i «%s» no es poden usar junts"
 
+#: builtin/rev-parse.c
 msgid "git rev-parse --parseopt [<options>] -- [<args>...]"
 msgstr "git rev-parse --parseopt [<opcions>] -- [<arguments>...]"
 
+#: builtin/rev-parse.c
 msgid "keep the `--` passed as an arg"
 msgstr "retén el «--» passat com a argument"
 
+#: builtin/rev-parse.c
 msgid "stop parsing after the first non-option argument"
 msgstr "deixa d'analitzar després del primer argument que no sigui d'opció"
 
+#: builtin/rev-parse.c
 msgid "output in stuck long form"
 msgstr "emet en forma llarga enganxada"
 
+#: builtin/rev-parse.c
 msgid "premature end of input"
 msgstr "final prematur de l'entrada"
 
+#: builtin/rev-parse.c
 msgid "no usage string given before the `--' separator"
 msgstr "no s'ha indicat cap cadena d'ús abans del separador «--»"
 
+#: builtin/rev-parse.c
 msgid "missing opt-spec before option flags"
 msgstr "manca l'opció opt-spec abans de les altres opcions"
 
+#: builtin/rev-parse.c
 msgid "Needed a single revision"
 msgstr "Cal una sola revisió"
 
+#: builtin/rev-parse.c
 msgid ""
 "git rev-parse --parseopt [<options>] -- [<args>...]\n"
 "   or: git rev-parse --sq-quote [<arg>...]\n"
@@ -11695,46 +14922,68 @@
 "Executeu «git rev-parse --parseopt -h» per a més informació sobre el primer "
 "ús."
 
+#: builtin/rev-parse.c
 msgid "--resolve-git-dir requires an argument"
 msgstr "--resolve-git-dir requereix un argument"
 
+#: builtin/rev-parse.c
 #, c-format
 msgid "not a gitdir '%s'"
 msgstr "no és un directori git «%s»"
 
+#: builtin/rev-parse.c
 msgid "--git-path requires an argument"
 msgstr "--git-path requereix un argument"
 
+#: builtin/rev-parse.c
 msgid "-n requires an argument"
 msgstr "-n requereix un argument"
 
+#: builtin/rev-parse.c
 msgid "--path-format requires an argument"
 msgstr "--path-format requereix un argument"
 
+#: builtin/rev-parse.c
 #, c-format
 msgid "unknown argument to --path-format: %s"
 msgstr "argument no vàlid per a --path-format: %s"
 
+#: builtin/rev-parse.c
 msgid "--default requires an argument"
 msgstr "--default requereix un argument"
 
+#: builtin/rev-parse.c
 msgid "--prefix requires an argument"
 msgstr "--prefix requereix un argument"
 
+#: builtin/rev-parse.c
+msgid "no object format specified"
+msgstr "no s'ha especificat cap format d'objecte"
+
+#: builtin/rev-parse.c
+#, c-format
+msgid "unsupported object format: %s"
+msgstr "format d'objecte no compatible: %s"
+
+#: builtin/rev-parse.c
 #, c-format
 msgid "unknown mode for --abbrev-ref: %s"
 msgstr "mode desconegut per a --abbrev-ref: %s"
 
+#: builtin/rev-parse.c setup.c
 msgid "this operation must be run in a work tree"
 msgstr "aquesta operació s'ha d'executar en un arbre de treball"
 
+#: builtin/rev-parse.c
 msgid "Could not read the index"
 msgstr "No s'ha pogut llegir l'índex"
 
+#: builtin/rev-parse.c
 #, c-format
 msgid "unknown mode for --show-object-format: %s"
 msgstr "mode desconegut per a --show-object-format: %s"
 
+#: builtin/revert.c
 msgid ""
 "git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] "
 "<commit>..."
@@ -11742,9 +14991,11 @@
 "git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] "
 "<comissió>..."
 
+#: builtin/revert.c
 msgid "git revert (--continue | --skip | --abort | --quit)"
 msgstr "git revert (--continue | --skip | --abort | --quit)"
 
+#: builtin/revert.c
 msgid ""
 "git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
 "                [-S[<keyid>]] <commit>..."
@@ -11752,68 +15003,89 @@
 "git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
 "                [-S[<keyid>]] <comissió>..."
 
+#: builtin/revert.c
 msgid "git cherry-pick (--continue | --skip | --abort | --quit)"
 msgstr "git cherry-pick (--continue | --skip | --abort | --quit)"
 
+#: builtin/revert.c
 #, c-format
 msgid "option `%s' expects a number greater than zero"
 msgstr "l'opció «%s» espera un nombre major que zero"
 
+#: builtin/revert.c
 #, c-format
 msgid "%s: %s cannot be used with %s"
 msgstr "%s: %s no es pot usar amb %s"
 
+#: builtin/revert.c
 msgid "end revert or cherry-pick sequence"
 msgstr "acaba la seqüència de reversió o el «cherry pick»"
 
+#: builtin/revert.c
 msgid "resume revert or cherry-pick sequence"
 msgstr "reprèn la seqüència de reversió o el «cherry pick»"
 
+#: builtin/revert.c
 msgid "cancel revert or cherry-pick sequence"
 msgstr "cancel·la la seqüència de reversió o el «cherry pick»"
 
+#: builtin/revert.c
 msgid "skip current commit and continue"
 msgstr "omet la comissió actual i continua"
 
+#: builtin/revert.c
 msgid "don't automatically commit"
 msgstr "no cometis automàticament"
 
+#: builtin/revert.c
 msgid "edit the commit message"
 msgstr "edita el missatge de comissió"
 
+#: builtin/revert.c
 msgid "parent-number"
 msgstr "número del pare"
 
+#: builtin/revert.c
 msgid "select mainline parent"
 msgstr "selecciona la línia principal del pare"
 
+#: builtin/revert.c
 msgid "merge strategy"
 msgstr "estratègia de fusió"
 
+#: builtin/revert.c
 msgid "option for merge strategy"
 msgstr "opció d'estratègia de fusió"
 
+#: builtin/revert.c
 msgid "append commit name"
 msgstr "nom de la comissió a annexar"
 
+#: builtin/revert.c
 msgid "preserve initially empty commits"
 msgstr "conserva les comissions inicialment buides"
 
+#: builtin/revert.c
 msgid "allow commits with empty messages"
 msgstr "permet les comissions amb missatges buits"
 
-msgid "keep redundant, empty commits"
-msgstr "retén les comissions redundants i buides"
+#: builtin/revert.c
+msgid "deprecated: use --empty=keep instead"
+msgstr "obsolet: utilitzeu --empty=keep en el seu lloc"
 
+#: builtin/revert.c
 msgid "use the 'reference' format to refer to commits"
 msgstr "useu el format «referència» per a referir-vos a les comissions"
 
+#: builtin/revert.c
 msgid "revert failed"
 msgstr "la reversió ha fallat"
 
+#: builtin/revert.c
 msgid "cherry-pick failed"
 msgstr "el «cherry pick» ha fallat"
 
+#: builtin/rm.c
 msgid ""
 "git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]\n"
 "       [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
@@ -11823,6 +15095,7 @@
 "       [--quiet] [--pathspec-from-file=<fitxer> [--pathspec-file-nul]]\n"
 "       [--] [<pathspec>...]"
 
+#: builtin/rm.c
 msgid ""
 "the following file has staged content different from both the\n"
 "file and the HEAD:"
@@ -11830,12 +15103,13 @@
 "the following files have staged content different from both the\n"
 "file and the HEAD:"
 msgstr[0] ""
-"el fitxer següent té contingut «staged» diferent al fitxer\n"
-"i a HEAD:"
+"el fitxer següent té contingut «staged» diferent del fitxer\n"
+"i de HEAD:"
 msgstr[1] ""
 "els fitxers següents tenen contingut «staged» diferent al fitxer\n"
 "i a HEAD:"
 
+#: builtin/rm.c
 msgid ""
 "\n"
 "(use -f to force removal)"
@@ -11843,11 +15117,13 @@
 "\n"
 "(useu -f per a forçar l'eliminació)"
 
+#: builtin/rm.c
 msgid "the following file has changes staged in the index:"
 msgid_plural "the following files have changes staged in the index:"
 msgstr[0] "el fitxer següent té canvis «staged» en l'índex:"
 msgstr[1] "els fitxers següents tenen canvis «staged» en l'índex:"
 
+#: builtin/rm.c
 msgid ""
 "\n"
 "(use --cached to keep the file, or -f to force removal)"
@@ -11855,42 +15131,53 @@
 "\n"
 "(useu --cached per a mantenir el fitxer, o -f per a forçar l'eliminació)"
 
+#: builtin/rm.c
 msgid "the following file has local modifications:"
 msgid_plural "the following files have local modifications:"
 msgstr[0] "el fitxer següent té modificacions locals:"
 msgstr[1] "els fitxers següents tenen modificacions locals:"
 
+#: builtin/rm.c
 msgid "do not list removed files"
 msgstr "no llistis els fitxers eliminats"
 
+#: builtin/rm.c
 msgid "only remove from the index"
 msgstr "només elimina de l'índex"
 
+#: builtin/rm.c
 msgid "override the up-to-date check"
 msgstr "passa per alt la comprovació d'actualitat"
 
+#: builtin/rm.c
 msgid "allow recursive removal"
 msgstr "permet l'eliminació recursiva"
 
+#: builtin/rm.c
 msgid "exit with a zero status even if nothing matched"
 msgstr "surt amb estat zero encara que res hagi coincidit"
 
+#: builtin/rm.c
 msgid "No pathspec was given. Which files should I remove?"
 msgstr ""
 "No s'ha indicat cap especificació de camí. Quins fitxers s'han de suprimir?"
 
+#: builtin/rm.c
 msgid "please stage your changes to .gitmodules or stash them to proceed"
 msgstr ""
 "feu un «stage» dels canvis a .gitmodules o feu un «stash» per a continuar"
 
+#: builtin/rm.c
 #, c-format
 msgid "not removing '%s' recursively without -r"
 msgstr "no s'eliminarà «%s» recursivament sense -r"
 
+#: builtin/rm.c
 #, c-format
 msgid "git rm: unable to remove %s"
 msgstr "git rm: no s'ha pogut eliminar %s"
 
+#: builtin/send-pack.c
 msgid ""
 "git send-pack [--mirror] [--dry-run] [--force]\n"
 "              [--receive-pack=<git-receive-pack>]\n"
@@ -11902,69 +15189,89 @@
 "              [--receive-pack=<git-receive-pack>]\n"
 "              [--verbose] [--thin] [--atomic]\n"
 "              [--[no-]signed | --signed=(true|false|if-asked)]\n"
-"              [<host>:]<directory> (--all | <ref>...)"
+"              [<host>:]<directori> (--all | <referència>...)"
 
+#: builtin/send-pack.c
 msgid "remote name"
 msgstr "nom del remot"
 
+#: builtin/send-pack.c
 msgid "push all refs"
 msgstr "puja totes les referències"
 
+#: builtin/send-pack.c
 msgid "use stateless RPC protocol"
 msgstr "usa el protocol RPC sense estat"
 
+#: builtin/send-pack.c
 msgid "read refs from stdin"
 msgstr "llegeix les referències des de stdin"
 
+#: builtin/send-pack.c
 msgid "print status from remote helper"
 msgstr "imprimeix l'estat des de l'ajudant remot"
 
+#: builtin/shortlog.c
 msgid "git shortlog [<options>] [<revision-range>] [[--] <path>...]"
 msgstr "git shortlog [<opcions>] [<rang-de-revisions>] [[--] <camí>...]"
 
+#: builtin/shortlog.c
 msgid "git log --pretty=short | git shortlog [<options>]"
 msgstr "git log --pretty=short | git shortlog [<opcions>]"
 
+#: builtin/shortlog.c
 msgid "using multiple --group options with stdin is not supported"
 msgstr "no s'admet l'ús de múltiples opcions --group amb stdin"
 
+#: builtin/shortlog.c
 #, c-format
 msgid "using %s with stdin is not supported"
 msgstr "no s'admet l'ús de %s amb stdin"
 
+#: builtin/shortlog.c
 #, c-format
 msgid "unknown group type: %s"
 msgstr "tipus de grup desconegut: %s"
 
+#: builtin/shortlog.c
 msgid "group by committer rather than author"
 msgstr "agrupa per «committer» en comptes de per autor"
 
+#: builtin/shortlog.c
 msgid "sort output according to the number of commits per author"
 msgstr "ordena la sortida segons el nombre de comissions per autor"
 
+#: builtin/shortlog.c
 msgid "suppress commit descriptions, only provides commit count"
 msgstr ""
 "omet les descripcions de les comissions, només proveeix el recompte de "
 "comissions"
 
+#: builtin/shortlog.c
 msgid "show the email address of each author"
 msgstr "mostra l'adreça electrònica de cada autor"
 
+#: builtin/shortlog.c
 msgid "<w>[,<i1>[,<i2>]]"
 msgstr "<w>[,<i1>[,<i2>]]"
 
+#: builtin/shortlog.c
 msgid "linewrap output"
 msgstr "ajusta les línies de la sortida"
 
+#: builtin/shortlog.c
 msgid "field"
 msgstr "camp"
 
+#: builtin/shortlog.c
 msgid "group by field"
 msgstr "agrupa per camp"
 
+#: builtin/shortlog.c
 msgid "too many arguments given outside repository"
 msgstr "hi ha massa arguments donats fora del repositori"
 
+#: builtin/show-branch.c
 msgid ""
 "git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
 "                [--current] [--color[=<when>] | --no-color] [--sparse]\n"
@@ -11976,114 +15283,144 @@
 "                [--current] [--color[=<when>] | --no-color] [--sparse]\n"
 "                [--more=<n> | --list | --independent | --merge-base]\n"
 "                [--no-name | --sha1-name] [--topics]\n"
-"                [(<rev> | <glob>)...]"
+"                [(<revisió> | <glob>)...]"
 
+#: builtin/show-branch.c
 msgid "git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"
 msgstr "git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<referència>]"
 
+#: builtin/show-branch.c
 #, c-format
 msgid "ignoring %s; cannot handle more than %d ref"
 msgid_plural "ignoring %s; cannot handle more than %d refs"
 msgstr[0] "s'està ignorant %s; no es pot gestionar més de %d referència"
 msgstr[1] "s'està ignorant %s; no es poden gestionar més de %d referències"
 
+#: builtin/show-branch.c
 #, c-format
 msgid "no matching refs with %s"
 msgstr "no hi ha referències coincidents amb %s"
 
+#: builtin/show-branch.c
 msgid "show remote-tracking and local branches"
 msgstr "mostra les branques amb seguiment remot i les locals"
 
+#: builtin/show-branch.c
 msgid "show remote-tracking branches"
 msgstr "mostra les branques amb seguiment remot"
 
+#: builtin/show-branch.c
 msgid "color '*!+-' corresponding to the branch"
 msgstr "colora «*!+-» corresponent a la branca"
 
+#: builtin/show-branch.c
 msgid "show <n> more commits after the common ancestor"
 msgstr "mostra <n> comissions després de l'avantpassat comú"
 
+#: builtin/show-branch.c
 msgid "synonym to more=-1"
 msgstr "sinònim de more=-1"
 
+#: builtin/show-branch.c
 msgid "suppress naming strings"
 msgstr "omet anomenar cadenes"
 
+#: builtin/show-branch.c
 msgid "include the current branch"
 msgstr "inclou la branca actual"
 
+#: builtin/show-branch.c
 msgid "name commits with their object names"
 msgstr "anomena les comissions amb els seus noms d'objecte"
 
+#: builtin/show-branch.c
 msgid "show possible merge bases"
 msgstr "mostra les bases de fusió possibles"
 
+#: builtin/show-branch.c
 msgid "show refs unreachable from any other ref"
 msgstr "mostra les referències inabastables de qualsevol altra referència"
 
+#: builtin/show-branch.c
 msgid "show commits in topological order"
 msgstr "mostra les comissions en ordre topològic"
 
+#: builtin/show-branch.c
 msgid "show only commits not on the first branch"
 msgstr "mostra només les comissions que no siguin en la primera branca"
 
+#: builtin/show-branch.c
 msgid "show merges reachable from only one tip"
 msgstr "mostra les fusions abastables de només una punta"
 
+#: builtin/show-branch.c
 msgid "topologically sort, maintaining date order where possible"
 msgstr "ordena topològicament, mantenint l'ordre de dates on sigui possible"
 
+#: builtin/show-branch.c
 msgid "<n>[,<base>]"
 msgstr "<n>[,<base>]"
 
+#: builtin/show-branch.c
 msgid "show <n> most recent ref-log entries starting at base"
 msgstr "mostra les <n> entrades més recents començant a la base"
 
+#: builtin/show-branch.c
 msgid "no branches given, and HEAD is not valid"
 msgstr "no s'ha donat cap branca, i HEAD no és vàlid"
 
+#: builtin/show-branch.c
 msgid "--reflog option needs one branch name"
 msgstr "l'opció --reflog necessita un nom de branca"
 
+#: builtin/show-branch.c
 #, c-format
 msgid "only %d entry can be shown at one time."
 msgid_plural "only %d entries can be shown at one time."
 msgstr[0] "es pot mostrar només %d entrada a la vegada."
 msgstr[1] "es poden mostrar només %d entrades a la vegada."
 
+#: builtin/show-branch.c
 #, c-format
 msgid "no such ref %s"
 msgstr "no hi ha tal referència %s"
 
+#: builtin/show-branch.c
 #, c-format
 msgid "cannot handle more than %d rev."
 msgid_plural "cannot handle more than %d revs."
 msgstr[0] "no es pot gestionar més d'%d revisió."
 msgstr[1] "no es poden gestionar més de %d revisions."
 
+#: builtin/show-branch.c
 #, c-format
 msgid "'%s' is not a valid ref."
 msgstr "«%s» no és una referència vàlida."
 
+#: builtin/show-branch.c
 #, c-format
 msgid "cannot find commit %s (%s)"
 msgstr "no es pot trobar la comissió %s (%s)"
 
+#: builtin/show-index.c
 msgid "hash-algorithm"
 msgstr "algorisme de resum"
 
+#: builtin/show-index.c
 msgid "Unknown hash algorithm"
 msgstr "Algorisme de resum desconegut"
 
+#: builtin/show-ref.c
 msgid ""
 "git show-ref [--head] [-d | --dereference]\n"
-"             [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-"             [--heads] [--] [<pattern>...]"
+"             [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+"             [--] [<pattern>...]"
 msgstr ""
 "git show-ref [--head] [-d | --dereference]\n"
-"             [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
-"             [--heads] [--] [<pattern>...]"
+"             [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+"             [--] [<patró>...]"
 
+#: builtin/show-ref.c
 msgid ""
 "git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
 "             [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
@@ -12091,49 +15428,63 @@
 msgstr ""
 "git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
 "             [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
-"             [--] [<ref>...]"
+"             [--] [<referència>...]"
 
+#: builtin/show-ref.c
 msgid "git show-ref --exclude-existing[=<pattern>]"
 msgstr "git show-ref --exclude-existing[=<patró>]"
 
+#: builtin/show-ref.c
 msgid "git show-ref --exists <ref>"
-msgstr "git show-ref --exists <ref>"
+msgstr "git show-ref --exists <referència>"
 
+#: builtin/show-ref.c
 msgid "reference does not exist"
 msgstr "la referència no existeix"
 
+#: builtin/show-ref.c
 msgid "failed to look up reference"
 msgstr "s'ha produït en cercar la referència"
 
-msgid "only show tags (can be combined with heads)"
-msgstr "mostra només les etiquetes (es pot combinar amb heads)"
+#: builtin/show-ref.c
+msgid "only show tags (can be combined with --branches)"
+msgstr "mostra només les etiquetes (es pot combinar amb --branches)"
 
-msgid "only show heads (can be combined with tags)"
-msgstr "mostra només els caps (es pot combinar amb tags)"
+#: builtin/show-ref.c
+msgid "only show branches (can be combined with --tags)"
+msgstr "mostra només les branques (es pot combinar amb --tags)"
 
+#: builtin/show-ref.c
 msgid "check for reference existence without resolving"
 msgstr "comprova l'existència de referència sense resoldre"
 
+#: builtin/show-ref.c
 msgid "stricter reference checking, requires exact ref path"
 msgstr ""
 "comprovació de referència més estricta, requereix el camí de referència "
 "exacte"
 
+#: builtin/show-ref.c
 msgid "show the HEAD reference, even if it would be filtered out"
 msgstr "mostra la referència HEAD, encara que es filtrés"
 
+#: builtin/show-ref.c
 msgid "dereference tags into object IDs"
 msgstr "desreferencia les etiquetes a ID d'objecte"
 
+#: builtin/show-ref.c
 msgid "only show SHA1 hash using <n> digits"
 msgstr "mostra el resum SHA1 usant només <n> xifres"
 
+#: builtin/show-ref.c
 msgid "do not print results to stdout (useful with --verify)"
 msgstr "no imprimeixis els resultats a stdout (útil amb --verify)"
 
+#: builtin/show-ref.c
 msgid "show refs from stdin that aren't in local repository"
 msgstr "mostra les referències de stdin que no siguin en el repositori local"
 
+#: builtin/sparse-checkout.c
 msgid ""
 "git sparse-checkout (init | list | set | add | reapply | disable | check-"
 "rules) [<options>]"
@@ -12141,14 +15492,17 @@
 "git sparse-checkout (init | list | set | add | reapply | disable | check-"
 "rules) [<opcions>]"
 
+#: builtin/sparse-checkout.c
 msgid "this worktree is not sparse"
 msgstr "aquest arbre de treball no és dispers"
 
+#: builtin/sparse-checkout.c
 msgid "this worktree is not sparse (sparse-checkout file may not exist)"
 msgstr ""
 "aquest arbre de treball no és dispers (pot ser que el fitxer sparse-checkout "
 "no existeixi)"
 
+#: builtin/sparse-checkout.c
 #, c-format
 msgid ""
 "directory '%s' contains untracked files, but is not in the sparse-checkout "
@@ -12157,53 +15511,73 @@
 "el directori «%s» conté fitxers no seguits, però no està en el con de sparse-"
 "checkout"
 
+#: builtin/sparse-checkout.c
 #, c-format
 msgid "failed to remove directory '%s'"
 msgstr "s'ha produït un error en suprimir el directori «%s»"
 
+#: builtin/sparse-checkout.c
 msgid "failed to create directory for sparse-checkout file"
 msgstr "no s'ha pogut crear el directori per al fitxer sparse-checkout"
 
+#: builtin/sparse-checkout.c
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "no he pogut fer fdopen de «%s»"
+
+#: builtin/sparse-checkout.c
 msgid "failed to initialize worktree config"
 msgstr "no s'ha pogut inicialitzar la configuració de l'arbre de treball"
 
+#: builtin/sparse-checkout.c
 msgid "failed to modify sparse-index config"
 msgstr "no s'ha pogut modificar la configuració de l'índex dispers"
 
+#: builtin/sparse-checkout.c
 msgid "initialize the sparse-checkout in cone mode"
 msgstr "inicialitza el «sparse-checkout» en mode con"
 
+#: builtin/sparse-checkout.c
 msgid "toggle the use of a sparse index"
 msgstr "commuta l'ús d'un índex dispers"
 
+#: builtin/sparse-checkout.c commit-graph.c midx-write.c sequencer.c
 #, c-format
 msgid "unable to create leading directories of %s"
 msgstr "no s'han pogut crear els directoris inicials de «%s»"
 
+#: builtin/sparse-checkout.c
 #, c-format
 msgid "failed to open '%s'"
 msgstr "s'ha produït un error en obrir «%s»"
 
+#: builtin/sparse-checkout.c
 #, c-format
 msgid "could not normalize path %s"
 msgstr "no s'ha pogut normalitzar el camí %s"
 
+#: builtin/sparse-checkout.c
 #, c-format
 msgid "unable to unquote C-style string '%s'"
 msgstr "no s'han pogut treure les cometes a la cadena amb estil C «%s»"
 
+#: builtin/sparse-checkout.c
 msgid "unable to load existing sparse-checkout patterns"
 msgstr "no s'han pogut carregar els patrons de «sparse-checkout» existents"
 
+#: builtin/sparse-checkout.c
 msgid "existing sparse-checkout patterns do not use cone mode"
 msgstr "els patrons de «sparse-checkout» existents no usen el mode con"
 
+#: builtin/sparse-checkout.c
 msgid "please run from the toplevel directory in non-cone mode"
 msgstr "executeu des del directori de nivell superior en mode que no sigui con"
 
+#: builtin/sparse-checkout.c
 msgid "specify directories rather than patterns (no leading slash)"
 msgstr "especifica els directoris en lloc dels patrons (sense barra inclinada)"
 
+#: builtin/sparse-checkout.c
 msgid ""
 "specify directories rather than patterns.  If your directory starts with a "
 "'!', pass --skip-checks"
@@ -12211,6 +15585,7 @@
 "especifica els directoris en lloc dels patrons.  Si el vostre directori "
 "comença amb un «!», passeu --skip-checks"
 
+#: builtin/sparse-checkout.c
 msgid ""
 "specify directories rather than patterns.  If your directory really has any "
 "of '*?[]\\' in it, pass --skip-checks"
@@ -12218,6 +15593,7 @@
 "especifica els directoris en lloc dels patrons.  Si el vostre directori "
 "realment té alguna de «*?[]\\», useu --skip-checks"
 
+#: builtin/sparse-checkout.c
 #, c-format
 msgid ""
 "'%s' is not a directory; to treat it as a directory anyway, rerun with --"
@@ -12226,6 +15602,7 @@
 "«%s» no és un directori; per a tractar-lo com un directori, torneu a "
 "executar amb --skip-checks"
 
+#: builtin/sparse-checkout.c
 #, c-format
 msgid ""
 "pass a leading slash before paths such as '%s' if you want a single file "
@@ -12234,35 +15611,43 @@
 "passa una barra d'inici abans dels camins com ara «%s» si voleu un sol "
 "fitxer (vegeu «NON-CONE PROBLEMS» al manual de git-sparse-checkout)."
 
+#: builtin/sparse-checkout.c
 msgid "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
-msgstr "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
+msgstr "git sparse-checkout add [--skip-checks] (--stdin | <patrons>)"
 
+#: builtin/sparse-checkout.c
 msgid ""
 "skip some sanity checks on the given paths that might give false positives"
 msgstr ""
 "omet alguns controls de sanitat en els camins donats que podrien donar "
 "falsos positius"
 
+#: builtin/sparse-checkout.c
 msgid "read patterns from standard in"
 msgstr "llegeix els patrons de l'entrada estàndard"
 
+#: builtin/sparse-checkout.c
 msgid "no sparse-checkout to add to"
 msgstr "no hi ha un sparse-checkout a afegir"
 
+#: builtin/sparse-checkout.c
 msgid ""
 "git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] "
 "(--stdin | <patterns>)"
 msgstr ""
 "git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] "
-"(--stdin | <patterns>)"
+"(--stdin | <patrons>)"
 
+#: builtin/sparse-checkout.c
 msgid "must be in a sparse-checkout to reapply sparsity patterns"
 msgstr ""
 "ha d'estar en un sparse-checkout per a tornar a aplicar patrons de dispersió"
 
+#: builtin/sparse-checkout.c
 msgid "error while refreshing working directory"
 msgstr "s'ha produït un error en actualitzar el directori de treball"
 
+#: builtin/sparse-checkout.c
 msgid ""
 "git sparse-checkout check-rules [-z] [--skip-checks][--[no-]cone] [--rules-"
 "file <file>]"
@@ -12270,20 +15655,25 @@
 "git sparse-checkout check-rules [-z] [--skip-checks][--[no-]cone] [--rules-"
 "file <fitxer>]"
 
+#: builtin/sparse-checkout.c
 msgid "terminate input and output files by a NUL character"
 msgstr "acaba els fitxers d'entrada i de sortida amb un caràcter NUL"
 
+#: builtin/sparse-checkout.c
 msgid "when used with --rules-file interpret patterns as cone mode patterns"
 msgstr ""
 "quan s'utilitza amb --rules-file, interpreta els patrons com a patrons del "
 "mode con"
 
+#: builtin/sparse-checkout.c
 msgid "use patterns in <file> instead of the current ones."
 msgstr "utilitza patrons en <file> en lloc dels actuals."
 
+#: builtin/stash.c
 msgid "git stash list [<log-options>]"
-msgstr "git stash list [<log-options>]"
+msgstr "git stash list [<opcions-registre>]"
 
+#: builtin/stash.c
 msgid ""
 "git stash show [-u | --include-untracked | --only-untracked] [<diff-"
 "options>] [<stash>]"
@@ -12291,22 +15681,28 @@
 "git stash show [-u | --include-untracked | --only-untracked] [<diff-"
 "options>] [<stash>]"
 
+#: builtin/stash.c
 msgid "git stash drop [-q | --quiet] [<stash>]"
 msgstr "git stash drop [-q | --quiet] [<stash>]"
 
+#: builtin/stash.c
 msgid "git stash pop [--index] [-q | --quiet] [<stash>]"
 msgstr "git stash pop [--index] [-q | --quiet] [<stash>]"
 
+#: builtin/stash.c
 msgid "git stash apply [--index] [-q | --quiet] [<stash>]"
 msgstr "git stash apply [--index] [-q | --quiet] [<stash>]"
 
+#: builtin/stash.c
 msgid "git stash branch <branchname> [<stash>]"
 msgstr "git stash branch <nom-de-branca> [<stash>]"
 
+#: builtin/stash.c
 msgid "git stash store [(-m | --message) <message>] [-q | --quiet] <commit>"
 msgstr ""
 "git stash store [(-m | --message) <missatge>] [-q | --quiet] <comissió>"
 
+#: builtin/stash.c
 msgid ""
 "git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q "
 "| --quiet]\n"
@@ -12322,6 +15718,7 @@
 "          [--pathspec-from-file=<fitxer> [--pathspec-file-nul]]\n"
 "          [--] [<pathspec>...]]"
 
+#: builtin/stash.c
 msgid ""
 "git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | "
 "--quiet]\n"
@@ -12331,27 +15728,34 @@
 "--quiet]\n"
 "          [-u | --include-untracked] [-a | --all] [<missatge>]"
 
+#: builtin/stash.c
 msgid "git stash create [<message>]"
 msgstr "git stash create [<missatge>]"
 
+#: builtin/stash.c
 #, c-format
 msgid "'%s' is not a stash-like commit"
 msgstr "«%s» no és una comissió de tipus «stash»"
 
+#: builtin/stash.c
 #, c-format
 msgid "Too many revisions specified:%s"
 msgstr "S'han especificat massa revisions:%s"
 
+#: builtin/stash.c
 msgid "No stash entries found."
 msgstr "No s'ha trobat cap entrada «stash»."
 
+#: builtin/stash.c
 #, c-format
 msgid "%s is not a valid reference"
 msgstr "«%s» no és una referència vàlida"
 
+#: builtin/stash.c
 msgid "git stash clear with arguments is unimplemented"
 msgstr "git stash clear amb paràmetres no està implementat"
 
+#: builtin/stash.c
 #, c-format
 msgid ""
 "WARNING: Untracked file in way of tracked file!  Renaming\n"
@@ -12362,154 +15766,202 @@
 "            %s -> %s\n"
 "         per a fer-ne espai.\n"
 
+#: builtin/stash.c
 msgid "cannot apply a stash in the middle of a merge"
 msgstr "no es pot aplicar un «stash» enmig d'una fusió"
 
+#: builtin/stash.c
 #, c-format
 msgid "could not generate diff %s^!."
 msgstr "no s'ha pogut generar diff %s^!."
 
+#: builtin/stash.c
 msgid "conflicts in index. Try without --index."
 msgstr "hi ha conflictes en l'índex. Proveu-ho sense --index."
 
+#: builtin/stash.c
 msgid "could not save index tree"
 msgstr "no s'ha pogut desar l'arbre d'índex"
 
+#: builtin/stash.c
 #, c-format
 msgid "Merging %s with %s"
 msgstr "S'està fusionant %s amb %s"
 
+#: builtin/stash.c
 msgid "Index was not unstashed."
 msgstr "L'índex no estava «unstashed»."
 
+#: builtin/stash.c
 msgid "could not restore untracked files from stash"
 msgstr "no s'han pogut restaurar els fitxers no seguits des del «stash»"
 
+#: builtin/stash.c
 msgid "attempt to recreate the index"
 msgstr "intenta tornar a crear l'índex"
 
+#: builtin/stash.c
 #, c-format
 msgid "Dropped %s (%s)"
 msgstr "Descartada %s (%s)"
 
+#: builtin/stash.c
 #, c-format
 msgid "%s: Could not drop stash entry"
 msgstr "%s: no s'ha pogut descartar l'entrada «stash»"
 
+#: builtin/stash.c
 #, c-format
 msgid "'%s' is not a stash reference"
 msgstr "«%s» no és una referència «stash»"
 
+#: builtin/stash.c
 msgid "The stash entry is kept in case you need it again."
-msgstr "Es conserva l'entrada «stash» en cas que la necessiteu altra vegada."
+msgstr ""
+"Es conserva l'entrada «stash» en cas que la necessiteu una altra vegada."
 
+#: builtin/stash.c
 msgid "No branch name specified"
 msgstr "Cap nom de branca especificat"
 
+#: builtin/stash.c
 msgid "failed to parse tree"
 msgstr "s'ha produït un error en analitzar l'arbre"
 
+#: builtin/stash.c
 msgid "failed to unpack trees"
 msgstr "s'ha produït un error en desempaquetar els arbres"
 
+#: builtin/stash.c
 msgid "include untracked files in the stash"
 msgstr "inclou els fitxers no seguits a «stash»"
 
+#: builtin/stash.c
 msgid "only show untracked files in the stash"
 msgstr "mostra només els fitxers no seguits a «stash»"
 
+#: builtin/stash.c
 #, c-format
 msgid "Cannot update %s with %s"
 msgstr "No es pot actualitzar %s amb %s"
 
+#: builtin/stash.c
 msgid "stash message"
 msgstr "missatge «stash»"
 
+#: builtin/stash.c
 msgid "\"git stash store\" requires one <commit> argument"
 msgstr "«git stash store» requereix un argument <comissió>"
 
+#: builtin/stash.c
 msgid "No staged changes"
 msgstr "No hi ha canvis a «stage»"
 
+#: builtin/stash.c
 msgid "No changes selected"
 msgstr "No hi ha canvis seleccionats"
 
+#: builtin/stash.c
 msgid "You do not have the initial commit yet"
 msgstr "Encara no teniu la comissió inicial"
 
+#: builtin/stash.c
 msgid "Cannot save the current index state"
 msgstr "No es pot desar l'estat d'índex actual"
 
+#: builtin/stash.c
 msgid "Cannot save the untracked files"
 msgstr "No es poden desar els fitxers no seguits"
 
+#: builtin/stash.c
 msgid "Cannot save the current worktree state"
 msgstr "No es pot desar l'estat d'arbre de treball actual"
 
+#: builtin/stash.c
 msgid "Cannot save the current staged state"
 msgstr "No es pot desar l'estat «stage» actual"
 
+#: builtin/stash.c
 msgid "Cannot record working tree state"
 msgstr "No es pot registrar l'estat de l'arbre de treball"
 
+#: builtin/stash.c
 msgid "Can't use --patch and --include-untracked or --all at the same time"
 msgstr "No es poden usar --patch i --include-untracked o --all a la vegada"
 
+#: builtin/stash.c
 msgid "Can't use --staged and --include-untracked or --all at the same time"
 msgstr "No es poden usar --staged i --include-untracked o --all a la vegada"
 
+#: builtin/stash.c
 msgid "Did you forget to 'git add'?"
 msgstr "Heu oblidat de fer «git add»?"
 
+#: builtin/stash.c
 msgid "No local changes to save"
 msgstr "No hi ha canvis locals a desar"
 
+#: builtin/stash.c
 msgid "Cannot initialize stash"
 msgstr "No es pot inicialitzar el magatzem"
 
+#: builtin/stash.c
 msgid "Cannot save the current status"
 msgstr "No es pot desar l'estat actual"
 
+#: builtin/stash.c
 #, c-format
 msgid "Saved working directory and index state %s"
 msgstr "S'han desat el directori de treball i l'estat d'índex %s"
 
+#: builtin/stash.c
 msgid "Cannot remove worktree changes"
 msgstr "No es poden eliminar els canvis de l'arbre de treball"
 
+#: builtin/stash.c
 msgid "keep index"
 msgstr "mantén l'índex"
 
+#: builtin/stash.c
 msgid "stash staged changes only"
 msgstr "fes «stash» només dels canvis «staged»"
 
+#: builtin/stash.c
 msgid "stash in patch mode"
 msgstr "fes «stash» en mode pedaç"
 
+#: builtin/stash.c
 msgid "quiet mode"
 msgstr "mode silenciós"
 
+#: builtin/stash.c
 msgid "include untracked files in stash"
 msgstr "inclou els fitxers no seguits a «stash»"
 
+#: builtin/stash.c
 msgid "include ignore files"
 msgstr "inclou els fitxers ignorats"
 
+#: builtin/stripspace.c
 msgid "skip and remove all lines starting with comment character"
 msgstr ""
 "omet i elimina totes les línies que comencin amb el caràcter de comentari"
 
+#: builtin/stripspace.c
 msgid "prepend comment character and space to each line"
 msgstr "anteposa el caràcter de comentari i un espai a cada línia"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Expecting a full ref name, got %s"
 msgstr "S'espera un nom de referència ple, s'ha rebut %s"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "could not get a repository handle for submodule '%s'"
 msgstr "no s'ha pogut obtenir el gestor del repositori pel submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid ""
 "could not look up configuration '%s'. Assuming this repository is its own "
@@ -12518,14 +15970,17 @@
 "no s'ha pogut trobar la configuració «%s». S'assumeix que aquest repositori "
 "és el seu repositori font autoritzat."
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
 msgstr "No s'ha trobat cap url per al camí de submòdul «%s» a .gitmodules"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Entering '%s'\n"
 msgstr "S'està entrant a «%s»\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid ""
 "run_command returned non-zero status for %s\n"
@@ -12534,6 +15989,7 @@
 "run_command ha retornat un estat diferent de zero per a %s\n"
 "."
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid ""
 "run_command returned non-zero status while recursing in the nested "
@@ -12544,56 +16000,70 @@
 "recursivament als submòduls imbricats de %s\n"
 "."
 
+#: builtin/submodule--helper.c
 msgid "suppress output of entering each submodule command"
 msgstr "omet la sortida en entrar a cada ordre del submòdul"
 
+#: builtin/submodule--helper.c
 msgid "recurse into nested submodules"
 msgstr "cerca recursivament als submòduls imbricats"
 
+#: builtin/submodule--helper.c
 msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
 msgstr "git submodule foreach [--quiet] [--recursive] [--] <ordre>"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Failed to register url for submodule path '%s'"
 msgstr "S'ha produït un error en registrar l'url per al camí de submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Submodule '%s' (%s) registered for path '%s'\n"
 msgstr "S'ha registrat el submòdul «%s» (%s) per al camí «%s»\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "warning: command update mode suggested for submodule '%s'\n"
 msgstr ""
 "advertència: se suggereix el mode d'actualització per ordre per al submòdul "
 "«%s»\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Failed to register update mode for submodule path '%s'"
 msgstr ""
 "S'ha produït un error en registrar el mode d'actualització per al camí de "
 "submòdul «%s»"
 
+#: builtin/submodule--helper.c
 msgid "suppress output for initializing a submodule"
 msgstr "omet la sortida en inicialitzar un submòdul"
 
+#: builtin/submodule--helper.c
 msgid "git submodule init [<options>] [<path>]"
 msgstr "git submodule init [<opcions>] [<camí>]"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "no submodule mapping found in .gitmodules for path '%s'"
 msgstr "no s'ha trobat cap mapatge de submòdul a .gitmodules per al camí «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "could not resolve HEAD ref inside the submodule '%s'"
 msgstr "no s'ha pogut resoldre la referència a HEAD dins del submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "failed to recurse into submodule '%s'"
 msgstr "s'ha produït un error en cercar recursivament al submòdul «%s»"
 
+#: builtin/submodule--helper.c
 msgid "suppress submodule status output"
 msgstr "suprimeix la sortida de l'estat del submòdul"
 
+#: builtin/submodule--helper.c
 msgid ""
 "use commit stored in the index instead of the one stored in the submodule "
 "HEAD"
@@ -12601,69 +16071,87 @@
 "utilitza la comissió emmagatzemada a l'índex en lloc de l'emmagatzemada al "
 "HEAD del submòdul"
 
+#: builtin/submodule--helper.c
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quiet] [--cached] [--recursive] [<camí>...]"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
 msgstr "* %s %s(blob)->%s(submòdul)"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "* %s %s(submodule)->%s(blob)"
 msgstr "* %s %s(submòdul)->%s(blob)"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "%s"
 msgstr "%s"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "couldn't hash object from '%s'"
 msgstr "no s'ha pogut fer el resum de l'objecte de «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
-msgid "unexpected mode %o\n"
-msgstr "mode inesperat %o\n"
+msgid "unexpected mode %o"
+msgstr "mode %o inesperat"
 
+#: builtin/submodule--helper.c
 msgid "use the commit stored in the index instead of the submodule HEAD"
 msgstr ""
 "utilitza la comissió emmagatzemada a l'índex en lloc de l'emmagatzemada al "
 "HEAD del submòdul"
 
+#: builtin/submodule--helper.c
 msgid "compare the commit in the index with that in the submodule HEAD"
 msgstr ""
 "compara la comissió emmagatzemada a l'índex en lloc de l'emmagatzemada al "
 "HEAD del submòdul"
 
+#: builtin/submodule--helper.c
 msgid "skip submodules with 'ignore_config' value set to 'all'"
 msgstr "omet els submòduls amb el valor «ignore_config» establert a «all»"
 
+#: builtin/submodule--helper.c
 msgid "limit the summary size"
 msgstr "limita la mida del resum"
 
+#: builtin/submodule--helper.c
 msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
 msgstr "git submodule summary [<opcions>] [<comissió>] [--] [<camí>]"
 
+#: builtin/submodule--helper.c
 msgid "could not fetch a revision for HEAD"
 msgstr "no s'ha pogut obtenir una revisió per a HEAD"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Synchronizing submodule url for '%s'\n"
 msgstr "S'està sincronitzant l'url del submòdul per a «%s»\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "failed to register url for submodule path '%s'"
 msgstr "s'ha produït un error en registrar l'url per al camí del submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "failed to update remote for submodule '%s'"
 msgstr "s'ha produït un error en actualitzar el remot pel submòdul «%s»"
 
+#: builtin/submodule--helper.c
 msgid "suppress output of synchronizing submodule url"
 msgstr "omet la sortida de la sincronització de l'URL del submòdul"
 
+#: builtin/submodule--helper.c
 msgid "git submodule sync [--quiet] [--recursive] [<path>]"
 msgstr "git submodule sync [--quiet] [--recursive] [<camí>]"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid ""
 "Submodule work tree '%s' contains a .git directory. This will be replaced "
@@ -12672,6 +16160,7 @@
 "L'arbre de treball del submòdul «%s» conté un directori .git. Aquest es "
 "reemplaçarà amb un fitxer a .git mitjançant l'ús d'«absorbgitdirs»."
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid ""
 "Submodule work tree '%s' contains local modifications; use '-f' to discard "
@@ -12680,38 +16169,47 @@
 "L'arbre de treball del submòdul «%s» conté modificacions locals; useu «-f» "
 "per a descartar-les"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Cleared directory '%s'\n"
 msgstr "S'ha esborrat el directori «%s»\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Could not remove submodule work tree '%s'\n"
 msgstr "No s'ha pogut eliminar l'arbre de treball de submòdul «%s»\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "could not create empty submodule directory %s"
 msgstr "no s'ha pogut crear el directori de submòdul buit %s"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Submodule '%s' (%s) unregistered for path '%s'\n"
 msgstr "S'ha desregistrat el submòdul «%s» (%s) per al camí «%s»\n"
 
+#: builtin/submodule--helper.c
 msgid "remove submodule working trees even if they contain local changes"
 msgstr ""
 "elimina els arbres de treball dels submòduls fins i tot si contenen canvis "
 "locals"
 
+#: builtin/submodule--helper.c
 msgid "unregister all submodules"
 msgstr "desregistra tots els submòduls"
 
+#: builtin/submodule--helper.c
 msgid ""
 "git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"
 msgstr ""
 "git submodule deinit [--quiet] [-f | --force] [--all | [--] [<camí>...]]"
 
+#: builtin/submodule--helper.c
 msgid "Use '--all' if you really want to deinitialize all submodules"
 msgstr "Useu «--all» si realment voleu desinicialitzar tots els submòduls"
 
+#: builtin/submodule--helper.c
 msgid ""
 "An alternate computed from a superproject's alternate is invalid.\n"
 "To allow Git to clone without an alternate in such a case, set\n"
@@ -12724,138 +16222,172 @@
 "submodule.alternateErrorStrategy a «info» o bé cloneu amb\n"
 "«--reference-if-able' en comptes de «--reference»."
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "could not get a repository handle for gitdir '%s'"
 msgstr "no s'ha pogut obtenir el gestor del repositori per al gitdir «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
 msgstr "el submòdul «%s» no pot afegir un alternatiu: %s"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Value '%s' for submodule.alternateErrorStrategy is not recognized"
 msgstr "No es reconeix el valor «%s» per a submodule.alternateErrorStrategy"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Value '%s' for submodule.alternateLocation is not recognized"
 msgstr "No es reconeix el valor «%s» per a submodule.alternateLocation"
 
+#: builtin/submodule--helper.c submodule.c
 #, c-format
 msgid "refusing to create/use '%s' in another submodule's git dir"
 msgstr "s'ha rebutjat crear/usar «%s» en el directori git d'un altre submòdul"
 
-#, c-format
-msgid "clone of '%s' into submodule path '%s' failed"
-msgstr "el clonatge de «%s» al camí de submòdul «%s» ha fallat"
-
+#: builtin/submodule--helper.c
 #, c-format
 msgid "directory not empty: '%s'"
 msgstr "directori no buit: «%s»"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "clone of '%s' into submodule path '%s' failed"
+msgstr "el clonatge de «%s» al camí de submòdul «%s» ha fallat"
+
+#: builtin/submodule--helper.c
 #, c-format
 msgid "could not get submodule directory for '%s'"
 msgstr "no s'ha pogut obtenir el directori de submòdul per a «%s»"
 
+#: builtin/submodule--helper.c
 msgid "alternative anchor for relative paths"
 msgstr "àncora alternativa per als camins relatius"
 
+#: builtin/submodule--helper.c
 msgid "where the new submodule will be cloned to"
 msgstr "a on es clonarà el submòdul nou"
 
+#: builtin/submodule--helper.c
 msgid "name of the new submodule"
 msgstr "nom del submòdul nou"
 
+#: builtin/submodule--helper.c
 msgid "url where to clone the submodule from"
 msgstr "url del qual clonar el submòdul"
 
+#: builtin/submodule--helper.c
 msgid "depth for shallow clones"
 msgstr "profunditat dels clons superficials"
 
+#: builtin/submodule--helper.c
 msgid "force cloning progress"
 msgstr "força el progrés del clonatge"
 
+#: builtin/submodule--helper.c
 msgid "disallow cloning into non-empty directory"
 msgstr "no permetis clonar en un directori no buit"
 
+#: builtin/submodule--helper.c
 msgid ""
 "git submodule--helper clone [--prefix=<path>] [--quiet] [--reference "
 "<repository>] [--name <name>] [--depth <depth>] [--single-branch] [--filter "
 "<filter-spec>] --url <url> --path <path>"
 msgstr ""
 "git submodule--helper clone [--prefix=<camí>] [--quiet] [--reference "
-"<repository>] [--name <name>] [--depth <depth>] [--single-branch] [--filter "
+"<repositori>] [--name <nom>] [--depth <depth>] [--single-branch] [--filter "
 "<filter-spec>] --url <url> --path <camí>"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
 msgstr ""
 "Mode d'actualització «%s» configurat no vàlid per al camí de submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Submodule path '%s' not initialized"
 msgstr "El camí de submòdul «%s» no està inicialitzat"
 
+#: builtin/submodule--helper.c
 msgid "Maybe you want to use 'update --init'?"
 msgstr "Potser voleu usar «update --init»?"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Skipping unmerged submodule %s"
 msgstr "S'està ometent el submòdul no fusionat %s"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Skipping submodule '%s'"
 msgstr "S'està ometent el submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "cannot clone submodule '%s' without a URL"
 msgstr "no es pot clonar el submòdul «%s» sense un URL"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
 msgstr "S'ha produït un error en clonar «%s». S'ha programat un reintent"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Failed to clone '%s' a second time, aborting"
 msgstr "S'ha produït un error per segon cop en clonar «%s», s'està avortant"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Unable to checkout '%s' in submodule path '%s'"
 msgstr "No s'ha pogut agafar «%s» en el camí de submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Unable to rebase '%s' in submodule path '%s'"
 msgstr "No s'ha pogut fer «rebase» «%s» en el camí de submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Unable to merge '%s' in submodule path '%s'"
 msgstr "No s'ha pogut fusionar «%s» en el camí de submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Execution of '%s %s' failed in submodule path '%s'"
 msgstr "L'execució de «%s %s» ha fallat en el camí de submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Submodule path '%s': checked out '%s'\n"
 msgstr "Camí de submòdul «%s»: s'ha agafat «%s»\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Submodule path '%s': rebased into '%s'\n"
 msgstr "Camí de submòdul «%s»: s'ha fet «rebase» en «%s»\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Submodule path '%s': merged in '%s'\n"
 msgstr "Camí de submòdul «%s»: s'ha fusionat en «%s»\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Submodule path '%s': '%s %s'\n"
 msgstr "El camí de submòdul «%s»: '%s %s'\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Unable to fetch in submodule path '%s'; trying to directly fetch %s:"
 msgstr ""
 "No s'ha pogut obtenir en el camí de submòdul «$%s»; s'està intentant obtenir "
 "directament %s:"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid ""
 "Fetched in submodule path '%s', but it did not contain %s. Direct fetching "
@@ -12864,10 +16396,12 @@
 "S'ha obtingut en un camí de submòdul «%s», però no contenia %s. L'obtenció "
 "directa d'aquesta comissió ha fallat."
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "could not initialize submodule at path '%s'"
 msgstr "no s'ha pogut inicialitzar el submòdul al camí «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
@@ -12876,62 +16410,80 @@
 "La branca de submòdul (%s) està configurada per a heretar la branca del "
 "superprojecte, però el superprojecte no és en cap branca"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
 msgstr "No s'ha pogut trobar la revisió actual al camí del submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Unable to fetch in submodule path '%s'"
 msgstr "No s'ha pogut obtenir el camí del submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Unable to find %s revision in submodule path '%s'"
 msgstr "No s'ha pogut trobar la revisió %s en el camí del submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Failed to recurse into submodule path '%s'"
 msgstr ""
 "s'ha produït un error en cercar recursivament al camí del submòdul «%s»"
 
+#: builtin/submodule--helper.c
 msgid "force checkout updates"
 msgstr "força les actualitzacions"
 
+#: builtin/submodule--helper.c
 msgid "initialize uninitialized submodules before update"
 msgstr "inicialitza els submòduls sense inicialitzar abans d'actualitzar"
 
+#: builtin/submodule--helper.c
 msgid "use SHA-1 of submodule's remote tracking branch"
 msgstr "usa el SHA-1 de la branca de seguiment remota del submòdul"
 
+#: builtin/submodule--helper.c
 msgid "traverse submodules recursively"
 msgstr "recorre els submòduls recursivament"
 
+#: builtin/submodule--helper.c
 msgid "don't fetch new objects from the remote site"
 msgstr "no obtinguis els objectes nous del lloc remot"
 
+#: builtin/submodule--helper.c
 msgid "use the 'checkout' update strategy (default)"
 msgstr "utilitza l'estratègia d'actualització «checkout» (predeterminada)"
 
+#: builtin/submodule--helper.c
 msgid "use the 'merge' update strategy"
 msgstr "utilitza l'estratègia d'actualització de «merge»"
 
+#: builtin/submodule--helper.c
 msgid "use the 'rebase' update strategy"
 msgstr "utilitza l'estratègia d'actualització de «rebase»"
 
+#: builtin/submodule--helper.c
 msgid "create a shallow clone truncated to the specified number of revisions"
 msgstr "crea un clon superficial truncat al nombre de revisions especificat"
 
+#: builtin/submodule--helper.c
 msgid "parallel jobs"
 msgstr "tasques paral·leles"
 
+#: builtin/submodule--helper.c
 msgid "whether the initial clone should follow the shallow recommendation"
 msgstr "si el clonatge inicial ha de seguir la recomanació de superficialitat"
 
+#: builtin/submodule--helper.c
 msgid "don't print cloning progress"
 msgstr "no imprimeixis el progrés del clonatge"
 
+#: builtin/submodule--helper.c
 msgid "disallow cloning into non-empty directory, implies --init"
 msgstr "no permetis clonar en un directori no buit, implica --init"
 
+#: builtin/submodule--helper.c
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
 "[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
@@ -12940,68 +16492,86 @@
 msgstr ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
 "[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
-"shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] "
+"shallow] [--reference <repositori>] [--recursive] [--[no-]single-branch] "
 "[--] [<camí>...]"
 
+#: builtin/submodule--helper.c submodule.c
 msgid "Failed to resolve HEAD as a valid ref."
 msgstr "S'ha produït un error en resoldre HEAD com a referència vàlida."
 
+#: builtin/submodule--helper.c
 msgid "git submodule absorbgitdirs [<options>] [<path>...]"
 msgstr "git submodule absorbgitdirs [<opcions>] [<camí>...]"
 
+#: builtin/submodule--helper.c
 msgid "suppress output for setting url of a submodule"
 msgstr "omet la sortida en configurar un URL d'un submòdul"
 
+#: builtin/submodule--helper.c
 msgid "git submodule set-url [--quiet] <path> <newurl>"
-msgstr "git submodule set-url [--quiet] <camí> <newurl>"
+msgstr "git submodule set-url [--quiet] <camí> <url-nou>"
 
+#: builtin/submodule--helper.c
 msgid "set the default tracking branch to master"
 msgstr "estableix la branca de seguiment per defecte a «master»"
 
+#: builtin/submodule--helper.c
 msgid "set the default tracking branch"
 msgstr "estableix la branca de seguiment per defecte"
 
+#: builtin/submodule--helper.c
 msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
 msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <camí>"
 
+#: builtin/submodule--helper.c
 msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
 msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <branca> <camí>"
 
+#: builtin/submodule--helper.c
 msgid "--branch or --default required"
 msgstr "cal --branch o --default"
 
+#: builtin/submodule--helper.c
 msgid "print only error messages"
 msgstr "mostra només els missatges d'error"
 
+#: builtin/submodule--helper.c
 msgid "force creation"
 msgstr "força la creació"
 
+#: builtin/submodule--helper.c
 msgid "show whether the branch would be created"
 msgstr "mostra si es crearà la branca"
 
+#: builtin/submodule--helper.c
 msgid ""
 "git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--"
 "quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> <start-name>"
 msgstr ""
 "git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--"
-"quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> <start-name>"
+"quiet] [-t|--track] [-n|--dry-run] <nom> <oid-inicial> <nom-inicial>"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "creating branch '%s'"
 msgstr "s'està creant la branca «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Adding existing repo at '%s' to the index\n"
 msgstr "S'està afegint el repositori existent a «%s» a l'índex\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "'%s' already exists and is not a valid git repo"
 msgstr "«%s» ja existeix i no és un repositori de git vàlid"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "A git directory for '%s' is found locally with remote(s):\n"
 msgstr "S'ha trobat un directori de git per a «%s» localment amb els remots:\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid ""
 "If you want to reuse this local git directory instead of cloning again from\n"
@@ -13019,46 +16589,58 @@
 "o no esteu segur de què vol dir això, trieu un altre nom amb l'opció «--"
 "name»."
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Reactivating local git directory for submodule '%s'\n"
 msgstr "S'està reactivant el directori de git local per al submòdul «%s»\n"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "unable to checkout submodule '%s'"
 msgstr "no s'ha pogut agafar el submòdul «%s»"
 
+#: builtin/submodule--helper.c
 msgid "please make sure that the .gitmodules file is in the working tree"
 msgstr "assegureu-vos que el fitxer .gitmodules és a l'arbre de treball"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Failed to add submodule '%s'"
 msgstr "S'ha produït un error en afegir el submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "Failed to register submodule '%s'"
 msgstr "S'ha produït un error en registrar el submòdul «%s»"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "'%s' already exists in the index"
 msgstr "«%s» ja existeix en l'índex"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "'%s' already exists in the index and is not a submodule"
 msgstr "«%s» ja existeix en l'índex i no és submòdul"
 
+#: builtin/submodule--helper.c read-cache.c
 #, c-format
 msgid "'%s' does not have a commit checked out"
 msgstr "«%s» no té una comissió comprovada"
 
+#: builtin/submodule--helper.c
 msgid "branch of repository to add as submodule"
 msgstr "la branca del repositori a afegir com a submòdul"
 
+#: builtin/submodule--helper.c
 msgid "allow adding an otherwise ignored submodule path"
 msgstr "permet afegir un camí de submòdul que si no s'hagués ignorat"
 
+#: builtin/submodule--helper.c
 msgid "borrow the objects from reference repositories"
 msgstr "manlleva els objectes dels repositoris de referències"
 
+#: builtin/submodule--helper.c
 msgid ""
 "sets the submodule's name to the given string instead of defaulting to its "
 "path"
@@ -13066,62 +16648,81 @@
 "estableix el nom del submòdul a la cadena donada en lloc de per defecte al "
 "seu camí"
 
+#: builtin/submodule--helper.c
 msgid "git submodule add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule add [<opcions>] [--] <repository> [<camí>]"
+msgstr "git submodule add [<opcions>] [--] <repositori> [<camí>]"
 
+#: builtin/submodule--helper.c
 msgid "Relative path can only be used from the toplevel of the working tree"
 msgstr ""
 "El camí relatiu només es pot usar des del nivell superior de l'arbre de "
 "treball"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "repo URL: '%s' must be absolute or begin with ./|../"
 msgstr "URL de repositori: «%s» ha de ser absolut o començar amb ./|../"
 
+#: builtin/submodule--helper.c
 #, c-format
 msgid "'%s' is not a valid submodule name"
 msgstr "«%s» no és un nom de submòdul vàlid"
 
+#: builtin/submodule--helper.c
 msgid "git submodule--helper <command>"
-msgstr "git submodule--helper <command>"
+msgstr "git submodule--helper <ordre>"
 
+#: builtin/symbolic-ref.c
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
-msgstr "git symbolic-ref [-m <reason>] <name> <ref>"
+msgstr "git symbolic-ref [-m <raó>] <nom> <referència>"
 
+#: builtin/symbolic-ref.c
 msgid "git symbolic-ref [-q] [--short] [--no-recurse] <name>"
-msgstr "git symbolic-ref [-q] [--short] [--no-recurse] <name>"
+msgstr "git symbolic-ref [-q] [--short] [--no-recurse] <nom>"
 
+#: builtin/symbolic-ref.c
 msgid "git symbolic-ref --delete [-q] <name>"
-msgstr "git symbolic-ref --delete [-q] <name>"
+msgstr "git symbolic-ref --delete [-q] <nom>"
 
+#: builtin/symbolic-ref.c
 msgid "suppress error message for non-symbolic (detached) refs"
 msgstr "omet el missatge d'error de referències no simbòliques (separades)"
 
+#: builtin/symbolic-ref.c
 msgid "delete symbolic ref"
 msgstr "suprimeix la referència simbòlica"
 
+#: builtin/symbolic-ref.c
 msgid "shorten ref output"
 msgstr "escurça la sortida de referències"
 
+#: builtin/symbolic-ref.c
 msgid "recursively dereference (default)"
 msgstr "desreferencia recursivament (per defecte)"
 
+#: builtin/symbolic-ref.c builtin/update-ref.c
 msgid "reason"
 msgstr "raó"
 
+#: builtin/symbolic-ref.c builtin/update-ref.c
 msgid "reason of the update"
 msgstr "raó de l'actualització"
 
+#: builtin/tag.c
 msgid ""
 "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+"        [(--trailer <token>[(=|:)<value>])...]\n"
 "        <tagname> [<commit> | <object>]"
 msgstr ""
-"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <fitxer>] [-e]\n"
-"        <tagname> [<comissió> | <objecte>]"
+"git tag [-a | -s | -u <id-clau>] [-f] [-m <missatge> | -F <fitxer>] [-e]\n"
+"        [(--trailer <token>[(=|:)<valor>])...]\n"
+"        <nom-etiqueta> [<comissió> | <objecte>]"
 
+#: builtin/tag.c
 msgid "git tag -d <tagname>..."
-msgstr "git tag -d <nom-d'etiqueta>..."
+msgstr "git tag -d <nom-etiqueta>..."
 
+#: builtin/tag.c
 msgid ""
 "git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
 "        [--points-at <object>] [--column[=<options>] | --no-column]\n"
@@ -13130,49 +16731,56 @@
 msgstr ""
 "git tag [-n[<num>]] -l [--contains <comissió>] [--no-contains <comissió>]\n"
 "        [--points-at <objecte>] [--column[=<opcions>] | --no-column]\n"
-"        [--create-reflog] [--sort=<key>] [--format=<format>]\n"
+"        [--create-reflog] [--sort=<clau>] [--format=<format>]\n"
 "        [--merged <comissió>] [--no-merged <comissió>] [<patró>...]"
 
+#: builtin/tag.c
 msgid "git tag -v [--format=<format>] <tagname>..."
-msgstr "git tag -v [--format=<format>] <nom-d'etiqueta>..."
+msgstr "git tag -v [--format=<format>] <nom-etiqueta>..."
 
+#: builtin/tag.c
 #, c-format
 msgid "tag '%s' not found."
 msgstr "no s'ha trobat l'etiqueta «%s»."
 
+#: builtin/tag.c
 #, c-format
 msgid "Deleted tag '%s' (was %s)\n"
 msgstr "S'ha suprimit l'etiqueta «%s» (era %s)\n"
 
+#: builtin/tag.c
 #, c-format
 msgid ""
 "\n"
 "Write a message for tag:\n"
 "  %s\n"
-"Lines starting with '%c' will be ignored.\n"
+"Lines starting with '%s' will be ignored.\n"
 msgstr ""
 "\n"
-"Escriviu el missatge de l'etiqueta:\n"
+"Escriviu un missatge per a l'etiqueta:\n"
 "  %s\n"
-"Les línies que comencin amb «%c» s'ignoraran.\n"
+"S'ignoraran les línies que comencen amb «%s».\n"
 
+#: builtin/tag.c
 #, c-format
 msgid ""
 "\n"
 "Write a message for tag:\n"
 "  %s\n"
-"Lines starting with '%c' will be kept; you may remove them yourself if you "
+"Lines starting with '%s' will be kept; you may remove them yourself if you "
 "want to.\n"
 msgstr ""
 "\n"
-"Escriviu el missatge de l'etiqueta:\n"
+"Escriviu un missatge per a l'etiqueta:\n"
 "  %s\n"
-"Les línies que comencin amb «%c» es retindran; podeu eliminar-les per vós "
-"mateix si voleu.\n"
+"Es mantindran les línies que comencin amb «%s»; les podeu eliminar si "
+"voleu.\n"
 
+#: builtin/tag.c
 msgid "unable to sign the tag"
 msgstr "no s'ha pogut signar l'etiqueta"
 
+#: builtin/tag.c
 #, c-format
 msgid ""
 "You have created a nested tag. The object referred to by your new tag is\n"
@@ -13186,275 +16794,361 @@
 "\n"
 "\tgit tag -f %s %s^{}"
 
+#: builtin/tag.c
 msgid "bad object type."
 msgstr "el tipus d'objecte és incorrecte."
 
+#: builtin/tag.c
 msgid "no tag message?"
 msgstr "no hi ha cap missatge d'etiqueta?"
 
+#: builtin/tag.c
 #, c-format
 msgid "The tag message has been left in %s\n"
 msgstr "S'ha deixat el missatge de l'etiqueta en %s\n"
 
+#: builtin/tag.c
 msgid "list tag names"
 msgstr "llista els noms d'etiqueta"
 
+#: builtin/tag.c
 msgid "print <n> lines of each tag message"
 msgstr "imprimeix <n> línies de cada missatge d'etiqueta"
 
+#: builtin/tag.c
 msgid "delete tags"
 msgstr "suprimeix les etiquetes"
 
+#: builtin/tag.c
 msgid "verify tags"
 msgstr "verifica les etiquetes"
 
+#: builtin/tag.c
 msgid "Tag creation options"
 msgstr "Opcions de creació d'etiquetes"
 
+#: builtin/tag.c
 msgid "annotated tag, needs a message"
 msgstr "etiqueta anotada, necessita un missatge"
 
+#: builtin/tag.c
 msgid "tag message"
 msgstr "missatge d'etiqueta"
 
+#: builtin/tag.c
 msgid "force edit of tag message"
 msgstr "força l'edició del missatge de l'etiqueta"
 
+#: builtin/tag.c
 msgid "annotated and GPG-signed tag"
 msgstr "etiqueta anotada i signada per GPG"
 
+#: builtin/tag.c
 msgid "use another key to sign the tag"
 msgstr "usa una altra clau per a signar l'etiqueta"
 
+#: builtin/tag.c
 msgid "replace the tag if exists"
 msgstr "reemplaça l'etiqueta si existeix"
 
+#: builtin/tag.c builtin/update-ref.c
 msgid "create a reflog"
 msgstr "crea un registre de referències"
 
+#: builtin/tag.c
 msgid "Tag listing options"
 msgstr "Opcions de llistat d'etiquetes"
 
+#: builtin/tag.c
 msgid "show tag list in columns"
 msgstr "mostra la llista d'etiquetes en columnes"
 
+#: builtin/tag.c
 msgid "print only tags that contain the commit"
 msgstr "imprimeix només les etiquetes que continguin la comissió"
 
+#: builtin/tag.c
 msgid "print only tags that don't contain the commit"
 msgstr "imprimeix només les etiquetes que no continguin la comissió"
 
+#: builtin/tag.c
 msgid "print only tags that are merged"
 msgstr "imprimeix només les etiquetes que s'han fusionat"
 
+#: builtin/tag.c
 msgid "print only tags that are not merged"
 msgstr "imprimeix només les etiquetes que no s'han fusionat"
 
+#: builtin/tag.c
 msgid "print only tags of the object"
 msgstr "imprimeix només les etiquetes de l'objecte"
 
+#: builtin/tag.c
+msgid "could not start 'git column'"
+msgstr "no s'ha pogut iniciar «git column»"
+
+#: builtin/tag.c
 #, c-format
 msgid "the '%s' option is only allowed in list mode"
 msgstr "l'opció «%s» només està permesa en mode de llista"
 
+#: builtin/tag.c
 #, c-format
 msgid "'%s' is not a valid tag name."
 msgstr "«%s» no és un nom d'etiqueta vàlid."
 
+#: builtin/tag.c
 #, c-format
 msgid "tag '%s' already exists"
 msgstr "l'etiqueta «%s» ja existeix"
 
+#: builtin/tag.c sequencer.c
 #, c-format
 msgid "Invalid cleanup mode %s"
 msgstr "Mode de neteja no vàlid %s"
 
+#: builtin/tag.c
 #, c-format
 msgid "Updated tag '%s' (was %s)\n"
 msgstr "Etiqueta «%s» actualitzada (era %s)\n"
 
+#: builtin/unpack-objects.c
 msgid "pack exceeds maximum allowed size"
 msgstr "el paquet supera la mida màxima permesa"
 
+#: builtin/unpack-objects.c
 msgid "failed to write object in stream"
 msgstr "no s'ha pogut escriure l'objecte al flux"
 
+#: builtin/unpack-objects.c
 #, c-format
 msgid "inflate returned (%d)"
 msgstr "inflate ha retornat (%d)"
 
+#: builtin/unpack-objects.c
 msgid "invalid blob object from stream"
 msgstr "l'objecte blob del flux no és vàlid"
 
+#: builtin/unpack-objects.c
 msgid "Unpacking objects"
 msgstr "S'estan desempaquetant els objectes"
 
+#: builtin/update-index.c
 #, c-format
 msgid "failed to create directory %s"
 msgstr "s'ha produït un error en crear el directori %s"
 
+#: builtin/update-index.c
 #, c-format
 msgid "failed to delete file %s"
 msgstr "s'ha produït un error en suprimir el fitxer %s"
 
+#: builtin/update-index.c
 #, c-format
 msgid "failed to delete directory %s"
 msgstr "s'ha produït un error en suprimir el directori %s"
 
+#: builtin/update-index.c
 #, c-format
 msgid "Testing mtime in '%s' "
 msgstr "S'està provant mtime en «%s» "
 
+#: builtin/update-index.c
 msgid "directory stat info does not change after adding a new file"
 msgstr ""
 "la informació de stat de directori no canvia després d'afegir un fitxer nou"
 
+#: builtin/update-index.c
 msgid "directory stat info does not change after adding a new directory"
 msgstr ""
 "la informació de stat de directori no canvia després d'afegir un directori "
 "nou"
 
+#: builtin/update-index.c
 msgid "directory stat info changes after updating a file"
 msgstr ""
 "la informació de stat de directori canvia després d'actualitzar un fitxer"
 
+#: builtin/update-index.c
 msgid "directory stat info changes after adding a file inside subdirectory"
 msgstr ""
 "la informació de stat de directori canvia després d'afegir un fitxer dins "
 "d'un subdirectori"
 
+#: builtin/update-index.c
 msgid "directory stat info does not change after deleting a file"
 msgstr ""
 "la informació de stat de directori no canvia després de suprimir un fitxer"
 
+#: builtin/update-index.c
 msgid "directory stat info does not change after deleting a directory"
 msgstr ""
 "la informació de stat de directori no canvia després de suprimir un directori"
 
+#: builtin/update-index.c
 msgid " OK"
 msgstr " D'acord"
 
+#: builtin/update-index.c
 msgid "git update-index [<options>] [--] [<file>...]"
 msgstr "git update-index [<opcions>] [--] [<fitxer>...]"
 
+#: builtin/update-index.c
 msgid "continue refresh even when index needs update"
 msgstr ""
 "continua l'actualització encara que l'índex necessiti una actualització"
 
+#: builtin/update-index.c
 msgid "refresh: ignore submodules"
 msgstr "actualitza: ignora els submòduls"
 
+#: builtin/update-index.c
 msgid "do not ignore new files"
 msgstr "no ignoris els fitxers nous"
 
+#: builtin/update-index.c
 msgid "let files replace directories and vice-versa"
 msgstr "deixa que els fitxers reemplacin els directoris i viceversa"
 
+#: builtin/update-index.c
 msgid "notice files missing from worktree"
 msgstr "tingues en compte els fitxers absents de l'arbre de treball"
 
+#: builtin/update-index.c
 msgid "refresh even if index contains unmerged entries"
 msgstr "actualitza encara que l'índex contingui entrades no fusionades"
 
+#: builtin/update-index.c
 msgid "refresh stat information"
 msgstr "actualitza la informació d'estadístiques"
 
+#: builtin/update-index.c
 msgid "like --refresh, but ignore assume-unchanged setting"
 msgstr "com --refresh, però ignora el paràmetre assume-unchanged"
 
+#: builtin/update-index.c
 msgid "<mode>,<object>,<path>"
 msgstr "<mode>,<objecte>,<camí>"
 
+#: builtin/update-index.c
 msgid "add the specified entry to the index"
 msgstr "afegeix l'entrada especificada a l'índex"
 
+#: builtin/update-index.c
 msgid "mark files as \"not changing\""
 msgstr "marca els fitxers com a «no canviant»"
 
+#: builtin/update-index.c
 msgid "clear assumed-unchanged bit"
 msgstr "esborra el bit assumed-unchanged"
 
+#: builtin/update-index.c
 msgid "mark files as \"index-only\""
 msgstr "marca els fitxers com a «només índex»"
 
+#: builtin/update-index.c
 msgid "clear skip-worktree bit"
 msgstr "esborra el bit skip-worktree"
 
+#: builtin/update-index.c
 msgid "do not touch index-only entries"
 msgstr "no toquis les entrades de només índex"
 
+#: builtin/update-index.c
 msgid "add to index only; do not add content to object database"
 msgstr ""
 "només afegeix a l'índex; no afegeixis el contingut a la base de dades "
 "d'objectes"
 
+#: builtin/update-index.c
 msgid "remove named paths even if present in worktree"
 msgstr ""
 "elimina els camins anomenats encara que estiguin presents en l'arbre de "
 "treball"
 
+#: builtin/update-index.c
 msgid "with --stdin: input lines are terminated by null bytes"
 msgstr "amb --stdin: les línies d'entrada acaben amb octets nuls"
 
+#: builtin/update-index.c
 msgid "read list of paths to be updated from standard input"
 msgstr "llegeix la llista de camins a actualitzar des de l'entrada estàndard"
 
+#: builtin/update-index.c
 msgid "add entries from standard input to the index"
 msgstr "afegeix les entrades de l'entrada estàndard a l'índex"
 
+#: builtin/update-index.c
 msgid "repopulate stages #2 and #3 for the listed paths"
 msgstr "reemplena les «stage» #2 i #3 per als camins llistats"
 
+#: builtin/update-index.c
 msgid "only update entries that differ from HEAD"
 msgstr "només actualitza les entrades que difereixin de HEAD"
 
+#: builtin/update-index.c
 msgid "ignore files missing from worktree"
 msgstr "ignora els fitxers absents de l'arbre de treball"
 
+#: builtin/update-index.c
 msgid "report actions to standard output"
 msgstr "informa de les accions en la sortida estàndard"
 
+#: builtin/update-index.c
 msgid "(for porcelains) forget saved unresolved conflicts"
 msgstr "(per a porcellanes) oblida't dels conflictes no resolts ni desats"
 
+#: builtin/update-index.c
 msgid "write index in this format"
 msgstr "escriu l'índex en aquest format"
 
+#: builtin/update-index.c
 msgid "report on-disk index format version"
 msgstr "informa sobre la versió del format de l'índex del disc"
 
+#: builtin/update-index.c
 msgid "enable or disable split index"
 msgstr "habilita o inhabilita l'índex dividit"
 
+#: builtin/update-index.c
 msgid "enable/disable untracked cache"
 msgstr "habilita/inhabilita la memòria cau no seguida"
 
+#: builtin/update-index.c
 msgid "test if the filesystem supports untracked cache"
 msgstr "prova si el sistema de fitxers admet la memòria cau no seguida"
 
+#: builtin/update-index.c
 msgid "enable untracked cache without testing the filesystem"
 msgstr "habilita la memòria cau no seguida sense provar el sistema de fitxers"
 
+#: builtin/update-index.c
 msgid "write out the index even if is not flagged as changed"
 msgstr "escriu l'índex encara que no estigui marcat com a canviat"
 
+#: builtin/update-index.c
 msgid "enable or disable file system monitor"
 msgstr "habilita o inhabilita el monitor del sistema de fitxers"
 
+#: builtin/update-index.c
 msgid "mark files as fsmonitor valid"
 msgstr "marca els fitxers com a vàlids pel fsmonitor"
 
+#: builtin/update-index.c
 msgid "clear fsmonitor valid bit"
 msgstr "esborra el bit de validesa del fsmonitor"
 
+#: builtin/update-index.c
 #, c-format
 msgid "%d\n"
 msgstr "%d\n"
 
+#: builtin/update-index.c
 #, c-format
 msgid "index-version: was %d, set to %d"
 msgstr "index-version: era %d, s'ha establert a %d"
 
+#: builtin/update-index.c
 msgid ""
 "core.splitIndex is set to false; remove or change it, if you really want to "
 "enable split index"
@@ -13462,6 +17156,7 @@
 "core.splitIndex està establert a fals; elimineu-lo o canviar-lo, si realment "
 "voleu habilitar l'índex dividit"
 
+#: builtin/update-index.c
 msgid ""
 "core.splitIndex is set to true; remove or change it, if you really want to "
 "disable split index"
@@ -13469,6 +17164,7 @@
 "core.splitIndex està establert a cert; elimineu-lo o canvieu-lo, si realment "
 "voleu inhabilitar l'índex dividit"
 
+#: builtin/update-index.c
 msgid ""
 "core.untrackedCache is set to true; remove or change it, if you really want "
 "to disable the untracked cache"
@@ -13476,9 +17172,11 @@
 "core.untrackedCache està establert a cert; elimineu-lo o canvieu-lo, si "
 "realment voleu inhabilitar el cau no seguit"
 
+#: builtin/update-index.c
 msgid "Untracked cache disabled"
 msgstr "La memòria cau no seguida està inhabilitada"
 
+#: builtin/update-index.c
 msgid ""
 "core.untrackedCache is set to false; remove or change it, if you really want "
 "to enable the untracked cache"
@@ -13486,96 +17184,124 @@
 "core.untrackedCache està establert a fals; elimineu-lo o canviar-lo, si "
 "realment voleu habilitar el cau no seguit"
 
+#: builtin/update-index.c
 #, c-format
 msgid "Untracked cache enabled for '%s'"
 msgstr "La memòria cau no seguida està habilitada per a «%s»"
 
+#: builtin/update-index.c
 msgid "core.fsmonitor is unset; set it if you really want to enable fsmonitor"
 msgstr ""
 "core.fsmonitor està establert a fals; establiu-lo a cert si realment voleu "
 "habilitar fsmonitor"
 
+#: builtin/update-index.c
 msgid "fsmonitor enabled"
 msgstr "fsmonitor habilitat"
 
+#: builtin/update-index.c
 msgid ""
 "core.fsmonitor is set; remove it if you really want to disable fsmonitor"
 msgstr ""
 "core.fsmonitor està establert a cert; elimineu-lo si realment voleu "
 "inhabilitar fsmonitor"
 
+#: builtin/update-index.c
 msgid "fsmonitor disabled"
 msgstr "fsmonitor inhabilitat"
 
-msgid "git update-ref [<options>] -d <refname> [<old-val>]"
-msgstr "git update-ref [<opcions>] -d <nom-de-referència> [<valor-antic>]"
+#: builtin/update-ref.c
+msgid "git update-ref [<options>] -d <refname> [<old-oid>]"
+msgstr "git update-ref [<opcions>] -d <nom-referència> [<oid-vell>]"
 
-msgid "git update-ref [<options>]    <refname> <new-val> [<old-val>]"
-msgstr ""
-"git update-ref [<opcions>]    <nom-de-referència> <valor-nou> [<valor-antic>]"
+#: builtin/update-ref.c
+msgid "git update-ref [<options>]    <refname> <new-oid> [<old-oid>]"
+msgstr "git update-ref [<opcions>]    <nom-referència> <oid-nou> [<oid-vell>]"
 
+#: builtin/update-ref.c
 msgid "git update-ref [<options>] --stdin [-z]"
 msgstr "git update-ref [<opcions>] --stdin [-z]"
 
+#: builtin/update-ref.c
 msgid "delete the reference"
 msgstr "suprimeix la referència"
 
+#: builtin/update-ref.c
 msgid "update <refname> not the one it points to"
-msgstr "actualitza <nom de referència>, no la que apunti"
+msgstr "actualitza <nom-referència>, no la que apunti"
 
+#: builtin/update-ref.c
 msgid "stdin has NUL-terminated arguments"
 msgstr "stdin té arguments acabats amb NUL"
 
+#: builtin/update-ref.c
 msgid "read updates from stdin"
 msgstr "llegeix les actualitzacions des de stdin"
 
+#: builtin/update-server-info.c
 msgid "update the info files from scratch"
 msgstr "actualitza els fitxers d'informació des de zero"
 
+#: builtin/upload-pack.c
 msgid ""
 "git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
 "                [--advertise-refs] <directory>"
 msgstr ""
 "git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
-"                [--advertise-refs] <directory>"
+"                [--advertise-refs] <directori>"
 
+#: builtin/upload-pack.c t/helper/test-serve-v2.c
 msgid "quit after a single request/response exchange"
 msgstr "surt després d'un sol intercanvi de sol·licitud/resposta"
 
+#: builtin/upload-pack.c
 msgid "serve up the info/refs for git-http-backend"
 msgstr "serveix les info/refs per a git-http-backend"
 
+#: builtin/upload-pack.c
 msgid "do not try <directory>/.git/ if <directory> is no Git directory"
 msgstr ""
 "no intentis <directori>/.git/ si <directori> no és cap directori del Git"
 
+#: builtin/upload-pack.c
 msgid "interrupt transfer after <n> seconds of inactivity"
 msgstr "interromp la transferència després de <n> segons d'inactivitat"
 
+#: builtin/verify-commit.c
 msgid "git verify-commit [-v | --verbose] [--raw] <commit>..."
 msgstr "git verify-commit [-v | --verbose] [--raw] <comissió>..."
 
+#: builtin/verify-commit.c
 msgid "print commit contents"
 msgstr "imprimeix els continguts de la comissió"
 
+#: builtin/verify-commit.c builtin/verify-tag.c
 msgid "print raw gpg status output"
 msgstr "imprimeix la sortida crua de l'estat gpg"
 
+#: builtin/verify-pack.c
 msgid "git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..."
-msgstr "git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..."
+msgstr ""
+"git verify-pack [-v | --verbose] [-s | --stat-only] [--] <paquet>.idx..."
 
+#: builtin/verify-pack.c
 msgid "verbose"
 msgstr "detallat"
 
+#: builtin/verify-pack.c
 msgid "show statistics only"
 msgstr "mostra només estadístiques"
 
+#: builtin/verify-tag.c
 msgid "git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."
-msgstr "git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."
+msgstr ""
+"git verify-tag [-v | --verbose] [--format=<format>] [--raw] <etiqueta>..."
 
+#: builtin/verify-tag.c
 msgid "print tag contents"
 msgstr "imprimeix els continguts de l'etiqueta"
 
+#: builtin/worktree.c
 msgid ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
 "                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
@@ -13583,30 +17309,39 @@
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <cadena>]]\n"
 "                 [--orphan] [(-b | -B) <new-branch>] <camí> [<commit-ish>]"
 
+#: builtin/worktree.c
 msgid "git worktree list [-v | --porcelain [-z]]"
 msgstr "git worktree list [-v | --porcelain [-z]]"
 
+#: builtin/worktree.c
 msgid "git worktree lock [--reason <string>] <worktree>"
-msgstr "git worktree lock [--reason <string>] <worktree>"
+msgstr "git worktree lock [--reason <cadena>] <arbre-treball>"
 
+#: builtin/worktree.c
 msgid "git worktree move <worktree> <new-path>"
-msgstr "git worktree move <arbre de treball> <camí-nou>"
+msgstr "git worktree move <arbre-treball> <camí-nou>"
 
+#: builtin/worktree.c
 msgid "git worktree prune [-n] [-v] [--expire <expire>]"
 msgstr "git worktree prune [-n] [-v] [--expire <expire>]"
 
+#: builtin/worktree.c
 msgid "git worktree remove [-f] <worktree>"
-msgstr "git worktree remove [-f] <worktree>"
+msgstr "git worktree remove [-f] <arbre-treball>"
 
+#: builtin/worktree.c
 msgid "git worktree repair [<path>...]"
 msgstr "git worktree repair [<camí>...]"
 
+#: builtin/worktree.c
 msgid "git worktree unlock <worktree>"
-msgstr "git worktree unlock <worktree>"
+msgstr "git worktree unlock <arbre-treball>"
 
+#: builtin/worktree.c
 msgid "No possible source branch, inferring '--orphan'"
 msgstr "No hi ha cap branca d'origen possible, inferint «--orphan»"
 
+#: builtin/worktree.c
 #, c-format
 msgid ""
 "If you meant to create a worktree containing a new unborn branch\n"
@@ -13621,6 +17356,7 @@
 "\n"
 "    git worktree add --orphan -b %s %s\n"
 
+#: builtin/worktree.c
 #, c-format
 msgid ""
 "If you meant to create a worktree containing a new unborn branch\n"
@@ -13635,24 +17371,30 @@
 "\n"
 "    git worktree add --orphan %s\n"
 
+#: builtin/worktree.c
 #, c-format
 msgid "Removing %s/%s: %s"
 msgstr "S'està eliminant %s/%s: %s"
 
+#: builtin/worktree.c
 msgid "report pruned working trees"
 msgstr "informa dels arbres de treball podats"
 
+#: builtin/worktree.c
 msgid "expire working trees older than <time>"
 msgstr "fes caducar els arbres de treball més antics que <data>"
 
+#: builtin/worktree.c
 #, c-format
 msgid "'%s' already exists"
 msgstr "«%s» ja existeix"
 
+#: builtin/worktree.c
 #, c-format
 msgid "unusable worktree destination '%s'"
 msgstr "destinació de l'arbre de treball no utilitzable «%s»"
 
+#: builtin/worktree.c
 #, c-format
 msgid ""
 "'%s' is a missing but locked worktree;\n"
@@ -13662,6 +17404,7 @@
 "useu «%s -f -f» per a sobreescriure-ho, o «unlock» i «prune» o «remove» per "
 "a netejar"
 
+#: builtin/worktree.c
 #, c-format
 msgid ""
 "'%s' is a missing but already registered worktree;\n"
@@ -13670,54 +17413,66 @@
 "manca «%s» però ja està registrat a l'arbre de treball;\n"
 "useu «%s»  per a sobreescriure-ho, o «prune» o «remove» per a netejar"
 
+#: builtin/worktree.c
 #, c-format
 msgid "failed to copy '%s' to '%s'; sparse-checkout may not work correctly"
 msgstr ""
 "no s'ha pogut copiar «%s» a «%s»; «sparse-checkout» pot no funcionar "
 "correctament"
 
+#: builtin/worktree.c
 #, c-format
 msgid "failed to copy worktree config from '%s' to '%s'"
 msgstr ""
 "no s'ha pogut copiar la configuració de l'arbre de treball de «%s» a «%s»"
 
+#: builtin/worktree.c
 #, c-format
 msgid "failed to unset '%s' in '%s'"
 msgstr "no s'ha pogut desassignar «%s» a «%s»"
 
+#: builtin/worktree.c
 #, c-format
 msgid "could not create directory of '%s'"
 msgstr "no s'ha pogut crear directori de «%s»"
 
+#: builtin/worktree.c
 msgid "initializing"
 msgstr "s'està inicialitzant"
 
+#: builtin/worktree.c
 #, c-format
 msgid "could not find created worktree '%s'"
 msgstr "no s'ha pogut trobar l'arbre de treball creat «%s»"
 
+#: builtin/worktree.c
 #, c-format
 msgid "Preparing worktree (new branch '%s')"
 msgstr "S'està preparant l'arbre de treball (branca nova «%s»)"
 
+#: builtin/worktree.c
 #, c-format
 msgid "Preparing worktree (resetting branch '%s'; was at %s)"
 msgstr ""
 "S'està preparant l'arbre de treball (s'està reiniciant la branca «%s»; "
 "estava a %s)"
 
+#: builtin/worktree.c
 #, c-format
 msgid "Preparing worktree (checking out '%s')"
 msgstr "S'està preparant l'arbre de treball (s'està agafant «%s»)"
 
+#: builtin/worktree.c
 #, c-format
 msgid "unreachable: invalid reference: %s"
 msgstr "no accessible: referència no vàlida: %s"
 
+#: builtin/worktree.c
 #, c-format
 msgid "Preparing worktree (detached HEAD %s)"
 msgstr "S'està preparant l'arbre de treball (HEAD %s separat)"
 
+#: builtin/worktree.c
 #, c-format
 msgid ""
 "HEAD points to an invalid (or orphaned) reference.\n"
@@ -13728,6 +17483,7 @@
 "Camí HEAD: «%s»\n"
 "Contingut HEAD: «%s»"
 
+#: builtin/worktree.c
 msgid ""
 "No local or remote refs exist despite at least one remote\n"
 "present, stopping; use 'add -f' to override or fetch a remote first"
@@ -13735,94 +17491,120 @@
 "No hi ha referències locals o remotes malgrat hi existeix almenys un\n"
 "remot, aturada; useu «add -f» per a anul·lar o obtenir primer un remot"
 
+#: builtin/worktree.c
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr "agafa <branca> encara que sigui agafada en altre arbre de treball"
 
+#: builtin/worktree.c
 msgid "create a new branch"
 msgstr "crea una branca nova"
 
+#: builtin/worktree.c
 msgid "create or reset a branch"
 msgstr "crea o restableix una branca"
 
+#: builtin/worktree.c
 msgid "create unborn branch"
 msgstr "crea una branca no nascuda"
 
+#: builtin/worktree.c
 msgid "populate the new working tree"
 msgstr "emplena l'arbre de treball nou"
 
+#: builtin/worktree.c
 msgid "keep the new working tree locked"
 msgstr "mantén l'arbre de treball nou bloquejat"
 
+#: builtin/worktree.c
 msgid "reason for locking"
 msgstr "raó per a bloquejar"
 
+#: builtin/worktree.c
 msgid "set up tracking mode (see git-branch(1))"
 msgstr "configura el mode de seguiment (vegeu git-branch(1))"
 
+#: builtin/worktree.c
 msgid "try to match the new branch name with a remote-tracking branch"
 msgstr ""
 "prova de fer coincidir el nom de la branca nova amb una branca amb seguiment "
 "remot"
 
+#: builtin/worktree.c diff.c parse-options.c
 #, c-format
 msgid "options '%s', '%s', and '%s' cannot be used together"
 msgstr "les opcions «%s», «%s», i «%s» no es poden usar juntes"
 
+#: builtin/worktree.c
 #, c-format
 msgid "option '%s' and commit-ish cannot be used together"
 msgstr "opció «%s» i les de comissió no es poden usar juntes"
 
+#: builtin/worktree.c
 msgid "added with --lock"
 msgstr "afegit amb --lock"
 
+#: builtin/worktree.c
 msgid "--[no-]track can only be used if a new branch is created"
 msgstr "--[no-]track només es pot usar si es crea una branca nova"
 
+#: builtin/worktree.c
 msgid "show extended annotations and reasons, if available"
 msgstr "mostra les anotacions esteses i les raons, si estan disponibles"
 
+#: builtin/worktree.c
 msgid "add 'prunable' annotation to worktrees older than <time>"
 msgstr ""
 "afegeix l'anotació «prunable» als arbres de treball més antics que <data>"
 
+#: builtin/worktree.c
 msgid "terminate records with a NUL character"
 msgstr "finalitza els registres amb un caràcter NUL"
 
+#: builtin/worktree.c
 #, c-format
 msgid "'%s' is not a working tree"
 msgstr "«%s» no és un arbre de treball"
 
+#: builtin/worktree.c
 msgid "The main working tree cannot be locked or unlocked"
 msgstr "No es pot bloquejar ni desbloquejar l'arbre de treball principal"
 
+#: builtin/worktree.c
 #, c-format
 msgid "'%s' is already locked, reason: %s"
 msgstr "«%s» ja està bloquejat, raó: «%s»"
 
+#: builtin/worktree.c
 #, c-format
 msgid "'%s' is already locked"
 msgstr "«%s» ja està bloquejat"
 
+#: builtin/worktree.c
 #, c-format
 msgid "'%s' is not locked"
 msgstr "«%s» no està bloquejat"
 
+#: builtin/worktree.c
 msgid "working trees containing submodules cannot be moved or removed"
 msgstr ""
 "els arbres de treball que contenen submòduls no es poden moure ni eliminar"
 
+#: builtin/worktree.c
 msgid "force move even if worktree is dirty or locked"
 msgstr ""
 "força el moviment encara que l'arbre de treball estigui brut o bloquejat"
 
+#: builtin/worktree.c
 #, c-format
 msgid "'%s' is a main working tree"
 msgstr "«%s» és un arbre de treball principal"
 
+#: builtin/worktree.c
 #, c-format
 msgid "could not figure out destination name from '%s'"
 msgstr "no s'ha pogut deduir el nom de destí des de «%s»"
 
+#: builtin/worktree.c
 #, c-format
 msgid ""
 "cannot move a locked working tree, lock reason: %s\n"
@@ -13831,6 +17613,7 @@
 "no es pot moure un arbre de treball bloquejat, raó del bloqueig: %s\n"
 "useu primer «move -f -f» per a sobreescriure'l o desbloquejar-lo primer"
 
+#: builtin/worktree.c
 msgid ""
 "cannot move a locked working tree;\n"
 "use 'move -f -f' to override or unlock first"
@@ -13838,31 +17621,38 @@
 "no es pot moure un arbre de treball bloquejat;\n"
 "useu primer «move -f -f» per a sobreescriure'l o desbloquejar-lo primer"
 
+#: builtin/worktree.c
 #, c-format
 msgid "validation failed, cannot move working tree: %s"
 msgstr "la validació ha fallat, no es pot moure l'arbre de treball: %s"
 
+#: builtin/worktree.c
 #, c-format
 msgid "failed to move '%s' to '%s'"
 msgstr "s'ha produït un error en moure «%s» a «%s»"
 
+#: builtin/worktree.c
 #, c-format
 msgid "failed to run 'git status' on '%s'"
 msgstr "no s'ha pogut executar «git status» a «%s»"
 
+#: builtin/worktree.c
 #, c-format
 msgid "'%s' contains modified or untracked files, use --force to delete it"
 msgstr ""
 "«%s» conté fitxers modificats o no seguits, useu --force per a suprimir-los"
 
+#: builtin/worktree.c
 #, c-format
 msgid "failed to run 'git status' on '%s', code %d"
 msgstr "no s'ha pogut executar «git status» a «%s», codi %d"
 
+#: builtin/worktree.c
 msgid "force removal even if worktree is dirty or locked"
 msgstr ""
 "força l'eliminació encara que l'arbre de treball estigui brut o bloquejat"
 
+#: builtin/worktree.c
 #, c-format
 msgid ""
 "cannot remove a locked working tree, lock reason: %s\n"
@@ -13871,6 +17661,7 @@
 "no es pot suprimir un arbre de treball bloquejat, raó del bloqueig: %s\n"
 "useu primer «remove -f -f» per a sobreescriure'l o desbloquejar-lo"
 
+#: builtin/worktree.c
 msgid ""
 "cannot remove a locked working tree;\n"
 "use 'remove -f -f' to override or unlock first"
@@ -13878,109 +17669,135 @@
 "no es pot suprimir un arbre de treball bloquejat;\n"
 "useu primer «remove -f -f» per a sobreescriure'l o desbloquejar-lo"
 
+#: builtin/worktree.c
 #, c-format
 msgid "validation failed, cannot remove working tree: %s"
 msgstr "la validació ha fallat, no es pot suprimir l'arbre de treball: %s"
 
+#: builtin/worktree.c
 #, c-format
 msgid "repair: %s: %s"
 msgstr "repara: %s: %s"
 
+#: builtin/worktree.c
 #, c-format
 msgid "error: %s: %s"
 msgstr "error: %s: %s"
 
+#: builtin/write-tree.c
 msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
 msgstr "git write-tree [--missing-ok] [--prefix=<prefix>/]"
 
+#: builtin/write-tree.c
 msgid "<prefix>/"
 msgstr "<prefix>/"
 
+#: builtin/write-tree.c
 msgid "write tree object for a subdirectory <prefix>"
 msgstr "escriu l'objecte d'arbre per a un subdirectori <prefix>"
 
+#: builtin/write-tree.c
 msgid "only useful for debugging"
 msgstr "només útil per a la depuració"
 
+#: bulk-checkin.c
 msgid "core.fsyncMethod = batch is unsupported on this platform"
 msgstr "core.fsyncMethod = batch no és compatible amb aquesta plataforma"
 
+#: bundle-uri.c
 #, c-format
 msgid "could not parse bundle list key %s with value '%s'"
 msgstr ""
 "no s'ha pogut analitzar la clau de llista de paquets %s amb el valor «%s»"
 
+#: bundle-uri.c
 #, c-format
 msgid "bundle list at '%s' has no mode"
 msgstr "la llista de farcells a «%s» no té mode"
 
+#: bundle-uri.c
 msgid "failed to create temporary file"
 msgstr "no s'ha pogut crear un fitxer temporal"
 
+#: bundle-uri.c
 msgid "insufficient capabilities"
 msgstr "capacitats insuficients"
 
+#: bundle-uri.c
 #, c-format
 msgid "file downloaded from '%s' is not a bundle"
 msgstr "el fitxer baixat de «%s» no és un paquet"
 
+#: bundle-uri.c
 msgid "failed to store maximum creation token"
 msgstr "no s'ha pogut emmagatzemar el testimoni de creació màxim"
 
+#: bundle-uri.c
 #, c-format
 msgid "unrecognized bundle mode from URI '%s'"
 msgstr "no s'ha reconegut el model del farcell de l'URI «%s»"
 
+#: bundle-uri.c
 #, c-format
 msgid "exceeded bundle URI recursion limit (%d)"
 msgstr "s'ha excedit el límit de recursió URI del paquet (%d)"
 
+#: bundle-uri.c
 #, c-format
 msgid "failed to download bundle from URI '%s'"
 msgstr "no s'ha pogut baixar el paquet de l'URI «%s»"
 
+#: bundle-uri.c
 #, c-format
 msgid "file at URI '%s' is not a bundle or bundle list"
 msgstr "el fitxer a l'URI «%s» no és farcell o una llista de farcells"
 
+#: bundle-uri.c
 #, c-format
 msgid "bundle-uri: unexpected argument: '%s'"
 msgstr "bundle-uri: argument inesperat: «%s»"
 
+#: bundle-uri.c
 msgid "bundle-uri: expected flush after arguments"
 msgstr "bundle-uri: s'esperava una neteja després dels arguments"
 
+#: bundle-uri.c
 msgid "bundle-uri: got an empty line"
 msgstr "bundle-uri: té una línia buida"
 
+#: bundle-uri.c
 msgid "bundle-uri: line is not of the form 'key=value'"
 msgstr "bundle-uri: la línia no és de la forma «key=value»"
 
+#: bundle-uri.c
 msgid "bundle-uri: line has empty key or value"
 msgstr "bundle-uri: la línia té una clau o un valor buit"
 
+#: bundle.c
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
 msgstr "algoritme de resum del farcell desconegut: %s"
 
+#: bundle.c
 #, c-format
 msgid "unknown capability '%s'"
 msgstr "funcionalitat «%s» desconeguda"
 
+#: bundle.c
 #, c-format
 msgid "'%s' does not look like a v2 or v3 bundle file"
 msgstr "«%s» no sembla un fitxer de farcell v2 o v3"
 
+#: bundle.c
 #, c-format
 msgid "unrecognized header: %s%s (%d)"
 msgstr "capçalera no reconeguda: %s%s (%d)"
 
+#: bundle.c
 msgid "Repository lacks these prerequisite commits:"
 msgstr "Al repositori li manquen aquestes comissions prerequerides:"
 
-msgid "need a repository to verify a bundle"
-msgstr "cal un repositori per a verificar un farcell"
-
+#: bundle.c
 msgid ""
 "some prerequisite commits exist in the object store, but are not connected "
 "to the repository's history"
@@ -13988,685 +17805,904 @@
 "hi ha algunes comissions requerides al magatzem d'objectes, però no estan "
 "connectades a l'historial del repositori"
 
+#: bundle.c
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
 msgstr[0] "El farcell conté aquesta referència:"
 msgstr[1] "El farcell conté aquestes %<PRIuMAX> referències:"
 
+#: bundle.c
 msgid "The bundle records a complete history."
 msgstr "El farcell registra una història completa."
 
+#: bundle.c
 #, c-format
 msgid "The bundle requires this ref:"
 msgid_plural "The bundle requires these %<PRIuMAX> refs:"
 msgstr[0] "El farcell requereix aquesta referència:"
 msgstr[1] "El farcell requereix aquestes %<PRIuMAX> referències:"
 
+#: bundle.c
 #, c-format
 msgid "The bundle uses this hash algorithm: %s"
 msgstr "El farcell utilitza aquest algoritme de resum: %s"
 
+#: bundle.c
 #, c-format
 msgid "The bundle uses this filter: %s"
 msgstr "El farcell utilitza aquest filtre: %s"
 
+#: bundle.c
 msgid "unable to dup bundle descriptor"
 msgstr "no s'ha pogut duplicar el descriptor del farcell"
 
+#: bundle.c
 msgid "Could not spawn pack-objects"
 msgstr "No s'ha pogut engendrar el pack-objects"
 
+#: bundle.c
 msgid "pack-objects died"
 msgstr "el pack-objects s'ha mort"
 
+#: bundle.c
 #, c-format
 msgid "ref '%s' is excluded by the rev-list options"
 msgstr "les opcions de la llista de revisions exclouen la referència «%s»"
 
+#: bundle.c
 #, c-format
 msgid "unsupported bundle version %d"
 msgstr "versió del farcell no compatible %d"
 
+#: bundle.c
 #, c-format
 msgid "cannot write bundle version %d with algorithm %s"
 msgstr "no es pot escriure la versió del farcell %d amb l'algorisme %s"
 
+#: bundle.c
 msgid "Refusing to create empty bundle."
 msgstr "S'està refusant crear un farcell buit."
 
+#: bundle.c
 #, c-format
 msgid "cannot create '%s'"
 msgstr "no es pot crear «%s»"
 
+#: bundle.c
 msgid "index-pack died"
 msgstr "l'index-pack s'ha mort"
 
+#: chunk-format.c
 msgid "terminating chunk id appears earlier than expected"
 msgstr ""
 "l'identificador de fragment de finalització apareix abans del que s'esperava"
 
+#: chunk-format.c
 #, c-format
 msgid "chunk id %<PRIx32> not %d-byte aligned"
-msgstr "ID del fragment %<PRIx32> no alineat %d-byte"
+msgstr "ID del fragment %<PRIx32> no alineat a %d-octets"
 
+#: chunk-format.c
 #, c-format
 msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
 msgstr "desplaçament incorrecte del fragment %<PRIx64> i %<PRIx64>"
 
+#: chunk-format.c
 #, c-format
 msgid "duplicate chunk ID %<PRIx32> found"
 msgstr "s'ha trobat un ID del fragment %<PRIx32> duplicat"
 
+#: chunk-format.c
 #, c-format
 msgid "final chunk has non-zero id %<PRIx32>"
 msgstr "el fragment final té un id %<PRIx32> que no és zero"
 
+#: chunk-format.c
 msgid "invalid hash version"
 msgstr "especificació de resum no vàlida"
 
+#: color.c
 #, c-format
 msgid "invalid color value: %.*s"
 msgstr "valor de color no vàlid: %.*s"
 
+#: command-list.h
 msgid "Add file contents to the index"
 msgstr "Afegeix els continguts dels fitxers a l'índex"
 
+#: command-list.h
 msgid "Apply a series of patches from a mailbox"
 msgstr "Aplica una sèrie de pedaços des d'una bústia de correu"
 
+#: command-list.h
 msgid "Annotate file lines with commit information"
 msgstr "Anota les línies del fitxer amb la informació de la comissió"
 
+#: command-list.h
 msgid "Apply a patch to files and/or to the index"
 msgstr "Aplica un pedaç a fitxer i/o a l'índex"
 
+#: command-list.h
 msgid "Import a GNU Arch repository into Git"
 msgstr "Importa un repositori GNU Arch a Git"
 
+#: command-list.h
 msgid "Create an archive of files from a named tree"
 msgstr "Crea un arxiu de fitxers des d'un arbre amb nom"
 
+#: command-list.h
 msgid "Use binary search to find the commit that introduced a bug"
 msgstr "Troba per cerca binària el canvi que hagi introduït un defecte"
 
+#: command-list.h
 msgid "Show what revision and author last modified each line of a file"
 msgstr ""
 "Mostra quina revisió i autor ha modificat per últim cop cada línia d'un "
 "fitxer"
 
+#: command-list.h
 msgid "List, create, or delete branches"
 msgstr "Llista, crea o suprimeix branques"
 
+#: command-list.h
 msgid "Collect information for user to file a bug report"
 msgstr "Recopila la informació per a l'usuari per a enviar un informe d'error"
 
+#: command-list.h
 msgid "Move objects and refs by archive"
 msgstr "Mou els objectes i les referències per arxiu"
 
+#: command-list.h
 msgid "Provide contents or details of repository objects"
 msgstr "Proporcioneu el contingut o els detalls dels objectes del repositori"
 
+#: command-list.h
 msgid "Display gitattributes information"
 msgstr "Mostra la informació de .gitattributes"
 
+#: command-list.h
 msgid "Debug gitignore / exclude files"
 msgstr "Depura gitignore / fitxers d'exclusió"
 
+#: command-list.h
 msgid "Show canonical names and email addresses of contacts"
 msgstr "Mostra els noms canònics i les adreces electròniques dels contactes"
 
+#: command-list.h
 msgid "Ensures that a reference name is well formed"
 msgstr "Assegura que un nom de referència està ben format"
 
+#: command-list.h
 msgid "Switch branches or restore working tree files"
 msgstr "Canvia de branca o restaura els fitxers de l'arbre de treball"
 
+#: command-list.h
 msgid "Copy files from the index to the working tree"
 msgstr "Copia fitxers des de l'índex a l'arbre de treball"
 
+#: command-list.h
 msgid "Find commits yet to be applied to upstream"
 msgstr "Troba les comissions que encara s'han d'aplicar a la font"
 
+#: command-list.h
 msgid "Apply the changes introduced by some existing commits"
 msgstr "Aplica els canvis introduïts per algunes comissions existents"
 
+#: command-list.h
 msgid "Graphical alternative to git-commit"
 msgstr "Alternativa gràfica a git-commit"
 
+#: command-list.h
 msgid "Remove untracked files from the working tree"
 msgstr "Elimina els fitxers no seguits de l'arbre de treball"
 
+#: command-list.h
 msgid "Clone a repository into a new directory"
 msgstr "Clona un repositori a un directori nou"
 
+#: command-list.h
 msgid "Display data in columns"
 msgstr "Mostra les dades en columnes"
 
+#: command-list.h
 msgid "Record changes to the repository"
 msgstr "Registra els canvis al repositori"
 
+#: command-list.h
 msgid "Write and verify Git commit-graph files"
 msgstr "Escriu i verifica els fitxers commit-graph de Git"
 
+#: command-list.h
 msgid "Create a new commit object"
 msgstr "Crea un objecte de comissió nou"
 
+#: command-list.h
 msgid "Get and set repository or global options"
 msgstr "Obté o estableix opcions de repositori o globals"
 
+#: command-list.h
 msgid "Count unpacked number of objects and their disk consumption"
 msgstr "Compta el nombre d'objectes desempaquetats i el seu consum de disc"
 
+#: command-list.h
 msgid "Retrieve and store user credentials"
 msgstr "Recupera i desa les credencials d'usuari"
 
+#: command-list.h
 msgid "Helper to temporarily store passwords in memory"
 msgstr "Ajudant per a emmagatzemar temporalment les contrasenyes en memòria"
 
+#: command-list.h
 msgid "Helper to store credentials on disk"
 msgstr "Ajudant per a emmagatzemar credencials a disc"
 
+#: command-list.h
 msgid "Export a single commit to a CVS checkout"
 msgstr "Exporta en una sola comissió a CVS checkout"
 
+#: command-list.h
 msgid "Salvage your data out of another SCM people love to hate"
 msgstr "Salveu les vostres dades d'un altre SMC al que la gent li agrada odiar"
 
+#: command-list.h
 msgid "A CVS server emulator for Git"
 msgstr "Un emulador de servidor CVS per al Git"
 
+#: command-list.h
 msgid "A really simple server for Git repositories"
 msgstr "Un servidor realment senzill per a repositoris Git"
 
+#: command-list.h
 msgid "Give an object a human readable name based on an available ref"
 msgstr ""
 "Dona un nom llegible per a humans basant-se en les referències disponibles"
 
+#: command-list.h
 msgid "Generate a zip archive of diagnostic information"
 msgstr "Genera un arxiu zip d'informació de diagnòstic"
 
+#: command-list.h
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr ""
 "Mostra els canvis entre comissions, la comissió i l'arbre de treball, etc"
 
+#: command-list.h
 msgid "Compares files in the working tree and the index"
 msgstr "Compara fitxers en l'arbre de treball i l'índex"
 
+#: command-list.h
 msgid "Compare a tree to the working tree or index"
 msgstr "Compara un arbre amb l'arbre de treball o l'índex"
 
+#: command-list.h
 msgid "Compares the content and mode of blobs found via two tree objects"
 msgstr ""
 "Compara el contingut i el mode dels blobs trobats a través de dos objectes "
 "d'arbre"
 
+#: command-list.h
 msgid "Show changes using common diff tools"
 msgstr "Mostra els canvis usant eines diff comunes"
 
+#: command-list.h
 msgid "Git data exporter"
 msgstr "Exportador de dades del Git"
 
+#: command-list.h
 msgid "Backend for fast Git data importers"
 msgstr "Rerefons per a importadors ràpids de dades de Git"
 
+#: command-list.h
 msgid "Download objects and refs from another repository"
 msgstr "Baixa objectes i referències d'un altre repositori"
 
+#: command-list.h
 msgid "Receive missing objects from another repository"
 msgstr "Rep els objectes que manquen des d'un altre repositori"
 
+#: command-list.h
 msgid "Rewrite branches"
 msgstr "Torna a escriure les branques"
 
+#: command-list.h
 msgid "Produce a merge commit message"
 msgstr "Produeix un missatge de comissió de fusió"
 
+#: command-list.h
 msgid "Output information on each ref"
 msgstr "Mostra la informació en cada referència"
 
+#: command-list.h
 msgid "Run a Git command on a list of repositories"
 msgstr "Executa una ordre Git en una llista de repositoris"
 
+#: command-list.h
 msgid "Prepare patches for e-mail submission"
 msgstr "Prepara pedaços per a enviar-los per correu electrònic"
 
+#: command-list.h
 msgid "Verifies the connectivity and validity of the objects in the database"
 msgstr "Verifica la connectivitat i validesa dels objectes a la base de dades"
 
+#: command-list.h
 msgid "Cleanup unnecessary files and optimize the local repository"
 msgstr "Neteja els fitxers innecessaris i optimitza el repositori local"
 
+#: command-list.h
 msgid "Extract commit ID from an archive created using git-archive"
 msgstr "Extreu l'ID de la comissió d'un arxiu creat amb el git-archive"
 
+#: command-list.h
 msgid "Print lines matching a pattern"
 msgstr "Imprimeix les línies coincidents amb un patró"
 
+#: command-list.h
 msgid "A portable graphical interface to Git"
 msgstr "Una interfície gràfica portable per al Git"
 
+#: command-list.h
 msgid "Compute object ID and optionally create an object from a file"
 msgstr ""
 "Calcula l'ID de l'objecte i opcionalment crea un objecte des del fitxer"
 
+#: command-list.h
 msgid "Display help information about Git"
 msgstr "Mostra informació d'ajuda del Git"
 
+#: command-list.h
 msgid "Run git hooks"
 msgstr "Executa els lligams del git"
 
+#: command-list.h
 msgid "Server side implementation of Git over HTTP"
 msgstr "Implementació al servidor del Git sobre HTTP"
 
+#: command-list.h
 msgid "Download from a remote Git repository via HTTP"
 msgstr "Baixa des d'un repositori Git remot via HTTP"
 
+#: command-list.h
 msgid "Push objects over HTTP/DAV to another repository"
 msgstr "Pujar objectes sobre HTTP/DAV a un altre repositori"
 
+#: command-list.h
 msgid "Send a collection of patches from stdin to an IMAP folder"
 msgstr ""
 "Envia una col·lecció de pedaços des de l'entrada estàndard a una carpeta IMAP"
 
+#: command-list.h
 msgid "Build pack index file for an existing packed archive"
 msgstr ""
 "Construeix el fitxer d'índex del paquet per a un arxiu empaquetat existent"
 
+#: command-list.h
 msgid "Create an empty Git repository or reinitialize an existing one"
 msgstr "Crea un repositori de Git buit o reinicialitza un existent"
 
+#: command-list.h
 msgid "Instantly browse your working repository in gitweb"
 msgstr "Navegueu instantàniament pel vostre repositori de treball a gitweb"
 
+#: command-list.h
 msgid "Add or parse structured information in commit messages"
 msgstr ""
 "Afegeix o analitza la informació estructurada en els missatges de comissió"
 
+#: command-list.h
 msgid "Show commit logs"
 msgstr "Mostra els registres de comissió"
 
+#: command-list.h
 msgid "Show information about files in the index and the working tree"
 msgstr "Mostra informació sobre els fitxers a l'índex i a l'arbre de treball"
 
+#: command-list.h
 msgid "List references in a remote repository"
 msgstr "Mostra les referències d'un repositori remot"
 
+#: command-list.h
 msgid "List the contents of a tree object"
 msgstr "Mostra els continguts d'un objecte de l'arbre"
 
+#: command-list.h
 msgid "Extracts patch and authorship from a single e-mail message"
 msgstr "Extreu el pedaç i l'autoria d'un sol missatge de correu electrònic"
 
+#: command-list.h
 msgid "Simple UNIX mbox splitter program"
 msgstr "Programa de divisió mbox simple per a UNIX"
 
+#: command-list.h
 msgid "Run tasks to optimize Git repository data"
 msgstr "Executa tasques per a optimitzar les dades del repositori Git"
 
+#: command-list.h
 msgid "Join two or more development histories together"
 msgstr "Uneix dues o més històries de desenvolupament"
 
+#: command-list.h
 msgid "Find as good common ancestors as possible for a merge"
 msgstr "Troba els millors avantpassats comuns possibles per a una fusió"
 
+#: command-list.h
 msgid "Run a three-way file merge"
 msgstr "Executa una fusió de fitxers de tres vies"
 
+#: command-list.h
 msgid "Run a merge for files needing merging"
 msgstr "Executa una fusió per als fitxers que cal fusionar"
 
+#: command-list.h
 msgid "The standard helper program to use with git-merge-index"
 msgstr "El programa d'ajuda estàndard a utilitzar amb git-merge-index"
 
+#: command-list.h
 msgid "Perform merge without touching index or working tree"
 msgstr "Realitza la fusió sense tocar l'índex o l'arbre de treball"
 
+#: command-list.h
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
 msgstr ""
 "Executa eines de resolució de conflictes per a resoldre conflictes de fusió"
 
+#: command-list.h
 msgid "Creates a tag object with extra validation"
 msgstr "Crea un objecte etiqueta amb validació addicional"
 
+#: command-list.h
 msgid "Build a tree-object from ls-tree formatted text"
 msgstr "Construeix un objecte en arbre a partir de text formatat amb ls-tree"
 
+#: command-list.h
 msgid "Write and verify multi-pack-indexes"
 msgstr "Escriu i verifica els índexs multipaquet"
 
+#: command-list.h
 msgid "Move or rename a file, a directory, or a symlink"
 msgstr "Mou o canvia de nom a un fitxer, directori o enllaç simbòlic"
 
+#: command-list.h
 msgid "Find symbolic names for given revs"
 msgstr "Cerca noms simbòlics per a les revisions donades"
 
+#: command-list.h
 msgid "Add or inspect object notes"
 msgstr "Afegeix o inspecciona notes de l'objecte"
 
+#: command-list.h
 msgid "Import from and submit to Perforce repositories"
 msgstr "Importa des de i envia a repositoris Perforce"
 
+#: command-list.h
 msgid "Create a packed archive of objects"
 msgstr "Crea un arxiu empaquetat d'objectes"
 
+#: command-list.h
 msgid "Find redundant pack files"
 msgstr "Troba fitxers empaquetats redundants"
 
+#: command-list.h
 msgid "Pack heads and tags for efficient repository access"
 msgstr ""
 "Empaqueta els caps i les etiquetes per a un accés eficient al repositori"
 
+#: command-list.h
 msgid "Compute unique ID for a patch"
 msgstr "Calcula un identificador únic per a cada pedaç"
 
+#: command-list.h
 msgid "Prune all unreachable objects from the object database"
 msgstr "Poda tots els objectes no accessibles de la base de dades d'objectes"
 
+#: command-list.h
 msgid "Remove extra objects that are already in pack files"
 msgstr "Elimina els objectes extres que ja estan en fitxers empaquetats"
 
+#: command-list.h
 msgid "Fetch from and integrate with another repository or a local branch"
 msgstr "Obtén i integra amb un altre repositori o una branca local"
 
+#: command-list.h
 msgid "Update remote refs along with associated objects"
 msgstr ""
 "Actualitza les referències remotes juntament amb els objectes associats"
 
+#: command-list.h
 msgid "Applies a quilt patchset onto the current branch"
 msgstr "Aplica un conjunt de pedaços a la branca actual"
 
+#: command-list.h
 msgid "Compare two commit ranges (e.g. two versions of a branch)"
 msgstr "Compara dos rangs de comissions (p. ex. dues versions d'una branca)"
 
+#: command-list.h
 msgid "Reads tree information into the index"
 msgstr "Llegeix la informació de l'arbre a l'índex"
 
+#: command-list.h
 msgid "Reapply commits on top of another base tip"
 msgstr "Torna a aplicar les comissions sobre un altre punt de basament"
 
+#: command-list.h
 msgid "Receive what is pushed into the repository"
 msgstr "Rep el que s'envia al repositori"
 
+#: command-list.h
 msgid "Manage reflog information"
 msgstr "Gestiona la informació del registre de referències"
 
+# Baix nivell / nivell baix
+#: command-list.h
+msgid "Low-level access to refs"
+msgstr "Accés de baix nivell a referències"
+
+#: command-list.h
 msgid "Manage set of tracked repositories"
 msgstr "Gestiona el conjunt de repositoris seguits"
 
+#: command-list.h
 msgid "Pack unpacked objects in a repository"
 msgstr "Empaqueta els objectes desempaquetats en un repositori"
 
+#: command-list.h
 msgid "Create, list, delete refs to replace objects"
 msgstr "Crea, llista i esborra referències per a substituir objectes"
 
+#: command-list.h
 msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too"
 msgstr ""
 "EXPERIMENTAL: torna a reproduir comissions sobre una nova base, també "
 "funciona amb repositoris nus"
 
+#: command-list.h
 msgid "Generates a summary of pending changes"
 msgstr "Genera un resum dels canvis pendents"
 
+#: command-list.h
 msgid "Reuse recorded resolution of conflicted merges"
 msgstr "Reutilitza la resolució registrada dels conflictes de fusió"
 
+#: command-list.h
 msgid "Reset current HEAD to the specified state"
 msgstr "Restableix la HEAD actual a l'estat especificat"
 
+#: command-list.h
 msgid "Restore working tree files"
 msgstr "Restaura els fitxers de l'arbre de treball"
 
+#: command-list.h
 msgid "Lists commit objects in reverse chronological order"
 msgstr "Mostra les comissions en ordre topològic invers"
 
+#: command-list.h
 msgid "Pick out and massage parameters"
 msgstr "Trieu i personalitzeu els paràmetres"
 
+#: command-list.h
 msgid "Revert some existing commits"
 msgstr "Reverteix comissions existents"
 
+#: command-list.h
 msgid "Remove files from the working tree and from the index"
 msgstr "Elimina fitxers de l'arbre de treball i de l'índex"
 
+#: command-list.h
 msgid "Send a collection of patches as emails"
 msgstr "Envia una col·lecció de pedaços com a correus electrònics"
 
+#: command-list.h
 msgid "Push objects over Git protocol to another repository"
 msgstr "Puja objectes sobre el protocol Git a un altre repositori"
 
+#: command-list.h
 msgid "Git's i18n setup code for shell scripts"
 msgstr ""
 "Codi de configuració i18n del Git per als scripts de l'intèrpret d'ordres"
 
+#: command-list.h
 msgid "Common Git shell script setup code"
 msgstr "Codi de scripts de configuració comuns pel Git shell"
 
+#: command-list.h
 msgid "Restricted login shell for Git-only SSH access"
 msgstr "Intèrpret d'ordres d'entrada restringit només per a accés SSH al Git"
 
+#: command-list.h
 msgid "Summarize 'git log' output"
 msgstr "Resumeix la sortida «git log»"
 
+#: command-list.h
 msgid "Show various types of objects"
 msgstr "Mostra diversos tipus d'objectes"
 
+#: command-list.h
 msgid "Show branches and their commits"
 msgstr "Mostra les branques i les seves comissions"
 
+#: command-list.h
 msgid "Show packed archive index"
 msgstr "Mostra l'índex d'arxius empaquetat"
 
+#: command-list.h
 msgid "List references in a local repository"
 msgstr "Llista les referències en un repositori local"
 
+#: command-list.h
 msgid "Reduce your working tree to a subset of tracked files"
 msgstr "Redueix l'arbre de treball a un subconjunt de fitxers seguits"
 
+#: command-list.h
 msgid "Add file contents to the staging area"
 msgstr "Afegeix el contingut del fitxer a l'àrea de «staging»"
 
+#: command-list.h
 msgid "Stash the changes in a dirty working directory away"
 msgstr "Fes «stash» dels canvis en un directori de treball brut"
 
+#: command-list.h
 msgid "Show the working tree status"
 msgstr "Mostra l'estat de l'arbre de treball"
 
+#: command-list.h
 msgid "Remove unnecessary whitespace"
 msgstr "Elimina l'espai en blanc innecessari"
 
+#: command-list.h
 msgid "Initialize, update or inspect submodules"
 msgstr "Inicialitza, actualitza o inspecciona submòduls"
 
+#: command-list.h
 msgid "Bidirectional operation between a Subversion repository and Git"
 msgstr "Operació bidireccional entre un repositori a Subversion i Git"
 
+#: command-list.h
 msgid "Switch branches"
 msgstr "Commuta entre branques"
 
+#: command-list.h
 msgid "Read, modify and delete symbolic refs"
 msgstr "Llegeix, modifica i suprimeix referències simbòliques"
 
+#: command-list.h
 msgid "Create, list, delete or verify a tag object signed with GPG"
 msgstr ""
 "Crea, llista, suprimeix o verifica un objecte d'etiqueta signat amb GPG"
 
+#: command-list.h
 msgid "Creates a temporary file with a blob's contents"
 msgstr "Crea un fitxer temporal amb els continguts dels blobs"
 
+#: command-list.h
 msgid "Unpack objects from a packed archive"
 msgstr "Desempaqueta objectes d'un arxiu empaquetat"
 
+#: command-list.h
 msgid "Register file contents in the working tree to the index"
 msgstr "Registra els continguts del fitxer en l'arbre de treball a l'índex"
 
+#: command-list.h
 msgid "Update the object name stored in a ref safely"
 msgstr ""
 "Actualitza el nom de l'objecte emmagatzemat en una referència de forma segura"
 
+#: command-list.h
 msgid "Update auxiliary info file to help dumb servers"
 msgstr ""
 "Actualitza el fitxer d'informació auxiliar per a ajudar als servidors ximples"
 
+#: command-list.h
 msgid "Send archive back to git-archive"
 msgstr "Envia l'arxiu de tornada al git-archive"
 
+#: command-list.h
 msgid "Send objects packed back to git-fetch-pack"
 msgstr "Envia els objectes empaquetats de tornada al git-fetch-pack"
 
+#: command-list.h
 msgid "Show a Git logical variable"
 msgstr "Mostra una variable lògica del Git"
 
+#: command-list.h
 msgid "Check the GPG signature of commits"
 msgstr "Verifica la signatura GPG de les comissions"
 
+#: command-list.h
 msgid "Validate packed Git archive files"
 msgstr "Valida els fitxers d'arxius Git empaquetats"
 
+#: command-list.h
 msgid "Check the GPG signature of tags"
 msgstr "Verifica la signatura GPG de les etiquetes"
 
+#: command-list.h
 msgid "Display version information about Git"
 msgstr "Mostra informació de la versió del Git"
 
+#: command-list.h
 msgid "Show logs with differences each commit introduces"
 msgstr "Mostra els registres amb les diferències que introdueix cada comissió"
 
+#: command-list.h
 msgid "Manage multiple working trees"
 msgstr "Gestiona múltiples arbres de treball"
 
+#: command-list.h
 msgid "Create a tree object from the current index"
 msgstr "Crea un objecte arbre des de l'índex actual"
 
+#: command-list.h
 msgid "Defining attributes per path"
 msgstr "La definició d'atributs per camí"
 
+#: command-list.h
 msgid "Git command-line interface and conventions"
 msgstr "Interfície i convencions de la línia d'ordres del Git"
 
+#: command-list.h
 msgid "A Git core tutorial for developers"
 msgstr "Un tutorial bàsic del Git per a desenvolupadors"
 
+#: command-list.h
 msgid "Providing usernames and passwords to Git"
 msgstr "Proporcionar noms d'usuari i contrasenyes a Git"
 
+#: command-list.h
 msgid "Git for CVS users"
 msgstr "Git per a usuaris del CVS"
 
+#: command-list.h
 msgid "Tweaking diff output"
 msgstr "Ajustament de la sortida de diferències"
 
+#: command-list.h
 msgid "A useful minimum set of commands for Everyday Git"
 msgstr "Un conjunt mínim útil d'ordres diàries del Git"
 
+#: command-list.h
 msgid "Frequently asked questions about using Git"
 msgstr "Preguntes freqüents sobre l'ús del Git"
 
+#: command-list.h
 msgid "The bundle file format"
 msgstr "El format del fitxer de farcell"
 
+#: command-list.h
 msgid "Chunk-based file formats"
 msgstr "Formats de fitxer basats en blocs"
 
+#: command-list.h
 msgid "Git commit-graph format"
 msgstr "Format de graf de comissions del Git"
 
+#: command-list.h
 msgid "Git index format"
 msgstr "Format de l'índex del Git"
 
+#: command-list.h
 msgid "Git pack format"
 msgstr "format de paquet del Git"
 
+#: command-list.h
 msgid "Git cryptographic signature formats"
 msgstr "Formats de signatura criptogràfica del Git"
 
+#: command-list.h
 msgid "A Git Glossary"
 msgstr "Un glossari de Git"
 
+#: command-list.h
 msgid "Hooks used by Git"
 msgstr "Lligams utilitzats pel Git"
 
+#: command-list.h
 msgid "Specifies intentionally untracked files to ignore"
 msgstr "Especifica els fitxers intencionalment no seguits a ignorar"
 
+#: command-list.h
 msgid "The Git repository browser"
 msgstr "El navegador de repositoris Git"
 
+#: command-list.h
 msgid "Map author/committer names and/or E-Mail addresses"
 msgstr "Assigna noms d'autor i comitent i/o adreces de correu electrònic"
 
+#: command-list.h
 msgid "Defining submodule properties"
 msgstr "La definició de les propietats de submòduls"
 
+#: command-list.h
 msgid "Git namespaces"
 msgstr "Espais de noms del Git"
 
+#: command-list.h
 msgid "Protocol v0 and v1 capabilities"
 msgstr "Capacitats de protocol v0 i v1"
 
+#: command-list.h
 msgid "Things common to various protocols"
 msgstr "Coses comunes en  diversos protocols"
 
+#: command-list.h
 msgid "Git HTTP-based protocols"
 msgstr "Protocols basats en HTTP del Git"
 
+#: command-list.h
 msgid "How packs are transferred over-the-wire"
 msgstr "Com es transfereixen els paquets en la xarxa"
 
+#: command-list.h
 msgid "Git Wire Protocol, Version 2"
 msgstr "Protocol Git Wire, versió 2"
 
+#: command-list.h
 msgid "Helper programs to interact with remote repositories"
 msgstr "Programes d'ajuda per a interactuar amb repositoris remots"
 
+#: command-list.h
 msgid "Git Repository Layout"
 msgstr "Disposició del repositori del Git"
 
+#: command-list.h
 msgid "Specifying revisions and ranges for Git"
 msgstr "L'especificació de revisions i rangs per al Git"
 
+#: command-list.h
 msgid "Mounting one repository inside another"
 msgstr "Muntant un repositori dins un altre"
 
+#: command-list.h
 msgid "A tutorial introduction to Git"
 msgstr "Un tutorial d'introducció al Git"
 
+#: command-list.h
 msgid "A tutorial introduction to Git: part two"
 msgstr "Un tutorial d'introducció al Git: segona part"
 
+#: command-list.h
 msgid "Git web interface (web frontend to Git repositories)"
 msgstr "Interfície web del Git (interfície web pels repositoris Git)"
 
+#: command-list.h
 msgid "An overview of recommended workflows with Git"
 msgstr "Una visió de conjunt de fluxos de treball recomanats amb Git"
 
+#: command-list.h
 msgid "A tool for managing large Git repositories"
 msgstr "Una eina per a gestionar dipòsits Git grans"
 
+#: commit-graph.c
 msgid "commit-graph file is too small"
 msgstr "el fitxer del graf de comissions és massa petit"
 
+#: commit-graph.c
 msgid "commit-graph oid fanout chunk is wrong size"
 msgstr ""
 "el fragment de «fanout» de l'oid del graf de comissions és de mida incorrecta"
 
+#: commit-graph.c
 msgid "commit-graph fanout values out of order"
 msgstr "valors de graf de comissions de «fanout» estan fora d'ordre"
 
+#: commit-graph.c
 msgid "commit-graph OID lookup chunk is the wrong size"
 msgstr "el fragment de cerca OID és de mida incorrecta"
 
+#: commit-graph.c
 msgid "commit-graph commit data chunk is wrong size"
 msgstr "el fragment de dades del graf de comissions és de mida incorrecta"
 
+#: commit-graph.c
 msgid "commit-graph generations chunk is wrong size"
 msgstr ""
 "el fragment de les generacions del graf de comissions és de mida incorrecta"
 
+#: commit-graph.c
 msgid "commit-graph changed-path index chunk is too small"
 msgstr ""
 "el fragment d'índex del canvi del camí del graf de comissions és massa petit"
 
+#: commit-graph.c
 #, c-format
 msgid ""
 "ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-"
@@ -14675,107 +18711,144 @@
 "s'ignorarà un fragment massa petit de camí canviat (%<PRIuMAX> < %<PRIuMAX>) "
 "al fitxer del graf de comissions"
 
+#: commit-graph.c
 #, c-format
 msgid "commit-graph signature %X does not match signature %X"
 msgstr ""
 "la signatura del graf de comissions %X no coincideix amb la signatura %X"
 
+#: commit-graph.c
 #, c-format
 msgid "commit-graph version %X does not match version %X"
 msgstr "la versió del graf de comissions %X no coincideix amb la versió %X"
 
+#: commit-graph.c
 #, c-format
 msgid "commit-graph hash version %X does not match version %X"
 msgstr ""
 "la versió del resum del graf de comissions %X no coincideix amb la versió %X"
 
+#: commit-graph.c
 #, c-format
 msgid "commit-graph file is too small to hold %u chunks"
 msgstr ""
 "el fitxer del graf de comissions és massa petit per a guardar %u fragments"
 
+#: commit-graph.c
 msgid "commit-graph required OID fanout chunk missing or corrupted"
 msgstr ""
 "manca o està malmès el fragment del «fanout» OID requerit al graf de "
 "comissions"
 
+#: commit-graph.c
 msgid "commit-graph required OID lookup chunk missing or corrupted"
 msgstr ""
 "manca o està malmès el fragment de cerca d'OID requerit al graf de comissions"
 
+#: commit-graph.c
 msgid "commit-graph required commit data chunk missing or corrupted"
 msgstr ""
 "manca o està corromput el fragment de dades de publicació requerit al graf "
 "de comissions"
 
+#: commit-graph.c
+#, c-format
+msgid ""
+"disabling Bloom filters for commit-graph layer '%s' due to incompatible "
+"settings"
+msgstr ""
+"s'han inhabilitat els filtres de Bloom per a la capa del graf de comissions "
+"«%s»\n"
+"perquè els paràmetres són incompatibles"
+
+#: commit-graph.c
 msgid "commit-graph has no base graphs chunk"
 msgstr "el fragment del graf de comissions no té grafs de base"
 
+#: commit-graph.c
 msgid "commit-graph base graphs chunk is too small"
 msgstr "el fragment de grafs base de la gràfica de comissió és massa petit"
 
+#: commit-graph.c
 msgid "commit-graph chain does not match"
 msgstr "la cadena del graf de comissions no coincideix"
 
+#: commit-graph.c
 #, c-format
 msgid "commit count in base graph too high: %<PRIuMAX>"
 msgstr "el nombre de comissions en el graf base és massa alt: %<PRIuMAX>"
 
+#: commit-graph.c
 msgid "commit-graph chain file too small"
 msgstr "el fitxer de cadena del graf de comissions és massa petit"
 
+#: commit-graph.c
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
 msgstr ""
 "la cadena del graf de comissions no és vàlida: la línia «%s» no és un hash"
 
+#: commit-graph.c
 msgid "unable to find all commit-graph files"
 msgstr "no es poden trobar tots els fitxers del graf de comissions"
 
+#: commit-graph.c
 msgid "invalid commit position. commit-graph is likely corrupt"
 msgstr ""
 "posició de la comissió no vàlida. Probablement el graf de comissions està "
 "malmès"
 
+#: commit-graph.c
 #, c-format
 msgid "could not find commit %s"
 msgstr "no s'ha pogut trobar la comissió %s"
 
+#: commit-graph.c
 msgid "commit-graph requires overflow generation data but has none"
 msgstr ""
 "el graf de comissions requereix dades de generació de desbordaments però no "
 "en té cap"
 
+#: commit-graph.c
 msgid "commit-graph overflow generation data is too small"
 msgstr ""
 "les dades de generació de desbordament del graf de comissions són massa "
 "petites"
 
+#: commit-graph.c
 msgid "commit-graph extra-edges pointer out of bounds"
 msgstr "punter de vores extra del graf de comissió està fora dels límits"
 
+#: commit-graph.c
 msgid "Loading known commits in commit graph"
 msgstr "S'estan carregant comissions conegudes al graf de comissions"
 
+#: commit-graph.c
 msgid "Expanding reachable commits in commit graph"
 msgstr "S'estan expandint les comissions abastables al graf de comissions"
 
+#: commit-graph.c
 msgid "Clearing commit marks in commit graph"
 msgstr "S'estan esborrant les marques de comissions al graf de comissions"
 
+#: commit-graph.c
 msgid "Computing commit graph topological levels"
 msgstr "S'estan calculant els nivells topològics del graf de comissions"
 
+#: commit-graph.c
 msgid "Computing commit graph generation numbers"
 msgstr "S'estan calculant els nombres de generació del graf de comissions"
 
+#: commit-graph.c
 msgid "Computing commit changed paths Bloom filters"
 msgstr ""
-"S'estan calculant els canvis les rutes de la comissió en els filtres Bloom"
+"S'estan calculant els canvis les rutes de la comissió en els filtres de Bloom"
 
+#: commit-graph.c
 msgid "Collecting referenced commits"
 msgstr "S'estan recollint els objectes referenciats"
 
+#: commit-graph.c
 #, c-format
 msgid "Finding commits for commit graph in %<PRIuMAX> pack"
 msgid_plural "Finding commits for commit graph in %<PRIuMAX> packs"
@@ -14784,128 +18857,166 @@
 msgstr[1] ""
 "S'estan cercant les comissions pel graf de comissions en %<PRIuMAX> paquets"
 
+#: commit-graph.c
 #, c-format
 msgid "error adding pack %s"
 msgstr "error en afegir paquet %s"
 
+#: commit-graph.c
 #, c-format
 msgid "error opening index for %s"
 msgstr "s'ha produït un error en obrir l'índex per «%s»"
 
+#: commit-graph.c
 msgid "Finding commits for commit graph among packed objects"
 msgstr ""
 "S'estan cercant les comissions pel graf de comissions entre els objectes "
 "empaquetats"
 
+#: commit-graph.c
 msgid "Finding extra edges in commit graph"
 msgstr "S'estan cercant les vores addicionals al graf de comissions"
 
+#: commit-graph.c
 msgid "failed to write correct number of base graph ids"
 msgstr ""
 "s'ha produït un error en escriure el nombre correcte d'ids base del graf"
 
+#: commit-graph.c
 msgid "unable to create temporary graph layer"
 msgstr "no s'ha pogut crear una capa de graf temporal"
 
+#: commit-graph.c midx-write.c
 #, c-format
 msgid "unable to adjust shared permissions for '%s'"
 msgstr "no s'han pogut ajustar els permisos compartits per a «%s»"
 
+#: commit-graph.c
 #, c-format
 msgid "Writing out commit graph in %d pass"
 msgid_plural "Writing out commit graph in %d passes"
 msgstr[0] "S'està escrivint el graf de comissions en %d pas"
 msgstr[1] "S'està escrivint el graf de comissions en %d passos"
 
+#: commit-graph.c
 msgid "unable to open commit-graph chain file"
 msgstr "no s'ha pogut obrir el fitxer d'encadenament del graf de comissions"
 
+#: commit-graph.c
 msgid "failed to rename base commit-graph file"
 msgstr "no s'ha pogut canviar el nom del fitxer base del graf de comissions"
 
+#: commit-graph.c
 msgid "failed to rename temporary commit-graph file"
 msgstr ""
 "no s'ha pogut canviar el nom del fitxer temporal del graf de comissions"
 
+#: commit-graph.c
 #, c-format
 msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
 msgstr "no es poden fusionar els gràfics amb %<PRIuMAX>, %<PRIuMAX>entregues"
 
+#: commit-graph.c
 #, c-format
 msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
 msgstr "no es pot fusionar el graf %s, hi ha massa comissions: %<PRIuMAX>"
 
+#: commit-graph.c
 msgid "Scanning merged commits"
 msgstr "S'estan escanejant les comissions fusionades"
 
+#: commit-graph.c
 msgid "Merging commit-graph"
 msgstr "S'està fusionant el graf de comissions"
 
+#: commit-graph.c
 msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
 msgstr ""
 "s'està intentant escriure un graf de comissions, però «core.commitGraph» "
 "està desactivat"
 
+#: commit-graph.c
+#, c-format
+msgid ""
+"attempting to write a commit-graph, but 'commitGraph."
+"changedPathsVersion' (%d) is not supported"
+msgstr ""
+"s'ha intentat escriure un graf de comissió, però no s'admet 'commitGraph."
+"changedPathsVersion' (%d)"
+
+#: commit-graph.c
 msgid "too many commits to write graph"
 msgstr "massa comissions per a escriure un graf"
 
+#: commit-graph.c
 msgid "the commit-graph file has incorrect checksum and is likely corrupt"
 msgstr ""
 "el fitxer commit-graph (graf de comissions) té una suma de verificació "
 "incorrecta i probablement és corrupte"
 
+#: commit-graph.c
 #, c-format
 msgid "commit-graph has incorrect OID order: %s then %s"
 msgstr "el graf de comissions té una ordre OID incorrecta; %s llavors %s"
 
+#: commit-graph.c
 #, c-format
 msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
 msgstr ""
 "el graf de comissions té un valor de «fanout» incorrecte: fanout[%d] = %u != "
 "%u"
 
+#: commit-graph.c
 #, c-format
 msgid "failed to parse commit %s from commit-graph"
 msgstr ""
 "s'ha produït un error en analitzar la comissió %s del graf de comissions"
 
+#: commit-graph.c
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
 msgstr ""
 "no s'han pogut analitzar la comissió %s de la base de dades d'objectes per "
 "al graf de comissions"
 
+#: commit-graph.c
 #, c-format
 msgid "root tree OID for commit %s in commit-graph is %s != %s"
 msgstr ""
 "OID de l'arbre arrel per a comissions %s en el graf de comissions és %s != %s"
 
+#: commit-graph.c
 #, c-format
 msgid "commit-graph parent list for commit %s is too long"
 msgstr ""
 "la llista de pares del graf de comissions per a la comissió %s és massa "
 "llarga"
 
+#: commit-graph.c
 #, c-format
 msgid "commit-graph parent for %s is %s != %s"
 msgstr "el pare pel graf de comissions %s és %s != %s"
 
+#: commit-graph.c
 #, c-format
 msgid "commit-graph parent list for commit %s terminates early"
 msgstr "la llista pare del graf de comissions per %s acaba aviat"
 
+#: commit-graph.c
 #, c-format
 msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
 msgstr ""
 "generació del graf de comissions per a la comissió %s és %<PRIuMAX> < "
 "%<PRIuMAX>"
 
+#: commit-graph.c
 #, c-format
 msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
 msgstr ""
 "la data d'enviament per a la comissió %s en el graf de comissions és "
 "%<PRIuMAX> != %<PRIuMAX>"
 
+#: commit-graph.c
 #, c-format
 msgid ""
 "commit-graph has both zero and non-zero generations (e.g., commits '%s' and "
@@ -14914,13 +19025,21 @@
 "El graf de comissió té tant generacions zero com no nul·les (p. ex., "
 "comissions «%s» i «%s»)"
 
+#: commit-graph.c
 msgid "Verifying commits in commit graph"
 msgstr "S'estan verificant les comissions al graf de comissions"
 
+#: commit-reach.c sequencer.c
+#, c-format
+msgid "could not parse commit %s"
+msgstr "no s'ha pogut analitzar la comissió %s"
+
+#: commit.c
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s no és una comissió!"
 
+#: commit.c
 msgid ""
 "Support for <GIT_DIR>/info/grafts is deprecated\n"
 "and will be removed in a future Git version.\n"
@@ -14940,28 +19059,34 @@
 "Desactiveu aquest missatge executant\n"
 "«git config advice.graftFileDeprecated false»"
 
+#: commit.c
 #, c-format
 msgid "commit %s exists in commit-graph but not in the object database"
 msgstr ""
 "la comissió %s existeix al graf de comissions però no a la base de dades "
 "d'objectes"
 
+#: commit.c
 #, c-format
 msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
 msgstr "La comissió %s té una signatura GPG no fiable, suposadament de %s."
 
+#: commit.c
 #, c-format
 msgid "Commit %s has a bad GPG signature allegedly by %s."
 msgstr "La comissió %s té una signatura GPG incorrecta suposadament de %s."
 
+#: commit.c
 #, c-format
 msgid "Commit %s does not have a GPG signature."
 msgstr "La comissió %s no té signatura GPG."
 
+#: commit.c
 #, c-format
 msgid "Commit %s has a good GPG signature by %s\n"
 msgstr "La comissió %s té una signatura GPG bona de %s\n"
 
+#: commit.c
 msgid ""
 "Warning: commit message did not conform to UTF-8.\n"
 "You may want to amend it after fixing the message, or set the config\n"
@@ -14972,203 +19097,260 @@
 "la variable de configuració i18n.commitencoding a la codificació que\n"
 "usi el vostre projecte.\n"
 
+#: compat/compiler.h
 msgid "no compiler information available\n"
 msgstr "no hi ha informació disponible del compilador\n"
 
+#: compat/compiler.h
 msgid "no libc information available\n"
 msgstr "no hi ha informació disponible de libc\n"
 
+#: compat/disk.h
 #, c-format
 msgid "could not determine free disk size for '%s'"
 msgstr "no s'ha pogut determinar l'espai de disc lliure per a «%s»"
 
+#: compat/disk.h
 #, c-format
 msgid "could not get info for '%s'"
 msgstr "no s'ha pogut obtenir la informació per a «%s»"
 
+#: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
 msgstr "[GLE %ld] el fil de salut no ha pogut obrir «%ls»"
 
+#: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "[GLE %ld] health thread getting BHFI for '%ls'"
 msgstr "[GLE %ld] s'està obtenint BHFI del fil de salut per a «%ls»"
 
+#: compat/fsmonitor/fsm-health-win32.c compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "could not convert to wide characters: '%s'"
 msgstr "no s'ha pogut convertir a caràcters amples: «%s»"
 
+#: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "BHFI changed '%ls'"
 msgstr "S'ha canviat BHFI «%ls»"
 
+#: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "unhandled case in 'has_worktree_moved': %d"
 msgstr "cas no gestionat a «has_worktree_moved»: %d"
 
+#: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "health thread wait failed [GLE %ld]"
 msgstr "ha fallat l'espera del fil de salut [GLE %ld]"
 
+#: compat/fsmonitor/fsm-ipc-darwin.c
 #, c-format
 msgid "Invalid path: %s"
 msgstr "Camí no vàlid: «%s»"
 
+#: compat/fsmonitor/fsm-listen-darwin.c
 msgid "Unable to create FSEventStream."
 msgstr "No s'ha pogut crear el FSEventStream."
 
+#: compat/fsmonitor/fsm-listen-darwin.c
 msgid "Failed to start the FSEventStream"
 msgstr "No s'ha pogut iniciar el FSEventStream"
 
+#: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "[GLE %ld] could not convert path to UTF-8: '%.*ls'"
 msgstr "[GLE %ld] no s'ha pogut convertir el camí a UTF-8: «%.*ls»"
 
+#: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "[GLE %ld] could not watch '%s'"
 msgstr "[GLE %ld] no s'ha pogut vigilar «%s»"
 
+#: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "[GLE %ld] could not get longname of '%s'"
 msgstr "[GLE %ld] no s'ha pogut obtenir el nom llarg de «%s»"
 
+#: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "ReadDirectoryChangedW failed on '%s' [GLE %ld]"
 msgstr "Ha fallat ReadDirectoryChangedW a «%s» [GLE %ld]"
 
+#: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "GetOverlappedResult failed on '%s' [GLE %ld]"
 msgstr "Ha fallat GetOverlappedResult a «%s» [GLE %ld]"
 
+#: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "could not read directory changes [GLE %ld]"
 msgstr "no s'han pogut llegir els canvis de directori [GLE %ld]"
 
+#: compat/fsmonitor/fsm-path-utils-darwin.c
 #, c-format
 msgid "opendir('%s') failed"
 msgstr "ha fallat opendir(«%s»)"
 
+#: compat/fsmonitor/fsm-path-utils-darwin.c
 #, c-format
 msgid "lstat('%s') failed"
 msgstr "ha fallat lstat(«%s»)"
 
+#: compat/fsmonitor/fsm-path-utils-darwin.c
 #, c-format
 msgid "strbuf_readlink('%s') failed"
 msgstr "ha fallat strbuf_readlink(«%s»)"
 
+#: compat/fsmonitor/fsm-path-utils-darwin.c
 #, c-format
 msgid "closedir('%s') failed"
 msgstr "ha fallat closedir(«%s»)"
 
+#: compat/fsmonitor/fsm-path-utils-win32.c
 #, c-format
 msgid "[GLE %ld] unable to open for read '%ls'"
 msgstr "[GLE %ld] no s'ha pogut obrir per a llegir «%ls»"
 
+#: compat/fsmonitor/fsm-path-utils-win32.c
 #, c-format
 msgid "[GLE %ld] unable to get protocol information for '%ls'"
 msgstr "[GLE %ld] no s'ha pogut obtenir la informació del protocol per a «%ls»"
 
+#: compat/mingw.c
 #, c-format
 msgid "failed to copy SID (%ld)"
 msgstr "no s'ha pogut copiar el SID (%ld)"
 
+#: compat/mingw.c
 #, c-format
 msgid "failed to get owner for '%s' (%ld)"
 msgstr "no s'ha pogut obtenir el propietari de «%s» (%ld)"
 
+#: compat/obstack.c
 msgid "memory exhausted"
 msgstr "memòria esgotada"
 
+#: compat/regex/regcomp.c
 msgid "Success"
 msgstr "Èxit"
 
+#: compat/regex/regcomp.c
 msgid "No match"
 msgstr "Cap coincidència"
 
+#: compat/regex/regcomp.c
 msgid "Invalid regular expression"
 msgstr "Expressió regular no vàlida"
 
+#: compat/regex/regcomp.c
 msgid "Invalid collation character"
 msgstr "El caràcter de col·lació no és vàlid"
 
+#: compat/regex/regcomp.c
 msgid "Invalid character class name"
 msgstr "Nom de la classe del caràcter no vàlid"
 
+#: compat/regex/regcomp.c
 msgid "Trailing backslash"
 msgstr "Barra inversa del final"
 
+#: compat/regex/regcomp.c
 msgid "Invalid back reference"
 msgstr "Referència anterior no vàlida"
 
+#: compat/regex/regcomp.c
 msgid "Unmatched [ or [^"
 msgstr "[ o [^ no emparellat"
 
+#: compat/regex/regcomp.c
 msgid "Unmatched ( or \\("
 msgstr "( o \\( no emparellat"
 
+#: compat/regex/regcomp.c
 msgid "Unmatched \\{"
 msgstr "\\{ no emparellat"
 
+#: compat/regex/regcomp.c
 msgid "Invalid content of \\{\\}"
 msgstr "Contingut no vàlid de \\{\\}"
 
+#: compat/regex/regcomp.c
 msgid "Invalid range end"
 msgstr "Fi d'interval no vàlid"
 
+#: compat/regex/regcomp.c
 msgid "Memory exhausted"
 msgstr "Memòria esgotada"
 
+#: compat/regex/regcomp.c
 msgid "Invalid preceding regular expression"
 msgstr "Expressió regular anterior no vàlida"
 
+#: compat/regex/regcomp.c
 msgid "Premature end of regular expression"
 msgstr "Fi prematur d'expressió regular"
 
+#: compat/regex/regcomp.c
 msgid "Regular expression too big"
 msgstr "Expressió regular és massa gran"
 
+#: compat/regex/regcomp.c
 msgid "Unmatched ) or \\)"
 msgstr ") o \\) no emparellat"
 
+#: compat/regex/regcomp.c
 msgid "No previous regular expression"
 msgstr "No hi ha expressió regular anterior"
 
+#: compat/simple-ipc/ipc-unix-socket.c compat/simple-ipc/ipc-win32.c
 msgid "could not send IPC command"
 msgstr "no s'ha pogut enviar l'ordre IPC"
 
+#: compat/simple-ipc/ipc-unix-socket.c compat/simple-ipc/ipc-win32.c
 msgid "could not read IPC response"
 msgstr "no s'ha pogut llegir la resposta IPC"
 
+#: compat/simple-ipc/ipc-unix-socket.c
 #, c-format
 msgid "could not start accept_thread '%s'"
 msgstr "no s'ha pogut començar un fil «accept_thread» «%s»"
 
+#: compat/simple-ipc/ipc-unix-socket.c
 #, c-format
 msgid "could not start worker[0] for '%s'"
 msgstr "no s'ha pogut iniciar el fil[0] per a «%s»"
 
+#: compat/simple-ipc/ipc-win32.c
 #, c-format
 msgid "ConnectNamedPipe failed for '%s' (%lu)"
 msgstr "Ha fallat ConnectNamedPipe per a «%s» (%lu)"
 
+#: compat/simple-ipc/ipc-win32.c
 #, c-format
 msgid "could not create fd from pipe for '%s'"
 msgstr "no s'ha pogut crear un fd a partir de la canonada per a «%s»"
 
+#: compat/simple-ipc/ipc-win32.c
 #, c-format
 msgid "could not start thread[0] for '%s'"
 msgstr "no s'ha pogut iniciar el fil[0] per a «%s»"
 
+#: compat/simple-ipc/ipc-win32.c
 #, c-format
 msgid "wait for hEvent failed for '%s'"
 msgstr "ha fallat l'espera de hEvent per a «%s»"
 
+#: compat/terminal.c
 msgid "cannot resume in the background, please use 'fg' to resume"
 msgstr "no es pot reprendre en segon pla, si us plau useu «fg» per a reprendre"
 
+#: compat/terminal.c
 msgid "cannot restore terminal settings"
 msgstr "no es poden restaurar els paràmetres del terminal"
 
+#: config.c
 #, c-format
 msgid ""
 "exceeded maximum include depth (%d) while including\n"
@@ -15183,17 +19365,21 @@
 "\t%s\n"
 "Això pot ser degut a inclusions circulars."
 
+#: config.c
 #, c-format
 msgid "could not expand include path '%s'"
 msgstr "no s'ha pogut expandir el camí d'inclusió «%s»"
 
+#: config.c
 msgid "relative config includes must come from files"
 msgstr "les inclusions de configuració relatives han de venir de fitxers"
 
+#: config.c
 msgid "relative config include conditionals must come from files"
 msgstr ""
 "els condicionals d'inclusió de configuració relatius han de venir de fitxers"
 
+#: config.c
 msgid ""
 "remote URLs cannot be configured in file directly or indirectly included by "
 "includeIf.hasconfig:remote.*.url"
@@ -15201,273 +19387,353 @@
 "URL remots no es poden configurar en un fitxer directament o indirectament "
 "inclòs per «includeIf.hasconfig:remote.*.url»"
 
+#: config.c
 #, c-format
 msgid "invalid config format: %s"
 msgstr "format de configuració no vàlid: %s"
 
+#: config.c
 #, c-format
 msgid "missing environment variable name for configuration '%.*s'"
 msgstr "falta el nom de la variable d'entorn per a la configuració «%.*s»"
 
+#: config.c
 #, c-format
 msgid "missing environment variable '%s' for configuration '%.*s'"
 msgstr "falta la variable d'entorn «%s» per a la configuració «%.*s»"
 
+#: config.c
 #, c-format
 msgid "key does not contain a section: %s"
 msgstr "la clau no conté una secció: «%s»"
 
+#: config.c
 #, c-format
 msgid "key does not contain variable name: %s"
 msgstr "la clau no conté un nom de variable: «%s»"
 
+#: config.c sequencer.c
 #, c-format
 msgid "invalid key: %s"
 msgstr "clau no vàlida: %s"
 
+#: config.c
 #, c-format
 msgid "invalid key (newline): %s"
 msgstr "clau no vàlida (línia nova): %s"
 
+#: config.c
 msgid "empty config key"
 msgstr "clau de configuració buida"
 
+#: config.c
 #, c-format
 msgid "bogus config parameter: %s"
 msgstr "paràmetre de configuració erroni: %s"
 
+#: config.c
 #, c-format
 msgid "bogus format in %s"
 msgstr "format erroni a %s"
 
+#: config.c
 #, c-format
 msgid "bogus count in %s"
 msgstr "comptatge erroni a %s"
 
+#: config.c
 #, c-format
 msgid "too many entries in %s"
 msgstr "hi ha massa arguments a %s"
 
+#: config.c
 #, c-format
 msgid "missing config key %s"
 msgstr "falta la clau de configuració %s"
 
+#: config.c
 #, c-format
 msgid "missing config value %s"
 msgstr "falta el valor de configuració %s"
 
+#: config.c
 #, c-format
 msgid "bad config line %d in blob %s"
 msgstr "línia de configuració %d errònia en el blob %s"
 
+#: config.c
 #, c-format
 msgid "bad config line %d in file %s"
 msgstr "línia de configuració %d errònia en el fitxer %s"
 
+#: config.c
 #, c-format
 msgid "bad config line %d in standard input"
 msgstr "línia de configuració %d errònia en l'entrada estàndard"
 
+#: config.c
 #, c-format
 msgid "bad config line %d in submodule-blob %s"
 msgstr "línia de configuració %d errònia en el blob de submòdul %s"
 
+#: config.c
 #, c-format
 msgid "bad config line %d in command line %s"
 msgstr "línia de configuració %d errònia en la línia d'ordres %s"
 
+#: config.c
 #, c-format
 msgid "bad config line %d in %s"
 msgstr "línia de configuració %d errònia en %s"
 
+#: config.c
 msgid "out of range"
 msgstr "fora de rang"
 
+#: config.c
 msgid "invalid unit"
 msgstr "unitat no vàlida"
 
+#: config.c
 #, c-format
 msgid "bad numeric config value '%s' for '%s': %s"
 msgstr "valor de configuració numèric erroni «%s» per «%s»: %s"
 
+#: config.c
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in blob %s: %s"
 msgstr "valor de configuració numèric erroni «%s» per «%s» en el blob %s: %s"
 
+#: config.c
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in file %s: %s"
 msgstr "valor de configuració numèric «%s» erroni per «%s» en el fitxer %s: %s"
 
+#: config.c
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in standard input: %s"
 msgstr ""
 "valor de configuració numèric «%s» erroni per «%s» en l'entrada estàndard: %s"
 
+#: config.c
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in submodule-blob %s: %s"
 msgstr ""
 "valor de configuració numèric «%s» erroni per «%s» en el blob de submòdul "
 "%s: %s"
 
+#: config.c
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in command line %s: %s"
 msgstr ""
 "valor de configuració numèric «%s» erroni per «%s» en la línia d'ordres %s: "
 "%s"
 
+#: config.c
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in %s: %s"
 msgstr "valor de configuració numèric incorrecte «%s» per «%s» en %s: %s"
 
+#: config.c
 #, c-format
 msgid "invalid value for variable %s"
 msgstr "valor no vàlid per a la variable %s"
 
+#: config.c
 #, c-format
 msgid "ignoring unknown core.fsync component '%s'"
 msgstr "s'ignora el component core.fsync «%s» desconegut"
 
+#: config.c
 #, c-format
 msgid "bad boolean config value '%s' for '%s'"
 msgstr "valor de configuració booleà erroni «%s» per a «%s»"
 
+#: config.c
 #, c-format
 msgid "failed to expand user dir in: '%s'"
 msgstr "s'ha produït un error en expandir el directori d'usuari en: «%s»"
 
+#: config.c
 #, c-format
 msgid "'%s' for '%s' is not a valid timestamp"
 msgstr "«%s» per a «%s» no és una marca de temps vàlida"
 
+#: config.c
 #, c-format
 msgid "abbrev length out of range: %d"
 msgstr "la longitud d'«abbrev» està fora de rang: %d"
 
+#: config.c
 #, c-format
 msgid "bad zlib compression level %d"
 msgstr "nivell de compressió de zlib incorrecte %d"
 
-msgid "core.commentChar should only be one ASCII character"
-msgstr "core.commentChar només hauria de ser un caràcter ASCII"
+# newline → línia nova o salt de línia?
+#: config.c
+#, c-format
+msgid "%s cannot contain newline"
+msgstr "%s no pot contenir una nova línia"
 
+#: config.c
+#, c-format
+msgid "%s must have at least one character"
+msgstr "%s ha de tenir almenys un caràcter"
+
+#: config.c
 #, c-format
 msgid "ignoring unknown core.fsyncMethod value '%s'"
 msgstr "s'ignora el valor desconegut «%s» de core.fsyncMethod"
 
+#: config.c
 msgid "core.fsyncObjectFiles is deprecated; use core.fsync instead"
 msgstr "core.fsyncObjectFiles és obsolet; useu core.fsync"
 
+#: config.c
 #, c-format
 msgid "invalid mode for object creation: %s"
 msgstr "mode de creació d'objecte no vàlid: %s"
 
+#: config.c
 #, c-format
 msgid "malformed value for %s"
 msgstr "valor no vàlid per a %s"
 
+#: config.c
 #, c-format
 msgid "malformed value for %s: %s"
 msgstr "valor no vàlid per a %s: %s"
 
+#: config.c
 msgid "must be one of nothing, matching, simple, upstream or current"
 msgstr ""
 "ha de ser un dels elements següents: nothing, matching, simple, upstream o "
 "current"
 
+#: config.c
 #, c-format
 msgid "unable to load config blob object '%s'"
 msgstr "no s'ha pogut carregar l'objecte blob de configuració «%s»"
 
+#: config.c
 #, c-format
 msgid "reference '%s' does not point to a blob"
 msgstr "la referència «%s» no assenyala a un blob"
 
+#: config.c
 #, c-format
 msgid "unable to resolve config blob '%s'"
 msgstr "no s'ha pogut resoldre el blob de configuració: «%s»"
 
+#: config.c
 msgid "unable to parse command-line config"
 msgstr "no s'ha pogut analitzar la configuració de la línia d'ordres"
 
+#: config.c
 msgid "unknown error occurred while reading the configuration files"
 msgstr "un error desconegut ha ocorregut en llegir els fitxers de configuració"
 
+#: config.c
 #, c-format
 msgid "Invalid %s: '%s'"
 msgstr "%s no vàlid: «%s»"
 
+#: config.c
 #, c-format
 msgid "splitIndex.maxPercentChange value '%d' should be between 0 and 100"
 msgstr "valor «%d» a splitIndex.maxPercentChange ha d'estar entre 0 i 100"
 
+#: config.c
 #, c-format
 msgid "unable to parse '%s' from command-line config"
 msgstr "no s'ha pogut analitzar «%s» de la configuració de la línia d'ordres"
 
+#: config.c
 #, c-format
 msgid "bad config variable '%s' in file '%s' at line %d"
 msgstr "variable de configuració «%s» errònia en el fitxer «%s» a la línia %d"
 
+#: config.c
 #, c-format
 msgid "invalid section name '%s'"
 msgstr "nom de secció no vàlid «%s»"
 
+#: config.c
 #, c-format
 msgid "%s has multiple values"
 msgstr "%s té múltiples valors"
 
+#: config.c
 #, c-format
 msgid "failed to write new configuration file %s"
 msgstr "no es pot escriure un nou fitxer de configuració %s"
 
+#: config.c
+#, c-format
+msgid "no multi-line comment allowed: '%s'"
+msgstr "no es permet el comentari multi-línia: «%s»"
+
+#: config.c
 #, c-format
 msgid "could not lock config file %s"
 msgstr "no s'ha pogut blocar el fitxer de configuració %s"
 
+#: config.c
 #, c-format
 msgid "opening %s"
 msgstr "s'està obrint %s"
 
+#: config.c
 #, c-format
 msgid "invalid config file %s"
 msgstr "fitxer de configuració no vàlid %s"
 
+#: config.c
 #, c-format
 msgid "fstat on %s failed"
 msgstr "ha fallat «fstat» a %s"
 
+#: config.c
 #, c-format
 msgid "unable to mmap '%s'%s"
 msgstr "no s'ha pogut fer «mmap» «%s»%s"
 
+#: config.c
 #, c-format
 msgid "chmod on %s failed"
 msgstr "ha fallat chmod a %s"
 
+#: config.c
 #, c-format
 msgid "could not write config file %s"
 msgstr "no s'ha pogut escriure el fitxer de configuració «%s»"
 
+#: config.c
 #, c-format
 msgid "could not set '%s' to '%s'"
 msgstr "no s'ha pogut establir «%s» a «%s»"
 
+#: config.c
 #, c-format
 msgid "invalid section name: %s"
 msgstr "nom de secció no vàlida: %s"
 
+#: config.c
 #, c-format
 msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
 msgstr ""
 "es rebutja treballar amb una línia massa llarga a «%s» a la línia %<PRIuMAX>"
 
+#: config.c
 #, c-format
 msgid "missing value for '%s'"
 msgstr "falta el valor per «%s»"
 
+#: connect.c
 msgid "the remote end hung up upon initial contact"
 msgstr "el costat remot ha penjat en el moment de contacte inicial"
 
+#: connect.c
 msgid ""
 "Could not read from remote repository.\n"
 "\n"
@@ -15479,77 +19745,97 @@
 "Assegureu-vos que tingueu els permisos\n"
 "d'accés correctes i que el repositori existeixi."
 
+#: connect.c
 #, c-format
 msgid "server doesn't support '%s'"
 msgstr "el servidor no és compatible amb «%s»"
 
+#: connect.c
 #, c-format
 msgid "server doesn't support feature '%s'"
 msgstr "el servidor no és compatible amb la característica «%s»"
 
+#: connect.c
 msgid "expected flush after capabilities"
 msgstr "s'esperava un buidatge després de les capacitats"
 
+#: connect.c
 #, c-format
 msgid "ignoring capabilities after first line '%s'"
 msgstr "ignora les capacitats després de la primera línia «%s»"
 
+#: connect.c
 msgid "protocol error: unexpected capabilities^{}"
 msgstr "error de protocol: unexpected capabilities^{}"
 
+#: connect.c
 #, c-format
 msgid "protocol error: expected shallow sha-1, got '%s'"
 msgstr ""
 "s'ha produït un error de protocol: s'esperava shallow sha-1, s'ha rebut «%s»"
 
+#: connect.c
 msgid "repository on the other end cannot be shallow"
 msgstr "el repositori de l'altre extrem no pot ser shallow"
 
+#: connect.c
 msgid "invalid packet"
 msgstr "paquet no vàlid"
 
+#: connect.c
 #, c-format
 msgid "protocol error: unexpected '%s'"
 msgstr "s'ha produït un error de protocol: no s'esperava «%s»"
 
+#: connect.c
 #, c-format
 msgid "unknown object format '%s' specified by server"
 msgstr "format d'objecte «%s» especificat pel servidor desconegut"
 
+#: connect.c
 #, c-format
 msgid "error on bundle-uri response line %d: %s"
 msgstr "error a la línia de resposta de bundle-uri %d: %s"
 
+#: connect.c
 msgid "expected flush after bundle-uri listing"
 msgstr "s'esperava un buidatge després del llistat de bundle-uri"
 
+#: connect.c
 msgid "expected response end packet after ref listing"
 msgstr ""
 "s'esperava un paquet de final de resposta després del llistat de referències"
 
+#: connect.c
 #, c-format
 msgid "invalid ls-refs response: %s"
 msgstr "resposta de ls-refs no vàlida: %s"
 
+#: connect.c
 msgid "expected flush after ref listing"
 msgstr "s'esperava una neteja després del llistat de referències"
 
+#: connect.c
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr "el protocol «%s» no és compatible"
 
+#: connect.c
 msgid "unable to set SO_KEEPALIVE on socket"
 msgstr "no s'ha pogut establir SO_KEEPALIVE al sòcol"
 
+#: connect.c
 #, c-format
 msgid "Looking up %s ... "
 msgstr "S'està cercant %s..."
 
+#: connect.c
 #, c-format
 msgid "unable to look up %s (port %s) (%s)"
 msgstr "no s'ha pogut trobar %s (port %s) (%s)"
 
 #. TRANSLATORS: this is the end of "Looking up %s ... "
+#: connect.c
 #, c-format
 msgid ""
 "done.\n"
@@ -15558,6 +19844,7 @@
 "fet.\n"
 "S'està connectant a %s (port %s) ... "
 
+#: connect.c
 #, c-format
 msgid ""
 "unable to connect to %s:\n"
@@ -15567,72 +19854,91 @@
 "%s"
 
 #. TRANSLATORS: this is the end of "Connecting to %s (port %s) ... "
+#: connect.c
 msgid "done."
 msgstr "fet."
 
+#: connect.c
 #, c-format
 msgid "unable to look up %s (%s)"
 msgstr "no s'ha pogut trobar %s (%s)"
 
+#: connect.c
 #, c-format
 msgid "unknown port %s"
 msgstr "port desconegut %s"
 
+#: connect.c
 #, c-format
 msgid "strange hostname '%s' blocked"
 msgstr "s'ha bloquejat el nom estrany d'amfitrió «%s»"
 
+#: connect.c
 #, c-format
 msgid "strange port '%s' blocked"
 msgstr "s'ha bloquejat el port estrany «%s»"
 
+#: connect.c
 #, c-format
 msgid "cannot start proxy %s"
 msgstr "no s'ha pogut iniciar servidor intermediari «%s»"
 
+#: connect.c
 msgid "no path specified; see 'git help pull' for valid url syntax"
 msgstr ""
 "no s'ha especificat un camí; vegeu «git help pull» per la sintaxi vàlida per "
 "URL"
 
+#: connect.c
 msgid "newline is forbidden in git:// hosts and repo paths"
 msgstr ""
 "la línia nova està prohibida en els servidors git:// i els camins de "
 "repositori"
 
+#: connect.c
 msgid "ssh variant 'simple' does not support -4"
 msgstr "la variant «simple» de ssh no és compatible amb -4"
 
+#: connect.c
 msgid "ssh variant 'simple' does not support -6"
 msgstr "la variant «simple» de ssh no és compatible amb -6"
 
+#: connect.c
 msgid "ssh variant 'simple' does not support setting port"
 msgstr "la variant «simple» de ssh no permet definir el port"
 
+#: connect.c
 #, c-format
 msgid "strange pathname '%s' blocked"
 msgstr "s'ha bloquejat el nom de fitxer estrany «%s»"
 
+#: connect.c
 msgid "unable to fork"
 msgstr "no s'ha pogut bifurcar"
 
+#: connected.c
 msgid "Could not run 'git rev-list'"
 msgstr "No s'ha pogut executar «git rev-list»"
 
+#: connected.c
 msgid "failed write to rev-list"
 msgstr "escriptura fallada al rev-list"
 
+#: connected.c
 msgid "failed to close rev-list's stdin"
 msgstr "s'ha produït un error en tancar l'stdin del rev-list"
 
+#: convert.c
 #, c-format
 msgid "illegal crlf_action %d"
 msgstr "crlf_action %d il·legal"
 
+#: convert.c
 #, c-format
 msgid "CRLF would be replaced by LF in %s"
 msgstr "CRLF es reemplaçà per LF en %s"
 
+#: convert.c
 #, c-format
 msgid ""
 "in the working copy of '%s', CRLF will be replaced by LF the next time Git "
@@ -15641,10 +19947,12 @@
 "a la còpia de treball de «%s», CRLF serà substituït per LF, la propera "
 "vegada que el Git ho modifiqui"
 
+#: convert.c
 #, c-format
 msgid "LF would be replaced by CRLF in %s"
 msgstr "LF es reemplaçà per CRLF en %s"
 
+#: convert.c
 #, c-format
 msgid ""
 "in the working copy of '%s', LF will be replaced by CRLF the next time Git "
@@ -15653,64 +19961,79 @@
 "a la còpia de treball de «%s», LF serà substituït per CRLF la propera vegada "
 "que Git ho modifiqui"
 
+#: convert.c
 #, c-format
 msgid "BOM is prohibited in '%s' if encoded as %s"
 msgstr "BOM està prohibida a «%s» si està codificada com a %s"
 
+#: convert.c
 #, c-format
 msgid ""
 "The file '%s' contains a byte order mark (BOM). Please use UTF-%.*s as "
 "working-tree-encoding."
 msgstr ""
-"El fitxer «%s» conté una marca d'ordre de byte (BOM). Utilitzeu UTF-%.*s com "
-"a codificacions d'arbre de treball."
+"El fitxer «%s» conté una marca d'ordre de octets (BOM). Utilitzeu UTF-%.*s "
+"com a codificacions d'arbre de treball."
 
+#: convert.c
 #, c-format
 msgid "BOM is required in '%s' if encoded as %s"
 msgstr "La BOM és necessària en «%s» si està codificada com a %s"
 
+#: convert.c
 #, c-format
 msgid ""
 "The file '%s' is missing a byte order mark (BOM). Please use UTF-%sBE or UTF-"
 "%sLE (depending on the byte order) as working-tree-encoding."
 msgstr ""
-"Falta una marca d'ordre de byte (BOM) al fitxer «%s». Useu UTF-%sBE o UTF-"
-"%sLE (depenent de l'ordre de byte) com a codificacions d'arbre de treball."
+"Falta una marca d'ordre d'octets (BOM) al fitxer «%s». Useu UTF-%sBE o UTF-"
+"%sLE (depenent de l'ordre dels octets) com a codificacions d'arbre de "
+"treball."
 
+#: convert.c
 #, c-format
 msgid "failed to encode '%s' from %s to %s"
 msgstr "s'ha produït un error en codificar «%s» des de %s a %s"
 
+#: convert.c
 #, c-format
 msgid "encoding '%s' from %s to %s and back is not the same"
 msgstr "codificar «%s» des de %s a %s i cap enrere no és el mateix"
 
+#: convert.c
 #, c-format
 msgid "cannot fork to run external filter '%s'"
 msgstr "no es pot bifurcar per a executar el filtre extern «%s»"
 
+#: convert.c
 #, c-format
 msgid "cannot feed the input to external filter '%s'"
 msgstr "no es pot alimentar l'entrada al filtre extern «%s»"
 
+#: convert.c
 #, c-format
 msgid "external filter '%s' failed %d"
 msgstr "el filtre extern «%s» ha fallat %d"
 
+#: convert.c
 #, c-format
 msgid "read from external filter '%s' failed"
 msgstr "la lectura del filtre extern «%s» ha fallat"
 
+#: convert.c
 #, c-format
 msgid "external filter '%s' failed"
 msgstr "el filtre extern «%s» ha fallat"
 
+#: convert.c
 msgid "unexpected filter type"
 msgstr "tipus de filtre inesperat"
 
+#: convert.c
 msgid "path name too long for external filter"
 msgstr "el nom del camí és massa gran per al filtre extern"
 
+#: convert.c
 #, c-format
 msgid ""
 "external filter '%s' is not available anymore although not all paths have "
@@ -15719,80 +20042,97 @@
 "el filtre extern «%s» ja no està disponible encara que no s'han filtrat tots "
 "els camins"
 
+#: convert.c
 msgid "true/false are no valid working-tree-encodings"
 msgstr "cert/fals no són codificacions d'arbre de treball vàlides"
 
+#: convert.c
 #, c-format
 msgid "%s: clean filter '%s' failed"
 msgstr "%s: el filtre de netejat «%s» ha fallat"
 
+#: convert.c
 #, c-format
 msgid "%s: smudge filter %s failed"
 msgstr "%s: ha fallat el filtre smudge %s"
 
+#: credential.c
 #, c-format
 msgid "skipping credential lookup for key: credential.%s"
 msgstr "s'està ometent la cerca de credencials per una clau: credential.%s"
 
+#: credential.c
 msgid "refusing to work with credential missing host field"
 msgstr ""
 "s'ha rebutjat treballar amb credencials que no tenen el camp d'amfitrió"
 
+#: credential.c
 msgid "refusing to work with credential missing protocol field"
 msgstr ""
 "s'ha rebutjat treballar amb credencials que no tenen el camp de protocol"
 
+#: credential.c
 #, c-format
 msgid "url contains a newline in its %s component: %s"
 msgstr "url conté una línia nova en %s component: %s"
 
+#: credential.c
 #, c-format
 msgid "url has no scheme: %s"
 msgstr "l'url no té esquema: %s"
 
+#: credential.c
 #, c-format
 msgid "credential url cannot be parsed: %s"
 msgstr "no s'ha pogut analitzar l'URL de credencials: %s"
 
+#: date.c
 msgid "in the future"
 msgstr "en el futur"
 
+#: date.c
 #, c-format
 msgid "%<PRIuMAX> second ago"
 msgid_plural "%<PRIuMAX> seconds ago"
 msgstr[0] "fa %<PRIuMAX> segon"
 msgstr[1] "fa %<PRIuMAX> segons"
 
+#: date.c
 #, c-format
 msgid "%<PRIuMAX> minute ago"
 msgid_plural "%<PRIuMAX> minutes ago"
 msgstr[0] "fa %<PRIuMAX> minut"
 msgstr[1] "fa %<PRIuMAX> minuts"
 
+#: date.c
 #, c-format
 msgid "%<PRIuMAX> hour ago"
 msgid_plural "%<PRIuMAX> hours ago"
 msgstr[0] "fa %<PRIuMAX> hora"
 msgstr[1] "fa %<PRIuMAX> hores"
 
+#: date.c
 #, c-format
 msgid "%<PRIuMAX> day ago"
 msgid_plural "%<PRIuMAX> days ago"
 msgstr[0] "fa %<PRIuMAX> dia"
 msgstr[1] "fa %<PRIuMAX> dies"
 
+#: date.c
 #, c-format
 msgid "%<PRIuMAX> week ago"
 msgid_plural "%<PRIuMAX> weeks ago"
 msgstr[0] "fa %<PRIuMAX> setmana"
 msgstr[1] "fa %<PRIuMAX> setmanes"
 
+#: date.c
 #, c-format
 msgid "%<PRIuMAX> month ago"
 msgid_plural "%<PRIuMAX> months ago"
 msgstr[0] "fa %<PRIuMAX> mes"
 msgstr[1] "fa %<PRIuMAX> mesos"
 
+#: date.c
 #, c-format
 msgid "%<PRIuMAX> year"
 msgid_plural "%<PRIuMAX> years"
@@ -15800,87 +20140,109 @@
 msgstr[1] "%<PRIuMAX> anys"
 
 #. TRANSLATORS: "%s" is "<n> years"
+#: date.c
 #, c-format
 msgid "%s, %<PRIuMAX> month ago"
 msgid_plural "%s, %<PRIuMAX> months ago"
 msgstr[0] "fa %s i %<PRIuMAX> mes"
 msgstr[1] "fa %s i %<PRIuMAX> mesos"
 
+#: date.c
 #, c-format
 msgid "%<PRIuMAX> year ago"
 msgid_plural "%<PRIuMAX> years ago"
 msgstr[0] "fa %<PRIuMAX> any"
 msgstr[1] "fa %<PRIuMAX> anys"
 
+#: delta-islands.c
 msgid "Propagating island marks"
 msgstr "S'estan propagant les marques d'illa"
 
+#: delta-islands.c
 #, c-format
 msgid "bad tree object %s"
 msgstr "objecte d'arbre malmès %s"
 
+#: delta-islands.c
 #, c-format
 msgid "failed to load island regex for '%s': %s"
 msgstr ""
 "s'ha produït un error en carregar l'expressió regular de l'illa per «%s»: %s"
 
+#: delta-islands.c
 #, c-format
 msgid "island regex from config has too many capture groups (max=%d)"
 msgstr ""
 "l'expressió regular de l'illa des de la configuració té massa grups de "
 "captura (màx=%d)"
 
+#: delta-islands.c
 #, c-format
 msgid "Marked %d islands, done.\n"
 msgstr "Marcades %d illes, fet.\n"
 
+#: diagnose.c
 #, c-format
 msgid "invalid --%s value '%s'"
 msgstr "no és vàlid --%s amb valor «%s»"
 
+#: diagnose.c
 #, c-format
 msgid "could not archive missing directory '%s'"
 msgstr "no s'ha pogut arxivar el directori que falta «%s»"
 
+#: diagnose.c dir.c
 #, c-format
 msgid "could not open directory '%s'"
 msgstr "no s'ha pogut obrir el directori «%s»"
 
+#: diagnose.c
 #, c-format
 msgid "skipping '%s', which is neither file nor directory"
 msgstr "s'omet «%s», que no és ni fitxer ni directori"
 
+#: diagnose.c
 msgid "could not duplicate stdout"
 msgstr "no s'ha pogut duplicar stdout"
 
+#: diagnose.c
 #, c-format
 msgid "could not add directory '%s' to archiver"
 msgstr "no s'ha pogut afegir el directori «%s» a l'arxivador"
 
+#: diagnose.c
 msgid "failed to write archive"
 msgstr "s'ha produït un error en escriure arxiu"
 
+#: diff-lib.c
 msgid "--merge-base does not work with ranges"
 msgstr "--merge-base no funciona amb intervals"
 
+#: diff-lib.c
 msgid "unable to get HEAD"
 msgstr "no s'ha pogut obtenir HEAD"
 
+#: diff-lib.c
 msgid "no merge base found"
 msgstr "no s'ha trobat una base de fusió"
 
+#: diff-lib.c
 msgid "multiple merge bases found"
 msgstr "s'han trobat múltiples bases de fusió"
 
+#: diff-no-index.c
 msgid "cannot compare stdin to a directory"
 msgstr "no es pot comparar stdin amb un directori"
 
+#: diff-no-index.c
 msgid "cannot compare a named pipe to a directory"
 msgstr "no es pot comparar una canonada amb nom amb un directori"
 
+#: diff-no-index.c
 msgid "git diff --no-index [<options>] <path> <path>"
 msgstr "git diff --no-index [<opcions>] <camí> <camí>"
 
+#: diff-no-index.c
 msgid ""
 "Not a git repository. Use --no-index to compare two paths outside a working "
 "tree"
@@ -15888,16 +20250,19 @@
 "No és un repositori Git. Useu --no-index per a comparar dos camins fora del "
 "directori de treball"
 
+#: diff.c
 #, c-format
 msgid "  Failed to parse dirstat cut-off percentage '%s'\n"
 msgstr ""
 "  S'ha produït un error en analitzar el percentatge limitant de dirstat "
 "«%s»\n"
 
+#: diff.c
 #, c-format
 msgid "  Unknown dirstat parameter '%s'\n"
 msgstr "  Paràmetre de dirstat desconegut «%s»\n"
 
+#: diff.c
 msgid ""
 "color moved setting must be one of 'no', 'default', 'blocks', 'zebra', "
 "'dimmed-zebra', 'plain'"
@@ -15905,6 +20270,7 @@
 "el paràmetre de color en moviment ha de ser «no», «default», «blocks», "
 "«zebra», «dimmed-zebra» o «plain»"
 
+#: diff.c
 #, c-format
 msgid ""
 "unknown color-moved-ws mode '%s', possible values are 'ignore-space-change', "
@@ -15914,6 +20280,7 @@
 "«ignore-space-change», «ignore-space-at-eol», «ignore-all-space», «allow-"
 "indentation-change»"
 
+#: diff.c
 msgid ""
 "color-moved-ws: allow-indentation-change cannot be combined with other "
 "whitespace modes"
@@ -15921,15 +20288,18 @@
 "color-moved-ws: allow-indentation-change no es pot combinar amb altres modes "
 "d'espai en blanc"
 
+#: diff.c
 #, c-format
 msgid "Unknown value for 'diff.submodule' config variable: '%s'"
 msgstr ""
 "Valor desconegut de la variable de configuració de «diff.submodule»: «%s»"
 
+#: diff.c merge-recursive.c transport.c
 #, c-format
 msgid "unknown value for config '%s': %s"
 msgstr "valor desconegut per al config «%s»': %s"
 
+#: diff.c
 #, c-format
 msgid ""
 "Found errors in 'diff.dirstat' config variable:\n"
@@ -15938,39 +20308,48 @@
 "S'han trobat errors en la variable de configuració «diff.dirstat»:\n"
 "%s"
 
+#: diff.c
 #, c-format
 msgid "external diff died, stopping at %s"
 msgstr "el diff external s'ha mort, s'està aturant a %s"
 
+#: diff.c
 msgid "--follow requires exactly one pathspec"
 msgstr "--follow requereix exactament una especificació de camí"
 
+#: diff.c
 #, c-format
 msgid "pathspec magic not supported by --follow: %s"
 msgstr "el «pathspec» màgic no està suportat per --follow: %s"
 
+#: diff.c parse-options.c
 #, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
 msgstr "les opcions «%s», «%s», «%s», i «%s» no es poden usar juntes"
 
+#: diff.c
 #, c-format
 msgid "options '%s' and '%s' cannot be used together, use '%s' with '%s'"
 msgstr "les opcions «%s» i «%s» no es poden usar juntes, useu «%s» amb «%s»"
 
+#: diff.c
 #, c-format
 msgid ""
 "options '%s' and '%s' cannot be used together, use '%s' with '%s' and '%s'"
 msgstr ""
 "les opcions «%s» i «%s» no es poden usar juntes, useu «%s» amb «%s» i «%s»"
 
+#: diff.c
 #, c-format
 msgid "invalid --stat value: %s"
 msgstr "valor --stat no vàlid: %s"
 
+#: diff.c parse-options.c
 #, c-format
 msgid "%s expects a numerical value"
 msgstr "%s espera un valor numèric"
 
+#: diff.c
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -15979,147 +20358,189 @@
 "S'ha produït un error en analitzar el paràmetre d'opció de --dirstat/-X:\n"
 "%s"
 
+#: diff.c
 #, c-format
 msgid "unknown change class '%c' in --diff-filter=%s"
 msgstr "classe de canvi «%c» desconeguda a --diff-filter=%s"
 
+#: diff.c
 #, c-format
 msgid "unknown value after ws-error-highlight=%.*s"
 msgstr "valor desconegut després de ws-error-highlight=%.*s"
 
+#: diff.c
 #, c-format
 msgid "unable to resolve '%s'"
 msgstr "no s'ha pogut resoldre «%s»"
 
+#: diff.c
 #, c-format
 msgid "%s expects <n>/<m> form"
 msgstr "%s espera una forma <n>/<m>"
 
+#: diff.c
 #, c-format
 msgid "%s expects a character, got '%s'"
 msgstr "%s esperava un caràcter, s'ha rebut «%s»"
 
+#: diff.c
 #, c-format
 msgid "bad --color-moved argument: %s"
 msgstr "argument --color-moved incorrecte: %s"
 
+#: diff.c
 #, c-format
 msgid "invalid mode '%s' in --color-moved-ws"
 msgstr "mode «%s» no vàlid en --color-moved-ws"
 
+#: diff.c
 #, c-format
 msgid "invalid argument to %s"
 msgstr "argument no vàlid a %s"
 
+#: diff.c
 #, c-format
 msgid "invalid regex given to -I: '%s'"
 msgstr "expressió regular donada a -I: no vàlida: «%s»"
 
+#: diff.c
 #, c-format
 msgid "failed to parse --submodule option parameter: '%s'"
 msgstr ""
 "s'ha produït un error en analitzar el paràmetre d'opció de --submodule: «%s»"
 
+#: diff.c
 #, c-format
 msgid "bad --word-diff argument: %s"
 msgstr "argument --word-diff incorrecte: %s"
 
+#: diff.c
 msgid "Diff output format options"
 msgstr "Opcions del format de sortida del diff"
 
+#: diff.c
 msgid "generate patch"
 msgstr "genera el pedaç"
 
+#: diff.c
 msgid "<n>"
 msgstr "<n>"
 
+#: diff.c
 msgid "generate diffs with <n> lines context"
 msgstr "genera diffs amb <n> línies de context"
 
+#: diff.c
 msgid "generate the diff in raw format"
 msgstr "genera el diff en format cru"
 
+#: diff.c
 msgid "synonym for '-p --raw'"
 msgstr "sinònim de «-p --raw»"
 
+#: diff.c
 msgid "synonym for '-p --stat'"
 msgstr "sinònim de «-p --stat»"
 
+#: diff.c
 msgid "machine friendly --stat"
 msgstr "llegible per una màquina --stat"
 
+#: diff.c
 msgid "output only the last line of --stat"
 msgstr "mostra només l'última línia de --stat"
 
+#: diff.c
 msgid "<param1>,<param2>..."
 msgstr "<param1>,<param2>..."
 
+#: diff.c
 msgid ""
 "output the distribution of relative amount of changes for each sub-directory"
 msgstr ""
 "genera la distribució de la quantitat relativa de canvis per a cada "
 "subdirectori"
 
+#: diff.c
 msgid "synonym for --dirstat=cumulative"
 msgstr "sinònim de --dirstat=cumulative"
 
+#: diff.c
 msgid "synonym for --dirstat=files,<param1>,<param2>..."
 msgstr "sinònim de --dirstat=files,<param1>,<param2>..."
 
+#: diff.c
 msgid "warn if changes introduce conflict markers or whitespace errors"
 msgstr ""
 "avisa si els canvis introdueixen marcadors en conflicte o errors d'espai en "
 "blanc"
 
+#: diff.c
 msgid "condensed summary such as creations, renames and mode changes"
 msgstr "resum condensat com ara creacions, canvis de nom i mode"
 
+#: diff.c
 msgid "show only names of changed files"
 msgstr "mostra només els noms de fitxers canviats"
 
+#: diff.c
 msgid "show only names and status of changed files"
 msgstr "mostra només els noms i l'estat dels fitxers canviats"
 
+#: diff.c
 msgid "<width>[,<name-width>[,<count>]]"
 msgstr "<amplada>[<amplada-nom>[,<recompte>]]"
 
+#: diff.c
 msgid "generate diffstat"
 msgstr "genera diffstat"
 
+#: diff.c
 msgid "<width>"
 msgstr "<amplada>"
 
+#: diff.c
 msgid "generate diffstat with a given width"
 msgstr "genera diffstat amb una amplada donada"
 
+#: diff.c
 msgid "generate diffstat with a given name width"
 msgstr "genera diffstat amb un nom d'amplada donat"
 
+#: diff.c
 msgid "generate diffstat with a given graph width"
 msgstr "genera diffstat amb una amplada de graf donada"
 
+#: diff.c
 msgid "<count>"
 msgstr "<comptador>"
 
+#: diff.c
 msgid "generate diffstat with limited lines"
 msgstr "genera diffstat amb línies limitades"
 
+#: diff.c
 msgid "generate compact summary in diffstat"
 msgstr "genera un resum compacte a diffstat"
 
+#: diff.c
 msgid "output a binary diff that can be applied"
 msgstr "diff amb sortida binària que pot ser aplicada"
 
+#: diff.c
 msgid "show full pre- and post-image object names on the \"index\" lines"
 msgstr ""
 "mostra els noms complets dels objectes pre i post-imatge a les línies «index»"
 
+#: diff.c
 msgid "show colored diff"
 msgstr "mostra un diff amb colors"
 
+#: diff.c
 msgid "<kind>"
 msgstr "<kind>"
 
+#: diff.c
 msgid ""
 "highlight whitespace errors in the 'context', 'old' or 'new' lines in the "
 "diff"
@@ -16127,6 +20548,7 @@
 "ressalta els errors d'espai en blanc a les línies «context», «old» o «new» "
 "al diff"
 
+#: diff.c
 msgid ""
 "do not munge pathnames and use NULs as output field terminators in --raw or "
 "--numstat"
@@ -16134,74 +20556,96 @@
 "no consolidis els noms de camí i utilitza NULs com a terminadors de camp de "
 "sortida en --raw o --numstat"
 
+#: diff.c
 msgid "<prefix>"
 msgstr "<prefix>"
 
+#: diff.c
 msgid "show the given source prefix instead of \"a/\""
 msgstr "mostra el prefix d'origen donat en lloc de «a/»"
 
+#: diff.c
 msgid "show the given destination prefix instead of \"b/\""
 msgstr "mostra el prefix de destinació indicat en lloc de «b/»"
 
+#: diff.c
 msgid "prepend an additional prefix to every line of output"
 msgstr "afegir un prefix addicional per a cada línia de sortida"
 
+#: diff.c
 msgid "do not show any source or destination prefix"
 msgstr "no mostris cap prefix d'origen o destí"
 
+#: diff.c
 msgid "use default prefixes a/ and b/"
 msgstr "utilitza els prefixos per defecte a/ i b/"
 
+#: diff.c
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr ""
 "mostra el context entre trossos de diferència fins al nombre especificat de "
 "línies"
 
+#: diff.c
 msgid "<char>"
-msgstr "<char>"
+msgstr "<caràcter>"
 
+#: diff.c
 msgid "specify the character to indicate a new line instead of '+'"
 msgstr ""
 "especifiqueu el caràcter per a indicar una línia nova en comptes de «+»"
 
+#: diff.c
 msgid "specify the character to indicate an old line instead of '-'"
 msgstr ""
 "especifiqueu el caràcter per a indicar una línia antiga en comptes de «-»"
 
+#: diff.c
 msgid "specify the character to indicate a context instead of ' '"
 msgstr "especifiqueu el caràcter per a indicar context en comptes de « »"
 
+#: diff.c
 msgid "Diff rename options"
 msgstr "Opcions de canvi de nom del diff"
 
+#: diff.c
 msgid "<n>[/<m>]"
 msgstr "<n>[/<m>]"
 
+#: diff.c
 msgid "break complete rewrite changes into pairs of delete and create"
 msgstr ""
 "divideix els canvis de reescriptura completa en parells de suprimir i crear"
 
+#: diff.c
 msgid "detect renames"
 msgstr "detecta els canvis de noms"
 
+#: diff.c
 msgid "omit the preimage for deletes"
 msgstr "omet les preimatges per les supressions"
 
+#: diff.c
 msgid "detect copies"
 msgstr "detecta còpies"
 
+#: diff.c
 msgid "use unmodified files as source to find copies"
 msgstr "usa els fitxers no modificats com a font per a trobar còpies"
 
+#: diff.c
 msgid "disable rename detection"
 msgstr "inhabilita la detecció de canvis de nom"
 
+#: diff.c
 msgid "use empty blobs as rename source"
 msgstr "usa els blobs buits com a font de canvi de nom"
 
+#: diff.c
 msgid "continue listing the history of a file beyond renames"
 msgstr "continua llistant l'històric d'un fitxer més enllà dels canvis de nom"
 
+#: diff.c
 msgid ""
 "prevent rename/copy detection if the number of rename/copy targets exceeds "
 "given limit"
@@ -16209,118 +20653,154 @@
 "evita la detecció de canvi de nom/còpia si el nombre d'objectius de canvi de "
 "nom/còpia supera el límit indicat"
 
+#: diff.c
 msgid "Diff algorithm options"
 msgstr "Opcions de l'algorisme Diff"
 
+#: diff.c
 msgid "produce the smallest possible diff"
 msgstr "produeix el diff més petit possible"
 
+#: diff.c
 msgid "ignore whitespace when comparing lines"
 msgstr "ignora els espais en blanc en comparar línies"
 
+#: diff.c
 msgid "ignore changes in amount of whitespace"
 msgstr "ignora els canvis en la quantitat d'espai en blanc"
 
+#: diff.c
 msgid "ignore changes in whitespace at EOL"
 msgstr "ignora els canvis d'espai en blanc al final de la línia"
 
+#: diff.c
 msgid "ignore carrier-return at the end of line"
 msgstr "ignora els retorns de línia al final de la línia"
 
+#: diff.c
 msgid "ignore changes whose lines are all blank"
 msgstr "ignora els canvis en línies que estan en blanc"
 
+#: diff.c
 msgid "<regex>"
-msgstr "<regex>"
+msgstr "<expr-reg>"
 
+#: diff.c
 msgid "ignore changes whose all lines match <regex>"
-msgstr "ignora els canvis en les línies que coincideixen amb <regex>"
+msgstr "ignora els canvis en les línies que coincideixen amb <expr-reg>"
 
+#: diff.c
 msgid "heuristic to shift diff hunk boundaries for easy reading"
 msgstr ""
 "heurística per a desplaçar els límits del tros de diferència per a una "
 "lectura fàcil"
 
+#: diff.c
 msgid "generate diff using the \"patience diff\" algorithm"
 msgstr "genera diff usant l'algorisme «patience diff»"
 
+#: diff.c
 msgid "generate diff using the \"histogram diff\" algorithm"
 msgstr "genera diff usant l'algorisme «histogram diff»"
 
+#: diff.c
 msgid "<text>"
 msgstr "<text>"
 
+#: diff.c
 msgid "generate diff using the \"anchored diff\" algorithm"
 msgstr "genera diff usant l'algorisme «anchored diff»"
 
+#: diff.c
 msgid "<mode>"
 msgstr "<mode>"
 
+#: diff.c
 msgid "show word diff, using <mode> to delimit changed words"
 msgstr ""
 "mostra el diff de paraules usant <mode> per a delimitar les paraules "
 "modificades"
 
+#: diff.c
 msgid "use <regex> to decide what a word is"
-msgstr "utilitza <regex> per a decidir què és una paraula"
+msgstr "utilitza <expr-reg> per a decidir què és una paraula"
 
+#: diff.c
 msgid "equivalent to --word-diff=color --word-diff-regex=<regex>"
-msgstr "equivalent a --word-diff=color --word-diff-regex=<regex>"
+msgstr "equivalent a --word-diff=color --word-diff-regex=<expr-reg>"
 
+#: diff.c
 msgid "moved lines of code are colored differently"
 msgstr "les línies de codi que s'han mogut s'acoloreixen diferent"
 
+#: diff.c
 msgid "how white spaces are ignored in --color-moved"
 msgstr "com s'ignoren els espais en blanc a --color-moved"
 
+#: diff.c
 msgid "Other diff options"
 msgstr "Altres opcions diff"
 
+#: diff.c
 msgid "when run from subdir, exclude changes outside and show relative paths"
 msgstr ""
 "quan s'executa des d'un subdirectori, exclou els canvis de fora i mostra els "
 "camins relatius"
 
+#: diff.c
 msgid "treat all files as text"
 msgstr "tracta tots els fitxers com a text"
 
+#: diff.c
 msgid "swap two inputs, reverse the diff"
 msgstr "intercanvia les dues entrades, inverteix el diff"
 
+#: diff.c
 msgid "exit with 1 if there were differences, 0 otherwise"
 msgstr "surt amb 1 si hi ha diferències, 0 en cas contrari"
 
+#: diff.c
 msgid "disable all output of the program"
 msgstr "inhabilita totes les sortides del programa"
 
+#: diff.c
 msgid "allow an external diff helper to be executed"
 msgstr "permet executar un ajudant de diff extern"
 
+#: diff.c
 msgid "run external text conversion filters when comparing binary files"
 msgstr ""
 "executa els filtres externs de conversió de text en comparar fitxers binaris"
 
+#: diff.c
 msgid "<when>"
 msgstr "<quan>"
 
+#: diff.c
 msgid "ignore changes to submodules in the diff generation"
 msgstr "ignora els canvis als submòduls en la generació del diff"
 
+#: diff.c
 msgid "<format>"
 msgstr "<format>"
 
+#: diff.c
 msgid "specify how differences in submodules are shown"
 msgstr "especifiqueu com es mostren els canvis als submòduls"
 
+#: diff.c
 msgid "hide 'git add -N' entries from the index"
 msgstr "amaga les entrades «git add -N» de l'índex"
 
+#: diff.c
 msgid "treat 'git add -N' entries as real in the index"
 msgstr "tracta les entrades «git add -N» com a reals a l'índex"
 
+#: diff.c
 msgid "<string>"
 msgstr "<cadena>"
 
+#: diff.c
 msgid ""
 "look for differences that change the number of occurrences of the specified "
 "string"
@@ -16328,6 +20808,7 @@
 "cerca les diferències que canvien el nombre d'ocurrències de la cadena "
 "especificada"
 
+#: diff.c
 msgid ""
 "look for differences that change the number of occurrences of the specified "
 "regex"
@@ -16335,27 +20816,35 @@
 "cerca les diferències que canvien el nombre d'ocurrències de l'expressió "
 "regular especificada"
 
+#: diff.c
 msgid "show all changes in the changeset with -S or -G"
 msgstr "mostra tots els canvis amb el conjunt de canvis amb -S o -G"
 
+#: diff.c
 msgid "treat <string> in -S as extended POSIX regular expression"
 msgstr "tracta <cadena> a -S com a expressió regular POSIX ampliada"
 
+#: diff.c
 msgid "control the order in which files appear in the output"
 msgstr "controla l'ordre amb el qual els fitxers apareixen en la sortida"
 
+#: diff.c
 msgid "<path>"
 msgstr "<camí>"
 
+#: diff.c
 msgid "show the change in the specified path first"
 msgstr "mostra el canvi primer al camí especificat"
 
+#: diff.c
 msgid "skip the output to the specified path"
 msgstr "omet la sortida al camí especificat"
 
+#: diff.c
 msgid "<object-id>"
 msgstr "<id de l'objecte>"
 
+#: diff.c
 msgid ""
 "look for differences that change the number of occurrences of the specified "
 "object"
@@ -16363,26 +20852,33 @@
 "cerca les diferències que canvien el nombre d'ocurrències de l'objecte "
 "especificat"
 
+#: diff.c
 msgid "[(A|C|D|M|R|T|U|X|B)...[*]]"
 msgstr "[(A|C|D|M|R|T|U|X|B)...[*]]"
 
+#: diff.c
 msgid "select files by diff type"
 msgstr "seleccioneu els fitxers per tipus de diff"
 
+#: diff.c
 msgid "<file>"
 msgstr "<fitxer>"
 
+#: diff.c
 msgid "output to a specific file"
 msgstr "sortida a un fitxer específic"
 
+#: diff.c
 msgid "exhaustive rename detection was skipped due to too many files."
 msgstr ""
 "s'ha omès la detecció de canvi de nom exhaustiva perquè hi ha massa fitxers."
 
+#: diff.c
 msgid "only found copies from modified paths due to too many files."
 msgstr ""
 "només s'han trobat còpies des de camins modificats perquè de massa fitxers."
 
+#: diff.c
 #, c-format
 msgid ""
 "you may want to set your %s variable to at least %d and retry the command."
@@ -16390,50 +20886,62 @@
 "potser voleu establir la vostra variable %s a almenys %d i tornar a intentar "
 "l'ordre."
 
+#: diffcore-order.c
 #, c-format
 msgid "failed to read orderfile '%s'"
 msgstr "s'ha produït un error en llegir el fitxer d'ordres «%s»"
 
+#: diffcore-rename.c
 msgid "Performing inexact rename detection"
 msgstr "S'està realitzant una detecció inexacta de canvis de nom"
 
+#: diffcore-rotate.c
 #, c-format
 msgid "No such path '%s' in the diff"
 msgstr "No existeix el camí «%s» al diff"
 
+#: dir.c
 #, c-format
 msgid "pathspec '%s' did not match any file(s) known to git"
 msgstr ""
 "l'especificació de camí «%s» no ha coincidit amb cap fitxer que git conegui"
 
+#: dir.c
 #, c-format
 msgid "unrecognized pattern: '%s'"
 msgstr "patró no reconegut: «%s»"
 
+#: dir.c
 #, c-format
 msgid "unrecognized negative pattern: '%s'"
 msgstr "patró negatiu no reconegut: «%s»"
 
+#: dir.c
 #, c-format
 msgid "your sparse-checkout file may have issues: pattern '%s' is repeated"
 msgstr ""
 "el vostre fitxer «sparse-checkout» pot tenir problemes el patró «%s» es "
 "repeteix"
 
+#: dir.c
 msgid "disabling cone pattern matching"
 msgstr "inhabilita la coincidència de patrons «cone»"
 
+#: dir.c
 #, c-format
 msgid "cannot use %s as an exclude file"
 msgstr "no es pot usar %s com a fitxer d'exclusió"
 
+#: dir.c
 msgid "failed to get kernel name and information"
 msgstr "s'ha produït un error en obtenir el nombre i la informació del nucli"
 
+#: dir.c
 msgid "untracked cache is disabled on this system or location"
 msgstr ""
 "la memòria cau no seguida està inhabilitada en aquest sistema o ubicació"
 
+#: dir.c
 msgid ""
 "No directory name could be guessed.\n"
 "Please specify a directory on the command line"
@@ -16441,191 +20949,243 @@
 "No s'ha pogut deduir cap nom de directori.\n"
 "Especifiqueu un directori en la línia d'ordres"
 
+#: dir.c
 #, c-format
 msgid "index file corrupt in repo %s"
 msgstr "el fitxer d'índex al repositori %s és malmès"
 
+#: dir.c
 #, c-format
 msgid "could not create directories for %s"
 msgstr "no s'han pogut crear directoris per %s"
 
+#: dir.c
 #, c-format
 msgid "could not migrate git directory from '%s' to '%s'"
 msgstr "no s'ha pogut migrar el directori de «%s» a «%s»"
 
+#: editor.c
 #, c-format
 msgid "hint: Waiting for your editor to close the file...%c"
 msgstr "consell: s'està esperant que el vostre editor tanqui el fitxer...%c"
 
+#: editor.c sequencer.c wrapper.c
 #, c-format
 msgid "could not write to '%s'"
 msgstr "no s'ha pogut escriure a «%s»"
 
+#: editor.c
 #, c-format
 msgid "could not edit '%s'"
 msgstr "no s'ha pogut editar «%s»"
 
+#: entry.c
 msgid "Filtering content"
 msgstr "S'està filtrant el contingut"
 
+#: entry.c
 #, c-format
 msgid "could not stat file '%s'"
 msgstr "no s'ha pogut fer «stat» sobre el fitxer «%s»"
 
+#: environment.c
 #, c-format
 msgid "bad git namespace path \"%s\""
 msgstr "camí d'espai de noms git incorrecte «%s»"
 
+#: exec-cmd.c
 #, c-format
 msgid "too many args to run %s"
 msgstr "hi ha massa arguments per a executar %s"
 
+#: fetch-pack.c
 msgid "git fetch-pack: expected shallow list"
 msgstr "git fetch-pack: llista shallow esperada"
 
+#: fetch-pack.c
 msgid "git fetch-pack: expected a flush packet after shallow list"
 msgstr ""
 "git fetch-pack: s'esperava un paquet de buidatge després d'una llista shallow"
 
+#: fetch-pack.c
 msgid "git fetch-pack: expected ACK/NAK, got a flush packet"
 msgstr "git fetch-pack: s'esperava ACK/NAK, s'ha rebut un paquet de buidatge"
 
+#: fetch-pack.c
 #, c-format
 msgid "git fetch-pack: expected ACK/NAK, got '%s'"
 msgstr "git fetch-pack: s'esperava ACK/NAK, s'ha rebut «%s»"
 
+#: fetch-pack.c
 msgid "unable to write to remote"
 msgstr "no s'ha pogut escriure al remot"
 
+#: fetch-pack.c
 msgid "Server supports filter"
 msgstr "El servidor accepta filtratge"
 
+#: fetch-pack.c
 #, c-format
 msgid "invalid shallow line: %s"
 msgstr "línia de shallow no vàlida: %s"
 
+#: fetch-pack.c
 #, c-format
 msgid "invalid unshallow line: %s"
 msgstr "línia d'unshallow no vàlida: %s"
 
+#: fetch-pack.c
 #, c-format
 msgid "object not found: %s"
 msgstr "objecte no trobat: %s"
 
+#: fetch-pack.c
 #, c-format
 msgid "error in object: %s"
 msgstr "error en objecte: %s"
 
+#: fetch-pack.c
 #, c-format
 msgid "no shallow found: %s"
 msgstr "no s'ha trobat cap shallow: %s"
 
+#: fetch-pack.c
 #, c-format
 msgid "expected shallow/unshallow, got %s"
 msgstr "s'esperava shallow/unshallow, s'ha rebut %s"
 
+#: fetch-pack.c
 #, c-format
 msgid "got %s %d %s"
 msgstr "s'ha rebut %s %d %s"
 
+#: fetch-pack.c
 #, c-format
 msgid "invalid commit %s"
 msgstr "comissió no vàlida %s"
 
+#: fetch-pack.c
 msgid "giving up"
 msgstr "s'abandona"
 
+#: fetch-pack.c progress.h
 msgid "done"
 msgstr "fet"
 
+#: fetch-pack.c
 #, c-format
 msgid "got %s (%d) %s"
 msgstr "s'ha rebut %s (%d) %s"
 
+#: fetch-pack.c
 #, c-format
 msgid "Marking %s as complete"
 msgstr "S'està marcant %s com a complet"
 
+#: fetch-pack.c
 #, c-format
 msgid "already have %s (%s)"
 msgstr "ja es té %s (%s)"
 
+#: fetch-pack.c
 msgid "fetch-pack: unable to fork off sideband demultiplexer"
 msgstr "fetch-pack: no s'ha pogut bifurcar del desmultiplexor de banda lateral"
 
+#: fetch-pack.c
 msgid "protocol error: bad pack header"
 msgstr "error de protocol: capçalera de paquet errònia"
 
+#: fetch-pack.c
 #, c-format
 msgid "fetch-pack: unable to fork off %s"
 msgstr "fetch-pack: no es pot bifurcar de %s"
 
+#: fetch-pack.c
 msgid "fetch-pack: invalid index-pack output"
 msgstr "fetch-pack: sortida d'index-pack no vàlida"
 
+#: fetch-pack.c
 #, c-format
 msgid "%s failed"
 msgstr "%s ha fallat"
 
+#: fetch-pack.c
 msgid "error in sideband demultiplexer"
 msgstr "error en desmultiplexor de banda lateral"
 
+#: fetch-pack.c
 #, c-format
 msgid "Server version is %.*s"
 msgstr "La versió del servidor és %.*s"
 
+#: fetch-pack.c
 #, c-format
 msgid "Server supports %s"
 msgstr "El servidor accepta %s"
 
+#: fetch-pack.c
 msgid "Server does not support shallow clients"
 msgstr "El servidor no permet clients superficials"
 
+#: fetch-pack.c
 msgid "Server does not support --shallow-since"
 msgstr "El servidor no admet --shallow-since"
 
+#: fetch-pack.c
 msgid "Server does not support --shallow-exclude"
 msgstr "El servidor no admet --shallow-exclude"
 
+#: fetch-pack.c
 msgid "Server does not support --deepen"
 msgstr "El servidor no admet --deepen"
 
+#: fetch-pack.c
 msgid "Server does not support this repository's object format"
 msgstr ""
 "El servidor no és compatible amb el format d'objecte d'aquest repositori"
 
+#: fetch-pack.c
 msgid "no common commits"
 msgstr "cap comissió en comú"
 
+#: fetch-pack.c
 msgid "git fetch-pack: fetch failed."
 msgstr "git fetch-pack: l'obtenció ha fallat."
 
+#: fetch-pack.c
 #, c-format
 msgid "mismatched algorithms: client %s; server %s"
 msgstr "algoritmes no coincidents: client %s; servidor %s"
 
+#: fetch-pack.c
 #, c-format
 msgid "the server does not support algorithm '%s'"
 msgstr "el servidor no és compatible amb l'algorisme «%s»"
 
+#: fetch-pack.c
 msgid "Server does not support shallow requests"
 msgstr "El servidor no permet sol·licituds superficials"
 
+#: fetch-pack.c
 msgid "unable to write request to remote"
 msgstr "no s'ha pogut escriure la sol·licitud al remot"
 
+#: fetch-pack.c
 #, c-format
 msgid "expected '%s', received '%s'"
 msgstr "s'esperava «%s», s'ha rebut «%s»"
 
+#: fetch-pack.c
 #, c-format
 msgid "expected '%s'"
 msgstr "s'esperava «%s»"
 
+#: fetch-pack.c
 #, c-format
 msgid "unexpected acknowledgment line: '%s'"
 msgstr "línia de confirmació inesperada: «%s»"
 
+#: fetch-pack.c
 #, c-format
 msgid "error processing acks: %d"
 msgstr "s'ha produït un error en processar els acks: %d"
@@ -16633,6 +21193,7 @@
 #. TRANSLATORS: The parameter will be 'ready', a protocol
 #. keyword.
 #.
+#: fetch-pack.c
 #, c-format
 msgid "expected packfile to be sent after '%s'"
 msgstr "s'esperava que el fitxer de paquet s'enviés després de «%s»"
@@ -16640,74 +21201,93 @@
 #. TRANSLATORS: The parameter will be 'ready', a protocol
 #. keyword.
 #.
+#: fetch-pack.c
 #, c-format
 msgid "expected no other sections to be sent after no '%s'"
 msgstr "no s'esperava que cap altra secció s'enviés després de «%s»"
 
+#: fetch-pack.c
 #, c-format
 msgid "error processing shallow info: %d"
 msgstr "s'ha produït un error en processar la informació superficial: %d"
 
+#: fetch-pack.c
 #, c-format
 msgid "expected wanted-ref, got '%s'"
 msgstr "s'esperava wanted-ref, s'ha rebut «%s»"
 
+#: fetch-pack.c
 #, c-format
 msgid "unexpected wanted-ref: '%s'"
 msgstr "wanted-ref inesperat: «%s»"
 
+#: fetch-pack.c
 #, c-format
 msgid "error processing wanted refs: %d"
 msgstr "s'ha produït un error en processar les referències desitjades: %d"
 
+#: fetch-pack.c
 msgid "git fetch-pack: expected response end packet"
 msgstr "git fetch-pack: s'esperava un paquet de final de resposta"
 
+#: fetch-pack.c
 msgid "no matching remote head"
 msgstr "no hi ha cap HEAD remot coincident"
 
+#: fetch-pack.c
 msgid "unexpected 'ready' from remote"
 msgstr "«ready» no esperat des del remot"
 
+#: fetch-pack.c
 #, c-format
 msgid "no such remote ref %s"
 msgstr "no existeix la referència remota %s"
 
+#: fetch-pack.c
 #, c-format
 msgid "Server does not allow request for unadvertised object %s"
 msgstr "El servidor no permet sol·licitar objectes no anunciats %s"
 
+#: fsmonitor-ipc.c
 #, c-format
 msgid "fsmonitor_ipc__send_query: invalid path '%s'"
 msgstr "fsmonitor_ipc__send_query: camí no vàlid «%s»"
 
+#: fsmonitor-ipc.c
 #, c-format
 msgid "fsmonitor_ipc__send_query: unspecified error on '%s'"
 msgstr "fsmonitor_ipc__send_query: error no especificat en «%s»"
 
+#: fsmonitor-ipc.c
 msgid "fsmonitor--daemon is not running"
 msgstr "fsmonitor--daemon no s'està executant"
 
+#: fsmonitor-ipc.c
 #, c-format
 msgid "could not send '%s' command to fsmonitor--daemon"
 msgstr "no s'ha pogut enviar l'ordre «%s» a fsmonitor--daemon"
 
+#: fsmonitor-settings.c
 #, c-format
 msgid "bare repository '%s' is incompatible with fsmonitor"
 msgstr "el repositori nu «%s» és incompatible amb fsmonitor"
 
+#: fsmonitor-settings.c
 #, c-format
 msgid "repository '%s' is incompatible with fsmonitor due to errors"
 msgstr "el repositori «%s» és incompatible amb fsmonitor a causa d'errors"
 
+#: fsmonitor-settings.c
 #, c-format
 msgid "remote repository '%s' is incompatible with fsmonitor"
 msgstr "el repositori remot «%s» no és compatible amb fsmonitor"
 
+#: fsmonitor-settings.c
 #, c-format
 msgid "virtual repository '%s' is incompatible with fsmonitor"
 msgstr "el repositori virtual «%s» és incompatible amb fsmonitor"
 
+#: fsmonitor-settings.c
 #, c-format
 msgid ""
 "socket directory '%s' is incompatible with fsmonitor due to lack of Unix "
@@ -16716,21 +21296,27 @@
 "el directori del sòcol «%s» és incompatible amb fsmonitor a causa de la "
 "manca de compatibilitat amb els sòcols Unix"
 
+#: git.c
 msgid ""
 "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
 "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
-"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
-"bare]\n"
-"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--config-env=<name>=<envvar>] <command> [<args>]"
+"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+"           [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n"
+"           [--work-tree=<path>] [--namespace=<name>] [--config-"
+"env=<name>=<envvar>]\n"
+"           <command> [<args>]"
 msgstr ""
-"git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
-"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
-"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
-"bare]\n"
-"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--config-env=<name>=<envvar>] <command> [<args>]"
+"git [-v | --version] [-h | --help] [-C <camí>] [-c <nom>=<valor>]\n"
+"           [--exec-path[=<camí>]] [--html-path] [--man-path] [--info-path]\n"
+"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-"
+"lazy-fetch]\n"
+"           [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<camí>]\n"
+"           [--work-tree=<camí>] [--namespace=<nom>] [--config-"
+"env=<nom>=<variable-d-entorn>]\n"
+"           <ordre> [<arguments>]"
 
+#: git.c
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
 "concept guides. See 'git help <command>' or 'git help <concept>'\n"
@@ -16742,38 +21328,47 @@
 "«git help <concepte>» per a llegir sobre una subordre o concepte\n"
 "específic. Vegeu «git help git» per a una visió general del sistema."
 
+#: git.c help.c
 #, c-format
 msgid "unsupported command listing type '%s'"
 msgstr "tipus de llistat de l'ordre no compatible «%s»"
 
+#: git.c
 #, c-format
 msgid "no directory given for '%s' option\n"
 msgstr "no s'ha especificat un directori per a l'opció «%s»\n"
 
+#: git.c
 #, c-format
 msgid "no namespace given for --namespace\n"
 msgstr "no s'ha especificat un nom d'espai per --namespace\n"
 
+#: git.c
 #, c-format
 msgid "-c expects a configuration string\n"
 msgstr "-c espera una cadena de configuració\n"
 
+#: git.c
 #, c-format
 msgid "no config key given for --config-env\n"
 msgstr "no s'ha indicat cap clau de configuració per a --config-env\n"
 
+#: git.c
 #, c-format
 msgid "no attribute source given for --attr-source\n"
 msgstr "no s'ha donat d'atribut font per a --attr-source\n"
 
+#: git.c
 #, c-format
 msgid "unknown option: %s\n"
 msgstr "opció desconeguda: %s\n"
 
+#: git.c
 #, c-format
 msgid "while expanding alias '%s': '%s'"
 msgstr "en expandir l'àlies «%s»: «%s»"
 
+#: git.c
 #, c-format
 msgid ""
 "alias '%s' changes environment variables.\n"
@@ -16782,31 +21377,39 @@
 "l'àlies «%s» canvia variables d'entorn.\n"
 "Podeu utilitzar «!git» a l'àlies per a fer-ho"
 
+#: git.c
 #, c-format
 msgid "empty alias for %s"
 msgstr "àlies buit per a %s"
 
+#: git.c
 #, c-format
 msgid "recursive alias: %s"
 msgstr "àlies recursiu: %s"
 
+#: git.c
 msgid "write failure on standard output"
 msgstr "fallada d'escriptura en la sortida estàndard"
 
+#: git.c
 msgid "unknown write failure on standard output"
 msgstr "fallada d'escriptura desconeguda en la sortida estàndard"
 
+#: git.c
 msgid "close failed on standard output"
 msgstr "ha fallat el tancament en la sortida estàndard"
 
+#: git.c
 #, c-format
 msgid "alias loop detected: expansion of '%s' does not terminate:%s"
 msgstr "bucle d'àlies detectat expansió de «%s» no acaba:%s"
 
+#: git.c
 #, c-format
 msgid "cannot handle %s as a builtin"
 msgstr "no es pot gestionar %s com a integrat"
 
+#: git.c
 #, c-format
 msgid ""
 "usage: %s\n"
@@ -16815,21 +21418,26 @@
 "ús: %s\n"
 "\n"
 
+#: git.c
 #, c-format
 msgid "expansion of alias '%s' failed; '%s' is not a git command\n"
 msgstr "ha fallat l'expansió de l'àlies «%s»; «%s» no és una ordre git\n"
 
+#: git.c
 #, c-format
 msgid "failed to run command '%s': %s\n"
 msgstr "s'ha produït un error en executar l'ordre «%s»: %s\n"
 
+#: gpg-interface.c
 msgid "could not create temporary file"
 msgstr "no s'ha pogut crear el fitxer temporal"
 
+#: gpg-interface.c
 #, c-format
 msgid "failed writing detached signature to '%s'"
 msgstr "s'ha produït un error en escriure la clau de signatura separada a «%s»"
 
+#: gpg-interface.c
 msgid ""
 "gpg.ssh.allowedSignersFile needs to be configured and exist for ssh "
 "signature verification"
@@ -16837,6 +21445,7 @@
 "gpg.ssh.allowedSignersFile s'ha de configurar i existeix per a la "
 "verificació de la signatura ssh"
 
+#: gpg-interface.c
 msgid ""
 "ssh-keygen -Y find-principals/verify is needed for ssh signature "
 "verification (available in openssh version 8.2p1+)"
@@ -16844,32 +21453,39 @@
 "ssh-keygen -Y find-principals/verify és necessari per a la verificació de la "
 "signatura ssh (disponible a opensh versió 8.2p1+)"
 
+#: gpg-interface.c
 #, c-format
 msgid "ssh signing revocation file configured but not found: %s"
 msgstr "fitxer de revocació de la signatura ssh configurat però no trobat: %s"
 
+#: gpg-interface.c
 #, c-format
 msgid "bad/incompatible signature '%s'"
 msgstr "la signatura «%s» és incompatible o està malmesa"
 
+#: gpg-interface.c
 #, c-format
 msgid "failed to get the ssh fingerprint for key '%s'"
 msgstr "no s'ha pogut obtenir l'empremta ssh de la clau  «%s»"
 
+#: gpg-interface.c
 msgid ""
 "either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured"
 msgstr ""
 "o bé user.signingkey o gpg.ssh.defaultKeyCommand han de ser configurats"
 
+#: gpg-interface.c
 #, c-format
 msgid "gpg.ssh.defaultKeyCommand succeeded but returned no keys: %s %s"
 msgstr ""
 "gpg.ssh.defaultKeyCommand ha tingut èxit però no ha retornat cap clau: %s %s"
 
+#: gpg-interface.c
 #, c-format
 msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
 msgstr "gpg.ssh.defaultKeyCommand ha fallat: %s %s"
 
+#: gpg-interface.c
 #, c-format
 msgid ""
 "gpg failed to sign the data:\n"
@@ -16878,17 +21494,21 @@
 "gpg ha fallat en signar les dades:\n"
 "%s"
 
+#: gpg-interface.c
 msgid "user.signingKey needs to be set for ssh signing"
 msgstr "user.signingKey s'ha d'establir per a signar amb ssh"
 
+#: gpg-interface.c
 #, c-format
 msgid "failed writing ssh signing key to '%s'"
 msgstr "s'ha produït un error en escriure la clau de signatura ssh a «%s»"
 
+#: gpg-interface.c
 #, c-format
 msgid "failed writing ssh signing key buffer to '%s'"
 msgstr "s'ha produït un error en escriure la clau de signatura ssh a «%s»"
 
+#: gpg-interface.c
 msgid ""
 "ssh-keygen -Y sign is needed for ssh signing (available in openssh version "
 "8.2p1+)"
@@ -16896,102 +21516,132 @@
 "ssh-keygen -Y sign és necessari per a signar amb ssh (disponible a openssh "
 "versió 8.2p1+)"
 
+#: gpg-interface.c
 #, c-format
 msgid "failed reading ssh signing data buffer from '%s'"
 msgstr "s'ha produït un error en llegir la signatura ssh des de «%s»"
 
+#: graph.c
 #, c-format
 msgid "ignored invalid color '%.*s' in log.graphColors"
 msgstr "ignora el color no vàlid «%.*s» a log.graphColors"
 
+#: grep.c
 msgid ""
 "given pattern contains NULL byte (via -f <file>). This is only supported "
 "with -P under PCRE v2"
 msgstr ""
-"el patró indicat conté byte NULL (via -f <fitxer>). Això només és compatible "
-"amb -P sota PCRE v2"
+"el patró indicat conté l'octet NULL (via -f <fitxer>). Això només és "
+"compatible amb -P sota PCRE v2"
 
+#: grep.c
 #, c-format
 msgid "'%s': unable to read %s"
 msgstr "«%s»: no s'ha pogut llegir %s"
 
+#: grep.c
 #, c-format
 msgid "'%s': short read"
 msgstr "«%s»: lectura curta"
 
+#: help.c
 msgid "start a working area (see also: git help tutorial)"
 msgstr "començar una àrea de treball (vegeu també: git help tutorial)"
 
+#: help.c
 msgid "work on the current change (see also: git help everyday)"
 msgstr "treballar en el canvi actual (vegeu també: git help everyday)"
 
+#: help.c
 msgid "examine the history and state (see also: git help revisions)"
 msgstr "examinar la història i l'estat (vegeu també: git help revisions)"
 
+#: help.c
 msgid "grow, mark and tweak your common history"
 msgstr "fer créixer, marcar i ajustar la vostra història comuna"
 
+#: help.c
 msgid "collaborate (see also: git help workflows)"
 msgstr "col·laborar (vegeu també: git help workflow)"
 
+#: help.c
 msgid "Main Porcelain Commands"
 msgstr "Ordres principals de porcellana"
 
+#: help.c
 msgid "Ancillary Commands / Manipulators"
 msgstr "Ordres auxiliars / manipuladors"
 
+#: help.c
 msgid "Ancillary Commands / Interrogators"
 msgstr "Ordres auxiliars / interrogadors"
 
+#: help.c
 msgid "Interacting with Others"
 msgstr "Interaccionar amb altres"
 
+#: help.c
 msgid "Low-level Commands / Manipulators"
 msgstr "Ordres de baix nivell / Manipuladors"
 
+#: help.c
 msgid "Low-level Commands / Interrogators"
 msgstr "Ordres de baix nivell / Interrogadors"
 
+#: help.c
 msgid "Low-level Commands / Syncing Repositories"
 msgstr "Ordres de baix nivell / Sincronització de repositoris"
 
+#: help.c
 msgid "Low-level Commands / Internal Helpers"
 msgstr "Ordres de baix nivell / Ajudants interns"
 
+#: help.c
 msgid "User-facing repository, command and file interfaces"
 msgstr "Repositori, ordre i interfície de fitxers que veu l'usuari"
 
+#: help.c
 msgid "Developer-facing file formats, protocols and other interfaces"
-msgstr "Formats de fitxers, protocols i interfícies que veu el desenvolupador"
+msgstr "Formats de fitxer, protocols i interfícies que veu el desenvolupador"
 
+#: help.c
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "ordres de git disponibles en «%s»"
 
+#: help.c
 msgid "git commands available from elsewhere on your $PATH"
 msgstr "ordres de git disponibles d'altres llocs en el vostre $PATH"
 
+#: help.c
 msgid "These are common Git commands used in various situations:"
 msgstr "Aquestes són ordres habituals del Git usades en diverses situacions:"
 
+#: help.c
 msgid "The Git concept guides are:"
 msgstr "Les guies de Git de conceptes són:"
 
+#: help.c
 msgid "User-facing repository, command and file interfaces:"
 msgstr "Repositori, ordre i interfície de fitxers que veu l'usuari:"
 
+#: help.c
 msgid "File formats, protocols and other developer interfaces:"
 msgstr "Formats de fitxer, protocols i altres interfícies de desenvolupador:"
 
+#: help.c
 msgid "External commands"
 msgstr "Ordres externes"
 
+#: help.c
 msgid "Command aliases"
 msgstr "Àlies d'ordres"
 
+#: help.c
 msgid "See 'git help <command>' to read about a specific subcommand"
 msgstr "Vegeu «git help <ordre>» per a llegir sobre una subordre específica"
 
+#: help.c
 #, c-format
 msgid ""
 "'%s' appears to be a git command, but we were not\n"
@@ -17000,31 +21650,38 @@
 "«%s» sembla una ordre de git, però no hem pogut\n"
 "executar-la. Pot ser que git-%s estigui malmès?"
 
+#: help.c
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
 msgstr "git: «%s» no és una ordre de git. Vegeu «git --help»."
 
+#: help.c
 msgid "Uh oh. Your system reports no Git commands at all."
 msgstr "Ai. El vostre sistema no informa de cap ordre de Git."
 
+#: help.c
 #, c-format
 msgid "WARNING: You called a Git command named '%s', which does not exist."
 msgstr ""
 "ADVERTÈNCIA: Heu invocat una ordre de Git amb nom «%s», la qual no existeix."
 
+#: help.c
 #, c-format
 msgid "Continuing under the assumption that you meant '%s'."
 msgstr "El procés continuarà, pressuposant que volíeu dir «%s»."
 
+#: help.c
 #, c-format
 msgid "Run '%s' instead [y/N]? "
 msgstr "Voleu executar «%s» en el seu lloc? [y/N]? "
 
+#: help.c
 #, c-format
 msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
 msgstr ""
 "El procés continuarà en %0.1f segons, pressuposant que volíeu dir «%s»."
 
+#: help.c
 msgid ""
 "\n"
 "The most similar command is"
@@ -17038,13 +21695,16 @@
 "\n"
 "Les ordres més similars són"
 
+#: help.c
 msgid "git version [--build-options]"
 msgstr "git version [--build-options]"
 
+#: help.c
 #, c-format
 msgid "%s: %s - %s"
 msgstr "%s: %s - %s"
 
+#: help.c
 msgid ""
 "\n"
 "Did you mean this?"
@@ -17058,6 +21718,7 @@
 "\n"
 "Volíeu dir un d'aquests?"
 
+#: hook.c
 #, c-format
 msgid ""
 "The '%s' hook was ignored because it's not set as executable.\n"
@@ -17066,40 +21727,62 @@
 "El lligam «%s» s'ha ignorat perquè no s'ha establert com a executable.\n"
 "Podeu desactivar aquest avís amb «git config advice.ignoredHook false»."
 
+#: http-fetch.c
+msgid "not a git repository"
+msgstr "no és un repositori de git"
+
+#: http-fetch.c
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
 msgstr "l'argument a --packfile ha de ser un resum vàlid (s'ha obtingut «%s»)"
 
-msgid "not a git repository"
-msgstr "no és un repositori de git"
-
+#: http.c
 #, c-format
 msgid "negative value for http.postBuffer; defaulting to %d"
 msgstr "valor negatiu per http.postBuffer; utilitzant el valor %d"
 
+#: http.c
 msgid "Delegation control is not supported with cURL < 7.22.0"
 msgstr "No s'admet el control de delegació amb el cURL < 7.22.0"
 
+#: http.c
 msgid "Public key pinning not supported with cURL < 7.39.0"
 msgstr "No s'admet la fixació de clau pública amb cURL < 7.39.0"
 
+#: http.c
+msgid "Unknown value for http.proactiveauth"
+msgstr "Valor desconegut de http.proactiveauth"
+
+#: http.c
 msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
 msgstr "CURLSSLOPT_NO_REVOKE no està admès amb cURL < 7.44.0"
 
+#: http.c
 #, c-format
 msgid "Unsupported SSL backend '%s'. Supported SSL backends:"
 msgstr "El rerefons SSL «%s» no està admès. Els rerefons SSL admesos:"
 
+#: http.c
 #, c-format
 msgid "Could not set SSL backend to '%s': cURL was built without SSL backends"
 msgstr ""
 "No s'ha pogut establir el rerefons SSL a «%s»: cURL es va construir sense "
 "rerefons SSL"
 
+#: http.c
 #, c-format
 msgid "Could not set SSL backend to '%s': already set"
 msgstr "No s'ha pogut establir el rerefons SSL a «%s»: ja establert"
 
+#: http.c
+msgid "refusing to read cookies from http.cookiefile '-'"
+msgstr "res'ha rebutjat llegir galetes del http.cookiefile «-»"
+
+#: http.c
+msgid "ignoring http.savecookies for empty http.cookiefile"
+msgstr "s'està ignorant http.savecookies per al http.cookiefile buit"
+
+#: http.c
 #, c-format
 msgid ""
 "unable to update url base from redirection:\n"
@@ -17110,12 +21793,15 @@
 "  petició: %s\n"
 "   redirecció: %s"
 
+#: ident.c
 msgid "Author identity unknown\n"
 msgstr "Identitat de l'autor desconeguda\n"
 
+#: ident.c
 msgid "Committer identity unknown\n"
 msgstr "Es desconeix la identitat del comitent\n"
 
+#: ident.c
 msgid ""
 "\n"
 "*** Please tell me who you are.\n"
@@ -17140,88 +21826,110 @@
 "per a establir la identitat predeterminada del vostre compte.\n"
 "Ometeu --global per a establir la identitat només en aquest repositori.\n"
 
+#: ident.c
 msgid "no email was given and auto-detection is disabled"
 msgstr ""
 "no s'ha proporcionat cap adreça electrònica i la detecció automàtica està "
 "inhabilitada"
 
+#: ident.c
 #, c-format
 msgid "unable to auto-detect email address (got '%s')"
 msgstr ""
 "no s'ha pogut detectar automàticament una adreça electrònica vàlida (s'ha "
 "rebut «%s»)"
 
+#: ident.c
 msgid "no name was given and auto-detection is disabled"
 msgstr ""
 "no s'ha proporcionat cap nom i la detecció automàtica està inhabilitada"
 
+#: ident.c
 #, c-format
 msgid "unable to auto-detect name (got '%s')"
 msgstr "no s'ha pogut detectar automàticament el nom (s'ha rebut «%s»)"
 
+#: ident.c
 #, c-format
 msgid "empty ident name (for <%s>) not allowed"
 msgstr "nom d'identitat buit (per <%s>) no és permès"
 
+#: ident.c
 #, c-format
 msgid "name consists only of disallowed characters: %s"
 msgstr "el nom conté només caràcters no permesos: %s"
 
+#: list-objects-filter-options.c
 msgid "expected 'tree:<depth>'"
 msgstr "s'esperava «tree:<profunditat>»"
 
+#: list-objects-filter-options.c
 msgid "sparse:path filters support has been dropped"
 msgstr "sparse: s'ha eliminat la implementació de filtres de camí sparse"
 
+#: list-objects-filter-options.c
 #, c-format
 msgid "'%s' for 'object:type=<type>' is not a valid object type"
 msgstr "«%s» per a «object:type=<tipus>» no és un tipus d'objecte vàlid"
 
+#: list-objects-filter-options.c
 #, c-format
 msgid "invalid filter-spec '%s'"
 msgstr "filtre d'especificació no vàlid: «%s»"
 
+#: list-objects-filter-options.c
 #, c-format
 msgid "must escape char in sub-filter-spec: '%c'"
 msgstr "cal escapar el caràcter en el sub-filter-spec «%c»"
 
+#: list-objects-filter-options.c
 msgid "expected something after combine:"
 msgstr "s'esperava alguna cosa després de combinar:"
 
+#: list-objects-filter-options.c
 msgid "multiple filter-specs cannot be combined"
 msgstr "no es poden combinar múltiples especificacions de filtratge"
 
+#: list-objects-filter-options.c
 msgid "unable to upgrade repository format to support partial clone"
 msgstr ""
 "no s'ha pogut actualitzar el format del repositori perquè sigui compatible "
 "amb un clonatge parcial"
 
+#: list-objects-filter-options.h
 msgid "args"
 msgstr "arguments"
 
+#: list-objects-filter-options.h
 msgid "object filtering"
 msgstr "filtratge d'objecte"
 
+#: list-objects-filter.c
 #, c-format
 msgid "unable to access sparse blob in '%s'"
 msgstr "no s'ha pogut accedir a un blob dispers en «%s»"
 
+#: list-objects-filter.c
 #, c-format
 msgid "unable to parse sparse filter data in %s"
 msgstr "no s'han pogut analitzar les dades disperses filtrades %s"
 
+#: list-objects.c
 #, c-format
 msgid "entry '%s' in tree %s has tree mode, but is not a tree"
 msgstr "l'entrada «%s» a l'arbre %s té mode d'arbre, però no és un arbre"
 
+#: list-objects.c
 #, c-format
 msgid "entry '%s' in tree %s has blob mode, but is not a blob"
 msgstr "l'entrada «%s» a l'arbre %s té mode blob, però no és un blob"
 
+#: list-objects.c
 #, c-format
 msgid "unable to load root tree for commit %s"
 msgstr "no s'ha pogut carregar l'arrel de l'arbre per la comissió %s"
 
+#: lockfile.c
 #, c-format
 msgid ""
 "Unable to create '%s.lock': %s.\n"
@@ -17241,46 +21949,82 @@
 "ha fallat en aquest repositori abans:\n"
 "elimineu el fitxer manualment per a continuar."
 
+#: lockfile.c
 #, c-format
 msgid "Unable to create '%s.lock': %s"
 msgstr "No s'ha pogut crear «%s.lock»: %s"
 
+#: log-tree.c
+msgid "unable to create temporary object directory"
+msgstr "no s'ha pogut crear el directori temporal de l'objecte"
+
+#: loose.c
+#, c-format
+msgid "could not write loose object index %s"
+msgstr "no s'ha pogut escriure l'índex d'objecte solt %s"
+
+#: loose.c
+#, c-format
+msgid "failed to write loose object index %s"
+msgstr "no s'ha pogut escriure l'índex d'objectes solts %s"
+
+#: ls-refs.c
 #, c-format
 msgid "unexpected line: '%s'"
 msgstr "línia inesperada: «%s»"
 
+#: ls-refs.c
 msgid "expected flush after ls-refs arguments"
 msgstr "s'esperava una neteja després dels arguments ls-refs"
 
+#: mailinfo.c
 msgid "quoted CRLF detected"
 msgstr "CRLF entre cometes detectat"
 
+#: mem-pool.c strbuf.c wrapper.c
+#, c-format
+msgid "unable to format message: %s"
+msgstr "no es pot formatar el missatge: %s"
+
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "S'ha produït un error en fusionar el submòdul %s (no està agafat)"
 
+#: merge-ort.c
 #, c-format
 msgid "Failed to merge submodule %s (no merge base)"
 msgstr "S'ha produït un error en fusionar el submòdul %s (no hi ha fusió base)"
 
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
 msgstr "S'ha produït un error en fusionar el submòdul %s (no hi ha comissions)"
 
+# corrupt → malmès OK per a repositori?
+#: merge-ort.c
+#, c-format
+msgid "error: failed to merge submodule %s (repository corrupt)"
+msgstr "error: no s'ha pogut fusionar el submòdul %s (repositori malmès)"
+
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (commits don't follow merge-base)"
 msgstr ""
 "S'ha produït un error en fusionar el submòdul %s (les comissions no "
 "segueixen merge-base)"
 
+#: merge-ort.c
 #, c-format
 msgid "Note: Fast-forwarding submodule %s to %s"
 msgstr "Nota: avançament ràpid del submòdul %s a %s"
 
+#: merge-ort.c
 #, c-format
 msgid "Failed to merge submodule %s"
 msgstr "S'ha produït un error en fusionar el submòdul «%s»"
 
+#: merge-ort.c
 #, c-format
 msgid ""
 "Failed to merge submodule %s, but a possible merge resolution exists: %s"
@@ -17288,6 +22032,7 @@
 "S'ha produït un error en fusionar el submòdul %s, però existeix una solució "
 "possible: %s"
 
+#: merge-ort.c
 #, c-format
 msgid ""
 "Failed to merge submodule %s, but multiple possible merges exist:\n"
@@ -17297,17 +22042,22 @@
 "solucions possibles:\n"
 "%s"
 
-msgid "failed to execute internal merge"
-msgstr "no s'ha pogut executar la fusió interna"
-
+#: merge-ort.c
 #, c-format
-msgid "unable to add %s to database"
-msgstr "no s'ha pogut afegir %s a la base de dades"
+msgid "error: failed to execute internal merge for %s"
+msgstr "no s'ha pogut executar la fusió interna per a %s"
 
+#: merge-ort.c
+#, c-format
+msgid "error: unable to add %s to database"
+msgstr "error: no es pot afegir %s a la base de dades"
+
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid "Auto-merging %s"
 msgstr "S'està autofusionant %s"
 
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (implicit dir rename): Existing file/dir at %s in the way of "
@@ -17317,6 +22067,7 @@
 "existent a %s en forma de canvi del nom del directori implícit, posant-hi "
 "els camins següents a: %s."
 
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (implicit dir rename): Cannot map more than one path to %s; "
@@ -17326,6 +22077,7 @@
 "camí a %s; els canvis del nom del directori implícits han intentat posar "
 "aquests camins a: %s segons"
 
+#: merge-ort.c
 #, c-format
 msgid ""
 "CONFLICT (directory rename split): Unclear where to rename %s to; it was "
@@ -17336,6 +22088,7 @@
 "%s; s'han canviat de nom a múltiples altres directoris, sense una destinació "
 "per a la majoria dels fitxers."
 
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid ""
 "WARNING: Avoiding applying %s -> %s rename to %s, because %s itself was "
@@ -17344,6 +22097,7 @@
 "AVÍS: S'està evitant aplicar el canvi de nom %s -> %s a %s, perquè %s ell "
 "mateix ja havia canviat de nom."
 
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid ""
 "Path updated: %s added in %s inside a directory that was renamed in %s; "
@@ -17352,6 +22106,7 @@
 "Pedaç actualitzat: %s afegit a %s dins d'un directori que va canviar de nom "
 "a %s; movent-lo a %s."
 
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid ""
 "Path updated: %s renamed to %s in %s, inside a directory that was renamed in "
@@ -17360,6 +22115,7 @@
 "Pedaç actualitzat: %s canviat al nom %s a %s, dins d'un directori que va "
 "canviar de nom a %s; movent-lo a %s."
 
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (file location): %s added in %s inside a directory that was renamed "
@@ -17368,6 +22124,7 @@
 "CONFLICTE (ubicació del fitxer): %s afegit a %s dins d'un directori que va "
 "canviar de nom a %s suggerint que potser hauria de moure's a %s."
 
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (file location): %s renamed to %s in %s, inside a directory that "
@@ -17377,11 +22134,13 @@
 "directori que va canviar de nom a %s, suggerint que potser hauria de moure's "
 "a %s."
 
+#: merge-ort.c
 #, c-format
 msgid "CONFLICT (rename/rename): %s renamed to %s in %s and to %s in %s."
 msgstr ""
 "CONFLICTE (canvi de nom/canvi de nom): %s ara té el nom %s a %s i %s a %s."
 
+#: merge-ort.c
 #, c-format
 msgid ""
 "CONFLICT (rename involved in collision): rename of %s -> %s has content "
@@ -17392,20 +22151,24 @@
 "%s té conflictes de contingut i col·lisiona amb un altre camí; això pot "
 "donar lloc a marcadors de conflicte imbricats."
 
+#: merge-ort.c
 #, c-format
 msgid "CONFLICT (rename/delete): %s renamed to %s in %s, but deleted in %s."
 msgstr ""
 "CONFLICTE (canvi de nom/supressió): %s ara té el nom %s a %s, però s'ha "
 "suprimit a %s."
 
+#: merge-ort.c
 #, c-format
-msgid "cannot read object %s"
-msgstr "no es pot llegir l'objecte %s"
+msgid "error: cannot read object %s"
+msgstr "error: no es pot llegir l'objecte %s"
 
+#: merge-ort.c
 #, c-format
-msgid "object %s is not a blob"
-msgstr "l'objecte %s no és un blob"
+msgid "error: object %s is not a blob"
+msgstr "error: l'objecte %s no és un blob"
 
+#: merge-ort.c
 #, c-format
 msgid ""
 "CONFLICT (file/directory): directory in the way of %s from %s; moving it to "
@@ -17414,6 +22177,7 @@
 "CONFLICTE (fitxer/directori): directori en el camí de %s des de %s; en "
 "comptes es mou a %s."
 
+#: merge-ort.c
 #, c-format
 msgid ""
 "CONFLICT (distinct types): %s had different types on each side; renamed both "
@@ -17422,6 +22186,7 @@
 "CONFLICTE (tipus diferents): %s tenia diferents tipus a cada costat; se'ls "
 "ha canviat el nom per tal que cadascun pugui ser registrat en algun lloc."
 
+#: merge-ort.c
 #, c-format
 msgid ""
 "CONFLICT (distinct types): %s had different types on each side; renamed one "
@@ -17431,19 +22196,24 @@
 "canviat el nom d'un d'ells per tal que cadascun pugui ser registrat en algun "
 "lloc."
 
+#: merge-ort.c merge-recursive.c
 msgid "content"
 msgstr "contingut"
 
+#: merge-ort.c merge-recursive.c
 msgid "add/add"
 msgstr "afegiment/afegiment"
 
+#: merge-ort.c merge-recursive.c
 msgid "submodule"
 msgstr "submòdul"
 
+#: merge-ort.c merge-recursive.c
 #, c-format
 msgid "CONFLICT (%s): Merge conflict in %s"
 msgstr "CONFLICTE (%s): Conflicte de fusió en %s"
 
+#: merge-ort.c
 #, c-format
 msgid ""
 "CONFLICT (modify/delete): %s deleted in %s and modified in %s.  Version %s "
@@ -17458,6 +22228,7 @@
 #. commit that needs to be merged.  For example:
 #.  - go to submodule (mysubmodule), and either merge commit abc1234"
 #.
+#: merge-ort.c
 #, c-format
 msgid ""
 " - go to submodule (%s), and either merge commit %s\n"
@@ -17466,6 +22237,7 @@
 " - aneu al submòdul (%s), i fusioneu la comissió %s\n"
 "   o actualitzeu-la a una comissió existent que ha fusionat aquests canvis\n"
 
+#: merge-ort.c
 #, c-format
 msgid ""
 "Recursive merging with submodules currently only supports trivial cases.\n"
@@ -17493,75 +22265,98 @@
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
 #.
+#: merge-ort.c
 #, c-format
 msgid "collecting merge info failed for trees %s, %s, %s"
 msgstr ""
 "ha fallat la recollida de la informació de fusió per als arbres %s, %s, %s"
 
+#: merge-recursive.c
 msgid "(bad commit)\n"
 msgstr "(comissió errònia)\n"
 
+#: merge-recursive.c
 #, c-format
 msgid "add_cacheinfo failed for path '%s'; merge aborting."
 msgstr "add_cacheinfo ha fallat per al camí «%s»; interrompent la fusió."
 
+#: merge-recursive.c
 #, c-format
 msgid "add_cacheinfo failed to refresh for path '%s'; merge aborting."
 msgstr ""
 "add_cacheinfo ha fallat al refrescar el camí «%s»; interrompent la fusió."
 
+#: merge-recursive.c
 #, c-format
 msgid "failed to create path '%s'%s"
 msgstr "s'ha produït un error en crear el camí «%s»%s"
 
+#: merge-recursive.c
 #, c-format
 msgid "Removing %s to make room for subdirectory\n"
 msgstr "S'està eliminant %s per a fer espai per al subdirectori\n"
 
+#: merge-recursive.c
 msgid ": perhaps a D/F conflict?"
 msgstr ": potser un conflicte D/F?"
 
+#: merge-recursive.c
 #, c-format
 msgid "refusing to lose untracked file at '%s'"
 msgstr "s'està refusant perdre el fitxer no seguit a «%s»"
 
+#: merge-recursive.c
 #, c-format
 msgid "blob expected for %s '%s'"
 msgstr "blob esperat per a %s «%s»"
 
+#: merge-recursive.c
 #, c-format
 msgid "failed to open '%s': %s"
 msgstr "s'ha produït un error en obrir «%s»: %s"
 
+#: merge-recursive.c
 #, c-format
 msgid "failed to symlink '%s': %s"
 msgstr "s'ha produït un error en fer l'enllaç simbòlic «%s»: %s"
 
+#: merge-recursive.c
 #, c-format
 msgid "do not know what to do with %06o %s '%s'"
 msgstr "no se sap què fer amb %06o %s «%s»"
 
+#: merge-recursive.c
+#, c-format
+msgid "Failed to merge submodule %s (repository corrupt)"
+msgstr "No s'ha pogut fusionar el submòdul %s (repositori malmès)"
+
+#: merge-recursive.c
 #, c-format
 msgid "Fast-forwarding submodule %s to the following commit:"
 msgstr "Avançament ràpid del submòdul %s a la següent comissió:"
 
+#: merge-recursive.c
 #, c-format
 msgid "Fast-forwarding submodule %s"
 msgstr "Avançament ràpid al submòdul %s"
 
+#: merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (merge following commits not found)"
 msgstr ""
 "Ha fallat en fusionar el submòdul %s (no s'ha trobat les comissions següents)"
 
+#: merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (not fast-forward)"
 msgstr ""
 "S'ha produït un error en fusionar el submòdul %s (sense avançament ràpid)"
 
+#: merge-recursive.c
 msgid "Found a possible merge resolution for the submodule:\n"
 msgstr "S'ha trobat una possible resolució de fusió pel submòdul:\n"
 
+#: merge-recursive.c
 #, c-format
 msgid ""
 "If this is correct simply add it to the index for example\n"
@@ -17578,18 +22373,30 @@
 "\n"
 "que acceptarà aquest suggeriment.\n"
 
+#: merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
 msgstr ""
 "S'ha produït un error en fusionar el submòdul %s (s'han trobat múltiples "
 "fusions)"
 
+#: merge-recursive.c
+msgid "failed to execute internal merge"
+msgstr "no s'ha pogut executar la fusió interna"
+
+#: merge-recursive.c
+#, c-format
+msgid "unable to add %s to database"
+msgstr "no s'ha pogut afegir %s a la base de dades"
+
+#: merge-recursive.c
 #, c-format
 msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
 msgstr ""
 "Error: s'està refusant perdre el fitxer no seguit a %s; en comptes s'ha "
 "escrit a %s."
 
+#: merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -17598,6 +22405,7 @@
 "CONFLICTE: (%s/supressió): %s suprimit en %s i %s en %s. La versió %s de %s "
 "s'ha deixat en l'arbre."
 
+#: merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s to %s in %s. Version %s of %s "
@@ -17606,6 +22414,7 @@
 "CONFLICTE: (%s/supressió): %s suprimit en %s i %s a %s en %s. La versió %s "
 "de %s s'ha deixat en l'arbre."
 
+#: merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -17614,6 +22423,7 @@
 "CONFLICTE: (%s/supressió): %s suprimit en %s i %s en %s. La versió %s de %s "
 "s'ha deixat en l'arbre a %s."
 
+#: merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s to %s in %s. Version %s of %s "
@@ -17622,38 +22432,46 @@
 "CONFLICTE: (%s/supressió): %s suprimit en %s i %s a %s en %s. La versió %s "
 "de %s s'ha deixat en l'arbre a %s."
 
+#: merge-recursive.c
 msgid "rename"
 msgstr "canvi de nom"
 
+#: merge-recursive.c
 msgid "renamed"
 msgstr "canviat de nom"
 
+#: merge-recursive.c
 #, c-format
 msgid "Refusing to lose dirty file at %s"
 msgstr "S'està refusant a perdre el fitxer brut a %s"
 
+#: merge-recursive.c
 #, c-format
 msgid "Refusing to lose untracked file at %s, even though it's in the way."
 msgstr ""
 "S'està refusant perdre el fitxer no seguit a «%s», malgrat que està en mig "
 "de l'operació."
 
+#: merge-recursive.c
 #, c-format
 msgid "CONFLICT (rename/add): Rename %s->%s in %s.  Added %s in %s"
 msgstr ""
 "CONFLICTE (canvi de nom/afegiment): Canvi de nom %s->%s a %s.  S'ha afegit "
 "%s a %s"
 
+#: merge-recursive.c
 #, c-format
 msgid "%s is a directory in %s adding as %s instead"
 msgstr "%s és un directori en %s; s'està afegint com a %s en lloc d'això"
 
+#: merge-recursive.c
 #, c-format
 msgid "Refusing to lose untracked file at %s; adding as %s instead"
 msgstr ""
 "S'està refusant perdre el fitxer no seguit a %s; en comptes, s'està afegint "
 "com a %s"
 
+#: merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename "
@@ -17662,15 +22480,18 @@
 "CONFLICTE (canvi de nom/canvi de nom): Canvi de nom «%s»->«%s» en la branca "
 "«%s» canvi de nom «%s»->«%s» en «%s»%s"
 
+#: merge-recursive.c
 msgid " (left unresolved)"
 msgstr " (deixat sense resolució)"
 
+#: merge-recursive.c
 #, c-format
 msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
 msgstr ""
 "CONFLICTE (canvi de nom/canvi de nom): Canvi de nom %s->%s en %s. Canvi de "
 "nom %s->%s en %s"
 
+#: merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (directory rename split): Unclear where to place %s because "
@@ -17681,6 +22502,7 @@
 "%s perquè el directori %s s'han canviat de nom a múltiples altres "
 "directoris, sense una destinació per a la majoria dels fitxers."
 
+#: merge-recursive.c
 #, c-format
 msgid ""
 "CONFLICT (rename/rename): Rename directory %s->%s in %s. Rename directory %s-"
@@ -17689,285 +22511,426 @@
 "CONFLICTE (canvi de nom/canvi de nom): canvi de nom %s->%s en %s. Canvi de "
 "nom de directori %s->%s en %s"
 
+#: merge-recursive.c
+#, c-format
+msgid "cannot read object %s"
+msgstr "no es pot llegir l'objecte %s"
+
+#: merge-recursive.c
+#, c-format
+msgid "object %s is not a blob"
+msgstr "l'objecte %s no és un blob"
+
+#: merge-recursive.c
 msgid "modify"
 msgstr "modificació"
 
+#: merge-recursive.c
 msgid "modified"
 msgstr "modificat"
 
+#: merge-recursive.c
 #, c-format
 msgid "Skipped %s (merged same as existing)"
 msgstr "S'ha omès %s (el fusionat és igual a l'existent)"
 
+#: merge-recursive.c
 #, c-format
 msgid "Adding as %s instead"
 msgstr "S'està afegint com a %s en lloc d'això"
 
+#: merge-recursive.c
 #, c-format
 msgid "Removing %s"
 msgstr "S'està eliminant %s"
 
+#: merge-recursive.c
 msgid "file/directory"
 msgstr "fitxer/directori"
 
+#: merge-recursive.c
 msgid "directory/file"
 msgstr "directori/fitxer"
 
+#: merge-recursive.c
 #, c-format
 msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
 msgstr ""
 "CONFLICTE (%s): Hi ha un directori amb nom %s en %s. S'està afegint %s com a "
 "%s"
 
+#: merge-recursive.c
 #, c-format
 msgid "Adding %s"
 msgstr "S'està afegint %s"
 
+#: merge-recursive.c
 #, c-format
 msgid "CONFLICT (add/add): Merge conflict in %s"
 msgstr "CONFLICTE (afegiment/afegiment): Conflicte de fusió en %s"
 
+#: merge-recursive.c
 #, c-format
 msgid "merging of trees %s and %s failed"
 msgstr "la fusió dels arbres %s i %s ha fallat"
 
+#: merge-recursive.c
 msgid "Merging:"
 msgstr "S'està fusionant:"
 
+#: merge-recursive.c
 #, c-format
 msgid "found %u common ancestor:"
 msgid_plural "found %u common ancestors:"
 msgstr[0] "s'ha trobat %u avantpassat en comú:"
 msgstr[1] "s'han trobat %u avantpassats en comú:"
 
+#: merge-recursive.c
 msgid "merge returned no commit"
 msgstr "la fusió no ha retornat cap comissió"
 
+#: merge-recursive.c
 #, c-format
 msgid "Could not parse object '%s'"
 msgstr "No s'ha pogut analitzar l'objecte «%s»"
 
+#: merge.c
 msgid "failed to read the cache"
 msgstr "s'ha produït un error en llegir la memòria cau"
 
+#: midx-write.c
+#, c-format
+msgid "failed to add packfile '%s'"
+msgstr "no s'ha pogut afegir el fitxer de paquet «%s»"
+
+#: midx-write.c
+#, c-format
+msgid "failed to open pack-index '%s'"
+msgstr "no s'ha pogut obrir l'índex del paquet «%s»"
+
+#: midx-write.c
+#, c-format
+msgid "failed to locate object %d in packfile"
+msgstr "no s'ha pogut localitzar l'objecte %d en el fitxer de paquet"
+
+#: midx-write.c
+msgid "cannot store reverse index file"
+msgstr "no es pot emmagatzemar el fitxer d'índex invers"
+
+#: midx-write.c
+#, c-format
+msgid "could not parse line: %s"
+msgstr "no s'ha pogut analitzar la línia: %s"
+
+#: midx-write.c
+#, c-format
+msgid "malformed line: %s"
+msgstr "línia mal formada: %s"
+
+#: midx-write.c
+msgid "could not load pack"
+msgstr "no s'ha pogut carregar el paquet"
+
+#: midx-write.c
+#, c-format
+msgid "could not open index for %s"
+msgstr "s'ha produït un error en obrir l'índex per «%s»"
+
+#: midx-write.c
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "no s'ha pogut enllaçar «%s» a «%s»"
+
+#: midx-write.c midx.c
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "no s'ha pogut netejar l'índex multipaquet a %s"
+
+#: midx-write.c
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "no es pot escriure un MIDX incremental amb mapa de bits"
+
+#: midx-write.c
+msgid "ignoring existing multi-pack-index; checksum mismatch"
+msgstr ""
+"s'està ignorant l'índex multipaquet existent; la suma de verificació no "
+"coincideix"
+
+#: midx-write.c
+msgid "Adding packfiles to multi-pack-index"
+msgstr "S'estan afegint fitxers empaquetats a l'índex multipaquet"
+
+#: midx-write.c
+#, c-format
+msgid "unknown preferred pack: '%s'"
+msgstr "paquet preferit desconegut: «%s»"
+
+#: midx-write.c
+#, c-format
+msgid "cannot select preferred pack %s with no objects"
+msgstr "no es pot seleccionar un paquet preferit %s sense objectes"
+
+#: midx-write.c
+#, c-format
+msgid "did not see pack-file %s to drop"
+msgstr "no s'ha vist caure el fitxer empaquetat %s"
+
+#: midx-write.c
+#, c-format
+msgid "preferred pack '%s' is expired"
+msgstr "el paquet preferit «%s» ha caducat"
+
+#: midx-write.c
+msgid "no pack files to index."
+msgstr "no hi ha fitxers empaquetats a indexar."
+
+#: midx-write.c
+msgid "refusing to write multi-pack .bitmap without any objects"
+msgstr "s'està refusant a escriure el .bitmap multipaquet sense cap objecte"
+
+#: midx-write.c
+msgid "unable to create temporary MIDX layer"
+msgstr "no s'ha pogut crear una capa MIDX temporal"
+
+#: midx-write.c
+msgid "could not write multi-pack bitmap"
+msgstr "no s'han pogut escriure els mapes de bits dels multipaquets"
+
+#: midx-write.c
+msgid "unable to open multi-pack-index chain file"
+msgstr "no s'ha pogut obrir el fitxer de cadenes multi-path-index"
+
+#: midx-write.c
+msgid "unable to rename new multi-pack-index layer"
+msgstr "no s'ha pogut canviar el nom de la capa multi-pack-index"
+
+#: midx-write.c
+msgid "could not write multi-pack-index"
+msgstr "no s'ha pogut escriure l'índex multipaquet"
+
+#: midx-write.c
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "no es pot fer caducar paquets d'un multi-pack-index incremental"
+
+#: midx-write.c
+msgid "Counting referenced objects"
+msgstr "S'estan comptant els objectes referenciats"
+
+#: midx-write.c
+msgid "Finding and deleting unreferenced packfiles"
+msgstr "S'estan cercant i suprimint els fitxers de paquets no referenciats"
+
+#: midx-write.c
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "no es pot reempaquetar un multi-pack-index incremental"
+
+#: midx-write.c
+msgid "could not start pack-objects"
+msgstr "no s'ha pogut iniciar el pack-objects"
+
+#: midx-write.c
+msgid "could not finish pack-objects"
+msgstr "no s'ha pogut finalitzar el pack-objects"
+
+#: midx.c
 msgid "multi-pack-index OID fanout is of the wrong size"
 msgstr "l'OID «fanout» de l'índex multipaquet és d'una mida incorrecta"
 
+#: midx.c
 #, c-format
 msgid ""
 "oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
 msgstr ""
 "oid «fanout» desordenat: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
 
+#: midx.c
 msgid "multi-pack-index OID lookup chunk is the wrong size"
 msgstr "El fragment de cerca OID índex multipaquet és de mida incorrecta"
 
+#: midx.c
 msgid "multi-pack-index object offset chunk is the wrong size"
 msgstr ""
 "el fragment de desplaçament de l'objecte índex multipaquet és d'una mida "
 "incorrecta"
 
+#: midx.c
 #, c-format
 msgid "multi-pack-index file %s is too small"
 msgstr "el fitxer de l'índex multipaquet %s és massa petit"
 
+#: midx.c
 #, c-format
 msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
 msgstr ""
 "la signatura de l'índex multipaquet 0x%08x no coincideix amb la signatura "
 "0x%08x"
 
+#: midx.c
 #, c-format
 msgid "multi-pack-index version %d not recognized"
 msgstr "no es reconeix la versió %d de l'índex multipaquet"
 
+#: midx.c
 #, c-format
 msgid "multi-pack-index hash version %u does not match version %u"
 msgstr ""
 "la versió del resum índex multipaquet %u no coincideix amb la versió %u"
 
+#: midx.c
 msgid "multi-pack-index required pack-name chunk missing or corrupted"
 msgstr ""
 "manca o està malmès el fragment del nom de paquet requerit de l'índex "
 "multipaquet"
 
+#: midx.c
 msgid "multi-pack-index required OID fanout chunk missing or corrupted"
 msgstr ""
 "manca o està malmès el fragment del «fanout» OID requerit a l'índex "
 "multipaquet"
 
+#: midx.c
 msgid "multi-pack-index required OID lookup chunk missing or corrupted"
 msgstr ""
 "manca o està malmès el fragment de cerca d'OID necessari a l'índex "
 "multipaquet"
 
+#: midx.c
 msgid "multi-pack-index required object offsets chunk missing or corrupted"
 msgstr ""
 "manca o està malmès el fragment de l'índex multipaquet dels objectes "
 "requerits"
 
+#: midx.c
 msgid "multi-pack-index pack-name chunk is too short"
 msgstr "el fragment de nom de l'índex multipaquet és massa curt"
 
+#: midx.c
 #, c-format
 msgid "multi-pack-index pack names out of order: '%s' before '%s'"
 msgstr ""
 "els noms de paquet de l'índex multipaquet estan desordenats «%s» abans de "
 "«%s»"
 
+#: midx.c
+msgid "multi-pack-index chain file too small"
+msgstr "el fitxer de cadena multi-pack-index és massa petit"
+
+#: midx.c
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "el recompte de paquets en el MIDX de base és massa alt: %<PRIuMAX>"
+
+#: midx.c
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "el recompte de objectes en el MIDX de base és massa alt: %<PRIuMAX>"
+
+#: midx.c
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "cadena multi-pack-index invàlida: la línia «%s» no és un hash"
+
+# tots els fitxers multi-pack-index ?
+#: midx.c
+msgid "unable to find all multi-pack index files"
+msgstr "no s'han pogut trobar tots els fitxers d'índex multi-pack"
+
+#: midx.c
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr ""
+"posició invàlida de l'objecte MIDX; probablement el MIDX s'ha corromput"
+
+#: midx.c
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
 msgstr "pack-int-id: %u incorrecte (%u paquets en total)"
 
+#: midx.c
 msgid "MIDX does not contain the BTMP chunk"
 msgstr "MIDX no conté el fragment BTMP"
 
+#: midx.c
 #, c-format
 msgid "could not load bitmapped pack %<PRIu32>"
 msgstr "no s'ha pogut carregar el paquet amb bits %<PRIu32>"
 
+#: midx.c
 msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
 msgstr ""
 "l'índex multipaquet emmagatzema un desplaçament de 64 bits, però off_t és "
 "massa petit"
 
+#: midx.c
 msgid "multi-pack-index large offset out of bounds"
 msgstr "desplaçament gran de l'índex multipaquet està fora dels límits"
 
-#, c-format
-msgid "failed to add packfile '%s'"
-msgstr "no s'ha pogut afegir el fitxer de paquet «%s»"
-
-#, c-format
-msgid "failed to open pack-index '%s'"
-msgstr "no s'ha pogut obrir l'índex del paquet «%s»"
-
-#, c-format
-msgid "failed to locate object %d in packfile"
-msgstr "no s'ha pogut localitzar l'objecte %d en el fitxer de paquet"
-
-msgid "cannot store reverse index file"
-msgstr "no es pot emmagatzemar el fitxer d'índex invers"
-
-#, c-format
-msgid "could not parse line: %s"
-msgstr "no s'ha pogut analitzar la línia: %s"
-
-#, c-format
-msgid "malformed line: %s"
-msgstr "línia mal formada: %s"
-
-msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr ""
-"s'està ignorant l'índex multipaquet existent; la suma de verificació no "
-"coincideix"
-
-msgid "could not load pack"
-msgstr "no s'ha pogut carregar el paquet"
-
-#, c-format
-msgid "could not open index for %s"
-msgstr "s'ha produït un error en obrir l'índex per «%s»"
-
-msgid "Adding packfiles to multi-pack-index"
-msgstr "S'estan afegint fitxers empaquetats a l'índex multipaquet"
-
-#, c-format
-msgid "unknown preferred pack: '%s'"
-msgstr "paquet preferit desconegut: «%s»"
-
-#, c-format
-msgid "cannot select preferred pack %s with no objects"
-msgstr "no es pot seleccionar un paquet preferit %s sense objectes"
-
-#, c-format
-msgid "did not see pack-file %s to drop"
-msgstr "no s'ha vist caure el fitxer empaquetat %s"
-
-#, c-format
-msgid "preferred pack '%s' is expired"
-msgstr "el paquet preferit «%s» ha caducat"
-
-msgid "no pack files to index."
-msgstr "no hi ha fitxers empaquetats a indexar."
-
-msgid "refusing to write multi-pack .bitmap without any objects"
-msgstr "s'està refusant a escriure el .bitmap multipaquet sense cap objecte"
-
-msgid "could not write multi-pack bitmap"
-msgstr "no s'han pogut escriure els mapes de bits dels multipaquets"
-
-msgid "could not write multi-pack-index"
-msgstr "no s'ha pogut escriure l'índex multipaquet"
-
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "no s'ha pogut netejar l'índex multipaquet a %s"
-
+#: midx.c
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr ""
 "el fitxer de l'índex multipaquet existeix, però no s'ha pogut analitzar"
 
+#: midx.c
 msgid "incorrect checksum"
 msgstr "suma de verificació incorrecta"
 
+#: midx.c
 msgid "Looking for referenced packfiles"
 msgstr "S'estan cercant fitxers empaquetats referenciats"
 
+#: midx.c
 msgid "the midx contains no oid"
 msgstr "el midx no conté cap oid"
 
+#: midx.c
 msgid "Verifying OID order in multi-pack-index"
 msgstr "S'està verificant l'ordre OID a l'índex multipaquet"
 
+#: midx.c
 #, c-format
 msgid "oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"
 msgstr "oid lookup desordenat: oid[%d] = %s >= %s = oid[%d]"
 
+#: midx.c
 msgid "Sorting objects by packfile"
 msgstr "S'estan ordenant els objectes per fitxer empaquetats"
 
+#: midx.c
 msgid "Verifying object offsets"
 msgstr "S'estan verificant els desplaçaments dels objectes"
 
+#: midx.c
 #, c-format
 msgid "failed to load pack entry for oid[%d] = %s"
 msgstr "no s'ha pogut carregar l'entrada del paquet per a oid[%d] = %s"
 
+#: midx.c
 #, c-format
 msgid "failed to load pack-index for packfile %s"
 msgstr "no s'ha pogut carregar l'índex del paquet per al fitxer empaquetat %s"
 
+#: midx.c
 #, c-format
 msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
 msgstr ""
 "desplaçament incorrecte de l'objecte per a oid[%d] = %s: %<PRIx64> != "
 "%<PRIx64>"
 
-msgid "Counting referenced objects"
-msgstr "S'estan comptant els objectes referenciats"
-
-msgid "Finding and deleting unreferenced packfiles"
-msgstr "S'estan cercant i suprimint els fitxers de paquets no referenciats"
-
-msgid "could not start pack-objects"
-msgstr "no s'ha pogut iniciar el pack-objects"
-
-msgid "could not finish pack-objects"
-msgstr "no s'ha pogut finalitzar el pack-objects"
-
+#: name-hash.c
 #, c-format
 msgid "unable to create lazy_dir thread: %s"
 msgstr "no s'ha pogut crear el fil «lazy_dir» :%s"
 
+#: name-hash.c
 #, c-format
 msgid "unable to create lazy_name thread: %s"
 msgstr "no s'ha pogut crear un fil «lazy_name»: %s"
 
+#: name-hash.c
 #, c-format
 msgid "unable to join lazy_name thread: %s"
 msgstr "no s'ha pogut unir el fil «lazy_name»: %s"
 
+#: notes-merge.c
 #, c-format
 msgid ""
 "You have not concluded your previous notes merge (%s exists).\n"
@@ -17978,17 +22941,21 @@
 "Useu «git notes merge --commit» o «git notes merge --abort» per a cometre/"
 "avortar la fusió prèvia abans de començar una fusió de notes nova."
 
+#: notes-merge.c
 #, c-format
 msgid "You have not concluded your notes merge (%s exists)."
 msgstr "No heu conclòs la vostra fusió de notes (%s existeix)."
 
+#: notes-utils.c
 msgid "Cannot commit uninitialized/unreferenced notes tree"
 msgstr "No es pot cometre un arbre de notes no inicialitzat / no referenciat"
 
+#: notes-utils.c
 #, c-format
 msgid "Bad notes.rewriteMode value: '%s'"
 msgstr "Valor de notes.rewriteMode erroni: «%s»"
 
+#: notes-utils.c
 #, c-format
 msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
 msgstr "S'està refusant reescriure les notes en %s (fora de refs/notes/)"
@@ -17997,217 +22964,310 @@
 #. the environment variable, the second %s is
 #. its value.
 #.
+#: notes-utils.c
 #, c-format
 msgid "Bad %s value: '%s'"
 msgstr "Valor erroni de %s: «%s»"
 
+#: object-file-convert.c
+msgid "failed to decode tree entry"
+msgstr "no s'ha pogut descodificar una entrada d'arbre"
+
+#: object-file-convert.c
+#, c-format
+msgid "failed to map tree entry for %s"
+msgstr "no s'ha pogut mapar l'entrada d'arbre per a %s"
+
+#: object-file-convert.c
+#, c-format
+msgid "bad %s in commit"
+msgstr "%s és incorrecte en la comissió"
+
+#: object-file-convert.c
+#, c-format
+msgid "unable to map %s %s in commit object"
+msgstr "no es pot mapar %s %s en l'objecte de comissió"
+
+#: object-file-convert.c
+#, c-format
+msgid "Failed to convert object from %s to %s"
+msgstr "No s'ha pogut convertir l'objecte de %s a %s"
+
+#: object-file.c
 #, c-format
 msgid "object directory %s does not exist; check .git/objects/info/alternates"
 msgstr ""
 "no existeix el directori d'objecte %s; comproveu .git/objects/info/alternates"
 
+#: object-file.c
 #, c-format
 msgid "unable to normalize alternate object path: %s"
 msgstr "no s'ha pogut normalitzar el camí a l'objecte alternatiu: %s"
 
+#: object-file.c
 #, c-format
 msgid "%s: ignoring alternate object stores, nesting too deep"
 msgstr ""
 "%s: s'estan ignorant els emmagatzematges alternatius d'objectes, imbricació "
 "massa profunda"
 
+#: object-file.c
 msgid "unable to fdopen alternates lockfile"
 msgstr "no s'ha pogut fer «fdopen» al fitxer de bloqueig alternatiu"
 
+#: object-file.c
 msgid "unable to read alternates file"
 msgstr "no es pot llegir el fitxer «alternates»"
 
+#: object-file.c
 msgid "unable to move new alternates file into place"
 msgstr "no s'ha pogut moure el nou fitxer «alternates» al lloc"
 
+#: object-file.c
 #, c-format
 msgid "path '%s' does not exist"
 msgstr "el camí «%s» no existeix"
 
+#: object-file.c
 #, c-format
 msgid "reference repository '%s' as a linked checkout is not supported yet."
 msgstr ""
 "encara no s'admet el repositori de referència «%s» com a agafament enllaçat."
 
+#: object-file.c
 #, c-format
 msgid "reference repository '%s' is not a local repository."
 msgstr "el repositori de referència «%s» no és un repositori local."
 
+#: object-file.c
 #, c-format
 msgid "reference repository '%s' is shallow"
 msgstr "el repositori de referència «%s» és superficial"
 
+#: object-file.c
 #, c-format
 msgid "reference repository '%s' is grafted"
 msgstr "el repositori de referència «%s» és empeltat"
 
+#: object-file.c
 #, c-format
 msgid "could not find object directory matching %s"
 msgstr "no s'ha pogut trobar el directori de l'objecte que coincideixi amb %s"
 
+#: object-file.c
 #, c-format
 msgid "invalid line while parsing alternate refs: %s"
 msgstr ""
 "línia no vàlida quan s'analitzaven les referències de l'«alternate»: %s"
 
+#: object-file.c
 #, c-format
 msgid "attempting to mmap %<PRIuMAX> over limit %<PRIuMAX>"
 msgstr "s'està intentant fer mmap %<PRIuMAX> per sobre del límit %<PRIuMAX>"
 
+#: object-file.c
 #, c-format
 msgid "mmap failed%s"
 msgstr "mmap ha fallat%s"
 
+#: object-file.c
 #, c-format
 msgid "object file %s is empty"
 msgstr "el tipus d'objecte %s és buit"
 
+#: object-file.c
 #, c-format
 msgid "corrupt loose object '%s'"
 msgstr "objecte solt corrupte «%s»"
 
+#: object-file.c
 #, c-format
 msgid "garbage at end of loose object '%s'"
 msgstr "brossa al final de l'objecte solt «%s»"
 
+#: object-file.c
 #, c-format
 msgid "unable to open loose object %s"
 msgstr "no s'ha pogut obrir l'objecte solt %s"
 
+#: object-file.c
 #, c-format
 msgid "unable to parse %s header"
 msgstr "no s'ha pogut analitzar la capçalera %s"
 
+#: object-file.c
 msgid "invalid object type"
 msgstr "tipus d'objecte és incorrecte"
 
+#: object-file.c
 #, c-format
 msgid "unable to unpack %s header"
 msgstr "no s'ha pogut desempaquetar la capçalera %s"
 
+#: object-file.c
 #, c-format
 msgid "header for %s too long, exceeds %d bytes"
-msgstr "la capçalera per a %s és massa llarga, supera els %d bytes"
+msgstr "la capçalera per a %s és massa llarga, supera els %d octets"
 
+#: object-file.c
 #, c-format
 msgid "loose object %s (stored in %s) is corrupt"
 msgstr "l'objecte solt %s (emmagatzemat a %s) és corrupte"
 
+#: object-file.c
 #, c-format
 msgid "replacement %s not found for %s"
 msgstr "no s'ha trobat el reemplaçament %s per a %s"
 
+#: object-file.c
 #, c-format
 msgid "packed object %s (stored in %s) is corrupt"
 msgstr "l'objecte empaquetat %s (emmagatzemat a %s) és corrupte"
 
+#: object-file.c
+#, c-format
+msgid "missing mapping of %s to %s"
+msgstr "manca el mapatge de %s a %s"
+
+#: object-file.c
+#, c-format
+msgid "unable to open %s"
+msgstr "no s'ha pogut obrir %s"
+
+#: object-file.c
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "els fitxers «%s» i «%s» difereixen en el contingut"
+
+#: object-file.c
 #, c-format
 msgid "unable to write file %s"
 msgstr "no s'ha pogut escriure al fitxer %s"
 
+#: object-file.c
 #, c-format
 msgid "unable to set permission to '%s'"
 msgstr "no s'ha pogut establir el permís a «%s»"
 
+#: object-file.c
 msgid "error when closing loose object file"
 msgstr "error en tancar el fitxer d'objecte solt"
 
+#: object-file.c
 #, c-format
 msgid "insufficient permission for adding an object to repository database %s"
 msgstr ""
 "permisos insuficients per a afegir un objecte a la base de dades del "
 "repositori %s"
 
+#: object-file.c
 msgid "unable to create temporary file"
 msgstr "no s'ha pogut crear un fitxer temporal"
 
+#: object-file.c
 msgid "unable to write loose object file"
 msgstr "no s'ha pogut escriure el fitxer d'objecte solt"
 
+#: object-file.c
 #, c-format
 msgid "unable to deflate new object %s (%d)"
 msgstr "no s'ha pogut desinflar l'object nou %s (%d)"
 
+#: object-file.c
 #, c-format
 msgid "deflateEnd on object %s failed (%d)"
 msgstr "ha fallat deflateEnd a l'objecte %s(%d)"
 
+#: object-file.c
 #, c-format
 msgid "confused by unstable object source data for %s"
 msgstr "confós per la font de dades inestable de l'objecte per a %s"
 
+#: object-file.c
 #, c-format
 msgid "write stream object %ld != %<PRIuMAX>"
 msgstr "escriu l'objecte de flux %ld != %<PRIuMAX>"
 
+#: object-file.c
 #, c-format
 msgid "unable to stream deflate new object (%d)"
 msgstr "no s'ha pogut desinflar l'object nou (%d)"
 
+#: object-file.c
 #, c-format
 msgid "deflateEnd on stream object failed (%d)"
 msgstr "ha fallat deflateEnd a l'objecte del flux (%d)"
 
+#: object-file.c
 #, c-format
 msgid "unable to create directory %s"
 msgstr "s'ha produït un error en crear el directori %s"
 
+#: object-file.c
 #, c-format
 msgid "cannot read object for %s"
 msgstr "no es pot llegir l'objecte per a %s"
 
+#: object-file.c
+#, c-format
+msgid "cannot map object %s to %s"
+msgstr "no és possible mapar l'objecte %s a %s"
+
+#: object-file.c
 #, c-format
 msgid "object fails fsck: %s"
 msgstr "l'objecte ha fallat fsck: %s"
 
+#: object-file.c
 msgid "refusing to create malformed object"
 msgstr "es rebutja crear un objecte mal format"
 
+#: object-file.c
 #, c-format
 msgid "read error while indexing %s"
 msgstr "error de lectura mentre s'indexava %s"
 
+#: object-file.c
 #, c-format
 msgid "short read while indexing %s"
 msgstr "lectura curta mentre s'indexa %s"
 
+#: object-file.c
 #, c-format
 msgid "%s: failed to insert into database"
 msgstr "%s: no s'han pogut inserir a la base de dades"
 
+#: object-file.c
 #, c-format
 msgid "%s: unsupported file type"
 msgstr "%s: tipus de fitxer no suportat"
 
+#: object-file.c
 #, c-format
 msgid "%s is not a valid '%s' object"
 msgstr "%s no és un objecte de «%s» vàlid"
 
-#, c-format
-msgid "unable to open %s"
-msgstr "no s'ha pogut obrir %s"
-
+#: object-file.c
 #, c-format
 msgid "hash mismatch for %s (expected %s)"
 msgstr "no coincideix el resum per a %s (s'esperava %s)"
 
+#: object-file.c
 #, c-format
 msgid "unable to mmap %s"
 msgstr "no s'ha pogut fer «mmap» %s"
 
+#: object-file.c
 #, c-format
 msgid "unable to unpack header of %s"
 msgstr "no s'ha pogut desempaquetar la capçalera de %s"
 
+#: object-file.c
 #, c-format
 msgid "unable to parse header of %s"
 msgstr "no s'ha pogut analitzar la capçalera de %s"
 
+#: object-file.c
 #, c-format
 msgid "unable to unpack contents of %s"
 msgstr "no s'han pogut desempaquetar els continguts de %s"
@@ -18216,6 +23276,7 @@
 #. output shown when we cannot look up or parse the
 #. object in question. E.g. "deadbeef [bad object]".
 #.
+#: object-name.c
 #, c-format
 msgid "%s [bad object]"
 msgstr "%s [objecte incorrecte]"
@@ -18225,6 +23286,7 @@
 #. *
 #.    "deadbeef commit 2021-01-01 - Some Commit Message"
 #.
+#: object-name.c
 #, c-format
 msgid "%s commit %s - %s"
 msgstr "%s comissió %s - %s"
@@ -18240,6 +23302,7 @@
 #. The third argument is the "tag" string
 #. from object.c.
 #.
+#: object-name.c
 #, c-format
 msgid "%s tag %s - %s"
 msgstr "%s etiqueta %s - %s"
@@ -18250,6 +23313,7 @@
 #. *
 #.    "deadbeef [bad tag, could not parse it]"
 #.
+#: object-name.c
 #, c-format
 msgid "%s [bad tag, could not parse it]"
 msgstr "%s [etiqueta malmesa, no s'ha pogut analitzar]"
@@ -18257,6 +23321,7 @@
 #. TRANSLATORS: This is a line of ambiguous <type>
 #. object output. E.g. "deadbeef tree".
 #.
+#: object-name.c
 #, c-format
 msgid "%s tree"
 msgstr "arbre %s"
@@ -18264,10 +23329,12 @@
 #. TRANSLATORS: This is a line of ambiguous <type>
 #. object output. E.g. "deadbeef blob".
 #.
+#: object-name.c
 #, c-format
 msgid "%s blob"
 msgstr "blob %s"
 
+#: object-name.c
 #, c-format
 msgid "short object ID %s is ambiguous"
 msgstr "l'id d'objecte curt %s és ambigu"
@@ -18276,6 +23343,7 @@
 #. objects composed in show_ambiguous_object(). See
 #. its "TRANSLATORS" comments for details.
 #.
+#: object-name.c
 #, c-format
 msgid ""
 "The candidates are:\n"
@@ -18284,6 +23352,7 @@
 "Els candidats són:\n"
 "%s"
 
+#: object-name.c
 msgid ""
 "Git normally never creates a ref that ends with 40 hex characters\n"
 "because it will be ignored when you just specify 40-hex. These refs\n"
@@ -18307,18 +23376,22 @@
 "suprimiu-les. Desactiveu aquest missatge executant\n"
 "«git config advice.objectNameWarning false»"
 
+#: object-name.c
 #, c-format
 msgid "log for '%.*s' only goes back to %s"
 msgstr "registre per a «%.*s» només retorna a %s"
 
+#: object-name.c
 #, c-format
 msgid "log for '%.*s' only has %d entries"
 msgstr "registre per a «%.*s» només té %d entrades"
 
+#: object-name.c
 #, c-format
 msgid "path '%s' exists on disk, but not in '%.*s'"
 msgstr "el camí «%s» existeix al disc, però no a «%.*s»"
 
+#: object-name.c
 #, c-format
 msgid ""
 "path '%s' exists, but not '%s'\n"
@@ -18327,10 +23400,12 @@
 "el camí «%s» existeix, però no «%s»\n"
 "consell: volíeu dir «%.*s:%s» conegut com a «%.*s:./%s»?"
 
+#: object-name.c
 #, c-format
 msgid "path '%s' does not exist in '%.*s'"
 msgstr "el camí «%s» no existeix en «%.*s»"
 
+#: object-name.c
 #, c-format
 msgid ""
 "path '%s' is in the index, but not at stage %d\n"
@@ -18339,6 +23414,7 @@
 "el camí «%s» està a l'índex, però no a «stage» %d\n"
 ".consell: volíeu dir «:%d:%s»?"
 
+#: object-name.c
 #, c-format
 msgid ""
 "path '%s' is in the index, but not '%s'\n"
@@ -18347,328 +23423,455 @@
 "el camí «%s» està a l'índex, però no a «%s»\n"
 ".consell: volíeu dir «:%d:%s» conegut com a «:%d:./%s»?"
 
+#: object-name.c
 #, c-format
 msgid "path '%s' exists on disk, but not in the index"
 msgstr "el camí «%s» existeix al disc, però no a l'índex"
 
+#: object-name.c
 #, c-format
 msgid "path '%s' does not exist (neither on disk nor in the index)"
 msgstr "el camí «%s» no existeix (ni al disc ni a l'índex)"
 
+#: object-name.c
 msgid "relative path syntax can't be used outside working tree"
 msgstr ""
 "la sintaxi de camí relatiu no es pot utilitzar fora de l'arbre de treball"
 
+#: object-name.c
 #, c-format
 msgid "<object>:<path> required, only <object> '%s' given"
 msgstr "<objecte>:<camí> requerit, només s'ha donat <objecte> «%s»"
 
+#: object-name.c
 #, c-format
 msgid "invalid object name '%.*s'."
 msgstr "nom d'objecte no vàlid «%.*s»."
 
+#: object.c
 #, c-format
 msgid "invalid object type \"%s\""
 msgstr "tipus d'objecte «%s» no vàlid"
 
+#: object.c
 #, c-format
 msgid "object %s is a %s, not a %s"
 msgstr "l'objecte %s és %s, no pas %s"
 
+#: object.c
 #, c-format
 msgid "object %s has unknown type id %d"
 msgstr "l'objecte %s té un identificador de tipus %d desconegut"
 
+#: object.c
 #, c-format
 msgid "unable to parse object: %s"
 msgstr "no s'ha pogut analitzar l'objecte: %s"
 
+#: object.c
 #, c-format
 msgid "hash mismatch %s"
 msgstr "el resum no coincideix %s"
 
+#: pack-bitmap-write.c
+#, c-format
+msgid "duplicate entry when writing bitmap index: %s"
+msgstr "entrada duplicada en escriure l'índex de mapa de bits: %s"
+
+#: pack-bitmap-write.c
+#, c-format
+msgid "attempted to store non-selected commit: '%s'"
+msgstr "s'ha intentat emmagatzemar una comissió no seleccionada: «%s»"
+
+#: pack-bitmap-write.c
+msgid "too many pseudo-merges"
+msgstr "massa pseudo-fusions"
+
+#: pack-bitmap-write.c
 msgid "trying to write commit not in index"
 msgstr "s'està intentant no escriure la comissió a l'índex"
 
+#: pack-bitmap.c
 msgid "failed to load bitmap index (corrupted?)"
 msgstr ""
 "s'ha produït un error en carregar l'índex de mapa de bits (està malmès?)"
 
+#: pack-bitmap.c
 msgid "corrupted bitmap index (too small)"
 msgstr "índex de mapa de bits malmès (massa petit)"
 
+#: pack-bitmap.c
 msgid "corrupted bitmap index file (wrong header)"
 msgstr "fitxer d'índex de mapa de bits malmès (capçalera incorrecta)"
 
+#: pack-bitmap.c
 #, c-format
 msgid "unsupported version '%d' for bitmap index file"
 msgstr "versió «%d» no admesa per al fitxer d'índex de mapa de bits"
 
+#: pack-bitmap.c
 msgid "corrupted bitmap index file (too short to fit hash cache)"
 msgstr ""
 "fitxer d'índex de mapa de bits malmès (massa curt per a ajustar-se a la "
 "memòria cau de hash)"
 
+#: pack-bitmap.c
 msgid "corrupted bitmap index file (too short to fit lookup table)"
 msgstr ""
 "fitxer d'índex de mapa de bits malmès (massa curt per a ajustar-se a la "
 "taula de cerca)"
 
+# 2 línies OK?
+#: pack-bitmap.c
+msgid ""
+"corrupted bitmap index file (too short to fit pseudo-merge table header)"
+msgstr ""
+"fitxer d'índex de mapes de bits malmès (massa curt per a ajustar-se\n"
+"a la capçalera de la taula de pseudo-fusions)"
+
+# 2 línies OK?
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit pseudo-merge table)"
+msgstr ""
+"fitxer d'índex de mapa de bits malmès (massa curt per a ajustar-se\n"
+"a la taula de pseudo-fusions)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file, pseudo-merge table too short"
+msgstr ""
+"fitxer d'índex de mapa de bits malmès, taula de pseudo-fusions massa curta"
+
+#: pack-bitmap.c
 #, c-format
 msgid "duplicate entry in bitmap index: '%s'"
 msgstr "entrada duplicada a l'índex del mapa de bits: «%s»"
 
+#: pack-bitmap.c
 #, c-format
 msgid "corrupt ewah bitmap: truncated header for entry %d"
 msgstr "mapa de bits ewah malmès: capçalera truncada per a l'entrada %d"
 
+#: pack-bitmap.c
 #, c-format
 msgid "corrupt ewah bitmap: commit index %u out of range"
 msgstr "mapa de bits ewah malmès: l'índex de comissió %u està fora de rang"
 
+#: pack-bitmap.c
 msgid "corrupted bitmap pack index"
 msgstr "índex de paquets de mapa de bits malmès"
 
+#: pack-bitmap.c
 msgid "invalid XOR offset in bitmap pack index"
 msgstr "el desplaçament XOR a l'índex de mapa de bits no és vàlid"
 
+#: pack-bitmap.c
 msgid "cannot fstat bitmap file"
 msgstr "no es pot fer fstat en el fitxer de mapa de bits"
 
+#: pack-bitmap.c
 msgid "checksum doesn't match in MIDX and bitmap"
 msgstr "la suma de verificació no coincideix amb el MIDX i el mapa de bits"
 
+#: pack-bitmap.c
 msgid "multi-pack bitmap is missing required reverse index"
 msgstr "falta l'índex invers necessari al mapa de bits multipaquet"
 
+#: pack-bitmap.c
 #, c-format
 msgid "could not open pack %s"
 msgstr "no s'ha pogut obrir el paquet %s"
 
+#: pack-bitmap.c t/helper/test-read-midx.c
 msgid "could not determine MIDX preferred pack"
 msgstr "no s'ha pogut determinar el paquet preferit MIDX"
 
+#: pack-bitmap.c
 #, c-format
 msgid "preferred pack (%s) is invalid"
 msgstr "el paquet preferit (%s) no és vàlid"
 
+#: pack-bitmap.c
 msgid "corrupt bitmap lookup table: triplet position out of index"
 msgstr ""
 "taula de cerca de mapa de bits malmesa: posició la tripleta fora de l'índex"
 
+#: pack-bitmap.c
 msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
 msgstr ""
 "taula de cerca de mapa de bits malmesa: la cadena xor excedeix el nombre "
 "d'entrades"
 
+#: pack-bitmap.c
 #, c-format
 msgid "corrupt bitmap lookup table: commit index %u out of range"
 msgstr ""
 "taula de cerca de mapa de bits malmesa: l'índex de comissió %u està fora de "
 "rang"
 
+#: pack-bitmap.c
 #, c-format
 msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
 msgstr ""
 "mapa de bits ewah malmès: capçalera truncada per al mapa de bits de la "
 "comissió «%s»"
 
+#: pack-bitmap.c
 #, c-format
 msgid "unable to load pack: '%s', disabling pack-reuse"
 msgstr ""
 "no s'ha pogut carregar el paquet: «%s», s'està inhabilitant lareutilització "
 "de paquets"
 
+# s'inhabilita / s'està inhabilitant?
+#: pack-bitmap.c
+msgid "unable to compute preferred pack, disabling pack-reuse"
+msgstr "no s'ha pogut calcular el paquet preferit, s'inhabilita pack-reuse"
+
+#: pack-bitmap.c
 #, c-format
 msgid "object '%s' not found in type bitmaps"
 msgstr "no s'ha trobat l'objecte «%s» als tipus de mapes de bits"
 
+#: pack-bitmap.c
 #, c-format
 msgid "object '%s' does not have a unique type"
 msgstr "l'objecte «%s» no té un tipus únic"
 
+#: pack-bitmap.c
 #, c-format
 msgid "object '%s': real type '%s', expected: '%s'"
 msgstr "objecte «%s»: tipus real «%s», s'esperava: «%s»"
 
+#: pack-bitmap.c
 #, c-format
 msgid "object not in bitmap: '%s'"
 msgstr "objecte no trobat al mapa de bits: «%s»"
 
+#: pack-bitmap.c
 msgid "failed to load bitmap indexes"
 msgstr "s'ha produït un error en carregar l'índex de mapa de bits"
 
+#: pack-bitmap.c
 msgid "you must specify exactly one commit to test"
 msgstr "heu d'especificar exactament una comissió a provar"
 
+#: pack-bitmap.c
 #, c-format
 msgid "commit '%s' doesn't have an indexed bitmap"
 msgstr "la comissió «%s» no té un mapa de bits indexat"
 
+#: pack-bitmap.c
 msgid "mismatch in bitmap results"
 msgstr "no coincideix en els resultats del mapa de bits"
 
+#: pack-bitmap.c
+#, c-format
+msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)"
+msgstr "l'índex de pseudo-fusions és fora de rang (%<PRIu32> >= %<PRIuMAX>)"
+
+#: pack-bitmap.c
 #, c-format
 msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
 msgstr "no s'ha pogut trobar «%s» al paquet «%s» al desplaçament %<PRIuMAX>"
 
+#: pack-bitmap.c
 #, c-format
 msgid "unable to get disk usage of '%s'"
 msgstr "no s'ha pogut obtenir l'ús del disc de «%s»"
 
+#: pack-bitmap.c
 #, c-format
 msgid "bitmap file '%s' has invalid checksum"
 msgstr "el fitxer de mapa de bits «%s» té una suma de verificació no vàlida"
 
+#: pack-mtimes.c
 #, c-format
 msgid "mtimes file %s is too small"
 msgstr "el fitxer mtimes %s és massa petit"
 
+#: pack-mtimes.c
 #, c-format
 msgid "mtimes file %s has unknown signature"
 msgstr "el fitxer mtimes %s té una signatura desconeguda"
 
+#: pack-mtimes.c
 #, c-format
 msgid "mtimes file %s has unsupported version %<PRIu32>"
 msgstr "el fitxer mtimes %s té la versió %<PRIu32> no admesa"
 
+#: pack-mtimes.c
 #, c-format
 msgid "mtimes file %s has unsupported hash id %<PRIu32>"
 msgstr "el fitxer mtimes %s té un ID de resum %<PRIu32> no admès"
 
+#: pack-mtimes.c
 #, c-format
 msgid "mtimes file %s is corrupt"
 msgstr "el fitxer mtimes %s està malmès"
 
+#: pack-revindex.c
 #, c-format
 msgid "reverse-index file %s is too small"
 msgstr "el fitxer d'índex invers %s és massa petit"
 
+#: pack-revindex.c
 #, c-format
 msgid "reverse-index file %s is corrupt"
 msgstr "el fitxer d'índex invers %s està malmès"
 
+#: pack-revindex.c
 #, c-format
 msgid "reverse-index file %s has unknown signature"
 msgstr "el fitxer d'índex invers %s té una signatura desconeguda"
 
+#: pack-revindex.c
 #, c-format
 msgid "reverse-index file %s has unsupported version %<PRIu32>"
 msgstr "el fitxer d'índex invers %s té la versió %<PRIu32> no admesa"
 
+#: pack-revindex.c
 #, c-format
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
 msgstr "el fitxer d'índex invers %s té un ID de resum %<PRIu32> no admès"
 
+#: pack-revindex.c
 msgid "invalid checksum"
 msgstr "suma de verificació no vàlida"
 
+#: pack-revindex.c
 #, c-format
 msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
 msgstr ""
 "posició no vàlida de l'índex de reversió a %<PRIu64>: %<PRIu32> != %<PRIu32>"
 
+#: pack-revindex.c
 msgid "multi-pack-index reverse-index chunk is the wrong size"
 msgstr ""
 "el fragment de l'index invers de l'índex multipaquet és de mida incorrecta"
 
+#: pack-revindex.c
 msgid "could not determine preferred pack"
 msgstr "no s'ha pogut determinar el paquet preferit"
 
+#: pack-write.c
 msgid "cannot both write and verify reverse index"
 msgstr "no es pot escriure i verificar l'índex invers"
 
+#: pack-write.c
 #, c-format
 msgid "could not stat: %s"
 msgstr "no s'ha pogut fer stat a: %s"
 
+#: pack-write.c
 #, c-format
 msgid "failed to make %s readable"
 msgstr "s'ha produït un error en fer %s llegible"
 
+#: pack-write.c
 #, c-format
 msgid "could not write '%s' promisor file"
 msgstr "no s'ha pogut escriure «%s» al fitxer «promisor»"
 
+#: packfile.c
 msgid "offset before end of packfile (broken .idx?)"
 msgstr "desplaçament abans de la fi del fitxer de paquet (.idx trencat?)"
 
+#: packfile.c
 #, c-format
 msgid "packfile %s cannot be mapped%s"
 msgstr "el fitxer de paquet %s no es pot mapar%s"
 
+#: packfile.c
 #, c-format
 msgid "offset before start of pack index for %s (corrupt index?)"
 msgstr ""
 "desplaçament abans d'inici d'índex de paquet per a %s (índex corromput?)"
 
+#: packfile.c
 #, c-format
 msgid "offset beyond end of pack index for %s (truncated index?)"
 msgstr ""
 "desplaçament més enllà de la fi d'índex de paquet per a %s (índex truncat?)"
 
+#: parse-options-cb.c
 #, c-format
 msgid "malformed expiration date '%s'"
 msgstr "data de venciment «%s» mal formada"
 
+#: parse-options-cb.c
 #, c-format
 msgid "option `%s' expects \"always\", \"auto\", or \"never\""
 msgstr "l'opció «%s» espera «always», «auto» o «never»"
 
+#: parse-options-cb.c
 #, c-format
 msgid "malformed object name '%s'"
 msgstr "nom d'objecte «%s» mal format"
 
+#: parse-options-cb.c
 #, c-format
 msgid "option `%s' expects \"%s\" or \"%s\""
 msgstr "l'opció «%s» espera «%s» o «%s»"
 
+#: parse-options.c
 #, c-format
 msgid "%s requires a value"
 msgstr "%s requereix un valor"
 
+#: parse-options.c
 #, c-format
 msgid "%s takes no value"
 msgstr "%s no accepta cap valor"
 
+#: parse-options.c
 #, c-format
 msgid "%s isn't available"
 msgstr "%s no és disponible"
 
+#: parse-options.c
 #, c-format
 msgid "%s expects a non-negative integer value with an optional k/m/g suffix"
 msgstr "%s espera un valor enter no negatiu amb un sufix opcional k/m/g"
 
+#: parse-options.c
 #, c-format
 msgid "ambiguous option: %s (could be --%s%s or --%s%s)"
 msgstr "opció ambigua: %s (pot ser --%s%s o --%s%s)"
 
+#: parse-options.c
 #, c-format
 msgid "did you mean `--%s` (with two dashes)?"
 msgstr "voleu dir «--%s» (amb dos guionets)?"
 
+#: parse-options.c
 #, c-format
 msgid "alias of --%s"
 msgstr "àlies de --%s"
 
+#: parse-options.c
 msgid "need a subcommand"
 msgstr "cal una subordre"
 
+#: parse-options.c
 #, c-format
 msgid "unknown option `%s'"
 msgstr "opció desconeguda «%s»"
 
+#: parse-options.c
 #, c-format
 msgid "unknown switch `%c'"
 msgstr "opció «%c» desconeguda"
 
+#: parse-options.c
 #, c-format
 msgid "unknown non-ascii option in string: `%s'"
 msgstr "opció no ascii desconeguda en la cadena: «%s»"
 
+#: parse-options.c
 msgid "..."
 msgstr "..."
 
+#: parse-options.c
 #, c-format
 msgid "usage: %s"
 msgstr "ús: %s"
@@ -18676,6 +23879,7 @@
 #. TRANSLATORS: the colon here should align with the
 #. one in "usage: %s" translation.
 #.
+#: parse-options.c
 #, c-format
 msgid "   or: %s"
 msgstr "   o: %s"
@@ -18699,83 +23903,105 @@
 #. translated) N_() usage string, which contained embedded
 #. newlines before we split it up.
 #.
+#: parse-options.c
 #, c-format
 msgid "%*s%s"
 msgstr "%*s%s"
 
+#: parse-options.c
 #, c-format
 msgid "    %s"
 msgstr "    %s"
 
+#: parse-options.c
 msgid "-NUM"
 msgstr "-NUM"
 
+#: parse-options.c
 #, c-format
 msgid "opposite of --no-%s"
 msgstr "oposat a --no-%s"
 
+#: parse-options.h
 msgid "expiry-date"
 msgstr "data-de-caducitat"
 
+#: parse-options.h
 msgid "no-op (backward compatibility)"
 msgstr "operació nul·la (per a compatibilitat amb versions anteriors)"
 
+#: parse-options.h
 msgid "be more verbose"
 msgstr "sigues més detallat"
 
+#: parse-options.h
 msgid "be more quiet"
 msgstr "sigues més discret"
 
+#: parse-options.h
 msgid "use <n> digits to display object names"
 msgstr "usa <n> xifres per a mostrar els noms d'objecte"
 
+#: parse-options.h
 msgid "prefixed path to initial superproject"
 msgstr "camí prefixat al superprojecte inicial"
 
+#: parse-options.h
 msgid "how to strip spaces and #comments from message"
 msgstr "com suprimir els espais i #comentaris del missatge"
 
+#: parse-options.h
 msgid "read pathspec from file"
 msgstr "llegeix l'especificació del camí del fitxer"
 
+#: parse-options.h
 msgid ""
 "with --pathspec-from-file, pathspec elements are separated with NUL character"
 msgstr ""
 "amb --pathspec-from-file els elements d'especificació del camí estan "
 "separats amb el caràcter NUL"
 
+#: parse.c
 #, c-format
 msgid "bad boolean environment value '%s' for '%s'"
 msgstr "el valor «%s» booleà de l'entorn és incorrecte per a «%s»"
 
+#: parse.c
 #, c-format
 msgid "failed to parse %s"
 msgstr "s'ha produït un error en analitzar %s"
 
+#: path.c
 #, c-format
 msgid "Could not make %s writable by group"
 msgstr "No s'ha pogut fer %s escrivible pel grup"
 
+#: pathspec.c
 msgid "Escape character '\\' not allowed as last character in attr value"
 msgstr ""
 "El caràcter d'escapament «\\» no està permès com a últim caràcter en un "
 "valor d'un atribut"
 
+#: pathspec.c
 msgid "Only one 'attr:' specification is allowed."
 msgstr "Només es permet una especificació «attr:»."
 
+#: pathspec.c
 msgid "attr spec must not be empty"
 msgstr "una especificació d'atribut no pot estar buida"
 
+#: pathspec.c
 #, c-format
 msgid "invalid attribute name %s"
 msgstr "nom d'atribut no vàlid %s"
 
+#: pathspec.c
 msgid "global 'glob' and 'noglob' pathspec settings are incompatible"
 msgstr ""
 "els paràmetres d'especificació de camí «glob» i «noglob» globals són "
 "incompatibles"
 
+#: pathspec.c
 msgid ""
 "global 'literal' pathspec setting is incompatible with all other global "
 "pathspec settings"
@@ -18783,138 +24009,273 @@
 "el paràmetre d'especificació de camí «literal» global és incompatible amb "
 "tots els altres paràmetres d'especificació de camí globals"
 
+#: pathspec.c
 msgid "invalid parameter for pathspec magic 'prefix'"
 msgstr "paràmetre no vàlid per a la màgia d'especificació de camí «prefix»"
 
+#: pathspec.c
 #, c-format
 msgid "Invalid pathspec magic '%.*s' in '%s'"
 msgstr "Màgia d'especificació de camí no vàlida «%.*s» en «%s»"
 
+#: pathspec.c
 #, c-format
 msgid "Missing ')' at the end of pathspec magic in '%s'"
 msgstr "«)» mancant al final de la màgia d'especificació de camí en «%s»"
 
+#: pathspec.c
 #, c-format
 msgid "Unimplemented pathspec magic '%c' in '%s'"
 msgstr "Màgia d'especificació de camí no implementada «%c» en «%s»"
 
+#: pathspec.c
 #, c-format
 msgid "%s: 'literal' and 'glob' are incompatible"
 msgstr "%s: «literal» i «glob» són incompatibles"
 
+#: pathspec.c
 #, c-format
 msgid "'%s' is outside the directory tree"
 msgstr "«%s» és fora de l'arbre de directoris"
 
+#: pathspec.c
 #, c-format
 msgid "%s: '%s' is outside repository at '%s'"
 msgstr "%s: «%s» està fora del repositori en «%s»"
 
+#: pathspec.c
 #, c-format
 msgid "'%s' (mnemonic: '%c')"
 msgstr "«%s» (mnemònic: «%c»)"
 
+#: pathspec.c
 #, c-format
 msgid "%s: pathspec magic not supported by this command: %s"
 msgstr ""
 "%s: aquesta ordre no està admesa amb la màgia d'especificació de camí: %s"
 
+#: pathspec.c
 #, c-format
 msgid "pathspec '%s' is beyond a symbolic link"
 msgstr "l'especificació de camí «%s» és més enllà d'un enllaç simbòlic"
 
+#: pathspec.c
 #, c-format
 msgid "line is badly quoted: %s"
 msgstr "la línia no està ben envoltada per cometes: %s"
 
+#: pkt-line.c
 msgid "unable to write flush packet"
 msgstr "no s'ha pogut escriure el paquet de buidatge"
 
+#: pkt-line.c
 msgid "unable to write delim packet"
 msgstr "no s'ha pogut escriure el paquet delim"
 
+#: pkt-line.c
 msgid "unable to write response end packet"
 msgstr "no s'ha pogut escriure el paquet de final de resposta"
 
+#: pkt-line.c
 msgid "flush packet write failed"
 msgstr "s'ha produït un error en escriure el paquet de buidatge"
 
+#: pkt-line.c
 msgid "protocol error: impossibly long line"
 msgstr "error de protocol: longitud de línia impossible"
 
+#: pkt-line.c
 msgid "packet write with format failed"
 msgstr "ha fallat l'escriptura del paquet amb format"
 
+#: pkt-line.c
 msgid "packet write failed - data exceeds max packet size"
 msgstr ""
 "no s'ha pogut escriure el paquet - les dades excedeixen la mida màxima del "
 "paquet"
 
+#: pkt-line.c
 #, c-format
 msgid "packet write failed: %s"
 msgstr "no s'ha pogut escriure el paquet: %s"
 
+#: pkt-line.c
 msgid "read error"
 msgstr "error de lectura"
 
+#: pkt-line.c
 msgid "the remote end hung up unexpectedly"
 msgstr "el remot ha penjat inesperadament"
 
+#: pkt-line.c
 #, c-format
 msgid "protocol error: bad line length character: %.4s"
 msgstr "error de protocol: caràcter de longitud de línia erroni: %.4s"
 
+#: pkt-line.c
 #, c-format
 msgid "protocol error: bad line length %d"
 msgstr "error de protocol: longitud de línia errònia %d"
 
+#: pkt-line.c sideband.c
 #, c-format
 msgid "remote error: %s"
 msgstr "error remot: %s"
 
+#: preload-index.c
 msgid "Refreshing index"
 msgstr "S'està actualitzant l'índex"
 
+#: preload-index.c
 #, c-format
 msgid "unable to create threaded lstat: %s"
 msgstr "no s'han pogut crear lstat amb fils %s"
 
+#: pretty.c
 msgid "unable to parse --pretty format"
 msgstr "no s'ha pogut analitzar el format --pretty"
 
+# lazy → tardà as in “lazy evaluation”
+# 2 línies OK?
+#: promisor-remote.c
+msgid "lazy fetching disabled; some objects may not be available"
+msgstr ""
+"s'ha inhabilitat l'obtenció tardana; por ser que alguns objectes\n"
+"no estiguin disponibles"
+
+#: promisor-remote.c
 msgid "promisor-remote: unable to fork off fetch subprocess"
 msgstr "promisor-remote: no es pot bifurcar el subprocés d'obtenció"
 
+#: promisor-remote.c
 msgid "promisor-remote: could not write to fetch subprocess"
 msgstr "promisor-remote: no s'ha pogut escriure per al subprocés d'obtenció"
 
+#: promisor-remote.c
 msgid "promisor-remote: could not close stdin to fetch subprocess"
 msgstr "promisor-remote: no s'ha pogut tancar stdin al subprocés d'obtenció"
 
+#: promisor-remote.c
 #, c-format
 msgid "promisor remote name cannot begin with '/': %s"
 msgstr "el nom remot «promisor» no pot començar amb «/»: %s"
 
+#: promisor-remote.c
 #, c-format
 msgid "could not fetch %s from promisor remote"
 msgstr "no s'ha pogut obtenir «%s» del «promisor» remot"
 
+#: protocol-caps.c
 msgid "object-info: expected flush after arguments"
 msgstr "object-info: s'esperava una neteja després dels arguments"
 
+#: prune-packed.c
 msgid "Removing duplicate objects"
 msgstr "S'estan eliminant els objectes duplicats"
 
+#: pseudo-merge.c
+#, c-format
+msgid "failed to load pseudo-merge regex for %s: '%s'"
+msgstr ""
+"no s'ha pogut carregar l'expressió regular de pseudo-fusió per a %s: «%s»"
+
+# gerundi → futur?
+# default → valor predeterminat?
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be non-negative, using default"
+msgstr "%s ha de ser no negatiu, s'usarà el valor predeterminat"
+
+# gerundi → futur?
+# default → valor predeterminat?
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be between 0 and 1, using default"
+msgstr "%s ha d'estar entre 0 i 1, s'usarà el valor predeterminat"
+
+# gerundi → futur?
+# default → valor predeterminat?
+#: pseudo-merge.c
+#, c-format
+msgid "%s must be positive, using default"
+msgstr "%s ha de ser positiu, s'usarà el valor predeterminat"
+
+#: pseudo-merge.c
+#, c-format
+msgid "pseudo-merge group '%s' missing required pattern"
+msgstr "manca un patró requerit al grup de pseudo-fusió «%s»"
+
+#: pseudo-merge.c
+#, c-format
+msgid "pseudo-merge group '%s' has unstable threshold before stable one"
+msgstr ""
+"el grup de pseudo-fusió «%s» té un llindar inestable abans de l'estable"
+
+#: pseudo-merge.c
+#, c-format
+msgid ""
+"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)"
+msgstr ""
+"l'expressió regular de pseudo-fusions procedent de la configuració\n"
+"té massa grups de captura (màxim=%<PRIuMAX>)"
+
+# lectura ampliada o pseudo-fusions ampliades?
+# read → lectura / llegit?
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"la lectura de pseudo-fusions ampliades és fora de rang  (%<PRIuMAX> >= "
+"%<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr ""
+"l'entrada de pseudo-fusions ampliades és massa curta (%<PRIuMAX> >= "
+"%<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>"
+msgstr ""
+"no s'ha pogut trobar una pseudo-fusió per a la comissió %s\n"
+"a la posició %<PRIuMAX>"
+
+# consulta ampliada o pseudo-fusions ampliades?
+#: pseudo-merge.c
+#, c-format
+msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)"
+msgstr ""
+"la consulta de pseudo-fusions ampliades és fora de rang (%<PRIu32> >= "
+"%<PRIu32>)"
+
+# read → lectura?
+#: pseudo-merge.c
+#, c-format
+msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)"
+msgstr "lectura fora de rang: (%<PRIuMAX> >= %<PRIuMAX>)"
+
+#: pseudo-merge.c
+#, c-format
+msgid "could not read extended pseudo-merge table for commit %s"
+msgstr ""
+"no s'ha pogut llegir la taula de pseudo-fusions ampliada per a la comissió %s"
+
+#: range-diff.c
 msgid "could not start `log`"
 msgstr "no s'ha pogut iniciar «log»"
 
+#: range-diff.c
 msgid "could not read `log` output"
 msgstr "no s'ha pogut llegir la sortida de «log»"
 
+#: range-diff.c sequencer.c
 #, c-format
 msgid "could not parse commit '%s'"
 msgstr "no s'ha pogut analitzar la comissió «%s»"
 
+#: range-diff.c
 #, c-format
 msgid ""
 "could not parse first line of `log` output: did not start with 'commit ': "
@@ -18923,51 +24284,64 @@
 "no s'ha pogut analitzar la primera línia de la sortida «log»: no començava "
 "amb «commit»: «%s»"
 
+#: range-diff.c
 #, c-format
 msgid "could not parse git header '%.*s'"
 msgstr "no s'ha pogut llegir la capçalera de la gif «%.*s»"
 
+#: range-diff.c
 msgid "failed to generate diff"
 msgstr "s'ha produït un error en generar el diff"
 
+#: range-diff.c
 #, c-format
 msgid "could not parse log for '%s'"
 msgstr "no s'ha pogut llegir el fitxer de registre per a «%s»"
 
+#: reachable.c
 #, c-format
 msgid "invalid extra cruft tip: '%s'"
 msgstr "punta extra extra no vàlida: «%s»"
 
+#: reachable.c
 msgid "unable to enumerate additional recent objects"
 msgstr "no s'han pogut enumerar els objectes recents addicionals"
 
+#: read-cache.c
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
 msgstr "no s'afegirà l'àlies «%s»: («%s» ja existeix en l'índex)"
 
+#: read-cache.c
 msgid "cannot create an empty blob in the object database"
 msgstr "no es pot crear un blob buit a la base de dades d'objectes"
 
+#: read-cache.c
 #, c-format
 msgid "%s: can only add regular files, symbolic links or git-directories"
 msgstr ""
 "%s: només pot afegir fitxers normals, enllaços simbòlics o directoris git"
 
+#: read-cache.c
 #, c-format
 msgid "unable to index file '%s'"
 msgstr "no es pot llegir indexar el fitxer «%s»"
 
+#: read-cache.c
 #, c-format
 msgid "unable to add '%s' to index"
 msgstr "no s'ha pogut afegir «%s» a l'índex"
 
+#: read-cache.c
 #, c-format
 msgid "'%s' appears as both a file and as a directory"
 msgstr "«%s» apareix com a fitxer i com a directori"
 
+#: read-cache.c
 msgid "Refresh index"
 msgstr "Actualitza l'índex"
 
+#: read-cache.c
 #, c-format
 msgid ""
 "index.version set, but the value is invalid.\n"
@@ -18976,6 +24350,7 @@
 "index.version està establerta, però el valor no és vàlid.\n"
 "S'està usant la versió %i"
 
+#: read-cache.c
 #, c-format
 msgid ""
 "GIT_INDEX_VERSION set, but the value is invalid.\n"
@@ -18984,114 +24359,143 @@
 "GIT_INDEX_VERSION està establerta, però el valor no és vàlid.\n"
 "S'està usant la versió %i"
 
+#: read-cache.c
 #, c-format
 msgid "bad signature 0x%08x"
 msgstr "signatura malmesa 0x%08x"
 
+#: read-cache.c
 #, c-format
 msgid "bad index version %d"
 msgstr "versió d'índex incorrecta %d"
 
+#: read-cache.c
 msgid "bad index file sha1 signature"
 msgstr "signatura sha1 malmesa al fitxer d'índex"
 
+#: read-cache.c
 #, c-format
 msgid "index uses %.4s extension, which we do not understand"
 msgstr "l'índex usa l'extensió %.4s, que no es pot entendre"
 
+#: read-cache.c
 #, c-format
 msgid "ignoring %.4s extension"
 msgstr "s'està ignorant l'extensió %.4s"
 
+#: read-cache.c
 #, c-format
 msgid "unknown index entry format 0x%08x"
 msgstr "format d'entrada d'índex desconeguda «0x%08x»"
 
+#: read-cache.c
 #, c-format
 msgid "malformed name field in the index, near path '%s'"
 msgstr "camp del nom mal formatat l'índex, camí a prop «%s»"
 
+#: read-cache.c
 msgid "unordered stage entries in index"
 msgstr "entrades «stage» no ordenades en l'índex"
 
+#: read-cache.c
 #, c-format
 msgid "multiple stage entries for merged file '%s'"
 msgstr "múltiples entrades «stage» per al fitxer fusionat «%s»"
 
+#: read-cache.c
 #, c-format
 msgid "unordered stage entries for '%s'"
 msgstr "entrades «stage» no ordenades per a «%s»"
 
+#: read-cache.c
 #, c-format
 msgid "unable to create load_cache_entries thread: %s"
 msgstr "no s'ha pogut crear fil «load_cache_entries»: %s"
 
+#: read-cache.c
 #, c-format
 msgid "unable to join load_cache_entries thread: %s"
 msgstr "no s'ha pogut unir al fil «load_cache_entries»: %s"
 
+#: read-cache.c
 #, c-format
 msgid "%s: index file open failed"
 msgstr "%s: ha fallat l'obertura del fitxer d'índex"
 
+#: read-cache.c
 #, c-format
 msgid "%s: cannot stat the open index"
 msgstr "%s: no es pot fer «stat» a l'índex obert"
 
+#: read-cache.c
 #, c-format
 msgid "%s: index file smaller than expected"
 msgstr "%s: fitxer d'índex més petit que s'esperava"
 
+#: read-cache.c
 #, c-format
 msgid "%s: unable to map index file%s"
 msgstr "%s: no es pot mapar el fitxer d'índex%s"
 
+#: read-cache.c
 #, c-format
 msgid "unable to create load_index_extensions thread: %s"
 msgstr "no s'ha pogut crear un fil «load_index_extensions»: %s"
 
+#: read-cache.c
 #, c-format
 msgid "unable to join load_index_extensions thread: %s"
 msgstr "no s'ha pogut unir un fil «load_index_extensions»: %s"
 
+#: read-cache.c
 #, c-format
 msgid "could not freshen shared index '%s'"
 msgstr "no s'ha pogut refrescar l'índex compartit «%s»"
 
+#: read-cache.c
 #, c-format
 msgid "broken index, expect %s in %s, got %s"
 msgstr "índex malmès, s'esperava %s a %s, s'ha rebut %s"
 
+#: read-cache.c
 msgid "cannot write split index for a sparse index"
 msgstr "no es pot escriure l'índex dividit per a un índex dispers"
 
+#: read-cache.c
 msgid "failed to convert to a sparse-index"
 msgstr "s'ha produït un error en convertir a un índex dispers"
 
+#: read-cache.c
 #, c-format
 msgid "unable to open git dir: %s"
 msgstr "no s'ha pogut obrir el directori git: %s"
 
+#: read-cache.c
 #, c-format
 msgid "unable to unlink: %s"
 msgstr "no s'ha pogut desenllaçar: %s"
 
+#: read-cache.c
 #, c-format
 msgid "cannot fix permission bits on '%s'"
 msgstr "no s'han pogut corregir els bits de permisos en «%s»"
 
+#: read-cache.c
 #, c-format
 msgid "%s: cannot drop to stage #0"
 msgstr "%s: no es pot baixar fins al «stage» #0"
 
+#: read-cache.c
 #, c-format
 msgid "unexpected diff status %c"
 msgstr "estat de diff inesperat %c"
 
+#: read-cache.c
 #, c-format
 msgid "remove '%s'\n"
 msgstr "elimina «%s»\n"
 
+#: rebase-interactive.c
 msgid ""
 "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
 "continue'.\n"
@@ -19101,6 +24505,7 @@
 "continue».\n"
 "O bé, podeu avortar el «rebase» amb «git rebase --abort».\n"
 
+#: rebase-interactive.c
 #, c-format
 msgid ""
 "unrecognized setting %s for option rebase.missingCommitsCheck. Ignoring."
@@ -19108,6 +24513,7 @@
 "no s'ha reconegut el paràmetre %s per rebase.missingCommitsCheck. S'està "
 "ignorant."
 
+#: rebase-interactive.c
 msgid ""
 "\n"
 "Commands:\n"
@@ -19160,20 +24566,22 @@
 "        (o línia única, si no hi ha cap comissió de fusió original "
 "especificada).\n"
 "        Useu -c <comissió> per a reescriure el missatge de la comissió.\n"
-"u, update-ref <ref> = segueix un marcador de posició per a actualitzar "
-"<ref>\n"
+"u, update-ref <referència> = segueix un marcador de posició per a "
+"actualitzar <ref>\n"
 "                      a aquesta posició en les comissions noves. La <ref> "
 "s'actualitza\n"
 "                      al final del «rebase»\n"
 "\n"
 "Es pot canviar l'ordre d'aquestes línies; s'executen de dalt a baix.\n"
 
+#: rebase-interactive.c
 #, c-format
 msgid "Rebase %s onto %s (%d command)"
 msgid_plural "Rebase %s onto %s (%d commands)"
 msgstr[0] "Fes «rebase» de %s a %s (%d ordre)"
 msgstr[1] "Fes «rebase» de %s a %s (%d ordres)"
 
+#: rebase-interactive.c
 msgid ""
 "\n"
 "Do not remove any line. Use 'drop' explicitly to remove a commit.\n"
@@ -19182,6 +24590,7 @@
 "No elimineu cap línia. Useu «drop» explícitament per a eliminar una "
 "comissió.\n"
 
+#: rebase-interactive.c
 msgid ""
 "\n"
 "If you remove a line here THAT COMMIT WILL BE LOST.\n"
@@ -19189,6 +24598,7 @@
 "\n"
 "Si elimineu una línia aquí, ES PERDRÀ AQUELLA COMISSIÓ.\n"
 
+#: rebase-interactive.c
 msgid ""
 "\n"
 "You are editing the todo file of an ongoing interactive rebase.\n"
@@ -19202,19 +24612,22 @@
 "    git rebase --continue\n"
 "\n"
 
+#: rebase-interactive.c
 msgid ""
 "\n"
 "However, if you remove everything, the rebase will be aborted.\n"
 "\n"
 msgstr ""
 "\n"
-"No obstant això, si elimineu tot, s'avortarà el «rebase».\n"
+"No obstant això, si ho elimineu tot, s'avortarà el «rebase».\n"
 "\n"
 
+#: rebase-interactive.c
 #, c-format
 msgid "could not write '%s'."
 msgstr "no s'ha pogut escriure a «%s»."
 
+#: rebase-interactive.c
 #, c-format
 msgid ""
 "Warning: some commits may have been dropped accidentally.\n"
@@ -19224,6 +24637,7 @@
 "accidentalment.\n"
 "Les comissions descartades (més nova a més vella):\n"
 
+#: rebase-interactive.c
 #, c-format
 msgid ""
 "To avoid this message, use \"drop\" to explicitly remove a commit.\n"
@@ -19240,113 +24654,146 @@
 "d'advertències.\n"
 "Els comportaments possibles són: ignore, warn, error.\n"
 
+#: rebase.c
 #, c-format
 msgid "%s: 'preserve' superseded by 'merges'"
 msgstr "%s: «conserva» substituït per «fusiona»"
 
+#: ref-filter.c wt-status.c
 msgid "gone"
 msgstr "no hi és"
 
+#: ref-filter.c
 #, c-format
 msgid "ahead %d"
 msgstr "davant per %d"
 
+#: ref-filter.c
 #, c-format
 msgid "behind %d"
 msgstr "darrere per %d"
 
+#: ref-filter.c
 #, c-format
 msgid "ahead %d, behind %d"
 msgstr "davant per %d, darrere per %d"
 
+#: ref-filter.c
 #, c-format
 msgid "%%(%.*s) does not take arguments"
 msgstr "%%(%.*s) no accepta arguments"
 
+#: ref-filter.c
 #, c-format
 msgid "unrecognized %%(%.*s) argument: %s"
 msgstr "argument %%(%.*s) desconegut: %s"
 
+#: ref-filter.c
 #, c-format
 msgid "expected format: %%(color:<color>)"
 msgstr "format esperat: %%(color:<color>)"
 
+#: ref-filter.c
 #, c-format
 msgid "unrecognized color: %%(color:%s)"
 msgstr "color no reconegut: %%(color:%s)"
 
+#: ref-filter.c
 #, c-format
 msgid "Integer value expected refname:lstrip=%s"
 msgstr "Valor enter esperat pel nom de referència:lstrip=%s"
 
+#: ref-filter.c
 #, c-format
 msgid "Integer value expected refname:rstrip=%s"
 msgstr "Valor enter esperat pel nom de referència:rstrip=%s"
 
+#: ref-filter.c
 #, c-format
 msgid "expected %%(trailers:key=<value>)"
-msgstr "s'esperava %%(trailers:key=<value>)"
+msgstr "s'esperava %%(trailers:key=<valor>)"
 
+#: ref-filter.c
 #, c-format
 msgid "unknown %%(trailers) argument: %s"
 msgstr "argument %%(trailers) desconegut: %s"
 
+#: ref-filter.c
 #, c-format
 msgid "positive value expected contents:lines=%s"
 msgstr "valor positiu esperat conté:lines=%s"
 
+#: ref-filter.c
 #, c-format
 msgid "argument expected for %s"
 msgstr "s'esperava un argument per a %s"
 
+#: ref-filter.c
 #, c-format
 msgid "positive value expected %s=%s"
 msgstr "valor positiu esperat %s=%s"
 
+#: ref-filter.c
 #, c-format
 msgid "cannot fully parse %s=%s"
 msgstr "no es pot analitzar completament %s=%s"
 
+#: ref-filter.c
 #, c-format
 msgid "value expected %s="
 msgstr "s'esperava un valor %s="
 
+#: ref-filter.c
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
 msgstr "valor positiu esperat «%s» a %%(%s)"
 
+#: ref-filter.c
 #, c-format
 msgid "expected format: %%(align:<width>,<position>)"
 msgstr "format esperat: %%(align:<amplada>,<posició>)"
 
+#: ref-filter.c
 #, c-format
 msgid "unrecognized position:%s"
 msgstr "posició no reconeguda:%s"
 
+#: ref-filter.c
 #, c-format
 msgid "unrecognized width:%s"
 msgstr "amplada no reconeguda:%s"
 
+#: ref-filter.c
 #, c-format
 msgid "unrecognized %%(%s) argument: %s"
 msgstr "argument %%(%s) desconegut: %s"
 
+#: ref-filter.c
 #, c-format
 msgid "positive width expected with the %%(align) atom"
 msgstr "amplada positiva esperada amb l'àtom %%(align)"
 
+#: ref-filter.c
 #, c-format
 msgid "expected format: %%(ahead-behind:<committish>)"
 msgstr "format esperat: %%(ahead-behind:<committish>)"
 
+#: ref-filter.c
+#, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "format esperat: %%(is-base:<committish>)"
+
+#: ref-filter.c
 #, c-format
 msgid "malformed field name: %.*s"
 msgstr "nom de camp mal format: %.*s"
 
+#: ref-filter.c
 #, c-format
 msgid "unknown field name: %.*s"
 msgstr "nom de camp desconegut: %.*s"
 
+#: ref-filter.c
 #, c-format
 msgid ""
 "not a git repository, but the field '%.*s' requires access to object data"
@@ -19354,117 +24801,147 @@
 "no és un repositori git, però el camp «%.*s» requereix accés a les dades de "
 "l'objecte"
 
+#: ref-filter.c
 #, c-format
 msgid "format: %%(%s) atom used without a %%(%s) atom"
 msgstr "format: l'àtom %%(%s) usat sense un àtom %%(%s)"
 
+#: ref-filter.c
 #, c-format
 msgid "format: %%(then) atom used more than once"
 msgstr "format: s'ha usat l'àtom %%(then) més d'un cop"
 
+#: ref-filter.c
 #, c-format
 msgid "format: %%(then) atom used after %%(else)"
 msgstr "format: s'ha usat l'àtom %%(then) després de %%(else)"
 
+#: ref-filter.c
 #, c-format
 msgid "format: %%(else) atom used more than once"
 msgstr "format: s'ha usat l'àtom %%(else) més d'un cop"
 
+#: ref-filter.c
 #, c-format
 msgid "format: %%(end) atom used without corresponding atom"
 msgstr "format: s'ha usat l'àtom %%(end) sense l'àtom corresponent"
 
+#: ref-filter.c
 #, c-format
 msgid "malformed format string %s"
 msgstr "cadena de format mal format %s"
 
+#: ref-filter.c
 #, c-format
 msgid "this command reject atom %%(%.*s)"
 msgstr "aquesta ordre rebutja l'àtom %%(%.*s)"
 
+#: ref-filter.c
 #, c-format
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
 msgstr "no es pot usar --format=%.*s amb --python, --shell, --tcl"
 
+#: ref-filter.c
 msgid "failed to run 'describe'"
 msgstr "no s'ha pogut executar «describe»"
 
+#: ref-filter.c
 #, c-format
 msgid "(no branch, rebasing %s)"
 msgstr "(sense branca, s'està fent «rebase» %s)"
 
+#: ref-filter.c
 #, c-format
 msgid "(no branch, rebasing detached HEAD %s)"
 msgstr "(sense branca, s'està fent «rebase» d'un «HEAD» separat %s)"
 
+#: ref-filter.c
 #, c-format
 msgid "(no branch, bisect started on %s)"
 msgstr "(sense branca, bisecció començada en %s)"
 
+#: ref-filter.c
 #, c-format
 msgid "(HEAD detached at %s)"
 msgstr "(HEAD separat a %s)"
 
+#: ref-filter.c
 #, c-format
 msgid "(HEAD detached from %s)"
 msgstr "(HEAD separat des de %s)"
 
+#: ref-filter.c
 msgid "(no branch)"
 msgstr "(sense branca)"
 
+#: ref-filter.c
 #, c-format
 msgid "missing object %s for %s"
 msgstr "manca l'objecte %s per a %s"
 
+#: ref-filter.c
 #, c-format
 msgid "parse_object_buffer failed on %s for %s"
 msgstr "parse_object_buffer ha fallat en %s per a %s"
 
+#: ref-filter.c
 #, c-format
 msgid "malformed object at '%s'"
 msgstr "objecte mal format a «%s»"
 
+#: ref-filter.c
 #, c-format
 msgid "ignoring ref with broken name %s"
 msgstr "s'està ignorant la referència amb nom malmès %s"
 
+#: ref-filter.c refs.c
 #, c-format
 msgid "ignoring broken ref %s"
 msgstr "s'està ignorant la referència malmesa %s"
 
+#: ref-filter.c
 #, c-format
 msgid "format: %%(end) atom missing"
 msgstr "format: manca l'àtom %%(end)"
 
+#: ref-filter.c
 #, c-format
 msgid "malformed object name %s"
 msgstr "nom d'objecte %s mal format"
 
+#: ref-filter.c
 #, c-format
 msgid "option `%s' must point to a commit"
 msgstr "l'opció «%s» ha d'apuntar a una comissió"
 
+#: ref-filter.h
 msgid "key"
 msgstr "clau"
 
+#: ref-filter.h
 msgid "field name to sort on"
 msgstr "nom del camp en el qual ordenar"
 
+#: ref-filter.h
 msgid "exclude refs which match pattern"
 msgstr "exclou refs que coincideixin amb el patró"
 
+#: reflog.c
 #, c-format
 msgid "not a reflog: %s"
-msgstr "no és un registre de referència: %s"
+msgstr "no és un registre de referències: %s"
 
+#: reflog.c
 #, c-format
 msgid "no reflog for '%s'"
-msgstr "cap registre de referència per a «%s»"
+msgstr "cap registre de referències per a «%s»"
 
+#: refs.c
 #, c-format
 msgid "%s does not point to a valid object!"
 msgstr "%s no apunta a un objecte vàlid"
 
+#: refs.c
 #, c-format
 msgid ""
 "Using '%s' as the name for the initial branch. This default branch name\n"
@@ -19492,231 +24969,438 @@
 "\n"
 "\tgit branch -m <nom>\n"
 
+#: refs.c
 #, c-format
 msgid "could not retrieve `%s`"
 msgstr "no s'ha pogut recuperar «%s»"
 
+#: refs.c
 #, c-format
 msgid "invalid branch name: %s = %s"
 msgstr "nom de branca no vàlida: %s = %s"
 
+#: refs.c
 #, c-format
 msgid "ignoring dangling symref %s"
-msgstr "s'està ignorant symref penjant %s"
+msgstr "s'està ignorant referència simbòlica despenjada %s"
 
+#: refs.c
 #, c-format
 msgid "log for ref %s has gap after %s"
 msgstr "registre per a ref %s té un buit després de %s"
 
+#: refs.c
 #, c-format
 msgid "log for ref %s unexpectedly ended on %s"
 msgstr "registre per als ref %s ha acabat inesperadament a %s"
 
+#: refs.c
 #, c-format
 msgid "log for %s is empty"
 msgstr "el registre per a %s és buit"
 
+#: refs.c
+msgid "refusing to force and skip creation of reflog"
+msgstr ""
+"s'ha rebutjat l'acció forçada i l'omissió de crear un registre de referències"
+
+#: refs.c
 #, c-format
 msgid "refusing to update ref with bad name '%s'"
 msgstr "s'està refusant la referència amb nom malmès «%s»"
 
+#: refs.c
+#, c-format
+msgid "refusing to update pseudoref '%s'"
+msgstr "s'ha rebutjat l'actualització de la pseudoreferència «%s»"
+
+#: refs.c
 #, c-format
 msgid "update_ref failed for ref '%s': %s"
 msgstr "ha fallat update_ref per a la ref «%s»: %s"
 
+#: refs.c
 #, c-format
 msgid "multiple updates for ref '%s' not allowed"
 msgstr "no es permeten múltiples actualitzacions per a la referència «%s»"
 
+#: refs.c
 msgid "ref updates forbidden inside quarantine environment"
 msgstr "no està permès actualitzar les referències en un entorn de quarantena"
 
+#: refs.c
 msgid "ref updates aborted by hook"
 msgstr "les actualitzacions de referències s'han avortat per un lligam"
 
+#: refs.c
 #, c-format
 msgid "'%s' exists; cannot create '%s'"
 msgstr "«%s» existeix; no es pot crear «%s»"
 
+#: refs.c
 #, c-format
 msgid "cannot process '%s' and '%s' at the same time"
 msgstr "no es poden processar «%s» i «%s» a la vegada"
 
+#: refs.c
 #, c-format
 msgid "could not delete reference %s: %s"
 msgstr "no s'ha pogut suprimir la referència %s: %s"
 
+#: refs.c
 #, c-format
 msgid "could not delete references: %s"
 msgstr "no s'han pogut suprimir les referències: %s"
 
+# 2 línies OK?
+#: refs.c
+#, c-format
+msgid "Finished dry-run migration of refs, the result can be found at '%s'\n"
+msgstr ""
+"S'ha acabat la prova no destructiva de migració de referències;\n"
+"el resultat es pot trobar a «%s»\n"
+
+# migració OK?
+#: refs.c
+#, c-format
+msgid "could not remove temporary migration directory '%s'"
+msgstr "no s'ha pogut eliminar el directori temporal de migració «%s»"
+
+# migrar OK?
+#: refs.c
+#, c-format
+msgid "migrated refs can be found at '%s'"
+msgstr "les referències migrades es poden trobar en «%s»"
+
+#: refs/files-backend.c refs/reftable-backend.c
+#, c-format
+msgid ""
+"cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
+msgstr ""
+"no puc bloquejar la referència«%s»: s'esperava una referència\n"
+"simbòlica amb destinació «%s» però és una referència regular"
+
+#: refs/files-backend.c
+#, c-format
+msgid "cannot open directory %s"
+msgstr "no es pot obrir el directori «%s»"
+
+#: refs/files-backend.c
+msgid "Checking references consistency"
+msgstr "S'està comprovant la consistència de les referències"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname is dangerous: %s"
+msgstr "el nom de referència és perillós: %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "trying to write ref '%s' with nonexistent object %s"
+msgstr ""
+"s'està intentant escriure la referència «%s» amb l'objecte que no existeix %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "trying to write non-commit object %s to branch '%s'"
+msgstr ""
+"s'està intentant escriure un objecte no de comissió %s en la branca «%s»"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid ""
+"multiple updates for 'HEAD' (including one via its referent '%s') are not "
+"allowed"
+msgstr ""
+"no es permeten actualitzacions múltiples de «HEAD» (inclosa una feta a "
+"través del\n"
+"seu referent «%s»)"
+
+# bloquejar → blocar
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': unable to resolve reference '%s'"
+msgstr ""
+"no es pot bloquejar la referència «%s»: no s'ha pogut resoldre la referència "
+"«%s»"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': error reading reference"
+msgstr "no es pot bloquejar la referència «%s»: error en llegir la referència"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid ""
+"multiple updates for '%s' (including one via symref '%s') are not allowed"
+msgstr ""
+"no es permeten les actualitzacions múltiples per a «%s» (inclosa una a\n"
+"través de la referència simbòlica «%s»"
+
+# bloquejar→blocar?
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': reference already exists"
+msgstr "no puc bloquejar la referència «%s»: la referència ja existeix"
+
+# massa llarg?
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': reference is missing but expected %s"
+msgstr ""
+"no puc bloquejar la referència «%s»: manca la referència però s'esperava %s"
+
+# blocar→bloquejar?
+#: refs/reftable-backend.c
+#, c-format
+msgid "cannot lock ref '%s': is at %s but expected %s"
+msgstr "no puc bloquejar la referència «%s»: és en %s però s'esperava %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "reftable: transaction prepare: %s"
+msgstr "taula de referències: prepara transacció: %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "reftable: transaction failure: %s"
+msgstr "taula de referències: fallada de transacció: %s"
+
+# stack→pila OK?
+#: refs/reftable-backend.c
+#, c-format
+msgid "unable to compact stack: %s"
+msgstr "no es pot compactar la pila: %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname %s not found"
+msgstr "no s'ha trobat el nom de referència %s"
+
+#: refs/reftable-backend.c
+#, c-format
+msgid "refname %s is a symbolic ref, copying it is not supported"
+msgstr ""
+"el nom de referència %s és una referència simbòlica: no es permet copiar"
+
+#: refspec.c
 #, c-format
 msgid "invalid refspec '%s'"
 msgstr "refspec no vàlida: «%s»"
 
+#: remote-curl.c
 #, c-format
 msgid "invalid quoting in push-option value: '%s'"
 msgstr "citació no vàlida en el valor de l'opció de pujada: «%s»"
 
+# object-format no traduït perquè és part de --show-object-format
+#: remote-curl.c
+#, c-format
+msgid "unknown value for object-format: %s"
+msgstr "valor desconegut per a l'object-format: %s"
+
+#: remote-curl.c
 #, c-format
 msgid "%sinfo/refs not valid: is this a git repository?"
 msgstr "%sinfo/refs no vàlides: és un repositori git?"
 
+#: remote-curl.c
 msgid "invalid server response; expected service, got flush packet"
 msgstr ""
 "resposta del servidor no és vàlida; el servei esperat, ha rebut in paquet de "
 "neteja"
 
+#: remote-curl.c
 #, c-format
 msgid "invalid server response; got '%s'"
 msgstr "resposta del servidor no vàlida; s'ha obtingut «%s»"
 
+#: remote-curl.c
 #, c-format
 msgid "repository '%s' not found"
 msgstr "no s'ha trobat el repositori «%s»"
 
+#: remote-curl.c
 #, c-format
 msgid "Authentication failed for '%s'"
 msgstr "S'ha produït un error en autenticar per «%s»"
 
+#: remote-curl.c
 #, c-format
 msgid "unable to access '%s' with http.pinnedPubkey configuration: %s"
 msgstr "no es pot accedir a «%s» la configuració de http.pinnedPubkey :%s"
 
+#: remote-curl.c
 #, c-format
 msgid "unable to access '%s': %s"
 msgstr "no s'ha pogut accedir a «%s»: %s"
 
+#: remote-curl.c
 #, c-format
 msgid "redirecting to %s"
 msgstr "s'està redirigint a %s"
 
+#: remote-curl.c
 msgid "shouldn't have EOF when not gentle on EOF"
 msgstr "no hauria de tenir EOF quan s'és lax amb els EOF"
 
+#: remote-curl.c
 msgid "remote server sent unexpected response end packet"
 msgstr "el servidor remot ha enviat un paquet de final de resposta inesperat"
 
+#: remote-curl.c
 msgid "unable to rewind rpc post data - try increasing http.postBuffer"
 msgstr ""
 "no s'han pogut rebobinar les dades de publicació rpc - proveu d'augmentar "
 "http.postBuffer"
 
+#: remote-curl.c
 #, c-format
 msgid "remote-curl: bad line length character: %.4s"
 msgstr "remote-curl: caràcter de longitud de línia erroni: %.4s"
 
+#: remote-curl.c
 msgid "remote-curl: unexpected response end packet"
 msgstr "remote-curl: paquet final de resposta inesperat"
 
+#: remote-curl.c
 #, c-format
 msgid "RPC failed; %s"
 msgstr "RPC ha fallat; %s"
 
+#: remote-curl.c
 msgid "cannot handle pushes this big"
 msgstr "no es pot gestionar pujades tan grans"
 
+#: remote-curl.c
 #, c-format
 msgid "cannot deflate request; zlib deflate error %d"
 msgstr "no es pot descomprimir la sol·licitud; error de deflate zlib %d"
 
+#: remote-curl.c
 #, c-format
 msgid "cannot deflate request; zlib end error %d"
 msgstr ""
 "no es pot descomprimir la sol·licitud; error de finalització de zlib %d"
 
+#: remote-curl.c
 #, c-format
 msgid "%d bytes of length header were received"
-msgstr "s'han rebut %d bytes de longitud de capçalera"
+msgstr "s'han rebut %d octets de longitud de capçalera"
 
+#: remote-curl.c
 #, c-format
 msgid "%d bytes of body are still expected"
-msgstr "encara s'esperen %d bytes del cos"
+msgstr "encara s'esperen %d octets del cos"
 
+#: remote-curl.c
 msgid "dumb http transport does not support shallow capabilities"
 msgstr "el transport ximple http no admet capacitats superficials"
 
+#: remote-curl.c
 msgid "fetch failed."
 msgstr "l'obtenció ha fallat."
 
+#: remote-curl.c
 msgid "cannot fetch by sha1 over smart http"
 msgstr "no s'ha pogut obtenir per sha1 a través de l'http intel·ligent"
 
+#: remote-curl.c
 #, c-format
 msgid "protocol error: expected sha/ref, got '%s'"
 msgstr "error de protocol: s'esperava sha/ref, s'ha obtingut «%s»"
 
+#: remote-curl.c
 #, c-format
 msgid "http transport does not support %s"
 msgstr "El transport http no admet %s"
 
+#: remote-curl.c
 msgid "protocol error: expected '<url> <path>', missing space"
 msgstr ""
 "s'ha produït un error de protocol: s'esperava «<url> <camí>», falta espai"
 
+#: remote-curl.c
 #, c-format
 msgid "failed to download file at URL '%s'"
 msgstr "no s'ha pogut baixar el fitxer a l'URL «%s»"
 
+#: remote-curl.c
 msgid "git-http-push failed"
 msgstr "git-http-push ha fallat"
 
+#: remote-curl.c
 msgid "remote-curl: usage: git remote-curl <remote> [<url>]"
-msgstr "remote-curl: ús: git remote-curl <remote> [<url>]"
+msgstr "remote-curl: ús: git remote-curl <remot> [<url>]"
 
+#: remote-curl.c
 msgid "remote-curl: error reading command stream from git"
 msgstr "remote-curl: error en llegir el flux d'ordres del git"
 
+#: remote-curl.c
 msgid "remote-curl: fetch attempted without a local repo"
 msgstr "remote-curl: s'ha intentat l'obtenció sense un repositori local"
 
+#: remote-curl.c
 #, c-format
 msgid "remote-curl: unknown command '%s' from git"
 msgstr "remote-curl: ordre «%s» desconeguda del git"
 
+#: remote.c
 #, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
 msgstr ""
 "l'abreviatura del fitxer de configuració remot no pot començar amb «/»: %s"
 
+#: remote.c
 msgid "more than one receivepack given, using the first"
 msgstr "més d'un paquet de recepció donat, usant el primer"
 
+#: remote.c
 msgid "more than one uploadpack given, using the first"
 msgstr "més d'un paquet de càrrega donat, usant el primer"
 
+#: remote.c
 #, c-format
 msgid "unrecognized value transfer.credentialsInUrl: '%s'"
 msgstr "valor no conegut per a transfer.credentialsInUrl: «%s»"
 
+#: remote.c
 #, c-format
 msgid "URL '%s' uses plaintext credentials"
 msgstr "L'URL «%s» utilitza credencials en text pla"
 
+#: remote.c
 #, c-format
 msgid "Cannot fetch both %s and %s to %s"
 msgstr "No es poden obtenir ambdós %s i %s a %s"
 
+#: remote.c
 #, c-format
 msgid "%s usually tracks %s, not %s"
 msgstr "%s generalment segueix %s, no %s"
 
+#: remote.c
 #, c-format
 msgid "%s tracks both %s and %s"
 msgstr "%s segueix ambdós %s i %s"
 
+#: remote.c
 #, c-format
 msgid "key '%s' of pattern had no '*'"
 msgstr "la clau «%s» del patró no té «*»"
 
+#: remote.c
 #, c-format
 msgid "value '%s' of pattern has no '*'"
 msgstr "el valor «%s» del patró no té «*»"
 
+#: remote.c
 #, c-format
 msgid "src refspec %s does not match any"
 msgstr "l'especificació de referència font %s no coincideix amb cap referència"
 
+#: remote.c
 #, c-format
 msgid "src refspec %s matches more than one"
 msgstr ""
@@ -19726,6 +25410,7 @@
 #. <remote> <src>:<dst>" push, and "being pushed ('%s')" is
 #. the <src>.
 #.
+#: remote.c
 #, c-format
 msgid ""
 "The destination you provided is not a full refname (i.e.,\n"
@@ -19748,6 +25433,7 @@
 "\n"
 "Res d'això ha funcionat. Cal que proporcioneu una referència completa."
 
+#: remote.c
 #, c-format
 msgid ""
 "The <src> part of the refspec is a commit object.\n"
@@ -19759,6 +25445,7 @@
 "Voleu crear una branca nova empenyent a\n"
 "«%s:refs/heads/%s»?"
 
+#: remote.c
 #, c-format
 msgid ""
 "The <src> part of the refspec is a tag object.\n"
@@ -19768,6 +25455,7 @@
 "La part <src> de l'especificació de la referència és un objecte d'etiqueta.\n"
 "Voleu crear una etiqueta pujant-la a «%s:refs/tags/%s»?"
 
+#: remote.c
 #, c-format
 msgid ""
 "The <src> part of the refspec is a tree object.\n"
@@ -19777,6 +25465,7 @@
 "La part <src> de l'especificació de la referència és un objecte d'arbre.\n"
 "Voleu crear una etiqueta pujant-la a «%s:refs/tags/%s»?"
 
+#: remote.c
 #, c-format
 msgid ""
 "The <src> part of the refspec is a blob object.\n"
@@ -19787,93 +25476,116 @@
 "Voleu posar una etiqueta al blob nou mitjançant la pujada a\n"
 "?«%s:refs/tags/%s»?"
 
+#: remote.c
 #, c-format
 msgid "%s cannot be resolved to branch"
 msgstr "«%s» no es pot resoldre a una branca"
 
+#: remote.c
 #, c-format
 msgid "unable to delete '%s': remote ref does not exist"
 msgstr "no s'ha pogut suprimir «%s»: la referència remota no existeix"
 
+#: remote.c
 #, c-format
 msgid "dst refspec %s matches more than one"
 msgstr ""
 "l'especificació de la referència dst %s coincideixen amb més d'una referència"
 
+#: remote.c
 #, c-format
 msgid "dst ref %s receives from more than one src"
 msgstr "l'especificació de la referència dst %s rep més d'una referència src"
 
+#: remote.c
 msgid "HEAD does not point to a branch"
 msgstr "HEAD no assenyala cap branca"
 
+#: remote.c
 #, c-format
 msgid "no such branch: '%s'"
 msgstr "no existeix la branca: «%s»"
 
+#: remote.c
 #, c-format
 msgid "no upstream configured for branch '%s'"
 msgstr "cap font configurada per a la branca «%s»"
 
+#: remote.c
 #, c-format
 msgid "upstream branch '%s' not stored as a remote-tracking branch"
 msgstr "la branca font «%s» no s'emmagatzema com a branca amb seguiment remot"
 
+#: remote.c
 #, c-format
 msgid "push destination '%s' on remote '%s' has no local tracking branch"
 msgstr ""
 "el destí de pujada «%s» en el remot «%s» no té cap branca amb seguiment remot"
 
+#: remote.c
 #, c-format
 msgid "branch '%s' has no remote for pushing"
 msgstr "la branca «%s» no té cap remot al qual pujar"
 
+#: remote.c
 #, c-format
 msgid "push refspecs for '%s' do not include '%s'"
 msgstr "les especificacions de referència de pujada «%s» no inclouen «%s»"
 
+#: remote.c
 msgid "push has no destination (push.default is 'nothing')"
 msgstr "push no té destí (push.default és «nothing»)"
 
+#: remote.c
 msgid "cannot resolve 'simple' push to a single destination"
 msgstr "no es pot resoldre una pujada «simple» a un sol destí"
 
+#: remote.c
 #, c-format
 msgid "couldn't find remote ref %s"
 msgstr "no s'ha pogut trobar la referència remota %s"
 
+#: remote.c
 #, c-format
 msgid "* Ignoring funny ref '%s' locally"
 msgstr "* S'estan ignorant les referències «%s» localment"
 
+#: remote.c
 #, c-format
 msgid "Your branch is based on '%s', but the upstream is gone.\n"
 msgstr "La vostra branca està basada en «%s», però la font no hi és.\n"
 
+#: remote.c
 msgid "  (use \"git branch --unset-upstream\" to fixup)\n"
 msgstr "  (useu «git branch --unset-upstream» per a arreglar-ho)\n"
 
+#: remote.c
 #, c-format
 msgid "Your branch is up to date with '%s'.\n"
 msgstr "La vostra branca està al dia amb «%s».\n"
 
+#: remote.c
 #, c-format
 msgid "Your branch and '%s' refer to different commits.\n"
-msgstr "La vostra branca i «%s» es refereixen a diferents comissions.\n"
+msgstr "La vostra branca i «%s» es refereixen a  comissions.\n"
 
+#: remote.c
 #, c-format
 msgid "  (use \"%s\" for details)\n"
 msgstr "  (useu «%s» per a detalls)\n"
 
+#: remote.c
 #, c-format
 msgid "Your branch is ahead of '%s' by %d commit.\n"
 msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
 msgstr[0] "La vostra branca està %2$d comissió per davant de «%1$s».\n"
 msgstr[1] "La vostra branca està %2$d comissions per davant de «%1$s».\n"
 
+#: remote.c
 msgid "  (use \"git push\" to publish your local commits)\n"
 msgstr "  (useu «git push» per a publicar les vostres comissions locals)\n"
 
+#: remote.c
 #, c-format
 msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
@@ -19885,9 +25597,11 @@
 "La vostra branca està %2$d comissions per darrere de «%1$s», i pot avançar-"
 "se ràpidament.\n"
 
+#: remote.c
 msgid "  (use \"git pull\" to update your local branch)\n"
 msgstr "  (useu «git pull» per a actualitzar la vostra branca local)\n"
 
+#: remote.c
 #, c-format
 msgid ""
 "Your branch and '%s' have diverged,\n"
@@ -19902,285 +25616,387 @@
 "La vostra branca i «%s» han divergit,\n"
 "i tenen %d i %d comissions distintes cada una, respectivament.\n"
 
+#: remote.c
 msgid ""
 "  (use \"git pull\" if you want to integrate the remote branch with yours)\n"
 msgstr ""
 "  (utilitzeu «git pull» si voleu integrar la branca remota amb la vostra)\n"
 
+#: remote.c
 #, c-format
 msgid "cannot parse expected object name '%s'"
 msgstr "no es pot analitzar el nom de l'objecte esperat «%s»"
 
+#: remote.c
 #, c-format
 msgid "cannot strip one component off url '%s'"
 msgstr "no es pot despullar un component de l'url «%s»"
 
+#: replace-object.c
 #, c-format
 msgid "bad replace ref name: %s"
 msgstr "nom de la referència reemplaçada incorrecte: %s"
 
+#: replace-object.c
 #, c-format
 msgid "duplicate replace ref: %s"
 msgstr "duplica les referències reemplaçades: %s"
 
+#: replace-object.c
 #, c-format
 msgid "replace depth too high for object %s"
 msgstr "la profunditat de reemplaçament és massa alta per l'objecte %s"
 
+#: rerere.c
 msgid "corrupt MERGE_RR"
 msgstr "MERGE_RR corrupte"
 
+#: rerere.c
 msgid "unable to write rerere record"
 msgstr "no s'ha pogut escriure el registre «rerere»"
 
+#: rerere.c
 #, c-format
 msgid "there were errors while writing '%s' (%s)"
 msgstr "s'han produït errors en escriure «%s» (%s)"
 
+#: rerere.c
 #, c-format
 msgid "could not parse conflict hunks in '%s'"
 msgstr "no s'han pogut analitzar els pedaços en conflicte a «%s»"
 
+#: rerere.c
 #, c-format
 msgid "failed utime() on '%s'"
 msgstr "s'ha produït un error en fer «failed utime()» a «%s»"
 
+#: rerere.c
 #, c-format
 msgid "writing '%s' failed"
 msgstr "s'ha produït un error en escriure «%s»"
 
+#: rerere.c
 #, c-format
 msgid "Staged '%s' using previous resolution."
 msgstr "«Staged» «%s» utilitzant una resolució anterior."
 
+#: rerere.c
 #, c-format
 msgid "Recorded resolution for '%s'."
 msgstr "Es recorda la resolució per a «%s»."
 
+#: rerere.c
 #, c-format
 msgid "Resolved '%s' using previous resolution."
 msgstr "S'ha resolt «%s» usant una resolució anterior."
 
+#: rerere.c
 #, c-format
 msgid "cannot unlink stray '%s'"
 msgstr "no es pot desenllaçar «%s» (extraviat)"
 
+#: rerere.c
 #, c-format
 msgid "Recorded preimage for '%s'"
 msgstr "Imatge prèvia registrada per a «%s»"
 
+#: rerere.c
 #, c-format
 msgid "failed to update conflicted state in '%s'"
 msgstr "ha fallat en actualitzar l'estat en conflicte a «%s»"
 
+#: rerere.c
 #, c-format
 msgid "no remembered resolution for '%s'"
 msgstr "no hi ha cap resolució recordada per a «%s»"
 
+#: rerere.c
 #, c-format
 msgid "Updated preimage for '%s'"
 msgstr "Imatge prèvia actualitzada per a «%s»"
 
+#: rerere.c
 #, c-format
 msgid "Forgot resolution for '%s'\n"
 msgstr "S'ha oblidat la resolució per a «%s»\n"
 
+#: rerere.c
 msgid "unable to open rr-cache directory"
 msgstr "no s'ha pogut obrir el directori rr-cache"
 
+#: rerere.h
 msgid "update the index with reused conflict resolution if possible"
 msgstr ""
 "actualitza l'índex amb la resolució de conflictes reusada si és possible"
 
+#: reset.c
 msgid "could not determine HEAD revision"
 msgstr "no s'ha pogut determinar la revisió de HEAD"
 
+#: reset.c sequencer.c
 #, c-format
 msgid "failed to find tree of %s"
 msgstr "s'ha produït un error en cercar l'arbre de %s"
 
+#: revision.c
 #, c-format
 msgid "unsupported section for hidden refs: %s"
 msgstr "secció d'índex no compatible per a les referències ocultes: %s"
 
+#: revision.c
 msgid "--exclude-hidden= passed more than once"
 msgstr "--exclude-hidden= passat més d'una vegada"
 
+#: revision.c
 #, c-format
 msgid "resolve-undo records `%s` which is missing"
 msgstr "resolve-undo indica «%s» que manquen"
 
+#: revision.c
 #, c-format
-msgid "could not get commit for ancestry-path argument %s"
-msgstr "no s'ha pogut obtenir la comissió per a l'argument d'ancestry-path %s"
+msgid "%s exists but is a symbolic ref"
+msgstr "%s existeix però és una referència simbòlica"
 
+#: revision.c
+msgid ""
+"--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD or REBASE_HEAD"
+msgstr ""
+"--merge requereix una de les pseudoreferències MERGE_HEAD, CHERRY_PICK_HEAD, "
+"REVERT_HEAD o REBASE_HEAD"
+
+#: revision.c
+#, c-format
+msgid "could not get commit for --ancestry-path argument %s"
+msgstr ""
+"no s'ha pogut obtenir una comissió per a l'argument %s d'--ancestry-path"
+
+#: revision.c
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<packfile> ja no s'admet"
 
+#: revision.c
 #, c-format
 msgid "invalid option '%s' in --stdin mode"
 msgstr "opció no vàlida: «%s» en mode --stdin"
 
+#: revision.c
 msgid "your current branch appears to be broken"
 msgstr "la vostra branca actual sembla malmesa"
 
+#: revision.c
 #, c-format
 msgid "your current branch '%s' does not have any commits yet"
 msgstr "la branca actual «%s» encara no té cap comissió"
 
+#: revision.c
 msgid "object filtering requires --objects"
 msgstr "el filtratge d'objectes requereix --objects"
 
+#: revision.c
 msgid "-L does not yet support diff formats besides -p and -s"
 msgstr "-L no és encara compatible amb formats que no siguin «-p» o «-s»"
 
+#: run-command.c
 #, c-format
 msgid "cannot create async thread: %s"
 msgstr "no s'ha pogut crear fil «async»: %s"
 
+#: scalar.c worktree.c
 #, c-format
 msgid "'%s' does not exist"
 msgstr "«%s» no existeix"
 
+#: scalar.c
 #, c-format
 msgid "could not switch to '%s'"
 msgstr "no s'ha pogut commutar a «%s»"
 
+#: scalar.c
 msgid "need a working directory"
 msgstr "cal un directori de treball"
 
+#: scalar.c
 msgid "Scalar enlistments require a worktree"
 msgstr "Els allistaments escalars requereixen un arbre de treball"
 
+#: scalar.c
 #, c-format
 msgid "could not configure %s=%s"
 msgstr "no s'ha pogut configurar %s=%s"
 
+#: scalar.c
 msgid "could not configure log.excludeDecoration"
 msgstr "no s'ha pogut configurar log.excludeDecoration"
 
+#: scalar.c
 msgid "could not add enlistment"
 msgstr "no s'ha afegit a l'allistament"
 
+#: scalar.c
 msgid "could not set recommended config"
 msgstr "no s'ha pogut establir la configuració recomanada"
 
+#: scalar.c
 msgid "could not turn on maintenance"
 msgstr "no s'ha pogut activar el manteniment"
 
+#: scalar.c
 msgid "could not start the FSMonitor daemon"
 msgstr "no s'ha pogut iniciar el dimoni del fsmonitor"
 
+#: scalar.c
 msgid "could not turn off maintenance"
 msgstr "no s'ha pogut desactivar el manteniment"
 
+#: scalar.c
 msgid "could not remove enlistment"
 msgstr "no s'ha pogut eliminar l'allistament"
 
+#: scalar.c
 #, c-format
 msgid "remote HEAD is not a branch: '%.*s'"
 msgstr "la HEAD remota no és una branca: «%.*s»"
 
+#: scalar.c
 msgid "failed to get default branch name from remote; using local default"
 msgstr ""
 "no s'ha pogut obtenir el nom de la branca per defecte del remot; s'usa ela "
 "predeterminada localment"
 
+#: scalar.c
 msgid "failed to get default branch name"
 msgstr "s'ha produït un error en obtenir el nom de branca predeterminada"
 
+#: scalar.c
 msgid "failed to unregister repository"
 msgstr "s'ha produït un error en desregistrar el repositori"
 
+#: scalar.c
 msgid "failed to stop the FSMonitor daemon"
 msgstr "no s'ha pogut aturar el dimoni del FSMonitor"
 
+#: scalar.c
 msgid "failed to delete enlistment directory"
 msgstr "s'ha produït un error en suprimir l'allistament del directori"
 
+#: scalar.c
 msgid "branch to checkout after clone"
 msgstr "branca a agafar després de clonar"
 
+#: scalar.c
 msgid "when cloning, create full working directory"
 msgstr "quan es clona, crear un directori de treball complet"
 
+#: scalar.c
 msgid "only download metadata for the branch that will be checked out"
 msgstr "només baixa les metadades per a la branca que s'agafarà"
 
+#: scalar.c
 msgid "create repository within 'src' directory"
 msgstr "crea un repositori dins del directori «src»"
 
+#: scalar.c
+msgid "specify if tags should be fetched during clone"
+msgstr "especifica si les etiquetes s'han d'obtenir durant el clon"
+
+# Deixem <enlistment> sense traduir de moment
+#: scalar.c
 msgid ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 msgstr ""
-"scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"scalar clone [--single-branch] [--branch <branca-principal>] [--full-clone]\n"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 
+#: scalar.c
 #, c-format
 msgid "cannot deduce worktree name from '%s'"
 msgstr "no es pot deduir el nom de l'arbre de treball de «%s»"
 
+#: scalar.c
 #, c-format
 msgid "directory '%s' exists already"
 msgstr "el directori «%s» ja existeix"
 
+#: scalar.c
 #, c-format
 msgid "failed to get default branch for '%s'"
 msgstr "s'ha produït un error en obtenir la branca per defecte per a «%s»"
 
+#: scalar.c
 #, c-format
 msgid "could not configure remote in '%s'"
 msgstr "no s'ha pogut configurar el remot a «%s»"
 
+#: scalar.c
+#, c-format
+msgid "could not disable tags in '%s'"
+msgstr "no s'han pogut inhabilitar les etiquetes en «%s»"
+
+#: scalar.c
 #, c-format
 msgid "could not configure '%s'"
 msgstr "no s'ha pogut configurar «%s»"
 
+#: scalar.c
 msgid "partial clone failed; attempting full clone"
 msgstr "ha fallat la clonació parcial; s'està intentant la clonació completa"
 
+#: scalar.c
 msgid "could not configure for full clone"
 msgstr "no s'ha pogut configurar per a una clonació completa"
 
+#: scalar.c
 msgid "scalar diagnose [<enlistment>]"
 msgstr "scalar diagnose [<enlistment>]"
 
+#: scalar.c
 msgid "`scalar list` does not take arguments"
 msgstr "«scalar list» no accepta arguments"
 
+#: scalar.c
 msgid "scalar register [<enlistment>]"
 msgstr "scalar register [<enlistment>]"
 
+#: scalar.c
 msgid "reconfigure all registered enlistments"
 msgstr "reconfigura tots els allistaments registrats"
 
+#: scalar.c
 msgid "scalar reconfigure [--all | <enlistment>]"
 msgstr "scalar reconfigure [--all | <enlistment>]"
 
+#: scalar.c
 msgid "--all or <enlistment>, but not both"
 msgstr "--all o <enlistment>, però no ambdós"
 
+#: scalar.c
 #, c-format
 msgid "could not remove stale scalar.repo '%s'"
 msgstr "no s'ha pogut suprimir el scalar.repo «%s» estancat"
 
+#: scalar.c
 #, c-format
 msgid "removed stale scalar.repo '%s'"
 msgstr "s'ha eliminat l'scalar.repo estancat «%s»"
 
+#: scalar.c
 #, c-format
 msgid "repository at '%s' has different owner"
 msgstr "el dipòsit a «%s» té un propietari diferent"
 
+#: scalar.c
 #, c-format
 msgid "repository at '%s' has a format issue"
 msgstr "el dipòsit a «%s» té un problema de format"
 
+#: scalar.c
 #, c-format
 msgid "repository not found in '%s'"
 msgstr "no s'ha trobat el dipòsit a «%s»"
 
+#: scalar.c
 #, c-format
 msgid ""
 "to unregister this repository from Scalar, run\n"
@@ -20189,6 +26005,7 @@
 "per a desregistrar aquest dipòsit de l'escalar, executeu\n"
 "\tgit config --global --unset --fixed-value scalar.repo «%s»"
 
+#: scalar.c
 msgid ""
 "scalar run <task> [<enlistment>]\n"
 "Tasks:\n"
@@ -20196,77 +26013,97 @@
 "scalar run <task>  {<enlistment>]\n"
 "Tasques:\n"
 
+#: scalar.c
 #, c-format
 msgid "no such task: '%s'"
 msgstr "no existeix la tasca: «%s»"
 
+#: scalar.c
 msgid "scalar unregister [<enlistment>]"
 msgstr "scalar unregister [<enlistment>]"
 
+#: scalar.c
 msgid "scalar delete <enlistment>"
 msgstr "supressió de l'escalar <enlistment>"
 
+#: scalar.c
 msgid "refusing to delete current working directory"
 msgstr "s'ha rebutjat suprimir el directori de treball actual"
 
+#: scalar.c
 msgid "include Git version"
 msgstr "inclou la versió del Git"
 
+#: scalar.c
 msgid "include Git's build options"
 msgstr "inclou les opcions de construcció del Git"
 
+#: scalar.c
 msgid "scalar verbose [-v | --verbose] [--build-options]"
 msgstr "scalar verbose [-v | --verbose] [--build-options]"
 
+#: scalar.c
 msgid "-C requires a <directory>"
-msgstr "-C requereix un <directory>"
+msgstr "-C requereix un <directori>"
 
+#: scalar.c
 #, c-format
 msgid "could not change to '%s'"
 msgstr "no s'ha pogut canviar a «%s»"
 
+#: scalar.c
 msgid "-c requires a <key>=<value> argument"
-msgstr "-c requereix un argument <key>=<value>"
+msgstr "-c requereix un argument <clau>=<valor>"
 
+#: scalar.c
 msgid ""
 "scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
 "\n"
 "Commands:\n"
 msgstr ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<opcions>]\n"
+"scalar [-C <directori>] [-c <clau>=<valor>] <ordre> [<opcions>]\n"
 "\n"
 "Ordres:\n"
 
+#: send-pack.c
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr ""
 "paquet de buidatge no esperat quan estava llegint l'estat del "
 "desempaquetament remot"
 
+#: send-pack.c
 #, c-format
 msgid "unable to parse remote unpack status: %s"
 msgstr "no s'ha pogut analitzar l'estat del desempaquetament remot: %s"
 
+#: send-pack.c
 #, c-format
 msgid "remote unpack failed: %s"
 msgstr "s'ha produït un error en el desempaquetament remot: %s"
 
+#: send-pack.c
 msgid "failed to sign the push certificate"
 msgstr "s'ha produït un error en signar el certificat de pujada"
 
+#: send-pack.c
 msgid "send-pack: unable to fork off fetch subprocess"
 msgstr "send-pack: no es pot bifurcar obtenint un subprocés"
 
+#: send-pack.c
 msgid "push negotiation failed; proceeding anyway with push"
 msgstr ""
 "ha fallat la negociació de la pujada; s'està procedint igualment amb "
 "l'empenta"
 
+#: send-pack.c
 msgid "the receiving end does not support this repository's hash algorithm"
 msgstr "el receptor de destí no admet l'algorisme de resum del repositori"
 
+#: send-pack.c
 msgid "the receiving end does not support --signed push"
 msgstr "el destí receptor no admet pujar --signed"
 
+#: send-pack.c
 msgid ""
 "not sending a push certificate since the receiving end does not support --"
 "signed push"
@@ -20274,33 +26111,58 @@
 "no s'està enviant una certificació de pujada perquè el destí receptor no "
 "admet pujar --signed"
 
+#: send-pack.c
 msgid "the receiving end does not support --atomic push"
 msgstr "el destí receptor no admet pujar --atomic"
 
+#: send-pack.c
 msgid "the receiving end does not support push options"
 msgstr "el receptor al destí no admet opcions de pujada"
 
+#: sequencer.c
 #, c-format
 msgid "invalid commit message cleanup mode '%s'"
 msgstr "mode de neteja «%s» no vàlid en la comissió del missatge"
 
+#: sequencer.c
 #, c-format
 msgid "could not delete '%s'"
 msgstr "no s'ha pogut suprimir «%s»"
 
+#: sequencer.c
 msgid "revert"
 msgstr "revertir"
 
+#: sequencer.c
 msgid "cherry-pick"
 msgstr "cherry-pick"
 
+#: sequencer.c
 msgid "rebase"
 msgstr "rebase"
 
+#: sequencer.c
 #, c-format
 msgid "unknown action: %d"
 msgstr "acció desconeguda: %d"
 
+#: sequencer.c
+msgid ""
+"Resolve all conflicts manually, mark them as resolved with\n"
+"\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n"
+"You can instead skip this commit: run \"git rebase --skip\".\n"
+"To abort and get back to the state before \"git rebase\", run \"git rebase --"
+"abort\"."
+msgstr ""
+"Resoleu tots els conflictes manualment, marqueu-los com a resolts amb\n"
+"«git add/rm <fitxers_amb_conflicte>», llavors executeu «git rebase --"
+"continue».\n"
+"Alternativament podeu ometre aquesta comissió: executeu «git rebase --"
+"skip».\n"
+"Per a avortar i tornar a l'estat anterior abans de l'ordre «git rebase», "
+"executeu «git rebase --abort»."
+
+#: sequencer.c
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'"
@@ -20308,6 +26170,7 @@
 "després de resoldre els conflictes, marqueu els camins\n"
 "corregits amb «git add <camins>» o «git rm <camins>»"
 
+#: sequencer.c
 msgid ""
 "After resolving the conflicts, mark them with\n"
 "\"git add/rm <pathspec>\", then run\n"
@@ -20323,6 +26186,7 @@
 "Per a interrompre i tornar a l'estat anterior abans de «git cherry-pick»,\n"
 "executeu «git cherry-pick --abort»."
 
+#: sequencer.c
 msgid ""
 "After resolving the conflicts, mark them with\n"
 "\"git add/rm <pathspec>\", then run\n"
@@ -20338,68 +26202,86 @@
 "Per a interrompre i tornar a l'estat anterior abans de «git revert»,\n"
 "executeu «git revert --abort»."
 
+#: sequencer.c
 #, c-format
 msgid "could not lock '%s'"
 msgstr "no s'ha pogut bloquejar «%s»"
 
+#: sequencer.c
 #, c-format
 msgid "could not write eol to '%s'"
 msgstr "no s'ha pogut escriure el terminador de línia a «%s»"
 
+#: sequencer.c
 #, c-format
 msgid "failed to finalize '%s'"
 msgstr "s'ha produït un error en finalitzar «%s»"
 
+#: sequencer.c
 #, c-format
 msgid "your local changes would be overwritten by %s."
 msgstr "els vostres canvis locals se sobreescriurien per %s."
 
+#: sequencer.c
 msgid "commit your changes or stash them to proceed."
 msgstr "cometeu els vostres canvis o feu un «stash» per a procedir."
 
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
+#: sequencer.c
 #, c-format
 msgid "%s: Unable to write new index file"
 msgstr "%s: No s'ha pogut escriure un fitxer d'índex nou"
 
+#: sequencer.c
 msgid "unable to update cache tree"
 msgstr "no s'ha pogut actualitzar l'arbre cau"
 
+#: sequencer.c
 msgid "could not resolve HEAD commit"
 msgstr "no s'ha pogut resoldre la comissió HEAD"
 
+#: sequencer.c
 #, c-format
 msgid "no key present in '%.*s'"
 msgstr "no hi ha una clau a «%.*s»"
 
+#: sequencer.c
 #, c-format
 msgid "unable to dequote value of '%s'"
 msgstr "no s'han pogut treure les cometes del valor de «%s»"
 
+#: sequencer.c
 msgid "'GIT_AUTHOR_NAME' already given"
 msgstr "Ja s'ha donat «GIT_AUTHOR_NAME»"
 
+#: sequencer.c
 msgid "'GIT_AUTHOR_EMAIL' already given"
 msgstr "Ja s'ha donat «GIT_AUTHOR_EMAIL»"
 
+#: sequencer.c
 msgid "'GIT_AUTHOR_DATE' already given"
 msgstr "Ja s'ha donat «GIT_AUTHOR_DATE»"
 
+#: sequencer.c
 #, c-format
 msgid "unknown variable '%s'"
 msgstr "variable «%s» desconeguda"
 
+#: sequencer.c
 msgid "missing 'GIT_AUTHOR_NAME'"
 msgstr "falta «GIT_AUTHOR_NAME»"
 
+#: sequencer.c
 msgid "missing 'GIT_AUTHOR_EMAIL'"
 msgstr "falta «GIT_AUTHOR_EMAIL»"
 
+#: sequencer.c
 msgid "missing 'GIT_AUTHOR_DATE'"
 msgstr "falta «GIT_AUTHOR_DATE»"
 
+#: sequencer.c
 #, c-format
 msgid ""
 "you have staged changes in your working tree\n"
@@ -20429,9 +26311,11 @@
 "\n"
 "  git rebase --continue\n"
 
+#: sequencer.c
 msgid "'prepare-commit-msg' hook failed"
 msgstr "el lligam «prepare-commit-msg» ha fallat"
 
+#: sequencer.c
 msgid ""
 "Your name and email address were configured automatically based\n"
 "on your username and hostname. Please check that they are accurate.\n"
@@ -20458,6 +26342,7 @@
 "\n"
 "    git commit --amend --reset-author\n"
 
+#: sequencer.c
 msgid ""
 "Your name and email address were configured automatically based\n"
 "on your username and hostname. Please check that they are accurate.\n"
@@ -20483,259 +26368,369 @@
 "\n"
 "    git commit --amend --reset-author\n"
 
+#: sequencer.c
 msgid "couldn't look up newly created commit"
 msgstr "no s'ha pogut trobar la comissió novament creada"
 
+#: sequencer.c
 msgid "could not parse newly created commit"
 msgstr "no s'ha pogut analitzar la comissió novament creada"
 
+#: sequencer.c
 msgid "unable to resolve HEAD after creating commit"
 msgstr "no s'ha pogut resoldre HEAD després de crear la comissió"
 
+#: sequencer.c
 msgid "detached HEAD"
 msgstr "HEAD separat"
 
+#: sequencer.c
 msgid " (root-commit)"
 msgstr " (comissió arrel)"
 
+#: sequencer.c
 msgid "could not parse HEAD"
 msgstr "no s'ha pogut analitzar HEAD"
 
+#: sequencer.c
 #, c-format
 msgid "HEAD %s is not a commit!"
 msgstr "HEAD %s no és una comissió!"
 
+#: sequencer.c
 msgid "unable to parse commit author"
 msgstr "no s'ha pogut analitzar l'autor de la comissió"
 
+#: sequencer.c
 #, c-format
 msgid "unable to read commit message from '%s'"
 msgstr "no s'ha pogut llegir el missatge de comissió des de «%s»"
 
+#: sequencer.c
 #, c-format
 msgid "invalid author identity '%s'"
 msgstr "identitat d'autor no vàlida: «%s»"
 
+#: sequencer.c
 msgid "corrupt author: missing date information"
 msgstr "autor malmès: falta la informació de la data"
 
+#: sequencer.c
 #, c-format
 msgid "could not update %s"
 msgstr "no s'ha pogut actualitzar %s"
 
-#, c-format
-msgid "could not parse commit %s"
-msgstr "no s'ha pogut analitzar la comissió %s"
-
+#: sequencer.c
 #, c-format
 msgid "could not parse parent commit %s"
 msgstr "no s'ha pogut analitzar la comissió pare %s"
 
+#: sequencer.c
 #, c-format
 msgid "unknown command: %d"
 msgstr "ordre desconeguda: %d"
 
+#: sequencer.c
 msgid "This is the 1st commit message:"
 msgstr "Aquest és el missatge de la 1a comissió:"
 
+#: sequencer.c
 #, c-format
 msgid "This is the commit message #%d:"
 msgstr "Aquest és el missatge de la #%d comissió:"
 
+#: sequencer.c
 msgid "The 1st commit message will be skipped:"
 msgstr "El missatge de la primera comissió s'ometrà:"
 
+#: sequencer.c
 #, c-format
 msgid "The commit message #%d will be skipped:"
 msgstr "El missatge de la comissió núm. #%d s'ometrà:"
 
+#: sequencer.c
 #, c-format
 msgid "This is a combination of %d commits."
 msgstr "Això és una combinació de %d comissions."
 
+#: sequencer.c
 #, c-format
 msgid "cannot write '%s'"
 msgstr "no es pot escriure «%s»"
 
+#: sequencer.c
 msgid "need a HEAD to fixup"
 msgstr "cal un HEAD per a reparar-ho"
 
+#: sequencer.c
 msgid "could not read HEAD"
 msgstr "no s'ha pogut llegir HEAD"
 
+#: sequencer.c
 msgid "could not read HEAD's commit message"
 msgstr "no s'ha pogut llegir el missatge de comissió de HEAD"
 
+#: sequencer.c
 #, c-format
 msgid "could not read commit message of %s"
 msgstr "no s'ha pogut llegir el missatge de comissió: %s"
 
+#: sequencer.c
 msgid "your index file is unmerged."
 msgstr "el vostre fitxer d'índex està sense fusionar."
 
+#: sequencer.c
 msgid "cannot fixup root commit"
 msgstr "no es pot arreglar la comissió arrel"
 
+#: sequencer.c
 #, c-format
 msgid "commit %s is a merge but no -m option was given."
 msgstr "la comissió %s és una fusió però no s'ha donat cap opció -m."
 
+#: sequencer.c
 #, c-format
 msgid "commit %s does not have parent %d"
 msgstr "la comissió %s no té pare %d"
 
+#: sequencer.c
 #, c-format
 msgid "cannot get commit message for %s"
 msgstr "no es pot obtenir el missatge de comissió de %s"
 
 #. TRANSLATORS: The first %s will be a "todo" command like
 #. "revert" or "pick", the second %s a SHA1.
+#: sequencer.c
 #, c-format
 msgid "%s: cannot parse parent commit %s"
 msgstr "%s: no es pot analitzar la comissió pare %s"
 
+#: sequencer.c
 #, c-format
 msgid "could not revert %s... %s"
 msgstr "no s'ha pogut revertir %s... %s"
 
+#: sequencer.c
 #, c-format
 msgid "could not apply %s... %s"
 msgstr "no s'ha pogut aplicar %s... %s"
 
+#: sequencer.c
 #, c-format
 msgid "dropping %s %s -- patch contents already upstream\n"
 msgstr "descartant %s %s -- el contingut del pedaç ja està a la font\n"
 
+#: sequencer.c
 #, c-format
 msgid "git %s: failed to read the index"
 msgstr "git %s: s'ha produït un error en llegir l'índex"
 
+#: sequencer.c
 #, c-format
 msgid "git %s: failed to refresh the index"
 msgstr "git %s: s'ha produït un error en actualitzar l'índex"
 
+#: sequencer.c
 #, c-format
 msgid "'%s' is not a valid label"
 msgstr "«%s» no és una etiqueta vàlida"
 
+#: sequencer.c
 #, c-format
 msgid "'%s' is not a valid refname"
 msgstr "«%s» no és un nom de referència vàlid"
 
+#: sequencer.c
 #, c-format
 msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
 msgstr ""
 "«update-ref» requereix un refname plenament qualificat, p. ex. refs/heads/%s"
 
+#: sequencer.c
+#, c-format
+msgid "'%s' does not accept merge commits"
+msgstr "%s no accepta comissions de fusió"
+
+#. TRANSLATORS: 'pick' and 'merge -C' should not be
+#. translated.
+#.
+#: sequencer.c
+msgid ""
+"'pick' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit."
+msgstr ""
+"«pick» no accepta una comissió de fusió. Si volíeu\n"
+"reproduir la fusió, utilitzeu «merge -C» en la comissió."
+
+#. TRANSLATORS: 'reword' and 'merge -c' should not be
+#. translated.
+#.
+#: sequencer.c
+msgid ""
+"'reword' does not take a merge commit. If you wanted to\n"
+"replay the merge and reword the commit message, use\n"
+"'merge -c' on the commit"
+msgstr ""
+"«reword» no accepta una comissió de fusió. Si volíeu\n"
+"reproduir la fusió i fer «reword» del missatge de comissió,\n"
+"utilitzeu «merge -c» en la comissió"
+
+#. TRANSLATORS: 'edit', 'merge -C' and 'break' should
+#. not be translated.
+#.
+#: sequencer.c
+msgid ""
+"'edit' does not take a merge commit. If you wanted to\n"
+"replay the merge, use 'merge -C' on the commit, and then\n"
+"'break' to give the control back to you so that you can\n"
+"do 'git commit --amend && git rebase --continue'."
+msgstr ""
+"«edit» no accepta una comissió de fusió. Si volíeu\n"
+"reproduir la fusió, utilitzeu «merge -C» en la comissió\n"
+" i després «break» per a recuperar el control perquè pugueu\n"
+"feu «git commit --amend && git rebase --continue»."
+
+#: sequencer.c
+msgid "cannot squash merge commit into another commit"
+msgstr "no es pot fer «squash» d'una comissió de fusió en una altra comissió"
+
+#: sequencer.c
 #, c-format
 msgid "invalid command '%.*s'"
 msgstr "ordre no vàlida «%.*s»"
 
-#, c-format
-msgid "%s does not accept arguments: '%s'"
-msgstr "%s no accepta arguments: «%s»"
-
+#: sequencer.c
 #, c-format
 msgid "missing arguments for %s"
 msgstr "falten els arguments per a %s"
 
+#: sequencer.c
 #, c-format
 msgid "could not parse '%s'"
 msgstr "no s'ha pogut analitzar «%s»"
 
+#: sequencer.c
 #, c-format
 msgid "invalid line %d: %.*s"
 msgstr "línia no vàlida %d: %.*s"
 
+#: sequencer.c
 #, c-format
 msgid "cannot '%s' without a previous commit"
 msgstr "no es pot «%s» sense una comissió prèvia"
 
+#: sequencer.c
 msgid "cancelling a cherry picking in progress"
 msgstr "s'està cancel·lant un «cherry pick» en curs"
 
+#: sequencer.c
 msgid "cancelling a revert in progress"
 msgstr "s'està cancel·lant la reversió en curs"
 
+#: sequencer.c
 msgid "please fix this using 'git rebase --edit-todo'."
 msgstr "corregiu-ho usant «git rebase --edit-todo»."
 
+#: sequencer.c
 #, c-format
 msgid "unusable instruction sheet: '%s'"
 msgstr "full d'instruccions inusable: «%s»"
 
+#: sequencer.c
 msgid "no commits parsed."
 msgstr "no s'ha analitzat cap comissió."
 
+#: sequencer.c
 msgid "cannot cherry-pick during a revert."
 msgstr "no es pot fer «cherry pick» durant una reversió."
 
+#: sequencer.c
 msgid "cannot revert during a cherry-pick."
 msgstr "no es pot revertir durant un «cherry pick»."
 
+#: sequencer.c
 msgid "unusable squash-onto"
 msgstr "«squash-onto» no usable"
 
+#: sequencer.c
 #, c-format
 msgid "malformed options sheet: '%s'"
 msgstr "full d'opcions mal format: «%s»"
 
+#: sequencer.c
 msgid "empty commit set passed"
 msgstr "conjunt de comissions buit passat"
 
+#: sequencer.c
 msgid "revert is already in progress"
 msgstr "una reversió ja està en curs"
 
+#: sequencer.c
 #, c-format
 msgid "try \"git revert (--continue | %s--abort | --quit)\""
 msgstr "intenteu «git revert (--continue | %s--abort | --quit)»"
 
+#: sequencer.c
 msgid "cherry-pick is already in progress"
 msgstr "un «cherry pick» ja està en curs"
 
+#: sequencer.c
 #, c-format
 msgid "try \"git cherry-pick (--continue | %s--abort | --quit)\""
 msgstr "intenteu «git cherry-pick (--continue | %s--abort | --quit)»"
 
+#: sequencer.c
 #, c-format
 msgid "could not create sequencer directory '%s'"
 msgstr "no s'ha pogut crear el directori de seqüenciador «%s»"
 
+#: sequencer.c
 msgid "no cherry-pick or revert in progress"
 msgstr "ni hi ha cap «cherry pick» ni cap reversió en curs"
 
+#: sequencer.c
 msgid "cannot resolve HEAD"
 msgstr "no es pot resoldre HEAD"
 
+#: sequencer.c
 msgid "cannot abort from a branch yet to be born"
 msgstr "no es pot avortar des d'una branca que encara ha de nàixer"
 
+#: sequencer.c
 #, c-format
 msgid "cannot read '%s': %s"
 msgstr "no es pot llegir «%s»: %s"
 
+#: sequencer.c
 msgid "unexpected end of file"
 msgstr "final de fitxer inesperat"
 
+#: sequencer.c
 #, c-format
 msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
 msgstr "el fitxer HEAD emmagatzemat abans de fer «cherry pick» «%s» és malmès"
 
+#: sequencer.c
 msgid "You seem to have moved HEAD. Not rewinding, check your HEAD!"
-msgstr "Sembla que heu mogut HEAD sense rebobinar, comproveu-ho HEAD"
+msgstr "Sembla que heu mogut HEAD. No es fa el rebobinat, comproveu-ho HEAD"
 
+#: sequencer.c
 msgid "no revert in progress"
 msgstr "no hi ha cap reversió en curs"
 
+#: sequencer.c
 msgid "no cherry-pick in progress"
 msgstr "ni hi ha cap «cherry pick» en curs"
 
+#: sequencer.c
 msgid "failed to skip the commit"
 msgstr "s'ha produït un error en ometre la comissió"
 
+#: sequencer.c
 msgid "there is nothing to skip"
 msgstr "no hi ha res a ometre"
 
+#: sequencer.c
 #, c-format
 msgid ""
 "have you committed already?\n"
@@ -20744,13 +26739,15 @@
 "heu fet ja una comissió?\n"
 "proveu «git %s --continue»"
 
+#: sequencer.c
 msgid "cannot read HEAD"
 msgstr "no es pot llegir HEAD"
 
-#, c-format
-msgid "unable to copy '%s' to '%s'"
-msgstr "no s'ha pogut copiar «%s» a «%s»"
+#: sequencer.c
+msgid "could not write commit message file"
+msgstr "no s'ha pogut escriure el fitxer de missatge de comissió"
 
+#: sequencer.c
 #, c-format
 msgid ""
 "You can amend the commit now, with\n"
@@ -20769,18 +26766,22 @@
 "\n"
 "  git rebase --continue\n"
 
+#: sequencer.c
 #, c-format
 msgid "Could not apply %s... %.*s"
 msgstr "No s'ha pogut aplicar %s... %.*s"
 
+#: sequencer.c
 #, c-format
 msgid "Could not merge %.*s"
 msgstr "No s'ha pogut fusionar %.*s"
 
+#: sequencer.c
 #, c-format
 msgid "Executing: %s\n"
 msgstr "S'està executant: %s\n"
 
+#: sequencer.c
 #, c-format
 msgid ""
 "execution failed: %s\n"
@@ -20795,9 +26796,11 @@
 " git rebase --continue\n"
 "\n"
 
+#: sequencer.c
 msgid "and made changes to the index and/or the working tree.\n"
 msgstr "i ha fet canvis a l'índex i/o a l'arbre de treball.\n"
 
+#: sequencer.c
 #, c-format
 msgid ""
 "execution succeeded: %s\n"
@@ -20814,52 +26817,65 @@
 "  git rebase --continue\n"
 "\n"
 
+#: sequencer.c
 #, c-format
 msgid "illegal label name: '%.*s'"
 msgstr "nom d'etiqueta no permès: «%.*s»"
 
+#: sequencer.c
 #, c-format
 msgid "could not resolve '%s'"
 msgstr "no s'ha pogut resoldre «%s»"
 
+#: sequencer.c
 msgid "writing fake root commit"
 msgstr "s'està escrivint una comissió arrel falsa"
 
+#: sequencer.c
 msgid "writing squash-onto"
 msgstr "s'està escrivint «squash-onto»"
 
+#: sequencer.c
 msgid "cannot merge without a current revision"
 msgstr "no es pot fusionar sense una revisió actual"
 
+#: sequencer.c
 #, c-format
 msgid "unable to parse '%.*s'"
 msgstr "no s'ha pogut analitzar «%.*s»"
 
+#: sequencer.c
 #, c-format
 msgid "nothing to merge: '%.*s'"
 msgstr "no hi ha res per a fusionar «%.*s»"
 
+#: sequencer.c
 msgid "octopus merge cannot be executed on top of a [new root]"
 msgstr ""
 "no es pot executar la fusió «octopus» a la part superior d'una [arrel nova]"
 
+#: sequencer.c
 #, c-format
 msgid "could not get commit message of '%s'"
 msgstr "no s'ha pogut llegir el missatge de comissió de «%s»"
 
+#: sequencer.c
 #, c-format
 msgid "could not even attempt to merge '%.*s'"
 msgstr "no s'ha pogut fusionar «%.*s»"
 
+#: sequencer.c
 msgid "merge: Unable to write new index file"
 msgstr "fusió: no s'ha pogut escriure un fitxer d'índex nou"
 
+#: sequencer.c
 #, c-format
 msgid ""
 "another 'rebase' process appears to be running; '%s.lock' already exists"
 msgstr ""
 "sembla que s'està executant un altre procés «rebase»: «%s.lock» ja existeix"
 
+#: sequencer.c
 #, c-format
 msgid ""
 "Updated the following refs with %s:\n"
@@ -20868,6 +26884,7 @@
 "S'han actualitzat els següents refs amb %s:\n"
 "%s"
 
+#: sequencer.c
 #, c-format
 msgid ""
 "Failed to update the following refs with %s:\n"
@@ -20876,32 +26893,40 @@
 "No s'han pogut actualitzar les referències següents amb %s:\n"
 "%s"
 
+#: sequencer.c
 msgid "Cannot autostash"
 msgstr "No es pot fer un «stash» automàticament"
 
+#: sequencer.c
 #, c-format
 msgid "Unexpected stash response: '%s'"
 msgstr "Resposta de «stash» inesperada: «%s»"
 
+#: sequencer.c
 #, c-format
 msgid "Could not create directory for '%s'"
 msgstr "No s'ha pogut crear el directori per a «%s»"
 
+#: sequencer.c
 #, c-format
 msgid "Created autostash: %s\n"
 msgstr "S'ha creat un «stash» automàticament: %s\n"
 
+#: sequencer.c
 msgid "could not reset --hard"
 msgstr "no s'ha pogut fer reset --hard"
 
+#: sequencer.c
 #, c-format
 msgid "Applied autostash.\n"
 msgstr "S'ha aplicat el «stash» automàticament.\n"
 
+#: sequencer.c
 #, c-format
 msgid "cannot store %s"
 msgstr "no es pot emmagatzemar %s"
 
+#: sequencer.c
 #, c-format
 msgid ""
 "%s\n"
@@ -20912,27 +26937,34 @@
 "Els vostres canvis estan segurs en el «stash».\n"
 "Podeu executar «git stash pop» o «git stash drop» en qualsevol moment.\n"
 
+#: sequencer.c
 msgid "Applying autostash resulted in conflicts."
 msgstr "L'aplicació del «stash» automàticament ha donat conflictes."
 
+#: sequencer.c
 msgid "Autostash exists; creating a new stash entry."
 msgstr ""
 "El «stash» automàtic ja existeix; s'està creant una entrada «stash» nova."
 
+#: sequencer.c
 msgid "autostash reference is a symref"
 msgstr "la referència d'autostash és un symref"
 
+#: sequencer.c
 msgid "could not detach HEAD"
 msgstr "no s'ha pogut separar HEAD"
 
+#: sequencer.c
 #, c-format
 msgid "Stopped at HEAD\n"
 msgstr "Aturat a HEAD\n"
 
+#: sequencer.c
 #, c-format
 msgid "Stopped at %s\n"
 msgstr "Aturat a %s\n"
 
+#: sequencer.c
 #, c-format
 msgid ""
 "Could not execute the todo command\n"
@@ -20953,46 +26985,58 @@
 "    git rebase --edit-todo\n"
 "    git rebase --continue\n"
 
+#: sequencer.c
 #, c-format
 msgid "Stopped at %s...  %.*s\n"
 msgstr "Aturat a %s...  %.*s\n"
 
+#: sequencer.c
 #, c-format
 msgid "Rebasing (%d/%d)%s"
 msgstr "S'està fent «rebase» (%d/%d)%s"
 
+#: sequencer.c
 #, c-format
 msgid "unknown command %d"
 msgstr "ordre %d desconeguda"
 
+#: sequencer.c
 msgid "could not read orig-head"
 msgstr "no s'ha pogut llegir orig-head"
 
+#: sequencer.c
 msgid "could not read 'onto'"
 msgstr "no s'ha pogut llegir «onto»"
 
+#: sequencer.c
 #, c-format
 msgid "could not update HEAD to %s"
 msgstr "no s'ha pogut actualitzar HEAD a %s"
 
+#: sequencer.c
 #, c-format
 msgid "Successfully rebased and updated %s.\n"
 msgstr "S'ha fet «rebase» i actualitzat %s amb èxit.\n"
 
+#: sequencer.c
 msgid "cannot rebase: You have unstaged changes."
 msgstr "no es pot fer «rebase»: teniu canvis «unstaged»."
 
+#: sequencer.c
 msgid "cannot amend non-existing commit"
 msgstr "no es pot esmenar una comissió no existent"
 
+#: sequencer.c
 #, c-format
 msgid "invalid file: '%s'"
 msgstr "fitxer no vàlid: «%s»"
 
+#: sequencer.c
 #, c-format
 msgid "invalid contents: '%s'"
 msgstr "contingut no vàlid: «%s»"
 
+#: sequencer.c
 msgid ""
 "\n"
 "You have uncommitted changes in your working tree. Please, commit them\n"
@@ -21002,57 +27046,73 @@
 "Teniu canvis no comesos en el vostre arbre de treball. \n"
 "Cometeu-los primer i després executeu «git rebase --continue» de nou."
 
+#: sequencer.c
 #, c-format
 msgid "could not write file: '%s'"
 msgstr "no s'ha pogut escriure el fitxer: «%s»"
 
+#: sequencer.c
 msgid "could not remove CHERRY_PICK_HEAD"
 msgstr "no s'ha pogut eliminar CHERRY_PICK_HEAD"
 
+#: sequencer.c
 msgid "could not commit staged changes."
 msgstr "no s'han pogut cometre els canvis «staged»."
 
+#: sequencer.c
 #, c-format
 msgid "%s: can't cherry-pick a %s"
 msgstr "%s: no es pot fer «cherry pick» a %s"
 
+#: sequencer.c
 #, c-format
 msgid "%s: bad revision"
 msgstr "%s: revisió incorrecta"
 
+#: sequencer.c
 msgid "can't revert as initial commit"
 msgstr "no es pot revertir com a comissió inicial"
 
+#: sequencer.c
 #, c-format
 msgid "skipped previously applied commit %s"
 msgstr "omet les comissions aplicades anteriorment %s"
 
+#: sequencer.c
 msgid "use --reapply-cherry-picks to include skipped commits"
 msgstr "useu --reapply-cherry-picks per a incloure les comissions omeses"
 
+#: sequencer.c
 msgid "make_script: unhandled options"
 msgstr "make_script: opcions no gestionades"
 
+#: sequencer.c
 msgid "make_script: error preparing revisions"
 msgstr "make_script: s'ha produït un error en preparar les revisions"
 
+#: sequencer.c
 msgid "nothing to do"
 msgstr "res a fer"
 
+#: sequencer.c
 msgid "could not skip unnecessary pick commands"
 msgstr "no s'han pogut ometre les ordres «picks» no necessàries"
 
+#: sequencer.c
 msgid "the script was already rearranged."
 msgstr "l'script ja estava endreçat."
 
+#: sequencer.c
 #, c-format
 msgid "update-refs file at '%s' is invalid"
 msgstr "el fitxer update-refs a «%s» no és vàlid"
 
+#: setup.c
 #, c-format
 msgid "'%s' is outside repository at '%s'"
 msgstr "«%s» està fora del repositori a «%s»"
 
+#: setup.c
 #, c-format
 msgid ""
 "%s: no such path in the working tree.\n"
@@ -21062,6 +27122,7 @@
 "Useu «git <ordre> -- <camí>...» per a especificar camins que no existeixin "
 "localment."
 
+#: setup.c
 #, c-format
 msgid ""
 "ambiguous argument '%s': unknown revision or path not in the working tree.\n"
@@ -21073,10 +27134,12 @@
 "Useu «--» per a separar els camins de les revisions:\n"
 "«git <ordre> [<revisió>...] -- [<fitxer>...]»"
 
+#: setup.c
 #, c-format
 msgid "option '%s' must come before non-option arguments"
 msgstr "l'opció «%s» ha d'aparèixer abans que els arguments opcionals"
 
+#: setup.c
 #, c-format
 msgid ""
 "ambiguous argument '%s': both revision and filename\n"
@@ -21087,89 +27150,94 @@
 "Useu «--» per a separar els camins de les revisions:\n"
 "«git <ordre> [<revisió>...] -- [<fitxer>...]»"
 
+#: setup.c
 msgid "unable to set up work tree using invalid config"
 msgstr ""
 "no s'ha pogut configurar un arbre de treball utilitzant una configuració no "
 "vàlida"
 
+#: setup.c
+#, c-format
+msgid "'%s' already specified as '%s'"
+msgstr "«%s» ja especificat com a «%s»"
+
+#: setup.c
 #, c-format
 msgid "Expected git repo version <= %d, found %d"
 msgstr "S'esperava una versió de repositori de git <= %d, s'ha trobat %d"
 
+#: setup.c
 msgid "unknown repository extension found:"
 msgid_plural "unknown repository extensions found:"
 msgstr[0] "s'ha trobat una extensió de repositori desconeguda:"
 msgstr[1] "s'han trobat extensions de repositori desconegudes:"
 
+#: setup.c
 msgid "repo version is 0, but v1-only extension found:"
 msgid_plural "repo version is 0, but v1-only extensions found:"
 msgstr[0] "el repositori és versió 0, però només s'han trobat una extensió v1:"
 msgstr[1] "el repositori és versió 0, però només s'han trobat extensions v1:"
 
+#: setup.c
 #, c-format
 msgid "error opening '%s'"
 msgstr "s'ha produït un error en obrir «%s»"
 
+#: setup.c
 #, c-format
 msgid "too large to be a .git file: '%s'"
 msgstr "massa gran per a ser un fitxer .git: «%s»"
 
+#: setup.c
 #, c-format
 msgid "error reading %s"
 msgstr "error en llegir %s"
 
+#: setup.c
 #, c-format
 msgid "invalid gitfile format: %s"
 msgstr "format gitfile no vàlid: %s"
 
+#: setup.c
 #, c-format
 msgid "no path in gitfile: %s"
 msgstr "sense camí al gitfile: %s"
 
+#: setup.c
 #, c-format
 msgid "not a git repository: %s"
 msgstr "no és un repositori de git: %s"
 
+#: setup.c
 #, c-format
 msgid "'$%s' too big"
 msgstr "«$%s» massa gran"
 
+#: setup.c
 #, c-format
 msgid "not a git repository: '%s'"
 msgstr "no és un repositori de git: «%s»"
 
+#: setup.c
 #, c-format
 msgid "cannot chdir to '%s'"
 msgstr "no es pot canviar de directori a «%s»"
 
+#: setup.c
 msgid "cannot come back to cwd"
 msgstr "no es pot tornar al directori de treball actual"
 
+#: setup.c
 #, c-format
 msgid "failed to stat '%*s%s%s'"
 msgstr "s'ha produït un error en fer stat a «%*s%s%s»"
 
-msgid "Unable to read current working directory"
-msgstr "No s'ha pogut llegir el directori de treball actual"
-
+#: setup.c
 #, c-format
-msgid "cannot change to '%s'"
-msgstr "no es pot canviar a «%s»"
+msgid "safe.directory '%s' not absolute"
+msgstr "el safe.directory «%s» no és absolut"
 
-#, c-format
-msgid "not a git repository (or any of the parent directories): %s"
-msgstr "no és un repositori de git (ni cap dels directoris pares): %s"
-
-#, c-format
-msgid ""
-"not a git repository (or any parent up to mount point %s)\n"
-"Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."
-msgstr ""
-"no és un repositori de git (ni existeix cap pare fins al punt de muntatge "
-"%s)\n"
-"S'atura a la frontera de sistema de fitxers (GIT_DISCOVERY_ACROSS_FILESYSTEM "
-"no està establert)."
-
+#: setup.c
 #, c-format
 msgid ""
 "detected dubious ownership in repository at '%s'\n"
@@ -21182,10 +27250,37 @@
 "\n"
 "\tgit config --global --add safe.directory %s"
 
+#: setup.c
+msgid "Unable to read current working directory"
+msgstr "No s'ha pogut llegir el directori de treball actual"
+
+#: setup.c
+#, c-format
+msgid "cannot change to '%s'"
+msgstr "no es pot canviar a «%s»"
+
+#: setup.c
+#, c-format
+msgid "not a git repository (or any of the parent directories): %s"
+msgstr "no és un repositori de git (ni cap dels directoris pares): %s"
+
+#: setup.c
+#, c-format
+msgid ""
+"not a git repository (or any parent up to mount point %s)\n"
+"Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."
+msgstr ""
+"no és un repositori de git (ni existeix cap pare fins al punt de muntatge "
+"%s)\n"
+"S'atura a la frontera de sistema de fitxers (GIT_DISCOVERY_ACROSS_FILESYSTEM "
+"no està establert)."
+
+#: setup.c
 #, c-format
 msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
 msgstr "no es pot utilitzar el dipòsit nu «%s» (safe.bareRepository és «%s»)"
 
+#: setup.c
 #, c-format
 msgid ""
 "problem with core.sharedRepository filemode value (0%.3o).\n"
@@ -21196,185 +27291,246 @@
 "El propietari dels fitxers sempre ha de tenir permisos de lectura i "
 "escriptura."
 
+#: setup.c
 msgid "fork failed"
 msgstr "el «fork» ha fallat"
 
+#: setup.c
 msgid "setsid failed"
 msgstr "«setsid» ha fallat"
 
+#: setup.c
 #, c-format
 msgid "cannot stat template '%s'"
 msgstr "no es pot fer stat en la plantilla «%s»"
 
+#: setup.c
 #, c-format
 msgid "cannot opendir '%s'"
 msgstr "no es pot fer opendir en el directori «%s»"
 
+#: setup.c
 #, c-format
 msgid "cannot readlink '%s'"
 msgstr "no es pot fer readlink en «%s»"
 
+#: setup.c
 #, c-format
 msgid "cannot symlink '%s' '%s'"
 msgstr "no es pot fer symlink en «%s» «%s»"
 
+#: setup.c
 #, c-format
 msgid "cannot copy '%s' to '%s'"
 msgstr "no es pot copiar «%s» a «%s»"
 
+#: setup.c
 #, c-format
 msgid "ignoring template %s"
 msgstr "s'està ignorant la plantilla %s"
 
+#: setup.c
 #, c-format
 msgid "templates not found in %s"
 msgstr "plantilles no trobades a %s"
 
+#: setup.c
 #, c-format
 msgid "not copying templates from '%s': %s"
 msgstr "no s'estan copiant plantilles de «%s»: %s"
 
+#: setup.c
 #, c-format
 msgid "invalid initial branch name: '%s'"
 msgstr "nom de branca inicial no vàlid: «%s»"
 
+#: setup.c
 #, c-format
 msgid "re-init: ignored --initial-branch=%s"
 msgstr "reinicialització: s'ha ignorat --initial-branch=%s"
 
+#: setup.c
 #, c-format
 msgid "unable to handle file type %d"
 msgstr "no s'ha pogut gestionar el tipus de fitxer %d"
 
+#: setup.c
 #, c-format
 msgid "unable to move %s to %s"
 msgstr "no s'ha pogut moure %s a %s"
 
+#: setup.c
 msgid "attempt to reinitialize repository with different hash"
 msgstr "s'ha intentat reinicialitzar el repositori amb un resum diferent"
 
+#: setup.c
 msgid ""
 "attempt to reinitialize repository with different reference storage format"
 msgstr ""
 "s'ha intentat reactivar el repositori amb un format d'emmagatzematge de "
 "referència diferent"
 
+#: setup.c
 #, c-format
 msgid "%s already exists"
 msgstr "%s ja existeix"
 
+#: setup.c
 #, c-format
 msgid "Reinitialized existing shared Git repository in %s%s\n"
 msgstr "S'ha reinicialitzat el repositori compartit existent del Git en %s%s\n"
 
+#: setup.c
 #, c-format
 msgid "Reinitialized existing Git repository in %s%s\n"
 msgstr "S'ha reinicialitzat el repositori existent del Git en %s%s\n"
 
+#: setup.c
 #, c-format
 msgid "Initialized empty shared Git repository in %s%s\n"
 msgstr "S'ha inicialitzat un repositori compartit buit del Git en %s%s\n"
 
+#: setup.c
 #, c-format
 msgid "Initialized empty Git repository in %s%s\n"
 msgstr "S'ha inicialitzat un repositori buit del Git en %s%s\n"
 
+#: sparse-index.c
 #, c-format
 msgid "index entry is a directory, but not sparse (%08x)"
 msgstr "l'entrada d'índex és un directori, però no dispers (%08x)"
 
+#: split-index.c
 msgid "cannot use split index with a sparse index"
 msgstr "no es pot utilitzar l'índex partit amb un índex dispers"
 
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: element '%s' does not start with '('"
+msgstr "format %s incorrecte: l'element «%s» no comença amb «(»"
+
+#. TRANSLATORS: The first %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: element '%s' does not end in ')'"
+msgstr "format %s incorrecte: l'element «%s» no acaba en «)»"
+
+#. TRANSLATORS: %s is a command like "ls-tree".
+#: strbuf.c
+#, c-format
+msgid "bad %s format: %%%.*s"
+msgstr "format %s incorrecte: %%%.*s"
+
 #. TRANSLATORS: IEC 80000-13:2008 gibibyte
+#: strbuf.c
 #, c-format
 msgid "%u.%2.2u GiB"
 msgstr "%u.%2.2u GiB"
 
 #. TRANSLATORS: IEC 80000-13:2008 gibibyte/second
+#: strbuf.c
 #, c-format
 msgid "%u.%2.2u GiB/s"
 msgstr "%u.%2.2u GiB/s"
 
 #. TRANSLATORS: IEC 80000-13:2008 mebibyte
+#: strbuf.c
 #, c-format
 msgid "%u.%2.2u MiB"
 msgstr "%u.%2.2u MiB"
 
 #. TRANSLATORS: IEC 80000-13:2008 mebibyte/second
+#: strbuf.c
 #, c-format
 msgid "%u.%2.2u MiB/s"
 msgstr "%u.%2.2u MiB/s"
 
 #. TRANSLATORS: IEC 80000-13:2008 kibibyte
+#: strbuf.c
 #, c-format
 msgid "%u.%2.2u KiB"
 msgstr "%u.%2.2u KiB"
 
 #. TRANSLATORS: IEC 80000-13:2008 kibibyte/second
+#: strbuf.c
 #, c-format
 msgid "%u.%2.2u KiB/s"
 msgstr "%u.%2.2u KiB/s"
 
 #. TRANSLATORS: IEC 80000-13:2008 byte
+#: strbuf.c
 #, c-format
 msgid "%u byte"
 msgid_plural "%u bytes"
-msgstr[0] "%u byte"
-msgstr[1] "%u bytes"
+msgstr[0] "%u octet"
+msgstr[1] "%u octets"
 
 #. TRANSLATORS: IEC 80000-13:2008 byte/second
+#: strbuf.c
 #, c-format
 msgid "%u byte/s"
 msgid_plural "%u bytes/s"
-msgstr[0] "%u byte/s"
-msgstr[1] "%u bytes/s"
+msgstr[0] "%u octet/s"
+msgstr[1] "%u octets/s"
 
+#: submodule-config.c
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
 msgstr "s'està ignorant el nom de submòdul sospitós %s"
 
+#: submodule-config.c
 msgid "negative values not allowed for submodule.fetchJobs"
 msgstr "no es permeten els valors negatius a submodule.fetchJobs"
 
+#: submodule-config.c
 #, c-format
 msgid "ignoring '%s' which may be interpreted as a command-line option: %s"
 msgstr ""
 "s'està ignorant «%s» que pot interpretar-se com a una opció de línia "
 "d'ordres: %s"
 
+#: submodule-config.c
 #, c-format
 msgid "Could not update .gitmodules entry %s"
 msgstr "No s'ha pogut actualitzar l'entrada de .gitmodules %s"
 
+#: submodule.c
 msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first"
 msgstr ""
 "No es pot canviar un .gitmodules no fusionat, primer resoleu els conflictes "
 "de fusió"
 
+#: submodule.c
 #, c-format
 msgid "Could not find section in .gitmodules where path=%s"
 msgstr "No s'ha pogut trobar la secció en .gitmodules on path=%s"
 
+#: submodule.c
 #, c-format
 msgid "Could not remove .gitmodules entry for %s"
 msgstr "No s'ha pogut eliminar l'entrada de .gitmodules per a %s"
 
+#: submodule.c
 msgid "staging updated .gitmodules failed"
 msgstr "l'allistament del .gitmodules actualitzat ha fallat"
 
+#: submodule.c
 #, c-format
 msgid "in unpopulated submodule '%s'"
 msgstr "al submòdul sense popular «%s»"
 
+#: submodule.c
 #, c-format
 msgid "Pathspec '%s' is in submodule '%.*s'"
 msgstr "L'especificació «%s» és en el submòdul «%.*s»"
 
+#: submodule.c
 #, c-format
 msgid "bad --ignore-submodules argument: %s"
 msgstr "argument incorrecte --ignore-submodules: %s"
 
+#: submodule.c
 #, c-format
 msgid ""
 "Submodule in commit %s at path: '%s' collides with a submodule named the "
@@ -21383,10 +27539,12 @@
 "El submòdul en la comissió %s al camí: «%s» col·lideix amb un submòdul amb "
 "el mateix nom. Ometent-lo."
 
+#: submodule.c
 #, c-format
 msgid "submodule entry '%s' (%s) is a %s, not a commit"
 msgstr "l'entrada del submòdul «%s» (%s) és a %s, no és una comissió"
 
+#: submodule.c
 #, c-format
 msgid ""
 "Could not run 'git rev-list <commits> --not --remotes -n 1' command in "
@@ -21395,34 +27553,42 @@
 "No s'ha pogut executar l'ordre «git rev-list <commits> --not --remotes -n 1» "
 "en el submòdul %s"
 
+#: submodule.c
 #, c-format
 msgid "process for submodule '%s' failed"
 msgstr "ha fallat el procés per al submòdul «%s»"
 
+#: submodule.c
 #, c-format
 msgid "Pushing submodule '%s'\n"
 msgstr "S'està pujant el submòdul «%s»\n"
 
+#: submodule.c
 #, c-format
 msgid "Unable to push submodule '%s'\n"
 msgstr "No s'ha pogut pujar el submòdul «%s»\n"
 
+#: submodule.c
 #, c-format
 msgid "Fetching submodule %s%s\n"
 msgstr "S'està obtenint el submòdul %s%s\n"
 
+#: submodule.c
 #, c-format
 msgid "Could not access submodule '%s'\n"
 msgstr "No s'ha pogut accedir al submòdul «%s»\n"
 
+#: submodule.c
 #, c-format
 msgid "Could not access submodule '%s' at commit %s\n"
 msgstr "No s'ha pogut accedir al submòdul «%s» en la comissió %s\n"
 
+#: submodule.c
 #, c-format
 msgid "Fetching submodule %s%s at commit %s\n"
 msgstr "S'està obtenint el submòdul %s%s en la comissió %s\n"
 
+#: submodule.c
 #, c-format
 msgid ""
 "Errors during submodule fetch:\n"
@@ -21431,51 +27597,74 @@
 "Errors durant l'obtenció de submòduls:\n"
 "%s"
 
+#: submodule.c
 #, c-format
 msgid "'%s' not recognized as a git repository"
 msgstr "«%s» no reconegut com un repositori git"
 
+#: submodule.c
 #, c-format
 msgid "Could not run 'git status --porcelain=2' in submodule %s"
 msgstr "No s'ha pogut executar «git status --porcelain=2» en el submòdul %s"
 
+#: submodule.c
 #, c-format
 msgid "'git status --porcelain=2' failed in submodule %s"
 msgstr "«git status --porcelain=2» ha fallat en el submòdul %s"
 
+#: submodule.c
 #, c-format
 msgid "could not start 'git status' in submodule '%s'"
 msgstr "no s'ha pogut iniciar «git status» al submòdul «%s»"
 
+#: submodule.c
 #, c-format
 msgid "could not run 'git status' in submodule '%s'"
 msgstr "no s'ha pogut executar «git status» al submòdul «%s»"
 
+#: submodule.c
 #, c-format
 msgid "Could not unset core.worktree setting in submodule '%s'"
 msgstr ""
 "No s'ha pogut desassignar el paràmetre «core.worktree» al submòdul «%s»"
 
+#: submodule.c
 #, c-format
 msgid "could not recurse into submodule '%s'"
 msgstr ""
 "s'ha produït un error en cercar recursivament al camí del submòdul «%s»"
 
+#: submodule.c
 msgid "could not reset submodule index"
 msgstr "no s'ha pogut restablir l'índex del submòdul"
 
+#: submodule.c
 #, c-format
 msgid "submodule '%s' has dirty index"
 msgstr "el submòdul «%s» té l'índex brut"
 
+#: submodule.c
 #, c-format
 msgid "Submodule '%s' could not be updated."
 msgstr "No s'ha pogut actualitzar el submòdul «%s»."
 
+#: submodule.c
 #, c-format
 msgid "submodule git dir '%s' is inside git dir '%.*s'"
 msgstr "submodule git dir «%s» està dins git dir «%.*s»"
 
+#: submodule.c
+#, c-format
+msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link"
+msgstr ""
+"s'esperava que «%.*s» en el camí del submòdul «%s» no fos un enllaç simbòlic"
+
+#: submodule.c
+#, c-format
+msgid "expected submodule path '%s' not to be a symbolic link"
+msgstr "s'esperava que el camí del submòdul «%s» no fos un enllaç simbòlic"
+
+#: submodule.c
 #, c-format
 msgid ""
 "relocate_gitdir for submodule '%s' with more than one worktree not supported"
@@ -21483,14 +27672,17 @@
 "no està admès relocate_gitdir per al submòdul «%s» amb més d'un arbre de "
 "treball"
 
+#: submodule.c
 #, c-format
 msgid "could not lookup name for submodule '%s'"
 msgstr "no s'ha trobat el nom pel submòdul «%s»"
 
+#: submodule.c
 #, c-format
 msgid "refusing to move '%s' into an existing git dir"
 msgstr "s'ha refusat moure «%s» a un directori git existent"
 
+#: submodule.c
 #, c-format
 msgid ""
 "Migrating git directory of '%s%s' from\n"
@@ -21501,150 +27693,186 @@
 "«%s» a\n"
 "«%s»\n"
 
+#: submodule.c
 msgid "could not start ls-files in .."
 msgstr "no s'ha pogut iniciar ls-files a .."
 
+#: submodule.c
 #, c-format
 msgid "ls-tree returned unexpected return code %d"
 msgstr "ls-tree ha retornat un codi de retorn %d no esperat"
 
+#: symlinks.c
 #, c-format
 msgid "failed to lstat '%s'"
 msgstr "s'ha produït un error en fer lstat a «%s»"
 
+#: t/helper/test-bundle-uri.c
 msgid "no remote configured to get bundle URIs from"
 msgstr "no hi ha cap remot configurat per a obtenir els URI del paquet"
 
-#, c-format
-msgid "remote '%s' has no configured URL"
-msgstr "el remot «%s» no té cap URL configurat"
-
+#: t/helper/test-bundle-uri.c
 msgid "could not get the bundle-uri list"
 msgstr "no s'ha pogut obtenir la llista bundle-uri"
 
+#: t/helper/test-cache-tree.c
 msgid "test-tool cache-tree <options> (control|prime|update)"
 msgstr "test-tool cache-tree <opcions> (control|prime|update)"
 
+#: t/helper/test-cache-tree.c
 msgid "clear the cache tree before each iteration"
 msgstr "neteja l'arbre de la memòria cau abans de cada iteració"
 
+#: t/helper/test-cache-tree.c
 msgid "number of entries in the cache tree to invalidate (default 0)"
 msgstr ""
 "nombre d'entrades a l'arbre de la memòria cau a invalidar (per defecte 0)"
 
+#: t/helper/test-reach.c
 #, c-format
 msgid "commit %s is not marked reachable"
 msgstr "la comissió %s no està marcada com abastable"
 
+#: t/helper/test-reach.c
 msgid "too many commits marked reachable"
 msgstr "hi ha massa comissions marcades com abastables"
 
+#: t/helper/test-serve-v2.c
 msgid "test-tool serve-v2 [<options>]"
 msgstr "test-tool serve-v2 [<opcions>]"
 
+#: t/helper/test-serve-v2.c
 msgid "exit immediately after advertising capabilities"
 msgstr "surt immediatament després d'anunciar les funcionalitats"
 
+#: t/helper/test-simple-ipc.c
 msgid "test-helper simple-ipc is-active    [<name>] [<options>]"
 msgstr "test-helper simple-ipc is-active    [<nom>] [<opcions>]"
 
+#: t/helper/test-simple-ipc.c
 msgid "test-helper simple-ipc run-daemon   [<name>] [<threads>]"
 msgstr "test-helper simple-ipc run-daemon   [<nom>] [<fils>]"
 
+#: t/helper/test-simple-ipc.c
 msgid "test-helper simple-ipc start-daemon [<name>] [<threads>] [<max-wait>]"
 msgstr "test-helper simple-ipc start-daemon [<nom>] [<fils>] [<max-wait>]"
 
+#: t/helper/test-simple-ipc.c
 msgid "test-helper simple-ipc stop-daemon  [<name>] [<max-wait>]"
 msgstr "test-helper simple-ipc stop-daemon  [<nom>] [<max-wait>]"
 
+#: t/helper/test-simple-ipc.c
 msgid "test-helper simple-ipc send         [<name>] [<token>]"
 msgstr "test-helper simple-ipc send         [<nom>] [<testimoni>]"
 
+#: t/helper/test-simple-ipc.c
 msgid "test-helper simple-ipc sendbytes    [<name>] [<bytecount>] [<byte>]"
-msgstr "test-helper simple-ipc sendbytes    [<nom>] [<bytecount>] [<byte>]"
+msgstr ""
+"test-helper simple-ipc sendbytes    [<nom>] [<recompte-octets>] [<octet>]"
 
+#: t/helper/test-simple-ipc.c
 msgid ""
 "test-helper simple-ipc multiple     [<name>] [<threads>] [<bytecount>] "
 "[<batchsize>]"
 msgstr ""
-"test-helper simple-ipc multiple     [<nom>] [<fils>] [<bytecount>] "
-"[<batchsize>]"
+"test-helper simple-ipc multiple     [<nom>] [<fils>] [<recompte-octets>] "
+"[<mida-lot>]"
 
+#: t/helper/test-simple-ipc.c
 msgid "name or pathname of unix domain socket"
 msgstr "nom o nom de camí del sòcol de domini unix"
 
+#: t/helper/test-simple-ipc.c
 msgid "named-pipe name"
 msgstr "nom del conducte amb nom"
 
+#: t/helper/test-simple-ipc.c
 msgid "number of threads in server thread pool"
 msgstr "nombre de fils en el conjunt de fils del servidor"
 
+#: t/helper/test-simple-ipc.c
 msgid "seconds to wait for daemon to start or stop"
 msgstr "segons a esperar que el dimoni comenci o s'aturi"
 
+#: t/helper/test-simple-ipc.c
 msgid "number of bytes"
 msgstr "nombre d'octets"
 
+#: t/helper/test-simple-ipc.c
 msgid "number of requests per thread"
 msgstr "nombre de peticions per fil"
 
+#: t/helper/test-simple-ipc.c
 msgid "byte"
 msgstr "octet"
 
+#: t/helper/test-simple-ipc.c
 msgid "ballast character"
 msgstr "caràcter de llast"
 
+#: t/helper/test-simple-ipc.c
 msgid "token"
 msgstr "testimoni"
 
+#: t/helper/test-simple-ipc.c
 msgid "command token to send to the server"
 msgstr "testimoni d'ordre a enviar al servidor"
 
+#: t/unit-tests/unit-test.c
+msgid "unit-test [<options>]"
+msgstr "unit-test [<opcions>]"
+
+#: t/unit-tests/unit-test.c
+msgid "immediately exit upon the first failed test"
+msgstr "sortir immediatament en fallar el primer test"
+
+# deixada sense traduir perquè pareix opció i no text
+#: t/unit-tests/unit-test.c
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+#: t/unit-tests/unit-test.c
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr ""
+"executa només el conjunt de proves o la prova individual <suite[::test]>"
+
+#: t/unit-tests/unit-test.c
+msgid "suite"
+msgstr "suite"
+
+#: t/unit-tests/unit-test.c
+msgid "exclude test suite <suite>"
+msgstr "exclou conjunt de proves <conjunt>"
+
+#: trailer.c
 #, c-format
 msgid "running trailer command '%s' failed"
 msgstr "l'execució de l'ordre «trailer» «%s» ha fallat"
 
+#: trailer.c
 #, c-format
 msgid "unknown value '%s' for key '%s'"
 msgstr "valor desconegut «%s» per a la clau «%s»"
 
+#: trailer.c
 #, c-format
 msgid "empty trailer token in trailer '%.*s'"
 msgstr "testimoni de «trailer» buit en el «trailer» «%.*s»"
 
-#, c-format
-msgid "could not read input file '%s'"
-msgstr "no s'ha pogut llegir el fitxer d'entrada «%s»"
-
-#, c-format
-msgid "could not stat %s"
-msgstr "no s'ha pogut fer stat a %s"
-
-#, c-format
-msgid "file %s is not a regular file"
-msgstr "el fitxer %s no és un fitxer regular"
-
-#, c-format
-msgid "file %s is not writable by user"
-msgstr "el fitxer %s no és gravable per l'usuari"
-
-msgid "could not open temporary file"
-msgstr "no s'ha pogut obrir el fitxer temporal"
-
-#, c-format
-msgid "could not rename temporary file to %s"
-msgstr "no s'ha pogut canviar el nom del fitxer temporal a %s"
-
+#: transport-helper.c
 msgid "full write to remote helper failed"
 msgstr "l'escriptura completa a l'ajudant remot ha fallat"
 
+#: transport-helper.c
 #, c-format
 msgid "unable to find remote helper for '%s'"
 msgstr "no s'ha pogut trobar l'ajudant remot per a «%s»"
 
+#: transport-helper.c
 msgid "can't dup helper output fd"
 msgstr "no es pot duplicar la sortida de l'ajudant «fd»"
 
+#: transport-helper.c
 #, c-format
 msgid ""
 "unknown mandatory capability %s; this remote helper probably needs newer "
@@ -21653,93 +27881,118 @@
 "funcionalitat obligatòria %s desconeguda; aquest ajudant remot probablement "
 "necessita una versió més nova del Git"
 
+#: transport-helper.c
 msgid "this remote helper should implement refspec capability"
 msgstr "aquest ajudant remot ha d'implementar la funcionalitat de refspec"
 
+#: transport-helper.c
 #, c-format
 msgid "%s unexpectedly said: '%s'"
 msgstr "%s ha dit inesperadament «%s»"
 
+#: transport-helper.c
 #, c-format
 msgid "%s also locked %s"
 msgstr "%s també està bloquejat %s"
 
+#: transport-helper.c
 msgid "couldn't run fast-import"
 msgstr "no s'ha pogut executar «fast-import»"
 
+#: transport-helper.c
 msgid "error while running fast-import"
 msgstr "error en executar la importació ràpida"
 
+#: transport-helper.c
 #, c-format
 msgid "could not read ref %s"
 msgstr "no s'ha pogut llegir la referència %s"
 
+#: transport-helper.c
 #, c-format
 msgid "unknown response to connect: %s"
 msgstr "resposta desconeguda en connectar: %s"
 
+#: transport-helper.c
 msgid "setting remote service path not supported by protocol"
 msgstr "el protocol no permet establir el camí del servei remot"
 
+#: transport-helper.c
 msgid "invalid remote service path"
 msgstr "el camí del servei remot no és vàlid"
 
+#: transport-helper.c
 #, c-format
 msgid "can't connect to subservice %s"
 msgstr "no es pot connectar al subservei %s"
 
+#: transport-helper.c transport.c
 msgid "--negotiate-only requires protocol v2"
 msgstr "--negotiate-only requereix el protocol v2"
 
+#: transport-helper.c
 msgid "'option' without a matching 'ok/error' directive"
 msgstr "«option» sense una directiva «ok/error» coincident"
 
+#: transport-helper.c
 #, c-format
 msgid "expected ok/error, helper said '%s'"
 msgstr "s'esperava error/OK, l'ajudant ha dit «%s»"
 
+#: transport-helper.c
 #, c-format
 msgid "helper reported unexpected status of %s"
 msgstr "l'ajudant ha informat d'un estat inesperat de %s"
 
+#: transport-helper.c
 #, c-format
 msgid "helper %s does not support dry-run"
 msgstr "l'ajudant %s no admet dry-run"
 
+#: transport-helper.c
 #, c-format
 msgid "helper %s does not support --signed"
 msgstr "l'ajudant %s no admet --signed"
 
+#: transport-helper.c
 #, c-format
 msgid "helper %s does not support --signed=if-asked"
 msgstr "l'ajudant %s no admet --signed=if-asked"
 
+#: transport-helper.c
 #, c-format
 msgid "helper %s does not support --atomic"
 msgstr "l'ajudant %s no admet --atomic"
 
+#: transport-helper.c
 #, c-format
 msgid "helper %s does not support --%s"
 msgstr "l'ajudant %s no admet --%s"
 
+#: transport-helper.c
 #, c-format
 msgid "helper %s does not support 'push-option'"
 msgstr "l'ajudant %s no admet «push-option»"
 
+#: transport-helper.c
 msgid "remote-helper doesn't support push; refspec needed"
 msgstr ""
-"remot-helper no permet pujar; es necessiten especificacions de referència"
+"remote-helper no permet pujar; es necessiten especificacions de referència"
 
+#: transport-helper.c
 #, c-format
-msgid "helper %s does not support 'force'"
-msgstr "l'ajudant %s no admet «force»"
+msgid "helper %s does not support '--force'"
+msgstr "l'ajudant %s no admet «--force»"
 
+#: transport-helper.c
 msgid "couldn't run fast-export"
 msgstr "no s'ha pogut executar l'exportació ràpida"
 
+#: transport-helper.c
 msgid "error while running fast-export"
 msgstr "error en executar l'exportació ràpida"
 
+#: transport-helper.c
 #, c-format
 msgid ""
 "No refs in common and none specified; doing nothing.\n"
@@ -21748,80 +28001,101 @@
 "No hi ha referències en comú i no n'hi ha cap d'especificada.\n"
 "No es farà res. Potser hauríeu d'especificar una branca.\n"
 
+#: transport-helper.c
 #, c-format
 msgid "unsupported object format '%s'"
 msgstr "format d'objecte no suportat «%s»"
 
+#: transport-helper.c
 #, c-format
 msgid "malformed response in ref list: %s"
 msgstr "resposta mal formada al llistat de referències: %s"
 
+#: transport-helper.c
 #, c-format
 msgid "read(%s) failed"
 msgstr "ha fallat la lectura(%s)"
 
+#: transport-helper.c
 #, c-format
 msgid "write(%s) failed"
 msgstr "ha fallat l'escriptura(%s)"
 
+#: transport-helper.c
 #, c-format
 msgid "%s thread failed"
 msgstr "%s ha fallat el fil"
 
+#: transport-helper.c
 #, c-format
 msgid "%s thread failed to join: %s"
 msgstr "el fil %s no s'ha pogut unir: %s"
 
+#: transport-helper.c
 #, c-format
 msgid "can't start thread for copying data: %s"
 msgstr "no es pot iniciar el fil per a copiar les dades: %s"
 
+#: transport-helper.c
 #, c-format
 msgid "%s process failed to wait"
 msgstr "el procés %s no ha pogut esperar"
 
+#: transport-helper.c
 #, c-format
 msgid "%s process failed"
 msgstr "el procés %s ha fallat"
 
+#: transport-helper.c
 msgid "can't start thread for copying data"
 msgstr "no es pot iniciar el fil per a copiar dades"
 
+#: transport.c
 #, c-format
 msgid "Would set upstream of '%s' to '%s' of '%s'\n"
 msgstr "Canviaria la font de «%s» a «%s» de «%s»\n"
 
+#: transport.c
 #, c-format
 msgid "could not read bundle '%s'"
 msgstr "no s'ha pogut llegir el farcell «%s»"
 
+#: transport.c
 #, c-format
 msgid "transport: invalid depth option '%s'"
 msgstr "transport: opció de profunditat no vàlida «%s»"
 
+#: transport.c
 msgid "see protocol.version in 'git help config' for more details"
 msgstr "vegeu «protocol.version» a «git help config» per a més detalls"
 
+#: transport.c
 msgid "server options require protocol version 2 or later"
 msgstr "les opcions del servidor requereixen el protocol versió 2 o posterior"
 
+#: transport.c
 msgid "server does not support wait-for-done"
 msgstr "el servidor no admet «wait-for-done»"
 
+#: transport.c
 msgid "could not parse transport.color.* config"
 msgstr "no s'ha pogut analitzar la configuració de transport.color.*"
 
+#: transport.c
 msgid "support for protocol v2 not implemented yet"
 msgstr ""
 "encara no s'ha implementat la compatibilitat amb la versió v2 del protocol"
 
+#: transport.c
 #, c-format
 msgid "transport '%s' not allowed"
 msgstr "no es permet el transport «%s»"
 
+#: transport.c
 msgid "git-over-rsync is no longer supported"
 msgstr "git-over-rsync ja no s'admet"
 
+#: transport.c
 #, c-format
 msgid ""
 "The following submodule paths contain changes that can\n"
@@ -21830,6 +28104,7 @@
 "Els camins de submòdul següents contenen canvis que no\n"
 "es poden trobar en cap remot:\n"
 
+#: transport.c
 #, c-format
 msgid ""
 "\n"
@@ -21855,34 +28130,44 @@
 "\n"
 "per a pujar-los a un remot.\n"
 
+#: transport.c
 msgid "Aborting."
 msgstr "S'està avortant."
 
+#: transport.c
 msgid "failed to push all needed submodules"
 msgstr "no s'han pogut pujar tots els submòduls necessaris"
 
+#: transport.c
 msgid "bundle-uri operation not supported by protocol"
 msgstr "L'operació bundle-uri no és compatible amb el protocol"
 
+#: transport.c
 msgid "could not retrieve server-advertised bundle-uri list"
 msgstr ""
 "no s'ha pogut recuperar la llista de paquets d'URI anunciats pel servidor"
 
+#: transport.c
 msgid "operation not supported by protocol"
 msgstr "opció no admesa pel protocol"
 
+#: tree-walk.c
 msgid "too-short tree object"
 msgstr "objecte d'arbre massa curt"
 
+#: tree-walk.c
 msgid "malformed mode in tree entry"
 msgstr "mode mal format en entrada d'arbre"
 
+#: tree-walk.c
 msgid "empty filename in tree entry"
 msgstr "nom de fitxer buit en una entrada d'arbre"
 
+#: tree-walk.c
 msgid "too-short tree file"
 msgstr "fitxer d'arbre massa curt"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by checkout:\n"
@@ -21891,6 +28176,7 @@
 "Els canvis locals als fitxers següents se sobreescriurien per a agafar:\n"
 "%%sCometeu els vostres canvis o feu «stash» abans de canviar de branca."
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by checkout:\n"
@@ -21899,6 +28185,7 @@
 "Els canvis locals als fitxers següents se sobreescriurien per a agafar:\n"
 "%%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by merge:\n"
@@ -21907,6 +28194,7 @@
 "Els canvis locals als fitxers següents se sobreescriurien per a fusionar:\n"
 "%%sCometeu els vostres canvis o feu «stash» abans de fusionar."
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by merge:\n"
@@ -21915,6 +28203,7 @@
 "Els canvis locals als fitxers següents se sobreescriurien per a fusionar:\n"
 "%%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by %s:\n"
@@ -21923,6 +28212,7 @@
 "Els vostres canvis locals als fitxers següents se sobreescriurien per %s:\n"
 "%%sCometeu els vostres canvis o feu «stash» abans de %s."
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by %s:\n"
@@ -21931,6 +28221,7 @@
 "Els vostres canvis locals als fitxers següents se sobreescriurien per %s:\n"
 "%%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "Updating the following directories would lose untracked files in them:\n"
@@ -21939,6 +28230,7 @@
 "En actualitzar els directoris següents perdria fitxers no seguits en el:\n"
 "%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "Refusing to remove the current working directory:\n"
@@ -21947,6 +28239,7 @@
 "S'ha rebutjat suprimir el directori de treball actual:\n"
 "%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by checkout:\n"
@@ -21956,6 +28249,7 @@
 "agafar:\n"
 "%%sMoveu-los o elimineu-los abans de canviar de branca."
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by checkout:\n"
@@ -21965,6 +28259,7 @@
 "agafar:\n"
 "%%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by merge:\n"
@@ -21974,6 +28269,7 @@
 "fusionar:\n"
 "%%sMoveu-los o elimineu-los abans de fusionar."
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by merge:\n"
@@ -21983,6 +28279,7 @@
 "fusionar:\n"
 "%%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by %s:\n"
@@ -21991,6 +28288,7 @@
 "Els següents fitxers no seguits en l'arbre de treball s'eliminarien per %s:\n"
 "%%sMoveu-los o elimineu-los abans de %s."
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by %s:\n"
@@ -21999,6 +28297,7 @@
 "Els següents fitxers no seguits en l'arbre de treball s'eliminarien per %s:\n"
 "%%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by "
@@ -22009,6 +28308,7 @@
 "a agafar:\n"
 "%%sMoveu-los o elimineu-los abans de canviar de branca."
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by "
@@ -22019,6 +28319,7 @@
 "a agafar:\n"
 "%%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by merge:\n"
@@ -22028,6 +28329,7 @@
 "a fusionar:\n"
 "%%sMoveu-los o elimineu-los abans de fusionar."
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by merge:\n"
@@ -22037,6 +28339,7 @@
 "a fusionar:\n"
 "%%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by %s:\n"
@@ -22046,6 +28349,7 @@
 "%s:\n"
 "%%sMoveu-los o elimineu-los abans de %s."
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by %s:\n"
@@ -22055,10 +28359,12 @@
 "%s:\n"
 "%%s"
 
+#: unpack-trees.c
 #, c-format
 msgid "Entry '%s' overlaps with '%s'.  Cannot bind."
 msgstr "L'entrada «%s» encavalca amb «%s».  No es pot vincular."
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "Cannot update submodule:\n"
@@ -22067,6 +28373,7 @@
 "No es pot actualitzar el submòdul:\n"
 "%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following paths are not up to date and were left despite sparse "
@@ -22077,6 +28384,7 @@
 "patrons dispersos:\n"
 "%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following paths are unmerged and were left despite sparse patterns:\n"
@@ -22086,6 +28394,7 @@
 "dispersos:\n"
 "%s"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "The following paths were already present and thus not updated despite sparse "
@@ -22096,10 +28405,12 @@
 "malgrat els patrons dispersos.:\n"
 "%s"
 
+#: unpack-trees.c
 #, c-format
 msgid "Aborting\n"
 msgstr "S'està avortant\n"
 
+#: unpack-trees.c
 #, c-format
 msgid ""
 "After fixing the above paths, you may want to run `git sparse-checkout "
@@ -22108,9 +28419,11 @@
 "Després de corregir els camins anteriors és possible que vulgueu executar "
 "«git sparse-checkout reapply».\n"
 
+#: unpack-trees.c
 msgid "Updating files"
 msgstr "S'estan actualitzant els fitxers"
 
+#: unpack-trees.c
 msgid ""
 "the following paths have collided (e.g. case-sensitive paths\n"
 "on a case-insensitive filesystem) and only one from the same\n"
@@ -22121,273 +28434,358 @@
 "minúscules). Només un camí del mateix grup de col·lisió es troba a l'arbre\n"
 "de treball:\n"
 
+#: unpack-trees.c
 msgid "Updating index flags"
 msgstr "Actualitzant els indicadors d'índex"
 
+#: unpack-trees.c
 #, c-format
 msgid "worktree and untracked commit have duplicate entries: %s"
 msgstr ""
 "l'arbre de treball i la comissió no seguida tenen entrades duplicades: %s"
 
+#: upload-pack.c
 msgid "expected flush after fetch arguments"
 msgstr "s'esperava una neteja després dels arguments del «fetch»"
 
+#: urlmatch.c
 msgid "invalid URL scheme name or missing '://' suffix"
 msgstr "l'esquema d'URL no és vàlid o li manca el sufix «://»"
 
+#: urlmatch.c
 #, c-format
 msgid "invalid %XX escape sequence"
 msgstr "seqüència d'escapament %XX no vàlida"
 
+#: urlmatch.c
 msgid "missing host and scheme is not 'file:'"
 msgstr "manca la màquina i l'esquema no és «file:»"
 
+#: urlmatch.c
 msgid "a 'file:' URL may not have a port number"
 msgstr "un URL «file:» no pot tenir número de port"
 
+#: urlmatch.c
 msgid "invalid characters in host name"
 msgstr "hi ha caràcters no vàlids en el nom de màquina"
 
+#: urlmatch.c
 msgid "invalid port number"
 msgstr "número de port no vàlid"
 
+#: urlmatch.c
 msgid "invalid '..' path segment"
 msgstr "segment de camí «..» no vàlid"
 
+#: usage.c
+#, c-format
+msgid "error: unable to format message: %s\n"
+msgstr "error: no s'ha pogut formatar el missatge: %s\n"
+
+#: usage.c
 msgid "usage: "
 msgstr "ús: "
 
+#: usage.c
 msgid "fatal: "
 msgstr "fatal: "
 
+#: usage.c
 msgid "error: "
 msgstr "error: "
 
+#: usage.c
 msgid "warning: "
 msgstr "avís: "
 
+#: walker.c
 msgid "Fetching objects"
 msgstr "S'estan obtenint objectes"
 
+#: worktree.c
 #, c-format
 msgid "'%s' at main working tree is not the repository directory"
 msgstr "«%s» a l'arbre de treball principal no és al directori del repositori"
 
+#: worktree.c
 #, c-format
 msgid "'%s' file does not contain absolute path to the working tree location"
 msgstr ""
 "El fitxer «%s» no conté el camí absolut a la ubicació de l'arbre de treball"
 
+#: worktree.c
 #, c-format
 msgid "'%s' is not a .git file, error code %d"
 msgstr "«%s» no és un fitxer .git, codi d'error %d"
 
+#: worktree.c
 #, c-format
 msgid "'%s' does not point back to '%s'"
 msgstr "«%s» no assenyala de tornada a «%s»"
 
+#: worktree.c
 msgid "not a directory"
 msgstr "no és en un directori"
 
+#: worktree.c
 msgid ".git is not a file"
 msgstr ".git no és un fitxer"
 
+#: worktree.c
 msgid ".git file broken"
 msgstr "fitxer .git malmès"
 
+#: worktree.c
 msgid ".git file incorrect"
 msgstr "fitxer .git incorrecte"
 
+#: worktree.c
 msgid "not a valid path"
 msgstr "no és un camí vàlid"
 
+#: worktree.c
 msgid "unable to locate repository; .git is not a file"
 msgstr "no s'ha pogut trobar el repositori; .git no és un fitxer"
 
+#: worktree.c
 msgid "unable to locate repository; .git file does not reference a repository"
 msgstr ""
 "no s'ha pogut trobar el repositori; el fitxer .git no fa referència a un "
 "repositori"
 
+#: worktree.c
 msgid "unable to locate repository; .git file broken"
 msgstr "no s'ha pogut trobar el repositori; el fitxer .git està malmès"
 
+#: worktree.c
 msgid "gitdir unreadable"
 msgstr "gitdir illegible"
 
+#: worktree.c
 msgid "gitdir incorrect"
 msgstr "gitdir incorrecte"
 
+#: worktree.c
 msgid "not a valid directory"
 msgstr "no és en un directori vàlid"
 
+#: worktree.c
 msgid "gitdir file does not exist"
 msgstr "el fitxer gitdir no existeix"
 
+#: worktree.c
 #, c-format
 msgid "unable to read gitdir file (%s)"
 msgstr "no s'ha pogut llegir el fitxer gitdir (%s)"
 
+#: worktree.c
 #, c-format
 msgid "short read (expected %<PRIuMAX> bytes, read %<PRIuMAX>)"
-msgstr "lectura curta (s'esperaven %<PRIuMAX> bytes, llegits %<PRIuMAX>)"
+msgstr "lectura curta (s'esperaven %<PRIuMAX> octets, s'han llegit %<PRIuMAX>)"
 
+#: worktree.c
 msgid "invalid gitdir file"
 msgstr "fitxer gitdir no vàlid"
 
+#: worktree.c
 msgid "gitdir file points to non-existent location"
 msgstr "el fitxer gitdir indica una ubicació no existent"
 
+#: worktree.c
 #, c-format
 msgid "unable to set %s in '%s'"
 msgstr "no s'han pogut establir %s en «%s»"
 
+#: worktree.c
 #, c-format
 msgid "unable to unset %s in '%s'"
 msgstr "no s'ha pogut desassignar %s en «%s»"
 
+#: worktree.c
 msgid "failed to set extensions.worktreeConfig setting"
 msgstr "no s'ha pogut establir el paràmetre extensions.worktreeConfig"
 
+#: wrapper.c
 #, c-format
 msgid "could not setenv '%s'"
 msgstr "no s'ha pogut fer setenv «%s»"
 
+#: wrapper.c
 #, c-format
 msgid "unable to create '%s'"
 msgstr "no s'ha pogut crear «%s»"
 
+#: wrapper.c
 #, c-format
 msgid "could not open '%s' for reading and writing"
 msgstr "no s'ha pogut obrir «%s» per a lectura i escriptura"
 
+#: wrapper.c
 #, c-format
 msgid "unable to access '%s'"
 msgstr "no s'ha pogut accedir a «%s»"
 
+#: wrapper.c
 msgid "unable to get current working directory"
 msgstr "no s'ha pogut obtenir el directori de treball actual"
 
+#: wrapper.c
 msgid "unable to get random bytes"
-msgstr "no s'han pogut obtenir bytes aleatoris"
+msgstr "no s'han pogut obtenir octets aleatoris"
 
+#: wt-status.c
 msgid "Unmerged paths:"
 msgstr "Camins sense fusionar:"
 
+#: wt-status.c
 msgid "  (use \"git restore --staged <file>...\" to unstage)"
 msgstr "  (useu «git restore --staged <fitxer>...» per a fer «unstage»)"
 
+#: wt-status.c
 #, c-format
 msgid "  (use \"git restore --source=%s --staged <file>...\" to unstage)"
 msgstr ""
 "  (useu «git restore --source=%s --staged <fitxer>...» per a fer «unstage»)"
 
+#: wt-status.c
 msgid "  (use \"git rm --cached <file>...\" to unstage)"
 msgstr "  (useu «git rm --cached <fitxer>...» per a fer «unstage»)"
 
+#: wt-status.c
 msgid "  (use \"git add <file>...\" to mark resolution)"
 msgstr "  (useu «git add <fitxer>...» per a senyalar resolució)"
 
+#: wt-status.c
 msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
 msgstr ""
 "  (useu «git add/rm <fitxer>...» segons sigui apropiat per a senyalar "
 "resolució)"
 
+#: wt-status.c
 msgid "  (use \"git rm <file>...\" to mark resolution)"
 msgstr "  (useu «git rm <fitxer>...» per a senyalar resolució)"
 
+#: wt-status.c
 msgid "Changes to be committed:"
 msgstr "Canvis a cometre:"
 
+#: wt-status.c
 msgid "Changes not staged for commit:"
 msgstr "Canvis no «staged» per a cometre:"
 
+#: wt-status.c
 msgid "  (use \"git add <file>...\" to update what will be committed)"
 msgstr "  (useu «git add <fitxer>...» per a actualitzar què es cometrà)"
 
+#: wt-status.c
 msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
 msgstr "  (useu «git add/rm <fitxer>...» per a actualitzar què es cometrà)"
 
+#: wt-status.c
 msgid ""
 "  (use \"git restore <file>...\" to discard changes in working directory)"
 msgstr ""
 "  (useu «git restore <fitxer>...» per a descartar canvis en el directori de "
 "treball)"
 
+#: wt-status.c
 msgid "  (commit or discard the untracked or modified content in submodules)"
 msgstr ""
 "  (cometeu o descarteu el contingut modificat o no seguit en els submòduls)"
 
+#: wt-status.c
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
 msgstr "  (useu «git %s <fitxer>...» per a incloure'ls en la comissió)"
 
+#: wt-status.c
 msgid "both deleted:"
 msgstr "suprimit per ambdós:"
 
+#: wt-status.c
 msgid "added by us:"
 msgstr "afegit per nosaltres:"
 
+#: wt-status.c
 msgid "deleted by them:"
 msgstr "suprimit per ells:"
 
+#: wt-status.c
 msgid "added by them:"
 msgstr "afegit per ells:"
 
+#: wt-status.c
 msgid "deleted by us:"
 msgstr "suprimit per nosaltres:"
 
+#: wt-status.c
 msgid "both added:"
 msgstr "afegit per ambdós:"
 
+#: wt-status.c
 msgid "both modified:"
 msgstr "modificat per ambdós:"
 
+#: wt-status.c
 msgid "new file:"
 msgstr "fitxer nou:"
 
+#: wt-status.c
 msgid "copied:"
 msgstr "copiat:"
 
+#: wt-status.c
 msgid "deleted:"
 msgstr "suprimit:"
 
+#: wt-status.c
 msgid "modified:"
 msgstr "modificat:"
 
+#: wt-status.c
 msgid "renamed:"
 msgstr "canviat de nom:"
 
+#: wt-status.c
 msgid "typechange:"
 msgstr "canviat de tipus:"
 
+#: wt-status.c
 msgid "unknown:"
 msgstr "desconegut:"
 
+#: wt-status.c
 msgid "unmerged:"
 msgstr "sense fusionar:"
 
+#: wt-status.c
 msgid "new commits, "
 msgstr "comissions noves, "
 
+#: wt-status.c
 msgid "modified content, "
 msgstr "contingut modificat, "
 
+#: wt-status.c
 msgid "untracked content, "
 msgstr "contingut no seguit, "
 
+#: wt-status.c
 #, c-format
 msgid "Your stash currently has %d entry"
 msgid_plural "Your stash currently has %d entries"
 msgstr[0] "L'«stash» té actualment %d entrada"
 msgstr[1] "L'«stash» té actualment %d entrades"
 
+#: wt-status.c
 msgid "Submodules changed but not updated:"
 msgstr "Submòduls canviats però no actualitzats:"
 
+#: wt-status.c
 msgid "Submodule changes to be committed:"
 msgstr "Canvis de submòdul a cometre:"
 
+#: wt-status.c
 msgid ""
 "Do not modify or remove the line above.\n"
 "Everything below it will be ignored."
@@ -22395,6 +28793,7 @@
 "No modifiqueu ni elimineu la línia de dalt.\n"
 "Tot el que hi ha a sota s'ignorarà."
 
+#: wt-status.c
 #, c-format
 msgid ""
 "\n"
@@ -22406,90 +28805,115 @@
 "darrere.\n"
 "Podeu utilitzar «--no-ahead-behind» per a evitar-ho.\n"
 
+#: wt-status.c
 msgid "You have unmerged paths."
 msgstr "Teniu camins sense fusionar."
 
+#: wt-status.c
 msgid "  (fix conflicts and run \"git commit\")"
 msgstr "  (arregleu els conflictes i executeu «git commit»)"
 
+#: wt-status.c
 msgid "  (use \"git merge --abort\" to abort the merge)"
 msgstr "  (useu «git merge --abort» per a avortar la fusió)"
 
+#: wt-status.c
 msgid "All conflicts fixed but you are still merging."
 msgstr "Tots els conflictes estan arreglats però encara esteu fusionant."
 
+#: wt-status.c
 msgid "  (use \"git commit\" to conclude merge)"
 msgstr "  (useu «git commit» per a concloure la fusió)"
 
+#: wt-status.c
 msgid "You are in the middle of an am session."
 msgstr "Esteu enmig d'una sessió am."
 
+#: wt-status.c
 msgid "The current patch is empty."
 msgstr "El pedaç actual està buit."
 
+#: wt-status.c
 msgid "  (fix conflicts and then run \"git am --continue\")"
 msgstr "  (arregleu els conflictes i després executeu «git am --continue»)"
 
+#: wt-status.c
 msgid "  (use \"git am --skip\" to skip this patch)"
 msgstr "  (useu «git am --skip» per a ometre aquest pedaç)"
 
+#: wt-status.c
 msgid ""
 "  (use \"git am --allow-empty\" to record this patch as an empty commit)"
 msgstr ""
 "  (useu «git am --allow-empty» per a enregistrar aquest pedaç com una "
 "comissió buida)"
 
+#: wt-status.c
 msgid "  (use \"git am --abort\" to restore the original branch)"
 msgstr "  (useu «git am --abort» per a restaurar la branca original)"
 
+#: wt-status.c
 msgid "git-rebase-todo is missing."
 msgstr "Manca git-rebase-todo."
 
+#: wt-status.c
 msgid "No commands done."
 msgstr "No s'ha fet cap ordre."
 
+#: wt-status.c
 #, c-format
 msgid "Last command done (%<PRIuMAX> command done):"
 msgid_plural "Last commands done (%<PRIuMAX> commands done):"
 msgstr[0] "Darrera ordre acabada (%<PRIuMAX> ordre acabada):"
 msgstr[1] "Darreres ordres acabades (%<PRIuMAX> ordres acabades):"
 
+#: wt-status.c
 #, c-format
 msgid "  (see more in file %s)"
 msgstr "  (vegeu més en el fitxer %s)"
 
+#: wt-status.c
 msgid "No commands remaining."
 msgstr "No manca cap ordre."
 
+#: wt-status.c
 #, c-format
 msgid "Next command to do (%<PRIuMAX> remaining command):"
 msgid_plural "Next commands to do (%<PRIuMAX> remaining commands):"
 msgstr[0] "Següent ordre a fer (%<PRIuMAX> ordre restant):"
 msgstr[1] "Següents ordres a fer (%<PRIuMAX> ordres restants):"
 
+#: wt-status.c
 msgid "  (use \"git rebase --edit-todo\" to view and edit)"
 msgstr "  (useu «git rebase --edit-todo» per a veure i editar)"
 
+#: wt-status.c
 #, c-format
 msgid "You are currently rebasing branch '%s' on '%s'."
 msgstr "Actualment esteu fent «rebase» de la branca «%s» en «%s»."
 
+#: wt-status.c
 msgid "You are currently rebasing."
 msgstr "Actualment esteu fent «rebase»."
 
+#: wt-status.c
 msgid "  (fix conflicts and then run \"git rebase --continue\")"
 msgstr "  (arregleu els conflictes i després executeu «git rebase --continue»)"
 
+#: wt-status.c
 msgid "  (use \"git rebase --skip\" to skip this patch)"
 msgstr "  (useu «git rebase --skip» per a ometre aquest pedaç)"
 
+#: wt-status.c
 msgid "  (use \"git rebase --abort\" to check out the original branch)"
 msgstr "  (useu «git rebase --abort» per a agafar la branca original)"
 
+#: wt-status.c
 msgid "  (all conflicts fixed: run \"git rebase --continue\")"
 msgstr ""
 "  (tots els conflictes estan arreglats: executeu «git rebase --continue»)"
 
+#: wt-status.c
 #, c-format
 msgid ""
 "You are currently splitting a commit while rebasing branch '%s' on '%s'."
@@ -22497,128 +28921,164 @@
 "Actualment esteu dividint una comissió mentre es fa «rebase» de la branca "
 "«%s» en «%s»."
 
+#: wt-status.c
 msgid "You are currently splitting a commit during a rebase."
 msgstr "Actualment esteu dividint una comissió durant un «rebase»."
 
+#: wt-status.c
 msgid "  (Once your working directory is clean, run \"git rebase --continue\")"
 msgstr ""
 "  (Una vegada que el vostre directori de treball sigui net, executeu «git "
 "rebase --continue»)"
 
+#: wt-status.c
 #, c-format
 msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
 msgstr ""
 "Actualment esteu editant una comissió mentre es fa «rebase» de la branca "
 "«%s» en «%s»."
 
+#: wt-status.c
 msgid "You are currently editing a commit during a rebase."
 msgstr "Actualment esteu editant una comissió durant un «rebase»."
 
+#: wt-status.c
 msgid "  (use \"git commit --amend\" to amend the current commit)"
 msgstr "  (useu «git commit --amend» per a esmenar la comissió actual)"
 
+#: wt-status.c
 msgid ""
 "  (use \"git rebase --continue\" once you are satisfied with your changes)"
 msgstr ""
 "  (useu «git rebase --continue» una vegada que estigueu satisfet amb els "
 "vostres canvis)"
 
+#: wt-status.c
 msgid "Cherry-pick currently in progress."
 msgstr "Hi ha «cherry pick» actualment en curs."
 
+#: wt-status.c
 #, c-format
 msgid "You are currently cherry-picking commit %s."
 msgstr "Actualment esteu fent «cherry pick» a la comissió %s."
 
+#: wt-status.c
 msgid "  (fix conflicts and run \"git cherry-pick --continue\")"
 msgstr "  (arregleu els conflictes i executeu «git cherry-pick --continue»)"
 
+#: wt-status.c
 msgid "  (run \"git cherry-pick --continue\" to continue)"
 msgstr "  (executeu «git cherry-pick --continue» per a continuar)"
 
+#: wt-status.c
 msgid "  (all conflicts fixed: run \"git cherry-pick --continue\")"
 msgstr ""
 "  (tots els conflictes estan arreglats: executeu «git cherry-pick --"
 "continue»)"
 
+#: wt-status.c
 msgid "  (use \"git cherry-pick --skip\" to skip this patch)"
 msgstr "  (useu «git cherry-pick --skip» per a ometre aquest pedaç)"
 
+#: wt-status.c
 msgid "  (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
 msgstr ""
 "  (useu «git cherry-pick --abort» per a cancel·lar l'operació de «cherry "
 "pick»)"
 
+#: wt-status.c
 msgid "Revert currently in progress."
 msgstr "Una reversió està actualment en curs."
 
+#: wt-status.c
 #, c-format
 msgid "You are currently reverting commit %s."
 msgstr "Actualment esteu revertint la comissió %s."
 
+#: wt-status.c
 msgid "  (fix conflicts and run \"git revert --continue\")"
 msgstr "  (arregleu els conflictes i executeu «git revert --continue»)"
 
+#: wt-status.c
 msgid "  (run \"git revert --continue\" to continue)"
 msgstr "  (executeu «git revert --continue» per a continuar)"
 
+#: wt-status.c
 msgid "  (all conflicts fixed: run \"git revert --continue\")"
 msgstr ""
 "  (tots els conflictes estan arreglats: executeu «git revert --continue»)"
 
+#: wt-status.c
 msgid "  (use \"git revert --skip\" to skip this patch)"
 msgstr "  (useu «git revert --skip» per a ometre aquest pedaç)"
 
+#: wt-status.c
 msgid "  (use \"git revert --abort\" to cancel the revert operation)"
 msgstr "  (useu «git revert --abort» per a cancel·lar l'operació de reversió)"
 
+#: wt-status.c
 #, c-format
 msgid "You are currently bisecting, started from branch '%s'."
 msgstr "Actualment esteu bisecant, heu començat des de la branca «%s»."
 
+#: wt-status.c
 msgid "You are currently bisecting."
 msgstr "Actualment esteu bisecant."
 
+#: wt-status.c
 msgid "  (use \"git bisect reset\" to get back to the original branch)"
 msgstr "  (useu «git bisect reset» per a tornar a la branca original)"
 
+#: wt-status.c
 msgid "You are in a sparse checkout."
 msgstr "Esteu en un «sparse-checkout»."
 
+#: wt-status.c
 #, c-format
 msgid "You are in a sparse checkout with %d%% of tracked files present."
 msgstr "Esteu en un «sparse-checkout» amb un %d%% de fitxers seguits presents."
 
+#: wt-status.c
 msgid "On branch "
 msgstr "En la branca "
 
+#: wt-status.c
 msgid "interactive rebase in progress; onto "
 msgstr "«rebase» interactiu en curs; sobre "
 
+#: wt-status.c
 msgid "rebase in progress; onto "
 msgstr "«rebase» en curs; sobre "
 
+#: wt-status.c
 msgid "HEAD detached at "
 msgstr "HEAD separat a "
 
+#: wt-status.c
 msgid "HEAD detached from "
 msgstr "HEAD separat des de "
 
+#: wt-status.c
 msgid "Not currently on any branch."
 msgstr "Actualment no s'és en cap branca."
 
+#: wt-status.c
 msgid "Initial commit"
 msgstr "Comissió inicial"
 
+#: wt-status.c
 msgid "No commits yet"
 msgstr "No s'ha fet cap comissió encara"
 
+#: wt-status.c
 msgid "Untracked files"
 msgstr "Fitxers no seguits"
 
+#: wt-status.c
 msgid "Ignored files"
 msgstr "Fitxers ignorats"
 
+#: wt-status.c
 #, c-format
 msgid ""
 "It took %.2f seconds to enumerate untracked files,\n"
@@ -22628,32 +29088,40 @@
 "però els resultats es van emmagatzemar a la memòria cau, i les\n"
 "execucions posteriors podrien ser més ràpides."
 
+#: wt-status.c
 #, c-format
 msgid "It took %.2f seconds to enumerate untracked files."
 msgstr "S'han trigat %.2f segons a enumerar els fitxers sense seguiment."
 
+#: wt-status.c
 msgid "See 'git help status' for information on how to improve this."
 msgstr ""
 "Vegeu «git help status» per a obtenir informació sobre com millorar-ho."
 
+#: wt-status.c
 #, c-format
 msgid "Untracked files not listed%s"
 msgstr "Els fitxers no seguits no estan llistats%s"
 
+#: wt-status.c
 msgid " (use -u option to show untracked files)"
 msgstr " (useu l'opció -u per a mostrar els fitxers no seguits)"
 
+#: wt-status.c
 msgid "No changes"
 msgstr "Sense canvis"
 
+#: wt-status.c
 #, c-format
 msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
 msgstr "no hi ha canvis afegits a cometre (useu «git add» o «git commit -a»)\n"
 
+#: wt-status.c
 #, c-format
 msgid "no changes added to commit\n"
 msgstr "no hi ha canvis afegits a cometre\n"
 
+#: wt-status.c
 #, c-format
 msgid ""
 "nothing added to commit but untracked files present (use \"git add\" to "
@@ -22662,60 +29130,75 @@
 "no hi ha res afegit a cometre però hi ha fitxers no seguits (useu «git add» "
 "per a seguir-los)\n"
 
+#: wt-status.c
 #, c-format
 msgid "nothing added to commit but untracked files present\n"
 msgstr "no hi ha res afegit a cometre però hi ha fitxers no seguits\n"
 
+#: wt-status.c
 #, c-format
 msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
 msgstr ""
 "no hi ha res a cometre (creeu/copieu fitxers i useu «git add» per a seguir-"
 "los)\n"
 
+#: wt-status.c
 #, c-format
 msgid "nothing to commit\n"
 msgstr "no hi ha res a cometre\n"
 
+#: wt-status.c
 #, c-format
 msgid "nothing to commit (use -u to show untracked files)\n"
 msgstr ""
 "no hi ha res a cometre (useu -u per a mostrar els fitxers no seguits)\n"
 
+#: wt-status.c
 #, c-format
 msgid "nothing to commit, working tree clean\n"
 msgstr "no hi ha res a cometre, l'arbre de treball està net\n"
 
+#: wt-status.c
 msgid "No commits yet on "
 msgstr "No s'ha fet cap comissió encara a "
 
+#: wt-status.c
 msgid "HEAD (no branch)"
 msgstr "HEAD (sense branca)"
 
+#: wt-status.c
 msgid "different"
 msgstr "diferent"
 
+#: wt-status.c
 msgid "behind "
 msgstr "darrere "
 
+#: wt-status.c
 msgid "ahead "
 msgstr "davant per "
 
 #. TRANSLATORS: the action is e.g. "pull with rebase"
+#: wt-status.c
 #, c-format
 msgid "cannot %s: You have unstaged changes."
 msgstr "no es pot %s: Teniu canvis «unstaged»."
 
+#: wt-status.c
 msgid "additionally, your index contains uncommitted changes."
 msgstr "addicionalment, el vostre índex conté canvis sense cometre."
 
+#: wt-status.c
 #, c-format
 msgid "cannot %s: Your index contains uncommitted changes."
 msgstr "no es pot %s: El vostre índex conté canvis sense cometre."
 
+#: xdiff-interface.c
 #, c-format
 msgid "unknown style '%s' given for '%s'"
 msgstr "estil desconegut «%s» donat per a «%s»"
 
+#: git-merge-octopus.sh git-merge-resolve.sh
 msgid ""
 "Error: Your local changes to the following files would be overwritten by "
 "merge"
@@ -22723,92 +29206,120 @@
 "Error: Els vostres canvis locals als fitxers següents se sobreescriurien per "
 "a fusionar"
 
+#: git-merge-octopus.sh
 msgid "Automated merge did not work."
 msgstr "La fusió automàtica no ha funcionat."
 
+#: git-merge-octopus.sh
 msgid "Should not be doing an octopus."
 msgstr "No s'ha de fer un «octopus»."
 
+#: git-merge-octopus.sh
 #, sh-format
 msgid "Unable to find common commit with $pretty_name"
 msgstr "No s'ha pogut trobar cap comissió en comú amb $pretty_name"
 
+#: git-merge-octopus.sh
 #, sh-format
 msgid "Already up to date with $pretty_name"
 msgstr "Ja està al dia amb $pretty_name"
 
+#: git-merge-octopus.sh
 #, sh-format
 msgid "Fast-forwarding to: $pretty_name"
 msgstr "S'està avançant ràpidament a: $pretty_name"
 
+#: git-merge-octopus.sh
 #, sh-format
 msgid "Trying simple merge with $pretty_name"
 msgstr "S'està intentant una fusió simple amb $pretty_name"
 
+#: git-merge-octopus.sh
 msgid "Simple merge did not work, trying automatic merge."
 msgstr ""
 "La fusió simple no ha funcionat, s'està intentant una fusió automàtica."
 
+#: git-sh-setup.sh
 #, sh-format
 msgid "usage: $dashless $USAGE"
 msgstr "ús: $dashless $USAGE"
 
+#: git-sh-setup.sh
 #, sh-format
 msgid "Cannot chdir to $cdup, the toplevel of the working tree"
 msgstr ""
 "No es pot canviar de directori a $cdup, el nivell superior de l'arbre de "
 "treball"
 
+#: git-sh-setup.sh
 #, sh-format
 msgid "fatal: $program_name cannot be used without a working tree."
 msgstr "fatal: no es pot usar $program_name sense un arbre de treball."
 
+#: git-sh-setup.sh
 msgid "Cannot rewrite branches: You have unstaged changes."
 msgstr "No es poden reescriure branques: Teniu canvis «unstaged»."
 
+#: git-sh-setup.sh
 #, sh-format
 msgid "Cannot $action: You have unstaged changes."
 msgstr "No es pot $action: Teniu canvis «unstaged»."
 
+#: git-sh-setup.sh
 #, sh-format
 msgid "Cannot $action: Your index contains uncommitted changes."
 msgstr "No es pot $action: El vostre índex conté canvis sense cometre."
 
+#: git-sh-setup.sh
 msgid "Additionally, your index contains uncommitted changes."
 msgstr "Addicionalment, el vostre índex conté canvis sense cometre."
 
+#: git-sh-setup.sh
 msgid "You need to run this command from the toplevel of the working tree."
 msgstr ""
 "Heu d'executar aquesta ordre des del nivell superior de l'arbre de treball."
 
+#: git-sh-setup.sh
 msgid "Unable to determine absolute path of git directory"
 msgstr "No s'ha pogut determinar el camí absolut del directori de git"
 
+#: git-send-email.perl
 msgid "local zone differs from GMT by a non-minute interval\n"
 msgstr "la zona local difereix de GMT per un interval que no és de minuts\n"
 
+#: git-send-email.perl
 msgid "local time offset greater than or equal to 24 hours\n"
 msgstr "el desplaçament de la zona local és més gran o igual a 24 hores\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "fatal: command '%s' died with exit code %d"
 msgstr "fatal: l'ordre «%s» ha mort amb el codi de sortida %d"
 
+#: git-send-email.perl
 msgid "the editor exited uncleanly, aborting everything"
 msgstr "l'editor no ha sortit correctament, avortant-ho tot"
 
+#: git-send-email.perl
 #, perl-format
 msgid ""
 "'%s' contains an intermediate version of the email you were composing.\n"
 msgstr "«%s» conté una versió intermèdia del correu que estàveu redactant.\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "'%s.final' contains the composed email.\n"
 msgstr "«%s.final» conté el correu redactat.\n"
 
+#: git-send-email.perl
 msgid "--dump-aliases incompatible with other options\n"
 msgstr "--dump-aliases és incompatible amb altres opcions\n"
 
+#: git-send-email.perl
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases i --translate-aliases s'exclouen mútuament\n"
+
+#: git-send-email.perl
 msgid ""
 "fatal: found configuration options for 'sendmail'\n"
 "git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -22819,9 +29330,11 @@
 "la «e». Establiu sendemail.forbidSendmailVariables a false per a desactivar\n"
 "la comprovació.\n"
 
+#: git-send-email.perl
 msgid "Cannot run git format-patch from outside a repository\n"
 msgstr "No es pot executar git format-patch des de fora del repositori\n"
 
+#: git-send-email.perl
 msgid ""
 "`batch-size` and `relogin` must be specified together (via command-line or "
 "configuration option)\n"
@@ -22829,30 +29342,37 @@
 "«batch-size» i «relogin» s'han d'especificar junts (a través de la línia "
 "d'ordres o l'opció de configuració)\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "Unknown --suppress-cc field: '%s'\n"
 msgstr "Camp --suppress-cc desconegut: «%s»\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "Unknown --confirm setting: '%s'\n"
 msgstr "Paràmetre --confirm desconegut: «%s»\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "warning: sendmail alias with quotes is not supported: %s\n"
 msgstr "avís: no s'admet l'àlies de sendmail amb cometes: %s\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "warning: `:include:` not supported: %s\n"
 msgstr "avís: «:include:» no s'admet: %s\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "warning: `/file` or `|pipe` redirection not supported: %s\n"
 msgstr "avís: les redireccions «/file» ni «|pipe» no s'admeten: %s\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "warning: sendmail line is not recognized: %s\n"
 msgstr "avís: no es pot reconèixer la línia sendmail: %s\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid ""
 "File '%s' exists but it could also be the range of commits\n"
@@ -22867,10 +29387,12 @@
 "    * Dient «./%s» si volíeu especificar un fitxer; o\n"
 "    * Proporcionant l'opció «--format-patch» si volíeu especificar un rang.\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "Failed to opendir %s: %s"
 msgstr "S'ha produït un error en obrir el directori %s: %s"
 
+#: git-send-email.perl
 msgid ""
 "\n"
 "No patch files specified!\n"
@@ -22880,14 +29402,17 @@
 "No s'han especificat fitxers de pedaç\n"
 "\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "No subject line in %s?"
 msgstr "Sense assumpte a %s?"
 
+#: git-send-email.perl
 #, perl-format
 msgid "Failed to open for writing %s: %s"
 msgstr "S'ha produït un error en obrir per escriptura %s: %s"
 
+#: git-send-email.perl
 msgid ""
 "Lines beginning in \"GIT:\" will be removed.\n"
 "Consider including an overall diffstat or table of contents\n"
@@ -22901,22 +29426,27 @@
 "\n"
 "Esborreu el contingut del cos si no voleu enviar cap resum.\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "Failed to open %s.final: %s"
 msgstr "S'ha produït un error en obrir %s.final: %s"
 
+#: git-send-email.perl
 #, perl-format
 msgid "Failed to open %s: %s"
 msgstr "S'ha produït un error en obrir %s: %s"
 
+#: git-send-email.perl
 msgid "Summary email is empty, skipping it\n"
 msgstr "El correu electrònic de resum està buit, s'omet\n"
 
 #. TRANSLATORS: please keep [y/N] as is.
+#: git-send-email.perl
 #, perl-format
 msgid "Are you sure you want to use <%s> [y/N]? "
 msgstr "Esteu segur que voleu usar <%s> [y/N]? "
 
+#: git-send-email.perl
 msgid ""
 "The following files are 8bit, but do not declare a Content-Transfer-"
 "Encoding.\n"
@@ -22924,9 +29454,11 @@
 "Els fitxers següents són 8bit, però no declaren un Content-Transfer-"
 "Encoding.\n"
 
+#: git-send-email.perl
 msgid "Which 8bit encoding should I declare [UTF-8]? "
 msgstr "Quina codificació de 8 bits hauria de declarar [UTF-8]? "
 
+#: git-send-email.perl
 #, perl-format
 msgid ""
 "Refusing to send because the patch\n"
@@ -22939,19 +29471,23 @@
 "perquè la plantilla té l'assumpte «*** SUBJECT HERE ***». Passeu --force si "
 "realment voleu enviar-ho.\n"
 
+#: git-send-email.perl
 msgid "To whom should the emails be sent (if anyone)?"
 msgstr ""
 "A qui s'haurien d'enviar els correus electrònics (si s'han d'enviar a algú)?"
 
+#: git-send-email.perl
 #, perl-format
 msgid "fatal: alias '%s' expands to itself\n"
 msgstr "fatal: l'àlies «%s» s'expandeix a si mateix\n"
 
+#: git-send-email.perl
 msgid "Message-ID to be used as In-Reply-To for the first email (if any)? "
 msgstr ""
 "S'ha d'usar el Message-ID com a In-Reply-To pel primer correu (si n'hi ha "
 "cap)? "
 
+#: git-send-email.perl
 #, perl-format
 msgid "error: unable to extract a valid address from: %s\n"
 msgstr "error: no s'ha pogut extreure una adreça vàlida de: %s\n"
@@ -22959,13 +29495,16 @@
 #. TRANSLATORS: Make sure to include [q] [d] [e] in your
 #. translation. The program will only accept English input
 #. at this point.
+#: git-send-email.perl
 msgid "What to do with this address? ([q]uit|[d]rop|[e]dit): "
 msgstr "Què cal fer amb aquesta adreça? ([q]surt|[d]escarta|[e]dita): "
 
+#: git-send-email.perl
 #, perl-format
 msgid "CA path \"%s\" does not exist"
 msgstr "el camí CA «%s» no existeix"
 
+#: git-send-email.perl
 msgid ""
 "    The Cc list above has been expanded by additional\n"
 "    addresses found in the patch commit message. By default\n"
@@ -22992,95 +29531,121 @@
 #. TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
 #. translation. The program will only accept English input
 #. at this point.
+#: git-send-email.perl
 msgid "Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "
 msgstr ""
 "Voleu enviar aquest correu electrònic? ([y]sí|[n]o|[e]dita|[q]surt|[a]tot): "
 
+#: git-send-email.perl
 msgid "Send this email reply required"
 msgstr "Requereix resposta en enviar el correu"
 
+#: git-send-email.perl
 msgid "The required SMTP server is not properly defined."
 msgstr "El servidor SMTP requerit no està correctament definit."
 
+#: git-send-email.perl
 #, perl-format
 msgid "Server does not support STARTTLS! %s"
 msgstr "El servidor no admet STARTTLS! %s"
 
+#: git-send-email.perl
 #, perl-format
 msgid "STARTTLS failed! %s"
 msgstr "STARTTLS ha fallat! %s"
 
+#: git-send-email.perl
 msgid "Unable to initialize SMTP properly. Check config and use --smtp-debug."
 msgstr ""
 "No s'ha pogut inicialitzar SMTP correctament. Comproveu-ho la configuració i "
 "useu --smtp-debug."
 
+#: git-send-email.perl
 #, perl-format
 msgid "Failed to send %s\n"
 msgstr "S'ha produït un error en enviar %s\n"
 
+#: git-send-email.perl
 #, perl-format
-msgid "Dry-Sent %s\n"
-msgstr "Simulació d'enviament %s\n"
+msgid "Dry-Sent %s"
+msgstr "Prova-Enviat %s"
 
+#: git-send-email.perl
 #, perl-format
-msgid "Sent %s\n"
-msgstr "Enviat %s\n"
+msgid "Sent %s"
+msgstr "Enviat %s"
 
-msgid "Dry-OK. Log says:\n"
-msgstr "Simulació de correcte. El registre diu:\n"
+#: git-send-email.perl
+msgid "Dry-OK. Log says:"
+msgstr "Prova correcta. El registre diu:"
 
-msgid "OK. Log says:\n"
-msgstr "Correcte. El registre diu: \n"
+#: git-send-email.perl
+msgid "OK. Log says:"
+msgstr "Correcte. El registre diu:"
 
+#: git-send-email.perl
 msgid "Result: "
 msgstr "Resultat: "
 
-msgid "Result: OK\n"
-msgstr "Resultat: correcte\n"
+# OK = correcte?
+#: git-send-email.perl
+msgid "Result: OK"
+msgstr "Resultat: correcte"
 
+#: git-send-email.perl
 #, perl-format
 msgid "can't open file %s"
 msgstr "no es pot obrir el fitxer %s"
 
+#: git-send-email.perl
 #, perl-format
 msgid "(mbox) Adding cc: %s from line '%s'\n"
 msgstr "(mbox) S'està afegint cc: %s des de la línia «%s»\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "(mbox) Adding to: %s from line '%s'\n"
 msgstr "(mbox) S'està afegint a: %s des de la línia «%s»\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "(non-mbox) Adding cc: %s from line '%s'\n"
 msgstr "(no mbox) S'està afegint cc: %s des de la línia «%s»\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "(body) Adding cc: %s from line '%s'\n"
 msgstr "(cos) S'està afegint cc: %s des de la línia «%s»\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "(%s) Could not execute '%s'"
 msgstr "(%s) no s'ha pogut executar «%s»"
 
+#: git-send-email.perl
 #, perl-format
 msgid "(%s) Malformed output from '%s'"
 msgstr "(%s) Sortida mal formada de «%s»"
 
+#: git-send-email.perl
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
 msgstr "(%s) s'ha produït un error en tancar el conducte «%s»"
 
+#: git-send-email.perl
 #, perl-format
 msgid "(%s) Adding %s: %s from: '%s'\n"
 msgstr "(%s) S'està afegint %s: %s des de: «%s»\n"
 
+#: git-send-email.perl
 msgid "cannot send message as 7bit"
 msgstr "no es pot enviar el missatge en 7 bits"
 
+#: git-send-email.perl
 msgid "invalid transfer encoding"
 msgstr "codificació de transferència no vàlida"
 
+#: git-send-email.perl
 #, perl-format
 msgid ""
 "fatal: %s: rejected by %s hook\n"
@@ -23091,10 +29656,12 @@
 "%s\n"
 "avís: no s'ha enviat cap pedaç\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "unable to open %s: %s\n"
 msgstr "no s'ha pogut obrir %s: %s\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid ""
 "fatal: %s:%d is longer than 998 characters\n"
@@ -23103,11 +29670,91 @@
 "fatal: %s:%d té més de 998 caràcters\n"
 "avís: no s'ha enviat cap pedaç\n"
 
+#: git-send-email.perl
 #, perl-format
 msgid "Skipping %s with backup suffix '%s'.\n"
 msgstr "S'està ometent %s amb el sufix de còpia de seguretat «%s».\n"
 
 #. TRANSLATORS: please keep "[y|N]" as is.
+#: git-send-email.perl
 #, perl-format
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Esteu segur que voleu enviar %s? [y|N]: "
+
+#~ msgid "revision walk setup failed\n"
+#~ msgstr "la configuració del recorregut de revisions ha fallat\n"
+
+#, c-format
+#~ msgid "unable to parse contact: %s"
+#~ msgstr "no s'ha pogut analitzar el contacte: %s"
+
+#, c-format
+#~ msgid "truncating .rej filename to %.*s.rej"
+#~ msgstr "s'està truncant el nom del fitxer .rej a %.*s.rej"
+
+#~ msgid ""
+#~ "the add.interactive.useBuiltin setting has been removed!\n"
+#~ "See its entry in 'git help config' for details."
+#~ msgstr ""
+#~ "s'ha eliminat la configuració add.interactive.useBuiltin\n"
+#~ "Per a més detalls, vegeu la seva entrada a «git help config»."
+
+#~ msgid ""
+#~ "Use -f if you really want to add them.\n"
+#~ "Turn this message off by running\n"
+#~ "\"git config advice.addIgnoredFile false\""
+#~ msgstr ""
+#~ "Utilitzeu -f si realment voleu afegir-los.\n"
+#~ "Desactiveu aquest missatge executant\n"
+#~ "«git config advice.addIgnoredFile false»"
+
+#~ msgid ""
+#~ "Maybe you wanted to say 'git add .'?\n"
+#~ "Turn this message off by running\n"
+#~ "\"git config advice.addEmptyPathspec false\""
+#~ msgstr ""
+#~ "Potser voleu dir «git add .»?\n"
+#~ "Desactiveu aquest missatge executant\n"
+#~ "«git config advice.addEmptyPathspec false»"
+
+#~ msgid "git archive: Remote with no URL"
+#~ msgstr "git archive: Remot sense URL"
+
+#~ msgid ""
+#~ "clean.requireForce defaults to true and neither -i, -n, nor -f given; "
+#~ "refusing to clean"
+#~ msgstr ""
+#~ "clean.requireForce és per defecte cert i ni -i, -n ni -f s'han indicat; "
+#~ "refusant netejar"
+
+#~ msgid "only one action at a time"
+#~ msgstr "només una acció cada cop"
+
+#~ msgid "use [RFC PATCH] instead of [PATCH]"
+#~ msgstr "useu [RFC PATCH] en comptes de [PATCH]"
+
+#, c-format
+#~ msgid "bad ls-files format: element '%s' does not start with '('"
+#~ msgstr "format incorrecte del ls-files: l'element «%s» no comença amb «(»"
+
+#, c-format
+#~ msgid "bad ls-files format: element '%s' does not end in ')'"
+#~ msgstr "format incorrecte del ls-files: l'element «%s» no acaba amb «)»"
+
+#, c-format
+#~ msgid "bad ls-files format: %%%.*s"
+#~ msgstr "format incorrecte de ls-files: %%%.*s"
+
+#, c-format
+#~ msgid "no URLs configured for remote '%s'"
+#~ msgstr "cap URL configurat per al remot «%s»"
+
+#~ msgid "keep redundant, empty commits"
+#~ msgstr "retén les comissions redundants i buides"
+
+#~ msgid "core.commentChar should only be one ASCII character"
+#~ msgstr "core.commentChar només hauria de ser un caràcter ASCII"
+
+#, c-format
+#~ msgid "remote '%s' has no configured URL"
+#~ msgstr "el remot «%s» no té cap URL configurat"
diff --git a/po/de.po b/po/de.po
index e271476..06055e7 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-07-19 19:21+0200\n"
-"PO-Revision-Date: 2024-07-19 19:25+0200\n"
+"POT-Creation-Date: 2024-10-05 16:17+0200\n"
+"PO-Revision-Date: 2024-10-05 16:18+0200\n"
 "Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
 "Language-Team: German\n"
 "Language: de\n"
@@ -566,7 +566,7 @@
 "/ - search for a hunk matching the given regex\n"
 "s - split the current hunk into smaller hunks\n"
 "e - manually edit the current hunk\n"
-"p - print the current hunk\n"
+"p - print the current hunk, 'P' to use the pager\n"
 "? - print help\n"
 msgstr ""
 "j - diesen Patch-Block unbestimmt lassen, nächsten unbestimmten Patch-Block "
@@ -579,7 +579,7 @@
 "/ - nach Patch-Block suchen, der regulärem Ausdruck entspricht\n"
 "s - aktuellen Patch-Block in kleinere Patch-Blöcke aufteilen\n"
 "e - aktuellen Patch-Block manuell editieren\n"
-"p - aktuellen Patch-Block anzeigen\n"
+"p - aktuellen Patch-Block anzeigen, 'P' um Anzeigeprogramm zu benutzen\n"
 "? - Hilfe anzeigen\n"
 
 #, c-format
@@ -1280,6 +1280,15 @@
 msgstr ""
 "versuche 3-Wege-Merge, weiche auf normalen Patch aus, wenn dies fehlschlägt"
 
+msgid "for conflicts, use our version"
+msgstr "bei Konflikten unsere Variante verwenden"
+
+msgid "for conflicts, use their version"
+msgstr "bei Konflikten ihre Variante verwenden"
+
+msgid "for conflicts, use a union version"
+msgstr "bei Konflikten eine gemeinsame Variante verwenden"
+
 msgid "build a temporary index based on embedded index information"
 msgstr ""
 "einen temporären Index, basierend auf den integrierten Index-Informationen, "
@@ -1329,6 +1338,9 @@
 msgid "don't return error for empty patches"
 msgstr "keinen Fehler für leere Patches zurückgeben"
 
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs, und --union erfordern --3way"
+
 #, c-format
 msgid "cannot stream blob %s"
 msgstr "kann Blob %s nicht streamen"
@@ -1402,6 +1414,10 @@
 msgstr "Kein Tree-Objekt: %s"
 
 #, c-format
+msgid "failed to unpack tree object %s"
+msgstr "Tree-Objekt %s konnte nicht entpackt werden"
+
+#, c-format
 msgid "File not found: %s"
 msgstr "Datei nicht gefunden: %s"
 
@@ -2525,9 +2541,6 @@
 "Ungültiges Argument %s für 'git bisect terms'.\n"
 "Unterstützte Optionen sind: --term-good|--term-old und --term-bad|--term-new."
 
-msgid "revision walk setup failed\n"
-msgstr "Einrichtung des Revisionsgangs fehlgeschlagen\n"
-
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "konnte '%s' nicht zum Anhängen öffnen"
@@ -3533,9 +3546,14 @@
 msgid "also read contacts from stdin"
 msgstr "ebenfalls Kontakte von der Standard-Eingabe lesen"
 
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "konnte Kontakt nicht parsen: %s"
+msgid "read additional mailmap entries from file"
+msgstr "zusätzliche mailmap-Einträge aus Datei lesen"
+
+msgid "blob"
+msgstr "Blob"
+
+msgid "read additional mailmap entries from blob"
+msgstr "zusätzliche mailmap-Einträge aus Blob lesen"
 
 msgid "no contacts specified"
 msgstr "keine Kontakte angegeben"
@@ -3898,6 +3916,10 @@
 msgstr "'%s' kann nicht beim Wechseln von Branches verwendet werden"
 
 #, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "'%s' benötigt die Pfade zum Auschecken"
+
+#, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr "'%s' kann nicht mit '%s' verwendet werden"
 
@@ -4693,7 +4715,7 @@
 msgid ""
 "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 <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
@@ -4703,7 +4725,7 @@
 msgstr ""
 "git commit [-a | --interactive | --patch] [-s] [-v] [-u<Modus>] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <Commit> | --fixup [(amend|"
-"reword):]<Commit>)]\n"
+"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"
@@ -5207,11 +5229,10 @@
 
 msgid ""
 "git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
-"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
-"<name>"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
 msgstr ""
 "git config get [<Datei-Option>] [<Anzeige-Option>] [--includes] [--all] [--"
-"regexp=<Regex>] [--value=<Wert>] [--fixed-value] [--default=<Standardwert>] "
+"regexp] [--value=<Wert>] [--fixed-value] [--default=<Standardwert>] "
 "<Name>"
 
 msgid ""
@@ -5243,6 +5264,15 @@
 "Terminal>]"
 
 msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<Datei-Option>] [<Anzeige-Option>] [--includes] [--all] [--"
+"regexp=<Regex>] [--value=<Wert>] [--fixed-value] [--default=<Standardwert>] "
+"<Name>"
+
+msgid ""
 "git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
 "[--value=<value>] [--fixed-value] <name> <value>"
 msgstr ""
@@ -6061,8 +6091,8 @@
 "zu umgehen.\n"
 
 #, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s hat nicht alle erforderlichen Objekte gesendet\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s hat nicht alle erforderlichen Objekte gesendet"
 
 #, c-format
 msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -6101,8 +6131,8 @@
 msgstr "Option \"%s\" Wert \"%s\" ist nicht gültig für %s"
 
 #, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "Option \"%s\" wird ignoriert für %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "Option \"%s\" wird für %s ignoriert"
 
 #, c-format
 msgid "%s is not a valid object"
@@ -6792,6 +6822,9 @@
 msgid "enable auto-gc mode"
 msgstr "\"auto-gc\" Modus aktivieren"
 
+msgid "perform garbage collection in the background"
+msgstr "Garbage Collection im Hintergrund ausführen"
+
 msgid "force running gc even if there may be another gc running"
 msgstr ""
 "Ausführung von \"git gc\" erzwingen, selbst wenn ein anderes\n"
@@ -6895,6 +6928,9 @@
 msgid "run tasks based on the state of the repository"
 msgstr "Aufgaben abhängig vom Zustand des Repositories ausführen"
 
+msgid "perform maintenance in the background"
+msgstr "Wartung im Hintergrund ausführen"
+
 msgid "frequency"
 msgstr "Häufigkeit"
 
@@ -7771,9 +7807,6 @@
 msgid "Final output: %d %s\n"
 msgstr "letzte Ausgabe: %d %s\n"
 
-msgid "unable to create temporary object directory"
-msgstr "konnte temporäres Objektverzeichnis nicht erstellen"
-
 #, c-format
 msgid "git show %s: bad file"
 msgstr "git show %s: ungültige Datei"
@@ -8353,15 +8386,6 @@
 msgid "use a zealous diff3 based merge"
 msgstr "einen eifrigen diff3 basierten Merge verwenden"
 
-msgid "for conflicts, use our version"
-msgstr "bei Konflikten unsere Variante verwenden"
-
-msgid "for conflicts, use their version"
-msgstr "bei Konflikten ihre Variante verwenden"
-
-msgid "for conflicts, use a union version"
-msgstr "bei Konflikten eine gemeinsame Variante verwenden"
-
 msgid "<algorithm>"
 msgstr "<Algorithmus>"
 
@@ -8841,6 +8865,9 @@
 msgid "write multi-pack bitmap"
 msgstr "schreibe Multi-Pack-Bitmap"
 
+msgid "write a new incremental MIDX"
+msgstr "ein neues inkrementelles MIDX schreiben"
+
 msgid "write multi-pack index containing only given indexes"
 msgstr "Multi-Pack-Index schreiben, der nur die gegebenen Indexe enthält"
 
@@ -10930,6 +10957,9 @@
 msgid "git refs migrate --ref-format=<format> [--dry-run]"
 msgstr "git refs migrate --ref-format=<Format> [--dry-run]"
 
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
 msgid "specify the reference format to convert to"
 msgstr "das Referenzformat angeben, in das konvertiert werden soll"
 
@@ -10943,6 +10973,12 @@
 msgid "repository already uses '%s' format"
 msgstr "das Repository verwendet bereits das Format '%s'"
 
+msgid "enable strict checking"
+msgstr "strenge Kontrolle aktivieren"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' nimmt keine Argumente an"
+
 msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
 "mirror=<fetch|push>] <name> <url>"
@@ -12397,11 +12433,11 @@
 msgid "failed to look up reference"
 msgstr "Fehler beim Nachschlagen der Referenz"
 
-msgid "only show tags (can be combined with branches)"
-msgstr "nur Tags anzeigen (kann mit Branches kombiniert werden)"
+msgid "only show tags (can be combined with --branches)"
+msgstr "nur Tags anzeigen (kann mit --branches kombiniert werden)"
 
-msgid "only show branches (can be combined with tags)"
-msgstr "nur Branches anzeigen (kann mit Tags kombiniert werden)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "nur Branches anzeigen (kann mit --tags kombiniert werden)"
 
 msgid "check for reference existence without resolving"
 msgstr "Prüfung auf Vorhandensein einer Referenz, ohne diese aufzulösen"
@@ -12460,6 +12496,10 @@
 "Fehler beim Erstellen eines Verzeichnisses für Datei eines partiellen "
 "Checkouts"
 
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "kann %s nicht öffnen"
+
 msgid "failed to initialize worktree config"
 msgstr "Fehler beim Initialisieren der Arbeitsverzeichnis-Konfiguration"
 
@@ -12927,8 +12967,8 @@
 msgstr "Hash eines Objektes von '%s' konnte nicht erzeugt werden"
 
 #, c-format
-msgid "unexpected mode %o\n"
-msgstr "unerwarteter Modus %o\n"
+msgid "unexpected mode %o"
+msgstr "unerwarteter Modus %o"
 
 msgid "use the commit stored in the index instead of the submodule HEAD"
 msgstr ""
@@ -17635,13 +17675,16 @@
 msgid "Unable to create '%s.lock': %s"
 msgstr "Konnte '%s.lock' nicht erstellen: %s"
 
+msgid "unable to create temporary object directory"
+msgstr "konnte temporäres Objektverzeichnis nicht erstellen"
+
 #, c-format
 msgid "could not write loose object index %s"
 msgstr "konnte den losen Objektindex %s nicht schreiben"
 
 #, c-format
-msgid "failed to write loose object index %s\n"
-msgstr "Fehler beim Schreiben des losen Objektindexes %s\n"
+msgid "failed to write loose object index %s"
+msgstr "Fehler beim Schreiben des losen Objektindex %s"
 
 #, c-format
 msgid "unexpected line: '%s'"
@@ -18213,6 +18256,17 @@
 msgid "could not open index for %s"
 msgstr "konnte Index für %s nicht öffnen"
 
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "kann '%s' nicht mit '%s' verknüpfen"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "Fehler beim Löschen des Multi-Pack-Index bei %s"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "kann kein inkrementelles MIDX mit Bitmap schreiben"
+
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr ""
 "ignoriere existierenden Multi-Pack-Index; Prüfsumme stimmt nicht überein"
@@ -18242,18 +18296,34 @@
 msgid "refusing to write multi-pack .bitmap without any objects"
 msgstr "Schreiben der Multi-Pack-Bitmap ohne Objekte abgelehnt"
 
+msgid "unable to create temporary MIDX layer"
+msgstr "konnte keine temporäre MIDX-Ebene erstellen"
+
 msgid "could not write multi-pack bitmap"
 msgstr "Multi-Pack-Bitmap konnte nicht geschrieben werden"
 
+msgid "unable to open multi-pack-index chain file"
+msgstr "Multi-Pack-Indexketten-Datei kann nicht geöffnet werden"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "neue Multi-Pack-Index-Ebene konnte nicht umbenannt werden"
+
 msgid "could not write multi-pack-index"
 msgstr "Multi-Pack-Index konnte nicht geschrieben werden"
 
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr ""
+"kann Pakete aus einem inkrementellen Multi-Pack-Index nicht ablaufen lassen"
+
 msgid "Counting referenced objects"
 msgstr "Referenzierte Objekte zählen"
 
 msgid "Finding and deleting unreferenced packfiles"
 msgstr "Suchen und Löschen von unreferenzierten Pack-Dateien"
 
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "kann einen inkrementellen Multi-Pack-Index nicht neu packen"
+
 msgid "could not start pack-objects"
 msgstr "Konnte 'pack-objects' nicht ausführen"
 
@@ -18316,6 +18386,27 @@
 msgid "multi-pack-index pack names out of order: '%s' before '%s'"
 msgstr "Falsche Reihenfolge bei Multi-Pack-Index Pack-Namen: '%s' vor '%s'"
 
+msgid "multi-pack-index chain file too small"
+msgstr "Multi-Pack-Index-Kettendatei zu klein"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "Paketanzahl im Basis-MIDX zu hoch: %<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "Objektanzahl in Basis-MIDX zu hoch: %<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "ungültige Multi-Pack-Index-Kette: Zeile '%s' ist kein Hash"
+
+msgid "unable to find all multi-pack index files"
+msgstr "konnte nicht alle Multi-Pack-Indexdateien finden"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "ungültige MIDX-Objektposition, MIDX ist wahrscheinlich beschädigt"
+
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
 msgstr "Ungültige pack-int-id: %u (%u Pakete insgesamt)"
@@ -18334,10 +18425,6 @@
 msgid "multi-pack-index large offset out of bounds"
 msgstr "multi-pack-index großer Offset außerhalb der Grenzen"
 
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "Fehler beim Löschen des Multi-Pack-Index bei %s"
-
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr "Multi-Pack-Index-Datei existiert, aber das Parsen schlug fehl"
 
@@ -18556,6 +18643,14 @@
 msgstr "fehlende Abbildung von %s auf %s"
 
 #, c-format
+msgid "unable to open %s"
+msgstr "kann %s nicht öffnen"
+
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "die Dateien '%s' und '%s' unterscheiden sich im Inhalt"
+
+#, c-format
 msgid "unable to write file %s"
 msgstr "Konnte Datei %s nicht schreiben."
 
@@ -18642,10 +18737,6 @@
 msgstr "%s ist kein gültiges '%s' Objekt"
 
 #, c-format
-msgid "unable to open %s"
-msgstr "kann %s nicht öffnen"
-
-#, c-format
 msgid "hash mismatch for %s (expected %s)"
 msgstr "Hash für %s stimmt nicht überein (%s erwartet)."
 
@@ -19882,6 +19973,10 @@
 msgstr "erwartetes Format: %%(ahead-behind:<Commit>)"
 
 #, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "erwartetes Format: %%(is-base:<committish>)"
+
+#, c-format
 msgid "malformed field name: %.*s"
 msgstr "Fehlerhafter Feldname: %.*s"
 
@@ -20121,6 +20216,13 @@
 "'%s': ist aber eine reguläre Referenz"
 
 #, c-format
+msgid "cannot open directory %s"
+msgstr "Verzeichnis %s kann nicht geöffnet werden"
+
+msgid "Checking references consistency"
+msgstr "Überprüfung der Konsistenz der Referenzen"
+
+#, c-format
 msgid "refname is dangerous: %s"
 msgstr "Referenzname ist gefährlich: %s"
 
@@ -20766,12 +20868,15 @@
 msgid "create repository within 'src' directory"
 msgstr "Repository im Verzeichnis 'src' erstellen"
 
+msgid "specify if tags should be fetched during clone"
+msgstr "Angabe, ob Tags während des Klonens abgerufen werden sollen"
+
 msgid ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 msgstr ""
 "scalar clone [--single-branch] [--branch <Haupt-Branch>] [--full-clone]\n"
-"\t[--[no-]src] <URL> [<Eintragung>]"
+"\t[--[no-]src] [--[no-]tags] <URL> [<Eintragung>]"
 
 #, c-format
 msgid "cannot deduce worktree name from '%s'"
@@ -20790,6 +20895,10 @@
 msgstr "konnte Remote-Repository in '%s' nicht konfigurieren"
 
 #, c-format
+msgid "could not disable tags in '%s'"
+msgstr "konnte die Tags in '%s' nicht deaktivieren"
+
+#, c-format
 msgid "could not configure '%s'"
 msgstr "konnte '%s' nicht konfigurieren"
 
@@ -21872,6 +21981,10 @@
 msgstr "Konnte '%*s%s%s' nicht lesen."
 
 #, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' nicht absolut"
+
+#, c-format
 msgid ""
 "detected dubious ownership in repository at '%s'\n"
 "%sTo add an exception for this directory, call:\n"
@@ -22339,6 +22452,24 @@
 msgid "command token to send to the server"
 msgstr "Befehlstoken, der an den Server gesendet werden soll"
 
+msgid "unit-test [<options>]"
+msgstr "unit-test [<Optionen>]"
+
+msgid "immediately exit upon the first failed test"
+msgstr "beim ersten fehlgeschlagenen Test sofort abbrechen"
+
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "nur Testsuite oder einzelnen Test ausführen <suite[::test]>"
+
+msgid "suite"
+msgstr "Suite"
+
+msgid "exclude test suite <suite>"
+msgstr "Testsuite <Suite> ausschließen"
+
 #, c-format
 msgid "running trailer command '%s' failed"
 msgstr "Ausführen des Anhang-Befehls '%s' fehlgeschlagen"
@@ -23588,6 +23719,10 @@
 msgid "--dump-aliases incompatible with other options\n"
 msgstr "--dump-aliases ist mit anderen Optionen inkompatibel\n"
 
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr ""
+"--dump-aliases und --translate-aliases schließen sich gegenseitig aus\n"
+
 msgid ""
 "fatal: found configuration options for 'sendmail'\n"
 "git-send-email is configured with the sendemail.* options - note the 'e'.\n"
diff --git a/po/fr.po b/po/fr.po
index 7b03f2c..481e1bd 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -80,8 +80,8 @@
 msgstr ""
 "Project-Id-Version: git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-07-17 21:57+0000\n"
-"PO-Revision-Date: 2024-07-19 20:25+0200\n"
+"POT-Creation-Date: 2024-10-02 16:57+0000\n"
+"PO-Revision-Date: 2024-10-04 23:03+0200\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"
@@ -628,7 +628,7 @@
 "/ - search for a hunk matching the given regex\n"
 "s - split the current hunk into smaller hunks\n"
 "e - manually edit the current hunk\n"
-"p - print the current hunk\n"
+"p - print the current hunk, 'P' to use the pager\n"
 "? - print help\n"
 msgstr ""
 "j - laisser cette section non décidée et aller à la suivante non-décidée\n"
@@ -639,7 +639,7 @@
 "/ - rechercher une section correspondant à une regex donnée\n"
 "s - découper la section en sections plus petites\n"
 "e - éditer manuellement la section actuelle\n"
-"p - afficher la section actuelle\n"
+"p - afficher la section actuelle, 'P' pour utiliser un paginateur\n"
 "? - afficher l'aide\n"
 
 #, c-format
@@ -1330,6 +1330,15 @@
 msgstr ""
 "tenter une fusion à 3 points, revenir à un rustinage normal en cas d'échec"
 
+msgid "for conflicts, use our version"
+msgstr "pour les conflits, utiliser notre version (our)"
+
+msgid "for conflicts, use their version"
+msgstr "pour les conflits, utiliser leur version (their)"
+
+msgid "for conflicts, use a union version"
+msgstr "pour les conflits, utiliser l'union des versions"
+
 msgid "build a temporary index based on embedded index information"
 msgstr ""
 "construire un index temporaire fondé sur l'information de l'index embarqué"
@@ -1380,6 +1389,9 @@
 msgid "don't return error for empty patches"
 msgstr "ne pas renvoyer d'erreur pour les rustines vides"
 
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs et --union requièrent --3way"
+
 #, c-format
 msgid "cannot stream blob %s"
 msgstr "impossible de transmettre le blob %s en flux"
@@ -1453,6 +1465,9 @@
 msgid "not a tree object: %s"
 msgstr "objet arbre invalide : %s"
 
+msgid "unable to checkout working tree"
+msgstr "impossible d'extraire la copie de travail"
+
 #, c-format
 msgid "File not found: %s"
 msgstr "Fichier non trouvé : %s"
@@ -2566,9 +2581,6 @@
 "Les options supportées sont : --term-good|--term-old et --term-bad|--term-"
 "new."
 
-msgid "revision walk setup failed\n"
-msgstr "échec de la préparation du parcours des révisions\n"
-
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "impossible d'ouvrir '%s' en ajout"
@@ -3364,7 +3376,7 @@
 
 #, c-format
 msgid "%s takes no arguments"
-msgstr "%s n'accepte aucune argument"
+msgstr "%s n'accepte aucun argument"
 
 msgid "only one batch option may be specified"
 msgstr "une seule option de traitement ne peut être spécifiée à la fois"
@@ -3569,9 +3581,14 @@
 msgid "also read contacts from stdin"
 msgstr "lire aussi les contacts depuis l'entrée standard"
 
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "impossible d'analyser le contact : %s"
+msgid "read additional mailmap entries from file"
+msgstr "lire des entrées supplémentaires de mailmap depuis un fichier"
+
+msgid "blob"
+msgstr "blob"
+
+msgid "read additional mailmap entries from blob"
+msgstr "lire des entrées supplémentaires depuis un blob"
 
 msgid "no contacts specified"
 msgstr "aucun contact spécifié"
@@ -3929,6 +3946,10 @@
 msgstr "'%s' ne peut pas être utilisé avec un basculement de branches"
 
 #, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "'%s' requiert les chemins à extraire"
+
+#, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr "'%s' ne peut pas être utilisé avec '%s'"
 
@@ -4415,9 +4436,6 @@
 "la HEAD distante réfère à une référence non existante, impossible de "
 "l'extraire"
 
-msgid "unable to checkout working tree"
-msgstr "impossible d'extraire la copie de travail"
-
 msgid "unable to write parameters to config file"
 msgstr "impossible d'écrire les paramètres dans le fichier de configuration"
 
@@ -4707,7 +4725,7 @@
 msgid ""
 "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 <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
@@ -4718,7 +4736,7 @@
 "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"
+"           [-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"
@@ -5222,12 +5240,11 @@
 
 msgid ""
 "git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
-"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
-"<name>"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
 msgstr ""
 "git config get [<option-de-fichier>] [<option-d-affichage>] [--includes] [--"
-"all] [--regexp=<regexp>] [--value=<valeur>] [--fixed-value] [--"
-"default=<défaut>] <name>"
+"all] [--regexp] [--value=<valeur>] [--fixed-value] [--default=<défaut>] "
+"<name>"
 
 msgid ""
 "git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
@@ -5258,6 +5275,15 @@
 "git config [<option-de-fichier>] --get-colorbool <nom> [<stdout-est-tty>]"
 
 msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<option-de-fichier>] [<option-d-affichage>] [--includes] [--"
+"all] [--regexp=<regexp>] [--value=<valeur>] [--fixed-value] [--"
+"default=<défaut>] <name>"
+
+msgid ""
 "git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
 "[--value=<value>] [--fixed-value] <name> <value>"
 msgstr ""
@@ -6077,8 +6103,8 @@
 "'git config fetch.showForcedUpdates false' pour éviter cette vérification\n"
 
 #, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s n'a pas envoyé tous les objets nécessaires\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s n'a pas envoyé tous les objets nécessaires"
 
 #, c-format
 msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -6117,8 +6143,8 @@
 msgstr "la valeur \"%2$s\" de l'option \"%1$s\" est invalide pour %3$s"
 
 #, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "l'option \"%s\" est ignorée pour %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "l'option \"%s\" est ignorée pour %s"
 
 #, c-format
 msgid "%s is not a valid object"
@@ -6797,6 +6823,9 @@
 msgid "enable auto-gc mode"
 msgstr "activer le mode auto-gc"
 
+msgid "perform garbage collection in the background"
+msgstr "réaliser le glanage de cellules en arrière plan"
+
 msgid "force running gc even if there may be another gc running"
 msgstr ""
 "forcer le lancement du ramasse-miettes même si un autre ramasse-miettes "
@@ -6897,6 +6926,9 @@
 msgid "run tasks based on the state of the repository"
 msgstr "lancer les tâches selon l'état du dépôt"
 
+msgid "perform maintenance in the background"
+msgstr "réaliser la maintenance en arrière-plan"
+
 msgid "frequency"
 msgstr "fréquence"
 
@@ -7776,9 +7808,6 @@
 msgid "Final output: %d %s\n"
 msgstr "Sortie finale : %d %s\n"
 
-msgid "unable to create temporary object directory"
-msgstr "impossible de créer un répertoire d'objets temporaire"
-
 #, c-format
 msgid "git show %s: bad file"
 msgstr "git show %s : fichier incorrect"
@@ -8365,15 +8394,6 @@
 msgid "use a zealous diff3 based merge"
 msgstr "utiliser une fusion basée sur un diff3 zélée"
 
-msgid "for conflicts, use our version"
-msgstr "pour les conflits, utiliser notre version (our)"
-
-msgid "for conflicts, use their version"
-msgstr "pour les conflits, utiliser leur version (their)"
-
-msgid "for conflicts, use a union version"
-msgstr "pour les conflits, utiliser l'ensemble des versions"
-
 msgid "<algorithm>"
 msgstr "<algorithme>"
 
@@ -8848,6 +8868,9 @@
 msgid "write multi-pack bitmap"
 msgstr "écriture du bitmap de multi-paquet"
 
+msgid "write a new incremental MIDX"
+msgstr "écrire un nouveau MIDX incrémental"
+
 msgid "write multi-pack index containing only given indexes"
 msgstr "écrire l'index multi-paquet ne contenant que les index fournis"
 
@@ -10903,6 +10926,9 @@
 msgid "git refs migrate --ref-format=<format> [--dry-run]"
 msgstr "git refs migrate --ref-format=<format> [--dry-run]"
 
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
 msgid "specify the reference format to convert to"
 msgstr "spécifier le format de réference vers lequel convertir"
 
@@ -10916,6 +10942,12 @@
 msgid "repository already uses '%s' format"
 msgstr "le dépôt utilise déjà le format '%s'"
 
+msgid "enable strict checking"
+msgstr "activer une vérification plus strict"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' n'accepte aucun argument"
+
 msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
 "mirror=<fetch|push>] <name> <url>"
@@ -12370,13 +12402,11 @@
 msgid "failed to look up reference"
 msgstr "échec de la recherche de la référence"
 
-msgid "only show tags (can be combined with branches)"
-msgstr ""
-"afficher seulement les étiquettes (peut être combiné avec les branches)"
+msgid "only show tags (can be combined with --branches)"
+msgstr "afficher seulement les étiquettes (peut être combiné avec --branches)"
 
-msgid "only show branches (can be combined with tags)"
-msgstr ""
-"afficher seulement les branches (peut être combiné avec les étiquettes)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "afficher seulement les branches (peut être combiné avec --tags)"
 
 msgid "check for reference existence without resolving"
 msgstr "vérifier l'existence de la référence sans la résoudre"
@@ -12435,6 +12465,10 @@
 msgstr ""
 "échec de la création du répertoire pour le fichier d'extraction clairsemée"
 
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "impossible d'ouvrir %s avec fdopen"
+
 msgid "failed to initialize worktree config"
 msgstr "échec lors de l'initialisation de la configuration d'arbre de travail"
 
@@ -12904,8 +12938,8 @@
 msgstr "impossible de calculer l'empreinte de l'objet depuis '%s'"
 
 #, c-format
-msgid "unexpected mode %o\n"
-msgstr "mode %o inattendu\n"
+msgid "unexpected mode %o"
+msgstr "mode %o inattendu"
 
 msgid "use the commit stored in the index instead of the submodule HEAD"
 msgstr ""
@@ -17628,13 +17662,16 @@
 msgid "Unable to create '%s.lock': %s"
 msgstr "Impossible de créer '%s.lock' : %s"
 
+msgid "unable to create temporary object directory"
+msgstr "impossible de créer un répertoire d'objets temporaire"
+
 #, c-format
 msgid "could not write loose object index %s"
 msgstr "impossible d'écrire l'objet esseulé %s"
 
 #, c-format
-msgid "failed to write loose object index %s\n"
-msgstr "Échec de l'écriture de l'index d'objet esseulé %s\n"
+msgid "failed to write loose object index %s"
+msgstr "Échec de l'écriture de l'index d'objet esseulé %s"
 
 #, c-format
 msgid "unexpected line: '%s'"
@@ -18190,6 +18227,17 @@
 msgid "could not open index for %s"
 msgstr "impossible d'ouvrir l'index pour %s"
 
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "impossible de lier '%s' à '%s'"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "échec du nettoyage de l'index de multi-paquet à %s"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "impossible d'écrire un MIDX incrémental avec des bitmap"
+
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr ""
 "index multi-paquet existant ignoré ; non-concordance de la somme de contrôle"
@@ -18219,18 +18267,34 @@
 msgid "refusing to write multi-pack .bitmap without any objects"
 msgstr "refus d'écrire le .bitmap multi-paquet sans aucun objet"
 
+msgid "unable to create temporary MIDX layer"
+msgstr "impossible de créer une couche MIDX temporaire"
+
 msgid "could not write multi-pack bitmap"
 msgstr "impossible d'écrire le bitmap multi-paquet"
 
+msgid "unable to open multi-pack-index chain file"
+msgstr "impossible d'ouvrir le fichier d'index multi-paquet"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "impossible d'écrire la nouvelle couche de l'index multi-paquet"
+
 msgid "could not write multi-pack-index"
 msgstr "échec de l'écriture de l'index de multi-paquet"
 
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr ""
+"impossible d'expirer les paquets dpuis un index multi-paquet incrémental"
+
 msgid "Counting referenced objects"
 msgstr "Comptage des objets référencés"
 
 msgid "Finding and deleting unreferenced packfiles"
 msgstr "Recherche et effacement des fichiers paquets non-référencés"
 
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "impossible de ré-empaqueter un index multi-paquet"
+
 msgid "could not start pack-objects"
 msgstr "impossible de démarrer le groupement d'objets"
 
@@ -18303,6 +18367,28 @@
 msgstr ""
 "index multi-paquet les noms de paquets sont en désordre : '%s' avant '%s'"
 
+msgid "multi-pack-index chain file too small"
+msgstr "le fichier de chaîne d'index multi-paquet est trop petit"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "nombre de paquets dans la base MIDX trop haut : %<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "nombre d'objets dans la base MIDX trop haut : %<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr ""
+"chaîne d'index multi-paquet invalide : la ligne '%s' n'est pas une empreinte"
+
+msgid "unable to find all multi-pack index files"
+msgstr "impossible de trouver tous les fichiers d'index multi-paquet"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "position d'objet MIDX invalide. MIDX est vraisemblablement corrompu"
+
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
 msgstr "mauvais pack-int-id : %u (%u paquets au total)"
@@ -18321,10 +18407,6 @@
 msgid "multi-pack-index large offset out of bounds"
 msgstr "le grand décalage de l'index-multi-paquet est hors limite"
 
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "échec du nettoyage de l'index de multi-paquet à %s"
-
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr "le fichier d'index multi-paquet existe mais n'a pu être analysé"
 
@@ -18534,6 +18616,14 @@
 msgstr "correspondance manquante entre %s et %s"
 
 #, c-format
+msgid "unable to open %s"
+msgstr "impossible d'ouvrir %s"
+
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "les fichiers '%s' et '%s' diffèrent par leur contenu"
+
+#, c-format
 msgid "unable to write file %s"
 msgstr "impossible d'écrire le fichier %s"
 
@@ -18619,10 +18709,6 @@
 msgstr "%s n'est pas un objet '%s' valide"
 
 #, c-format
-msgid "unable to open %s"
-msgstr "impossible d'ouvrir %s"
-
-#, c-format
 msgid "hash mismatch for %s (expected %s)"
 msgstr "incohérence de hachage pour %s (%s attendu)"
 
@@ -19866,6 +19952,10 @@
 msgstr "format attendu : %%(ahead-behind:<commit-esque>)"
 
 #, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "format attendu : %%(is-base:<commit-esque>)"
+
+#, c-format
 msgid "malformed field name: %.*s"
 msgstr "nom de champ malformé %.*s"
 
@@ -20100,6 +20190,13 @@
 "normale trouvée"
 
 #, c-format
+msgid "cannot open directory %s"
+msgstr "impossible d'ouvrir le répertoire %s"
+
+msgid "Checking references consistency"
+msgstr "Vérification de la cohérence des références"
+
+#, c-format
 msgid "refname is dangerous: %s"
 msgstr "le nom de réference est dangereux : %s"
 
@@ -20750,13 +20847,17 @@
 msgid "create repository within 'src' directory"
 msgstr "Créer un dépôt dans le repertoire 'src'"
 
+msgid "specify if tags should be fetched during clone"
+msgstr ""
+"spécifier si les étiquettes devraient être récupérées pendant le clonage"
+
 msgid ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 msgstr ""
 "scalar clone [--single-branch] [--branch <branche-principale>] [--full-"
 "clone]\n"
-"\t[--[no-]src] <url> [<enrôlement>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enrôlement>]"
 
 #, c-format
 msgid "cannot deduce worktree name from '%s'"
@@ -20775,6 +20876,10 @@
 msgstr "impossible de paramétrer le distant dans '%s'"
 
 #, c-format
+msgid "could not disable tags in '%s'"
+msgstr "impossible de désactiver les étiquettes dans '%s'"
+
+#, c-format
 msgid "could not configure '%s'"
 msgstr "impossible de configurer '%s'"
 
@@ -21846,6 +21951,10 @@
 msgstr "échec du stat de '%*s%s%s'"
 
 #, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' n'est pas absolu"
+
+#, c-format
 msgid ""
 "detected dubious ownership in repository at '%s'\n"
 "%sTo add an exception for this directory, call:\n"
@@ -22320,6 +22429,25 @@
 msgid "command token to send to the server"
 msgstr "jeton de commande à envoyer au serveur"
 
+msgid "unit-test [<options>]"
+msgstr "unit-test [<options>]"
+
+msgid "immediately exit upon the first failed test"
+msgstr "sortir immédiatement sur le premier échec"
+
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr ""
+"lancer seulement la suite de test ou le test individuel <suite[::test]>"
+
+msgid "suite"
+msgstr "suite"
+
+msgid "exclude test suite <suite>"
+msgstr "exclure la suite de tests <suite>"
+
 #, c-format
 msgid "running trailer command '%s' failed"
 msgstr "échec de la commande trailer '%s'"
@@ -23526,6 +23654,9 @@
 msgid "--dump-aliases incompatible with other options\n"
 msgstr "--dump-aliases est incompatible avec d'autres options\n"
 
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases et --translate-aliases sont mutuellement exclusifs.\n"
+
 msgid ""
 "fatal: found configuration options for 'sendmail'\n"
 "git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -23830,6 +23961,13 @@
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Souhaitez-vous réellement envoyer %s ?[y|N] : "
 
+#~ msgid "revision walk setup failed\n"
+#~ msgstr "échec de la préparation du parcours des révisions\n"
+
+#, c-format
+#~ msgid "unable to parse contact: %s"
+#~ msgstr "impossible d'analyser le contact : %s"
+
 #, c-format
 #~ msgid "truncating .rej filename to %.*s.rej"
 #~ msgstr "troncature du nom de fichier .rej en %.*s.rej"
@@ -23855,10 +23993,6 @@
 #~ msgstr "aucune URL configurée pour le dépôt distant '%s'"
 
 #, c-format
-#~ msgid "unable to copy '%s' to '%s'"
-#~ msgstr "impossible de copier '%s' vers '%s'"
-
-#, c-format
 #~ msgid "remote '%s' has no configured URL"
 #~ msgstr "le distant '%s' n'a pas d'URL configuré"
 
diff --git a/po/id.po b/po/id.po
index 7131a49..fc34140 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-07-19 14:03+0700\n"
-"PO-Revision-Date: 2024-07-19 14:25+0700\n"
+"POT-Creation-Date: 2024-10-04 08:33+0700\n"
+"PO-Revision-Date: 2024-10-04 08:52+0700\n"
 "Last-Translator: Bagas Sanjaya <bagasdotme@gmail.com>\n"
 "Language-Team: Indonesian\n"
 "Language: id\n"
@@ -651,18 +651,20 @@
 "/ - search for a hunk matching the given regex\n"
 "s - split the current hunk into smaller hunks\n"
 "e - manually edit the current hunk\n"
-"p - print the current hunk\n"
+"p - print the current hunk, 'P' to use the pager\n"
 "? - print help\n"
 msgstr ""
-"j - biarkan bingkah ini, lihat bingkah berikutnya yang belum diputuskan\n"
-"J - biarkan bingkah ini, lihat bingkah berikutnya\n"
-"k - biarkan bingkah ini, lihat bingkah sebelumnya yang belum diputuskan\n"
-"K - biarkan bingkah ini, lihat bingkah sebelumnya\n"
+"j - biarkan bingkah ini tak diputuskan, lihat bingkah berikutnya yang belum "
+"diputuskan\n"
+"J - biarkan bingkah ini tak diputuskan, lihat bingkah berikutnya\n"
+"k - biarkan bingkah ini tak diputuskan, lihat bingkah sebelumnya yang belum "
+"diputuskan\n"
+"K - biarkan bingkah ini tak diputuskan, lihat bingkah sebelumnya\n"
 "g - pilih satu bingkah untuk dikunjungi\n"
 "/ - cari satu bingkah yang cocok dengan regex yang diberikan\n"
 "s - belah bingkah saat ini ke dalam bingkah yang lebih kecil\n"
 "e - sunting bingkah saat ini secara manual\n"
-"p - lihat bingkah saat ini\n"
+"p - lihat bingkah saat ini, 'P' untuk menggunakan pager\n"
 "? - lihat bantuan\n"
 
 #: add-patch.c
@@ -1502,6 +1504,18 @@
 msgid "attempt three-way merge, fall back on normal patch if that fails"
 msgstr "coba penggabungan tiga arah, mundur ke penambalan normal jika gagal"
 
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use our version"
+msgstr "untuk konflik, gunakan versi kami"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use their version"
+msgstr "untuk konflik, gunakan versi mereka"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use a union version"
+msgstr "untuk konflik, gunakan versi bersatu"
+
 #: apply.c
 msgid "build a temporary index based on embedded index information"
 msgstr "bangun sebuah indeks sementara berdasarkan informasi indeks tertanam"
@@ -1563,6 +1577,10 @@
 msgid "don't return error for empty patches"
 msgstr "jangan kembalikan kesalahan untuk tambalan kosong"
 
+#: apply.c
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs, dan --union memerlukan --3way"
+
 #: archive-tar.c archive-zip.c
 #, c-format
 msgid "cannot stream blob %s"
@@ -1652,6 +1670,10 @@
 msgid "not a tree object: %s"
 msgstr "bukan objek pohon: %s"
 
+#: archive.c builtin/clone.c
+msgid "unable to checkout working tree"
+msgstr "tidak dapat men-checkout pohon kerja"
+
 #: archive.c
 #, c-format
 msgid "File not found: %s"
@@ -1768,7 +1790,7 @@
 msgid "Unexpected option --output"
 msgstr "Opsi --output tak diharapkan"
 
-#: archive.c
+#: archive.c t/unit-tests/unit-test.c
 #, c-format
 msgid "extra command line parameter '%s'"
 msgstr "parameter konfigurasi tambahan: '%s'"
@@ -1840,7 +1862,7 @@
 msgstr "tidak dapat men-stat '%s'"
 
 #: bisect.c builtin/cat-file.c builtin/index-pack.c builtin/notes.c
-#: builtin/pack-objects.c combine-diff.c rerere.c
+#: builtin/pack-objects.c combine-diff.c object-file.c rerere.c
 #, c-format
 msgid "unable to read %s"
 msgstr "tidak dapat membaca %s"
@@ -1978,7 +2000,7 @@
 msgstr ""
 "--reverse dan --first-parent bersama-sama butuh komit terbaru yang disebutkan"
 
-#: blame.c builtin/commit.c builtin/log.c builtin/merge.c
+#: blame.c builtin/bisect.c builtin/commit.c builtin/log.c builtin/merge.c
 #: builtin/pack-objects.c builtin/shortlog.c midx-write.c pack-bitmap.c
 #: remote.c sequencer.c submodule.c
 msgid "revision walk setup failed"
@@ -2239,7 +2261,7 @@
 
 #: builtin/add.c builtin/check-ignore.c builtin/commit.c
 #: builtin/count-objects.c builtin/fsck.c builtin/log.c builtin/mv.c
-#: builtin/read-tree.c
+#: builtin/read-tree.c builtin/refs.c
 msgid "be verbose"
 msgstr "jadi berkata-kata"
 
@@ -2738,7 +2760,7 @@
 #: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
 #: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c
 #: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c
-#: builtin/tag.c builtin/verify-tag.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/verify-tag.c
 msgid "format"
 msgstr "format"
 
@@ -3037,10 +3059,6 @@
 "Opsi yang didukung adalah: --term-good|--term-old dan --term-bad|--term-new."
 
 #: builtin/bisect.c
-msgid "revision walk setup failed\n"
-msgstr "setup jalan revisi gagal\n"
-
-#: builtin/bisect.c
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "tidak dapat membuka '%s' untuk menambahkan"
@@ -4282,9 +4300,16 @@
 msgstr "juga baca kontak dari masukan standar"
 
 #: builtin/check-mailmap.c
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "tidak dapat menguraikan kontak: %s"
+msgid "read additional mailmap entries from file"
+msgstr "baca entri mailmap tambahan dari berkas"
+
+#: builtin/check-mailmap.c
+msgid "blob"
+msgstr "blob"
+
+#: builtin/check-mailmap.c
+msgid "read additional mailmap entries from blob"
+msgstr "baca entri mailmap tambahan dari blob"
 
 #: builtin/check-mailmap.c
 msgid "no contacts specified"
@@ -4711,6 +4736,11 @@
 
 #: builtin/checkout.c
 #, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "'%s' butuh jalur untuk di-checkout"
+
+#: builtin/checkout.c
+#, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr "'%s' tidak dapat digunakan dengan '%s'"
 
@@ -5178,7 +5208,7 @@
 msgid "separate git dir from working tree"
 msgstr "pisahkan direktori git dari pohon kerja"
 
-#: builtin/clone.c builtin/init-db.c
+#: builtin/clone.c builtin/init-db.c builtin/submodule--helper.c
 msgid "specify the reference format to use"
 msgstr "sebutkan format referensi untuk digunakan"
 
@@ -5276,7 +5306,7 @@
 msgid "failed to copy file to '%s'"
 msgstr "gagal menyalin berkas ke '%s'"
 
-#: builtin/clone.c
+#: builtin/clone.c refs/files-backend.c
 #, c-format
 msgid "failed to iterate over '%s'"
 msgstr "gagal iterasi pada '%s'"
@@ -5319,10 +5349,6 @@
 msgstr "HEAD remote merujuk pada ref yang tidak ada, tidak dapat men-checkout"
 
 #: builtin/clone.c
-msgid "unable to checkout working tree"
-msgstr "tidak dapat men-checkout pohon kerja"
-
-#: builtin/clone.c
 msgid "unable to write parameters to config file"
 msgstr "tidak dapat menulis parameter ke berkas konfigurasi"
 
@@ -5342,7 +5368,8 @@
 msgid "You must specify a repository to clone."
 msgstr "Anda harus sebutkan repositori untuk diklon."
 
-#: builtin/clone.c builtin/init-db.c builtin/refs.c setup.c
+#: builtin/clone.c builtin/init-db.c builtin/refs.c builtin/submodule--helper.c
+#: setup.c
 #, c-format
 msgid "unknown ref storage format '%s'"
 msgstr "format penyimpanan referensi tidak dikenal '%s'"
@@ -5687,7 +5714,7 @@
 msgid ""
 "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 <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
@@ -5697,7 +5724,7 @@
 msgstr ""
 "git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <komit> | --fixup [(amend|"
-"reword):]<komit>)]\n"
+"reword):]<komit>]\n"
 "           [-F <berkas> | -m <pesan>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--"
 "author=<pengarang>]\n"
@@ -6304,12 +6331,10 @@
 #: builtin/config.c
 msgid ""
 "git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
-"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
-"<name>"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
 msgstr ""
-"git config get [<opsi berkas>] [<opsi tampilan] [--includes] [--all] [--"
-"regexp=<regexp> [--value=<nilai>] [--fixed-value] [--default=<default>] "
-"<nama>"
+"git config get [<opsi berkas>] [<opsi tampilan>] [--includes] [--all] [--"
+"regexp] [--value=<nilai>] [--fixed-value] [--default=<default>] <nama>"
 
 #: builtin/config.c
 msgid ""
@@ -6345,6 +6370,16 @@
 
 #: builtin/config.c
 msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<opsi berkas>] [<opsi tampilan] [--includes] [--all] [--"
+"regexp=<regexp> [--value=<nilai>] [--fixed-value] [--default=<default>] "
+"<nama>"
+
+#: builtin/config.c
+msgid ""
 "git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
 "[--value=<value>] [--fixed-value] <name> <value>"
 msgstr ""
@@ -7372,8 +7407,8 @@
 
 #: builtin/fetch.c
 #, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s tidak mengirim semua objek yang diperlukan\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s tidak mengirim semua objek yang diperlukan"
 
 #: builtin/fetch.c
 #, c-format
@@ -7419,8 +7454,8 @@
 
 #: builtin/fetch.c
 #, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "opsi \"%s\" diabaikan untuk %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "opsi \"%s\" diabaikan untuk %s"
 
 #: builtin/fetch.c object-file.c
 #, c-format
@@ -8277,6 +8312,10 @@
 msgstr "aktifkan mode gc otomatis"
 
 #: builtin/gc.c
+msgid "perform garbage collection in the background"
+msgstr "lakukan pengumpulan sampah di latar belakang"
+
+#: builtin/gc.c
 msgid "force running gc even if there may be another gc running"
 msgstr "paksa jalankan gc bahkan jika mungkin ada gc lain yang berjalan"
 
@@ -8397,6 +8436,10 @@
 msgstr "jalankan tugas berdasarkan keadaan repositori"
 
 #: builtin/gc.c
+msgid "perform maintenance in the background"
+msgstr "lakukan pemeliharaan di latar belakang"
+
+#: builtin/gc.c
 msgid "frequency"
 msgstr "frekuensi"
 
@@ -9503,10 +9546,6 @@
 msgstr "Keluaran terakhir: %d %s\n"
 
 #: builtin/log.c
-msgid "unable to create temporary object directory"
-msgstr "tidak dapat membuat direktori objek sementara"
-
-#: builtin/log.c
 #, c-format
 msgid "git show %s: bad file"
 msgstr "git show %s: berkas jelek"
@@ -10246,18 +10285,6 @@
 msgid "use a zealous diff3 based merge"
 msgstr "gunakan penggabungan berdasarkan diff3 yang bersemangat"
 
-#: builtin/merge-file.c
-msgid "for conflicts, use our version"
-msgstr "untuk konflik, gunakan versi kami"
-
-#: builtin/merge-file.c
-msgid "for conflicts, use their version"
-msgstr "untuk konflik, gunakan versi mereka"
-
-#: builtin/merge-file.c
-msgid "for conflicts, use a union version"
-msgstr "untuk konflik, gunakan versi bersatu"
-
 #: builtin/merge-file.c diff.c
 msgid "<algorithm>"
 msgstr "<algoritma>"
@@ -10553,7 +10580,7 @@
 msgid "Not handling anything other than two heads merge."
 msgstr "Tak tangani apapun selain penggabungan dua kepala."
 
-#: builtin/merge.c
+#: builtin/merge.c builtin/sparse-checkout.c
 #, c-format
 msgid "unable to write %s"
 msgstr "tidak dapat menulis %s"
@@ -10853,6 +10880,10 @@
 msgstr "tulis bitmap multipak"
 
 #: builtin/multi-pack-index.c
+msgid "write a new incremental MIDX"
+msgstr "tulis MIDX tambahan baru"
+
+#: builtin/multi-pack-index.c
 msgid "write multi-pack index containing only given indexes"
 msgstr "tulis indeks multipak yang hanya berisi indeks yang diberikan"
 
@@ -13337,6 +13368,10 @@
 msgstr "git refs migrate --ref-format=<format> [--dry-run]"
 
 #: builtin/refs.c
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [---verbose]"
+
+#: builtin/refs.c
 msgid "specify the reference format to convert to"
 msgstr "sebutkan format referensi untuk dikonversi"
 
@@ -13353,6 +13388,14 @@
 msgid "repository already uses '%s' format"
 msgstr "repositori telah menggunakan format '%s'"
 
+#: builtin/refs.c
+msgid "enable strict checking"
+msgstr "aktifkan pemeriksaan lebih ketat"
+
+#: builtin/refs.c
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' tidak mengambil argumen"
+
 #: builtin/remote.c
 msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
@@ -15156,12 +15199,12 @@
 msgstr "gagal mencari referensi"
 
 #: builtin/show-ref.c
-msgid "only show tags (can be combined with branches)"
-msgstr "hanya perlihatkan tag (bisa dikombinasikan dengan cabang)"
+msgid "only show tags (can be combined with --branches)"
+msgstr "hanya perlihatkan tag (bisa dikombinasikan dengan --branches)"
 
 #: builtin/show-ref.c
-msgid "only show branches (can be combined with tags)"
-msgstr "hanya perlihatkan cabang (bisa dikombinasikan dengan tag)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "hanya perlihatkan cabang (bisa dikombinasikan dengan --tags)"
 
 #: builtin/show-ref.c
 msgid "check for reference existence without resolving"
@@ -15228,6 +15271,11 @@
 msgstr "gagal membuat direktori untuk berkas sparse-checkout"
 
 #: builtin/sparse-checkout.c
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "tidak dapat membuka (fdopen) %s"
+
+#: builtin/sparse-checkout.c
 msgid "failed to initialize worktree config"
 msgstr "gagal menginisialisasi konfigurasi pohon kerja"
 
@@ -15797,8 +15845,8 @@
 
 #: builtin/submodule--helper.c
 #, c-format
-msgid "unexpected mode %o\n"
-msgstr "mode tidak diharapkan %o\n"
+msgid "unexpected mode %o"
+msgstr "mode tidak diharapkan %o"
 
 #: builtin/submodule--helper.c
 msgid "use the commit stored in the index instead of the submodule HEAD"
@@ -18519,7 +18567,7 @@
 msgid "unable to create temporary graph layer"
 msgstr "tidak dapat membuat lapisan grafik dasar"
 
-#: commit-graph.c
+#: commit-graph.c midx-write.c
 #, c-format
 msgid "unable to adjust shared permissions for '%s'"
 msgstr "tidak dapat menyesuaikan perizinan berbagi untuk '%s'"
@@ -19894,7 +19942,7 @@
 msgid "Unknown value for 'diff.submodule' config variable: '%s'"
 msgstr "Nilai tidak dikenal untuk variabel konfigurasi 'diff.submodule': '%s'"
 
-#: diff.c transport.c
+#: diff.c merge-recursive.c transport.c
 #, c-format
 msgid "unknown value for config '%s': %s"
 msgstr "nilai tidak dikenal untuk konfigurasi '%s': %s"
@@ -21529,6 +21577,10 @@
 msgid "Unable to create '%s.lock': %s"
 msgstr "Tidak dapat membuat '%s.lock': %s"
 
+#: log-tree.c
+msgid "unable to create temporary object directory"
+msgstr "tidak dapat membuat direktori objek sementara"
+
 #: loose.c
 #, c-format
 msgid "could not write loose object index %s"
@@ -21536,8 +21588,8 @@
 
 #: loose.c
 #, c-format
-msgid "failed to write loose object index %s\n"
-msgstr "gagal menulis indeks objek longgar %s\n"
+msgid "failed to write loose object index %s"
+msgstr "gagal menulis indeks objek longgar %s"
 
 #: ls-refs.c
 #, c-format
@@ -22201,6 +22253,20 @@
 msgstr "tidak dapat membuka indeks untuk %s"
 
 #: midx-write.c
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "tidak dapat mentautkan '%s' ke '%s'"
+
+#: midx-write.c midx.c
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "gagal membersihkan indeks multipak pada %s"
+
+#: midx-write.c
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "tidak dapat menulis MIDX tambahan dengan bitmap"
+
+#: midx-write.c
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr "abaikan indeks multipak yang sudah ada; checksum tidak cocok"
 
@@ -22237,14 +22303,30 @@
 msgstr "menolak menulis .bitmap multipak tanpa objek apapun"
 
 #: midx-write.c
+msgid "unable to create temporary MIDX layer"
+msgstr "tidak dapat membuat lapisan MIDX sementara"
+
+#: midx-write.c
 msgid "could not write multi-pack bitmap"
 msgstr "tidak dapat menulis bitmap multipak"
 
 #: midx-write.c
+msgid "unable to open multi-pack-index chain file"
+msgstr "tidak dapat membuka berkas rantai indeks multipak"
+
+#: midx-write.c
+msgid "unable to rename new multi-pack-index layer"
+msgstr "tidak dapat menamai ulang lapisan indeks multipak baru"
+
+#: midx-write.c
 msgid "could not write multi-pack-index"
 msgstr "gagal menulis indeks multipak"
 
 #: midx-write.c
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "tidak dapat mengkadaluarsakan pak dari indeks multipak tambahan"
+
+#: midx-write.c
 msgid "Counting referenced objects"
 msgstr "Menghitung objek tereferensi"
 
@@ -22253,6 +22335,10 @@
 msgstr "Mencari dan menghapus berkas pak tak tereferensi"
 
 #: midx-write.c
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "tidak dapat mempak ulang indeks multipak tambahan"
+
+#: midx-write.c
 msgid "could not start pack-objects"
 msgstr "tidak dapat memulai pack-objects"
 
@@ -22329,6 +22415,33 @@
 msgstr "nama pak indeks multipak tidak berurutan: '%s' sebelum '%s'"
 
 #: midx.c
+msgid "multi-pack-index chain file too small"
+msgstr "berkas rantai indeks multipak terlalu kecil"
+
+#: midx.c
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "jumlah pak pada MIDX dasarterlalu tinggi: %<PRIuMAX>"
+
+#: midx.c
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "jumlah object pada MIDX dasar terlalu tinggi: %<PRIuMAX>"
+
+#: midx.c
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "rantai indeks multipak tidak valid: baris '%s' bukan suatu hash"
+
+#: midx.c
+msgid "unable to find all multi-pack index files"
+msgstr "tidak dapat menemukan semua berkas indeks multipak"
+
+#: midx.c
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "posisi objek MIDX tidak valid, MIDX mungkin rusak"
+
+#: midx.c
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
 msgstr "pack-int-id jelek: %u (total pak %u)"
@@ -22351,11 +22464,6 @@
 msgstr "offset indeks multipak besar di luar jangkauan"
 
 #: midx.c
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "gagal membersihkan indeks multipak pada %s"
-
-#: midx.c
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr "berkas indeks multipak ada, tetapi gagal diurai"
 
@@ -22616,6 +22724,16 @@
 
 #: object-file.c
 #, c-format
+msgid "unable to open %s"
+msgstr "tidak dapat membuka %s"
+
+#: object-file.c
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "berkas '%s' dan '%s' berbeda konteks"
+
+#: object-file.c
+#, c-format
 msgid "unable to write file %s"
 msgstr "tidak dapat menulis berkas %s"
 
@@ -22724,11 +22842,6 @@
 
 #: object-file.c
 #, c-format
-msgid "unable to open %s"
-msgstr "tidak dapat membuka %s"
-
-#: object-file.c
-#, c-format
 msgid "hash mismatch for %s (expected %s)"
 msgstr "hash tidak cocok untuk %s (diharapkan %s)"
 
@@ -24215,6 +24328,11 @@
 
 #: ref-filter.c
 #, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "format yang diharapkan: %%(is-base:<mirip komit>)"
+
+#: ref-filter.c
+#, c-format
 msgid "malformed field name: %.*s"
 msgstr "nama bidang rusak: %.*s"
 
@@ -24502,6 +24620,15 @@
 "tidak dapat mengunci referensi '%s': diharapkan referensi simbolik dengan "
 "target '%s': tetapi bukan referensi reguler"
 
+#: refs/files-backend.c
+#, c-format
+msgid "cannot open directory %s"
+msgstr "tidak dapat membuka direktori %s"
+
+#: refs/files-backend.c
+msgid "Checking references consistency"
+msgstr "Memeriksa konsistensi referensi"
+
 #: refs/reftable-backend.c
 #, c-format
 msgid "refname is dangerous: %s"
@@ -25290,12 +25417,16 @@
 msgstr "salin repositori di dalam direktori 'src'"
 
 #: scalar.c
+msgid "specify if tags should be fetched during clone"
+msgstr "rincikan jikan tag hendak diambil selama kloning"
+
+#: scalar.c
 msgid ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 msgstr ""
 "scalar clone [--single-branch] [--branch <cabang utama>] [--full-clone]\n"
-"\t[--[-no-]src] <url> [<pendaftaran>]"
+"\t[--[-no-]src] [--[no-]tags] <url> [<pendaftaran>]"
 
 #: scalar.c
 #, c-format
@@ -25319,6 +25450,11 @@
 
 #: scalar.c
 #, c-format
+msgid "could not disable tags in '%s'"
+msgstr "tidak dapat menonaktifkan tag di '%s'"
+
+#: scalar.c
+#, c-format
 msgid "could not configure '%s'"
 msgstr "tidak dapat menyetel '%s'"
 
@@ -26608,6 +26744,11 @@
 
 #: setup.c
 #, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' bukan mutlak"
+
+#: setup.c
+#, c-format
 msgid ""
 "detected dubious ownership in repository at '%s'\n"
 "%sTo add an exception for this directory, call:\n"
@@ -27181,6 +27322,30 @@
 msgid "command token to send to the server"
 msgstr "token perintah untuk dikirim ke peladen"
 
+#: t/unit-tests/unit-test.c
+msgid "unit-test [<options>]"
+msgstr "unit-test [<opsi>]"
+
+#: t/unit-tests/unit-test.c
+msgid "immediately exit upon the first failed test"
+msgstr "langsung keluar pada saat kegagalan tes pertama"
+
+#: t/unit-tests/unit-test.c
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+#: t/unit-tests/unit-test.c
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "hanya jalankan rangkaian tes atau tes individu <suite[::test]>"
+
+#: t/unit-tests/unit-test.c
+msgid "suite"
+msgstr "rangkaian"
+
+#: t/unit-tests/unit-test.c
+msgid "exclude test suite <suite>"
+msgstr "kecualikan rangkaian tes <rangkaian>"
+
 #: trailer.c
 #, c-format
 msgid "running trailer command '%s' failed"
@@ -28630,6 +28795,10 @@
 msgstr "--dump-aliases tidak kompatibel dengan opsi yang lain\n"
 
 #: git-send-email.perl
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases dan --translate-aliases saling eksklusif\n"
+
+#: git-send-email.perl
 msgid ""
 "fatal: found configuration options for 'sendmail'\n"
 "git-send-email is configured with the sendemail.* options - note the 'e'.\n"
diff --git a/po/sv.po b/po/sv.po
index 4e05168..973dd94 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -5,10 +5,10 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.46.0\n"
+"Project-Id-Version: git 2.47.0\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-07-20 21:56+0100\n"
-"PO-Revision-Date: 2024-07-21 14:53+0100\n"
+"POT-Creation-Date: 2024-09-19 02:06+0000\n"
+"PO-Revision-Date: 2024-09-28 15:45+0100\n"
 "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
 "Language-Team: Svenska <tp-sv@listor.tp-sv.se>\n"
 "Language: sv\n"
@@ -542,7 +542,7 @@
 "/ - search for a hunk matching the given regex\n"
 "s - split the current hunk into smaller hunks\n"
 "e - manually edit the current hunk\n"
-"p - print the current hunk\n"
+"p - print the current hunk, 'P' to use the pager\n"
 "? - print help\n"
 msgstr ""
 "j - lämna stycket obestämt, se nästa obestämda stycke\n"
@@ -553,7 +553,7 @@
 "/ - sök efter stycke som motsvarar angivet reguljärt uttryck\n"
 "s - dela aktuellt stycke i mindre styckens\n"
 "e - redigera aktuellt stycke manuellt\n"
-"p - visa aktuellt stycke\n"
+"p - visa aktuellt stycke, ”P” för att använda bläddrare\n"
 "? - visa hjälp\n"
 
 #, c-format
@@ -664,7 +664,7 @@
 "som lämpligt för att ange lösning och checka in."
 
 msgid "Exiting because of an unresolved conflict."
-msgstr "Avslutar på grund av olöst konflikgt."
+msgstr "Avslutar på grund av olöst konflikt."
 
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr "Du har inte avslutat sammanslagningen (MERGE_HEAD finns)."
@@ -1229,6 +1229,15 @@
 "försök en trevägssammanslagning, fall tillbaka på normal patch om det "
 "misslyckas"
 
+msgid "for conflicts, use our version"
+msgstr "för konflikter, använd vår version"
+
+msgid "for conflicts, use their version"
+msgstr "för konflikter, använd deras version"
+
+msgid "for conflicts, use a union version"
+msgstr "för konflikter, använd en förenad version"
+
 msgid "build a temporary index based on embedded index information"
 msgstr "bygg ett temporärt index baserat på inbyggd indexinformation"
 
@@ -1274,6 +1283,9 @@
 msgid "don't return error for empty patches"
 msgstr "ge inte någon felkod för tomma patchar"
 
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs, och --union kräver --3way"
+
 #, c-format
 msgid "cannot stream blob %s"
 msgstr "kan inte strömma blob:en %s"
@@ -2440,9 +2452,6 @@
 "ogiltigt argument %s för ”git bisect terms”.\n"
 "Flaggor som stöds är: --term-good|--term-old och --term-bad|--term-new."
 
-msgid "revision walk setup failed\n"
-msgstr "misslyckades starta revisionstraversering\n"
-
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "kunde inte öppna ”%s” för tillägg"
@@ -3414,9 +3423,14 @@
 msgid "also read contacts from stdin"
 msgstr "läs även kontakter från standard in"
 
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "kan inte tolka kontakt: %s"
+msgid "read additional mailmap entries from file"
+msgstr "läs ytterligare mailmap-poster från fil"
+
+msgid "blob"
+msgstr "blob"
+
+msgid "read additional mailmap entries from blob"
+msgstr "läs ytterligare mailmap-poster från blob"
 
 msgid "no contacts specified"
 msgstr "inga kontakter angavs"
@@ -3765,6 +3779,10 @@
 msgstr "”%s” kan inte användas vid byte av gren"
 
 #, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "”%s” behöver sökvägar att checka ut"
+
+#, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr "”%s” kan inte användas med ”%s”"
 
@@ -4521,7 +4539,7 @@
 msgid ""
 "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 <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
@@ -4531,7 +4549,7 @@
 msgstr ""
 "git commit [-a | --interactive | --patch] [-s] [-v] [-u<läge>] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <incheckning> | --fixup [(amend|"
-"reword):]<incheckning>)]\n"
+"reword):]<incheckning>]\n"
 "           [-F <fil> | -m <medd>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--"
 "author=<författare>]\n"
@@ -5022,12 +5040,10 @@
 
 msgid ""
 "git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
-"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
-"<name>"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
 msgstr ""
 "git config get [<filflagga>] [<visningsflagga>] [--includes] [--all] [--"
-"regexp=<reguttr>] [--value=<värde>] [--fixed-value] [--default=<förval>] "
-"<namn>"
+"regexp] [--value=<värde>] [--fixed-value] [--default=<förval>] <namn>"
 
 msgid ""
 "git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
@@ -5056,6 +5072,15 @@
 msgstr "git config [<filflagga>] --get-colorbool <namn> [<stdout-är-tty>]"
 
 msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<filflagga>] [<visningsflagga>] [--includes] [--all] [--"
+"regexp=<reguttr>] [--value=<värde>] [--fixed-value] [--default=<förval>] "
+"<namn>"
+
+msgid ""
 "git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
 "[--value=<value>] [--fixed-value] <name> <value>"
 msgstr ""
@@ -5853,8 +5878,8 @@
 "false” för att undvika testet\n"
 
 #, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s sände inte alla nödvändiga objekt\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s sände inte alla nödvändiga objekt"
 
 #, c-format
 msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -5891,8 +5916,8 @@
 msgstr "flaggan ”%s” med värdet ”%s” är inte giltigt för %s"
 
 #, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "flaggan ”%s” ignoreras för %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "flaggan ”%s” ignoreras för %s"
 
 #, c-format
 msgid "%s is not a valid object"
@@ -6568,6 +6593,9 @@
 msgid "enable auto-gc mode"
 msgstr "aktivera auto-gc-läge"
 
+msgid "perform garbage collection in the background"
+msgstr "utför skräpsamling i bakgrunden"
+
 msgid "force running gc even if there may be another gc running"
 msgstr "tvinga gc-körning även om en annan gc kanske körs"
 
@@ -6664,6 +6692,9 @@
 msgid "run tasks based on the state of the repository"
 msgstr "kör uppgifter baserad på arkivets tillstånd"
 
+msgid "perform maintenance in the background"
+msgstr "utför underhåll i bakgrunden"
+
 msgid "frequency"
 msgstr "frekvens"
 
@@ -7521,9 +7552,6 @@
 msgid "Final output: %d %s\n"
 msgstr "Slututdata: %d %s\n"
 
-msgid "unable to create temporary object directory"
-msgstr "kan inte skapa temporär objektkatalog"
-
 #, c-format
 msgid "git show %s: bad file"
 msgstr "git show %s: felaktig fil"
@@ -8080,15 +8108,6 @@
 msgid "use a zealous diff3 based merge"
 msgstr "använd nitisk diff3-baserad sammanslagning"
 
-msgid "for conflicts, use our version"
-msgstr "för konflikter, använd vår version"
-
-msgid "for conflicts, use their version"
-msgstr "för konflikter, använd deras version"
-
-msgid "for conflicts, use a union version"
-msgstr "för konflikter, använd en förenad version"
-
 msgid "<algorithm>"
 msgstr "<algoritm>"
 
@@ -8553,6 +8572,9 @@
 msgid "write multi-pack bitmap"
 msgstr "skriv flerpaketsbitkarta"
 
+msgid "write a new incremental MIDX"
+msgstr "skriv en ny inkrementell MIDX"
+
 msgid "write multi-pack index containing only given indexes"
 msgstr "skriv flerpaketsindex som endast innehåller angivna index"
 
@@ -10546,6 +10568,9 @@
 msgid "git refs migrate --ref-format=<format> [--dry-run]"
 msgstr "git refs migrate --ref-format=<format> [--dry-run]"
 
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
 msgid "specify the reference format to convert to"
 msgstr "ange referensformatet att konvertera till"
 
@@ -10559,6 +10584,12 @@
 msgid "repository already uses '%s' format"
 msgstr "arkivet använder redan ”%s”-format"
 
+msgid "enable strict checking"
+msgstr "aktivera strikt kontroll"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "”git refs verify” tar inget argument"
+
 msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
 "mirror=<fetch|push>] <name> <url>"
@@ -11978,11 +12009,11 @@
 msgid "failed to look up reference"
 msgstr "misslyckades slå upp referensen"
 
-msgid "only show tags (can be combined with branches)"
-msgstr "visa endast taggar (kan kombineras med grenar)"
+msgid "only show tags (can be combined with --branches)"
+msgstr "visa endast taggar (kan kombineras med --branches)"
 
-msgid "only show branches (can be combined with tags)"
-msgstr "visa endast grenar (kan kombineras med taggar)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "visa endast grenar (kan kombineras med --tags)"
 
 msgid "check for reference existence without resolving"
 msgstr "kontrollerar att referensen existerar utan att slå upp dem"
@@ -12034,6 +12065,10 @@
 msgid "failed to create directory for sparse-checkout file"
 msgstr "misslyckades skapa katalog för ”sparse-checkout”-filen"
 
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "kan inte utföra fdopen %s"
+
 msgid "failed to initialize worktree config"
 msgstr "misslyckades initiera arbetskataloginställning"
 
@@ -12485,8 +12520,8 @@
 msgstr "kunde inte hasha objekt från ”%s”"
 
 #, c-format
-msgid "unexpected mode %o\n"
-msgstr "okänt läge %o\n"
+msgid "unexpected mode %o"
+msgstr "okänt läge %o"
 
 msgid "use the commit stored in the index instead of the submodule HEAD"
 msgstr "använd incechkning lagrad i indexet istället för undermodulens HEAD"
@@ -17031,13 +17066,16 @@
 msgid "Unable to create '%s.lock': %s"
 msgstr "Kunde inte skapa ”%s.lock”: %s"
 
+msgid "unable to create temporary object directory"
+msgstr "kan inte skapa temporär objektkatalog"
+
 #, c-format
 msgid "could not write loose object index %s"
 msgstr "kunde inte skriva löst objektindex %s"
 
 #, c-format
-msgid "failed to write loose object index %s\n"
-msgstr "misslyckades skriva löst objektindex %s\n"
+msgid "failed to write loose object index %s"
+msgstr "misslyckades skriva löst objektindex %s"
 
 #, c-format
 msgid "unexpected line: '%s'"
@@ -17586,6 +17624,17 @@
 msgid "could not open index for %s"
 msgstr "kunde inte öppna indexet för %s"
 
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "kan inte länka ”%s” till ”%s”"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "misslyckades städa multi-pack-index på %s"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "kan inte skriva inkrementell MIDX med bitkarta"
+
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr "ignorerar befintlig multi-pack-index; felaktig kontrollsumma"
 
@@ -17614,18 +17663,33 @@
 msgid "refusing to write multi-pack .bitmap without any objects"
 msgstr "kunde inte skriva fler-paketsbitkarta utan några objekt"
 
+msgid "unable to create temporary MIDX layer"
+msgstr "kan inte skapa temporärt MIDX-lager"
+
 msgid "could not write multi-pack bitmap"
 msgstr "kunde inte skriva fler-paketsbitkarta"
 
+msgid "unable to open multi-pack-index chain file"
+msgstr "kan inte öppna kedjefil för multi-pack-index"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "kan inte byta namn på nytt multi-pack-index-lager"
+
 msgid "could not write multi-pack-index"
 msgstr "kunde inte skriva flerpakets-index"
 
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "kan inte låta tid gå ut för paket från inkrementellt multi-pack-index"
+
 msgid "Counting referenced objects"
 msgstr "Räknar refererade objekt"
 
 msgid "Finding and deleting unreferenced packfiles"
 msgstr "Ser efter och tar bort orefererade packfiler"
 
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "kunde packa om ett inkrementellt multi-pack-index"
+
 msgid "could not start pack-objects"
 msgstr "kunde inte starta pack-objects"
 
@@ -17687,6 +17751,27 @@
 msgid "multi-pack-index pack names out of order: '%s' before '%s'"
 msgstr "paketnamn för multi-pack-index i fel ordning: ”%s” före ”%s”"
 
+msgid "multi-pack-index chain file too small"
+msgstr "kedjefilen för multi-pack-index är för liten"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "antalet paket i bas-MIDX för högt: %<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "antalet object i bas-MIDX för högt: %<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "ogiltig kedja för multi-pack-index: raden ”%s” är inte ett hash-värde"
+
+msgid "unable to find all multi-pack index files"
+msgstr "kan inte hitta alla indexfiler för multi-pack"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "ogiltig MIDX-objektposition, MIDX är troligtvis trasig"
+
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
 msgstr "bad pack-int-id: %u (%u paket totalt)"
@@ -17704,10 +17789,6 @@
 msgid "multi-pack-index large offset out of bounds"
 msgstr "stort offset för mult-pack-index utanför gränsen"
 
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "misslyckades städa multi-pack-index på %s"
-
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr "multi-pack-indexfilen finns, men kunde inte tolkas"
 
@@ -19219,6 +19300,10 @@
 msgstr "förväntat format: %%(ahead-behind:<incheckning-igt>)"
 
 #, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "förväntat format: %%(is-base:<incheckning-igt>)"
+
+#, c-format
 msgid "malformed field name: %.*s"
 msgstr "felformat fältnamn: %.*s"
 
@@ -19451,6 +19536,13 @@
 "men är en vanlig referens"
 
 #, c-format
+msgid "cannot open directory %s"
+msgstr "kunde inte öppna katalogen %s"
+
+msgid "Checking references consistency"
+msgstr "Kontrollerar konsistens för referenser"
+
+#, c-format
 msgid "refname is dangerous: %s"
 msgstr "refnamnet är farligt: %s"
 
@@ -20077,12 +20169,15 @@
 msgid "create repository within 'src' directory"
 msgstr "skapa arkiv inuti katalogen ”src”"
 
+msgid "specify if tags should be fetched during clone"
+msgstr "ange om taggar ska hämtas vid kloning"
+
 msgid ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 msgstr ""
 "scalar clone [--single-branch] [--branch <huvudgren>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enrollering>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enrollering>]"
 
 #, c-format
 msgid "cannot deduce worktree name from '%s'"
@@ -20101,6 +20196,10 @@
 msgstr "kunde inte ställa in fjärr i ”%s”"
 
 #, c-format
+msgid "could not disable tags in '%s'"
+msgstr "kunde inte inaktivera taggar i ”%s”"
+
+#, c-format
 msgid "could not configure '%s'"
 msgstr "kunde inte ställa in ”%s”"
 
@@ -21162,6 +21261,10 @@
 msgstr "misslyckades ta status på ”%*ss%s%s”"
 
 #, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory ”%s” är inte absolut"
+
+#, c-format
 msgid ""
 "detected dubious ownership in repository at '%s'\n"
 "%sTo add an exception for this directory, call:\n"
@@ -21624,6 +21727,24 @@
 msgid "command token to send to the server"
 msgstr "igenkänningstecken för kommando att sända till servern"
 
+msgid "unit-test [<options>]"
+msgstr "unit-test [<flaggor>]"
+
+msgid "immediately exit upon the first failed test"
+msgstr "avsluta omedelbart vid det första misslyckade testet"
+
+msgid "suite[::test]"
+msgstr "svit[::test]"
+
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "kör endast testsviten eller individuella testet <svit[::test]>"
+
+msgid "suite"
+msgstr "svit"
+
+msgid "exclude test suite <suite>"
+msgstr "uteslut testsviten <svit>"
+
 #, c-format
 msgid "running trailer command '%s' failed"
 msgstr "misslyckades utföra släpradskommandot ”%s”"
@@ -22793,6 +22914,9 @@
 msgid "--dump-aliases incompatible with other options\n"
 msgstr "--dump-aliases är inkompatibelt med andra flaggor\n"
 
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases och --translate-aliases är ömsesidigt utelsutande\n"
+
 msgid ""
 "fatal: found configuration options for 'sendmail'\n"
 "git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -23093,3 +23217,10 @@
 #, perl-format
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Vill du verkligen sända %s? [y=ja, n=nej]: "
+
+#~ msgid "revision walk setup failed\n"
+#~ msgstr "misslyckades starta revisionstraversering\n"
+
+#, c-format
+#~ msgid "unable to parse contact: %s"
+#~ msgstr "kan inte tolka kontakt: %s"
diff --git a/po/tr.po b/po/tr.po
index 61692d4..7aede5c 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-07-19 13:59+0300\n"
-"PO-Revision-Date: 2024-07-19 14:00+0300\n"
+"POT-Creation-Date: 2024-10-03 06:52+0300\n"
+"PO-Revision-Date: 2024-10-03 07: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"
@@ -632,7 +632,7 @@
 "/ - search for a hunk matching the given regex\n"
 "s - split the current hunk into smaller hunks\n"
 "e - manually edit the current hunk\n"
-"p - print the current hunk\n"
+"p - print the current hunk, 'P' to use the pager\n"
 "? - print help\n"
 msgstr ""
 "j - bu parça için sonra karar ver, bir sonraki karar verilmemiş parçayı gör\n"
@@ -642,8 +642,8 @@
 "g - gidilecek bir parça seç\n"
 "/ - verilen düzenli ifade ile eşleşen bir parça ara\n"
 "s - geçerli parçayı daha ufak parçalara böl\n"
-"e - geçerli parçayı el ile düzenle\n"
-"p - geçerli parçalı yazdır\n"
+"e - geçerli parçayı elle düzenle\n"
+"p - geçerli parçalı yazdır, sayfalayıcı için 'P' kullan\n"
 "? - yardımı yazdır\n"
 
 #, c-format
@@ -1314,6 +1314,15 @@
 msgid "attempt three-way merge, fall back on normal patch if that fails"
 msgstr "3 yönlü birleştirme dene, başarısız olursa normal yamaya geri çekil"
 
+msgid "for conflicts, use our version"
+msgstr "çakışmalarda bizim sürümü kullan"
+
+msgid "for conflicts, use their version"
+msgstr "çakışmalarda onların sürümünü kullan"
+
+msgid "for conflicts, use a union version"
+msgstr "çakışmalarda birlik olmuş bir sürüm kullan"
+
 msgid "build a temporary index based on embedded index information"
 msgstr "gömülü indeks bilgisini temel alan geçici bir indeks oluştur"
 
@@ -1359,6 +1368,9 @@
 msgid "don't return error for empty patches"
 msgstr "boş yamalar için hata döndürme"
 
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs ve --union; --3way gerektiriyor"
+
 #, c-format
 msgid "cannot stream blob %s"
 msgstr "%s ikili nesnesi akıtılamıyor"
@@ -1429,6 +1441,9 @@
 msgid "not a tree object: %s"
 msgstr "bir ağaç nesnesi değil: %s"
 
+msgid "unable to checkout working tree"
+msgstr "çalışma ağacı çıkış yapılamıyor"
+
 #, c-format
 msgid "File not found: %s"
 msgstr "Dosya bulunamadı: %s"
@@ -2531,9 +2546,6 @@
 "'git bisect terms' için geçersiz argüman %s.\n"
 "Desteklenen seçenekler: --term-good|--term-old ve --term-bad|--term-new."
 
-msgid "revision walk setup failed\n"
-msgstr "revizyonda gezinme ayarlaması başarısız oldu\n"
-
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "'%s' iliştirme için açılamadı"
@@ -3508,9 +3520,14 @@
 msgid "also read contacts from stdin"
 msgstr "stdin'den kişileri de oku"
 
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "kişi ayrıştırılamadı: %s"
+msgid "read additional mailmap entries from file"
+msgstr "dosyadan ek mailmap girdilerini oku"
+
+msgid "blob"
+msgstr "ikili nesne"
+
+msgid "read additional mailmap entries from blob"
+msgstr "ikili nesneden ek mailmap girdilerini oku"
 
 msgid "no contacts specified"
 msgstr "kişi belirtilmedi"
@@ -3858,6 +3875,10 @@
 msgstr "dal değiştirilirken '%s' kullanılamaz"
 
 #, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "çıkış yapmak için '%s' yollara gereksinim duyuyor"
+
+#, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr "'%s', '%s' ile birlikte kullanılamaz"
 
@@ -4334,9 +4355,6 @@
 msgid "remote HEAD refers to nonexistent ref, unable to checkout"
 msgstr "uzak konum HEAD'i, var olmayan başvuruya başvuruyor; çıkış yapılamıyor"
 
-msgid "unable to checkout working tree"
-msgstr "çalışma ağacı çıkış yapılamıyor"
-
 msgid "unable to write parameters to config file"
 msgstr "parametreler yapılandırma dosyasına yazılamıyor"
 
@@ -4622,7 +4640,7 @@
 msgid ""
 "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 <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
@@ -4631,14 +4649,14 @@
 "           [--] [<pathspec>...]"
 msgstr ""
 "git commit [-a | --interactive | --patch] [-s] [-v] [-u<kip>] [--amend]\n"
-"           [--dry-run] [(-c | -C | --squash) <işleme> | --fixup [(amend|"
-"reword):]<işleme>)]\n"
-"           [-F <dosya> | -m <ileti>] [--reset-author] [--allow-empty]\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"
 "           [--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"
-"           [--] [<yol-blrtç>...]"
+"           [--] [<yol-belirteci>...]"
 
 msgid "git status [<options>] [--] [<pathspec>...]"
 msgstr "git status [<seçenekler>] [--] [<yol-blrtç>...]"
@@ -5131,12 +5149,10 @@
 
 msgid ""
 "git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
-"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
-"<name>"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
 msgstr ""
-"git config get [<dosya-seçeneği>] [<görüntüleme-seçeneği>] [--includes] [--"
-"all] [--regexp=<düzenli-ifade>] [--value=<değer>] [--fixed-value] [--"
-"default=<öntanımlı>] <ad>"
+"git config get [<dosya-sçnği>] [<görüntü-sçnği>] [--includes] [--all] [--"
+"regexp] [--value=<değer>] [--fixed-value] [--default=<öntanımlı>] <ad>"
 
 msgid ""
 "git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
@@ -5165,6 +5181,15 @@
 msgstr "git config [<dosya-seçeneği>] --get-colorbool <ad> [<stdout-tty>]"
 
 msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<dosya-seçeneği>] [<görüntüleme-seçeneği>] [--includes] [--"
+"all] [--regexp=<düzenli-ifade>] [--value=<değer>] [--fixed-value] [--"
+"default=<öntanımlı>] <ad>"
+
+msgid ""
 "git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
 "[--value=<value>] [--fixed-value] <name> <value>"
 msgstr ""
@@ -5966,8 +5991,8 @@
 "bu denetlemeden kaçınabilirsiniz.\n"
 
 #, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s tüm gerekli nesneleri göndermedi\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s tüm gerekli nesneleri göndermedi"
 
 #, c-format
 msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -6004,8 +6029,8 @@
 msgstr "\"%s\" seçeneği \"%s\" değeri %s için geçerli değil"
 
 #, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "\"%s\" seçeneği %s için yok sayılıyor\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "\"%s\" seçeneği %s için yok sayılıyor"
 
 #, c-format
 msgid "%s is not a valid object"
@@ -6678,6 +6703,9 @@
 msgid "enable auto-gc mode"
 msgstr "auto-gc kipini etkinleştir"
 
+msgid "perform garbage collection in the background"
+msgstr "çöp toplamayı arka planda gerçekleştir"
+
 msgid "force running gc even if there may be another gc running"
 msgstr "başka bir gc çalışıyor olsa bile zorla gc çalıştır"
 
@@ -6773,6 +6801,9 @@
 msgid "run tasks based on the state of the repository"
 msgstr "görevleri deponun durumuna göre çalıştır"
 
+msgid "perform maintenance in the background"
+msgstr "bakımı arka planda gerçekleştir"
+
 msgid "frequency"
 msgstr "sıklık"
 
@@ -7635,9 +7666,6 @@
 msgid "Final output: %d %s\n"
 msgstr "Son çıktı: %d %s\n"
 
-msgid "unable to create temporary object directory"
-msgstr "geçici nesne dizini oluşturulamıyor"
-
 #, c-format
 msgid "git show %s: bad file"
 msgstr "git show %s: hatalı dosya"
@@ -8199,15 +8227,6 @@
 msgid "use a zealous diff3 based merge"
 msgstr "gayretli bir diff3 tabanlı birleştirme kullan"
 
-msgid "for conflicts, use our version"
-msgstr "çakışmalarda bizim sürümü kullan"
-
-msgid "for conflicts, use their version"
-msgstr "çakışmalarda onların sürümünü kullan"
-
-msgid "for conflicts, use a union version"
-msgstr "çakışmalarda birlik olmuş bir sürüm kullan"
-
 msgid "<algorithm>"
 msgstr "<algoritma>"
 
@@ -8670,6 +8689,9 @@
 msgid "write multi-pack bitmap"
 msgstr "çoklu paket biteşlemi yaz"
 
+msgid "write a new incremental MIDX"
+msgstr "yeni bir artımlı MIDX yaz"
+
 msgid "write multi-pack index containing only given indexes"
 msgstr "yalnızca verilen indeksleri içeren çoklu paket indekslerini yaz"
 
@@ -10678,6 +10700,9 @@
 msgid "git refs migrate --ref-format=<format> [--dry-run]"
 msgstr "git refs migrate --ref-format=<biçim> [--dry-run]"
 
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
 msgid "specify the reference format to convert to"
 msgstr "dönüştürülecek başvuru biçimini belirt"
 
@@ -10691,6 +10716,12 @@
 msgid "repository already uses '%s' format"
 msgstr "depo halihazırda '%s' biçimini kullanıyor"
 
+msgid "enable strict checking"
+msgstr "kesin denetlemeyi etkinleştir"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' bir argüman almıyor"
+
 msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
 "mirror=<fetch|push>] <name> <url>"
@@ -12121,11 +12152,11 @@
 msgid "failed to look up reference"
 msgstr "başvuru bakılamadı"
 
-msgid "only show tags (can be combined with branches)"
-msgstr "yalnızca etiketleri göster (dallarla birlikte kullanılabilir)"
+msgid "only show tags (can be combined with --branches)"
+msgstr "yalnızca etiketleri göster (--branches ile birlikte kullanılabilir)"
 
-msgid "only show branches (can be combined with tags)"
-msgstr "yalnızca dalları göster (etiketlerle birlikte kullanılabilir)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "yalnızca dalları göster (--tags ile birlikte kullanılabilir)"
 
 msgid "check for reference existence without resolving"
 msgstr "çözmeden başvuru varlığını denetle"
@@ -12177,6 +12208,10 @@
 msgid "failed to create directory for sparse-checkout file"
 msgstr "aralıklı çıkış dosyası için dizin oluşturulamadı"
 
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "%s fdopen yapılamıyor"
+
 msgid "failed to initialize worktree config"
 msgstr "çalışma ağacı yapılandırması ilklendirilemedi"
 
@@ -12625,8 +12660,8 @@
 msgstr "'%s' üzerinden nesne sağlaması yapılamadı"
 
 #, c-format
-msgid "unexpected mode %o\n"
-msgstr "beklenmedik kip %o\n"
+msgid "unexpected mode %o"
+msgstr "beklenmedik kip %o"
 
 msgid "use the commit stored in the index instead of the submodule HEAD"
 msgstr "altmodül HEAD'i içindeki işleme ile indekstekini karşılaştırmak için"
@@ -17177,13 +17212,16 @@
 msgid "Unable to create '%s.lock': %s"
 msgstr "'%s.lock' oluşturulamıyor: %s"
 
+msgid "unable to create temporary object directory"
+msgstr "geçici nesne dizini oluşturulamıyor"
+
 #, c-format
 msgid "could not write loose object index %s"
 msgstr "gevşek nesne indeksi %s yazılamadı"
 
 #, c-format
-msgid "failed to write loose object index %s\n"
-msgstr "gevşek nesne indeksi %s yazımı başarısız\n"
+msgid "failed to write loose object index %s"
+msgstr "gevşek nesne indeksi %s yazılamadı"
 
 #, c-format
 msgid "unexpected line: '%s'"
@@ -17739,6 +17777,17 @@
 msgid "could not open index for %s"
 msgstr "%s için indeks açılamadı"
 
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "'%s', '%s' ile bağlantılanamıyor"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "multi-pack-index %s konumunda temizlenemedi"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "biteşlem ile artımlı MIDX yazılamıyor"
+
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr "var olan multi-pack-index yok sayılıyor; sağlama toplamı uyumsuzluğu"
 
@@ -17767,18 +17816,34 @@
 msgid "refusing to write multi-pack .bitmap without any objects"
 msgstr "bir nesne olmadan multi-pack .bitmap yazımı reddediliyor"
 
+msgid "unable to create temporary MIDX layer"
+msgstr "geçici MIDX katmanı oluşturulamıyor"
+
 msgid "could not write multi-pack bitmap"
 msgstr "çoklu paket biteşlem yazılamadı"
 
+msgid "unable to open multi-pack-index chain file"
+msgstr "multi-pack-index zincir dosyası açılamıyor"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "yeni multi-pack-index katmanı yeniden adlandırılamıyor"
+
 msgid "could not write multi-pack-index"
 msgstr "multi-pack-index yazılamadı"
 
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr ""
+"artımlı bir multi-pack-index ögesinden paketlerin süresi doldurulamıyor"
+
 msgid "Counting referenced objects"
 msgstr "Başvurulmuş nesneler sayılıyor"
 
 msgid "Finding and deleting unreferenced packfiles"
 msgstr "Başvurulmamış paket dosyaları bulunuyor ve siliniyor"
 
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "artımlı bir multi-pack-index yeniden paketlenemiyor"
+
 msgid "could not start pack-objects"
 msgstr "pack-objects başlatılamadı"
 
@@ -17836,6 +17901,27 @@
 msgid "multi-pack-index pack names out of order: '%s' before '%s'"
 msgstr "multi-pack-index paket adlarının sırasız: '%s' şundan önce: '%s'"
 
+msgid "multi-pack-index chain file too small"
+msgstr "multi-pack-index zincir dosyası pek küçük"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "temel MIDX içindeki paket sayısı pek yüksek: %<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "temel MIDX içindeki nesne sayısı pek yüksek: %<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "geçersiz multi-pack-index zinciri: '%s' bir sağlama değil"
+
+msgid "unable to find all multi-pack index files"
+msgstr "tüm multi-pack-index dosyaları bulunamıyor"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "geçersiz MIDX nesnesi konumu, MIDX büyük olasılıkla hasarlı"
+
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
 msgstr "hatalı pack-int-id: %u (%u toplam paket)"
@@ -17853,10 +17939,6 @@
 msgid "multi-pack-index large offset out of bounds"
 msgstr "multi-pack-index geniş ofseti sınırlar dışında"
 
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "multi-pack-index %s konumunda temizlenemedi"
-
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr "multi-pack-index dosyası var; ancak ayrıştırılamadı"
 
@@ -18065,6 +18147,14 @@
 msgstr "%s ögesinin %s ögesine eksik eşlemlemesi"
 
 #, c-format
+msgid "unable to open %s"
+msgstr "%s açılamıyor"
+
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "'%s' ve '%s' dosyalarının içeriği farklı"
+
+#, c-format
 msgid "unable to write file %s"
 msgstr "%s dosyası yazılamıyor"
 
@@ -18149,10 +18239,6 @@
 msgstr "%s geçerli bir '%s' nesnesi değil"
 
 #, c-format
-msgid "unable to open %s"
-msgstr "%s açılamıyor"
-
-#, c-format
 msgid "hash mismatch for %s (expected %s)"
 msgstr "%s için sağlama uyuşmazlığı (%s bekleniyordu)"
 
@@ -19362,6 +19448,10 @@
 msgstr "beklenen biçim: %%(ahead-behind:<işlememsi>)"
 
 #, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "beklenen biçim: %%(is-base:<işlememsi>)"
+
+#, c-format
 msgid "malformed field name: %.*s"
 msgstr "hatalı oluşturulmuş alan adı: %.*s"
 
@@ -19597,6 +19687,13 @@
 "bekleniyordu; ancak bu normal bir başvuru"
 
 #, c-format
+msgid "cannot open directory %s"
+msgstr "%s dizini açılamıyor"
+
+msgid "Checking references consistency"
+msgstr "Başvuruların tutarlılığı denetleniyor"
+
+#, c-format
 msgid "refname is dangerous: %s"
 msgstr "başvuru adı tehlikeli: %s"
 
@@ -20227,12 +20324,15 @@
 msgid "create repository within 'src' directory"
 msgstr "'src' dizininde depo oluştur"
 
+msgid "specify if tags should be fetched during clone"
+msgstr "etiketlerin klonlama sırasında getirilip getirilmeyeceğini belirt"
+
 msgid ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 msgstr ""
 "scalar clone [--single-branch] [--branch <ana-dal>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<yazılma>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<listeleme>]"
 
 #, c-format
 msgid "cannot deduce worktree name from '%s'"
@@ -20251,6 +20351,10 @@
 msgstr "'%s' içindeki uzak konum yapılandırılamadı"
 
 #, c-format
+msgid "could not disable tags in '%s'"
+msgstr "'%s' içindeki etiketler devre dışı bırakılamıyor"
+
+#, c-format
 msgid "could not configure '%s'"
 msgstr "'%s' yapılandırılamadı"
 
@@ -21306,6 +21410,10 @@
 msgstr "'%*s%s%s' bilgileri alınamadı"
 
 #, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' mutlak değil"
+
+#, c-format
 msgid ""
 "detected dubious ownership in repository at '%s'\n"
 "%sTo add an exception for this directory, call:\n"
@@ -21768,6 +21876,24 @@
 msgid "command token to send to the server"
 msgstr "sunucuya gönderilecek komut jetonu"
 
+msgid "unit-test [<options>]"
+msgstr "unit-test [<seçenekler>]"
+
+msgid "immediately exit upon the first failed test"
+msgstr "ilk başarısız sınamada anında çık"
+
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "yalnızca sınama paketini veya bireysel <süit[::sınama]> çalıştır"
+
+msgid "suite"
+msgstr "suite"
+
+msgid "exclude test suite <suite>"
+msgstr "<süit> sınama süitini dışla"
+
 #, c-format
 msgid "running trailer command '%s' failed"
 msgstr "'%s' artbilgi komutunu çalıştırma başarısız oldu"
@@ -22934,6 +23060,9 @@
 msgid "--dump-aliases incompatible with other options\n"
 msgstr "--dump-aliases diğer seçeneklerle uyumsuz\n"
 
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases ve --translate-aliases birlikte kullanılamaz\n"
+
 msgid ""
 "fatal: found configuration options for 'sendmail'\n"
 "git-send-email is configured with the sendemail.* options - note the 'e'.\n"
diff --git a/po/vi.po b/po/vi.po
index 5f42970..00008b5 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -64,10 +64,10 @@
 # +------------------------------------------------------------------+
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.46\n"
+"Project-Id-Version: git 2.47\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-07-21 00:11+0700\n"
-"PO-Revision-Date: 2024-07-26 11:31+0700\n"
+"POT-Creation-Date: 2024-10-05 01:20+0000\n"
+"PO-Revision-Date: 2024-10-05 16:48+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"
@@ -605,7 +605,7 @@
 "/ - search for a hunk matching the given regex\n"
 "s - split the current hunk into smaller hunks\n"
 "e - manually edit the current hunk\n"
-"p - print the current hunk\n"
+"p - print the current hunk, 'P' to use the pager\n"
 "? - print help\n"
 msgstr ""
 "j - để lại khúc này là chưa quyết định, xem khúc chưa quyết định kế tiếp\n"
@@ -616,7 +616,7 @@
 "/ - tìm một khúc khớp với biểu thức chính quy\n"
 "s - chia khúc hiện tại thành các khúc nhỏ hơn\n"
 "e - sửa bằng tay khúc hiện hành\n"
-"p - in ra khúc hiện hành\n"
+"p - in ra khúc hiện hành, 'P' để chạy trình phân trang\n"
 "? - hiển thị trợ giúp\n"
 
 #, c-format
@@ -1282,6 +1282,15 @@
 msgid "attempt three-way merge, fall back on normal patch if that fails"
 msgstr "thử hòa trộn kiểu three-way, quay lại kiểu bình thường nếu thất bại"
 
+msgid "for conflicts, use our version"
+msgstr "nếu xung đột, sử dụng phiên bản của ta"
+
+msgid "for conflicts, use their version"
+msgstr "nếu xung đột, sử dụng phiên bản của họ"
+
+msgid "for conflicts, use a union version"
+msgstr "nếu xung đột, sử dụng phiên bản kết hợp"
+
 msgid "build a temporary index based on embedded index information"
 msgstr "xây dựng chỉ mục tạm thời dựa trên thông tin chỉ mục được nhúng"
 
@@ -1328,6 +1337,9 @@
 msgid "don't return error for empty patches"
 msgstr "đừng trả về lỗi khi các bản vá trống rỗng"
 
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours, --theirs, và --union cần tuỳ chọn --3way"
+
 #, c-format
 msgid "cannot stream blob %s"
 msgstr "không thể stream blob '%s'"
@@ -1400,6 +1412,10 @@
 msgstr "không phải là đối tượng cây: %s"
 
 #, c-format
+msgid "failed to unpack tree object %s"
+msgstr "gặp lỗi khi giải nén đối tượng cây %s"
+
+#, c-format
 msgid "File not found: %s"
 msgstr "Không tìm thấy tập tin: %s"
 
@@ -2497,9 +2513,6 @@
 "tham số không hợp lệ %s cho 'git bisect terms'.\n"
 "Các tùy chọn hỗ trợ là: --term-good|--term-old và --term-bad|--term-new."
 
-msgid "revision walk setup failed\n"
-msgstr "gặp lỗi cài đặt việc di chuyển qua các điểm xét duyệt\n"
-
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "không thể mở '%s' để nối thêm"
@@ -2707,17 +2720,17 @@
 msgstr "bỏ qua các điểm xét duyệt từ <tập tin>"
 
 msgid "color redundant metadata from previous line differently"
-msgstr "siêu dữ liệu dư thừa màu từ dòng trước khác hẳn"
+msgstr "tô màu khác cho siêu dữ liệu dư thừa từ dòng trước"
 
 msgid "color lines by age"
-msgstr "các dòng màu theo tuổi"
+msgstr "tô màu các dòng theo tuổi"
 
 msgid "spend extra cycles to find better match"
-msgstr "tiêu thụ thêm năng tài nguyên máy móc để tìm kiếm tốt hơn nữa"
+msgstr "tiêu thụ thêm tài nguyên để tìm kiếm tốt hơn nữa"
 
 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 điểm xét duyệt (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"
@@ -3474,9 +3487,14 @@
 msgid "also read contacts from stdin"
 msgstr "đồng thời đọc các danh bạ từ stdin"
 
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "không thể đọc danh bạ: '%s'"
+msgid "read additional mailmap entries from file"
+msgstr "đọc thêm mục mailmap từ tập-tin"
+
+msgid "blob"
+msgstr "blob"
+
+msgid "read additional mailmap entries from blob"
+msgstr "đọc thêm mục mailmap từ blob"
 
 msgid "no contacts specified"
 msgstr "chưa chỉ ra danh bạ"
@@ -3813,7 +3831,11 @@
 
 #, c-format
 msgid "'%s' cannot be used with switching branches"
-msgstr "'%s' không thể được sử dụng với các nhánh chuyển"
+msgstr "'%s' không thể được sử dụng khi chuyển nhánh"
+
+#, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "'%s' cần đường dẫn để checkout"
 
 #, c-format
 msgid "'%s' cannot be used with '%s'"
@@ -4585,7 +4607,7 @@
 msgid ""
 "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 <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
@@ -4660,7 +4682,7 @@
 msgstr "cập nhật tập tin gặp lỗi"
 
 msgid "failed to unpack HEAD tree object"
-msgstr "gặp lỗi khi tháo dỡ HEAD đối tượng cây"
+msgstr "gặp lỗi khi giải nén đối tượng cây HEAD"
 
 msgid "No paths with --include/--only does not make sense."
 msgstr "Không đường dẫn với các tùy chọn --include/--only không hợp lý."
@@ -5106,12 +5128,11 @@
 
 msgid ""
 "git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
-"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
-"<name>"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
 msgstr ""
 "git config get [<tuỳ-chọn>] [<tuỳ-chọn-hiển-thị>] [--includes] [--all] [--"
-"regexp=<biểu-thức-chính-quy>] [--value=<giá-trị>] [--fixed-value] [--"
-"default=<giá-trị-mặc-định>] <khoá>"
+"regexp] [--value=<giá-trị>] [--fixed-value] [--default=<giá-trị-mặc-định>] "
+"<tên>"
 
 msgid ""
 "git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--"
@@ -5141,6 +5162,15 @@
 "git config [<tuỳ-chọn>] --get-colorbool <tên> [<stdout-là-tty-hay-không>]"
 
 msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<tuỳ-chọn>] [<tuỳ-chọn-hiển-thị>] [--includes] [--all] [--"
+"regexp=<biểu-thức-chính-quy>] [--value=<giá-trị>] [--fixed-value] [--"
+"default=<giá-trị-mặc-định>] <khoá>"
+
+msgid ""
 "git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
 "[--value=<value>] [--fixed-value] <name> <value>"
 msgstr ""
@@ -5941,8 +5971,8 @@
 "để tránh kiểm tra này\n"
 
 #, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s đã không gửi tất cả các đối tượng cần thiết\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s đã không gửi tất cả các đối tượng cần thiết"
 
 #, c-format
 msgid "rejected %s because shallow roots are not allowed to be updated"
@@ -5979,8 +6009,8 @@
 msgstr "tùy chọn \"%s\" có giá trị \"%s\" là không hợp lệ cho %s"
 
 #, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "tùy chọn \"%s\" bị bỏ qua với %s\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "tùy chọn \"%s\" bị bỏ qua với %s"
 
 #, c-format
 msgid "%s is not a valid object"
@@ -6652,7 +6682,10 @@
 msgstr "cẩn thận hơn nữa (tăng thời gian chạy)"
 
 msgid "enable auto-gc mode"
-msgstr "bật chế độ auto-gc"
+msgstr "bật chế độ auto-gc (tự động dọn rác)"
+
+msgid "perform garbage collection in the background"
+msgstr "tiến hành gc (dọn rác) trong nền"
 
 msgid "force running gc even if there may be another gc running"
 msgstr "buộc gc chạy ngay cả khi có tiến trình gc khác đang chạy"
@@ -6751,6 +6784,9 @@
 msgid "run tasks based on the state of the repository"
 msgstr "chạy nhiệm vụ dựa trên trạng thái của kho chứa"
 
+msgid "perform maintenance in the background"
+msgstr "tiến hành bảo trì trong nền"
+
 msgid "frequency"
 msgstr "tần số"
 
@@ -7030,10 +7066,10 @@
 msgstr "chỉ hiển thị những cái khớp từ tập tin mà nó khớp toàn bộ các mẫu"
 
 msgid "pager"
-msgstr "dàn trang"
+msgstr "trình phân trang"
 
 msgid "show matching files in the pager"
-msgstr "hiển thị các tập tin khớp trong trang giấy"
+msgstr "hiển thị các tập tin khớp trong trình phân trang"
 
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "cho phép gọi grep(1) (bị bỏ qua bởi lần dịch này)"
@@ -7519,7 +7555,7 @@
 msgstr "sửa các tập tin tại chỗ"
 
 msgid "trim empty trailers"
-msgstr "cắt bỏ phần trống thừa ở đuôi"
+msgstr "cắt bỏ phần trailer trống ở đuôi"
 
 msgid "placement"
 msgstr "vị trí"
@@ -7603,9 +7639,6 @@
 msgid "Final output: %d %s\n"
 msgstr "Đầu ra cuối cùng: %d %s\n"
 
-msgid "unable to create temporary object directory"
-msgstr "không thể tạo thư mục đối tượng tạm thời"
-
 #, c-format
 msgid "git show %s: bad file"
 msgstr "git show %s: sai tập tin"
@@ -8174,15 +8207,6 @@
 msgid "use a zealous diff3 based merge"
 msgstr "dùng kiểu hòa trộn dựa trên 'zealous diff3'"
 
-msgid "for conflicts, use our version"
-msgstr "nếu xung đột, sử dụng phiên bản của ta"
-
-msgid "for conflicts, use their version"
-msgstr "nếu xung đột, sử dụng phiên bản của họ"
-
-msgid "for conflicts, use a union version"
-msgstr "nếu xung đột, sử dụng phiên bản kết hợp"
-
 msgid "<algorithm>"
 msgstr "<thuật toán>"
 
@@ -8654,6 +8678,9 @@
 msgid "write multi-pack bitmap"
 msgstr "ghi multi-pack bitmap"
 
+msgid "write a new incremental MIDX"
+msgstr "ghi incremental MIDX mới"
+
 msgid "write multi-pack index containing only given indexes"
 msgstr "ghi chỉ mục multi-pack chỉ chứa các chỉ mục đã cho"
 
@@ -10674,6 +10701,9 @@
 msgid "git refs migrate --ref-format=<format> [--dry-run]"
 msgstr "git refs migrate --ref-format=<định dạng> [--dry-run]"
 
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
 msgid "specify the reference format to convert to"
 msgstr "chỉ định định dạng tham chiếu để chuyển đổi sang"
 
@@ -10687,6 +10717,12 @@
 msgid "repository already uses '%s' format"
 msgstr "kho đã dùng định dạng '%s'"
 
+msgid "enable strict checking"
+msgstr "cho phép kiểm tra nghiêm ngặt"
+
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' không nhận tham số"
+
 msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
 "mirror=<fetch|push>] <name> <url>"
@@ -12095,11 +12131,11 @@
 msgid "failed to look up reference"
 msgstr "gặp lỗi khi tìm tham chiếu"
 
-msgid "only show tags (can be combined with branches)"
-msgstr "chỉ hiển thị thẻ (có thể tổ hợp cùng với nhánh)"
+msgid "only show tags (can be combined with --branches)"
+msgstr "chỉ hiển thị thẻ (có thể kết hợp với --branches)"
 
-msgid "only show branches (can be combined with tags)"
-msgstr "chỉ hiển thị đầu (có thể tổ hợp cùng với thẻ)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "chỉ hiển thị đầu (có thể kết hợp với --tags)"
 
 msgid "check for reference existence without resolving"
 msgstr "kiểm tra tồn tại tham chiếu nhưng không phân giải"
@@ -12151,6 +12187,10 @@
 msgid "failed to create directory for sparse-checkout file"
 msgstr "gặp lỗi khi tạo thư mục cho tập tin sparse-checkout"
 
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "không thể fdopen %s"
+
 msgid "failed to initialize worktree config"
 msgstr "gặp lỗi khi khởi tạo cấu hình cây làm việc"
 
@@ -12394,7 +12434,7 @@
 msgstr "gặp lỗi khi đọc cây"
 
 msgid "failed to unpack trees"
-msgstr "gặp lỗi khi tháo dỡ cây"
+msgstr "gặp lỗi khi giải nén cây"
 
 msgid "include untracked files in the stash"
 msgstr "bao gồm các tập tin không được theo dõi trong stash"
@@ -12605,8 +12645,8 @@
 msgstr "không thể băm đối tượng từ '%s'"
 
 #, c-format
-msgid "unexpected mode %o\n"
-msgstr "gặp chế độ không như mong chờ %o\n"
+msgid "unexpected mode %o"
+msgstr "gặp chế độ không rõ %o"
 
 msgid "use the commit stored in the index instead of the submodule HEAD"
 msgstr "hùng lần chuyển giao đã lưu trong chỉ mục thay cho HEAD mô-đun-con"
@@ -14774,7 +14814,7 @@
 msgstr[0] "Đang ghi ra đồ thị các lần chuyển giao trong lần %d"
 
 msgid "unable to open commit-graph chain file"
-msgstr "không thể mở tập tin mắt xích đồ thị chuyển giao"
+msgstr "không thể mở tập tin chain đồ thị chuyển giao"
 
 msgid "failed to rename base commit-graph file"
 msgstr "gặp lỗi khi đổi tên tập tin đồ-thị-chuyển-giao"
@@ -17171,13 +17211,16 @@
 msgid "Unable to create '%s.lock': %s"
 msgstr "Không thể tạo '%s.lock': %s"
 
+msgid "unable to create temporary object directory"
+msgstr "không thể tạo thư mục đối tượng tạm thời"
+
 #, c-format
 msgid "could not write loose object index %s"
 msgstr "không thể ghi tập tin đối tượng loose %s"
 
 #, c-format
-msgid "failed to write loose object index %s\n"
-msgstr "ghi chỉ mục đối tượng loose %s thất bại\n"
+msgid "failed to write loose object index %s"
+msgstr "ghi chỉ mục đối tượng loose %s thất bại"
 
 #, c-format
 msgid "unexpected line: '%s'"
@@ -17701,7 +17744,7 @@
 
 #, c-format
 msgid "failed to add packfile '%s'"
-msgstr "gặp lỗi khi thêm tập tin gói '%s'"
+msgstr "gặp lỗi khi thêm packfile '%s'"
 
 #, c-format
 msgid "failed to open pack-index '%s'"
@@ -17729,6 +17772,17 @@
 msgid "could not open index for %s"
 msgstr "không thể mở chỉ mục cho %s"
 
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "không thể liên kết '%s' vào '%s'"
+
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "gặp lỗi khi xóa multi-pack-index tại %s"
+
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "không thể ghi incremental MIDX với bitmap"
+
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr "bỏ qua multi-pack-index sẵn có; tổng kiểm không khớp"
 
@@ -17737,7 +17791,7 @@
 
 #, c-format
 msgid "unknown preferred pack: '%s'"
-msgstr "không hiểu \"preferred pack\": %s"
+msgstr "không hiểu preferred pack: %s"
 
 #, c-format
 msgid "cannot select preferred pack %s with no objects"
@@ -17749,19 +17803,31 @@
 
 #, c-format
 msgid "preferred pack '%s' is expired"
-msgstr "\"preferred pack\" '%s' đã hết hạn"
+msgstr "preferred pack '%s' đã hết hạn"
 
 msgid "no pack files to index."
 msgstr "không có tập tin gói để đánh chỉ mục."
 
 msgid "refusing to write multi-pack .bitmap without any objects"
-msgstr "từ chối ghi 'multi-pack bitmap' mà không có bất kỳ đối tượng nào"
+msgstr "từ chối ghi multi-pack bitmap mà không có bất kỳ đối tượng nào"
+
+msgid "unable to create temporary MIDX layer"
+msgstr "không thể tạo lớp MIDX tạm thời"
 
 msgid "could not write multi-pack bitmap"
-msgstr "không thể ghi 'multi-pack bitmap'"
+msgstr "không thể ghi multi-pack bitmap"
+
+msgid "unable to open multi-pack-index chain file"
+msgstr "không thể mở tập tin chain multi-pack-index"
+
+msgid "unable to rename new multi-pack-index layer"
+msgstr "gặp lỗi khi đổi tên lớp multi-pack-index"
 
 msgid "could not write multi-pack-index"
-msgstr "không thể ghi 'multi-pack-index'"
+msgstr "không thể ghi multi-pack-index"
+
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "không thể hết hạn gói từ incremental multi-pack-index"
 
 msgid "Counting referenced objects"
 msgstr "Đang đếm các đối tượng được tham chiếu"
@@ -17769,6 +17835,9 @@
 msgid "Finding and deleting unreferenced packfiles"
 msgstr "Đang tìm và xóa các gói không được tham chiếu"
 
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "không thể repack incremental multi-pack-index"
+
 msgid "could not start pack-objects"
 msgstr "không thể khởi chạy pack-objects"
 
@@ -17825,6 +17894,27 @@
 msgid "multi-pack-index pack names out of order: '%s' before '%s'"
 msgstr "các tên gói multi-pack-index không đúng thứ tự: '%s' trước '%s'"
 
+msgid "multi-pack-index chain file too small"
+msgstr "tập tin chain multi-pack-index quá nhỏ"
+
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "số pack trong base MIDX quá lớn: %<PRIuMAX>"
+
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "số đối tượng trong base MIDX quá lớn: %<PRIuMAX>"
+
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "multi-pack-index chain không hợp lệ: dòng '%s' không phải là mã băm"
+
+msgid "unable to find all multi-pack index files"
+msgstr "không thể tìm thấy tất cả các tập tin multi-pack index"
+
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "vị trí đối tượng MIDX không hợp lệ. MIDX có vẻ như đã bị hỏng"
+
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
 msgstr "pack-int-id sai: %u (%u các gói tổng)"
@@ -17842,10 +17932,6 @@
 msgid "multi-pack-index large offset out of bounds"
 msgstr "multi-pack-index large offset nằm ngoài biên"
 
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "gặp lỗi khi xóa multi-pack-index tại %s"
-
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr "đã có tập tin multi-pack-index, nhưng gặp lỗi khi đọc cú pháp"
 
@@ -18056,6 +18142,14 @@
 msgstr "thiếu ánh xạ %s sang %s"
 
 #, c-format
+msgid "unable to open %s"
+msgstr "không thể mở %s"
+
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "tập tin '%s' và '%s' có nội dung khác nhau"
+
+#, c-format
 msgid "unable to write file %s"
 msgstr "không thể ghi tập tin %s"
 
@@ -18103,7 +18197,7 @@
 
 #, c-format
 msgid "unable to create directory %s"
-msgstr "tạo thư mục \"%s\" gặp lỗi"
+msgstr "tạo thư mục %s gặp lỗi"
 
 #, c-format
 msgid "cannot read object for %s"
@@ -18141,10 +18235,6 @@
 msgstr "%s không phải là một đối tượng '%s' hợp lệ"
 
 #, c-format
-msgid "unable to open %s"
-msgstr "không thể mở %s"
-
-#, c-format
 msgid "hash mismatch for %s (expected %s)"
 msgstr "mã băm không khớp cho %s (cần %s)"
 
@@ -19079,10 +19169,10 @@
 msgstr "chỉ mục bị hỏng, cần %s trong %s, nhưng lại có %s"
 
 msgid "cannot write split index for a sparse index"
-msgstr "không thể ghi chỉ mục chia tách cho \"sparse index\""
+msgstr "không thể ghi chỉ mục chia tách cho sparse index"
 
 msgid "failed to convert to a sparse-index"
-msgstr "gặp lỗi khi chuyển đổi sang \"sparse-index\""
+msgstr "gặp lỗi khi chuyển đổi sang sparse-index"
 
 #, c-format
 msgid "unable to open git dir: %s"
@@ -19352,6 +19442,10 @@
 msgstr "cần định dạng: %%(ahead-behind:<committish>)"
 
 #, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "cần định dạng: %%(is-base:<committish>)"
+
+#, c-format
 msgid "malformed field name: %.*s"
 msgstr "tên trường sai quy cách: %.*s"
 
@@ -19586,6 +19680,13 @@
 "tham chiếu thường"
 
 #, c-format
+msgid "cannot open directory %s"
+msgstr "không thể mở thư mục %s"
+
+msgid "Checking references consistency"
+msgstr "Đang kiểm tra tính nhất quán các tham chiếu"
+
+#, c-format
 msgid "refname is dangerous: %s"
 msgstr "tên tham chiếu không an toàn: %s"
 
@@ -20144,7 +20245,7 @@
 
 #, c-format
 msgid "'%s' does not exist"
-msgstr "\"%s\" không tồn tại"
+msgstr "'%s' không tồn tại"
 
 #, c-format
 msgid "could not switch to '%s'"
@@ -20212,12 +20313,15 @@
 msgid "create repository within 'src' directory"
 msgstr "tạo kho chứa trong thư mục 'src'"
 
+msgid "specify if tags should be fetched during clone"
+msgstr "có nên lấy về thẻ khi nhân bản"
+
 msgid ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 msgstr ""
 "scalar clone [--single-branch] [--branch <nhánh-chính>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 
 #, c-format
 msgid "cannot deduce worktree name from '%s'"
@@ -20236,6 +20340,10 @@
 msgstr "không thể cấu hình máy chủ trong '%s'"
 
 #, c-format
+msgid "could not disable tags in '%s'"
+msgstr "không thể vô hiệu thẻ trong '%s'"
+
+#, c-format
 msgid "could not configure '%s'"
 msgstr "không thể cấu hình '%s'"
 
@@ -21301,6 +21409,10 @@
 msgstr "gặp lỗi khi stat'%*s%s%s'"
 
 #, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' không phải đường dẫn tuyệt đối"
+
+#, c-format
 msgid ""
 "detected dubious ownership in repository at '%s'\n"
 "%sTo add an exception for this directory, call:\n"
@@ -21762,9 +21874,27 @@
 msgid "command token to send to the server"
 msgstr "thẻ bài lệnh để gửi lên cho máy chủ"
 
+msgid "unit-test [<options>]"
+msgstr "unit-test [<các tùy chọn>]"
+
+msgid "immediately exit upon the first failed test"
+msgstr "thoát ngay khi gặp test thất bại"
+
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "chạy riêng test suite hoặc test <suite[::test]>"
+
+msgid "suite"
+msgstr "suite"
+
+msgid "exclude test suite <suite>"
+msgstr "loại trừ test suite <suite>"
+
 #, c-format
 msgid "running trailer command '%s' failed"
-msgstr "chạy lệnh kéo theo '%s' gặp lỗi"
+msgstr "chạy lệnh trailer '%s' gặp lỗi"
 
 #, c-format
 msgid "unknown value '%s' for key '%s'"
@@ -21772,7 +21902,7 @@
 
 #, c-format
 msgid "empty trailer token in trailer '%.*s'"
-msgstr "thẻ thừa trống rỗng trong phần thừa '%.*s'"
+msgstr "thẻ trailer trống rỗng trong phần trailer '%.*s'"
 
 msgid "full write to remote helper failed"
 msgstr "ghi đầy đủ lên helper máy chủ gặp lỗi"
@@ -22962,6 +23092,9 @@
 msgid "--dump-aliases incompatible with other options\n"
 msgstr "--dump-aliases không tương thích với các tùy chọn khác\n"
 
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases và --translate-aliases không tương thích với nhau\n"
+
 msgid ""
 "fatal: found configuration options for 'sendmail'\n"
 "git-send-email is configured with the sendemail.* options - note the 'e'.\n"
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 91b8b79..55d2aee 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -154,8 +154,8 @@
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2024-07-27 22:28+0800\n"
-"PO-Revision-Date: 2024-07-28 19:52+0800\n"
+"POT-Creation-Date: 2024-10-05 03:31+0800\n"
+"PO-Revision-Date: 2024-10-05 03:32+0800\n"
 "Last-Translator: Teng Long <dyroneteng@gmail.com>\n"
 "Language-Team: GitHub <https://github.com/dyrone/git/>\n"
 "Language: zh_CN\n"
@@ -784,7 +784,7 @@
 "/ - search for a hunk matching the given regex\n"
 "s - split the current hunk into smaller hunks\n"
 "e - manually edit the current hunk\n"
-"p - print the current hunk\n"
+"p - print the current hunk, 'P' to use the pager\n"
 "? - print help\n"
 msgstr ""
 "j - 维持该块未决状态,查看下一个未决块\n"
@@ -795,7 +795,7 @@
 "/ - 查找和给定正则表达式匹配的块\n"
 "s - 拆分当前块为更小的块\n"
 "e - 手动编辑当前块\n"
-"p - 显示当前块\n"
+"p - 显示当前块, 'P' 使用分页器\n"
 "? - 显示帮助\n"
 
 #: add-patch.c
@@ -1613,6 +1613,18 @@
 msgid "attempt three-way merge, fall back on normal patch if that fails"
 msgstr "尝试三路合并,如果失败则回落至正常补丁模式"
 
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use our version"
+msgstr "如果冲突,使用我们的版本"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use their version"
+msgstr "如果冲突,使用他们的版本"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use a union version"
+msgstr "如果冲突,使用联合版本"
+
 #: apply.c
 msgid "build a temporary index based on embedded index information"
 msgstr "创建一个临时索引基于嵌入的索引信息"
@@ -1674,6 +1686,10 @@
 msgid "don't return error for empty patches"
 msgstr "对空的补丁不返回错误"
 
+#: apply.c
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours、--theirs 和 --union 需要 --3way"
+
 #: archive-tar.c archive-zip.c
 #, c-format
 msgid "cannot stream blob %s"
@@ -1762,6 +1778,10 @@
 msgid "not a tree object: %s"
 msgstr "不是一个树对象:%s"
 
+#: archive.c builtin/clone.c
+msgid "unable to checkout working tree"
+msgstr "不能检出工作区"
+
 #: archive.c
 #, c-format
 msgid "File not found: %s"
@@ -1878,7 +1898,7 @@
 msgid "Unexpected option --output"
 msgstr "未知参数 --output"
 
-#: archive.c
+#: archive.c t/unit-tests/unit-test.c
 #, c-format
 msgid "extra command line parameter '%s'"
 msgstr "额外的命令行参数:'%s'"
@@ -1949,7 +1969,7 @@
 msgstr "无法对 %s 执行 stat"
 
 #: bisect.c builtin/cat-file.c builtin/index-pack.c builtin/notes.c
-#: builtin/pack-objects.c combine-diff.c rerere.c
+#: builtin/pack-objects.c combine-diff.c object-file.c rerere.c
 #, c-format
 msgid "unable to read %s"
 msgstr "不能读 %s"
@@ -2086,7 +2106,7 @@
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr "--reverse 和 --first-parent 共用,需要指定最新的提交"
 
-#: blame.c builtin/commit.c builtin/log.c builtin/merge.c
+#: blame.c builtin/bisect.c builtin/commit.c builtin/log.c builtin/merge.c
 #: builtin/pack-objects.c builtin/shortlog.c midx-write.c pack-bitmap.c
 #: remote.c sequencer.c submodule.c
 msgid "revision walk setup failed"
@@ -2333,7 +2353,7 @@
 
 #: builtin/add.c builtin/check-ignore.c builtin/commit.c
 #: builtin/count-objects.c builtin/fsck.c builtin/log.c builtin/mv.c
-#: builtin/read-tree.c
+#: builtin/read-tree.c builtin/refs.c
 msgid "be verbose"
 msgstr "冗长输出"
 
@@ -2813,7 +2833,7 @@
 #: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
 #: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c
 #: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c
-#: builtin/tag.c builtin/verify-tag.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/verify-tag.c
 msgid "format"
 msgstr "格式"
 
@@ -3108,10 +3128,6 @@
 "支持的选项有:--term-good|--term-old 和 --term-bad|--term-new。"
 
 #: builtin/bisect.c
-msgid "revision walk setup failed\n"
-msgstr "版本遍历设置失败\n"
-
-#: builtin/bisect.c
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "无法打开 '%s' 进行追加"
@@ -4337,9 +4353,16 @@
 msgstr "还从标准输入读取联系地址"
 
 #: builtin/check-mailmap.c
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "不能解析联系地址:%s"
+msgid "read additional mailmap entries from file"
+msgstr "从文件中读取附加邮件映射条目"
+
+#: builtin/check-mailmap.c
+msgid "blob"
+msgstr "数据对象"
+
+#: builtin/check-mailmap.c
+msgid "read additional mailmap entries from blob"
+msgstr "从数据对象中读取附加邮件映射条目"
 
 #: builtin/check-mailmap.c
 msgid "no contacts specified"
@@ -4759,6 +4782,11 @@
 
 #: builtin/checkout.c
 #, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "'%s' 需要路径进行检出"
+
+#: builtin/checkout.c
+#, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr "'%s' 不能和 '%s' 同时使用"
 
@@ -5223,7 +5251,7 @@
 msgid "separate git dir from working tree"
 msgstr "git目录和工作区分离"
 
-#: builtin/clone.c builtin/init-db.c
+#: builtin/clone.c builtin/init-db.c builtin/submodule--helper.c
 msgid "specify the reference format to use"
 msgstr "指定要使用的引用格式"
 
@@ -5320,7 +5348,7 @@
 msgid "failed to copy file to '%s'"
 msgstr "无法拷贝文件至 '%s'"
 
-#: builtin/clone.c
+#: builtin/clone.c refs/files-backend.c
 #, c-format
 msgid "failed to iterate over '%s'"
 msgstr "无法在 '%s' 上迭代"
@@ -5363,10 +5391,6 @@
 msgstr "远程 HEAD 指向一个不存在的引用,无法检出"
 
 #: builtin/clone.c
-msgid "unable to checkout working tree"
-msgstr "不能检出工作区"
-
-#: builtin/clone.c
 msgid "unable to write parameters to config file"
 msgstr "无法将参数写入配置文件"
 
@@ -5386,7 +5410,8 @@
 msgid "You must specify a repository to clone."
 msgstr "您必须指定一个仓库来克隆。"
 
-#: builtin/clone.c builtin/init-db.c builtin/refs.c setup.c
+#: builtin/clone.c builtin/init-db.c builtin/refs.c builtin/submodule--helper.c
+#: setup.c
 #, c-format
 msgid "unknown ref storage format '%s'"
 msgstr "未知的引用存储格式 '%s'"
@@ -5724,7 +5749,7 @@
 msgid ""
 "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 <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
@@ -5734,7 +5759,7 @@
 msgstr ""
 "git commit [-a | --interactive | --patch] [-s] [-v] [-u<模式>] [--amend]\n"
 "           [--dry-run] [(-c | -C | --squash) <提交> | --fixup [(amend|"
-"reword):]<提交>)]\n"
+"reword):]<提交>]\n"
 "           [-F <文件> | -m <消息>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<作者>]\n"
 "           [--date=<日期>] [--cleanup=<模式>] [--[no-]status]\n"
@@ -6327,11 +6352,10 @@
 #: builtin/config.c
 msgid ""
 "git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
-"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
-"<name>"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
 msgstr ""
-"git config get [<文件选项>] [<显示选项>] [--includes] [--all] [--regexp=<正则"
-"表达式>] [--value=<值>] [--fixed-value] [--default=<默认值>] <名称>"
+"git config get [<文件选项>] [<显示选项>] [--includes] [--all] [--regexp] [--"
+"value=<值>] [--fixed-value] [--default=<默认值>] <名称>"
 
 #: builtin/config.c
 msgid ""
@@ -6367,6 +6391,15 @@
 
 #: builtin/config.c
 msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<文件选项>] [<显示选项>] [--includes] [--all] [--regexp=<正则"
+"表达式>] [--value=<值>] [--fixed-value] [--default=<默认值>] <名称>"
+
+#: builtin/config.c
+msgid ""
 "git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
 "[--value=<value>] [--fixed-value] <name> <value>"
 msgstr ""
@@ -7373,8 +7406,8 @@
 
 #: builtin/fetch.c
 #, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s 未发送所有必需的对象\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s 未发送所有必需的对象"
 
 #: builtin/fetch.c
 #, c-format
@@ -7422,8 +7455,8 @@
 
 #: builtin/fetch.c
 #, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "选项 \"%s\" 为 %s 所忽略\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "选项 \"%s\" 为 %s 所忽略"
 
 #: builtin/fetch.c object-file.c
 #, c-format
@@ -8266,6 +8299,10 @@
 msgstr "启用自动垃圾回收模式"
 
 #: builtin/gc.c
+msgid "perform garbage collection in the background"
+msgstr "在后台进行垃圾回收"
+
+#: builtin/gc.c
 msgid "force running gc even if there may be another gc running"
 msgstr "强制执行 gc 即使另外一个 gc 正在执行"
 
@@ -8383,6 +8420,10 @@
 msgstr "基于仓库状态来运行任务"
 
 #: builtin/gc.c
+msgid "perform maintenance in the background"
+msgstr "在后台执行运维"
+
+#: builtin/gc.c
 msgid "frequency"
 msgstr "频率"
 
@@ -9474,10 +9515,6 @@
 msgstr "最终输出:%d %s\n"
 
 #: builtin/log.c
-msgid "unable to create temporary object directory"
-msgstr "无法创建临时对象目录"
-
-#: builtin/log.c
 #, c-format
 msgid "git show %s: bad file"
 msgstr "git show %s: 损坏的文件"
@@ -10205,18 +10242,6 @@
 msgid "use a zealous diff3 based merge"
 msgstr "使用基于狂热 diff3(zealous diff3)的合并"
 
-#: builtin/merge-file.c
-msgid "for conflicts, use our version"
-msgstr "如果冲突,使用我们的版本"
-
-#: builtin/merge-file.c
-msgid "for conflicts, use their version"
-msgstr "如果冲突,使用他们的版本"
-
-#: builtin/merge-file.c
-msgid "for conflicts, use a union version"
-msgstr "如果冲突,使用联合版本"
-
 #: builtin/merge-file.c diff.c
 msgid "<algorithm>"
 msgstr "<算法>"
@@ -10512,7 +10537,7 @@
 msgid "Not handling anything other than two heads merge."
 msgstr "未处理两个头合并之外的任何操作。"
 
-#: builtin/merge.c
+#: builtin/merge.c builtin/sparse-checkout.c
 #, c-format
 msgid "unable to write %s"
 msgstr "不能写 %s"
@@ -10804,6 +10829,10 @@
 msgstr "写入多包位图"
 
 #: builtin/multi-pack-index.c
+msgid "write a new incremental MIDX"
+msgstr "写入一个新的增量 MIDX"
+
+#: builtin/multi-pack-index.c
 msgid "write multi-pack index containing only given indexes"
 msgstr "写入只包括给定索引的多包索引"
 
@@ -13206,6 +13235,10 @@
 msgstr "git refs migrate --ref-format=<格式> [--dry-run]"
 
 #: builtin/refs.c
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+#: builtin/refs.c
 msgid "specify the reference format to convert to"
 msgstr "指定要转换的引用格式"
 
@@ -13222,6 +13255,14 @@
 msgid "repository already uses '%s' format"
 msgstr "仓库已使用 '%s' 格式"
 
+#: builtin/refs.c
+msgid "enable strict checking"
+msgstr "启用严格的检查"
+
+#: builtin/refs.c
+msgid "'git refs verify' takes no arguments"
+msgstr "'git refs verify' 不接受任何参数"
+
 #: builtin/remote.c
 msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
@@ -14996,12 +15037,12 @@
 msgstr "无法找到引用"
 
 #: builtin/show-ref.c
-msgid "only show tags (can be combined with branches)"
-msgstr "仅显示标签(可与分支组合使用)"
+msgid "only show tags (can be combined with --branches)"
+msgstr "仅显示标签(可与 --branches 组合使用)"
 
 #: builtin/show-ref.c
-msgid "only show branches (can be combined with tags)"
-msgstr "仅显示分支(可以和标签组合使用)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "仅显示分支(可与 --tags 组合使用)"
 
 #: builtin/show-ref.c
 msgid "check for reference existence without resolving"
@@ -15064,6 +15105,11 @@
 msgstr "无法为稀疏检出文件创建目录"
 
 #: builtin/sparse-checkout.c
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "不能 fdopen %s"
+
+#: builtin/sparse-checkout.c
 msgid "failed to initialize worktree config"
 msgstr "无法初始化工作树配置"
 
@@ -15612,8 +15658,8 @@
 
 #: builtin/submodule--helper.c
 #, c-format
-msgid "unexpected mode %o\n"
-msgstr "意外的模式 %o\n"
+msgid "unexpected mode %o"
+msgstr "意外的模式 %o"
 
 #: builtin/submodule--helper.c
 msgid "use the commit stored in the index instead of the submodule HEAD"
@@ -18289,7 +18335,7 @@
 msgid "unable to create temporary graph layer"
 msgstr "无法创建临时图层"
 
-#: commit-graph.c
+#: commit-graph.c midx-write.c
 #, c-format
 msgid "unable to adjust shared permissions for '%s'"
 msgstr "无法为 '%s' 调整共享权限"
@@ -19638,7 +19684,7 @@
 msgid "Unknown value for 'diff.submodule' config variable: '%s'"
 msgstr "配置变量 'diff.submodule' 未知的取值:'%s'"
 
-#: diff.c transport.c
+#: diff.c merge-recursive.c transport.c
 #, c-format
 msgid "unknown value for config '%s': %s"
 msgstr "配置 '%s' 未知的取值:%s"
@@ -21117,6 +21163,7 @@
 "\n"
 "来设置您账号的缺省身份标识。\n"
 "如果仅在本仓库设置身份标识,则省略 --global 参数。\n"
+"\n"
 
 #: ident.c
 msgid "no email was given and auto-detection is disabled"
@@ -21237,6 +21284,10 @@
 msgid "Unable to create '%s.lock': %s"
 msgstr "不能创建 '%s.lock':%s"
 
+#: log-tree.c
+msgid "unable to create temporary object directory"
+msgstr "无法创建临时对象目录"
+
 #: loose.c
 #, c-format
 msgid "could not write loose object index %s"
@@ -21244,8 +21295,8 @@
 
 #: loose.c
 #, c-format
-msgid "failed to write loose object index %s\n"
-msgstr "无法写入松散对象索引 %s\n"
+msgid "failed to write loose object index %s"
+msgstr "无法写入松散对象索引 %s"
 
 #: ls-refs.c
 #, c-format
@@ -21879,6 +21930,20 @@
 msgstr "不能打开 %s 的索引"
 
 #: midx-write.c
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "无法将 '%s' 链接至 '%s'"
+
+#: midx-write.c midx.c
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "无法清理位于 %s 的多包索引"
+
+#: midx-write.c
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "无法使用位图写入增量 MIDX"
+
+#: midx-write.c
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr "忽略已存在的多包索引,校验码不匹配"
 
@@ -21915,14 +21980,30 @@
 msgstr "拒绝写入没有任何对象的多包位图"
 
 #: midx-write.c
+msgid "unable to create temporary MIDX layer"
+msgstr "无法创建临时 MIDX 层"
+
+#: midx-write.c
 msgid "could not write multi-pack bitmap"
 msgstr "无法写入多包位图"
 
 #: midx-write.c
+msgid "unable to open multi-pack-index chain file"
+msgstr "无法打开多包索引链文件"
+
+#: midx-write.c
+msgid "unable to rename new multi-pack-index layer"
+msgstr "无法重命名新的多包索引层"
+
+#: midx-write.c
 msgid "could not write multi-pack-index"
 msgstr "无法写入多包索引"
 
 #: midx-write.c
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "增量多包索引中的包不能过期"
+
+#: midx-write.c
 msgid "Counting referenced objects"
 msgstr "正在对引用对象计数"
 
@@ -21931,6 +22012,10 @@
 msgstr "正在查找和删除未引用的包文件"
 
 #: midx-write.c
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "无法重新打包增量多包索引"
+
+#: midx-write.c
 msgid "could not start pack-objects"
 msgstr "不能开始 pack-objects"
 
@@ -22002,6 +22087,33 @@
 msgstr "多包索引包名无序:'%s' 在 '%s' 之前"
 
 #: midx.c
+msgid "multi-pack-index chain file too small"
+msgstr "多包索引链文件太小"
+
+#: midx.c
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "基线的 MIDX 中包的数量过高:%<PRIuMAX>"
+
+#: midx.c
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "基线的 MIDX 中对象的数量过高:%<PRIuMAX>"
+
+#: midx.c
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "无效的多包索引链:第 '%s' 行不是哈希值"
+
+#: midx.c
+msgid "unable to find all multi-pack index files"
+msgstr "无法找到所有的多包索引文件"
+
+#: midx.c
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "无效的 MIDX 对象位置,MIDX 可能已损坏"
+
+#: midx.c
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
 msgstr "错的 pack-int-id:%u(共有 %u 个包)"
@@ -22024,11 +22136,6 @@
 msgstr "多包索引大偏移区越界"
 
 #: midx.c
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "无法清理位于 %s 的多包索引"
-
-#: midx.c
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr "多包索引文件存在,但无法解析"
 
@@ -22287,6 +22394,16 @@
 
 #: object-file.c
 #, c-format
+msgid "unable to open %s"
+msgstr "不能打开 %s"
+
+#: object-file.c
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "文件 '%s' 和 '%s' 的内容不同"
+
+#: object-file.c
+#, c-format
 msgid "unable to write file %s"
 msgstr "无法写文件 %s"
 
@@ -22393,11 +22510,6 @@
 
 #: object-file.c
 #, c-format
-msgid "unable to open %s"
-msgstr "不能打开 %s"
-
-#: object-file.c
-#, c-format
 msgid "hash mismatch for %s (expected %s)"
 msgstr "%s 的哈希值不匹配(预期 %s)"
 
@@ -23844,6 +23956,11 @@
 
 #: ref-filter.c
 #, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "期望的格式:%%(is-base:<提交号>)"
+
+#: ref-filter.c
+#, c-format
 msgid "malformed field name: %.*s"
 msgstr "格式错误的字段名:%.*s"
 
@@ -24125,6 +24242,15 @@
 "cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
 msgstr "无法锁定引用 '%s':预期目标为 '%s' 的符号引用:但是是普通引用"
 
+#: refs/files-backend.c
+#, c-format
+msgid "cannot open directory %s"
+msgstr "无法打开目录 %s"
+
+#: refs/files-backend.c
+msgid "Checking references consistency"
+msgstr "正在检查引用一致性"
+
 #: refs/reftable-backend.c
 #, c-format
 msgid "refname is dangerous: %s"
@@ -24895,12 +25021,16 @@
 msgstr "在 'src' 目录中创建仓库"
 
 #: scalar.c
+msgid "specify if tags should be fetched during clone"
+msgstr "如若应在克隆期间获取标签则指定"
+
+#: scalar.c
 msgid ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 msgstr ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<登记>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<登记>]"
 
 #: scalar.c
 #, c-format
@@ -24924,6 +25054,11 @@
 
 #: scalar.c
 #, c-format
+msgid "could not disable tags in '%s'"
+msgstr "无法禁用 '%s' 中的标签"
+
+#: scalar.c
+#, c-format
 msgid "could not configure '%s'"
 msgstr "无法配置 '%s'"
 
@@ -26192,6 +26327,11 @@
 
 #: setup.c
 #, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory '%s' 不是绝对路径"
+
+#: setup.c
+#, c-format
 msgid ""
 "detected dubious ownership in repository at '%s'\n"
 "%sTo add an exception for this directory, call:\n"
@@ -26750,6 +26890,30 @@
 msgid "command token to send to the server"
 msgstr "发送到服务器的命令令牌"
 
+#: t/unit-tests/unit-test.c
+msgid "unit-test [<options>]"
+msgstr "unit-test [<选项>]"
+
+#: t/unit-tests/unit-test.c
+msgid "immediately exit upon the first failed test"
+msgstr "第一次测试失败后立即退出"
+
+#: t/unit-tests/unit-test.c
+msgid "suite[::test]"
+msgstr "suite[::测试用例]"
+
+#: t/unit-tests/unit-test.c
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "只运行测试套件或单独的测试 <测试套件[::测试用例]>"
+
+#: t/unit-tests/unit-test.c
+msgid "suite"
+msgstr "测试套件"
+
+#: t/unit-tests/unit-test.c
+msgid "exclude test suite <suite>"
+msgstr "排除测试套件 <测试套件>"
+
 #: trailer.c
 #, c-format
 msgid "running trailer command '%s' failed"
@@ -28201,6 +28365,10 @@
 msgstr "--dump-aliases 和其它选项不兼容\n"
 
 #: git-send-email.perl
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases 和 --translate-aliases 是互斥的\n"
+
+#: git-send-email.perl
 msgid ""
 "fatal: found configuration options for 'sendmail'\n"
 "git-send-email is configured with the sendemail.* options - note the 'e'.\n"
diff --git a/po/zh_TW.po b/po/zh_TW.po
index abf7157..5e6818f 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-07-19 15:00+0800\n"
-"PO-Revision-Date: 2024-07-24 08:21+0000\n"
+"POT-Creation-Date: 2024-10-05 01:20+0000\n"
+"PO-Revision-Date: 2024-10-05 15:45+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"
@@ -40,7 +40,7 @@
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.6.2\n"
+"X-Generator: Poedit 3.5\n"
 "X-ZhConverter: 繁化姬 dict-f4bc617e-r910 @ 2019/11/16 20:23:12 | https://"
 "zhconvert.org\n"
 
@@ -663,7 +663,7 @@
 "/ - search for a hunk matching the given regex\n"
 "s - split the current hunk into smaller hunks\n"
 "e - manually edit the current hunk\n"
-"p - print the current hunk\n"
+"p - print the current hunk, 'P' to use the pager\n"
 "? - print help\n"
 msgstr ""
 "j - 維持此區塊未決定狀態,檢視下一個未決定區塊\n"
@@ -674,7 +674,7 @@
 "/ - 尋找符合提供之常規表示式的區塊\n"
 "s - 分割目前區塊為更小的區塊\n"
 "e - 手動編輯目前區塊\n"
-"p - 輸出目前區塊\n"
+"p - 輸出目前區塊,「P」分頁顯示\n"
 "? - 顯示說明\n"
 
 #: add-patch.c
@@ -1487,6 +1487,18 @@
 msgid "attempt three-way merge, fall back on normal patch if that fails"
 msgstr "嘗試三方合併,若失敗則回到正常修補模式"
 
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use our version"
+msgstr "如果衝突,使用我們的版本"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use their version"
+msgstr "如果衝突,使用他們的版本"
+
+#: apply.c builtin/merge-file.c
+msgid "for conflicts, use a union version"
+msgstr "如果衝突,使用聯合版本"
+
 #: apply.c
 msgid "build a temporary index based on embedded index information"
 msgstr "組建以嵌入索引資訊為基礎的暫存索引"
@@ -1548,6 +1560,10 @@
 msgid "don't return error for empty patches"
 msgstr "遇到空白修補檔時,不回傳錯誤"
 
+#: apply.c
+msgid "--ours, --theirs, and --union require --3way"
+msgstr "--ours、--theirs 和 --union 需要 --3way"
+
 #: archive-tar.c archive-zip.c
 #, c-format
 msgid "cannot stream blob %s"
@@ -1638,6 +1654,11 @@
 
 #: archive.c
 #, c-format
+msgid "failed to unpack tree object %s"
+msgstr "解包 %s 樹狀物件失敗"
+
+#: archive.c
+#, c-format
 msgid "File not found: %s"
 msgstr "找不到檔案:%s"
 
@@ -1752,7 +1773,7 @@
 msgid "Unexpected option --output"
 msgstr "非預期選項 --output"
 
-#: archive.c
+#: archive.c t/unit-tests/unit-test.c
 #, c-format
 msgid "extra command line parameter '%s'"
 msgstr "多出命令列參數「%s」"
@@ -1823,7 +1844,7 @@
 msgstr "無法統計「%s」"
 
 #: bisect.c builtin/cat-file.c builtin/index-pack.c builtin/notes.c
-#: builtin/pack-objects.c combine-diff.c rerere.c
+#: builtin/pack-objects.c combine-diff.c object-file.c rerere.c
 #, c-format
 msgid "unable to read %s"
 msgstr "無法讀取 %s"
@@ -1958,7 +1979,7 @@
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr "--reverse 和 --first-parent 共用,需要指定最新的提交"
 
-#: blame.c builtin/commit.c builtin/log.c builtin/merge.c
+#: blame.c builtin/bisect.c builtin/commit.c builtin/log.c builtin/merge.c
 #: builtin/pack-objects.c builtin/shortlog.c midx-write.c pack-bitmap.c
 #: remote.c sequencer.c submodule.c
 msgid "revision walk setup failed"
@@ -2035,12 +2056,10 @@
 msgstr "未追蹤:「%s」引用有歧義"
 
 #  譯者:為保證在輸出中對齊,注意調整句中空格!
-#. #-#-#-#-#  branch.c.po  #-#-#-#-#
 #. TRANSLATORS: This is a line listing a remote with duplicate
 #. refspecs in the advice message below. For RTL languages you'll
 #. probably want to swap the "%s" and leading "  " space around.
 #.
-#. #-#-#-#-#  object-name.c.po  #-#-#-#-#
 #. TRANSLATORS: This is line item of ambiguous object output
 #. from describe_ambiguous_object() above. For RTL languages
 #. you'll probably want to swap the "%s" and leading " " space
@@ -2208,7 +2227,7 @@
 
 #: builtin/add.c builtin/check-ignore.c builtin/commit.c
 #: builtin/count-objects.c builtin/fsck.c builtin/log.c builtin/mv.c
-#: builtin/read-tree.c
+#: builtin/read-tree.c builtin/refs.c
 msgid "be verbose"
 msgstr "詳細輸出"
 
@@ -2694,7 +2713,7 @@
 #: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
 #: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c
 #: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c
-#: builtin/tag.c builtin/verify-tag.c
+#: builtin/submodule--helper.c builtin/tag.c builtin/verify-tag.c
 msgid "format"
 msgstr "format"
 
@@ -2991,10 +3010,6 @@
 "支援的選項有:--term-good|--term-old 和 --term-bad|--term-new。"
 
 #: builtin/bisect.c
-msgid "revision walk setup failed\n"
-msgstr "修訂版遍歷設定失敗\n"
-
-#: builtin/bisect.c
 #, c-format
 msgid "could not open '%s' for appending"
 msgstr "無法開啟「%s」進行附加"
@@ -4225,9 +4240,16 @@
 msgstr "亦從 stdin 讀取聯絡地址"
 
 #: builtin/check-mailmap.c
-#, c-format
-msgid "unable to parse contact: %s"
-msgstr "無法解析聯絡地址:%s"
+msgid "read additional mailmap entries from file"
+msgstr "從檔案讀取其他 mailmap 項目"
+
+#: builtin/check-mailmap.c
+msgid "blob"
+msgstr "資料物件"
+
+#: builtin/check-mailmap.c
+msgid "read additional mailmap entries from blob"
+msgstr "從 blob 讀取其他 mailmap 項目"
 
 #: builtin/check-mailmap.c
 msgid "no contacts specified"
@@ -4636,6 +4658,11 @@
 
 #: builtin/checkout.c
 #, c-format
+msgid "'%s' needs the paths to check out"
+msgstr "「%s」需要指定要簽出的路徑"
+
+#: builtin/checkout.c
+#, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr "「%s」不能與「%s」同時使用"
 
@@ -5101,7 +5128,7 @@
 msgid "separate git dir from working tree"
 msgstr "git 目錄和工作區分離"
 
-#: builtin/clone.c builtin/init-db.c
+#: builtin/clone.c builtin/init-db.c builtin/submodule--helper.c
 msgid "specify the reference format to use"
 msgstr "指定要使用的引用格式"
 
@@ -5198,7 +5225,7 @@
 msgid "failed to copy file to '%s'"
 msgstr "複製檔案至 '%s' 失敗"
 
-#: builtin/clone.c
+#: builtin/clone.c refs/files-backend.c
 #, c-format
 msgid "failed to iterate over '%s'"
 msgstr "無法在 '%s' 上疊代"
@@ -5264,7 +5291,8 @@
 msgid "You must specify a repository to clone."
 msgstr "您必須指定要複製的版本庫。"
 
-#: builtin/clone.c builtin/init-db.c builtin/refs.c setup.c
+#: builtin/clone.c builtin/init-db.c builtin/refs.c builtin/submodule--helper.c
+#: setup.c
 #, c-format
 msgid "unknown ref storage format '%s'"
 msgstr "未知的引用儲存格式「%s」"
@@ -5602,7 +5630,7 @@
 msgid ""
 "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 <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
@@ -5612,7 +5640,7 @@
 msgstr ""
 "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 <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
 "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
 "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
@@ -6211,11 +6239,10 @@
 #: builtin/config.c
 msgid ""
 "git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
-"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
-"<name>"
+"regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"
 msgstr ""
-"git config get [<檔案選項>] [<顯示選項>] [--includes] [--all] [--regexp=<常規"
-"表示式>] [--value=<值>] [--fixed-value] [--default=<預設值>] <名稱>"
+"git config get [<檔案選項>] [<顯示選項>] [--includes] [--all] [--regexp] [--"
+"value=<值>] [--fixed-value] [--default=<預設值>] <名稱>"
 
 #: builtin/config.c
 msgid ""
@@ -6251,6 +6278,15 @@
 
 #: builtin/config.c
 msgid ""
+"git config get [<file-option>] [<display-option>] [--includes] [--all] [--"
+"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] "
+"<name>"
+msgstr ""
+"git config get [<檔案選項>] [<顯示選項>] [--includes] [--all] [--regexp=<常規"
+"表示式>] [--value=<值>] [--fixed-value] [--default=<預設值>] <名稱>"
+
+#: builtin/config.c
+msgid ""
 "git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] "
 "[--value=<value>] [--fixed-value] <name> <value>"
 msgstr ""
@@ -7259,8 +7295,8 @@
 
 #: builtin/fetch.c
 #, c-format
-msgid "%s did not send all necessary objects\n"
-msgstr "%s 未傳送所有必需的物件\n"
+msgid "%s did not send all necessary objects"
+msgstr "%s 未傳送所有必需的物件"
 
 #: builtin/fetch.c
 #, c-format
@@ -7308,8 +7344,8 @@
 
 #: builtin/fetch.c
 #, c-format
-msgid "option \"%s\" is ignored for %s\n"
-msgstr "選項「%s」被 %s 忽略\n"
+msgid "option \"%s\" is ignored for %s"
+msgstr "選項「%s」被 %s 忽略"
 
 #: builtin/fetch.c object-file.c
 #, c-format
@@ -8155,6 +8191,10 @@
 msgstr "啟用自動垃圾回收模式"
 
 #: builtin/gc.c
+msgid "perform garbage collection in the background"
+msgstr "在背景執行垃圾回收"
+
+#: builtin/gc.c
 msgid "force running gc even if there may be another gc running"
 msgstr "強制執行 gc 即使另外一個 gc 正在執行"
 
@@ -8271,6 +8311,10 @@
 msgstr "基於版本庫狀態執行作業"
 
 #: builtin/gc.c
+msgid "perform maintenance in the background"
+msgstr "在背景執行維護"
+
+#: builtin/gc.c
 msgid "frequency"
 msgstr "frequency"
 
@@ -8434,7 +8478,6 @@
 msgid "invalid number of threads specified (%d) for %s"
 msgstr "為 %2$s 設定的執行緒數 (%1$d) 無效"
 
-#. #-#-#-#-#  grep.c.po  #-#-#-#-#
 #. TRANSLATORS: %s is the configuration
 #. variable for tweaking threads, currently
 #. grep.threads
@@ -9357,10 +9400,6 @@
 msgstr "最終輸出:%d %s\n"
 
 #: builtin/log.c
-msgid "unable to create temporary object directory"
-msgstr "無法建立暫存物件目錄"
-
-#: builtin/log.c
 #, c-format
 msgid "git show %s: bad file"
 msgstr "git show %s: 損壞的檔案"
@@ -10086,18 +10125,6 @@
 msgid "use a zealous diff3 based merge"
 msgstr "使用基於 zealous diff3 的合併"
 
-#: builtin/merge-file.c
-msgid "for conflicts, use our version"
-msgstr "如果衝突,使用我們的版本"
-
-#: builtin/merge-file.c
-msgid "for conflicts, use their version"
-msgstr "如果衝突,使用他們的版本"
-
-#: builtin/merge-file.c
-msgid "for conflicts, use a union version"
-msgstr "如果衝突,使用聯合版本"
-
 #: builtin/merge-file.c diff.c
 msgid "<algorithm>"
 msgstr "<演算法>"
@@ -10393,7 +10420,7 @@
 msgid "Not handling anything other than two heads merge."
 msgstr "未處理兩個頭合併之外的任何動作。"
 
-#: builtin/merge.c
+#: builtin/merge.c builtin/sparse-checkout.c
 #, c-format
 msgid "unable to write %s"
 msgstr "不能寫 %s"
@@ -10685,6 +10712,10 @@
 msgstr "寫入多包位圖"
 
 #: builtin/multi-pack-index.c
+msgid "write a new incremental MIDX"
+msgstr "寫入新的增量 MIDX"
+
+#: builtin/multi-pack-index.c
 msgid "write multi-pack index containing only given indexes"
 msgstr "寫入只包含指定索引的多包索引"
 
@@ -13091,6 +13122,10 @@
 msgstr "git refs migrate --ref-format=<格式> [--dry-run]"
 
 #: builtin/refs.c
+msgid "git refs verify [--strict] [--verbose]"
+msgstr "git refs verify [--strict] [--verbose]"
+
+#: builtin/refs.c
 msgid "specify the reference format to convert to"
 msgstr "指定要轉換成的引用格式"
 
@@ -13107,6 +13142,14 @@
 msgid "repository already uses '%s' format"
 msgstr "版本庫已經使用 '%s' 格式"
 
+#: builtin/refs.c
+msgid "enable strict checking"
+msgstr "啟用嚴格檢查"
+
+#: builtin/refs.c
+msgid "'git refs verify' takes no arguments"
+msgstr "「git refs verify」不接受引數"
+
 #: builtin/remote.c
 msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
@@ -14877,12 +14920,12 @@
 msgstr "無法查詢引用"
 
 #: builtin/show-ref.c
-msgid "only show tags (can be combined with branches)"
-msgstr "只顯示標籤(可以和分支共用)"
+msgid "only show tags (can be combined with --branches)"
+msgstr "只顯示標籤(可以和 --branches 共用)"
 
 #: builtin/show-ref.c
-msgid "only show branches (can be combined with tags)"
-msgstr "只顯示分支(可以和標籤共用)"
+msgid "only show branches (can be combined with --tags)"
+msgstr "只顯示分支(可以和 --tags 共用)"
 
 #: builtin/show-ref.c
 msgid "check for reference existence without resolving"
@@ -14945,6 +14988,11 @@
 msgstr "無法建立稀疏簽出檔案的目錄"
 
 #: builtin/sparse-checkout.c
+#, c-format
+msgid "unable to fdopen %s"
+msgstr "無法 fdopen %s"
+
+#: builtin/sparse-checkout.c
 msgid "failed to initialize worktree config"
 msgstr "無法初始化工作區組態"
 
@@ -15496,8 +15544,8 @@
 
 #: builtin/submodule--helper.c
 #, c-format
-msgid "unexpected mode %o\n"
-msgstr "非預期的模式 %o\n"
+msgid "unexpected mode %o"
+msgstr "非預期的模式 %o"
 
 #: builtin/submodule--helper.c
 msgid "use the commit stored in the index instead of the submodule HEAD"
@@ -18167,7 +18215,7 @@
 msgid "unable to create temporary graph layer"
 msgstr "無法建立暫時性圖層"
 
-#: commit-graph.c
+#: commit-graph.c midx-write.c
 #, c-format
 msgid "unable to adjust shared permissions for '%s'"
 msgstr "無法調整「%s」的共用權限"
@@ -19504,7 +19552,7 @@
 msgid "Unknown value for 'diff.submodule' config variable: '%s'"
 msgstr "設定變數 'diff.submodule' 未知的取值:'%s'"
 
-#: diff.c transport.c
+#: diff.c merge-recursive.c transport.c
 #, c-format
 msgid "unknown value for config '%s': %s"
 msgstr "設定 '%s' 的取值未知:%s"
@@ -21100,6 +21148,10 @@
 msgid "Unable to create '%s.lock': %s"
 msgstr "不能建立 '%s.lock':%s"
 
+#: log-tree.c
+msgid "unable to create temporary object directory"
+msgstr "無法建立暫存物件目錄"
+
 #: loose.c
 #, c-format
 msgid "could not write loose object index %s"
@@ -21107,8 +21159,8 @@
 
 #: loose.c
 #, c-format
-msgid "failed to write loose object index %s\n"
-msgstr "寫入鬆散物件索引 %s 失敗\n"
+msgid "failed to write loose object index %s"
+msgstr "寫入鬆散物件索引 %s 失敗"
 
 #: ls-refs.c
 #, c-format
@@ -21744,6 +21796,20 @@
 msgstr "無法開啟 %s 的索引"
 
 #: midx-write.c
+#, c-format
+msgid "unable to link '%s' to '%s'"
+msgstr "無法將「%s」link 至「%s」"
+
+#: midx-write.c midx.c
+#, c-format
+msgid "failed to clear multi-pack-index at %s"
+msgstr "清理位於 %s 的多包索引失敗"
+
+#: midx-write.c
+msgid "cannot write incremental MIDX with bitmap"
+msgstr "無法寫入有位圖的增量 MIDX"
+
+#: midx-write.c
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr "忽略現有的多包索引:總和檢查碼不符"
 
@@ -21780,14 +21846,30 @@
 msgstr "拒絕寫入無任何物件的多包 .bitmap"
 
 #: midx-write.c
+msgid "unable to create temporary MIDX layer"
+msgstr "無法建立暫時的 MIDX 層"
+
+#: midx-write.c
 msgid "could not write multi-pack bitmap"
 msgstr "無法寫入多包位圖"
 
 #: midx-write.c
+msgid "unable to open multi-pack-index chain file"
+msgstr "無法開啟多封裝索引鏈檔案"
+
+#: midx-write.c
+msgid "unable to rename new multi-pack-index layer"
+msgstr "無法更改新多封裝索引層的名稱"
+
+#: midx-write.c
 msgid "could not write multi-pack-index"
 msgstr "無法寫入多包索引"
 
 #: midx-write.c
+msgid "cannot expire packs from an incremental multi-pack-index"
+msgstr "無法將一個增量多封裝索引的套件設為過期"
+
+#: midx-write.c
 msgid "Counting referenced objects"
 msgstr "正在計算引用物件"
 
@@ -21796,6 +21878,10 @@
 msgstr "正在尋找並刪除沒有引用的 packfile"
 
 #: midx-write.c
+msgid "cannot repack an incremental multi-pack-index"
+msgstr "無法重新封裝增量的多封裝索引"
+
+#: midx-write.c
 msgid "could not start pack-objects"
 msgstr "不能開始 pack-objects"
 
@@ -21867,6 +21953,33 @@
 msgstr "多包索引包名無序:'%s' 在 '%s' 之前"
 
 #: midx.c
+msgid "multi-pack-index chain file too small"
+msgstr "多封裝索引鏈檔案過小"
+
+#: midx.c
+#, c-format
+msgid "pack count in base MIDX too high: %<PRIuMAX>"
+msgstr "基礎 MIDX 的封裝計數太高:%<PRIuMAX>"
+
+#: midx.c
+#, c-format
+msgid "object count in base MIDX too high: %<PRIuMAX>"
+msgstr "基礎 MIDX 的物件計數太高:%<PRIuMAX>"
+
+#: midx.c
+#, c-format
+msgid "invalid multi-pack-index chain: line '%s' not a hash"
+msgstr "無法的多封裝索引鏈:「%s」列不是雜湊值"
+
+#: midx.c
+msgid "unable to find all multi-pack index files"
+msgstr "找不到所有的多封裝索引檔案"
+
+#: midx.c
+msgid "invalid MIDX object position, MIDX is likely corrupt"
+msgstr "無效的 MIDX 物件位置,MIDX 大概有問題"
+
+#: midx.c
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
 msgstr "錯的 pack-int-id:%u(共有 %u 個包)"
@@ -21889,11 +22002,6 @@
 msgstr "多包索引的最大偏移超出邊界"
 
 #: midx.c
-#, c-format
-msgid "failed to clear multi-pack-index at %s"
-msgstr "清理位於 %s 的多包索引失敗"
-
-#: midx.c
 msgid "multi-pack-index file exists, but failed to parse"
 msgstr "有 multi-pack-index 檔案,但無法解析"
 
@@ -22152,6 +22260,16 @@
 
 #: object-file.c
 #, c-format
+msgid "unable to open %s"
+msgstr "不能開啟 %s"
+
+#: object-file.c
+#, c-format
+msgid "files '%s' and '%s' differ in contents"
+msgstr "「%s」和「%s」檔案內容不同"
+
+#: object-file.c
+#, c-format
 msgid "unable to write file %s"
 msgstr "無法寫檔案 %s"
 
@@ -22258,11 +22376,6 @@
 
 #: object-file.c
 #, c-format
-msgid "unable to open %s"
-msgstr "不能開啟 %s"
-
-#: object-file.c
-#, c-format
 msgid "hash mismatch for %s (expected %s)"
 msgstr "%s 的雜湊值不符合(預期 %s)"
 
@@ -23709,6 +23822,11 @@
 
 #: ref-filter.c
 #, c-format
+msgid "expected format: %%(is-base:<committish>)"
+msgstr "預期格式:%%(is-base:<committish>)"
+
+#: ref-filter.c
+#, c-format
 msgid "malformed field name: %.*s"
 msgstr "格式錯誤的欄位名:%.*s"
 
@@ -23991,6 +24109,15 @@
 "cannot lock ref '%s': expected symref with target '%s': but is a regular ref"
 msgstr "無法鎖定引用「%s」:預期是指向「%s」的符號引用,但這個是一般引用"
 
+#: refs/files-backend.c
+#, c-format
+msgid "cannot open directory %s"
+msgstr "無法開啟 %s 目錄"
+
+#: refs/files-backend.c
+msgid "Checking references consistency"
+msgstr "正在檢查引用一致性"
+
 #: refs/reftable-backend.c
 #, c-format
 msgid "refname is dangerous: %s"
@@ -24760,12 +24887,16 @@
 msgstr "在「src」目錄建立版本庫"
 
 #: scalar.c
+msgid "specify if tags should be fetched during clone"
+msgstr "指定是否要在複製階段抓取標籤"
+
+#: scalar.c
 msgid ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 msgstr ""
 "scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-"\t[--[no-]src] <url> [<enlistment>]"
+"\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"
 
 #: scalar.c
 #, c-format
@@ -24789,6 +24920,11 @@
 
 #: scalar.c
 #, c-format
+msgid "could not disable tags in '%s'"
+msgstr "無法停用「%s」的標籤"
+
+#: scalar.c
+#, c-format
 msgid "could not configure '%s'"
 msgstr "無法設定「%s」"
 
@@ -26061,6 +26197,11 @@
 
 #: setup.c
 #, c-format
+msgid "safe.directory '%s' not absolute"
+msgstr "safe.directory「%s」不是絕對路徑"
+
+#: setup.c
+#, c-format
 msgid ""
 "detected dubious ownership in repository at '%s'\n"
 "%sTo add an exception for this directory, call:\n"
@@ -26617,6 +26758,30 @@
 msgid "command token to send to the server"
 msgstr "要傳送至伺服器的命令代符"
 
+#: t/unit-tests/unit-test.c
+msgid "unit-test [<options>]"
+msgstr "unit-test [<options>]"
+
+#: t/unit-tests/unit-test.c
+msgid "immediately exit upon the first failed test"
+msgstr "一旦有測試失敗就立刻退出"
+
+#: t/unit-tests/unit-test.c
+msgid "suite[::test]"
+msgstr "suite[::test]"
+
+#: t/unit-tests/unit-test.c
+msgid "run only test suite or individual test <suite[::test]>"
+msgstr "只執行測試套件或單獨的測試 <suite[::test]>"
+
+#: t/unit-tests/unit-test.c
+msgid "suite"
+msgstr "suite"
+
+#: t/unit-tests/unit-test.c
+msgid "exclude test suite <suite>"
+msgstr "排除測試套件 <suite>"
+
 #: trailer.c
 #, c-format
 msgid "running trailer command '%s' failed"
@@ -28068,6 +28233,10 @@
 msgstr "--dump-aliases 和其它選項不相容\n"
 
 #: git-send-email.perl
+msgid "--dump-aliases and --translate-aliases are mutually exclusive\n"
+msgstr "--dump-aliases 和 --translate-aliases 互斥\n"
+
+#: git-send-email.perl
 msgid ""
 "fatal: found configuration options for 'sendmail'\n"
 "git-send-email is configured with the sendemail.* options - note the 'e'.\n"
@@ -28413,6 +28582,13 @@
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "您真的要傳送 %s?[y|N]: "
 
+#~ msgid "revision walk setup failed\n"
+#~ msgstr "修訂版遍歷設定失敗\n"
+
+#, c-format
+#~ msgid "unable to parse contact: %s"
+#~ msgstr "無法解析聯絡地址:%s"
+
 #~ msgid ""
 #~ "the add.interactive.useBuiltin setting has been removed!\n"
 #~ "See its entry in 'git help config' for details."
@@ -28434,10 +28610,6 @@
 #~ msgstr "沒有給遠端版本庫 '%s' 設定 URL"
 
 #, c-format
-#~ msgid "unable to copy '%s' to '%s'"
-#~ msgstr "無法複製 '%s' 至 '%s'"
-
-#, c-format
 #~ msgid "remote '%s' has no configured URL"
 #~ msgstr "“%s” 遠端未設定 URL"
 
diff --git a/preload-index.c b/preload-index.c
index 63fd35d..7926eb0 100644
--- a/preload-index.c
+++ b/preload-index.c
@@ -1,6 +1,9 @@
 /*
  * Copyright (C) 2008 Linus Torvalds
  */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "pathspec.h"
 #include "dir.h"
diff --git a/pretty.c b/pretty.c
index 44222fb..6403e26 100644
--- a/pretty.c
+++ b/pretty.c
@@ -63,7 +63,7 @@ static int git_pretty_formats_config(const char *var, const char *value,
 				     void *cb UNUSED)
 {
 	struct cmt_fmt_map *commit_format = NULL;
-	const char *name;
+	const char *name, *stripped;
 	char *fmt;
 	int i;
 
@@ -90,15 +90,21 @@ static int git_pretty_formats_config(const char *var, const char *value,
 		commit_formats_len++;
 	}
 
+	free((char *)commit_format->name);
 	commit_format->name = xstrdup(name);
 	commit_format->format = CMIT_FMT_USERFORMAT;
 	if (git_config_string(&fmt, var, value))
 		return -1;
 
-	if (skip_prefix(fmt, "format:", &commit_format->user_format)) {
+	free((char *)commit_format->user_format);
+	if (skip_prefix(fmt, "format:", &stripped)) {
 		commit_format->is_tformat = 0;
-	} else if (skip_prefix(fmt, "tformat:", &commit_format->user_format)) {
+		commit_format->user_format = xstrdup(stripped);
+		free(fmt);
+	} else if (skip_prefix(fmt, "tformat:", &stripped)) {
 		commit_format->is_tformat = 1;
+		commit_format->user_format = xstrdup(stripped);
+		free(fmt);
 	} else if (strchr(fmt, '%')) {
 		commit_format->is_tformat = 1;
 		commit_format->user_format = fmt;
@@ -1770,6 +1776,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 		}
 	trailer_out:
 		string_list_clear(&filter_list, 0);
+		strbuf_release(&kvsepbuf);
 		strbuf_release(&sepbuf);
 		return ret;
 	}
@@ -2198,7 +2205,7 @@ static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt,
 }
 
 /*
- * pp_handle_indent() prints out the intendation, and
+ * pp_handle_indent() prints out the indentation, and
  * the whole line (without the final newline), after
  * de-tabifying.
  */
diff --git a/promisor-remote.c b/promisor-remote.c
index 317e1b1..9345ae3 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -154,6 +154,7 @@ static int promisor_remote_config(const char *var, const char *value,
 		if (!r)
 			return 0;
 
+		FREE_AND_NULL(r->partial_clone_filter);
 		return git_config_string(&r->partial_clone_filter, var, value);
 	}
 
@@ -189,6 +190,7 @@ void promisor_remote_clear(struct promisor_remote_config *config)
 {
 	while (config->promisors) {
 		struct promisor_remote *r = config->promisors;
+		free(r->partial_clone_filter);
 		config->promisors = config->promisors->next;
 		free(r);
 	}
diff --git a/prompt.c b/prompt.c
index 8935fe4..f21c5bf 100644
--- a/prompt.c
+++ b/prompt.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "parse.h"
 #include "environment.h"
diff --git a/protocol.c b/protocol.c
index 079ba75..bae7226 100644
--- a/protocol.c
+++ b/protocol.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "environment.h"
diff --git a/prune-packed.c b/prune-packed.c
index e54daf7..2bb99c2 100644
--- a/prune-packed.c
+++ b/prune-packed.c
@@ -1,10 +1,12 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
-#include "environment.h"
 #include "gettext.h"
 #include "object-store-ll.h"
 #include "packfile.h"
 #include "progress.h"
 #include "prune-packed.h"
+#include "repository.h"
 
 static struct progress *progress;
 
@@ -37,7 +39,7 @@ void prune_packed_objects(int opts)
 	if (opts & PRUNE_PACKED_VERBOSE)
 		progress = start_delayed_progress(_("Removing duplicate objects"), 256);
 
-	for_each_loose_file_in_objdir(get_object_directory(),
+	for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
 				      prune_object, NULL, prune_subdir, &opts);
 
 	/* Ensure we show 100% before finishing progress */
diff --git a/pseudo-merge.c b/pseudo-merge.c
index f0fde13..10ebd9a 100644
--- a/pseudo-merge.c
+++ b/pseudo-merge.c
@@ -183,11 +183,12 @@ static int pseudo_merge_config(const char *var, const char *value,
 	return ret;
 }
 
-void load_pseudo_merges_from_config(struct string_list *list)
+void load_pseudo_merges_from_config(struct repository *r,
+				    struct string_list *list)
 {
 	struct string_list_item *item;
 
-	git_config(pseudo_merge_config, list);
+	repo_config(r, pseudo_merge_config, list);
 
 	for_each_string_list_item(item, list) {
 		struct pseudo_merge_group *group = item->util;
@@ -201,6 +202,7 @@ void load_pseudo_merges_from_config(struct string_list *list)
 }
 
 static int find_pseudo_merge_group_for_ref(const char *refname,
+					   const char *referent UNUSED,
 					   const struct object_id *oid,
 					   int flags UNUSED,
 					   void *_data)
@@ -217,6 +219,8 @@ static int find_pseudo_merge_group_for_ref(const char *refname,
 	c = lookup_commit(the_repository, oid);
 	if (!c)
 		return 0;
+	if (!packlist_find(writer->to_pack, oid))
+		return 0;
 
 	has_bitmap = bitmap_writer_has_bitmapped_object_id(writer, oid);
 
@@ -357,8 +361,10 @@ static void select_pseudo_merges_1(struct bitmap_writer *writer,
 			p = commit_list_append(c, p);
 		} while (j % group->stable_size);
 
-		bitmap_writer_push_commit(writer, merge, 1);
-		writer->pseudo_merges_nr++;
+		if (merge->parents) {
+			bitmap_writer_push_commit(writer, merge, 1);
+			writer->pseudo_merges_nr++;
+		}
 	}
 
 	/* make up to group->max_merges pseudo merges for unstable commits */
@@ -398,8 +404,9 @@ static void select_pseudo_merges_1(struct bitmap_writer *writer,
 			p = commit_list_append(c, p);
 		}
 
-		bitmap_writer_push_commit(writer, merge, 1);
-		writer->pseudo_merges_nr++;
+		if (merge->parents) {
+			bitmap_writer_push_commit(writer, merge, 1);
+			writer->pseudo_merges_nr++; }
 		if (end >= matches->unstable_nr)
 			break;
 	}
@@ -423,8 +430,7 @@ static void sort_pseudo_merge_matches(struct pseudo_merge_matches *matches)
 	QSORT(matches->unstable, matches->unstable_nr, commit_date_cmp);
 }
 
-void select_pseudo_merges(struct bitmap_writer *writer,
-			  struct commit **commits, size_t commits_nr)
+void select_pseudo_merges(struct bitmap_writer *writer)
 {
 	struct progress *progress = NULL;
 	uint32_t i;
diff --git a/pseudo-merge.h b/pseudo-merge.h
index 2aca01d..4b5feba 100644
--- a/pseudo-merge.h
+++ b/pseudo-merge.h
@@ -10,6 +10,7 @@ struct commit;
 struct string_list;
 struct bitmap_index;
 struct bitmap_writer;
+struct repository;
 
 /*
  * A pseudo-merge group tracks the set of non-bitmapped reference tips
@@ -72,7 +73,7 @@ struct pseudo_merge_matches {
  * entry keys are the pseudo-merge group names, and the values are
  * pointers to the pseudo_merge_group structure itself.
  */
-void load_pseudo_merges_from_config(struct string_list *list);
+void load_pseudo_merges_from_config(struct repository *r, struct string_list *list);
 
 /*
  * A pseudo-merge commit index (pseudo_merge_commit_idx) maps a
@@ -94,8 +95,7 @@ struct pseudo_merge_commit_idx {
  *
  * Optionally shows a progress meter.
  */
-void select_pseudo_merges(struct bitmap_writer *writer,
-			  struct commit **commits, size_t commits_nr);
+void select_pseudo_merges(struct bitmap_writer *writer);
 
 /*
  * Represents a serialized view of a file containing pseudo-merge(s)
diff --git a/range-diff.c b/range-diff.c
index 5f01605..10885ba 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -450,8 +450,10 @@ static void output_pair_header(struct diff_options *diffopt,
 }
 
 static struct userdiff_driver section_headers = {
-	.funcname = { "^ ## (.*) ##$\n"
-		      "^.?@@ (.*)$", REG_EXTENDED }
+	.funcname = {
+		.pattern = "^ ## (.*) ##$\n^.?@@ (.*)$",
+		.cflags = REG_EXTENDED,
+	},
 };
 
 static struct diff_filespec *get_filespec(const char *name, const char *p)
@@ -478,7 +480,7 @@ static void patch_diff(const char *a, const char *b,
 	diff_flush(diffopt);
 }
 
-static struct strbuf *output_prefix_cb(struct diff_options *opt UNUSED, void *data)
+static const char *output_prefix_cb(struct diff_options *opt UNUSED, void *data)
 {
 	return data;
 }
@@ -506,7 +508,7 @@ static void output(struct string_list *a, struct string_list *b,
 	opts.flags.suppress_hunk_header_line_count = 1;
 	opts.output_prefix = output_prefix_cb;
 	strbuf_addstr(&indent, "    ");
-	opts.output_prefix_data = &indent;
+	opts.output_prefix_data = indent.buf;
 	diff_setup_done(&opts);
 
 	/*
diff --git a/reachable.c b/reachable.c
index 46613a6..3e9b3dd 100644
--- a/reachable.c
+++ b/reachable.c
@@ -79,7 +79,7 @@ static void add_rebase_files(struct rev_info *revs)
 	free_worktrees(worktrees);
 }
 
-static int add_one_ref(const char *path, const struct object_id *oid,
+static int add_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
 		       int flag, void *cb_data)
 {
 	struct rev_info *revs = (struct rev_info *)cb_data;
diff --git a/read-cache-ll.h b/read-cache-ll.h
index e0e3960..b5d11d0 100644
--- a/read-cache-ll.h
+++ b/read-cache-ll.h
@@ -151,7 +151,7 @@ enum sparse_index_mode {
 
 	/*
 	 * The index has already been collapsed to sparse directories
-	 * whereever possible.
+	 * wherever possible.
 	 */
 	INDEX_COLLAPSED,
 
diff --git a/read-cache.c b/read-cache.c
index 1f67bb7..294971a 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -31,6 +31,7 @@
 #include "path.h"
 #include "preload-index.h"
 #include "read-cache.h"
+#include "repository.h"
 #include "resolve-undo.h"
 #include "revision.h"
 #include "strbuf.h"
@@ -1945,7 +1946,7 @@ static void tweak_untracked_cache(struct index_state *istate)
 
 static void tweak_split_index(struct index_state *istate)
 {
-	switch (git_config_get_split_index()) {
+	switch (repo_config_get_split_index(the_repository)) {
 	case -1: /* unset: do nothing */
 		break;
 	case 0: /* false */
@@ -2187,6 +2188,7 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con
 		if (err)
 			die(_("unable to join load_cache_entries thread: %s"), strerror(err));
 		mem_pool_combine(istate->ce_mem_pool, p->ce_mem_pool);
+		free(p->ce_mem_pool);
 		consumed += p->consumed;
 	}
 
@@ -2267,7 +2269,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
 
 	src_offset = sizeof(*hdr);
 
-	if (git_config_get_index_threads(&nr_threads))
+	if (repo_config_get_index_threads(the_repository, &nr_threads))
 		nr_threads = 1;
 
 	/* TODO: does creating more threads than cores help? */
@@ -2787,7 +2789,7 @@ static int record_eoie(void)
 	 * used for threading is written by default if the user
 	 * explicitly requested threaded index reads.
 	 */
-	return !git_config_get_index_threads(&val) && val != 1;
+	return !repo_config_get_index_threads(the_repository, &val) && val != 1;
 }
 
 static int record_ieot(void)
@@ -2802,7 +2804,7 @@ static int record_ieot(void)
 	 * written by default if the user explicitly requested
 	 * threaded index reads.
 	 */
-	return !git_config_get_index_threads(&val) && val != 1;
+	return !repo_config_get_index_threads(the_repository, &val) && val != 1;
 }
 
 enum write_extensions {
@@ -2840,8 +2842,9 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 	int csum_fsync_flag;
 	int ieot_entries = 1;
 	struct index_entry_offset_table *ieot = NULL;
-	int nr, nr_threads;
 	struct repository *r = istate->repo;
+	struct strbuf sb = STRBUF_INIT;
+	int nr, nr_threads, ret;
 
 	f = hashfd(tempfile->fd, tempfile->filename.buf);
 
@@ -2875,7 +2878,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 
 	hashwrite(f, &hdr, sizeof(hdr));
 
-	if (!HAVE_THREADS || git_config_get_index_threads(&nr_threads))
+	if (!HAVE_THREADS || repo_config_get_index_threads(the_repository, &nr_threads))
 		nr_threads = 1;
 
 	if (nr_threads != 1 && record_ieot()) {
@@ -2962,8 +2965,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 	strbuf_release(&previous_name_buf);
 
 	if (err) {
-		free(ieot);
-		goto cleanup;
+		ret = err;
+		goto out;
 	}
 
 	offset = hashfile_total(f);
@@ -2985,26 +2988,20 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 	 * index.
 	 */
 	if (ieot) {
-		struct strbuf sb = STRBUF_INIT;
+		strbuf_reset(&sb);
 
 		write_ieot_extension(&sb, ieot);
 		err = write_index_ext_header(f, eoie_c, CACHE_EXT_INDEXENTRYOFFSETTABLE, sb.len) < 0;
 		hashwrite(f, sb.buf, sb.len);
-		strbuf_release(&sb);
-		free(ieot);
-		/*
-		 * NEEDSWORK: write_index_ext_header() never returns a failure,
-		 * and this part may want to be simplified.
-		 */
 		if (err) {
-			err = -1;
-			goto cleanup;
+			ret = -1;
+			goto out;
 		}
 	}
 
 	if (write_extensions & WRITE_SPLIT_INDEX_EXTENSION &&
 	    istate->split_index) {
-		struct strbuf sb = STRBUF_INIT;
+		strbuf_reset(&sb);
 
 		if (istate->sparse_index)
 			die(_("cannot write split index for a sparse index"));
@@ -3013,95 +3010,65 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 			write_index_ext_header(f, eoie_c, CACHE_EXT_LINK,
 					       sb.len) < 0;
 		hashwrite(f, sb.buf, sb.len);
-		strbuf_release(&sb);
-		/*
-		 * NEEDSWORK: write_link_extension() never returns a failure,
-		 * and this part may want to be simplified.
-		 */
 		if (err) {
-			err = -1;
-			goto cleanup;
+			ret = -1;
+			goto out;
 		}
 	}
 	if (write_extensions & WRITE_CACHE_TREE_EXTENSION &&
 	    !drop_cache_tree && istate->cache_tree) {
-		struct strbuf sb = STRBUF_INIT;
+		strbuf_reset(&sb);
 
 		cache_tree_write(&sb, istate->cache_tree);
 		err = write_index_ext_header(f, eoie_c, CACHE_EXT_TREE, sb.len) < 0;
 		hashwrite(f, sb.buf, sb.len);
-		strbuf_release(&sb);
-		/*
-		 * NEEDSWORK: write_index_ext_header() never returns a failure,
-		 * and this part may want to be simplified.
-		 */
 		if (err) {
-			err = -1;
-			goto cleanup;
+			ret = -1;
+			goto out;
 		}
 	}
 	if (write_extensions & WRITE_RESOLVE_UNDO_EXTENSION &&
 	    istate->resolve_undo) {
-		struct strbuf sb = STRBUF_INIT;
+		strbuf_reset(&sb);
 
 		resolve_undo_write(&sb, istate->resolve_undo);
 		err = write_index_ext_header(f, eoie_c, CACHE_EXT_RESOLVE_UNDO,
 					     sb.len) < 0;
 		hashwrite(f, sb.buf, sb.len);
-		strbuf_release(&sb);
-		/*
-		 * NEEDSWORK: write_index_ext_header() never returns a failure,
-		 * and this part may want to be simplified.
-		 */
 		if (err) {
-			err = -1;
-			goto cleanup;
+			ret = -1;
+			goto out;
 		}
 	}
 	if (write_extensions & WRITE_UNTRACKED_CACHE_EXTENSION &&
 	    istate->untracked) {
-		struct strbuf sb = STRBUF_INIT;
+		strbuf_reset(&sb);
 
 		write_untracked_extension(&sb, istate->untracked);
 		err = write_index_ext_header(f, eoie_c, CACHE_EXT_UNTRACKED,
 					     sb.len) < 0;
 		hashwrite(f, sb.buf, sb.len);
-		strbuf_release(&sb);
-		/*
-		 * NEEDSWORK: write_index_ext_header() never returns a failure,
-		 * and this part may want to be simplified.
-		 */
 		if (err) {
-			err = -1;
-			goto cleanup;
+			ret = -1;
+			goto out;
 		}
 	}
 	if (write_extensions & WRITE_FSMONITOR_EXTENSION &&
 	    istate->fsmonitor_last_update) {
-		struct strbuf sb = STRBUF_INIT;
+		strbuf_reset(&sb);
 
 		write_fsmonitor_extension(&sb, istate);
 		err = write_index_ext_header(f, eoie_c, CACHE_EXT_FSMONITOR, sb.len) < 0;
 		hashwrite(f, sb.buf, sb.len);
-		strbuf_release(&sb);
-		/*
-		 * NEEDSWORK: write_index_ext_header() never returns a failure,
-		 * and this part may want to be simplified.
-		 */
 		if (err) {
-			err = -1;
-			goto cleanup;
+			ret = -1;
+			goto out;
 		}
 	}
 	if (istate->sparse_index) {
-		err = write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0);
-		/*
-		 * NEEDSWORK: write_index_ext_header() never returns a failure,
-		 * and this part may want to be simplified.
-		 */
-		if (err) {
-			err = -1;
-			goto cleanup;
+		if (write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0) {
+			ret = -1;
+			goto out;
 		}
 	}
 
@@ -3112,19 +3079,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 	 * when loading the shared index.
 	 */
 	if (eoie_c) {
-		struct strbuf sb = STRBUF_INIT;
+		strbuf_reset(&sb);
 
 		write_eoie_extension(&sb, eoie_c, offset);
 		err = write_index_ext_header(f, NULL, CACHE_EXT_ENDOFINDEXENTRIES, sb.len) < 0;
 		hashwrite(f, sb.buf, sb.len);
-		strbuf_release(&sb);
-		/*
-		 * NEEDSWORK: write_index_ext_header() never returns a failure,
-		 * and this part may want to be simplified.
-		 */
 		if (err) {
-			err = -1;
-			goto cleanup;
+			ret = -1;
+			goto out;
 		}
 	}
 
@@ -3137,12 +3099,12 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 	f = NULL;
 
 	if (close_tempfile_gently(tempfile)) {
-		err = error(_("could not close '%s'"), get_tempfile_path(tempfile));
-		goto cleanup;
+		ret = error(_("could not close '%s'"), get_tempfile_path(tempfile));
+		goto out;
 	}
 	if (stat(get_tempfile_path(tempfile), &st)) {
-		err = error_errno(_("could not stat '%s'"), get_tempfile_path(tempfile));
-		goto cleanup;
+		ret = -1;
+		goto out;
 	}
 	istate->timestamp.sec = (unsigned int)st.st_mtime;
 	istate->timestamp.nsec = ST_MTIME_NSEC(st);
@@ -3157,12 +3119,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 	trace2_data_intmax("index", the_repository, "write/cache_nr",
 			   istate->cache_nr);
 
-	return 0;
+	ret = 0;
 
-cleanup:
+out:
 	if (f)
-		discard_hashfile(f);
-	return err;
+		free_hashfile(f);
+	strbuf_release(&sb);
+	free(ieot);
+	return ret;
 }
 
 void set_alternate_index_output(const char *name)
@@ -3213,9 +3177,9 @@ static int do_write_locked_index(struct index_state *istate,
 	else
 		ret = close_lock_file_gently(lock);
 
-	run_hooks_l("post-index-change",
-			istate->updated_workdir ? "1" : "0",
-			istate->updated_skipworktree ? "1" : "0", NULL);
+	run_hooks_l(the_repository, "post-index-change",
+		    istate->updated_workdir ? "1" : "0",
+		    istate->updated_skipworktree ? "1" : "0", NULL);
 	istate->updated_workdir = 0;
 	istate->updated_skipworktree = 0;
 
@@ -3233,18 +3197,24 @@ static int write_split_index(struct index_state *istate,
 	return ret;
 }
 
-static const char *shared_index_expire = "2.weeks.ago";
-
 static unsigned long get_shared_index_expire_date(void)
 {
 	static unsigned long shared_index_expire_date;
 	static int shared_index_expire_date_prepared;
 
 	if (!shared_index_expire_date_prepared) {
-		git_config_get_expiry("splitindex.sharedindexexpire",
-				      &shared_index_expire);
+		const char *shared_index_expire = "2.weeks.ago";
+		char *value = NULL;
+
+		repo_config_get_expiry(the_repository, "splitindex.sharedindexexpire",
+				       &value);
+		if (value)
+			shared_index_expire = value;
+
 		shared_index_expire_date = approxidate(shared_index_expire);
 		shared_index_expire_date_prepared = 1;
+
+		free(value);
 	}
 
 	return shared_index_expire_date;
@@ -3270,10 +3240,11 @@ static int should_delete_shared_index(const char *shared_index_path)
 static int clean_shared_index_files(const char *current_hex)
 {
 	struct dirent *de;
-	DIR *dir = opendir(get_git_dir());
+	DIR *dir = opendir(repo_get_git_dir(the_repository));
 
 	if (!dir)
-		return error_errno(_("unable to open git dir: %s"), get_git_dir());
+		return error_errno(_("unable to open git dir: %s"),
+				   repo_get_git_dir(the_repository));
 
 	while ((de = readdir(dir)) != NULL) {
 		const char *sha1_hex;
@@ -3332,7 +3303,7 @@ static const int default_max_percent_split_change = 20;
 static int too_many_not_shared_entries(struct index_state *istate)
 {
 	int i, not_shared = 0;
-	int max_split = git_config_get_max_percent_split_change();
+	int max_split = repo_config_get_max_percent_split_change(the_repository);
 
 	switch (max_split) {
 	case -1:
@@ -3363,8 +3334,9 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
 	int new_shared_index, ret, test_split_index_env;
 	struct split_index *si = istate->split_index;
 
-	if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
-		cache_tree_verify(the_repository, istate);
+	if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0) &&
+	    cache_tree_verify(the_repository, istate) < 0)
+		return -1;
 
 	if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
 		if (flags & COMMIT_LOCK)
diff --git a/rebase.c b/rebase.c
index 69a1822..9d1ae95 100644
--- a/rebase.c
+++ b/rebase.c
@@ -11,7 +11,7 @@
  * The callers that care if (any) rebase is requested should say
  *   if (REBASE_TRUE <= rebase_parse_value(string))
  *
- * The callers that want to differenciate an unrecognised value and
+ * The callers that want to differentiate an unrecognised value and
  * false can do so by treating _INVALID and _FALSE differently.
  */
 enum rebase_type rebase_parse_value(const char *value)
diff --git a/ref-filter.c b/ref-filter.c
index 54880a2..dd19500 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -13,6 +13,7 @@
 #include "object-name.h"
 #include "object-store-ll.h"
 #include "oid-array.h"
+#include "repo-settings.h"
 #include "repository.h"
 #include "commit.h"
 #include "mailmap.h"
@@ -75,11 +76,11 @@ struct refname_atom {
 	int lstrip, rstrip;
 };
 
-static struct ref_trailer_buf {
+struct ref_trailer_buf {
 	struct string_list filter_list;
 	struct strbuf sepbuf;
 	struct strbuf kvsepbuf;
-} ref_trailer_buf = {STRING_LIST_INIT_NODUP, STRBUF_INIT, STRBUF_INIT};
+};
 
 static struct expand_data {
 	struct object_id oid;
@@ -169,6 +170,7 @@ enum atom_type {
 	ATOM_ELSE,
 	ATOM_REST,
 	ATOM_AHEADBEHIND,
+	ATOM_ISBASE,
 };
 
 /*
@@ -200,6 +202,7 @@ static struct used_atom {
 			enum { C_BARE, C_BODY, C_BODY_DEP, C_LENGTH, C_LINES,
 			       C_SIG, C_SUB, C_SUB_SANITIZE, C_TRAILERS } option;
 			struct process_trailer_options trailer_opts;
+			struct ref_trailer_buf *trailer_buf;
 			unsigned int nlines;
 		} contents;
 		struct {
@@ -231,7 +234,7 @@ static struct used_atom {
 			enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
 			       S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
 		} signature;
-		const char **describe_args;
+		struct strvec describe_args;
 		struct refname_atom refname;
 		char *head;
 	} u;
@@ -565,21 +568,36 @@ static int trailers_atom_parser(struct ref_format *format UNUSED,
 	atom->u.contents.trailer_opts.no_divider = 1;
 
 	if (arg) {
-		const char *argbuf = xstrfmt("%s)", arg);
+		char *argbuf = xstrfmt("%s)", arg);
+		const char *arg = argbuf;
 		char *invalid_arg = NULL;
+		struct ref_trailer_buf *tb;
+
+		/*
+		 * Do not inline these directly into the used_atom struct!
+		 * When we parse them in format_set_trailers_options(),
+		 * we will make pointer references directly to them,
+		 * which will not survive a realloc() of the used_atom list.
+		 * They must be allocated in a separate, stable struct.
+		 */
+		atom->u.contents.trailer_buf = tb = xmalloc(sizeof(*tb));
+		string_list_init_dup(&tb->filter_list);
+		strbuf_init(&tb->sepbuf, 0);
+		strbuf_init(&tb->kvsepbuf, 0);
 
 		if (format_set_trailers_options(&atom->u.contents.trailer_opts,
-		    &ref_trailer_buf.filter_list,
-		    &ref_trailer_buf.sepbuf,
-		    &ref_trailer_buf.kvsepbuf,
-		    &argbuf, &invalid_arg)) {
+						&tb->filter_list,
+						&tb->sepbuf, &tb->kvsepbuf,
+						&arg, &invalid_arg)) {
 			if (!invalid_arg)
 				strbuf_addf(err, _("expected %%(trailers:key=<value>)"));
 			else
 				strbuf_addf(err, _("unknown %%(trailers) argument: %s"), invalid_arg);
-			free((char *)invalid_arg);
+			free(invalid_arg);
+			free(argbuf);
 			return -1;
 		}
+		free(argbuf);
 	}
 	atom->u.contents.option = C_TRAILERS;
 	return 0;
@@ -676,7 +694,7 @@ static int describe_atom_parser(struct ref_format *format UNUSED,
 				struct used_atom *atom,
 				const char *arg, struct strbuf *err)
 {
-	struct strvec args = STRVEC_INIT;
+	strvec_init(&atom->u.describe_args);
 
 	for (;;) {
 		int found = 0;
@@ -685,13 +703,12 @@ static int describe_atom_parser(struct ref_format *format UNUSED,
 		if (!arg || !*arg)
 			break;
 
-		found = describe_atom_option_parser(&args, &arg, err);
+		found = describe_atom_option_parser(&atom->u.describe_args, &arg, err);
 		if (found < 0)
 			return found;
 		if (!found)
 			return err_bad_arg(err, "describe", bad_arg);
 	}
-	atom->u.describe_args = strvec_detach(&args);
 	return 0;
 }
 
@@ -742,8 +759,7 @@ static int person_name_atom_parser(struct ref_format *format UNUSED,
 	return 0;
 }
 
-static int email_atom_option_parser(struct used_atom *atom,
-				    const char **arg, struct strbuf *err)
+static int email_atom_option_parser(const char **arg)
 {
 	if (!*arg)
 		return EO_RAW;
@@ -761,7 +777,7 @@ static int person_email_atom_parser(struct ref_format *format UNUSED,
 				    const char *arg, struct strbuf *err)
 {
 	for (;;) {
-		int opt = email_atom_option_parser(atom, &arg, err);
+		int opt = email_atom_option_parser(&arg);
 		const char *bad_arg = arg;
 
 		if (opt < 0)
@@ -891,6 +907,23 @@ static int ahead_behind_atom_parser(struct ref_format *format,
 	return 0;
 }
 
+static int is_base_atom_parser(struct ref_format *format,
+			       struct used_atom *atom UNUSED,
+			       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)
+		die("failed to find '%s'", arg);
+
+	return 0;
+}
+
 static int head_atom_parser(struct ref_format *format UNUSED,
 			    struct used_atom *atom,
 			    const char *arg, struct strbuf *err)
@@ -956,6 +989,7 @@ static struct {
 	[ATOM_ELSE] = { "else", SOURCE_NONE },
 	[ATOM_REST] = { "rest", SOURCE_NONE, FIELD_STR, rest_atom_parser },
 	[ATOM_AHEADBEHIND] = { "ahead-behind", SOURCE_OTHER, FIELD_STR, ahead_behind_atom_parser },
+	[ATOM_ISBASE] = { "is-base", SOURCE_OTHER, FIELD_STR, is_base_atom_parser },
 	/*
 	 * Please update $__git_ref_fieldlist in git-completion.bash
 	 * when you add new atoms
@@ -968,6 +1002,7 @@ struct ref_formatting_stack {
 	struct ref_formatting_stack *prev;
 	struct strbuf output;
 	void (*at_end)(struct ref_formatting_stack **stack);
+	void (*at_end_data_free)(void *data);
 	void *at_end_data;
 };
 
@@ -1136,6 +1171,8 @@ static void pop_stack_element(struct ref_formatting_stack **stack)
 	if (prev)
 		strbuf_addbuf(&prev->output, &current->output);
 	strbuf_release(&current->output);
+	if (current->at_end_data_free)
+		current->at_end_data_free(current->at_end_data);
 	free(current);
 	*stack = prev;
 }
@@ -1195,15 +1232,13 @@ static void if_then_else_handler(struct ref_formatting_stack **stack)
 	}
 
 	*stack = cur;
-	free(if_then_else);
 }
 
 static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
 			   struct strbuf *err UNUSED)
 {
 	struct ref_formatting_stack *new_stack;
-	struct if_then_else *if_then_else = xcalloc(1,
-						    sizeof(struct if_then_else));
+	struct if_then_else *if_then_else = xcalloc(1, sizeof(*if_then_else));
 
 	if_then_else->str = atomv->atom->u.if_then_else.str;
 	if_then_else->cmp_status = atomv->atom->u.if_then_else.cmp_status;
@@ -1212,6 +1247,7 @@ static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state
 	new_stack = state->stack;
 	new_stack->at_end = if_then_else_handler;
 	new_stack->at_end_data = if_then_else;
+	new_stack->at_end_data_free = free;
 	return 0;
 }
 
@@ -1815,16 +1851,10 @@ static void find_subpos(const char *buf,
 			size_t *nonsiglen,
 			const char **sig, size_t *siglen)
 {
-	struct strbuf payload = STRBUF_INIT;
-	struct strbuf signature = STRBUF_INIT;
 	const char *eol;
 	const char *end = buf + strlen(buf);
 	const char *sigstart;
 
-	/* parse signature first; we might not even have a subject line */
-	parse_signature(buf, end - buf, &payload, &signature);
-	strbuf_release(&payload);
-
 	/* skip past header until we hit empty line */
 	while (*buf && *buf != '\n') {
 		eol = strchrnul(buf, '\n');
@@ -1835,8 +1865,10 @@ static void find_subpos(const char *buf,
 	/* skip any empty lines */
 	while (*buf == '\n')
 		buf++;
-	*sig = strbuf_detach(&signature, siglen);
+	/* parse signature first; we might not even have a subject line */
 	sigstart = buf + parse_signed_buffer(buf, strlen(buf));
+	*sig = sigstart;
+	*siglen = end - *sig;
 
 	/* subject is first non-empty line */
 	*sub = buf;
@@ -1911,7 +1943,7 @@ static void grab_describe_values(struct atom_value *val, int deref,
 
 		cmd.git_cmd = 1;
 		strvec_push(&cmd.args, "describe");
-		strvec_pushv(&cmd.args, atom->u.describe_args);
+		strvec_pushv(&cmd.args, atom->u.describe_args.v);
 		strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
 		if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) {
 			error(_("failed to run 'describe'"));
@@ -1994,16 +2026,23 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct exp
 			v->s = strbuf_detach(&s, NULL);
 		} else if (atom->u.contents.option == C_TRAILERS) {
 			struct strbuf s = STRBUF_INIT;
+			const char *msg;
+			char *to_free = NULL;
+
+			if (siglen)
+				msg = to_free = xmemdupz(subpos, sigpos - subpos);
+			else
+				msg = subpos;
 
 			/* Format the trailer info according to the trailer_opts given */
-			format_trailers_from_commit(&atom->u.contents.trailer_opts, subpos, &s);
+			format_trailers_from_commit(&atom->u.contents.trailer_opts, msg, &s);
+			free(to_free);
 
 			v->s = strbuf_detach(&s, NULL);
 		} else if (atom->u.contents.option == C_BARE)
 			v->s = xstrdup(subpos);
 
 	}
-	free((void *)sigpos);
 }
 
 /*
@@ -2142,7 +2181,7 @@ static const char *show_ref(struct refname_atom *atom, const char *refname)
 	if (atom->option == R_SHORT)
 		return refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
 						    refname,
-						    warn_ambiguous_refs);
+						    repo_settings_get_warn_ambiguous_refs(the_repository));
 	else if (atom->option == R_LSTRIP)
 		return lstrip_ref_components(refname, atom->lstrip);
 	else if (atom->option == R_RSTRIP)
@@ -2201,7 +2240,7 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
 		const char *merge;
 
 		merge = remote_ref_for_branch(branch, atom->u.remote_ref.push);
-		*s = xstrdup(merge ? merge : "");
+		*s = merge ? merge : xstrdup("");
 	} else
 		BUG("unhandled RR_* enum");
 }
@@ -2341,9 +2380,16 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 	int i;
 	struct object_info empty = OBJECT_INFO_INIT;
 	int ahead_behind_atoms = 0;
+	int is_base_atoms = 0;
 
 	CALLOC_ARRAY(ref->value, used_atom_cnt);
 
+	/**
+	 * NEEDSWORK: The following code might be unnecessary if all codepaths
+	 * that call populate_value() populates the symref member of ref_array_item
+	 * like in apply_ref_filter(). Currently pretty_print_ref() is the only codepath
+	 * that calls populate_value() without first populating symref.
+	 */
 	if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
 		ref->symref = refs_resolve_refdup(get_main_ref_store(the_repository),
 						  ref->refname,
@@ -2484,6 +2530,15 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 				v->s = xstrdup("");
 			}
 			continue;
+		} else if (atom_type == ATOM_ISBASE) {
+			if (ref->is_base && ref->is_base[is_base_atoms]) {
+				v->s = xstrfmt("(%s)", ref->is_base[is_base_atoms]);
+				free(ref->is_base[is_base_atoms]);
+			} else {
+				v->s = xstrdup("");
+			}
+			is_base_atoms++;
+			continue;
 		} else
 			continue;
 
@@ -2784,7 +2839,7 @@ static int filter_ref_kind(struct ref_filter *filter, const char *refname)
 	return ref_kind_from_refname(refname);
 }
 
-static struct ref_array_item *apply_ref_filter(const char *refname, const struct object_id *oid,
+static struct ref_array_item *apply_ref_filter(const char *refname, const char *referent, const struct object_id *oid,
 			    int flag, struct ref_filter *filter)
 {
 	struct ref_array_item *ref;
@@ -2853,6 +2908,7 @@ static struct ref_array_item *apply_ref_filter(const char *refname, const struct
 	ref->commit = commit;
 	ref->flag = flag;
 	ref->kind = kind;
+	ref->symref = xstrdup_or_null(referent);
 
 	return ref;
 }
@@ -2866,12 +2922,12 @@ struct ref_filter_cbdata {
  * A call-back given to for_each_ref().  Filter refs and keep them for
  * later object processing.
  */
-static int filter_one(const char *refname, const struct object_id *oid, int flag, void *cb_data)
+static int filter_one(const char *refname, const char *referent, const struct object_id *oid, int flag, void *cb_data)
 {
 	struct ref_filter_cbdata *ref_cbdata = cb_data;
 	struct ref_array_item *ref;
 
-	ref = apply_ref_filter(refname, oid, flag, ref_cbdata->filter);
+	ref = apply_ref_filter(refname, referent, oid, flag, ref_cbdata->filter);
 	if (ref)
 		ref_array_append(ref_cbdata->array, ref);
 
@@ -2889,6 +2945,7 @@ static void free_array_item(struct ref_array_item *item)
 		free(item->value);
 	}
 	free(item->counts);
+	free(item->is_base);
 	free(item);
 }
 
@@ -2901,13 +2958,13 @@ struct ref_filter_and_format_cbdata {
 	} internal;
 };
 
-static int filter_and_format_one(const char *refname, const struct object_id *oid, int flag, void *cb_data)
+static int filter_and_format_one(const char *refname, const char *referent, const struct object_id *oid, int flag, void *cb_data)
 {
 	struct ref_filter_and_format_cbdata *ref_cbdata = cb_data;
 	struct ref_array_item *ref;
 	struct strbuf output = STRBUF_INIT, err = STRBUF_INIT;
 
-	ref = apply_ref_filter(refname, oid, flag, ref_cbdata->filter);
+	ref = apply_ref_filter(refname, referent, oid, flag, ref_cbdata->filter);
 	if (!ref)
 		return 0;
 
@@ -2949,6 +3006,19 @@ void ref_array_clear(struct ref_array *array)
 		struct used_atom *atom = &used_atom[i];
 		if (atom->atom_type == ATOM_HEAD)
 			free(atom->u.head);
+		else if (atom->atom_type == ATOM_DESCRIBE)
+			strvec_clear(&atom->u.describe_args);
+		else if (atom->atom_type == ATOM_TRAILERS ||
+			 (atom->atom_type == ATOM_CONTENTS &&
+			  atom->u.contents.option == C_TRAILERS)) {
+			struct ref_trailer_buf *tb = atom->u.contents.trailer_buf;
+			if (tb) {
+				string_list_clear(&tb->filter_list, 0);
+				strbuf_release(&tb->sepbuf);
+				strbuf_release(&tb->kvsepbuf);
+				free(tb);
+			}
+		}
 		free((char *)atom->name);
 	}
 	FREE_AND_NULL(used_atom);
@@ -3053,6 +3123,49 @@ void filter_ahead_behind(struct repository *r,
 	free(commits);
 }
 
+void filter_is_base(struct repository *r,
+		    struct ref_format *format,
+		    struct ref_array *array)
+{
+	struct commit **bases;
+	size_t bases_nr = 0;
+	struct ref_array_item **back_index;
+
+	if (!format->is_base_tips.nr || !array->nr)
+		return;
+
+	CALLOC_ARRAY(back_index, array->nr);
+	CALLOC_ARRAY(bases, array->nr);
+
+	for (size_t i = 0; i < array->nr; i++) {
+		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);
+
+		if (!c)
+			continue;
+
+		back_index[bases_nr] = array->items[i];
+		bases[bases_nr] = c;
+		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);
+
+		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);
+	}
+
+	free(back_index);
+	free(bases);
+}
+
 static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref_fn fn, void *cb_data)
 {
 	int ret = 0;
@@ -3146,7 +3259,8 @@ static inline int can_do_iterative_format(struct ref_filter *filter,
 	return !(filter->reachable_from ||
 		 filter->unreachable_from ||
 		 sorting ||
-		 format->bases.nr);
+		 format->bases.nr ||
+		 format->is_base_tips.nr);
 }
 
 void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
@@ -3170,6 +3284,7 @@ void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
 		struct ref_array array = { 0 };
 		filter_refs(&array, filter, type);
 		filter_ahead_behind(the_repository, format, &array);
+		filter_is_base(the_repository, format, &array);
 		ref_array_sort(sorting, &array);
 		print_formatted_ref_array(&array, format);
 		ref_array_clear(&array);
@@ -3509,3 +3624,16 @@ 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 27ae1aa..754038a 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -48,6 +48,7 @@ struct ref_array_item {
 	struct commit *commit;
 	struct atom_value *value;
 	struct ahead_behind_count **counts;
+	char **is_base;
 
 	char refname[FLEX_ARRAY];
 };
@@ -101,6 +102,9 @@ struct ref_format {
 	/* 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;
@@ -114,6 +118,7 @@ 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 */
@@ -203,7 +208,20 @@ void filter_ahead_behind(struct repository *r,
 			 struct ref_format *format,
 			 struct ref_array *array);
 
+/*
+ * If the provided format includes is-base atoms, then compute the base checks
+ * for those tips against all refs.
+ *
+ * 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/reflog.c b/reflog.c
index eeccd5f..875ac1a 100644
--- a/reflog.c
+++ b/reflog.c
@@ -300,6 +300,7 @@ int should_expire_reflog_ent_verbose(struct object_id *ooid,
 }
 
 static int push_tip_to_list(const char *refname UNUSED,
+			    const char *referent UNUSED,
 			    const struct object_id *oid,
 			    int flags, void *cb_data)
 {
diff --git a/refs.c b/refs.c
index 915aeb4..5f729ed 100644
--- a/refs.c
+++ b/refs.c
@@ -24,7 +24,7 @@
 #include "submodule.h"
 #include "worktree.h"
 #include "strvec.h"
-#include "repository.h"
+#include "repo-settings.h"
 #include "setup.h"
 #include "sigchain.h"
 #include "date.h"
@@ -318,6 +318,11 @@ int check_refname_format(const char *refname, int flags)
 	return check_or_sanitize_refname(refname, flags, NULL);
 }
 
+int refs_fsck(struct ref_store *refs, struct fsck_options *o)
+{
+	return refs->be->fsck(refs, o);
+}
+
 void sanitize_refname_component(const char *refname, struct strbuf *out)
 {
 	if (check_or_sanitize_refname(refname, REFNAME_ALLOW_ONELEVEL, out))
@@ -414,7 +419,7 @@ int refs_ref_exists(struct ref_store *refs, const char *refname)
 					 NULL, NULL);
 }
 
-static int for_each_filter_refs(const char *refname,
+static int for_each_filter_refs(const char *refname, const char *referent,
 				const struct object_id *oid,
 				int flags, void *data)
 {
@@ -424,7 +429,7 @@ static int for_each_filter_refs(const char *refname,
 		return 0;
 	if (filter->prefix)
 		skip_prefix(refname, filter->prefix, &refname);
-	return filter->fn(refname, oid, flags, filter->cb_data);
+	return filter->fn(refname, referent, oid, flags, filter->cb_data);
 }
 
 struct warn_if_dangling_data {
@@ -435,7 +440,7 @@ struct warn_if_dangling_data {
 	const char *msg_fmt;
 };
 
-static int warn_if_dangling_symref(const char *refname,
+static int warn_if_dangling_symref(const char *refname, const char *referent UNUSED,
 				   const struct object_id *oid UNUSED,
 				   int flags, void *cb_data)
 {
@@ -506,7 +511,7 @@ int refs_head_ref_namespaced(struct ref_store *refs, each_ref_fn fn, void *cb_da
 
 	strbuf_addf(&buf, "%sHEAD", get_git_namespace());
 	if (!refs_read_ref_full(refs, buf.buf, RESOLVE_REF_READING, &oid, &flag))
-		ret = fn(buf.buf, &oid, flag, cb_data);
+		ret = fn(buf.buf, NULL, &oid, flag, cb_data);
 	strbuf_release(&buf);
 
 	return ret;
@@ -725,7 +730,7 @@ int expand_ref(struct repository *repo, const char *str, int len,
 		if (r) {
 			if (!refs_found++)
 				*ref = xstrdup(r);
-			if (!warn_ambiguous_refs)
+			if (!repo_settings_get_warn_ambiguous_refs(repo))
 				break;
 		} else if ((flag & REF_ISSYMREF) && strcmp(fullref.buf, "HEAD")) {
 			warning(_("ignoring dangling symref %s"), fullref.buf);
@@ -770,7 +775,7 @@ int repo_dwim_log(struct repository *r, const char *str, int len,
 			if (oid)
 				oidcpy(oid, &hash);
 		}
-		if (!warn_ambiguous_refs)
+		if (!repo_settings_get_warn_ambiguous_refs(r))
 			break;
 	}
 	strbuf_release(&path);
@@ -953,7 +958,8 @@ static char *normalize_reflog_message(const char *msg)
 	return strbuf_detach(&sb, NULL);
 }
 
-int should_autocreate_reflog(const char *refname)
+int should_autocreate_reflog(enum log_refs_config log_all_ref_updates,
+			     const char *refname)
 {
 	switch (log_all_ref_updates) {
 	case LOG_REFS_ALWAYS:
@@ -1512,6 +1518,19 @@ const char **hidden_refs_to_excludes(const struct strvec *hide_refs)
 	return hide_refs->v;
 }
 
+const char **get_namespaced_exclude_patterns(const char **exclude_patterns,
+					     const char *namespace,
+					     struct strvec *out)
+{
+	if (!namespace || !*namespace || !exclude_patterns || !*exclude_patterns)
+		return exclude_patterns;
+
+	for (size_t i = 0; exclude_patterns[i]; i++)
+		strvec_pushf(out, "%s%s", namespace, exclude_patterns[i]);
+
+	return out->v;
+}
+
 const char *find_descendant_ref(const char *dirname,
 				const struct string_list *extras,
 				const struct string_list *skip)
@@ -1547,7 +1566,7 @@ int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
 
 	if (refs_resolve_ref_unsafe(refs, "HEAD", RESOLVE_REF_READING,
 				    &oid, &flag))
-		return fn("HEAD", &oid, flag, cb_data);
+		return fn("HEAD", NULL, &oid, flag, cb_data);
 
 	return 0;
 }
@@ -1629,11 +1648,19 @@ int refs_for_each_namespaced_ref(struct ref_store *refs,
 				 const char **exclude_patterns,
 				 each_ref_fn fn, void *cb_data)
 {
-	struct strbuf buf = STRBUF_INIT;
+	struct strvec namespaced_exclude_patterns = STRVEC_INIT;
+	struct strbuf prefix = STRBUF_INIT;
 	int ret;
-	strbuf_addf(&buf, "%srefs/", get_git_namespace());
-	ret = do_for_each_ref(refs, buf.buf, exclude_patterns, fn, 0, 0, cb_data);
-	strbuf_release(&buf);
+
+	exclude_patterns = get_namespaced_exclude_patterns(exclude_patterns,
+							   get_git_namespace(),
+							   &namespaced_exclude_patterns);
+
+	strbuf_addf(&prefix, "%srefs/", get_git_namespace());
+	ret = do_for_each_ref(refs, prefix.buf, exclude_patterns, fn, 0, 0, cb_data);
+
+	strvec_clear(&namespaced_exclude_patterns);
+	strbuf_release(&prefix);
 	return ret;
 }
 
@@ -1714,6 +1741,7 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
 				      const char **exclude_patterns,
 				      each_ref_fn fn, void *cb_data)
 {
+	struct strvec namespaced_exclude_patterns = STRVEC_INIT;
 	struct string_list prefixes = STRING_LIST_INIT_DUP;
 	struct string_list_item *prefix;
 	struct strbuf buf = STRBUF_INIT;
@@ -1725,6 +1753,10 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
 		strbuf_addstr(&buf, namespace);
 	namespace_len = buf.len;
 
+	exclude_patterns = get_namespaced_exclude_patterns(exclude_patterns,
+							   namespace,
+							   &namespaced_exclude_patterns);
+
 	for_each_string_list_item(prefix, &prefixes) {
 		strbuf_addstr(&buf, prefix->string);
 		ret = refs_for_each_fullref_in(ref_store, buf.buf,
@@ -1734,6 +1766,7 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
 		strbuf_setlen(&buf, namespace_len);
 	}
 
+	strvec_clear(&namespaced_exclude_patterns);
 	string_list_clear(&prefixes, 0);
 	strbuf_release(&buf);
 	return ret;
@@ -1754,8 +1787,8 @@ static int refs_read_special_head(struct ref_store *ref_store,
 		goto done;
 	}
 
-	result = parse_loose_ref_contents(content.buf, oid, referent, type,
-					  failure_errno);
+	result = parse_loose_ref_contents(ref_store->repo->hash_algo, content.buf,
+					  oid, referent, type, failure_errno);
 
 done:
 	strbuf_release(&full_path);
@@ -1838,7 +1871,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
 			    failure_errno != ENOTDIR)
 				return NULL;
 
-			oidclr(oid, the_repository->hash_algo);
+			oidclr(oid, refs->repo->hash_algo);
 			if (*flags & REF_BAD_NAME)
 				*flags |= REF_ISBROKEN;
 			return refname;
@@ -1848,7 +1881,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
 
 		if (!(read_flags & REF_ISSYMREF)) {
 			if (*flags & REF_BAD_NAME) {
-				oidclr(oid, the_repository->hash_algo);
+				oidclr(oid, refs->repo->hash_algo);
 				*flags |= REF_ISBROKEN;
 			}
 			return refname;
@@ -1856,7 +1889,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
 
 		refname = sb_refname.buf;
 		if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
-			oidclr(oid, the_repository->hash_algo);
+			oidclr(oid, refs->repo->hash_algo);
 			return refname;
 		}
 		if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
@@ -2011,7 +2044,7 @@ struct ref_store *repo_get_submodule_ref_store(struct repository *repo,
 		free(subrepo);
 		goto done;
 	}
-	refs = ref_store_init(subrepo, the_repository->ref_storage_format,
+	refs = ref_store_init(subrepo, subrepo->ref_storage_format,
 			      submodule_sb.buf,
 			      REF_STORE_READ | REF_STORE_ODB);
 	register_ref_store_map(&repo->submodule_ref_stores, "submodule",
@@ -2045,7 +2078,7 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt)
 				      common_path.buf, REF_STORE_ALL_CAPS);
 		strbuf_release(&common_path);
 	} else {
-		refs = ref_store_init(wt->repo, the_repository->ref_storage_format,
+		refs = ref_store_init(wt->repo, wt->repo->ref_storage_format,
 				      wt->repo->commondir, REF_STORE_ALL_CAPS);
 	}
 
@@ -2134,7 +2167,7 @@ static int run_transaction_hook(struct ref_transaction *transaction,
 	const char *hook;
 	int ret = 0, i;
 
-	hook = find_hook("reference-transaction");
+	hook = find_hook(transaction->ref_store->repo, "reference-transaction");
 	if (!hook)
 		return ret;
 
@@ -2388,8 +2421,9 @@ struct do_for_each_reflog_help {
 };
 
 static int do_for_each_reflog_helper(const char *refname,
+				     const char *referent UNUSED,
 				     const struct object_id *oid UNUSED,
-				     int flags,
+				     int flags UNUSED,
 				     void *cb_data)
 {
 	struct do_for_each_reflog_help *hp = cb_data;
@@ -2593,7 +2627,7 @@ struct migration_data {
 	struct strbuf *errbuf;
 };
 
-static int migrate_one_ref(const char *refname, const struct object_id *oid,
+static int migrate_one_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			   int flags, void *cb_data)
 {
 	struct migration_data *data = cb_data;
diff --git a/refs.h b/refs.h
index b3e39bc..108dfc9 100644
--- a/refs.h
+++ b/refs.h
@@ -3,7 +3,9 @@
 
 #include "commit.h"
 #include "repository.h"
+#include "repo-settings.h"
 
+struct fsck_options;
 struct object_id;
 struct ref_store;
 struct strbuf;
@@ -15,7 +17,7 @@ enum ref_storage_format ref_storage_format_by_name(const char *name);
 const char *ref_storage_format_to_name(enum ref_storage_format ref_storage_format);
 
 /*
- * Resolve a reference, recursively following symbolic refererences.
+ * Resolve a reference, recursively following symbolic references.
  *
  * Return the name of the non-symbolic reference that ultimately pointed
  * at the resolved object name.  The return value, if not NULL, is a
@@ -110,7 +112,8 @@ int refs_verify_refname_available(struct ref_store *refs,
 
 int refs_ref_exists(struct ref_store *refs, const char *refname);
 
-int should_autocreate_reflog(const char *refname);
+int should_autocreate_reflog(enum log_refs_config log_all_ref_updates,
+			     const char *refname);
 
 int is_branch(const char *refname);
 
@@ -298,7 +301,7 @@ struct ref_transaction;
  * arguments is only guaranteed to be valid for the duration of a
  * single callback invocation.
  */
-typedef int each_ref_fn(const char *refname,
+typedef int each_ref_fn(const char *refname, const char *referent,
 			const struct object_id *oid, int flags, void *cb_data);
 
 /*
@@ -487,7 +490,7 @@ int refs_delete_reflog(struct ref_store *refs, const char *refname);
  * from UTC.  Its absolute value is formed by multiplying the hour
  * part by 100 and adding the minute part.  For example, 1 hour ahead
  * of UTC, CET == "+0100", is represented as positive one hundred (not
- * postiive sixty).
+ * positive sixty).
  *
  * The msg parameter is a single complete line; a reflog message given
  * to refs_delete_ref, refs_update_ref, etc. is returned to the
@@ -542,6 +545,13 @@ int refs_for_each_reflog(struct ref_store *refs, each_reflog_fn fn, void *cb_dat
 int check_refname_format(const char *refname, int flags);
 
 /*
+ * Check the reference database for consistency. Return 0 if refs and
+ * reflogs are consistent, and non-zero otherwise. The errors will be
+ * written to stderr.
+ */
+int refs_fsck(struct ref_store *refs, struct fsck_options *o);
+
+/*
  * Apply the rules from check_refname_format, but mutate the result until it
  * is acceptable, and place the result in "out".
  */
@@ -851,6 +861,15 @@ int ref_is_hidden(const char *, const char *, const struct strvec *);
  */
 const char **hidden_refs_to_excludes(const struct strvec *hide_refs);
 
+/*
+ * Prefix all exclude patterns with the namespace, if any. This is required
+ * because exclude patterns apply to the stripped reference name, not the full
+ * reference name with the namespace.
+ */
+const char **get_namespaced_exclude_patterns(const char **exclude_patterns,
+					     const char *namespace,
+					     struct strvec *out);
+
 /* Is this a per-worktree ref living in the refs/ namespace? */
 int is_per_worktree_ref(const char *refname);
 
@@ -978,7 +997,7 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt);
 
 /*
  * Some of the names specified by refs have special meaning to Git.
- * Organize these namespaces in a comon 'ref_namespace' array for
+ * Organize these namespaces in a common 'ref_namespace' array for
  * reference from multiple places in the codebase.
  */
 
@@ -1086,211 +1105,4 @@ int repo_migrate_ref_storage_format(struct repository *repo,
 				    unsigned int flags,
 				    struct strbuf *err);
 
-/*
- * The following functions have been removed in Git v2.46 in favor of functions
- * that receive a `ref_store` as parameter. The intent of this section is
- * merely to help patch authors of in-flight series to have a reference what
- * they should be migrating to. The section will be removed in Git v2.47.
- */
-#if 0
-static char *resolve_refdup(const char *refname, int resolve_flags,
-			    struct object_id *oid, int *flags)
-{
-	return refs_resolve_refdup(get_main_ref_store(the_repository),
-				   refname, resolve_flags,
-				   oid, flags);
-}
-
-static int read_ref_full(const char *refname, int resolve_flags,
-			 struct object_id *oid, int *flags)
-{
-	return refs_read_ref_full(get_main_ref_store(the_repository), refname,
-				  resolve_flags, oid, flags);
-}
-
-static int read_ref(const char *refname, struct object_id *oid)
-{
-	return refs_read_ref(get_main_ref_store(the_repository), refname, oid);
-}
-
-static int ref_exists(const char *refname)
-{
-	return refs_ref_exists(get_main_ref_store(the_repository), refname);
-}
-
-static int for_each_tag_ref(each_ref_fn fn, void *cb_data)
-{
-	return refs_for_each_tag_ref(get_main_ref_store(the_repository), fn, cb_data);
-}
-
-static int for_each_branch_ref(each_ref_fn fn, void *cb_data)
-{
-	return refs_for_each_branch_ref(get_main_ref_store(the_repository), fn, cb_data);
-}
-
-static int for_each_remote_ref(each_ref_fn fn, void *cb_data)
-{
-	return refs_for_each_remote_ref(get_main_ref_store(the_repository), fn, cb_data);
-}
-
-static int head_ref_namespaced(each_ref_fn fn, void *cb_data)
-{
-	return refs_head_ref_namespaced(get_main_ref_store(the_repository),
-					fn, cb_data);
-}
-
-static int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
-				const char *prefix, void *cb_data)
-{
-	return refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
-					 fn, pattern, prefix, cb_data);
-}
-
-static int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)
-{
-	return refs_for_each_glob_ref(get_main_ref_store(the_repository),
-				      fn, pattern, cb_data);
-}
-
-static int delete_ref(const char *msg, const char *refname,
-		      const struct object_id *old_oid, unsigned int flags)
-{
-	return refs_delete_ref(get_main_ref_store(the_repository), msg, refname,
-			       old_oid, flags);
-}
-
-static struct ref_transaction *ref_transaction_begin(struct strbuf *err)
-{
-	return ref_store_transaction_begin(get_main_ref_store(the_repository), err);
-}
-
-static int update_ref(const char *msg, const char *refname,
-		      const struct object_id *new_oid,
-		      const struct object_id *old_oid,
-		      unsigned int flags, enum action_on_err onerr)
-{
-	return refs_update_ref(get_main_ref_store(the_repository), msg, refname, new_oid,
-			       old_oid, flags, onerr);
-}
-
-static char *shorten_unambiguous_ref(const char *refname, int strict)
-{
-	return refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
-					    refname, strict);
-}
-
-static int head_ref(each_ref_fn fn, void *cb_data)
-{
-	return refs_head_ref(get_main_ref_store(the_repository), fn, cb_data);
-}
-
-static int for_each_ref(each_ref_fn fn, void *cb_data)
-{
-	return refs_for_each_ref(get_main_ref_store(the_repository), fn, cb_data);
-}
-
-static int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
-{
-	return refs_for_each_ref_in(get_main_ref_store(the_repository), prefix, fn, cb_data);
-}
-
-static int for_each_fullref_in(const char *prefix,
-			       const char **exclude_patterns,
-			       each_ref_fn fn, void *cb_data)
-{
-	return refs_for_each_fullref_in(get_main_ref_store(the_repository),
-					prefix, exclude_patterns, fn, cb_data);
-}
-
-static int for_each_namespaced_ref(const char **exclude_patterns,
-				   each_ref_fn fn, void *cb_data)
-{
-	return refs_for_each_namespaced_ref(get_main_ref_store(the_repository),
-					    exclude_patterns, fn, cb_data);
-}
-
-static int for_each_rawref(each_ref_fn fn, void *cb_data)
-{
-	return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data);
-}
-
-static const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
-				      struct object_id *oid, int *flags)
-{
-	return refs_resolve_ref_unsafe(get_main_ref_store(the_repository), refname,
-				       resolve_flags, oid, flags);
-}
-
-static int create_symref(const char *ref_target, const char *refs_heads_master,
-			 const char *logmsg)
-{
-	return refs_create_symref(get_main_ref_store(the_repository), ref_target,
-				  refs_heads_master, logmsg);
-}
-
-static int for_each_reflog(each_reflog_fn fn, void *cb_data)
-{
-	return refs_for_each_reflog(get_main_ref_store(the_repository), fn, cb_data);
-}
-
-static int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn,
-				       void *cb_data)
-{
-	return refs_for_each_reflog_ent_reverse(get_main_ref_store(the_repository),
-						refname, fn, cb_data);
-}
-
-static int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn,
-			       void *cb_data)
-{
-	return refs_for_each_reflog_ent(get_main_ref_store(the_repository), refname,
-					fn, cb_data);
-}
-
-static int reflog_exists(const char *refname)
-{
-	return refs_reflog_exists(get_main_ref_store(the_repository), refname);
-}
-
-static int safe_create_reflog(const char *refname, struct strbuf *err)
-{
-	return refs_create_reflog(get_main_ref_store(the_repository), refname,
-				  err);
-}
-
-static int delete_reflog(const char *refname)
-{
-	return refs_delete_reflog(get_main_ref_store(the_repository), refname);
-}
-
-static int reflog_expire(const char *refname,
-			 unsigned int flags,
-			 reflog_expiry_prepare_fn prepare_fn,
-			 reflog_expiry_should_prune_fn should_prune_fn,
-			 reflog_expiry_cleanup_fn cleanup_fn,
-			 void *policy_cb_data)
-{
-	return refs_reflog_expire(get_main_ref_store(the_repository),
-				  refname, flags,
-				  prepare_fn, should_prune_fn,
-				  cleanup_fn, policy_cb_data);
-}
-
-static int delete_refs(const char *msg, struct string_list *refnames,
-		       unsigned int flags)
-{
-	return refs_delete_refs(get_main_ref_store(the_repository), msg, refnames, flags);
-}
-
-static int rename_ref(const char *oldref, const char *newref, const char *logmsg)
-{
-	return refs_rename_ref(get_main_ref_store(the_repository), oldref, newref, logmsg);
-}
-
-static int copy_existing_ref(const char *oldref, const char *newref, const char *logmsg)
-{
-	return refs_copy_existing_ref(get_main_ref_store(the_repository), oldref, newref, logmsg);
-}
-#endif
-
 #endif /* REFS_H */
diff --git a/refs/debug.c b/refs/debug.c
index 547d924..45e2e78 100644
--- a/refs/debug.c
+++ b/refs/debug.c
@@ -419,6 +419,15 @@ static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,
 	return res;
 }
 
+static int debug_fsck(struct ref_store *ref_store,
+		      struct fsck_options *o)
+{
+	struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
+	int res = drefs->refs->be->fsck(drefs->refs, o);
+	trace_printf_key(&trace_refs, "fsck: %d\n", res);
+	return res;
+}
+
 struct ref_storage_be refs_be_debug = {
 	.name = "debug",
 	.init = NULL,
@@ -451,4 +460,6 @@ struct ref_storage_be refs_be_debug = {
 	.create_reflog = debug_create_reflog,
 	.delete_reflog = debug_delete_reflog,
 	.reflog_expire = debug_reflog_expire,
+
+	.fsck = debug_fsck,
 };
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 11551de..0824c0b 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1,12 +1,15 @@
 #define USE_THE_REPOSITORY_VARIABLE
 
 #include "../git-compat-util.h"
+#include "../config.h"
 #include "../copy.h"
 #include "../environment.h"
 #include "../gettext.h"
 #include "../hash.h"
 #include "../hex.h"
+#include "../fsck.h"
 #include "../refs.h"
+#include "../repo-settings.h"
 #include "refs-internal.h"
 #include "ref-cache.h"
 #include "packed-backend.h"
@@ -73,6 +76,8 @@ struct files_ref_store {
 	unsigned int store_flags;
 
 	char *gitcommondir;
+	enum log_refs_config log_all_ref_updates;
+	int prefer_symlink_refs;
 
 	struct ref_cache *loose;
 
@@ -105,6 +110,8 @@ static struct ref_store *files_ref_store_init(struct repository *repo,
 	refs->gitcommondir = strbuf_detach(&sb, NULL);
 	refs->packed_ref_store =
 		packed_ref_store_init(repo, refs->gitcommondir, flags);
+	refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
+	repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
 
 	chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
 	chdir_notify_reparent("files-backend $GIT_COMMONDIR",
@@ -246,10 +253,13 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
 {
 	struct object_id oid;
 	int flag;
+	const char *referent = refs_resolve_ref_unsafe(&refs->base,
+						       refname,
+						       RESOLVE_REF_READING,
+						       &oid, &flag);
 
-	if (!refs_resolve_ref_unsafe(&refs->base, refname, RESOLVE_REF_READING,
-				     &oid, &flag)) {
-		oidclr(&oid, the_repository->hash_algo);
+	if (!referent) {
+		oidclr(&oid, refs->base.repo->hash_algo);
 		flag |= REF_ISBROKEN;
 	} else if (is_null_oid(&oid)) {
 		/*
@@ -266,10 +276,14 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
 	if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
 		if (!refname_is_safe(refname))
 			die("loose refname is dangerous: %s", refname);
-		oidclr(&oid, the_repository->hash_algo);
+		oidclr(&oid, refs->base.repo->hash_algo);
 		flag |= REF_BAD_NAME | REF_ISBROKEN;
 	}
-	add_entry_to_dir(dir, create_ref_entry(refname, &oid, flag));
+
+	if (!(flag & REF_ISSYMREF))
+		referent = NULL;
+
+	add_entry_to_dir(dir, create_ref_entry(refname, referent, &oid, flag));
 }
 
 /*
@@ -553,7 +567,8 @@ static int read_ref_internal(struct ref_store *ref_store, const char *refname,
 	strbuf_rtrim(&sb_contents);
 	buf = sb_contents.buf;
 
-	ret = parse_loose_ref_contents(buf, oid, referent, type, &myerr);
+	ret = parse_loose_ref_contents(ref_store->repo->hash_algo, buf,
+				       oid, referent, type, &myerr);
 
 out:
 	if (ret && !myerr)
@@ -587,7 +602,8 @@ static int files_read_symbolic_ref(struct ref_store *ref_store, const char *refn
 	return !(type & REF_ISSYMREF);
 }
 
-int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+int parse_loose_ref_contents(const struct git_hash_algo *algop,
+			     const char *buf, struct object_id *oid,
 			     struct strbuf *referent, unsigned int *type,
 			     int *failure_errno)
 {
@@ -605,7 +621,7 @@ int parse_loose_ref_contents(const char *buf, struct object_id *oid,
 	/*
 	 * FETCH_HEAD has additional data after the sha.
 	 */
-	if (parse_oid_hex(buf, oid, &p) ||
+	if (parse_oid_hex_algop(buf, oid, &p, algop) ||
 	    (*p != '\0' && !isspace(*p))) {
 		*type |= REF_ISBROKEN;
 		*failure_errno = EINVAL;
@@ -887,6 +903,8 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		iter->base.refname = iter->iter0->refname;
 		iter->base.oid = iter->iter0->oid;
 		iter->base.flags = iter->iter0->flags;
+		iter->base.referent = iter->iter0->referent;
+
 		return ITER_OK;
 	}
 
@@ -1153,7 +1171,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
 
 	if (!refs_resolve_ref_unsafe(&refs->base, lock->ref_name, 0,
 				     &lock->old_oid, NULL))
-		oidclr(&lock->old_oid, the_repository->hash_algo);
+		oidclr(&lock->old_oid, refs->base.repo->hash_algo);
 	goto out;
 
  error_return:
@@ -1301,6 +1319,68 @@ static int should_pack_ref(struct files_ref_store *refs,
 	return 0;
 }
 
+static int should_pack_refs(struct files_ref_store *refs,
+			    struct pack_refs_opts *opts)
+{
+	struct ref_iterator *iter;
+	size_t packed_size;
+	size_t refcount = 0;
+	size_t limit;
+	int ret;
+
+	if (!(opts->flags & PACK_REFS_AUTO))
+		return 1;
+
+	ret = packed_refs_size(refs->packed_ref_store, &packed_size);
+	if (ret < 0)
+		die("cannot determine packed-refs size");
+
+	/*
+	 * Packing loose references into the packed-refs file scales with the
+	 * number of references we're about to write. We thus decide whether we
+	 * repack refs by weighing the current size of the packed-refs file
+	 * against the number of loose references. This is done such that we do
+	 * not repack too often on repositories with a huge number of
+	 * references, where we can expect a lot of churn in the number of
+	 * references.
+	 *
+	 * As a heuristic, we repack if the number of loose references in the
+	 * repository exceeds `log2(nr_packed_refs) * 5`, where we estimate
+	 * `nr_packed_refs = packed_size / 100`, which scales as following:
+	 *
+	 * - 1kB ~ 10 packed refs: 16 refs
+	 * - 10kB ~ 100 packed refs: 33 refs
+	 * - 100kB ~ 1k packed refs: 49 refs
+	 * - 1MB ~ 10k packed refs: 66 refs
+	 * - 10MB ~ 100k packed refs: 82 refs
+	 * - 100MB ~ 1m packed refs: 99 refs
+	 *
+	 * We thus allow roughly 16 additional loose refs per factor of ten of
+	 * packed refs. This heuristic may be tweaked in the future, but should
+	 * serve as a sufficiently good first iteration.
+	 */
+	limit = log2u(packed_size / 100) * 5;
+	if (limit < 16)
+		limit = 16;
+
+	iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
+					refs->base.repo, 0);
+	while ((ret = ref_iterator_advance(iter)) == ITER_OK) {
+		if (should_pack_ref(refs, iter->refname, iter->oid,
+				    iter->flags, opts))
+			refcount++;
+		if (refcount >= limit) {
+			ref_iterator_abort(iter);
+			return 1;
+		}
+	}
+
+	if (ret != ITER_DONE)
+		die("error while iterating over references");
+
+	return 0;
+}
+
 static int files_pack_refs(struct ref_store *ref_store,
 			   struct pack_refs_opts *opts)
 {
@@ -1313,6 +1393,9 @@ static int files_pack_refs(struct ref_store *ref_store,
 	struct strbuf err = STRBUF_INIT;
 	struct ref_transaction *transaction;
 
+	if (!should_pack_refs(refs, opts))
+		return 0;
+
 	transaction = ref_store_transaction_begin(refs->packed_ref_store, &err);
 	if (!transaction)
 		return -1;
@@ -1431,6 +1514,7 @@ static int write_ref_to_lockfile(struct files_ref_store *refs,
 static int commit_ref_update(struct files_ref_store *refs,
 			     struct ref_lock *lock,
 			     const struct object_id *oid, const char *logmsg,
+			     int flags,
 			     struct strbuf *err);
 
 /*
@@ -1574,7 +1658,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
 	oidcpy(&lock->old_oid, &orig_oid);
 
 	if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
-	    commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {
+	    commit_ref_update(refs, lock, &orig_oid, logmsg, 0, &err)) {
 		error("unable to write current sha1 into %s: %s", newrefname, err.buf);
 		strbuf_release(&err);
 		goto rollback;
@@ -1591,14 +1675,11 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
 		goto rollbacklog;
 	}
 
-	flag = log_all_ref_updates;
-	log_all_ref_updates = LOG_REFS_NONE;
 	if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
-	    commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {
+	    commit_ref_update(refs, lock, &orig_oid, NULL, REF_SKIP_CREATE_REFLOG, &err)) {
 		error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
 		strbuf_release(&err);
 	}
-	log_all_ref_updates = flag;
 
  rollbacklog:
 	if (logmoved && rename(sb_newref.buf, sb_oldref.buf))
@@ -1693,13 +1774,17 @@ static int log_ref_setup(struct files_ref_store *refs,
 			 const char *refname, int force_create,
 			 int *logfd, struct strbuf *err)
 {
+	enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
 	struct strbuf logfile_sb = STRBUF_INIT;
 	char *logfile;
 
+	if (log_refs_cfg == LOG_REFS_UNSET)
+		log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+
 	files_reflog_path(refs, &logfile_sb, refname);
 	logfile = strbuf_detach(&logfile_sb, NULL);
 
-	if (force_create || should_autocreate_reflog(refname)) {
+	if (force_create || should_autocreate_reflog(log_refs_cfg, refname)) {
 		if (raceproof_create_file(logfile, open_or_create_logfile, logfd)) {
 			if (errno == ENOENT)
 				strbuf_addf(err, "unable to create directory for '%s': "
@@ -1788,9 +1873,6 @@ static int files_log_ref_write(struct files_ref_store *refs,
 	if (flags & REF_SKIP_CREATE_REFLOG)
 		return 0;
 
-	if (log_all_ref_updates == LOG_REFS_UNSET)
-		log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
-
 	result = log_ref_setup(refs, refname,
 			       flags & REF_FORCE_CREATE_REFLOG,
 			       &logfd, err);
@@ -1879,6 +1961,7 @@ static int write_ref_to_lockfile(struct files_ref_store *refs,
 static int commit_ref_update(struct files_ref_store *refs,
 			     struct ref_lock *lock,
 			     const struct object_id *oid, const char *logmsg,
+			     int flags,
 			     struct strbuf *err)
 {
 	files_assert_main_repository(refs, "commit_ref_update");
@@ -1886,7 +1969,7 @@ static int commit_ref_update(struct files_ref_store *refs,
 	clear_loose_ref_cache(refs);
 	if (files_log_ref_write(refs, lock->ref_name,
 				&lock->old_oid, oid,
-				logmsg, 0, err)) {
+				logmsg, flags, err)) {
 		char *old_msg = strbuf_detach(err, NULL);
 		strbuf_addf(err, "cannot update the ref '%s': %s",
 			    lock->ref_name, old_msg);
@@ -1919,7 +2002,7 @@ static int commit_ref_update(struct files_ref_store *refs,
 			struct strbuf log_err = STRBUF_INIT;
 			if (files_log_ref_write(refs, "HEAD",
 						&lock->old_oid, oid,
-						logmsg, 0, &log_err)) {
+						logmsg, flags, &log_err)) {
 				error("%s", log_err.buf);
 				strbuf_release(&log_err);
 			}
@@ -1936,10 +2019,13 @@ static int commit_ref_update(struct files_ref_store *refs,
 	return 0;
 }
 
+#ifdef NO_SYMLINK_HEAD
+#define create_ref_symlink(a, b) (-1)
+#else
 static int create_ref_symlink(struct ref_lock *lock, const char *target)
 {
 	int ret = -1;
-#ifndef NO_SYMLINK_HEAD
+
 	char *ref_path = get_locked_file_path(&lock->lk);
 	unlink(ref_path);
 	ret = symlink(target, ref_path);
@@ -1947,13 +2033,12 @@ static int create_ref_symlink(struct ref_lock *lock, const char *target)
 
 	if (ret)
 		fprintf(stderr, "no symlink - falling back to symbolic ref\n");
-#endif
 	return ret;
 }
+#endif
 
-static int create_symref_lock(struct files_ref_store *refs,
-			      struct ref_lock *lock, const char *refname,
-			      const char *target, struct strbuf *err)
+static int create_symref_lock(struct ref_lock *lock, const char *target,
+			      struct strbuf *err)
 {
 	if (!fdopen_lock_file(&lock->lk, "w")) {
 		strbuf_addf(err, "unable to fdopen %s: %s",
@@ -1999,7 +2084,8 @@ static int files_delete_reflog(struct ref_store *ref_store,
 	return ret;
 }
 
-static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *cb_data)
+static int show_one_reflog_ent(struct files_ref_store *refs, struct strbuf *sb,
+			       each_reflog_ent_fn fn, void *cb_data)
 {
 	struct object_id ooid, noid;
 	char *email_end, *message;
@@ -2009,8 +2095,8 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c
 
 	/* old SP new SP name <email> SP time TAB msg LF */
 	if (!sb->len || sb->buf[sb->len - 1] != '\n' ||
-	    parse_oid_hex(p, &ooid, &p) || *p++ != ' ' ||
-	    parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||
+	    parse_oid_hex_algop(p, &ooid, &p, refs->base.repo->hash_algo) || *p++ != ' ' ||
+	    parse_oid_hex_algop(p, &noid, &p, refs->base.repo->hash_algo) || *p++ != ' ' ||
 	    !(email_end = strchr(p, '>')) ||
 	    email_end[1] != ' ' ||
 	    !(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||
@@ -2109,7 +2195,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
 				strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
 				scanp = bp;
 				endp = bp + 1;
-				ret = show_one_reflog_ent(&sb, fn, cb_data);
+				ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
 				strbuf_reset(&sb);
 				if (ret)
 					break;
@@ -2121,7 +2207,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
 				 * Process it, and we can end the loop.
 				 */
 				strbuf_splice(&sb, 0, 0, buf, endp - buf);
-				ret = show_one_reflog_ent(&sb, fn, cb_data);
+				ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
 				strbuf_reset(&sb);
 				break;
 			}
@@ -2171,7 +2257,7 @@ static int files_for_each_reflog_ent(struct ref_store *ref_store,
 		return -1;
 
 	while (!ret && !strbuf_getwholeline(&sb, logfp, '\n'))
-		ret = show_one_reflog_ent(&sb, fn, cb_data);
+		ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
 	fclose(logfp);
 	strbuf_release(&sb);
 	return ret;
@@ -2568,8 +2654,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
 	}
 
 	if (update->new_target && !(update->flags & REF_LOG_ONLY)) {
-		if (create_symref_lock(refs, lock, update->refname,
-				       update->new_target, err)) {
+		if (create_symref_lock(lock, update->new_target, err)) {
 			ret = TRANSACTION_GENERIC_ERROR;
 			goto out;
 		}
@@ -2928,7 +3013,7 @@ static int files_transaction_finish(struct ref_store *ref_store,
 		 * We try creating a symlink, if that succeeds we continue to the
 		 * next update. If not, we try and create a regular symref.
 		 */
-		if (update->new_target && prefer_symlink_refs)
+		if (update->new_target && refs->prefer_symlink_refs)
 			if (!create_ref_symlink(lock, update->new_target))
 				continue;
 
@@ -3036,7 +3121,7 @@ static int files_transaction_abort(struct ref_store *ref_store,
 	return 0;
 }
 
-static int ref_present(const char *refname,
+static int ref_present(const char *refname, const char *referent UNUSED,
 		       const struct object_id *oid UNUSED,
 		       int flags UNUSED,
 		       void *cb_data)
@@ -3409,6 +3494,116 @@ static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
 	return ret;
 }
 
+/*
+ * For refs and reflogs, they share a unified interface when scanning
+ * the whole directory. This function is used as the callback for each
+ * regular file or symlink in the directory.
+ */
+typedef int (*files_fsck_refs_fn)(struct ref_store *ref_store,
+				  struct fsck_options *o,
+				  const char *refs_check_dir,
+				  struct dir_iterator *iter);
+
+static int files_fsck_refs_name(struct ref_store *ref_store UNUSED,
+				struct fsck_options *o,
+				const char *refs_check_dir,
+				struct dir_iterator *iter)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret = 0;
+
+	/*
+	 * Ignore the files ending with ".lock" as they may be lock files
+	 * However, do not allow bare ".lock" files.
+	 */
+	if (iter->basename[0] != '.' && ends_with(iter->basename, ".lock"))
+		goto cleanup;
+
+	if (check_refname_format(iter->basename, REFNAME_ALLOW_ONELEVEL)) {
+		struct fsck_ref_report report = { .path = NULL };
+
+		strbuf_addf(&sb, "%s/%s", refs_check_dir, iter->relative_path);
+		report.path = sb.buf;
+		ret = fsck_report_ref(o, &report,
+				      FSCK_MSG_BAD_REF_NAME,
+				      "invalid refname format");
+	}
+
+cleanup:
+	strbuf_release(&sb);
+	return ret;
+}
+
+static int files_fsck_refs_dir(struct ref_store *ref_store,
+			       struct fsck_options *o,
+			       const char *refs_check_dir,
+			       files_fsck_refs_fn *fsck_refs_fn)
+{
+	struct strbuf sb = STRBUF_INIT;
+	struct dir_iterator *iter;
+	int iter_status;
+	int ret = 0;
+
+	strbuf_addf(&sb, "%s/%s", ref_store->gitdir, refs_check_dir);
+
+	iter = dir_iterator_begin(sb.buf, 0);
+	if (!iter) {
+		ret = error_errno(_("cannot open directory %s"), sb.buf);
+		goto out;
+	}
+
+	while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
+		if (S_ISDIR(iter->st.st_mode)) {
+			continue;
+		} else if (S_ISREG(iter->st.st_mode) ||
+			   S_ISLNK(iter->st.st_mode)) {
+			if (o->verbose)
+				fprintf_ln(stderr, "Checking %s/%s",
+					   refs_check_dir, iter->relative_path);
+			for (size_t i = 0; fsck_refs_fn[i]; i++) {
+				if (fsck_refs_fn[i](ref_store, o, refs_check_dir, iter))
+					ret = -1;
+			}
+		} else {
+			struct fsck_ref_report report = { .path = iter->basename };
+			if (fsck_report_ref(o, &report,
+					    FSCK_MSG_BAD_REF_FILETYPE,
+					    "unexpected file type"))
+				ret = -1;
+		}
+	}
+
+	if (iter_status != ITER_DONE)
+		ret = error(_("failed to iterate over '%s'"), sb.buf);
+
+out:
+	strbuf_release(&sb);
+	return ret;
+}
+
+static int files_fsck_refs(struct ref_store *ref_store,
+			   struct fsck_options *o)
+{
+	files_fsck_refs_fn fsck_refs_fn[]= {
+		files_fsck_refs_name,
+		NULL,
+	};
+
+	if (o->verbose)
+		fprintf_ln(stderr, _("Checking references consistency"));
+	return files_fsck_refs_dir(ref_store, o,  "refs", fsck_refs_fn);
+}
+
+static int files_fsck(struct ref_store *ref_store,
+		      struct fsck_options *o)
+{
+	struct files_ref_store *refs =
+		files_downcast(ref_store, REF_STORE_READ, "fsck");
+
+	return files_fsck_refs(ref_store, o) |
+	       refs->packed_ref_store->be->fsck(refs->packed_ref_store, o);
+}
+
 struct ref_storage_be refs_be_files = {
 	.name = "files",
 	.init = files_ref_store_init,
@@ -3435,5 +3630,7 @@ struct ref_storage_be refs_be_files = {
 	.reflog_exists = files_reflog_exists,
 	.create_reflog = files_create_reflog,
 	.delete_reflog = files_delete_reflog,
-	.reflog_expire = files_reflog_expire
+	.reflog_expire = files_reflog_expire,
+
+	.fsck = files_fsck,
 };
diff --git a/refs/iterator.c b/refs/iterator.c
index d355ebf..8e999d8 100644
--- a/refs/iterator.c
+++ b/refs/iterator.c
@@ -29,6 +29,7 @@ void base_ref_iterator_init(struct ref_iterator *iter,
 {
 	iter->vtable = vtable;
 	iter->refname = NULL;
+	iter->referent = NULL;
 	iter->oid = NULL;
 	iter->flags = 0;
 }
@@ -199,6 +200,7 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		}
 
 		if (selection & ITER_YIELD_CURRENT) {
+			iter->base.referent = (*iter->current)->referent;
 			iter->base.refname = (*iter->current)->refname;
 			iter->base.oid = (*iter->current)->oid;
 			iter->base.flags = (*iter->current)->flags;
@@ -448,7 +450,7 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,
 
 	current_ref_iter = iter;
 	while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
-		retval = fn(iter->refname, iter->oid, iter->flags, cb_data);
+		retval = fn(iter->refname, iter->referent, iter->oid, iter->flags, cb_data);
 		if (retval) {
 			/*
 			 * If ref_iterator_abort() returns ITER_ERROR,
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index a066640..07c57fd 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -794,7 +794,7 @@ static int packed_read_raw_ref(struct ref_store *ref_store, const char *refname,
 		return -1;
 	}
 
-	if (get_oid_hex(rec, oid))
+	if (get_oid_hex_algop(rec, oid, ref_store->repo->hash_algo))
 		die_invalid_line(refs->path, rec, snapshot->eof - rec);
 
 	*type = REF_ISPACKED;
@@ -879,7 +879,7 @@ static int next_record(struct packed_ref_iterator *iter)
 	p = iter->pos;
 
 	if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 2 ||
-	    parse_oid_hex(p, &iter->oid, &p) ||
+	    parse_oid_hex_algop(p, &iter->oid, &p, iter->repo->hash_algo) ||
 	    !isspace(*p++))
 		die_invalid_line(iter->snapshot->refs->path,
 				 iter->pos, iter->eof - iter->pos);
@@ -896,7 +896,7 @@ static int next_record(struct packed_ref_iterator *iter)
 		if (!refname_is_safe(iter->base.refname))
 			die("packed refname is dangerous: %s",
 			    iter->base.refname);
-		oidclr(&iter->oid, the_repository->hash_algo);
+		oidclr(&iter->oid, iter->repo->hash_algo);
 		iter->base.flags |= REF_BAD_NAME | REF_ISBROKEN;
 	}
 	if (iter->snapshot->peeled == PEELED_FULLY ||
@@ -909,7 +909,7 @@ static int next_record(struct packed_ref_iterator *iter)
 	if (iter->pos < iter->eof && *iter->pos == '^') {
 		p = iter->pos + 1;
 		if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 1 ||
-		    parse_oid_hex(p, &iter->peeled, &p) ||
+		    parse_oid_hex_algop(p, &iter->peeled, &p, iter->repo->hash_algo) ||
 		    *p++ != '\n')
 			die_invalid_line(iter->snapshot->refs->path,
 					 iter->pos, iter->eof - iter->pos);
@@ -921,13 +921,13 @@ static int next_record(struct packed_ref_iterator *iter)
 		 * we suppress it if the reference is broken:
 		 */
 		if ((iter->base.flags & REF_ISBROKEN)) {
-			oidclr(&iter->peeled, the_repository->hash_algo);
+			oidclr(&iter->peeled, iter->repo->hash_algo);
 			iter->base.flags &= ~REF_KNOWS_PEELED;
 		} else {
 			iter->base.flags |= REF_KNOWS_PEELED;
 		}
 	} else {
-		oidclr(&iter->peeled, the_repository->hash_algo);
+		oidclr(&iter->peeled, iter->repo->hash_algo);
 	}
 
 	return ITER_OK;
@@ -1250,6 +1250,24 @@ int packed_refs_is_locked(struct ref_store *ref_store)
 	return is_lock_file_locked(&refs->lock);
 }
 
+int packed_refs_size(struct ref_store *ref_store,
+		     size_t *out)
+{
+	struct packed_ref_store *refs = packed_downcast(ref_store, REF_STORE_READ,
+							"packed_refs_size");
+	struct stat st;
+
+	if (stat(refs->path, &st) < 0) {
+		if (errno != ENOENT)
+			return -1;
+		*out = 0;
+		return 0;
+	}
+
+	*out = st.st_size;
+	return 0;
+}
+
 /*
  * The packed-refs header line that we write out. Perhaps other traits
  * will be added later.
@@ -1735,6 +1753,12 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s
 	return empty_ref_iterator_begin();
 }
 
+static int packed_fsck(struct ref_store *ref_store UNUSED,
+		       struct fsck_options *o UNUSED)
+{
+	return 0;
+}
+
 struct ref_storage_be refs_be_packed = {
 	.name = "packed",
 	.init = packed_ref_store_init,
@@ -1762,4 +1786,6 @@ struct ref_storage_be refs_be_packed = {
 	.create_reflog = NULL,
 	.delete_reflog = NULL,
 	.reflog_expire = NULL,
+
+	.fsck = packed_fsck,
 };
diff --git a/refs/packed-backend.h b/refs/packed-backend.h
index 09437ad..9481d5e 100644
--- a/refs/packed-backend.h
+++ b/refs/packed-backend.h
@@ -28,6 +28,13 @@ void packed_refs_unlock(struct ref_store *ref_store);
 int packed_refs_is_locked(struct ref_store *ref_store);
 
 /*
+ * Obtain the size of the `packed-refs` file. Reports `0` as size in case there
+ * is no packed-refs file. Returns 0 on success, negative otherwise.
+ */
+int packed_refs_size(struct ref_store *ref_store,
+		     size_t *out);
+
+/*
  * Return true if `transaction` really needs to be carried out against
  * the specified packed_ref_store, or false if it can be skipped
  * (i.e., because it is an obvious NOOP). `ref_store` must be locked
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index 4ce519b..35bae7e 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -34,6 +34,7 @@ struct ref_dir *get_ref_dir(struct ref_entry *entry)
 }
 
 struct ref_entry *create_ref_entry(const char *refname,
+				   const char *referent,
 				   const struct object_id *oid, int flag)
 {
 	struct ref_entry *ref;
@@ -41,6 +42,8 @@ struct ref_entry *create_ref_entry(const char *refname,
 	FLEX_ALLOC_STR(ref, name, refname);
 	oidcpy(&ref->u.value.oid, oid);
 	ref->flag = flag;
+	ref->u.value.referent = xstrdup_or_null(referent);
+
 	return ref;
 }
 
@@ -66,6 +69,7 @@ static void free_ref_entry(struct ref_entry *entry)
 		 */
 		clear_ref_dir(&entry->u.subdir);
 	}
+	free(entry->u.value.referent);
 	free(entry);
 }
 
@@ -431,6 +435,7 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
 			level->index = -1;
 		} else {
 			iter->base.refname = entry->name;
+			iter->base.referent = entry->u.value.referent;
 			iter->base.oid = &entry->u.value.oid;
 			iter->base.flags = entry->flag;
 			return ITER_OK;
diff --git a/refs/ref-cache.h b/refs/ref-cache.h
index 31ebe24..5f04e51 100644
--- a/refs/ref-cache.h
+++ b/refs/ref-cache.h
@@ -42,6 +42,7 @@ struct ref_value {
 	 * referred to by the last reference in the symlink chain.
 	 */
 	struct object_id oid;
+	char *referent;
 };
 
 /*
@@ -173,6 +174,7 @@ struct ref_entry *create_dir_entry(struct ref_cache *cache,
 				   const char *dirname, size_t len);
 
 struct ref_entry *create_ref_entry(const char *refname,
+				   const char *referent,
 				   const struct object_id *oid, int flag);
 
 /*
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index fa975d6..2313c83 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -4,6 +4,7 @@
 #include "refs.h"
 #include "iterator.h"
 
+struct fsck_options;
 struct ref_transaction;
 
 /*
@@ -299,6 +300,7 @@ enum do_for_each_ref_flags {
 struct ref_iterator {
 	struct ref_iterator_vtable *vtable;
 	const char *refname;
+	const char *referent;
 	const struct object_id *oid;
 	unsigned int flags;
 };
@@ -650,6 +652,9 @@ typedef int read_raw_ref_fn(struct ref_store *ref_store, const char *refname,
 typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refname,
 				 struct strbuf *referent);
 
+typedef int fsck_fn(struct ref_store *ref_store,
+		    struct fsck_options *o);
+
 struct ref_storage_be {
 	const char *name;
 	ref_store_init_fn *init;
@@ -677,6 +682,8 @@ struct ref_storage_be {
 	create_reflog_fn *create_reflog;
 	delete_reflog_fn *delete_reflog;
 	reflog_expire_fn *reflog_expire;
+
+	fsck_fn *fsck;
 };
 
 extern struct ref_storage_be refs_be_files;
@@ -705,7 +712,8 @@ struct ref_store {
  * Parse contents of a loose ref file. *failure_errno maybe be set to EINVAL for
  * invalid contents.
  */
-int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+int parse_loose_ref_contents(const struct git_hash_algo *algop,
+			     const char *buf, struct object_id *oid,
 			     struct strbuf *referent, unsigned int *type,
 			     int *failure_errno);
 
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index fbe74c2..3c96fbf 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -19,8 +19,10 @@
 #include "../reftable/reftable-record.h"
 #include "../reftable/reftable-error.h"
 #include "../reftable/reftable-iterator.h"
+#include "../repo-settings.h"
 #include "../setup.h"
 #include "../strmap.h"
+#include "../trace2.h"
 #include "parse.h"
 #include "refs-internal.h"
 
@@ -51,6 +53,7 @@ struct reftable_ref_store {
 	struct reftable_write_options write_options;
 
 	unsigned int store_flags;
+	enum log_refs_config log_all_ref_updates;
 	int err;
 };
 
@@ -156,22 +159,23 @@ static struct reftable_stack *stack_for(struct reftable_ref_store *store,
 	}
 }
 
-static int should_write_log(struct ref_store *refs, const char *refname)
+static int should_write_log(struct reftable_ref_store *refs, const char *refname)
 {
-	if (log_all_ref_updates == LOG_REFS_UNSET)
-		log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+	enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
+	if (log_refs_cfg == LOG_REFS_UNSET)
+		log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
 
-	switch (log_all_ref_updates) {
+	switch (log_refs_cfg) {
 	case LOG_REFS_NONE:
-		return refs_reflog_exists(refs, refname);
+		return refs_reflog_exists(&refs->base, refname);
 	case LOG_REFS_ALWAYS:
 		return 1;
 	case LOG_REFS_NORMAL:
-		if (should_autocreate_reflog(refname))
+		if (should_autocreate_reflog(log_refs_cfg, refname))
 			return 1;
-		return refs_reflog_exists(refs, refname);
+		return refs_reflog_exists(&refs->base, refname);
 	default:
-		BUG("unhandled core.logAllRefUpdates value %d", log_all_ref_updates);
+		BUG("unhandled core.logAllRefUpdates value %d", log_refs_cfg);
 	}
 }
 
@@ -201,7 +205,8 @@ static void fill_reftable_log_record(struct reftable_log_record *log, const stru
 	log->value.update.tz_offset = sign * atoi(tz_begin);
 }
 
-static int read_ref_without_reload(struct reftable_stack *stack,
+static int read_ref_without_reload(struct reftable_ref_store *refs,
+				   struct reftable_stack *stack,
 				   const char *refname,
 				   struct object_id *oid,
 				   struct strbuf *referent,
@@ -220,7 +225,7 @@ static int read_ref_without_reload(struct reftable_stack *stack,
 		*type |= REF_ISSYMREF;
 	} else if (reftable_ref_record_val1(&ref)) {
 		oidread(oid, reftable_ref_record_val1(&ref),
-			the_repository->hash_algo);
+			refs->base.repo->hash_algo);
 	} else {
 		/* We got a tombstone, which should not happen. */
 		BUG("unhandled reference value type %d", ref.value_type);
@@ -255,6 +260,13 @@ static int reftable_be_config(const char *var, const char *value,
 		if (factor > UINT8_MAX)
 			die("reftable geometric factor cannot exceed %u", (unsigned)UINT8_MAX);
 		opts->auto_compaction_factor = factor;
+	} else if (!strcmp(var, "reftable.locktimeout")) {
+		int64_t lock_timeout = git_config_int64(var, value, ctx->kvi);
+		if (lock_timeout > LONG_MAX)
+			die("reftable lock timeout cannot exceed %"PRIdMAX, (intmax_t)LONG_MAX);
+		if (lock_timeout < 0 && lock_timeout != -1)
+			die("reftable lock timeout does not support negative values other than -1");
+		opts->lock_timeout_ms = lock_timeout;
 	}
 
 	return 0;
@@ -275,11 +287,13 @@ static struct ref_store *reftable_be_init(struct repository *repo,
 	base_ref_store_init(&refs->base, repo, gitdir, &refs_be_reftable);
 	strmap_init(&refs->worktree_stacks);
 	refs->store_flags = store_flags;
+	refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
 
 	refs->write_options.hash_id = repo->hash_algo->format_id;
 	refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask);
 	refs->write_options.disable_auto_compact =
 		!git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
+	refs->write_options.lock_timeout_ms = 100;
 
 	git_config(reftable_be_config, &refs->write_options);
 
@@ -446,15 +460,87 @@ struct reftable_ref_iterator {
 
 	const char *prefix;
 	size_t prefix_len;
+	char **exclude_patterns;
+	size_t exclude_patterns_index;
+	size_t exclude_patterns_strlen;
 	unsigned int flags;
 	int err;
 };
 
+/*
+ * Handle exclude patterns. Returns either `1`, which tells the caller that the
+ * current reference shall not be shown. Or `0`, which indicates that it should
+ * be shown.
+ */
+static int should_exclude_current_ref(struct reftable_ref_iterator *iter)
+{
+	while (iter->exclude_patterns[iter->exclude_patterns_index]) {
+		const char *pattern = iter->exclude_patterns[iter->exclude_patterns_index];
+		char *ref_after_pattern;
+		int cmp;
+
+		/*
+		 * Lazily cache the pattern length so that we don't have to
+		 * recompute it every time this function is called.
+		 */
+		if (!iter->exclude_patterns_strlen)
+			iter->exclude_patterns_strlen = strlen(pattern);
+
+		/*
+		 * When the reference name is lexicographically bigger than the
+		 * current exclude pattern we know that it won't ever match any
+		 * of the following references, either. We thus advance to the
+		 * next pattern and re-check whether it matches.
+		 *
+		 * Otherwise, if it's smaller, then we do not have a match and
+		 * thus want to show the current reference.
+		 */
+		cmp = strncmp(iter->ref.refname, pattern,
+			      iter->exclude_patterns_strlen);
+		if (cmp > 0) {
+			iter->exclude_patterns_index++;
+			iter->exclude_patterns_strlen = 0;
+			continue;
+		}
+		if (cmp < 0)
+			return 0;
+
+		/*
+		 * The reference shares a prefix with the exclude pattern and
+		 * shall thus be omitted. We skip all references that match the
+		 * pattern by seeking to the first reference after the block of
+		 * matches.
+		 *
+		 * This is done by appending the highest possible character to
+		 * the pattern. Consequently, all references that have the
+		 * pattern as prefix and whose suffix starts with anything in
+		 * the range [0x00, 0xfe] are skipped. And given that 0xff is a
+		 * non-printable character that shouldn't ever be in a ref name,
+		 * we'd not yield any such record, either.
+		 *
+		 * Note that the seeked-to reference may also be excluded. This
+		 * is not handled here though, but the caller is expected to
+		 * loop and re-verify the next reference for us.
+		 */
+		ref_after_pattern = xstrfmt("%s%c", pattern, 0xff);
+		iter->err = reftable_iterator_seek_ref(&iter->iter, ref_after_pattern);
+		iter->exclude_patterns_index++;
+		iter->exclude_patterns_strlen = 0;
+		trace2_counter_add(TRACE2_COUNTER_ID_REFTABLE_RESEEKS, 1);
+
+		free(ref_after_pattern);
+		return 1;
+	}
+
+	return 0;
+}
+
 static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
 {
 	struct reftable_ref_iterator *iter =
 		(struct reftable_ref_iterator *)ref_iterator;
 	struct reftable_ref_store *refs = iter->refs;
+	const char *referent = NULL;
 
 	while (!iter->err) {
 		int flags = 0;
@@ -479,6 +565,9 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
 			break;
 		}
 
+		if (iter->exclude_patterns && should_exclude_current_ref(iter))
+			continue;
+
 		if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
 		    parse_worktree_ref(iter->ref.refname, NULL, NULL, NULL) !=
 			    REF_WORKTREE_CURRENT)
@@ -487,16 +576,19 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		switch (iter->ref.value_type) {
 		case REFTABLE_REF_VAL1:
 			oidread(&iter->oid, iter->ref.value.val1,
-				the_repository->hash_algo);
+				refs->base.repo->hash_algo);
 			break;
 		case REFTABLE_REF_VAL2:
 			oidread(&iter->oid, iter->ref.value.val2.value,
-				the_repository->hash_algo);
+				refs->base.repo->hash_algo);
 			break;
 		case REFTABLE_REF_SYMREF:
-			if (!refs_resolve_ref_unsafe(&iter->refs->base, iter->ref.refname,
-						     RESOLVE_REF_READING, &iter->oid, &flags))
-				oidclr(&iter->oid, the_repository->hash_algo);
+			referent = refs_resolve_ref_unsafe(&iter->refs->base,
+							   iter->ref.refname,
+							   RESOLVE_REF_READING,
+							   &iter->oid, &flags);
+			if (!referent)
+				oidclr(&iter->oid, refs->base.repo->hash_algo);
 			break;
 		default:
 			BUG("unhandled reference value type %d", iter->ref.value_type);
@@ -508,7 +600,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
 		if (check_refname_format(iter->ref.refname, REFNAME_ALLOW_ONELEVEL)) {
 			if (!refname_is_safe(iter->ref.refname))
 				die(_("refname is dangerous: %s"), iter->ref.refname);
-			oidclr(&iter->oid, the_repository->hash_algo);
+			oidclr(&iter->oid, refs->base.repo->hash_algo);
 			flags |= REF_BAD_NAME | REF_ISBROKEN;
 		}
 
@@ -523,6 +615,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
 				continue;
 
 		iter->base.refname = iter->ref.refname;
+		iter->base.referent = referent;
 		iter->base.oid = &iter->oid;
 		iter->base.flags = flags;
 
@@ -551,7 +644,7 @@ static int reftable_ref_iterator_peel(struct ref_iterator *ref_iterator,
 
 	if (iter->ref.value_type == REFTABLE_REF_VAL2) {
 		oidread(peeled, iter->ref.value.val2.target_value,
-			the_repository->hash_algo);
+			iter->refs->base.repo->hash_algo);
 		return 0;
 	}
 
@@ -564,6 +657,11 @@ static int reftable_ref_iterator_abort(struct ref_iterator *ref_iterator)
 		(struct reftable_ref_iterator *)ref_iterator;
 	reftable_ref_record_release(&iter->ref);
 	reftable_iterator_destroy(&iter->iter);
+	if (iter->exclude_patterns) {
+		for (size_t i = 0; iter->exclude_patterns[i]; i++)
+			free(iter->exclude_patterns[i]);
+		free(iter->exclude_patterns);
+	}
 	free(iter);
 	return ITER_DONE;
 }
@@ -574,9 +672,53 @@ static struct ref_iterator_vtable reftable_ref_iterator_vtable = {
 	.abort = reftable_ref_iterator_abort
 };
 
+static int qsort_strcmp(const void *va, const void *vb)
+{
+	const char *a = *(const char **)va;
+	const char *b = *(const char **)vb;
+	return strcmp(a, b);
+}
+
+static char **filter_exclude_patterns(const char **exclude_patterns)
+{
+	size_t filtered_size = 0, filtered_alloc = 0;
+	char **filtered = NULL;
+
+	if (!exclude_patterns)
+		return NULL;
+
+	for (size_t i = 0; ; i++) {
+		const char *exclude_pattern = exclude_patterns[i];
+		int has_glob = 0;
+
+		if (!exclude_pattern)
+			break;
+
+		for (const char *p = exclude_pattern; *p; p++) {
+			has_glob = is_glob_special(*p);
+			if (has_glob)
+				break;
+		}
+		if (has_glob)
+			continue;
+
+		ALLOC_GROW(filtered, filtered_size + 1, filtered_alloc);
+		filtered[filtered_size++] = xstrdup(exclude_pattern);
+	}
+
+	if (filtered_size) {
+		QSORT(filtered, filtered_size, qsort_strcmp);
+		ALLOC_GROW(filtered, filtered_size + 1, filtered_alloc);
+		filtered[filtered_size++] = NULL;
+	}
+
+	return filtered;
+}
+
 static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_store *refs,
 							    struct reftable_stack *stack,
 							    const char *prefix,
+							    const char **exclude_patterns,
 							    int flags)
 {
 	struct reftable_ref_iterator *iter;
@@ -589,6 +731,7 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
 	iter->base.oid = &iter->oid;
 	iter->flags = flags;
 	iter->refs = refs;
+	iter->exclude_patterns = filter_exclude_patterns(exclude_patterns);
 
 	ret = refs->err;
 	if (ret)
@@ -621,7 +764,8 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
 		required_flags |= REF_STORE_ODB;
 	refs = reftable_be_downcast(ref_store, required_flags, "ref_iterator_begin");
 
-	main_iter = ref_iterator_for_stack(refs, refs->main_stack, prefix, flags);
+	main_iter = ref_iterator_for_stack(refs, refs->main_stack, prefix,
+					   exclude_patterns, flags);
 
 	/*
 	 * The worktree stack is only set when we're in an actual worktree
@@ -635,7 +779,8 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
 	 * Otherwise we merge both the common and the per-worktree refs into a
 	 * single iterator.
 	 */
-	worktree_iter = ref_iterator_for_stack(refs, refs->worktree_stack, prefix, flags);
+	worktree_iter = ref_iterator_for_stack(refs, refs->worktree_stack, prefix,
+					       exclude_patterns, flags);
 	return merge_ref_iterator_begin(&worktree_iter->base, &main_iter->base,
 					ref_iterator_select, NULL);
 }
@@ -659,7 +804,7 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store,
 	if (ret)
 		return ret;
 
-	ret = read_ref_without_reload(stack, refname, oid, referent, type);
+	ret = read_ref_without_reload(refs, stack, refname, oid, referent, type);
 	if (ret < 0)
 		return ret;
 	if (ret > 0) {
@@ -756,7 +901,8 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
 		if (ret)
 			return ret;
 
-		ret = reftable_stack_new_addition(&addition, stack);
+		ret = reftable_stack_new_addition(&addition, stack,
+						  REFTABLE_STACK_NEW_ADDITION_RELOAD);
 		if (ret) {
 			if (ret == REFTABLE_LOCK_ERROR)
 				strbuf_addstr(err, "cannot lock references");
@@ -868,8 +1014,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
 		goto done;
 	}
 
-	ret = read_ref_without_reload(stack_for(refs, "HEAD", NULL), "HEAD", &head_oid,
-				      &head_referent, &head_type);
+	ret = read_ref_without_reload(refs, stack_for(refs, "HEAD", NULL), "HEAD",
+				      &head_oid, &head_referent, &head_type);
 	if (ret < 0)
 		goto done;
 	ret = 0;
@@ -936,7 +1082,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
 			string_list_insert(&affected_refnames, new_update->refname);
 		}
 
-		ret = read_ref_without_reload(stack, rewritten_ref,
+		ret = read_ref_without_reload(refs, stack, rewritten_ref,
 					      &current_oid, &referent, &u->type);
 		if (ret < 0)
 			goto done;
@@ -1119,9 +1265,9 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
 	return ret;
 }
 
-static int reftable_be_transaction_abort(struct ref_store *ref_store,
+static int reftable_be_transaction_abort(struct ref_store *ref_store UNUSED,
 					 struct ref_transaction *transaction,
-					 struct strbuf *err)
+					 struct strbuf *err UNUSED)
 {
 	struct reftable_transaction_data *tx_data = transaction->backend_data;
 	free_transaction_data(tx_data);
@@ -1212,7 +1358,7 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
 		} else if (!(u->flags & REF_SKIP_CREATE_REFLOG) &&
 			   (u->flags & REF_HAVE_NEW) &&
 			   (u->flags & REF_FORCE_CREATE_REFLOG ||
-			    should_write_log(&arg->refs->base, u->refname))) {
+			    should_write_log(arg->refs, u->refname))) {
 			struct reftable_log_record *log;
 			int create_reflog = 1;
 
@@ -1311,7 +1457,7 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
 	return ret;
 }
 
-static int reftable_be_transaction_finish(struct ref_store *ref_store,
+static int reftable_be_transaction_finish(struct ref_store *ref_store UNUSED,
 					  struct ref_transaction *transaction,
 					  struct strbuf *err)
 {
@@ -1500,7 +1646,8 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
 		memcpy(logs[logs_nr].value.update.old_hash, old_ref.value.val1, GIT_MAX_RAWSZ);
 		logs_nr++;
 
-		ret = read_ref_without_reload(arg->stack, "HEAD", &head_oid, &head_referent, &head_type);
+		ret = read_ref_without_reload(arg->refs, arg->stack, "HEAD", &head_oid,
+					      &head_referent, &head_type);
 		if (ret < 0)
 			goto done;
 		append_head_reflog = (head_type & REF_ISSYMREF) && !strcmp(head_referent.buf, arg->oldname);
@@ -1721,8 +1868,8 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
 	return ITER_OK;
 }
 
-static int reftable_reflog_iterator_peel(struct ref_iterator *ref_iterator,
-						 struct object_id *peeled)
+static int reftable_reflog_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
+					 struct object_id *peeled UNUSED)
 {
 	BUG("reftable reflog iterator cannot be peeled");
 	return -1;
@@ -1790,15 +1937,16 @@ static struct ref_iterator *reftable_be_reflog_iterator_begin(struct ref_store *
 					ref_iterator_select, NULL);
 }
 
-static int yield_log_record(struct reftable_log_record *log,
+static int yield_log_record(struct reftable_ref_store *refs,
+			    struct reftable_log_record *log,
 			    each_reflog_ent_fn fn,
 			    void *cb_data)
 {
 	struct object_id old_oid, new_oid;
 	const char *full_committer;
 
-	oidread(&old_oid, log->value.update.old_hash, the_repository->hash_algo);
-	oidread(&new_oid, log->value.update.new_hash, the_repository->hash_algo);
+	oidread(&old_oid, log->value.update.old_hash, refs->base.repo->hash_algo);
+	oidread(&new_oid, log->value.update.new_hash, refs->base.repo->hash_algo);
 
 	/*
 	 * When both the old object ID and the new object ID are null
@@ -1841,7 +1989,7 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
 			break;
 		}
 
-		ret = yield_log_record(&log, fn, cb_data);
+		ret = yield_log_record(refs, &log, fn, cb_data);
 		if (ret)
 			break;
 	}
@@ -1886,7 +2034,7 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
 	}
 
 	for (i = logs_nr; i--;) {
-		ret = yield_log_record(&logs[i], fn, cb_data);
+		ret = yield_log_record(refs, &logs[i], fn, cb_data);
 		if (ret)
 			goto done;
 	}
@@ -1982,7 +2130,7 @@ static int write_reflog_existence_table(struct reftable_writer *writer,
 
 static int reftable_be_create_reflog(struct ref_store *ref_store,
 				     const char *refname,
-				     struct strbuf *errmsg)
+				     struct strbuf *errmsg UNUSED)
 {
 	struct reftable_ref_store *refs =
 		reftable_be_downcast(ref_store, REF_STORE_WRITE, "create_reflog");
@@ -2191,7 +2339,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
 	if (ret < 0)
 		goto done;
 
-	ret = reftable_stack_new_addition(&add, stack);
+	ret = reftable_stack_new_addition(&add, stack, 0);
 	if (ret < 0)
 		goto done;
 
@@ -2200,7 +2348,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
 		goto done;
 	if (reftable_ref_record_val1(&ref_record))
 		oidread(&oid, reftable_ref_record_val1(&ref_record),
-			the_repository->hash_algo);
+			ref_store->repo->hash_algo);
 	prepare_fn(refname, &oid, policy_cb_data);
 
 	while (1) {
@@ -2216,9 +2364,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
 		}
 
 		oidread(&old_oid, log.value.update.old_hash,
-			the_repository->hash_algo);
+			ref_store->repo->hash_algo);
 		oidread(&new_oid, log.value.update.new_hash,
-			the_repository->hash_algo);
+			ref_store->repo->hash_algo);
 
 		/*
 		 * Skip over the reflog existence marker. We will add it back
@@ -2250,9 +2398,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
 
 		*dest = logs[i];
 		oidread(&old_oid, logs[i].value.update.old_hash,
-			the_repository->hash_algo);
+			ref_store->repo->hash_algo);
 		oidread(&new_oid, logs[i].value.update.new_hash,
-			the_repository->hash_algo);
+			ref_store->repo->hash_algo);
 
 		if (should_prune_fn(&old_oid, &new_oid, logs[i].value.update.email,
 				    (timestamp_t)logs[i].value.update.time,
@@ -2269,7 +2417,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
 
 	if (flags & EXPIRE_REFLOGS_UPDATE_REF && last_hash &&
 	    reftable_ref_record_val1(&ref_record))
-		oidread(&arg.update_oid, last_hash, the_repository->hash_algo);
+		oidread(&arg.update_oid, last_hash, ref_store->repo->hash_algo);
 
 	arg.refs = refs;
 	arg.records = rewritten;
@@ -2303,6 +2451,12 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
 	return ret;
 }
 
+static int reftable_be_fsck(struct ref_store *ref_store UNUSED,
+			    struct fsck_options *o UNUSED)
+{
+	return 0;
+}
+
 struct ref_storage_be refs_be_reftable = {
 	.name = "reftable",
 	.init = reftable_be_init,
@@ -2330,4 +2484,6 @@ struct ref_storage_be refs_be_reftable = {
 	.create_reflog = reftable_be_create_reflog,
 	.delete_reflog = reftable_be_delete_reflog,
 	.reflog_expire = reftable_be_reflog_expire,
+
+	.fsck = reftable_be_fsck,
 };
diff --git a/refspec.c b/refspec.c
index ec90ab3..c3cf003 100644
--- a/refspec.c
+++ b/refspec.c
@@ -225,7 +225,7 @@ void refspec_clear(struct refspec *rs)
 	rs->nr = 0;
 
 	for (i = 0; i < rs->raw_nr; i++)
-		free((char *)rs->raw[i]);
+		free(rs->raw[i]);
 	FREE_AND_NULL(rs->raw);
 	rs->raw_alloc = 0;
 	rs->raw_nr = 0;
diff --git a/refspec.h b/refspec.h
index 754be45..3760fda 100644
--- a/refspec.h
+++ b/refspec.h
@@ -43,7 +43,7 @@ struct refspec {
 	int alloc;
 	int nr;
 
-	const char **raw;
+	char **raw;
 	int raw_alloc;
 	int raw_nr;
 
diff --git a/reftable/block_test.c b/reftable/block_test.c
deleted file mode 100644
index 90aecd5..0000000
--- a/reftable/block_test.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "block.h"
-
-#include "system.h"
-#include "blocksource.h"
-#include "basics.h"
-#include "constants.h"
-#include "record.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-
-static void test_block_read_write(void)
-{
-	const int header_off = 21; /* random */
-	char *names[30];
-	const int N = ARRAY_SIZE(names);
-	const int block_size = 1024;
-	struct reftable_block block = { NULL };
-	struct block_writer bw = {
-		.last_key = STRBUF_INIT,
-	};
-	struct reftable_record rec = {
-		.type = BLOCK_TYPE_REF,
-	};
-	int i = 0;
-	int n;
-	struct block_reader br = { 0 };
-	struct block_iter it = BLOCK_ITER_INIT;
-	int j = 0;
-	struct strbuf want = STRBUF_INIT;
-
-	REFTABLE_CALLOC_ARRAY(block.data, block_size);
-	block.len = block_size;
-	block.source = malloc_block_source();
-	block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
-			  header_off, hash_size(GIT_SHA1_FORMAT_ID));
-
-	rec.u.ref.refname = (char *) "";
-	rec.u.ref.value_type = REFTABLE_REF_DELETION;
-	n = block_writer_add(&bw, &rec);
-	EXPECT(n == REFTABLE_API_ERROR);
-
-	for (i = 0; i < N; i++) {
-		char name[100];
-		snprintf(name, sizeof(name), "branch%02d", i);
-
-		rec.u.ref.refname = name;
-		rec.u.ref.value_type = REFTABLE_REF_VAL1;
-		memset(rec.u.ref.value.val1, i, GIT_SHA1_RAWSZ);
-
-		names[i] = xstrdup(name);
-		n = block_writer_add(&bw, &rec);
-		rec.u.ref.refname = NULL;
-		rec.u.ref.value_type = REFTABLE_REF_DELETION;
-		EXPECT(n == 0);
-	}
-
-	n = block_writer_finish(&bw);
-	EXPECT(n > 0);
-
-	block_writer_release(&bw);
-
-	block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
-
-	block_iter_seek_start(&it, &br);
-
-	while (1) {
-		int r = block_iter_next(&it, &rec);
-		EXPECT(r >= 0);
-		if (r > 0) {
-			break;
-		}
-		EXPECT_STREQ(names[j], rec.u.ref.refname);
-		j++;
-	}
-
-	reftable_record_release(&rec);
-	block_iter_close(&it);
-
-	for (i = 0; i < N; i++) {
-		struct block_iter it = BLOCK_ITER_INIT;
-		strbuf_reset(&want);
-		strbuf_addstr(&want, names[i]);
-
-		n = block_iter_seek_key(&it, &br, &want);
-		EXPECT(n == 0);
-
-		n = block_iter_next(&it, &rec);
-		EXPECT(n == 0);
-
-		EXPECT_STREQ(names[i], rec.u.ref.refname);
-
-		want.len--;
-		n = block_iter_seek_key(&it, &br, &want);
-		EXPECT(n == 0);
-
-		n = block_iter_next(&it, &rec);
-		EXPECT(n == 0);
-		EXPECT_STREQ(names[10 * (i / 10)], rec.u.ref.refname);
-
-		block_iter_close(&it);
-	}
-
-	reftable_record_release(&rec);
-	reftable_block_done(&br.block);
-	strbuf_release(&want);
-	for (i = 0; i < N; i++) {
-		reftable_free(names[i]);
-	}
-}
-
-int block_test_main(int argc, const char *argv[])
-{
-	RUN_TEST(test_block_read_write);
-	return 0;
-}
diff --git a/reftable/blocksource.c b/reftable/blocksource.c
index eeed254..e93cac9 100644
--- a/reftable/blocksource.c
+++ b/reftable/blocksource.c
@@ -13,14 +13,14 @@ license that can be found in the LICENSE file or at
 #include "reftable-blocksource.h"
 #include "reftable-error.h"
 
-static void strbuf_return_block(void *b, struct reftable_block *dest)
+static void strbuf_return_block(void *b UNUSED, struct reftable_block *dest)
 {
 	if (dest->len)
 		memset(dest->data, 0xff, dest->len);
 	reftable_free(dest->data);
 }
 
-static void strbuf_close(void *b)
+static void strbuf_close(void *b UNUSED)
 {
 }
 
@@ -55,26 +55,6 @@ void block_source_from_strbuf(struct reftable_block_source *bs,
 	bs->arg = buf;
 }
 
-static void malloc_return_block(void *b, struct reftable_block *dest)
-{
-	if (dest->len)
-		memset(dest->data, 0xff, dest->len);
-	reftable_free(dest->data);
-}
-
-static struct reftable_block_source_vtable malloc_vtable = {
-	.return_block = &malloc_return_block,
-};
-
-static struct reftable_block_source malloc_block_source_instance = {
-	.ops = &malloc_vtable,
-};
-
-struct reftable_block_source malloc_block_source(void)
-{
-	return malloc_block_source_instance;
-}
-
 struct file_block_source {
 	uint64_t size;
 	unsigned char *data;
@@ -85,7 +65,7 @@ static uint64_t file_size(void *b)
 	return ((struct file_block_source *)b)->size;
 }
 
-static void file_return_block(void *b, struct reftable_block *dest)
+static void file_return_block(void *b UNUSED, struct reftable_block *dest UNUSED)
 {
 }
 
diff --git a/reftable/blocksource.h b/reftable/blocksource.h
index 072e272..659a27b 100644
--- a/reftable/blocksource.h
+++ b/reftable/blocksource.h
@@ -17,6 +17,4 @@ struct reftable_block_source;
 void block_source_from_strbuf(struct reftable_block_source *bs,
 			      struct strbuf *buf);
 
-struct reftable_block_source malloc_block_source(void);
-
 #endif
diff --git a/reftable/dump.c b/reftable/dump.c
deleted file mode 100644
index dd65d9e..0000000
--- a/reftable/dump.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "git-compat-util.h"
-#include "hash.h"
-
-#include "reftable-blocksource.h"
-#include "reftable-error.h"
-#include "reftable-record.h"
-#include "reftable-tests.h"
-#include "reftable-writer.h"
-#include "reftable-iterator.h"
-#include "reftable-reader.h"
-#include "reftable-stack.h"
-
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-static int compact_stack(const char *stackdir)
-{
-	struct reftable_stack *stack = NULL;
-	struct reftable_write_options opts = { 0 };
-
-	int err = reftable_new_stack(&stack, stackdir, &opts);
-	if (err < 0)
-		goto done;
-
-	err = reftable_stack_compact_all(stack, NULL);
-	if (err < 0)
-		goto done;
-done:
-	if (stack) {
-		reftable_stack_destroy(stack);
-	}
-	return err;
-}
-
-static void print_help(void)
-{
-	printf("usage: dump [-cst] arg\n\n"
-	       "options: \n"
-	       "  -c compact\n"
-	       "  -b dump blocks\n"
-	       "  -t dump table\n"
-	       "  -s dump stack\n"
-	       "  -6 sha256 hash format\n"
-	       "  -h this help\n"
-	       "\n");
-}
-
-int reftable_dump_main(int argc, char *const *argv)
-{
-	int err = 0;
-	int opt_dump_blocks = 0;
-	int opt_dump_table = 0;
-	int opt_dump_stack = 0;
-	int opt_compact = 0;
-	uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID;
-	const char *arg = NULL, *argv0 = argv[0];
-
-	for (; argc > 1; argv++, argc--)
-		if (*argv[1] != '-')
-			break;
-		else if (!strcmp("-b", argv[1]))
-			opt_dump_blocks = 1;
-		else if (!strcmp("-t", argv[1]))
-			opt_dump_table = 1;
-		else if (!strcmp("-6", argv[1]))
-			opt_hash_id = GIT_SHA256_FORMAT_ID;
-		else if (!strcmp("-s", argv[1]))
-			opt_dump_stack = 1;
-		else if (!strcmp("-c", argv[1]))
-			opt_compact = 1;
-		else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) {
-			print_help();
-			return 2;
-		}
-
-	if (argc != 2) {
-		fprintf(stderr, "need argument\n");
-		print_help();
-		return 2;
-	}
-
-	arg = argv[1];
-
-	if (opt_dump_blocks) {
-		err = reftable_reader_print_blocks(arg);
-	} else if (opt_dump_table) {
-		err = reftable_reader_print_file(arg);
-	} else if (opt_dump_stack) {
-		err = reftable_stack_print_directory(arg, opt_hash_id);
-	} else if (opt_compact) {
-		err = compact_stack(arg);
-	}
-
-	if (err < 0) {
-		fprintf(stderr, "%s: %s: %s\n", argv0, arg,
-			reftable_error_str(err));
-		return 1;
-	}
-	return 0;
-}
diff --git a/reftable/generic.c b/reftable/generic.c
deleted file mode 100644
index 28ae261..0000000
--- a/reftable/generic.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "constants.h"
-#include "record.h"
-#include "generic.h"
-#include "reftable-iterator.h"
-#include "reftable-generic.h"
-
-void table_init_iter(struct reftable_table *tab,
-		     struct reftable_iterator *it,
-		     uint8_t typ)
-{
-
-	tab->ops->init_iter(tab->table_arg, it, typ);
-}
-
-void reftable_table_init_ref_iter(struct reftable_table *tab,
-				  struct reftable_iterator *it)
-{
-	table_init_iter(tab, it, BLOCK_TYPE_REF);
-}
-
-void reftable_table_init_log_iter(struct reftable_table *tab,
-				  struct reftable_iterator *it)
-{
-	table_init_iter(tab, it, BLOCK_TYPE_LOG);
-}
-
-int reftable_iterator_seek_ref(struct reftable_iterator *it,
-			       const char *name)
-{
-	struct reftable_record want = {
-		.type = BLOCK_TYPE_REF,
-		.u.ref = {
-			.refname = (char *)name,
-		},
-	};
-	return it->ops->seek(it->iter_arg, &want);
-}
-
-int reftable_iterator_seek_log_at(struct reftable_iterator *it,
-				  const char *name, uint64_t update_index)
-{
-	struct reftable_record want = {
-		.type = BLOCK_TYPE_LOG,
-		.u.log = {
-			.refname = (char *)name,
-			.update_index = update_index,
-		},
-	};
-	return it->ops->seek(it->iter_arg, &want);
-}
-
-int reftable_iterator_seek_log(struct reftable_iterator *it,
-			       const char *name)
-{
-	return reftable_iterator_seek_log_at(it, name, ~((uint64_t) 0));
-}
-
-int reftable_table_read_ref(struct reftable_table *tab, const char *name,
-			    struct reftable_ref_record *ref)
-{
-	struct reftable_iterator it = { NULL };
-	int err;
-
-	reftable_table_init_ref_iter(tab, &it);
-
-	err = reftable_iterator_seek_ref(&it, name);
-	if (err)
-		goto done;
-
-	err = reftable_iterator_next_ref(&it, ref);
-	if (err)
-		goto done;
-
-	if (strcmp(ref->refname, name) ||
-	    reftable_ref_record_is_deletion(ref)) {
-		reftable_ref_record_release(ref);
-		err = 1;
-		goto done;
-	}
-
-done:
-	reftable_iterator_destroy(&it);
-	return err;
-}
-
-int reftable_table_print(struct reftable_table *tab) {
-	struct reftable_iterator it = { NULL };
-	struct reftable_ref_record ref = { NULL };
-	struct reftable_log_record log = { NULL };
-	uint32_t hash_id = reftable_table_hash_id(tab);
-	int err;
-
-	reftable_table_init_ref_iter(tab, &it);
-
-	err = reftable_iterator_seek_ref(&it, "");
-	if (err < 0)
-		return err;
-
-	while (1) {
-		err = reftable_iterator_next_ref(&it, &ref);
-		if (err > 0) {
-			break;
-		}
-		if (err < 0) {
-			return err;
-		}
-		reftable_ref_record_print(&ref, hash_id);
-	}
-	reftable_iterator_destroy(&it);
-	reftable_ref_record_release(&ref);
-
-	reftable_table_init_log_iter(tab, &it);
-
-	err = reftable_iterator_seek_log(&it, "");
-	if (err < 0)
-		return err;
-
-	while (1) {
-		err = reftable_iterator_next_log(&it, &log);
-		if (err > 0) {
-			break;
-		}
-		if (err < 0) {
-			return err;
-		}
-		reftable_log_record_print(&log, hash_id);
-	}
-	reftable_iterator_destroy(&it);
-	reftable_log_record_release(&log);
-	return 0;
-}
-
-uint64_t reftable_table_max_update_index(struct reftable_table *tab)
-{
-	return tab->ops->max_update_index(tab->table_arg);
-}
-
-uint64_t reftable_table_min_update_index(struct reftable_table *tab)
-{
-	return tab->ops->min_update_index(tab->table_arg);
-}
-
-uint32_t reftable_table_hash_id(struct reftable_table *tab)
-{
-	return tab->ops->hash_id(tab->table_arg);
-}
-
-void reftable_iterator_destroy(struct reftable_iterator *it)
-{
-	if (!it->ops) {
-		return;
-	}
-	it->ops->close(it->iter_arg);
-	it->ops = NULL;
-	FREE_AND_NULL(it->iter_arg);
-}
-
-int reftable_iterator_next_ref(struct reftable_iterator *it,
-			       struct reftable_ref_record *ref)
-{
-	struct reftable_record rec = {
-		.type = BLOCK_TYPE_REF,
-		.u = {
-			.ref = *ref
-		},
-	};
-	int err = iterator_next(it, &rec);
-	*ref = rec.u.ref;
-	return err;
-}
-
-int reftable_iterator_next_log(struct reftable_iterator *it,
-			       struct reftable_log_record *log)
-{
-	struct reftable_record rec = {
-		.type = BLOCK_TYPE_LOG,
-		.u = {
-			.log = *log,
-		},
-	};
-	int err = iterator_next(it, &rec);
-	*log = rec.u.log;
-	return err;
-}
-
-int iterator_seek(struct reftable_iterator *it, struct reftable_record *want)
-{
-	return it->ops->seek(it->iter_arg, want);
-}
-
-int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
-{
-	return it->ops->next(it->iter_arg, rec);
-}
-
-static int empty_iterator_seek(void *arg, struct reftable_record *want)
-{
-	return 0;
-}
-
-static int empty_iterator_next(void *arg, struct reftable_record *rec)
-{
-	return 1;
-}
-
-static void empty_iterator_close(void *arg)
-{
-}
-
-static struct reftable_iterator_vtable empty_vtable = {
-	.seek = &empty_iterator_seek,
-	.next = &empty_iterator_next,
-	.close = &empty_iterator_close,
-};
-
-void iterator_set_empty(struct reftable_iterator *it)
-{
-	assert(!it->ops);
-	it->iter_arg = NULL;
-	it->ops = &empty_vtable;
-}
diff --git a/reftable/generic.h b/reftable/generic.h
deleted file mode 100644
index 8341fa5..0000000
--- a/reftable/generic.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef GENERIC_H
-#define GENERIC_H
-
-#include "record.h"
-#include "reftable-generic.h"
-
-/* generic interface to reftables */
-struct reftable_table_vtable {
-	void (*init_iter)(void *tab, struct reftable_iterator *it, uint8_t typ);
-	uint32_t (*hash_id)(void *tab);
-	uint64_t (*min_update_index)(void *tab);
-	uint64_t (*max_update_index)(void *tab);
-};
-
-void table_init_iter(struct reftable_table *tab,
-		     struct reftable_iterator *it,
-		     uint8_t typ);
-
-struct reftable_iterator_vtable {
-	int (*seek)(void *iter_arg, struct reftable_record *want);
-	int (*next)(void *iter_arg, struct reftable_record *rec);
-	void (*close)(void *iter_arg);
-};
-
-void iterator_set_empty(struct reftable_iterator *it);
-int iterator_seek(struct reftable_iterator *it, struct reftable_record *want);
-int iterator_next(struct reftable_iterator *it, struct reftable_record *rec);
-
-#endif
diff --git a/reftable/iter.c b/reftable/iter.c
index fddea31..416a9f6 100644
--- a/reftable/iter.c
+++ b/reftable/iter.c
@@ -11,11 +11,47 @@ license that can be found in the LICENSE file or at
 #include "system.h"
 
 #include "block.h"
-#include "generic.h"
 #include "constants.h"
 #include "reader.h"
 #include "reftable-error.h"
 
+int iterator_seek(struct reftable_iterator *it, struct reftable_record *want)
+{
+	return it->ops->seek(it->iter_arg, want);
+}
+
+int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
+{
+	return it->ops->next(it->iter_arg, rec);
+}
+
+static int empty_iterator_seek(void *arg UNUSED, struct reftable_record *want UNUSED)
+{
+	return 0;
+}
+
+static int empty_iterator_next(void *arg UNUSED, struct reftable_record *rec UNUSED)
+{
+	return 1;
+}
+
+static void empty_iterator_close(void *arg UNUSED)
+{
+}
+
+static struct reftable_iterator_vtable empty_vtable = {
+	.seek = &empty_iterator_seek,
+	.next = &empty_iterator_next,
+	.close = &empty_iterator_close,
+};
+
+void iterator_set_empty(struct reftable_iterator *it)
+{
+	assert(!it->ops);
+	it->iter_arg = NULL;
+	it->ops = &empty_vtable;
+}
+
 static void filtering_ref_iterator_close(void *iter_arg)
 {
 	struct filtering_ref_iterator *fri = iter_arg;
@@ -42,26 +78,6 @@ static int filtering_ref_iterator_next(void *iter_arg,
 			break;
 		}
 
-		if (fri->double_check) {
-			struct reftable_iterator it = { NULL };
-
-			reftable_table_init_ref_iter(&fri->tab, &it);
-
-			err = reftable_iterator_seek_ref(&it, ref->refname);
-			if (err == 0)
-				err = reftable_iterator_next_ref(&it, ref);
-
-			reftable_iterator_destroy(&it);
-
-			if (err < 0) {
-				break;
-			}
-
-			if (err > 0) {
-				continue;
-			}
-		}
-
 		if (ref->value_type == REFTABLE_REF_VAL2 &&
 		    (!memcmp(fri->oid.buf, ref->value.val2.target_value,
 			     fri->oid.len) ||
@@ -127,7 +143,8 @@ static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
 	return 0;
 }
 
-static int indexed_table_ref_iter_seek(void *p, struct reftable_record *want)
+static int indexed_table_ref_iter_seek(void *p UNUSED,
+				       struct reftable_record *want UNUSED)
 {
 	BUG("seeking indexed table is not supported");
 	return -1;
@@ -201,3 +218,71 @@ void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
 	it->iter_arg = itr;
 	it->ops = &indexed_table_ref_iter_vtable;
 }
+
+void reftable_iterator_destroy(struct reftable_iterator *it)
+{
+	if (!it->ops)
+		return;
+	it->ops->close(it->iter_arg);
+	it->ops = NULL;
+	FREE_AND_NULL(it->iter_arg);
+}
+
+int reftable_iterator_seek_ref(struct reftable_iterator *it,
+			       const char *name)
+{
+	struct reftable_record want = {
+		.type = BLOCK_TYPE_REF,
+		.u.ref = {
+			.refname = (char *)name,
+		},
+	};
+	return it->ops->seek(it->iter_arg, &want);
+}
+
+int reftable_iterator_next_ref(struct reftable_iterator *it,
+			       struct reftable_ref_record *ref)
+{
+	struct reftable_record rec = {
+		.type = BLOCK_TYPE_REF,
+		.u = {
+			.ref = *ref
+		},
+	};
+	int err = iterator_next(it, &rec);
+	*ref = rec.u.ref;
+	return err;
+}
+
+int reftable_iterator_seek_log_at(struct reftable_iterator *it,
+				  const char *name, uint64_t update_index)
+{
+	struct reftable_record want = {
+		.type = BLOCK_TYPE_LOG,
+		.u.log = {
+			.refname = (char *)name,
+			.update_index = update_index,
+		},
+	};
+	return it->ops->seek(it->iter_arg, &want);
+}
+
+int reftable_iterator_seek_log(struct reftable_iterator *it,
+			       const char *name)
+{
+	return reftable_iterator_seek_log_at(it, name, ~((uint64_t) 0));
+}
+
+int reftable_iterator_next_log(struct reftable_iterator *it,
+			       struct reftable_log_record *log)
+{
+	struct reftable_record rec = {
+		.type = BLOCK_TYPE_LOG,
+		.u = {
+			.log = *log,
+		},
+	};
+	int err = iterator_next(it, &rec);
+	*log = rec.u.log;
+	return err;
+}
diff --git a/reftable/iter.h b/reftable/iter.h
index 537431b..befc459 100644
--- a/reftable/iter.h
+++ b/reftable/iter.h
@@ -14,12 +14,36 @@ license that can be found in the LICENSE file or at
 #include "record.h"
 
 #include "reftable-iterator.h"
-#include "reftable-generic.h"
+
+/*
+ * The virtual function table for implementing generic reftable iterators.
+ */
+struct reftable_iterator_vtable {
+	int (*seek)(void *iter_arg, struct reftable_record *want);
+	int (*next)(void *iter_arg, struct reftable_record *rec);
+	void (*close)(void *iter_arg);
+};
+
+/*
+ * Position the iterator at the wanted record such that a call to
+ * `iterator_next()` would return that record, if it exists.
+ */
+int iterator_seek(struct reftable_iterator *it, struct reftable_record *want);
+
+/*
+ * Yield the next record and advance the iterator. Returns <0 on error, 0 when
+ * a record was yielded, and >0 when the iterator hit an error.
+ */
+int iterator_next(struct reftable_iterator *it, struct reftable_record *rec);
+
+/*
+ * Set up the iterator such that it behaves the same as an iterator with no
+ * entries.
+ */
+void iterator_set_empty(struct reftable_iterator *it);
 
 /* iterator that produces only ref records that point to `oid` */
 struct filtering_ref_iterator {
-	int double_check;
-	struct reftable_table tab;
 	struct strbuf oid;
 	struct reftable_iterator it;
 };
diff --git a/reftable/merged.c b/reftable/merged.c
index 6adce44..128a810 100644
--- a/reftable/merged.c
+++ b/reftable/merged.c
@@ -11,8 +11,8 @@ license that can be found in the LICENSE file or at
 #include "constants.h"
 #include "iter.h"
 #include "pq.h"
+#include "reader.h"
 #include "record.h"
-#include "generic.h"
 #include "reftable-merged.h"
 #include "reftable-error.h"
 #include "system.h"
@@ -25,7 +25,7 @@ struct merged_subiter {
 struct merged_iter {
 	struct merged_subiter *subiters;
 	struct merged_iter_pqueue pq;
-	size_t stack_len;
+	size_t subiters_len;
 	int suppress_deletions;
 	ssize_t advance_index;
 };
@@ -38,12 +38,12 @@ static void merged_iter_init(struct merged_iter *mi,
 	mi->advance_index = -1;
 	mi->suppress_deletions = mt->suppress_deletions;
 
-	REFTABLE_CALLOC_ARRAY(mi->subiters, mt->stack_len);
-	for (size_t i = 0; i < mt->stack_len; i++) {
+	REFTABLE_CALLOC_ARRAY(mi->subiters, mt->readers_len);
+	for (size_t i = 0; i < mt->readers_len; i++) {
 		reftable_record_init(&mi->subiters[i].rec, typ);
-		table_init_iter(&mt->stack[i], &mi->subiters[i].iter, typ);
+		reader_init_iter(mt->readers[i], &mi->subiters[i].iter, typ);
 	}
-	mi->stack_len = mt->stack_len;
+	mi->subiters_len = mt->readers_len;
 }
 
 static void merged_iter_close(void *p)
@@ -51,7 +51,7 @@ static void merged_iter_close(void *p)
 	struct merged_iter *mi = p;
 
 	merged_iter_pqueue_release(&mi->pq);
-	for (size_t i = 0; i < mi->stack_len; i++) {
+	for (size_t i = 0; i < mi->subiters_len; i++) {
 		reftable_iterator_destroy(&mi->subiters[i].iter);
 		reftable_record_release(&mi->subiters[i].rec);
 	}
@@ -80,7 +80,7 @@ static int merged_iter_seek(struct merged_iter *mi, struct reftable_record *want
 
 	mi->advance_index = -1;
 
-	for (size_t i = 0; i < mi->stack_len; i++) {
+	for (size_t i = 0; i < mi->subiters_len; i++) {
 		err = iterator_seek(&mi->subiters[i].iter, want);
 		if (err < 0)
 			return err;
@@ -192,8 +192,8 @@ static void iterator_from_merged_iter(struct reftable_iterator *it,
 	it->ops = &merged_iter_vtable;
 }
 
-int reftable_new_merged_table(struct reftable_merged_table **dest,
-			      struct reftable_table *stack, size_t n,
+int reftable_merged_table_new(struct reftable_merged_table **dest,
+			      struct reftable_reader **readers, size_t n,
 			      uint32_t hash_id)
 {
 	struct reftable_merged_table *m = NULL;
@@ -201,10 +201,10 @@ int reftable_new_merged_table(struct reftable_merged_table **dest,
 	uint64_t first_min = 0;
 
 	for (size_t i = 0; i < n; i++) {
-		uint64_t min = reftable_table_min_update_index(&stack[i]);
-		uint64_t max = reftable_table_max_update_index(&stack[i]);
+		uint64_t min = reftable_reader_min_update_index(readers[i]);
+		uint64_t max = reftable_reader_max_update_index(readers[i]);
 
-		if (reftable_table_hash_id(&stack[i]) != hash_id) {
+		if (reftable_reader_hash_id(readers[i]) != hash_id) {
 			return REFTABLE_FORMAT_ERROR;
 		}
 		if (i == 0 || min < first_min) {
@@ -216,8 +216,8 @@ int reftable_new_merged_table(struct reftable_merged_table **dest,
 	}
 
 	REFTABLE_CALLOC_ARRAY(m, 1);
-	m->stack = stack;
-	m->stack_len = n;
+	m->readers = readers;
+	m->readers_len = n;
 	m->min = first_min;
 	m->max = last_max;
 	m->hash_id = hash_id;
@@ -229,7 +229,6 @@ void reftable_merged_table_free(struct reftable_merged_table *mt)
 {
 	if (!mt)
 		return;
-	FREE_AND_NULL(mt->stack);
 	reftable_free(mt);
 }
 
@@ -254,44 +253,19 @@ void merged_table_init_iter(struct reftable_merged_table *mt,
 	iterator_from_merged_iter(it, mi);
 }
 
+void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
+					     struct reftable_iterator *it)
+{
+	merged_table_init_iter(mt, it, BLOCK_TYPE_REF);
+}
+
+void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
+					     struct reftable_iterator *it)
+{
+	merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
+}
+
 uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt)
 {
 	return mt->hash_id;
 }
-
-static void reftable_merged_table_init_iter_void(void *tab,
-						 struct reftable_iterator *it,
-						 uint8_t typ)
-{
-	merged_table_init_iter(tab, it, typ);
-}
-
-static uint32_t reftable_merged_table_hash_id_void(void *tab)
-{
-	return reftable_merged_table_hash_id(tab);
-}
-
-static uint64_t reftable_merged_table_min_update_index_void(void *tab)
-{
-	return reftable_merged_table_min_update_index(tab);
-}
-
-static uint64_t reftable_merged_table_max_update_index_void(void *tab)
-{
-	return reftable_merged_table_max_update_index(tab);
-}
-
-static struct reftable_table_vtable merged_table_vtable = {
-	.init_iter = reftable_merged_table_init_iter_void,
-	.hash_id = reftable_merged_table_hash_id_void,
-	.min_update_index = reftable_merged_table_min_update_index_void,
-	.max_update_index = reftable_merged_table_max_update_index_void,
-};
-
-void reftable_table_from_merged_table(struct reftable_table *tab,
-				      struct reftable_merged_table *merged)
-{
-	assert(!tab->ops);
-	tab->ops = &merged_table_vtable;
-	tab->table_arg = merged;
-}
diff --git a/reftable/merged.h b/reftable/merged.h
index 2efe571..de5fd33 100644
--- a/reftable/merged.h
+++ b/reftable/merged.h
@@ -12,8 +12,8 @@ license that can be found in the LICENSE file or at
 #include "system.h"
 
 struct reftable_merged_table {
-	struct reftable_table *stack;
-	size_t stack_len;
+	struct reftable_reader **readers;
+	size_t readers_len;
 	uint32_t hash_id;
 
 	/* If unset, produce deletions. This is useful for compaction. For the
diff --git a/reftable/merged_test.c b/reftable/merged_test.c
deleted file mode 100644
index a9d6661..0000000
--- a/reftable/merged_test.c
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "merged.h"
-
-#include "system.h"
-
-#include "basics.h"
-#include "blocksource.h"
-#include "constants.h"
-#include "reader.h"
-#include "record.h"
-#include "test_framework.h"
-#include "reftable-merged.h"
-#include "reftable-tests.h"
-#include "reftable-generic.h"
-#include "reftable-writer.h"
-
-static void write_test_table(struct strbuf *buf,
-			     struct reftable_ref_record refs[], int n)
-{
-	uint64_t min = 0xffffffff;
-	uint64_t max = 0;
-	int i = 0;
-	int err;
-
-	struct reftable_write_options opts = {
-		.block_size = 256,
-	};
-	struct reftable_writer *w = NULL;
-	for (i = 0; i < n; i++) {
-		uint64_t ui = refs[i].update_index;
-		if (ui > max) {
-			max = ui;
-		}
-		if (ui < min) {
-			min = ui;
-		}
-	}
-
-	w = reftable_new_writer(&strbuf_add_void, &noop_flush, buf, &opts);
-	reftable_writer_set_limits(w, min, max);
-
-	for (i = 0; i < n; i++) {
-		uint64_t before = refs[i].update_index;
-		int n = reftable_writer_add_ref(w, &refs[i]);
-		EXPECT(n == 0);
-		EXPECT(before == refs[i].update_index);
-	}
-
-	err = reftable_writer_close(w);
-	EXPECT_ERR(err);
-
-	reftable_writer_free(w);
-}
-
-static void write_test_log_table(struct strbuf *buf,
-				 struct reftable_log_record logs[], int n,
-				 uint64_t update_index)
-{
-	int i = 0;
-	int err;
-
-	struct reftable_write_options opts = {
-		.block_size = 256,
-		.exact_log_message = 1,
-	};
-	struct reftable_writer *w = NULL;
-	w = reftable_new_writer(&strbuf_add_void, &noop_flush, buf, &opts);
-	reftable_writer_set_limits(w, update_index, update_index);
-
-	for (i = 0; i < n; i++) {
-		int err = reftable_writer_add_log(w, &logs[i]);
-		EXPECT_ERR(err);
-	}
-
-	err = reftable_writer_close(w);
-	EXPECT_ERR(err);
-
-	reftable_writer_free(w);
-}
-
-static struct reftable_merged_table *
-merged_table_from_records(struct reftable_ref_record **refs,
-			  struct reftable_block_source **source,
-			  struct reftable_reader ***readers, int *sizes,
-			  struct strbuf *buf, size_t n)
-{
-	struct reftable_merged_table *mt = NULL;
-	struct reftable_table *tabs;
-	int err;
-
-	REFTABLE_CALLOC_ARRAY(tabs, n);
-	REFTABLE_CALLOC_ARRAY(*readers, n);
-	REFTABLE_CALLOC_ARRAY(*source, n);
-
-	for (size_t i = 0; i < n; i++) {
-		write_test_table(&buf[i], refs[i], sizes[i]);
-		block_source_from_strbuf(&(*source)[i], &buf[i]);
-
-		err = reftable_new_reader(&(*readers)[i], &(*source)[i],
-					  "name");
-		EXPECT_ERR(err);
-		reftable_table_from_reader(&tabs[i], (*readers)[i]);
-	}
-
-	err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID);
-	EXPECT_ERR(err);
-	return mt;
-}
-
-static void readers_destroy(struct reftable_reader **readers, size_t n)
-{
-	int i = 0;
-	for (; i < n; i++)
-		reftable_reader_free(readers[i]);
-	reftable_free(readers);
-}
-
-static void test_merged_between(void)
-{
-	struct reftable_ref_record r1[] = { {
-		.refname = (char *) "b",
-		.update_index = 1,
-		.value_type = REFTABLE_REF_VAL1,
-		.value.val1 = { 1, 2, 3, 0 },
-	} };
-	struct reftable_ref_record r2[] = { {
-		.refname = (char *) "a",
-		.update_index = 2,
-		.value_type = REFTABLE_REF_DELETION,
-	} };
-
-	struct reftable_ref_record *refs[] = { r1, r2 };
-	int sizes[] = { 1, 1 };
-	struct strbuf bufs[2] = { STRBUF_INIT, STRBUF_INIT };
-	struct reftable_block_source *bs = NULL;
-	struct reftable_reader **readers = NULL;
-	struct reftable_merged_table *mt =
-		merged_table_from_records(refs, &bs, &readers, sizes, bufs, 2);
-	int i;
-	struct reftable_ref_record ref = { NULL };
-	struct reftable_iterator it = { NULL };
-	int err;
-
-	merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
-	err = reftable_iterator_seek_ref(&it, "a");
-	EXPECT_ERR(err);
-
-	err = reftable_iterator_next_ref(&it, &ref);
-	EXPECT_ERR(err);
-	EXPECT(ref.update_index == 2);
-	reftable_ref_record_release(&ref);
-	reftable_iterator_destroy(&it);
-	readers_destroy(readers, 2);
-	reftable_merged_table_free(mt);
-	for (i = 0; i < ARRAY_SIZE(bufs); i++) {
-		strbuf_release(&bufs[i]);
-	}
-	reftable_free(bs);
-}
-
-static void test_merged(void)
-{
-	struct reftable_ref_record r1[] = {
-		{
-			.refname = (char *) "a",
-			.update_index = 1,
-			.value_type = REFTABLE_REF_VAL1,
-			.value.val1 = { 1 },
-		},
-		{
-			.refname = (char *) "b",
-			.update_index = 1,
-			.value_type = REFTABLE_REF_VAL1,
-			.value.val1 = { 1 },
-		},
-		{
-			.refname = (char *) "c",
-			.update_index = 1,
-			.value_type = REFTABLE_REF_VAL1,
-			.value.val1 = { 1 },
-		}
-	};
-	struct reftable_ref_record r2[] = { {
-		.refname = (char *) "a",
-		.update_index = 2,
-		.value_type = REFTABLE_REF_DELETION,
-	} };
-	struct reftable_ref_record r3[] = {
-		{
-			.refname = (char *) "c",
-			.update_index = 3,
-			.value_type = REFTABLE_REF_VAL1,
-			.value.val1 = { 2 },
-		},
-		{
-			.refname = (char *) "d",
-			.update_index = 3,
-			.value_type = REFTABLE_REF_VAL1,
-			.value.val1 = { 1 },
-		},
-	};
-
-	struct reftable_ref_record *want[] = {
-		&r2[0],
-		&r1[1],
-		&r3[0],
-		&r3[1],
-	};
-
-	struct reftable_ref_record *refs[] = { r1, r2, r3 };
-	int sizes[3] = { 3, 1, 2 };
-	struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT };
-	struct reftable_block_source *bs = NULL;
-	struct reftable_reader **readers = NULL;
-	struct reftable_merged_table *mt =
-		merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3);
-	struct reftable_iterator it = { NULL };
-	int err;
-	struct reftable_ref_record *out = NULL;
-	size_t len = 0;
-	size_t cap = 0;
-	int i = 0;
-
-	merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
-	err = reftable_iterator_seek_ref(&it, "a");
-	EXPECT_ERR(err);
-	EXPECT(reftable_merged_table_hash_id(mt) == GIT_SHA1_FORMAT_ID);
-	EXPECT(reftable_merged_table_min_update_index(mt) == 1);
-
-	while (len < 100) { /* cap loops/recursion. */
-		struct reftable_ref_record ref = { NULL };
-		int err = reftable_iterator_next_ref(&it, &ref);
-		if (err > 0)
-			break;
-
-		REFTABLE_ALLOC_GROW(out, len + 1, cap);
-		out[len++] = ref;
-	}
-	reftable_iterator_destroy(&it);
-
-	EXPECT(ARRAY_SIZE(want) == len);
-	for (i = 0; i < len; i++) {
-		EXPECT(reftable_ref_record_equal(want[i], &out[i],
-						 GIT_SHA1_RAWSZ));
-	}
-	for (i = 0; i < len; i++) {
-		reftable_ref_record_release(&out[i]);
-	}
-	reftable_free(out);
-
-	for (i = 0; i < 3; i++) {
-		strbuf_release(&bufs[i]);
-	}
-	readers_destroy(readers, 3);
-	reftable_merged_table_free(mt);
-	reftable_free(bs);
-}
-
-static struct reftable_merged_table *
-merged_table_from_log_records(struct reftable_log_record **logs,
-			      struct reftable_block_source **source,
-			      struct reftable_reader ***readers, int *sizes,
-			      struct strbuf *buf, size_t n)
-{
-	struct reftable_merged_table *mt = NULL;
-	struct reftable_table *tabs;
-	int err;
-
-	REFTABLE_CALLOC_ARRAY(tabs, n);
-	REFTABLE_CALLOC_ARRAY(*readers, n);
-	REFTABLE_CALLOC_ARRAY(*source, n);
-
-	for (size_t i = 0; i < n; i++) {
-		write_test_log_table(&buf[i], logs[i], sizes[i], i + 1);
-		block_source_from_strbuf(&(*source)[i], &buf[i]);
-
-		err = reftable_new_reader(&(*readers)[i], &(*source)[i],
-					  "name");
-		EXPECT_ERR(err);
-		reftable_table_from_reader(&tabs[i], (*readers)[i]);
-	}
-
-	err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID);
-	EXPECT_ERR(err);
-	return mt;
-}
-
-static void test_merged_logs(void)
-{
-	struct reftable_log_record r1[] = {
-		{
-			.refname = (char *) "a",
-			.update_index = 2,
-			.value_type = REFTABLE_LOG_UPDATE,
-			.value.update = {
-				.old_hash = { 2 },
-				/* deletion */
-				.name = (char *) "jane doe",
-				.email = (char *) "jane@invalid",
-				.message = (char *) "message2",
-			}
-		},
-		{
-			.refname = (char *) "a",
-			.update_index = 1,
-			.value_type = REFTABLE_LOG_UPDATE,
-			.value.update = {
-				.old_hash = { 1 },
-				.new_hash = { 2 },
-				.name = (char *) "jane doe",
-				.email = (char *) "jane@invalid",
-				.message = (char *) "message1",
-			}
-		},
-	};
-	struct reftable_log_record r2[] = {
-		{
-			.refname = (char *) "a",
-			.update_index = 3,
-			.value_type = REFTABLE_LOG_UPDATE,
-			.value.update = {
-				.new_hash = { 3 },
-				.name = (char *) "jane doe",
-				.email = (char *) "jane@invalid",
-				.message = (char *) "message3",
-			}
-		},
-	};
-	struct reftable_log_record r3[] = {
-		{
-			.refname = (char *) "a",
-			.update_index = 2,
-			.value_type = REFTABLE_LOG_DELETION,
-		},
-	};
-	struct reftable_log_record *want[] = {
-		&r2[0],
-		&r3[0],
-		&r1[1],
-	};
-
-	struct reftable_log_record *logs[] = { r1, r2, r3 };
-	int sizes[3] = { 2, 1, 1 };
-	struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT };
-	struct reftable_block_source *bs = NULL;
-	struct reftable_reader **readers = NULL;
-	struct reftable_merged_table *mt = merged_table_from_log_records(
-		logs, &bs, &readers, sizes, bufs, 3);
-	struct reftable_iterator it = { NULL };
-	int err;
-	struct reftable_log_record *out = NULL;
-	size_t len = 0;
-	size_t cap = 0;
-	int i = 0;
-
-	merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
-	err = reftable_iterator_seek_log(&it, "a");
-	EXPECT_ERR(err);
-	EXPECT(reftable_merged_table_hash_id(mt) == GIT_SHA1_FORMAT_ID);
-	EXPECT(reftable_merged_table_min_update_index(mt) == 1);
-
-	while (len < 100) { /* cap loops/recursion. */
-		struct reftable_log_record log = { NULL };
-		int err = reftable_iterator_next_log(&it, &log);
-		if (err > 0)
-			break;
-
-		REFTABLE_ALLOC_GROW(out, len + 1, cap);
-		out[len++] = log;
-	}
-	reftable_iterator_destroy(&it);
-
-	EXPECT(ARRAY_SIZE(want) == len);
-	for (i = 0; i < len; i++) {
-		EXPECT(reftable_log_record_equal(want[i], &out[i],
-						 GIT_SHA1_RAWSZ));
-	}
-
-	merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
-	err = reftable_iterator_seek_log_at(&it, "a", 2);
-	EXPECT_ERR(err);
-	reftable_log_record_release(&out[0]);
-	err = reftable_iterator_next_log(&it, &out[0]);
-	EXPECT_ERR(err);
-	EXPECT(reftable_log_record_equal(&out[0], &r3[0], GIT_SHA1_RAWSZ));
-	reftable_iterator_destroy(&it);
-
-	for (i = 0; i < len; i++) {
-		reftable_log_record_release(&out[i]);
-	}
-	reftable_free(out);
-
-	for (i = 0; i < 3; i++) {
-		strbuf_release(&bufs[i]);
-	}
-	readers_destroy(readers, 3);
-	reftable_merged_table_free(mt);
-	reftable_free(bs);
-}
-
-static void test_default_write_opts(void)
-{
-	struct reftable_write_options opts = { 0 };
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-
-	struct reftable_ref_record rec = {
-		.refname = (char *) "master",
-		.update_index = 1,
-	};
-	int err;
-	struct reftable_block_source source = { NULL };
-	struct reftable_table *tab = reftable_calloc(1, sizeof(*tab));
-	uint32_t hash_id;
-	struct reftable_reader *rd = NULL;
-	struct reftable_merged_table *merged = NULL;
-
-	reftable_writer_set_limits(w, 1, 1);
-
-	err = reftable_writer_add_ref(w, &rec);
-	EXPECT_ERR(err);
-
-	err = reftable_writer_close(w);
-	EXPECT_ERR(err);
-	reftable_writer_free(w);
-
-	block_source_from_strbuf(&source, &buf);
-
-	err = reftable_new_reader(&rd, &source, "filename");
-	EXPECT_ERR(err);
-
-	hash_id = reftable_reader_hash_id(rd);
-	EXPECT(hash_id == GIT_SHA1_FORMAT_ID);
-
-	reftable_table_from_reader(&tab[0], rd);
-	err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA1_FORMAT_ID);
-	EXPECT_ERR(err);
-
-	reftable_reader_free(rd);
-	reftable_merged_table_free(merged);
-	strbuf_release(&buf);
-}
-
-/* XXX test refs_for(oid) */
-
-int merged_test_main(int argc, const char *argv[])
-{
-	RUN_TEST(test_merged_logs);
-	RUN_TEST(test_merged_between);
-	RUN_TEST(test_merged);
-	RUN_TEST(test_default_write_opts);
-	return 0;
-}
diff --git a/reftable/pq.c b/reftable/pq.c
index 7fb45d8..2b5b7d1 100644
--- a/reftable/pq.c
+++ b/reftable/pq.c
@@ -22,27 +22,21 @@ int pq_less(struct pq_entry *a, struct pq_entry *b)
 
 struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq)
 {
-	int i = 0;
+	size_t i = 0;
 	struct pq_entry e = pq->heap[0];
 	pq->heap[0] = pq->heap[pq->len - 1];
 	pq->len--;
 
-	i = 0;
 	while (i < pq->len) {
-		int min = i;
-		int j = 2 * i + 1;
-		int k = 2 * i + 2;
-		if (j < pq->len && pq_less(&pq->heap[j], &pq->heap[i])) {
+		size_t min = i;
+		size_t j = 2 * i + 1;
+		size_t k = 2 * i + 2;
+		if (j < pq->len && pq_less(&pq->heap[j], &pq->heap[i]))
 			min = j;
-		}
-		if (k < pq->len && pq_less(&pq->heap[k], &pq->heap[min])) {
+		if (k < pq->len && pq_less(&pq->heap[k], &pq->heap[min]))
 			min = k;
-		}
-
-		if (min == i) {
+		if (min == i)
 			break;
-		}
-
 		SWAP(pq->heap[i], pq->heap[min]);
 		i = min;
 	}
@@ -52,20 +46,17 @@ struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq)
 
 void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e)
 {
-	int i = 0;
+	size_t i = 0;
 
 	REFTABLE_ALLOC_GROW(pq->heap, pq->len + 1, pq->cap);
 	pq->heap[pq->len++] = *e;
 
 	i = pq->len - 1;
 	while (i > 0) {
-		int j = (i - 1) / 2;
-		if (pq_less(&pq->heap[j], &pq->heap[i])) {
+		size_t j = (i - 1) / 2;
+		if (pq_less(&pq->heap[j], &pq->heap[i]))
 			break;
-		}
-
 		SWAP(pq->heap[j], pq->heap[i]);
-
 		i = j;
 	}
 }
diff --git a/reftable/pq.h b/reftable/pq.h
index f796c23..707bd26 100644
--- a/reftable/pq.h
+++ b/reftable/pq.h
@@ -22,7 +22,6 @@ struct merged_iter_pqueue {
 	size_t cap;
 };
 
-void merged_iter_pqueue_check(struct merged_iter_pqueue pq);
 struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq);
 void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e);
 void merged_iter_pqueue_release(struct merged_iter_pqueue *pq);
diff --git a/reftable/pq_test.c b/reftable/pq_test.c
deleted file mode 100644
index b7d3c80..0000000
--- a/reftable/pq_test.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "system.h"
-
-#include "basics.h"
-#include "constants.h"
-#include "pq.h"
-#include "record.h"
-#include "reftable-tests.h"
-#include "test_framework.h"
-
-void merged_iter_pqueue_check(struct merged_iter_pqueue pq)
-{
-	int i;
-	for (i = 1; i < pq.len; i++) {
-		int parent = (i - 1) / 2;
-
-		EXPECT(pq_less(&pq.heap[parent], &pq.heap[i]));
-	}
-}
-
-static void test_pq(void)
-{
-	struct merged_iter_pqueue pq = { NULL };
-	struct reftable_record recs[54];
-	int N = ARRAY_SIZE(recs) - 1, i;
-	char *last = NULL;
-
-	for (i = 0; i < N; i++) {
-		struct strbuf refname = STRBUF_INIT;
-		strbuf_addf(&refname, "%02d", i);
-
-		reftable_record_init(&recs[i], BLOCK_TYPE_REF);
-		recs[i].u.ref.refname = strbuf_detach(&refname, NULL);
-	}
-
-	i = 1;
-	do {
-		struct pq_entry e = {
-			.rec = &recs[i],
-		};
-
-		merged_iter_pqueue_add(&pq, &e);
-		merged_iter_pqueue_check(pq);
-
-		i = (i * 7) % N;
-	} while (i != 1);
-
-	while (!merged_iter_pqueue_is_empty(pq)) {
-		struct pq_entry e = merged_iter_pqueue_remove(&pq);
-		merged_iter_pqueue_check(pq);
-
-		EXPECT(reftable_record_type(e.rec) == BLOCK_TYPE_REF);
-		if (last)
-			EXPECT(strcmp(last, e.rec->u.ref.refname) < 0);
-		last = e.rec->u.ref.refname;
-	}
-
-	for (i = 0; i < N; i++)
-		reftable_record_release(&recs[i]);
-	merged_iter_pqueue_release(&pq);
-}
-
-int pq_test_main(int argc, const char *argv[])
-{
-	RUN_TEST(test_pq);
-	return 0;
-}
diff --git a/reftable/reader.c b/reftable/reader.c
index 29c99e2..6494ce2 100644
--- a/reftable/reader.c
+++ b/reftable/reader.c
@@ -11,11 +11,9 @@ license that can be found in the LICENSE file or at
 #include "system.h"
 #include "block.h"
 #include "constants.h"
-#include "generic.h"
 #include "iter.h"
 #include "record.h"
 #include "reftable-error.h"
-#include "reftable-generic.h"
 
 uint64_t block_source_size(struct reftable_block_source *source)
 {
@@ -164,58 +162,6 @@ static int parse_footer(struct reftable_reader *r, uint8_t *footer,
 	return err;
 }
 
-int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
-		const char *name)
-{
-	struct reftable_block footer = { NULL };
-	struct reftable_block header = { NULL };
-	int err = 0;
-	uint64_t file_size = block_source_size(source);
-
-	/* Need +1 to read type of first block. */
-	uint32_t read_size = header_size(2) + 1; /* read v2 because it's larger.  */
-	memset(r, 0, sizeof(struct reftable_reader));
-
-	if (read_size > file_size) {
-		err = REFTABLE_FORMAT_ERROR;
-		goto done;
-	}
-
-	err = block_source_read_block(source, &header, 0, read_size);
-	if (err != read_size) {
-		err = REFTABLE_IO_ERROR;
-		goto done;
-	}
-
-	if (memcmp(header.data, "REFT", 4)) {
-		err = REFTABLE_FORMAT_ERROR;
-		goto done;
-	}
-	r->version = header.data[4];
-	if (r->version != 1 && r->version != 2) {
-		err = REFTABLE_FORMAT_ERROR;
-		goto done;
-	}
-
-	r->size = file_size - footer_size(r->version);
-	r->source = *source;
-	r->name = xstrdup(name);
-	r->hash_id = 0;
-
-	err = block_source_read_block(source, &footer, r->size,
-				      footer_size(r->version));
-	if (err != footer_size(r->version)) {
-		err = REFTABLE_IO_ERROR;
-		goto done;
-	}
-
-	err = parse_footer(r, footer.data, header.data);
-done:
-	reftable_block_done(&footer);
-	reftable_block_done(&header);
-	return err;
-}
-
 struct table_iter {
 	struct reftable_reader *r;
 	uint8_t typ;
@@ -229,6 +175,7 @@ static int table_iter_init(struct table_iter *ti, struct reftable_reader *r)
 {
 	struct block_iter bi = BLOCK_ITER_INIT;
 	memset(ti, 0, sizeof(*ti));
+	reftable_reader_incref(r);
 	ti->r = r;
 	ti->bi = bi;
 	return 0;
@@ -316,6 +263,7 @@ static void table_iter_close(struct table_iter *ti)
 {
 	table_iter_block_done(ti);
 	block_iter_close(&ti->bi);
+	reftable_reader_decref(ti->r);
 }
 
 static int table_iter_next_block(struct table_iter *ti)
@@ -380,6 +328,7 @@ static int table_iter_seek_to(struct table_iter *ti, uint64_t off, uint8_t typ)
 	ti->typ = block_reader_type(&ti->br);
 	ti->block_off = off;
 	block_iter_seek_start(&ti->bi, &ti->br);
+	ti->is_finished = 0;
 	return 0;
 }
 
@@ -605,9 +554,9 @@ static void iterator_from_table_iter(struct reftable_iterator *it,
 	it->ops = &table_iter_vtable;
 }
 
-static void reader_init_iter(struct reftable_reader *r,
-			     struct reftable_iterator *it,
-			     uint8_t typ)
+void reader_init_iter(struct reftable_reader *r,
+		      struct reftable_iterator *it,
+		      uint8_t typ)
 {
 	struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
 
@@ -633,31 +582,90 @@ void reftable_reader_init_log_iterator(struct reftable_reader *r,
 	reader_init_iter(r, it, BLOCK_TYPE_LOG);
 }
 
-void reader_close(struct reftable_reader *r)
+int reftable_reader_new(struct reftable_reader **out,
+			struct reftable_block_source *source, char const *name)
 {
-	block_source_close(&r->source);
-	FREE_AND_NULL(r->name);
-}
+	struct reftable_block footer = { 0 };
+	struct reftable_block header = { 0 };
+	struct reftable_reader *r;
+	uint64_t file_size = block_source_size(source);
+	uint32_t read_size;
+	int err;
 
-int reftable_new_reader(struct reftable_reader **p,
-			struct reftable_block_source *src, char const *name)
-{
-	struct reftable_reader *rd = reftable_calloc(1, sizeof(*rd));
-	int err = init_reader(rd, src, name);
-	if (err == 0) {
-		*p = rd;
-	} else {
-		block_source_close(src);
-		reftable_free(rd);
+	REFTABLE_CALLOC_ARRAY(r, 1);
+
+	/*
+	 * We need one extra byte to read the type of first block. We also
+	 * pretend to always be reading v2 of the format because it is larger.
+	 */
+	read_size = header_size(2) + 1;
+	if (read_size > file_size) {
+		err = REFTABLE_FORMAT_ERROR;
+		goto done;
+	}
+
+	err = block_source_read_block(source, &header, 0, read_size);
+	if (err != read_size) {
+		err = REFTABLE_IO_ERROR;
+		goto done;
+	}
+
+	if (memcmp(header.data, "REFT", 4)) {
+		err = REFTABLE_FORMAT_ERROR;
+		goto done;
+	}
+	r->version = header.data[4];
+	if (r->version != 1 && r->version != 2) {
+		err = REFTABLE_FORMAT_ERROR;
+		goto done;
+	}
+
+	r->size = file_size - footer_size(r->version);
+	r->source = *source;
+	r->name = xstrdup(name);
+	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)) {
+		err = REFTABLE_IO_ERROR;
+		goto done;
+	}
+
+	err = parse_footer(r, footer.data, header.data);
+	if (err)
+		goto done;
+
+	*out = r;
+
+done:
+	reftable_block_done(&footer);
+	reftable_block_done(&header);
+	if (err) {
+		reftable_free(r);
+		block_source_close(source);
 	}
 	return err;
 }
 
-void reftable_reader_free(struct reftable_reader *r)
+void reftable_reader_incref(struct reftable_reader *r)
+{
+	if (!r->refcount)
+		BUG("cannot increment ref counter of dead reader");
+	r->refcount++;
+}
+
+void reftable_reader_decref(struct reftable_reader *r)
 {
 	if (!r)
 		return;
-	reader_close(r);
+	if (!r->refcount)
+		BUG("cannot decrement ref counter of dead reader");
+	if (--r->refcount)
+		return;
+	block_source_close(&r->source);
+	FREE_AND_NULL(r->name);
 	reftable_free(r);
 }
 
@@ -735,8 +743,6 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
 	*filter = empty;
 
 	strbuf_add(&filter->oid, oid, oid_len);
-	reftable_table_from_reader(&filter->tab, r);
-	filter->double_check = 0;
 	iterator_from_table_iter(&filter->it, ti);
 
 	iterator_from_filtering_ref_iterator(it, filter);
@@ -761,66 +767,6 @@ uint64_t reftable_reader_min_update_index(struct reftable_reader *r)
 	return r->min_update_index;
 }
 
-/* generic table interface. */
-
-static void reftable_reader_init_iter_void(void *tab,
-					   struct reftable_iterator *it,
-					   uint8_t typ)
-{
-	reader_init_iter(tab, it, typ);
-}
-
-static uint32_t reftable_reader_hash_id_void(void *tab)
-{
-	return reftable_reader_hash_id(tab);
-}
-
-static uint64_t reftable_reader_min_update_index_void(void *tab)
-{
-	return reftable_reader_min_update_index(tab);
-}
-
-static uint64_t reftable_reader_max_update_index_void(void *tab)
-{
-	return reftable_reader_max_update_index(tab);
-}
-
-static struct reftable_table_vtable reader_vtable = {
-	.init_iter = reftable_reader_init_iter_void,
-	.hash_id = reftable_reader_hash_id_void,
-	.min_update_index = reftable_reader_min_update_index_void,
-	.max_update_index = reftable_reader_max_update_index_void,
-};
-
-void reftable_table_from_reader(struct reftable_table *tab,
-				struct reftable_reader *reader)
-{
-	assert(!tab->ops);
-	tab->ops = &reader_vtable;
-	tab->table_arg = reader;
-}
-
-
-int reftable_reader_print_file(const char *tablename)
-{
-	struct reftable_block_source src = { NULL };
-	int err = reftable_block_source_from_file(&src, tablename);
-	struct reftable_reader *r = NULL;
-	struct reftable_table tab = { NULL };
-	if (err < 0)
-		goto done;
-
-	err = reftable_new_reader(&r, &src, tablename);
-	if (err < 0)
-		goto done;
-
-	reftable_table_from_reader(&tab, r);
-	err = reftable_table_print(&tab);
-done:
-	reftable_reader_free(r);
-	return err;
-}
-
 int reftable_reader_print_blocks(const char *tablename)
 {
 	struct {
@@ -850,7 +796,7 @@ int reftable_reader_print_blocks(const char *tablename)
 	if (err < 0)
 		goto done;
 
-	err = reftable_new_reader(&r, &src, tablename);
+	err = reftable_reader_new(&r, &src, tablename);
 	if (err < 0)
 		goto done;
 
@@ -881,7 +827,7 @@ int reftable_reader_print_blocks(const char *tablename)
 	}
 
 done:
-	reftable_reader_free(r);
+	reftable_reader_decref(r);
 	table_iter_close(&ti);
 	return err;
 }
diff --git a/reftable/reader.h b/reftable/reader.h
index e869165..91377b9 100644
--- a/reftable/reader.h
+++ b/reftable/reader.h
@@ -30,7 +30,7 @@ struct reftable_reader_offsets {
 
 /* The state for reading a reftable file. */
 struct reftable_reader {
-	/* for convience, associate a name with the instance. */
+	/* for convenience, associate a name with the instance. */
 	char *name;
 	struct reftable_block_source source;
 
@@ -50,13 +50,16 @@ struct reftable_reader {
 	struct reftable_reader_offsets ref_offsets;
 	struct reftable_reader_offsets obj_offsets;
 	struct reftable_reader_offsets log_offsets;
+
+	uint64_t refcount;
 };
 
-int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
-		const char *name);
-void reader_close(struct reftable_reader *r);
 const char *reader_name(struct reftable_reader *r);
 
+void reader_init_iter(struct reftable_reader *r,
+		      struct reftable_iterator *it,
+		      uint8_t typ);
+
 /* initialize a block reader to read from `r` */
 int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br,
 			     uint64_t next_off, uint8_t want_typ);
diff --git a/reftable/readwrite_test.c b/reftable/readwrite_test.c
deleted file mode 100644
index f411abf..0000000
--- a/reftable/readwrite_test.c
+++ /dev/null
@@ -1,979 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "system.h"
-
-#include "basics.h"
-#include "block.h"
-#include "blocksource.h"
-#include "reader.h"
-#include "record.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-#include "reftable-writer.h"
-
-static const int update_index = 5;
-
-static void test_buffer(void)
-{
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_block_source source = { NULL };
-	struct reftable_block out = { NULL };
-	int n;
-	uint8_t in[] = "hello";
-	strbuf_add(&buf, in, sizeof(in));
-	block_source_from_strbuf(&source, &buf);
-	EXPECT(block_source_size(&source) == 6);
-	n = block_source_read_block(&source, &out, 0, sizeof(in));
-	EXPECT(n == sizeof(in));
-	EXPECT(!memcmp(in, out.data, n));
-	reftable_block_done(&out);
-
-	n = block_source_read_block(&source, &out, 1, 2);
-	EXPECT(n == 2);
-	EXPECT(!memcmp(out.data, "el", 2));
-
-	reftable_block_done(&out);
-	block_source_close(&source);
-	strbuf_release(&buf);
-}
-
-static void write_table(char ***names, struct strbuf *buf, int N,
-			int block_size, uint32_t hash_id)
-{
-	struct reftable_write_options opts = {
-		.block_size = block_size,
-		.hash_id = hash_id,
-	};
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, buf, &opts);
-	struct reftable_ref_record ref = { NULL };
-	int i = 0, n;
-	struct reftable_log_record log = { NULL };
-	const struct reftable_stats *stats = NULL;
-
-	REFTABLE_CALLOC_ARRAY(*names, N + 1);
-
-	reftable_writer_set_limits(w, update_index, update_index);
-	for (i = 0; i < N; i++) {
-		char name[100];
-		int n;
-
-		snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
-
-		ref.refname = name;
-		ref.update_index = update_index;
-		ref.value_type = REFTABLE_REF_VAL1;
-		set_test_hash(ref.value.val1, i);
-		(*names)[i] = xstrdup(name);
-
-		n = reftable_writer_add_ref(w, &ref);
-		EXPECT(n == 0);
-	}
-
-	for (i = 0; i < N; i++) {
-		char name[100];
-		int n;
-
-		snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
-
-		log.refname = name;
-		log.update_index = update_index;
-		log.value_type = REFTABLE_LOG_UPDATE;
-		set_test_hash(log.value.update.new_hash, i);
-		log.value.update.message = (char *) "message";
-
-		n = reftable_writer_add_log(w, &log);
-		EXPECT(n == 0);
-	}
-
-	n = reftable_writer_close(w);
-	EXPECT(n == 0);
-
-	stats = reftable_writer_stats(w);
-	for (i = 0; i < stats->ref_stats.blocks; i++) {
-		int off = i * opts.block_size;
-		if (off == 0) {
-			off = header_size(
-				(hash_id == GIT_SHA256_FORMAT_ID) ? 2 : 1);
-		}
-		EXPECT(buf->buf[off] == 'r');
-	}
-
-	EXPECT(stats->log_stats.blocks > 0);
-	reftable_writer_free(w);
-}
-
-static void test_log_buffer_size(void)
-{
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_write_options opts = {
-		.block_size = 4096,
-	};
-	int err;
-	int i;
-	struct reftable_log_record
-		log = { .refname = (char *) "refs/heads/master",
-			.update_index = 0xa,
-			.value_type = REFTABLE_LOG_UPDATE,
-			.value = { .update = {
-					   .name = (char *) "Han-Wen Nienhuys",
-					   .email = (char *) "hanwen@google.com",
-					   .tz_offset = 100,
-					   .time = 0x5e430672,
-					   .message = (char *) "commit: 9\n",
-				   } } };
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-
-	/* This tests buffer extension for log compression. Must use a random
-	   hash, to ensure that the compressed part is larger than the original.
-	*/
-	for (i = 0; i < GIT_SHA1_RAWSZ; i++) {
-		log.value.update.old_hash[i] = (uint8_t)(git_rand() % 256);
-		log.value.update.new_hash[i] = (uint8_t)(git_rand() % 256);
-	}
-	reftable_writer_set_limits(w, update_index, update_index);
-	err = reftable_writer_add_log(w, &log);
-	EXPECT_ERR(err);
-	err = reftable_writer_close(w);
-	EXPECT_ERR(err);
-	reftable_writer_free(w);
-	strbuf_release(&buf);
-}
-
-static void test_log_overflow(void)
-{
-	struct strbuf buf = STRBUF_INIT;
-	char msg[256] = { 0 };
-	struct reftable_write_options opts = {
-		.block_size = ARRAY_SIZE(msg),
-	};
-	int err;
-	struct reftable_log_record log = {
-		.refname = (char *) "refs/heads/master",
-		.update_index = 0xa,
-		.value_type = REFTABLE_LOG_UPDATE,
-		.value = {
-			.update = {
-				.old_hash = { 1 },
-				.new_hash = { 2 },
-				.name = (char *) "Han-Wen Nienhuys",
-				.email = (char *) "hanwen@google.com",
-				.tz_offset = 100,
-				.time = 0x5e430672,
-				.message = msg,
-			},
-		},
-	};
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-
-	memset(msg, 'x', sizeof(msg) - 1);
-	reftable_writer_set_limits(w, update_index, update_index);
-	err = reftable_writer_add_log(w, &log);
-	EXPECT(err == REFTABLE_ENTRY_TOO_BIG_ERROR);
-	reftable_writer_free(w);
-	strbuf_release(&buf);
-}
-
-static void test_log_write_read(void)
-{
-	int N = 2;
-	char **names = reftable_calloc(N + 1, sizeof(*names));
-	int err;
-	struct reftable_write_options opts = {
-		.block_size = 256,
-	};
-	struct reftable_ref_record ref = { NULL };
-	int i = 0;
-	struct reftable_log_record log = { NULL };
-	int n;
-	struct reftable_iterator it = { NULL };
-	struct reftable_reader rd = { NULL };
-	struct reftable_block_source source = { NULL };
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-	const struct reftable_stats *stats = NULL;
-	reftable_writer_set_limits(w, 0, N);
-	for (i = 0; i < N; i++) {
-		char name[256];
-		struct reftable_ref_record ref = { NULL };
-		snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7);
-		names[i] = xstrdup(name);
-		ref.refname = name;
-		ref.update_index = i;
-
-		err = reftable_writer_add_ref(w, &ref);
-		EXPECT_ERR(err);
-	}
-	for (i = 0; i < N; i++) {
-		struct reftable_log_record log = { NULL };
-
-		log.refname = names[i];
-		log.update_index = i;
-		log.value_type = REFTABLE_LOG_UPDATE;
-		set_test_hash(log.value.update.old_hash, i);
-		set_test_hash(log.value.update.new_hash, i + 1);
-
-		err = reftable_writer_add_log(w, &log);
-		EXPECT_ERR(err);
-	}
-
-	n = reftable_writer_close(w);
-	EXPECT(n == 0);
-
-	stats = reftable_writer_stats(w);
-	EXPECT(stats->log_stats.blocks > 0);
-	reftable_writer_free(w);
-	w = NULL;
-
-	block_source_from_strbuf(&source, &buf);
-
-	err = init_reader(&rd, &source, "file.log");
-	EXPECT_ERR(err);
-
-	reftable_reader_init_ref_iterator(&rd, &it);
-
-	err = reftable_iterator_seek_ref(&it, names[N - 1]);
-	EXPECT_ERR(err);
-
-	err = reftable_iterator_next_ref(&it, &ref);
-	EXPECT_ERR(err);
-
-	/* end of iteration. */
-	err = reftable_iterator_next_ref(&it, &ref);
-	EXPECT(0 < err);
-
-	reftable_iterator_destroy(&it);
-	reftable_ref_record_release(&ref);
-
-	reftable_reader_init_log_iterator(&rd, &it);
-
-	err = reftable_iterator_seek_log(&it, "");
-	EXPECT_ERR(err);
-
-	i = 0;
-	while (1) {
-		int err = reftable_iterator_next_log(&it, &log);
-		if (err > 0) {
-			break;
-		}
-
-		EXPECT_ERR(err);
-		EXPECT_STREQ(names[i], log.refname);
-		EXPECT(i == log.update_index);
-		i++;
-		reftable_log_record_release(&log);
-	}
-
-	EXPECT(i == N);
-	reftable_iterator_destroy(&it);
-
-	/* cleanup. */
-	strbuf_release(&buf);
-	free_names(names);
-	reader_close(&rd);
-}
-
-static void test_log_zlib_corruption(void)
-{
-	struct reftable_write_options opts = {
-		.block_size = 256,
-	};
-	struct reftable_iterator it = { 0 };
-	struct reftable_reader rd = { 0 };
-	struct reftable_block_source source = { 0 };
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-	const struct reftable_stats *stats = NULL;
-	char message[100] = { 0 };
-	int err, i, n;
-	struct reftable_log_record log = {
-		.refname = (char *) "refname",
-		.value_type = REFTABLE_LOG_UPDATE,
-		.value = {
-			.update = {
-				.new_hash = { 1 },
-				.old_hash = { 2 },
-				.name = (char *) "My Name",
-				.email = (char *) "myname@invalid",
-				.message = message,
-			},
-		},
-	};
-
-	for (i = 0; i < sizeof(message) - 1; i++)
-		message[i] = (uint8_t)(git_rand() % 64 + ' ');
-
-	reftable_writer_set_limits(w, 1, 1);
-
-	err = reftable_writer_add_log(w, &log);
-	EXPECT_ERR(err);
-
-	n = reftable_writer_close(w);
-	EXPECT(n == 0);
-
-	stats = reftable_writer_stats(w);
-	EXPECT(stats->log_stats.blocks > 0);
-	reftable_writer_free(w);
-	w = NULL;
-
-	/* corrupt the data. */
-	buf.buf[50] ^= 0x99;
-
-	block_source_from_strbuf(&source, &buf);
-
-	err = init_reader(&rd, &source, "file.log");
-	EXPECT_ERR(err);
-
-	reftable_reader_init_log_iterator(&rd, &it);
-	err = reftable_iterator_seek_log(&it, "refname");
-	EXPECT(err == REFTABLE_ZLIB_ERROR);
-
-	reftable_iterator_destroy(&it);
-
-	/* cleanup. */
-	strbuf_release(&buf);
-	reader_close(&rd);
-}
-
-static void test_table_read_write_sequential(void)
-{
-	char **names;
-	struct strbuf buf = STRBUF_INIT;
-	int N = 50;
-	struct reftable_iterator it = { NULL };
-	struct reftable_block_source source = { NULL };
-	struct reftable_reader rd = { NULL };
-	int err = 0;
-	int j = 0;
-
-	write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
-
-	block_source_from_strbuf(&source, &buf);
-
-	err = init_reader(&rd, &source, "file.ref");
-	EXPECT_ERR(err);
-
-	reftable_reader_init_ref_iterator(&rd, &it);
-	err = reftable_iterator_seek_ref(&it, "");
-	EXPECT_ERR(err);
-
-	while (1) {
-		struct reftable_ref_record ref = { NULL };
-		int r = reftable_iterator_next_ref(&it, &ref);
-		EXPECT(r >= 0);
-		if (r > 0) {
-			break;
-		}
-		EXPECT(0 == strcmp(names[j], ref.refname));
-		EXPECT(update_index == ref.update_index);
-
-		j++;
-		reftable_ref_record_release(&ref);
-	}
-	EXPECT(j == N);
-	reftable_iterator_destroy(&it);
-	strbuf_release(&buf);
-	free_names(names);
-
-	reader_close(&rd);
-}
-
-static void test_table_write_small_table(void)
-{
-	char **names;
-	struct strbuf buf = STRBUF_INIT;
-	int N = 1;
-	write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID);
-	EXPECT(buf.len < 200);
-	strbuf_release(&buf);
-	free_names(names);
-}
-
-static void test_table_read_api(void)
-{
-	char **names;
-	struct strbuf buf = STRBUF_INIT;
-	int N = 50;
-	struct reftable_reader rd = { NULL };
-	struct reftable_block_source source = { NULL };
-	int err;
-	int i;
-	struct reftable_log_record log = { NULL };
-	struct reftable_iterator it = { NULL };
-
-	write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
-
-	block_source_from_strbuf(&source, &buf);
-
-	err = init_reader(&rd, &source, "file.ref");
-	EXPECT_ERR(err);
-
-	reftable_reader_init_ref_iterator(&rd, &it);
-	err = reftable_iterator_seek_ref(&it, names[0]);
-	EXPECT_ERR(err);
-
-	err = reftable_iterator_next_log(&it, &log);
-	EXPECT(err == REFTABLE_API_ERROR);
-
-	strbuf_release(&buf);
-	for (i = 0; i < N; i++) {
-		reftable_free(names[i]);
-	}
-	reftable_iterator_destroy(&it);
-	reftable_free(names);
-	reader_close(&rd);
-	strbuf_release(&buf);
-}
-
-static void test_table_read_write_seek(int index, int hash_id)
-{
-	char **names;
-	struct strbuf buf = STRBUF_INIT;
-	int N = 50;
-	struct reftable_reader rd = { NULL };
-	struct reftable_block_source source = { NULL };
-	int err;
-	int i = 0;
-
-	struct reftable_iterator it = { NULL };
-	struct strbuf pastLast = STRBUF_INIT;
-	struct reftable_ref_record ref = { NULL };
-
-	write_table(&names, &buf, N, 256, hash_id);
-
-	block_source_from_strbuf(&source, &buf);
-
-	err = init_reader(&rd, &source, "file.ref");
-	EXPECT_ERR(err);
-	EXPECT(hash_id == reftable_reader_hash_id(&rd));
-
-	if (!index) {
-		rd.ref_offsets.index_offset = 0;
-	} else {
-		EXPECT(rd.ref_offsets.index_offset > 0);
-	}
-
-	for (i = 1; i < N; i++) {
-		reftable_reader_init_ref_iterator(&rd, &it);
-		err = reftable_iterator_seek_ref(&it, names[i]);
-		EXPECT_ERR(err);
-		err = reftable_iterator_next_ref(&it, &ref);
-		EXPECT_ERR(err);
-		EXPECT(0 == strcmp(names[i], ref.refname));
-		EXPECT(REFTABLE_REF_VAL1 == ref.value_type);
-		EXPECT(i == ref.value.val1[0]);
-
-		reftable_ref_record_release(&ref);
-		reftable_iterator_destroy(&it);
-	}
-
-	strbuf_addstr(&pastLast, names[N - 1]);
-	strbuf_addstr(&pastLast, "/");
-
-	reftable_reader_init_ref_iterator(&rd, &it);
-	err = reftable_iterator_seek_ref(&it, pastLast.buf);
-	if (err == 0) {
-		struct reftable_ref_record ref = { NULL };
-		int err = reftable_iterator_next_ref(&it, &ref);
-		EXPECT(err > 0);
-	} else {
-		EXPECT(err > 0);
-	}
-
-	strbuf_release(&pastLast);
-	reftable_iterator_destroy(&it);
-
-	strbuf_release(&buf);
-	for (i = 0; i < N; i++) {
-		reftable_free(names[i]);
-	}
-	reftable_free(names);
-	reader_close(&rd);
-}
-
-static void test_table_read_write_seek_linear(void)
-{
-	test_table_read_write_seek(0, GIT_SHA1_FORMAT_ID);
-}
-
-static void test_table_read_write_seek_linear_sha256(void)
-{
-	test_table_read_write_seek(0, GIT_SHA256_FORMAT_ID);
-}
-
-static void test_table_read_write_seek_index(void)
-{
-	test_table_read_write_seek(1, GIT_SHA1_FORMAT_ID);
-}
-
-static void test_table_refs_for(int indexed)
-{
-	int N = 50;
-	char **want_names = reftable_calloc(N + 1, sizeof(*want_names));
-	int want_names_len = 0;
-	uint8_t want_hash[GIT_SHA1_RAWSZ];
-
-	struct reftable_write_options opts = {
-		.block_size = 256,
-	};
-	struct reftable_ref_record ref = { NULL };
-	int i = 0;
-	int n;
-	int err;
-	struct reftable_reader rd;
-	struct reftable_block_source source = { NULL };
-
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-
-	struct reftable_iterator it = { NULL };
-	int j;
-
-	set_test_hash(want_hash, 4);
-
-	for (i = 0; i < N; i++) {
-		uint8_t hash[GIT_SHA1_RAWSZ];
-		char fill[51] = { 0 };
-		char name[100];
-		struct reftable_ref_record ref = { NULL };
-
-		memset(hash, i, sizeof(hash));
-		memset(fill, 'x', 50);
-		/* Put the variable part in the start */
-		snprintf(name, sizeof(name), "br%02d%s", i, fill);
-		name[40] = 0;
-		ref.refname = name;
-
-		ref.value_type = REFTABLE_REF_VAL2;
-		set_test_hash(ref.value.val2.value, i / 4);
-		set_test_hash(ref.value.val2.target_value, 3 + i / 4);
-
-		/* 80 bytes / entry, so 3 entries per block. Yields 17
-		 */
-		/* blocks. */
-		n = reftable_writer_add_ref(w, &ref);
-		EXPECT(n == 0);
-
-		if (!memcmp(ref.value.val2.value, want_hash, GIT_SHA1_RAWSZ) ||
-		    !memcmp(ref.value.val2.target_value, want_hash, GIT_SHA1_RAWSZ)) {
-			want_names[want_names_len++] = xstrdup(name);
-		}
-	}
-
-	n = reftable_writer_close(w);
-	EXPECT(n == 0);
-
-	reftable_writer_free(w);
-	w = NULL;
-
-	block_source_from_strbuf(&source, &buf);
-
-	err = init_reader(&rd, &source, "file.ref");
-	EXPECT_ERR(err);
-	if (!indexed) {
-		rd.obj_offsets.is_present = 0;
-	}
-
-	reftable_reader_init_ref_iterator(&rd, &it);
-	err = reftable_iterator_seek_ref(&it, "");
-	EXPECT_ERR(err);
-	reftable_iterator_destroy(&it);
-
-	err = reftable_reader_refs_for(&rd, &it, want_hash);
-	EXPECT_ERR(err);
-
-	j = 0;
-	while (1) {
-		int err = reftable_iterator_next_ref(&it, &ref);
-		EXPECT(err >= 0);
-		if (err > 0) {
-			break;
-		}
-
-		EXPECT(j < want_names_len);
-		EXPECT(0 == strcmp(ref.refname, want_names[j]));
-		j++;
-		reftable_ref_record_release(&ref);
-	}
-	EXPECT(j == want_names_len);
-
-	strbuf_release(&buf);
-	free_names(want_names);
-	reftable_iterator_destroy(&it);
-	reader_close(&rd);
-}
-
-static void test_table_refs_for_no_index(void)
-{
-	test_table_refs_for(0);
-}
-
-static void test_table_refs_for_obj_index(void)
-{
-	test_table_refs_for(1);
-}
-
-static void test_write_empty_table(void)
-{
-	struct reftable_write_options opts = { 0 };
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-	struct reftable_block_source source = { NULL };
-	struct reftable_reader *rd = NULL;
-	struct reftable_ref_record rec = { NULL };
-	struct reftable_iterator it = { NULL };
-	int err;
-
-	reftable_writer_set_limits(w, 1, 1);
-
-	err = reftable_writer_close(w);
-	EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
-	reftable_writer_free(w);
-
-	EXPECT(buf.len == header_size(1) + footer_size(1));
-
-	block_source_from_strbuf(&source, &buf);
-
-	err = reftable_new_reader(&rd, &source, "filename");
-	EXPECT_ERR(err);
-
-	reftable_reader_init_ref_iterator(rd, &it);
-	err = reftable_iterator_seek_ref(&it, "");
-	EXPECT_ERR(err);
-
-	err = reftable_iterator_next_ref(&it, &rec);
-	EXPECT(err > 0);
-
-	reftable_iterator_destroy(&it);
-	reftable_reader_free(rd);
-	strbuf_release(&buf);
-}
-
-static void test_write_object_id_min_length(void)
-{
-	struct reftable_write_options opts = {
-		.block_size = 75,
-	};
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-	struct reftable_ref_record ref = {
-		.update_index = 1,
-		.value_type = REFTABLE_REF_VAL1,
-		.value.val1 = {42},
-	};
-	int err;
-	int i;
-
-	reftable_writer_set_limits(w, 1, 1);
-
-	/* Write the same hash in many refs. If there is only 1 hash, the
-	 * disambiguating prefix is length 0 */
-	for (i = 0; i < 256; i++) {
-		char name[256];
-		snprintf(name, sizeof(name), "ref%05d", i);
-		ref.refname = name;
-		err = reftable_writer_add_ref(w, &ref);
-		EXPECT_ERR(err);
-	}
-
-	err = reftable_writer_close(w);
-	EXPECT_ERR(err);
-	EXPECT(reftable_writer_stats(w)->object_id_len == 2);
-	reftable_writer_free(w);
-	strbuf_release(&buf);
-}
-
-static void test_write_object_id_length(void)
-{
-	struct reftable_write_options opts = {
-		.block_size = 75,
-	};
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-	struct reftable_ref_record ref = {
-		.update_index = 1,
-		.value_type = REFTABLE_REF_VAL1,
-		.value.val1 = {42},
-	};
-	int err;
-	int i;
-
-	reftable_writer_set_limits(w, 1, 1);
-
-	/* Write the same hash in many refs. If there is only 1 hash, the
-	 * disambiguating prefix is length 0 */
-	for (i = 0; i < 256; i++) {
-		char name[256];
-		snprintf(name, sizeof(name), "ref%05d", i);
-		ref.refname = name;
-		ref.value.val1[15] = i;
-		err = reftable_writer_add_ref(w, &ref);
-		EXPECT_ERR(err);
-	}
-
-	err = reftable_writer_close(w);
-	EXPECT_ERR(err);
-	EXPECT(reftable_writer_stats(w)->object_id_len == 16);
-	reftable_writer_free(w);
-	strbuf_release(&buf);
-}
-
-static void test_write_empty_key(void)
-{
-	struct reftable_write_options opts = { 0 };
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-	struct reftable_ref_record ref = {
-		.refname = (char *) "",
-		.update_index = 1,
-		.value_type = REFTABLE_REF_DELETION,
-	};
-	int err;
-
-	reftable_writer_set_limits(w, 1, 1);
-	err = reftable_writer_add_ref(w, &ref);
-	EXPECT(err == REFTABLE_API_ERROR);
-
-	err = reftable_writer_close(w);
-	EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
-	reftable_writer_free(w);
-	strbuf_release(&buf);
-}
-
-static void test_write_key_order(void)
-{
-	struct reftable_write_options opts = { 0 };
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_writer *w =
-		reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
-	struct reftable_ref_record refs[2] = {
-		{
-			.refname = (char *) "b",
-			.update_index = 1,
-			.value_type = REFTABLE_REF_SYMREF,
-			.value = {
-				.symref = (char *) "target",
-			},
-		}, {
-			.refname = (char *) "a",
-			.update_index = 1,
-			.value_type = REFTABLE_REF_SYMREF,
-			.value = {
-				.symref = (char *) "target",
-			},
-		}
-	};
-	int err;
-
-	reftable_writer_set_limits(w, 1, 1);
-	err = reftable_writer_add_ref(w, &refs[0]);
-	EXPECT_ERR(err);
-	err = reftable_writer_add_ref(w, &refs[1]);
-	EXPECT(err == REFTABLE_API_ERROR);
-	reftable_writer_close(w);
-	reftable_writer_free(w);
-	strbuf_release(&buf);
-}
-
-static void test_write_multiple_indices(void)
-{
-	struct reftable_write_options opts = {
-		.block_size = 100,
-	};
-	struct strbuf writer_buf = STRBUF_INIT, buf = STRBUF_INIT;
-	struct reftable_block_source source = { 0 };
-	struct reftable_iterator it = { 0 };
-	const struct reftable_stats *stats;
-	struct reftable_writer *writer;
-	struct reftable_reader *reader;
-	int err, i;
-
-	writer = reftable_new_writer(&strbuf_add_void, &noop_flush, &writer_buf, &opts);
-	reftable_writer_set_limits(writer, 1, 1);
-	for (i = 0; i < 100; i++) {
-		struct reftable_ref_record ref = {
-			.update_index = 1,
-			.value_type = REFTABLE_REF_VAL1,
-			.value.val1 = {i},
-		};
-
-		strbuf_reset(&buf);
-		strbuf_addf(&buf, "refs/heads/%04d", i);
-		ref.refname = buf.buf,
-
-		err = reftable_writer_add_ref(writer, &ref);
-		EXPECT_ERR(err);
-	}
-
-	for (i = 0; i < 100; i++) {
-		struct reftable_log_record log = {
-			.update_index = 1,
-			.value_type = REFTABLE_LOG_UPDATE,
-			.value.update = {
-				.old_hash = { i },
-				.new_hash = { i },
-			},
-		};
-
-		strbuf_reset(&buf);
-		strbuf_addf(&buf, "refs/heads/%04d", i);
-		log.refname = buf.buf,
-
-		err = reftable_writer_add_log(writer, &log);
-		EXPECT_ERR(err);
-	}
-
-	reftable_writer_close(writer);
-
-	/*
-	 * The written data should be sufficiently large to result in indices
-	 * for each of the block types.
-	 */
-	stats = reftable_writer_stats(writer);
-	EXPECT(stats->ref_stats.index_offset > 0);
-	EXPECT(stats->obj_stats.index_offset > 0);
-	EXPECT(stats->log_stats.index_offset > 0);
-
-	block_source_from_strbuf(&source, &writer_buf);
-	err = reftable_new_reader(&reader, &source, "filename");
-	EXPECT_ERR(err);
-
-	/*
-	 * Seeking the log uses the log index now. In case there is any
-	 * confusion regarding indices we would notice here.
-	 */
-	reftable_reader_init_log_iterator(reader, &it);
-	err = reftable_iterator_seek_log(&it, "");
-	EXPECT_ERR(err);
-
-	reftable_iterator_destroy(&it);
-	reftable_writer_free(writer);
-	reftable_reader_free(reader);
-	strbuf_release(&writer_buf);
-	strbuf_release(&buf);
-}
-
-static void test_write_multi_level_index(void)
-{
-	struct reftable_write_options opts = {
-		.block_size = 100,
-	};
-	struct strbuf writer_buf = STRBUF_INIT, buf = STRBUF_INIT;
-	struct reftable_block_source source = { 0 };
-	struct reftable_iterator it = { 0 };
-	const struct reftable_stats *stats;
-	struct reftable_writer *writer;
-	struct reftable_reader *reader;
-	int err;
-
-	writer = reftable_new_writer(&strbuf_add_void, &noop_flush, &writer_buf, &opts);
-	reftable_writer_set_limits(writer, 1, 1);
-	for (size_t i = 0; i < 200; i++) {
-		struct reftable_ref_record ref = {
-			.update_index = 1,
-			.value_type = REFTABLE_REF_VAL1,
-			.value.val1 = {i},
-		};
-
-		strbuf_reset(&buf);
-		strbuf_addf(&buf, "refs/heads/%03" PRIuMAX, (uintmax_t)i);
-		ref.refname = buf.buf,
-
-		err = reftable_writer_add_ref(writer, &ref);
-		EXPECT_ERR(err);
-	}
-	reftable_writer_close(writer);
-
-	/*
-	 * The written refs should be sufficiently large to result in a
-	 * multi-level index.
-	 */
-	stats = reftable_writer_stats(writer);
-	EXPECT(stats->ref_stats.max_index_level == 2);
-
-	block_source_from_strbuf(&source, &writer_buf);
-	err = reftable_new_reader(&reader, &source, "filename");
-	EXPECT_ERR(err);
-
-	/*
-	 * Seeking the last ref should work as expected.
-	 */
-	reftable_reader_init_ref_iterator(reader, &it);
-	err = reftable_iterator_seek_ref(&it, "refs/heads/199");
-	EXPECT_ERR(err);
-
-	reftable_iterator_destroy(&it);
-	reftable_writer_free(writer);
-	reftable_reader_free(reader);
-	strbuf_release(&writer_buf);
-	strbuf_release(&buf);
-}
-
-static void test_corrupt_table_empty(void)
-{
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_block_source source = { NULL };
-	struct reftable_reader rd = { NULL };
-	int err;
-
-	block_source_from_strbuf(&source, &buf);
-	err = init_reader(&rd, &source, "file.log");
-	EXPECT(err == REFTABLE_FORMAT_ERROR);
-}
-
-static void test_corrupt_table(void)
-{
-	uint8_t zeros[1024] = { 0 };
-	struct strbuf buf = STRBUF_INIT;
-	struct reftable_block_source source = { NULL };
-	struct reftable_reader rd = { NULL };
-	int err;
-	strbuf_add(&buf, zeros, sizeof(zeros));
-
-	block_source_from_strbuf(&source, &buf);
-	err = init_reader(&rd, &source, "file.log");
-	EXPECT(err == REFTABLE_FORMAT_ERROR);
-	strbuf_release(&buf);
-}
-
-int readwrite_test_main(int argc, const char *argv[])
-{
-	RUN_TEST(test_log_zlib_corruption);
-	RUN_TEST(test_corrupt_table);
-	RUN_TEST(test_corrupt_table_empty);
-	RUN_TEST(test_log_write_read);
-	RUN_TEST(test_write_key_order);
-	RUN_TEST(test_table_read_write_seek_linear_sha256);
-	RUN_TEST(test_log_buffer_size);
-	RUN_TEST(test_table_write_small_table);
-	RUN_TEST(test_buffer);
-	RUN_TEST(test_table_read_api);
-	RUN_TEST(test_table_read_write_sequential);
-	RUN_TEST(test_table_read_write_seek_linear);
-	RUN_TEST(test_table_read_write_seek_index);
-	RUN_TEST(test_table_refs_for_no_index);
-	RUN_TEST(test_table_refs_for_obj_index);
-	RUN_TEST(test_write_empty_key);
-	RUN_TEST(test_write_empty_table);
-	RUN_TEST(test_log_overflow);
-	RUN_TEST(test_write_object_id_length);
-	RUN_TEST(test_write_object_id_min_length);
-	RUN_TEST(test_write_multiple_indices);
-	RUN_TEST(test_write_multi_level_index);
-	return 0;
-}
diff --git a/reftable/record.c b/reftable/record.c
index a2cba5e..6b5a075 100644
--- a/reftable/record.c
+++ b/reftable/record.c
@@ -259,58 +259,6 @@ static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
 	}
 }
 
-static char hexdigit(int c)
-{
-	if (c <= 9)
-		return '0' + c;
-	return 'a' + (c - 10);
-}
-
-static void hex_format(char *dest, const unsigned char *src, int hash_size)
-{
-	assert(hash_size > 0);
-	if (src) {
-		int i = 0;
-		for (i = 0; i < hash_size; i++) {
-			dest[2 * i] = hexdigit(src[i] >> 4);
-			dest[2 * i + 1] = hexdigit(src[i] & 0xf);
-		}
-		dest[2 * hash_size] = 0;
-	}
-}
-
-static void reftable_ref_record_print_sz(const struct reftable_ref_record *ref,
-					 int hash_size)
-{
-	char hex[GIT_MAX_HEXSZ + 1] = { 0 }; /* BUG */
-	printf("ref{%s(%" PRIu64 ") ", ref->refname, ref->update_index);
-	switch (ref->value_type) {
-	case REFTABLE_REF_SYMREF:
-		printf("=> %s", ref->value.symref);
-		break;
-	case REFTABLE_REF_VAL2:
-		hex_format(hex, ref->value.val2.value, hash_size);
-		printf("val 2 %s", hex);
-		hex_format(hex, ref->value.val2.target_value,
-			   hash_size);
-		printf("(T %s)", hex);
-		break;
-	case REFTABLE_REF_VAL1:
-		hex_format(hex, ref->value.val1, hash_size);
-		printf("val 1 %s", hex);
-		break;
-	case REFTABLE_REF_DELETION:
-		printf("delete");
-		break;
-	}
-	printf("}\n");
-}
-
-void reftable_ref_record_print(const struct reftable_ref_record *ref,
-			       uint32_t hash_id) {
-	reftable_ref_record_print_sz(ref, hash_size(hash_id));
-}
-
 static void reftable_ref_record_release_void(void *rec)
 {
 	reftable_ref_record_release(rec);
@@ -480,12 +428,6 @@ static int reftable_ref_record_cmp_void(const void *_a, const void *_b)
 	return strcmp(a->refname, b->refname);
 }
 
-static void reftable_ref_record_print_void(const void *rec,
-					   int hash_size)
-{
-	reftable_ref_record_print_sz((struct reftable_ref_record *) rec, hash_size);
-}
-
 static struct reftable_record_vtable reftable_ref_record_vtable = {
 	.key = &reftable_ref_record_key,
 	.type = BLOCK_TYPE_REF,
@@ -497,7 +439,6 @@ static struct reftable_record_vtable reftable_ref_record_vtable = {
 	.is_deletion = &reftable_ref_record_is_deletion_void,
 	.equal = &reftable_ref_record_equal_void,
 	.cmp = &reftable_ref_record_cmp_void,
-	.print = &reftable_ref_record_print_void,
 };
 
 static void reftable_obj_record_key(const void *r, struct strbuf *dest)
@@ -516,23 +457,8 @@ static void reftable_obj_record_release(void *rec)
 	memset(obj, 0, sizeof(struct reftable_obj_record));
 }
 
-static void reftable_obj_record_print(const void *rec, int hash_size)
-{
-	const struct reftable_obj_record *obj = rec;
-	char hex[GIT_MAX_HEXSZ + 1] = { 0 };
-	struct strbuf offset_str = STRBUF_INIT;
-	int i;
-
-	for (i = 0; i < obj->offset_len; i++)
-		strbuf_addf(&offset_str, "%" PRIu64 " ", obj->offsets[i]);
-	hex_format(hex, obj->hash_prefix, obj->hash_prefix_len);
-	printf("prefix %s (len %d), offsets [%s]\n",
-	       hex, obj->hash_prefix_len, offset_str.buf);
-	strbuf_release(&offset_str);
-}
-
 static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
-					  int hash_size)
+					  int hash_size UNUSED)
 {
 	struct reftable_obj_record *obj = rec;
 	const struct reftable_obj_record *src =
@@ -559,7 +485,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)
+				      int hash_size UNUSED)
 {
 	const struct reftable_obj_record *r = rec;
 	struct string_view start = s;
@@ -594,7 +520,8 @@ static int reftable_obj_record_encode(const void *rec, struct string_view s,
 
 static int reftable_obj_record_decode(void *rec, struct strbuf key,
 				      uint8_t val_type, struct string_view in,
-				      int hash_size, struct strbuf *scratch UNUSED)
+				      int hash_size UNUSED,
+				      struct strbuf *scratch UNUSED)
 {
 	struct string_view start = in;
 	struct reftable_obj_record *r = rec;
@@ -647,12 +574,13 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
 	return start.len - in.len;
 }
 
-static int not_a_deletion(const void *p)
+static int not_a_deletion(const void *p UNUSED)
 {
 	return 0;
 }
 
-static int reftable_obj_record_equal_void(const void *a, const void *b, int hash_size)
+static int reftable_obj_record_equal_void(const void *a, const void *b,
+					  int hash_size UNUSED)
 {
 	struct reftable_obj_record *ra = (struct reftable_obj_record *) a;
 	struct reftable_obj_record *rb = (struct reftable_obj_record *) b;
@@ -701,41 +629,8 @@ static struct reftable_record_vtable reftable_obj_record_vtable = {
 	.is_deletion = &not_a_deletion,
 	.equal = &reftable_obj_record_equal_void,
 	.cmp = &reftable_obj_record_cmp_void,
-	.print = &reftable_obj_record_print,
 };
 
-static void reftable_log_record_print_sz(struct reftable_log_record *log,
-					 int hash_size)
-{
-	char hex[GIT_MAX_HEXSZ + 1] = { 0 };
-
-	switch (log->value_type) {
-	case REFTABLE_LOG_DELETION:
-		printf("log{%s(%" PRIu64 ") delete\n", log->refname,
-		       log->update_index);
-		break;
-	case REFTABLE_LOG_UPDATE:
-		printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n",
-		       log->refname, log->update_index,
-		       log->value.update.name ? log->value.update.name : "",
-		       log->value.update.email ? log->value.update.email : "",
-		       log->value.update.time,
-		       log->value.update.tz_offset);
-		hex_format(hex, log->value.update.old_hash, hash_size);
-		printf("%s => ", hex);
-		hex_format(hex, log->value.update.new_hash, hash_size);
-		printf("%s\n\n%s\n}\n", hex,
-		       log->value.update.message ? log->value.update.message : "");
-		break;
-	}
-}
-
-void reftable_log_record_print(struct reftable_log_record *log,
-				      uint32_t hash_id)
-{
-	reftable_log_record_print_sz(log, hash_size(hash_id));
-}
-
 static void reftable_log_record_key(const void *r, struct strbuf *dest)
 {
 	const struct reftable_log_record *rec =
@@ -1039,11 +934,6 @@ static int reftable_log_record_is_deletion_void(const void *p)
 		(const struct reftable_log_record *)p);
 }
 
-static void reftable_log_record_print_void(const void *rec, int hash_size)
-{
-	reftable_log_record_print_sz((struct reftable_log_record*)rec, hash_size);
-}
-
 static struct reftable_record_vtable reftable_log_record_vtable = {
 	.key = &reftable_log_record_key,
 	.type = BLOCK_TYPE_LOG,
@@ -1055,7 +945,6 @@ static struct reftable_record_vtable reftable_log_record_vtable = {
 	.is_deletion = &reftable_log_record_is_deletion_void,
 	.equal = &reftable_log_record_equal_void,
 	.cmp = &reftable_log_record_cmp_void,
-	.print = &reftable_log_record_print_void,
 };
 
 static void reftable_index_record_key(const void *r, struct strbuf *dest)
@@ -1066,7 +955,7 @@ static void reftable_index_record_key(const void *r, struct strbuf *dest)
 }
 
 static void reftable_index_record_copy_from(void *rec, const void *src_rec,
-					    int hash_size)
+					    int hash_size UNUSED)
 {
 	struct reftable_index_record *dst = rec;
 	const struct reftable_index_record *src = src_rec;
@@ -1082,13 +971,13 @@ static void reftable_index_record_release(void *rec)
 	strbuf_release(&idx->last_key);
 }
 
-static uint8_t reftable_index_record_val_type(const void *rec)
+static uint8_t reftable_index_record_val_type(const void *rec UNUSED)
 {
 	return 0;
 }
 
 static int reftable_index_record_encode(const void *rec, struct string_view out,
-					int hash_size)
+					int hash_size UNUSED)
 {
 	const struct reftable_index_record *r =
 		(const struct reftable_index_record *)rec;
@@ -1104,8 +993,10 @@ static int reftable_index_record_encode(const void *rec, struct string_view out,
 }
 
 static int reftable_index_record_decode(void *rec, struct strbuf key,
-					uint8_t val_type, struct string_view in,
-					int hash_size, struct strbuf *scratch UNUSED)
+					uint8_t val_type UNUSED,
+					struct string_view in,
+					int hash_size UNUSED,
+					struct strbuf *scratch UNUSED)
 {
 	struct string_view start = in;
 	struct reftable_index_record *r = rec;
@@ -1122,7 +1013,8 @@ static int reftable_index_record_decode(void *rec, struct strbuf key,
 	return start.len - in.len;
 }
 
-static int reftable_index_record_equal(const void *a, const void *b, int hash_size)
+static int reftable_index_record_equal(const void *a, const void *b,
+				       int hash_size UNUSED)
 {
 	struct reftable_index_record *ia = (struct reftable_index_record *) a;
 	struct reftable_index_record *ib = (struct reftable_index_record *) b;
@@ -1137,13 +1029,6 @@ static int reftable_index_record_cmp(const void *_a, const void *_b)
 	return strbuf_cmp(&a->last_key, &b->last_key);
 }
 
-static void reftable_index_record_print(const void *rec, int hash_size)
-{
-	const struct reftable_index_record *idx = rec;
-	/* TODO: escape null chars? */
-	printf("\"%s\" %" PRIu64 "\n", idx->last_key.buf, idx->offset);
-}
-
 static struct reftable_record_vtable reftable_index_record_vtable = {
 	.key = &reftable_index_record_key,
 	.type = BLOCK_TYPE_INDEX,
@@ -1155,7 +1040,6 @@ static struct reftable_record_vtable reftable_index_record_vtable = {
 	.is_deletion = &not_a_deletion,
 	.equal = &reftable_index_record_equal,
 	.cmp = &reftable_index_record_cmp,
-	.print = &reftable_index_record_print,
 };
 
 void reftable_record_key(struct reftable_record *rec, struct strbuf *dest)
@@ -1334,9 +1218,3 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ)
 		BUG("unhandled record type");
 	}
 }
-
-void reftable_record_print(struct reftable_record *rec, int hash_size)
-{
-	printf("'%c': ", rec->type);
-	reftable_record_vtable(rec)->print(reftable_record_data(rec), hash_size);
-}
diff --git a/reftable/record.h b/reftable/record.h
index d778133..5003bac 100644
--- a/reftable/record.h
+++ b/reftable/record.h
@@ -136,7 +136,6 @@ 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);
-void reftable_record_print(struct reftable_record *rec, int hash_size);
 void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);
 void reftable_record_copy_from(struct reftable_record *rec,
 			       struct reftable_record *src, int hash_size);
diff --git a/reftable/reftable-generic.h b/reftable/reftable-generic.h
deleted file mode 100644
index 65670ea..0000000
--- a/reftable/reftable-generic.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef REFTABLE_GENERIC_H
-#define REFTABLE_GENERIC_H
-
-#include "reftable-iterator.h"
-
-struct reftable_table_vtable;
-
-/*
- * Provides a unified API for reading tables, either merged tables, or single
- * readers. */
-struct reftable_table {
-	struct reftable_table_vtable *ops;
-	void *table_arg;
-};
-
-void reftable_table_init_ref_iter(struct reftable_table *tab,
-				  struct reftable_iterator *it);
-
-void reftable_table_init_log_iter(struct reftable_table *tab,
-				  struct reftable_iterator *it);
-
-/* returns the hash ID from a generic reftable_table */
-uint32_t reftable_table_hash_id(struct reftable_table *tab);
-
-/* returns the max update_index covered by this table. */
-uint64_t reftable_table_max_update_index(struct reftable_table *tab);
-
-/* returns the min update_index covered by this table. */
-uint64_t reftable_table_min_update_index(struct reftable_table *tab);
-
-/* convenience function to read a single ref. Returns < 0 for error, 0
-   for success, and 1 if ref not found. */
-int reftable_table_read_ref(struct reftable_table *tab, const char *name,
-			    struct reftable_ref_record *ref);
-
-/* dump table contents onto stdout for debugging */
-int reftable_table_print(struct reftable_table *tab);
-
-#endif
diff --git a/reftable/reftable-merged.h b/reftable/reftable-merged.h
index 14d5fc9..16d19f8 100644
--- a/reftable/reftable-merged.h
+++ b/reftable/reftable-merged.h
@@ -26,16 +26,24 @@ license that can be found in the LICENSE file or at
 /* A merged table is implements seeking/iterating over a stack of tables. */
 struct reftable_merged_table;
 
-/* A generic reftable; see below. */
-struct reftable_table;
+struct reftable_reader;
 
-/* reftable_new_merged_table creates a new merged table. It takes ownership of
-   the stack array.
-*/
-int reftable_new_merged_table(struct reftable_merged_table **dest,
-			      struct reftable_table *stack, size_t n,
+/*
+ * reftable_merged_table_new creates a new merged table. The readers must be
+ * kept alive as long as the merged table is still in use.
+ */
+int reftable_merged_table_new(struct reftable_merged_table **dest,
+			      struct reftable_reader **readers, size_t n,
 			      uint32_t hash_id);
 
+/* Initialize a merged table iterator for reading refs. */
+void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
+					     struct reftable_iterator *it);
+
+/* Initialize a merged table iterator for reading logs. */
+void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
+					     struct reftable_iterator *it);
+
 /* returns the max update_index covered by this merged table. */
 uint64_t
 reftable_merged_table_max_update_index(struct reftable_merged_table *mt);
@@ -50,8 +58,4 @@ void reftable_merged_table_free(struct reftable_merged_table *m);
 /* return the hash ID of the merged table. */
 uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *m);
 
-/* create a generic table from reftable_merged_table */
-void reftable_table_from_merged_table(struct reftable_table *tab,
-				      struct reftable_merged_table *table);
-
 #endif
diff --git a/reftable/reftable-reader.h b/reftable/reftable-reader.h
index a32f31d..a600452 100644
--- a/reftable/reftable-reader.h
+++ b/reftable/reftable-reader.h
@@ -23,19 +23,28 @@
 /* The reader struct is a handle to an open reftable file. */
 struct reftable_reader;
 
-/* Generic table. */
-struct reftable_table;
-
-/* reftable_new_reader opens a reftable for reading. If successful,
+/* reftable_reader_new opens a reftable for reading. If successful,
  * returns 0 code and sets pp. The name is used for creating a
  * stack. Typically, it is the basename of the file. The block source
  * `src` is owned by the reader, and is closed on calling
  * reftable_reader_destroy(). On error, the block source `src` is
  * closed as well.
  */
-int reftable_new_reader(struct reftable_reader **pp,
+int reftable_reader_new(struct reftable_reader **pp,
 			struct reftable_block_source *src, const char *name);
 
+/*
+ * Manage the reference count of the reftable reader. A newly initialized
+ * reader starts with a refcount of 1 and will be deleted once the refcount has
+ * reached 0.
+ *
+ * This is required because readers may have longer lifetimes than the stack
+ * they belong to. The stack may for example be reloaded while the old tables
+ * are still being accessed by an iterator.
+ */
+void reftable_reader_incref(struct reftable_reader *reader);
+void reftable_reader_decref(struct reftable_reader *reader);
+
 /* Initialize a reftable iterator for reading refs. */
 void reftable_reader_init_ref_iterator(struct reftable_reader *r,
 				       struct reftable_iterator *it);
@@ -47,9 +56,6 @@ void reftable_reader_init_log_iterator(struct reftable_reader *r,
 /* returns the hash ID used in this table. */
 uint32_t reftable_reader_hash_id(struct reftable_reader *r);
 
-/* closes and deallocates a reader. */
-void reftable_reader_free(struct reftable_reader *);
-
 /* return an iterator for the refs pointing to `oid`. */
 int reftable_reader_refs_for(struct reftable_reader *r,
 			     struct reftable_iterator *it, uint8_t *oid);
@@ -60,12 +66,6 @@ uint64_t reftable_reader_max_update_index(struct reftable_reader *r);
 /* return the min_update_index for a table */
 uint64_t reftable_reader_min_update_index(struct reftable_reader *r);
 
-/* creates a generic table from a file reader. */
-void reftable_table_from_reader(struct reftable_table *tab,
-				struct reftable_reader *reader);
-
-/* print table onto stdout for debugging. */
-int reftable_reader_print_file(const char *tablename);
 /* print blocks onto stdout for debugging. */
 int reftable_reader_print_blocks(const char *tablename);
 
diff --git a/reftable/reftable-record.h b/reftable/reftable-record.h
index ff486eb..2d42463 100644
--- a/reftable/reftable-record.h
+++ b/reftable/reftable-record.h
@@ -60,10 +60,6 @@ const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record *
 /* returns whether 'ref' represents a deletion */
 int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref);
 
-/* prints a reftable_ref_record onto stdout. Useful for debugging. */
-void reftable_ref_record_print(const struct reftable_ref_record *ref,
-			       uint32_t hash_id);
-
 /* frees and nulls all pointer values inside `ref`. */
 void reftable_ref_record_release(struct reftable_ref_record *ref);
 
@@ -111,8 +107,4 @@ void reftable_log_record_release(struct reftable_log_record *log);
 int reftable_log_record_equal(const struct reftable_log_record *a,
 			      const struct reftable_log_record *b, int hash_size);
 
-/* dumps a reftable_log_record on stdout, for debugging/testing. */
-void reftable_log_record_print(struct reftable_log_record *log,
-			       uint32_t hash_id);
-
 #endif
diff --git a/reftable/reftable-stack.h b/reftable/reftable-stack.h
index 09e97c9..6370fe4 100644
--- a/reftable/reftable-stack.h
+++ b/reftable/reftable-stack.h
@@ -37,12 +37,21 @@ uint64_t reftable_stack_next_update_index(struct reftable_stack *st);
 /* holds a transaction to add tables at the top of a stack. */
 struct reftable_addition;
 
+enum {
+	/*
+	 * Reload the stack when the stack is out-of-date after locking it.
+	 */
+	REFTABLE_STACK_NEW_ADDITION_RELOAD = (1 << 0),
+};
+
 /*
  * returns a new transaction to add reftables to the given stack. As a side
- * effect, the ref database is locked.
+ * effect, the ref database is locked. Accepts REFTABLE_STACK_NEW_ADDITION_*
+ * flags.
  */
 int reftable_stack_new_addition(struct reftable_addition **dest,
-				struct reftable_stack *st);
+				struct reftable_stack *st,
+				unsigned int flags);
 
 /* Adds a reftable to transaction. */
 int reftable_addition_add(struct reftable_addition *add,
@@ -140,7 +149,4 @@ struct reftable_compaction_stats {
 struct reftable_compaction_stats *
 reftable_stack_compaction_stats(struct reftable_stack *st);
 
-/* print the entire stack represented by the directory */
-int reftable_stack_print_directory(const char *stackdir, uint32_t hash_id);
-
 #endif
diff --git a/reftable/reftable-tests.h b/reftable/reftable-tests.h
deleted file mode 100644
index 114cc3d..0000000
--- a/reftable/reftable-tests.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef REFTABLE_TESTS_H
-#define REFTABLE_TESTS_H
-
-int basics_test_main(int argc, const char **argv);
-int block_test_main(int argc, const char **argv);
-int merged_test_main(int argc, const char **argv);
-int pq_test_main(int argc, const char **argv);
-int record_test_main(int argc, const char **argv);
-int readwrite_test_main(int argc, const char **argv);
-int stack_test_main(int argc, const char **argv);
-int tree_test_main(int argc, const char **argv);
-int reftable_dump_main(int argc, char *const *argv);
-
-#endif
diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h
index 189b1f4..f5e25cf 100644
--- a/reftable/reftable-writer.h
+++ b/reftable/reftable-writer.h
@@ -51,6 +51,17 @@ struct reftable_write_options {
 	 * tables to compact. Defaults to 2 if unset.
 	 */
 	uint8_t auto_compaction_factor;
+
+	/*
+	 * The number of milliseconds to wait when trying to lock "tables.list".
+	 * Note that this does not apply to locking individual tables, as these
+	 * should only ever be locked when already holding the "tables.list"
+	 * lock.
+	 *
+	 * Passing 0 will fail immediately when the file is locked, passing a
+	 * negative value will cause us to block indefinitely.
+	 */
+	long lock_timeout_ms;
 };
 
 /* reftable_block_stats holds statistics for a single block type */
diff --git a/reftable/stack.c b/reftable/stack.c
index 7375911..84cf37a 100644
--- a/reftable/stack.c
+++ b/reftable/stack.c
@@ -14,7 +14,6 @@ license that can be found in the LICENSE file or at
 #include "merged.h"
 #include "reader.h"
 #include "reftable-error.h"
-#include "reftable-generic.h"
 #include "reftable-record.h"
 #include "reftable-merged.h"
 #include "writer.h"
@@ -187,7 +186,7 @@ void reftable_stack_destroy(struct reftable_stack *st)
 			if (names && !has_name(names, name)) {
 				stack_filename(&filename, st, name);
 			}
-			reftable_reader_free(st->readers[i]);
+			reftable_reader_decref(st->readers[i]);
 
 			if (filename.len) {
 				/* On Windows, can only unlink after closing. */
@@ -225,13 +224,13 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
 				      const char **names,
 				      int reuse_open)
 {
-	size_t cur_len = !st->merged ? 0 : st->merged->stack_len;
+	size_t cur_len = !st->merged ? 0 : st->merged->readers_len;
 	struct reftable_reader **cur = stack_copy_readers(st, cur_len);
+	struct reftable_reader **reused = NULL;
+	size_t reused_len = 0, reused_alloc = 0;
 	size_t names_len = names_length(names);
 	struct reftable_reader **new_readers =
 		reftable_calloc(names_len, sizeof(*new_readers));
-	struct reftable_table *new_tables =
-		reftable_calloc(names_len, sizeof(*new_tables));
 	size_t new_readers_len = 0;
 	struct reftable_merged_table *new_merged = NULL;
 	struct strbuf table_path = STRBUF_INIT;
@@ -248,6 +247,18 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
 			if (cur[i] && 0 == strcmp(cur[i]->name, name)) {
 				rd = cur[i];
 				cur[i] = NULL;
+
+				/*
+				 * When reloading the stack fails, we end up
+				 * releasing all new readers. This also
+				 * includes the reused readers, even though
+				 * they are still in used by the old stack. We
+				 * thus need to keep them alive here, which we
+				 * do by bumping their refcount.
+				 */
+				REFTABLE_ALLOC_GROW(reused, reused_len + 1, reused_alloc);
+				reused[reused_len++] = rd;
+				reftable_reader_incref(rd);
 				break;
 			}
 		}
@@ -261,55 +272,62 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
 			if (err < 0)
 				goto done;
 
-			err = reftable_new_reader(&rd, &src, name);
+			err = reftable_reader_new(&rd, &src, name);
 			if (err < 0)
 				goto done;
 		}
 
 		new_readers[new_readers_len] = rd;
-		reftable_table_from_reader(&new_tables[new_readers_len], rd);
 		new_readers_len++;
 	}
 
 	/* success! */
-	err = reftable_new_merged_table(&new_merged, new_tables,
+	err = reftable_merged_table_new(&new_merged, new_readers,
 					new_readers_len, st->opts.hash_id);
 	if (err < 0)
 		goto done;
 
-	new_tables = NULL;
-	st->readers_len = new_readers_len;
-	if (st->merged)
-		reftable_merged_table_free(st->merged);
-	if (st->readers) {
-		reftable_free(st->readers);
-	}
-	st->readers = new_readers;
-	new_readers = NULL;
-	new_readers_len = 0;
-
-	new_merged->suppress_deletions = 1;
-	st->merged = new_merged;
+	/*
+	 * Close the old, non-reused readers and proactively try to unlink
+	 * them. This is done for systems like Windows, where the underlying
+	 * file of such an open reader wouldn't have been possible to be
+	 * unlinked by the compacting process.
+	 */
 	for (i = 0; i < cur_len; i++) {
 		if (cur[i]) {
 			const char *name = reader_name(cur[i]);
 			stack_filename(&table_path, st, name);
-
-			reader_close(cur[i]);
-			reftable_reader_free(cur[i]);
-
-			/* On Windows, can only unlink after closing. */
+			reftable_reader_decref(cur[i]);
 			unlink(table_path.buf);
 		}
 	}
 
+	/* Update the stack to point to the new tables. */
+	if (st->merged)
+		reftable_merged_table_free(st->merged);
+	new_merged->suppress_deletions = 1;
+	st->merged = new_merged;
+
+	if (st->readers)
+		reftable_free(st->readers);
+	st->readers = new_readers;
+	st->readers_len = new_readers_len;
+	new_readers = NULL;
+	new_readers_len = 0;
+
+	/*
+	 * Decrement the refcount of reused readers again. This only needs to
+	 * happen on the successful case, because on the unsuccessful one we
+	 * decrement their refcount via `new_readers`.
+	 */
+	for (i = 0; i < reused_len; i++)
+		reftable_reader_decref(reused[i]);
+
 done:
-	for (i = 0; i < new_readers_len; i++) {
-		reader_close(new_readers[i]);
-		reftable_reader_free(new_readers[i]);
-	}
+	for (i = 0; i < new_readers_len; i++)
+		reftable_reader_decref(new_readers[i]);
 	reftable_free(new_readers);
-	reftable_free(new_tables);
+	reftable_free(reused);
 	reftable_free(cur);
 	strbuf_release(&table_path);
 	return err;
@@ -520,7 +538,7 @@ static int stack_uptodate(struct reftable_stack *st)
 		}
 	}
 
-	if (names[st->merged->stack_len]) {
+	if (names[st->merged->readers_len]) {
 		err = 1;
 		goto done;
 	}
@@ -567,7 +585,7 @@ static void format_name(struct strbuf *dest, uint64_t min, uint64_t max)
 }
 
 struct reftable_addition {
-	struct tempfile *lock_file;
+	struct lock_file tables_list_lock;
 	struct reftable_stack *stack;
 
 	char **new_tables;
@@ -578,16 +596,19 @@ struct reftable_addition {
 #define REFTABLE_ADDITION_INIT {0}
 
 static int reftable_stack_init_addition(struct reftable_addition *add,
-					struct reftable_stack *st)
+					struct reftable_stack *st,
+					unsigned int flags)
 {
 	struct strbuf lock_file_name = STRBUF_INIT;
-	int err = 0;
+	int err;
+
 	add->stack = st;
 
-	strbuf_addf(&lock_file_name, "%s.lock", st->list_file);
-
-	add->lock_file = create_tempfile(lock_file_name.buf);
-	if (!add->lock_file) {
+	err = hold_lock_file_for_update_timeout(&add->tables_list_lock,
+						st->list_file,
+						LOCK_NO_DEREF,
+						st->opts.lock_timeout_ms);
+	if (err < 0) {
 		if (errno == EEXIST) {
 			err = REFTABLE_LOCK_ERROR;
 		} else {
@@ -596,7 +617,8 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
 		goto done;
 	}
 	if (st->opts.default_permissions) {
-		if (chmod(add->lock_file->filename.buf, st->opts.default_permissions) < 0) {
+		if (chmod(get_lock_file_path(&add->tables_list_lock),
+			  st->opts.default_permissions) < 0) {
 			err = REFTABLE_IO_ERROR;
 			goto done;
 		}
@@ -605,6 +627,11 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
 	err = stack_uptodate(st);
 	if (err < 0)
 		goto done;
+	if (err > 0 && flags & REFTABLE_STACK_NEW_ADDITION_RELOAD) {
+		err = reftable_stack_reload_maybe_reuse(add->stack, 1);
+		if (err)
+			goto done;
+	}
 	if (err > 0) {
 		err = REFTABLE_OUTDATED_ERROR;
 		goto done;
@@ -612,9 +639,8 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
 
 	add->next_update_index = reftable_stack_next_update_index(st);
 done:
-	if (err) {
+	if (err)
 		reftable_addition_close(add);
-	}
 	strbuf_release(&lock_file_name);
 	return err;
 }
@@ -635,7 +661,7 @@ static void reftable_addition_close(struct reftable_addition *add)
 	add->new_tables_len = 0;
 	add->new_tables_cap = 0;
 
-	delete_tempfile(&add->lock_file);
+	rollback_lock_file(&add->tables_list_lock);
 	strbuf_release(&nm);
 }
 
@@ -651,14 +677,14 @@ void reftable_addition_destroy(struct reftable_addition *add)
 int reftable_addition_commit(struct reftable_addition *add)
 {
 	struct strbuf table_list = STRBUF_INIT;
-	int lock_file_fd = get_tempfile_fd(add->lock_file);
+	int lock_file_fd = get_lock_file_fd(&add->tables_list_lock);
 	int err = 0;
 	size_t i;
 
 	if (add->new_tables_len == 0)
 		goto done;
 
-	for (i = 0; i < add->stack->merged->stack_len; i++) {
+	for (i = 0; i < add->stack->merged->readers_len; i++) {
 		strbuf_addstr(&table_list, add->stack->readers[i]->name);
 		strbuf_addstr(&table_list, "\n");
 	}
@@ -674,10 +700,13 @@ int reftable_addition_commit(struct reftable_addition *add)
 		goto done;
 	}
 
-	fsync_component_or_die(FSYNC_COMPONENT_REFERENCE, lock_file_fd,
-			       get_tempfile_path(add->lock_file));
+	err = fsync_component(FSYNC_COMPONENT_REFERENCE, lock_file_fd);
+	if (err < 0) {
+		err = REFTABLE_IO_ERROR;
+		goto done;
+	}
 
-	err = rename_tempfile(&add->lock_file, add->stack->list_file);
+	err = commit_lock_file(&add->tables_list_lock);
 	if (err < 0) {
 		err = REFTABLE_IO_ERROR;
 		goto done;
@@ -715,13 +744,14 @@ int reftable_addition_commit(struct reftable_addition *add)
 }
 
 int reftable_stack_new_addition(struct reftable_addition **dest,
-				struct reftable_stack *st)
+				struct reftable_stack *st,
+				unsigned int flags)
 {
 	int err = 0;
 	struct reftable_addition empty = REFTABLE_ADDITION_INIT;
 	REFTABLE_CALLOC_ARRAY(*dest, 1);
 	**dest = empty;
-	err = reftable_stack_init_addition(*dest, st);
+	err = reftable_stack_init_addition(*dest, st, flags);
 	if (err) {
 		reftable_free(*dest);
 		*dest = NULL;
@@ -735,7 +765,7 @@ static int stack_try_add(struct reftable_stack *st,
 			 void *arg)
 {
 	struct reftable_addition add = REFTABLE_ADDITION_INIT;
-	int err = reftable_stack_init_addition(&add, st);
+	int err = reftable_stack_init_addition(&add, st, 0);
 	if (err < 0)
 		goto done;
 
@@ -835,7 +865,7 @@ int reftable_addition_add(struct reftable_addition *add,
 
 uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
 {
-	int sz = st->merged->stack_len;
+	int sz = st->merged->readers_len;
 	if (sz > 0)
 		return reftable_reader_max_update_index(st->readers[sz - 1]) +
 		       1;
@@ -902,30 +932,23 @@ static int stack_write_compact(struct reftable_stack *st,
 			       size_t first, size_t last,
 			       struct reftable_log_expiry_config *config)
 {
-	size_t subtabs_len = last - first + 1;
-	struct reftable_table *subtabs = reftable_calloc(
-		last - first + 1, sizeof(*subtabs));
 	struct reftable_merged_table *mt = NULL;
 	struct reftable_iterator it = { NULL };
 	struct reftable_ref_record ref = { NULL };
 	struct reftable_log_record log = { NULL };
+	size_t subtabs_len = last - first + 1;
 	uint64_t entries = 0;
 	int err = 0;
 
-	for (size_t i = first, j = 0; i <= last; i++) {
-		struct reftable_reader *t = st->readers[i];
-		reftable_table_from_reader(&subtabs[j++], t);
-		st->stats.bytes += t->size;
-	}
+	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_new_merged_table(&mt, subtabs, subtabs_len,
+	err = reftable_merged_table_new(&mt, st->readers + first, subtabs_len,
 					st->opts.hash_id);
-	if (err < 0) {
-		reftable_free(subtabs);
+	if (err < 0)
 		goto done;
-	}
 
 	merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
 	err = reftable_iterator_seek_ref(&it, "");
@@ -995,6 +1018,15 @@ static int stack_write_compact(struct reftable_stack *st,
 	return err;
 }
 
+enum stack_compact_range_flags {
+	/*
+	 * Perform a best-effort compaction. That is, even if we cannot lock
+	 * all tables in the specified range, we will try to compact the
+	 * remaining slice.
+	 */
+	STACK_COMPACT_RANGE_BEST_EFFORT = (1 << 0),
+};
+
 /*
  * Compact all tables in the range `[first, last)` into a single new table.
  *
@@ -1006,7 +1038,8 @@ static int stack_write_compact(struct reftable_stack *st,
  */
 static int stack_compact_range(struct reftable_stack *st,
 			       size_t first, size_t last,
-			       struct reftable_log_expiry_config *expiry)
+			       struct reftable_log_expiry_config *expiry,
+			       unsigned int flags)
 {
 	struct strbuf tables_list_buf = STRBUF_INIT;
 	struct strbuf new_table_name = STRBUF_INIT;
@@ -1016,7 +1049,9 @@ static int stack_compact_range(struct reftable_stack *st,
 	struct lock_file *table_locks = NULL;
 	struct tempfile *new_table = NULL;
 	int is_empty_table = 0, err = 0;
-	size_t i;
+	size_t first_to_replace, last_to_replace;
+	size_t i, nlocks = 0;
+	char **names = NULL;
 
 	if (first > last || (!expiry && first == last)) {
 		err = 0;
@@ -1029,8 +1064,10 @@ static int stack_compact_range(struct reftable_stack *st,
 	 * Hold the lock so that we can read "tables.list" and lock all tables
 	 * which are part of the user-specified range.
 	 */
-	err = hold_lock_file_for_update(&tables_list_lock, st->list_file,
-					LOCK_NO_DEREF);
+	err = hold_lock_file_for_update_timeout(&tables_list_lock,
+						st->list_file,
+						LOCK_NO_DEREF,
+						st->opts.lock_timeout_ms);
 	if (err < 0) {
 		if (errno == EEXIST)
 			err = REFTABLE_LOCK_ERROR;
@@ -1046,19 +1083,47 @@ static int stack_compact_range(struct reftable_stack *st,
 	/*
 	 * Lock all tables in the user-provided range. This is the slice of our
 	 * stack which we'll compact.
+	 *
+	 * Note that we lock tables in reverse order from last to first. The
+	 * intent behind this is to allow a newer process to perform best
+	 * effort compaction of tables that it has added in the case where an
+	 * older process is still busy compacting tables which are preexisting
+	 * from the point of view of the newer process.
 	 */
 	REFTABLE_CALLOC_ARRAY(table_locks, last - first + 1);
-	for (i = first; i <= last; i++) {
-		stack_filename(&table_name, st, reader_name(st->readers[i]));
+	for (i = last + 1; i > first; i--) {
+		stack_filename(&table_name, st, reader_name(st->readers[i - 1]));
 
-		err = hold_lock_file_for_update(&table_locks[i - first],
+		err = hold_lock_file_for_update(&table_locks[nlocks],
 						table_name.buf, LOCK_NO_DEREF);
 		if (err < 0) {
-			if (errno == EEXIST)
+			/*
+			 * When the table is locked already we may do a
+			 * best-effort compaction and compact only the tables
+			 * that we have managed to lock so far. This of course
+			 * requires that we have been able to lock at least two
+			 * tables, otherwise there would be nothing to compact.
+			 * In that case, we return a lock error to our caller.
+			 */
+			if (errno == EEXIST && last - (i - 1) >= 2 &&
+			    flags & STACK_COMPACT_RANGE_BEST_EFFORT) {
+				err = 0;
+				/*
+				 * The subtraction is to offset the index, the
+				 * addition is to only compact up to the table
+				 * of the preceding iteration. They obviously
+				 * cancel each other out, but that may be
+				 * non-obvious when it was omitted.
+				 */
+				first = (i - 1) + 1;
+				break;
+			} else if (errno == EEXIST) {
 				err = REFTABLE_LOCK_ERROR;
-			else
+				goto done;
+			} else {
 				err = REFTABLE_IO_ERROR;
-			goto done;
+				goto done;
+			}
 		}
 
 		/*
@@ -1066,7 +1131,7 @@ static int stack_compact_range(struct reftable_stack *st,
 		 * run into file descriptor exhaustion when we compress a lot
 		 * of tables.
 		 */
-		err = close_lock_file_gently(&table_locks[i - first]);
+		err = close_lock_file_gently(&table_locks[nlocks++]);
 		if (err < 0) {
 			err = REFTABLE_IO_ERROR;
 			goto done;
@@ -1101,8 +1166,10 @@ static int stack_compact_range(struct reftable_stack *st,
 	 * "tables.list". We'll then replace the compacted range of tables with
 	 * the new table.
 	 */
-	err = hold_lock_file_for_update(&tables_list_lock, st->list_file,
-					LOCK_NO_DEREF);
+	err = hold_lock_file_for_update_timeout(&tables_list_lock,
+						st->list_file,
+						LOCK_NO_DEREF,
+						st->opts.lock_timeout_ms);
 	if (err < 0) {
 		if (errno == EEXIST)
 			err = REFTABLE_LOCK_ERROR;
@@ -1120,6 +1187,100 @@ static int stack_compact_range(struct reftable_stack *st,
 	}
 
 	/*
+	 * As we have unlocked the stack while compacting our slice of tables
+	 * it may have happened that a concurrently running process has updated
+	 * the stack while we were compacting. In that case, we need to check
+	 * whether the tables that we have just compacted still exist in the
+	 * stack in the exact same order as we have compacted them.
+	 *
+	 * If they do exist, then it is fine to continue and replace those
+	 * tables with our compacted version. If they don't, then we need to
+	 * abort.
+	 */
+	err = stack_uptodate(st);
+	if (err < 0)
+		goto done;
+	if (err > 0) {
+		ssize_t new_offset = -1;
+		int fd;
+
+		fd = open(st->list_file, O_RDONLY);
+		if (fd < 0) {
+			err = REFTABLE_IO_ERROR;
+			goto done;
+		}
+
+		err = fd_read_lines(fd, &names);
+		close(fd);
+		if (err < 0)
+			goto done;
+
+		/*
+		 * Search for the offset of the first table that we have
+		 * compacted in the updated "tables.list" file.
+		 */
+		for (size_t i = 0; names[i]; i++) {
+			if (strcmp(names[i], st->readers[first]->name))
+				continue;
+
+			/*
+			 * We have found the first entry. Verify that all the
+			 * subsequent tables we have compacted still exist in
+			 * the modified stack in the exact same order as we
+			 * have compacted them.
+			 */
+			for (size_t j = 1; j < last - first + 1; j++) {
+				const char *old = first + j < st->merged->readers_len ?
+					st->readers[first + j]->name : NULL;
+				const char *new = names[i + j];
+
+				/*
+				 * If some entries are missing or in case the tables
+				 * have changed then we need to bail out. Again, this
+				 * shouldn't ever happen because we have locked the
+				 * tables we are compacting.
+				 */
+				if (!old || !new || strcmp(old, new)) {
+					err = REFTABLE_OUTDATED_ERROR;
+					goto done;
+				}
+			}
+
+			new_offset = i;
+			break;
+		}
+
+		/*
+		 * In case we didn't find our compacted tables in the stack we
+		 * need to bail out. In theory, this should have never happened
+		 * because we locked the tables we are compacting.
+		 */
+		if (new_offset < 0) {
+			err = REFTABLE_OUTDATED_ERROR;
+			goto done;
+		}
+
+		/*
+		 * We have found the new range that we want to replace, so
+		 * let's update the range of tables that we want to replace.
+		 */
+		first_to_replace = new_offset;
+		last_to_replace = last + (new_offset - first);
+	} else {
+		/*
+		 * `fd_read_lines()` uses a `NULL` sentinel to indicate that
+		 * the array is at its end. As we use `free_names()` to free
+		 * the array, we need to include this sentinel value here and
+		 * thus have to allocate `readers_len + 1` many entries.
+		 */
+		REFTABLE_CALLOC_ARRAY(names, st->merged->readers_len + 1);
+		for (size_t i = 0; i < st->merged->readers_len; i++)
+			names[i] = xstrdup(st->readers[i]->name);
+		first_to_replace = first;
+		last_to_replace = last;
+	}
+
+	/*
 	 * If the resulting compacted table is not empty, then we need to move
 	 * it into place now.
 	 */
@@ -1141,12 +1302,12 @@ static int stack_compact_range(struct reftable_stack *st,
 	 * have just written. In case the compacted table became empty we
 	 * simply skip writing it.
 	 */
-	for (i = 0; i < first; i++)
-		strbuf_addf(&tables_list_buf, "%s\n", st->readers[i]->name);
+	for (i = 0; i < first_to_replace; i++)
+		strbuf_addf(&tables_list_buf, "%s\n", names[i]);
 	if (!is_empty_table)
 		strbuf_addf(&tables_list_buf, "%s\n", new_table_name.buf);
-	for (i = last + 1; i < st->merged->stack_len; i++)
-		strbuf_addf(&tables_list_buf, "%s\n", st->readers[i]->name);
+	for (i = last_to_replace + 1; names[i]; i++)
+		strbuf_addf(&tables_list_buf, "%s\n", names[i]);
 
 	err = write_in_full(get_lock_file_fd(&tables_list_lock),
 			    tables_list_buf.buf, tables_list_buf.len);
@@ -1183,8 +1344,8 @@ static int stack_compact_range(struct reftable_stack *st,
 	 * Delete the old tables. They may still be in use by concurrent
 	 * readers, so it is expected that unlinking tables may fail.
 	 */
-	for (i = first; i <= last; i++) {
-		struct lock_file *table_lock = &table_locks[i - first];
+	for (i = 0; i < nlocks; i++) {
+		struct lock_file *table_lock = &table_locks[i];
 		char *table_path = get_locked_file_path(table_lock);
 		unlink(table_path);
 		free(table_path);
@@ -1192,34 +1353,28 @@ static int stack_compact_range(struct reftable_stack *st,
 
 done:
 	rollback_lock_file(&tables_list_lock);
-	for (i = first; table_locks && i <= last; i++)
-		rollback_lock_file(&table_locks[i - first]);
+	for (i = 0; table_locks && i < nlocks; i++)
+		rollback_lock_file(&table_locks[i]);
 	reftable_free(table_locks);
 
 	delete_tempfile(&new_table);
 	strbuf_release(&new_table_name);
 	strbuf_release(&new_table_path);
-
 	strbuf_release(&tables_list_buf);
 	strbuf_release(&table_name);
+	free_names(names);
+
+	if (err == REFTABLE_LOCK_ERROR)
+		st->stats.failures++;
+
 	return err;
 }
 
 int reftable_stack_compact_all(struct reftable_stack *st,
 			       struct reftable_log_expiry_config *config)
 {
-	return stack_compact_range(st, 0, st->merged->stack_len ?
-			st->merged->stack_len - 1 : 0, config);
-}
-
-static int stack_compact_range_stats(struct reftable_stack *st,
-				     size_t first, size_t last,
-				     struct reftable_log_expiry_config *config)
-{
-	int err = stack_compact_range(st, first, last, config);
-	if (err == REFTABLE_LOCK_ERROR)
-		st->stats.failures++;
-	return err;
+	size_t last = st->merged->readers_len ? st->merged->readers_len - 1 : 0;
+	return stack_compact_range(st, 0, last, config, 0);
 }
 
 static int segment_size(struct segment *s)
@@ -1305,14 +1460,15 @@ struct segment suggest_compaction_segment(uint64_t *sizes, size_t n,
 
 static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
 {
-	uint64_t *sizes =
-		reftable_calloc(st->merged->stack_len, sizeof(*sizes));
 	int version = (st->opts.hash_id == GIT_SHA1_FORMAT_ID) ? 1 : 2;
 	int overhead = header_size(version) - 1;
-	int i = 0;
-	for (i = 0; i < st->merged->stack_len; i++) {
+	uint64_t *sizes;
+
+	REFTABLE_CALLOC_ARRAY(sizes, st->merged->readers_len);
+
+	for (size_t i = 0; i < st->merged->readers_len; i++)
 		sizes[i] = st->readers[i]->size - overhead;
-	}
+
 	return sizes;
 }
 
@@ -1320,12 +1476,12 @@ int reftable_stack_auto_compact(struct reftable_stack *st)
 {
 	uint64_t *sizes = stack_table_sizes_for_compaction(st);
 	struct segment seg =
-		suggest_compaction_segment(sizes, st->merged->stack_len,
+		suggest_compaction_segment(sizes, st->merged->readers_len,
 					   st->opts.auto_compaction_factor);
 	reftable_free(sizes);
 	if (segment_size(&seg) > 0)
-		return stack_compact_range_stats(st, seg.start, seg.end - 1,
-						 NULL);
+		return stack_compact_range(st, seg.start, seg.end - 1,
+					   NULL, STACK_COMPACT_RANGE_BEST_EFFORT);
 
 	return 0;
 }
@@ -1339,9 +1495,28 @@ reftable_stack_compaction_stats(struct reftable_stack *st)
 int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
 			    struct reftable_ref_record *ref)
 {
-	struct reftable_table tab = { NULL };
-	reftable_table_from_merged_table(&tab, reftable_stack_merged_table(st));
-	return reftable_table_read_ref(&tab, refname, ref);
+	struct reftable_iterator it = { 0 };
+	int ret;
+
+	reftable_merged_table_init_ref_iterator(st->merged, &it);
+	ret = reftable_iterator_seek_ref(&it, refname);
+	if (ret)
+		goto out;
+
+	ret = reftable_iterator_next_ref(&it, ref);
+	if (ret)
+		goto out;
+
+	if (strcmp(ref->refname, refname) ||
+	    reftable_ref_record_is_deletion(ref)) {
+		reftable_ref_record_release(ref);
+		ret = 1;
+		goto out;
+	}
+
+out:
+	reftable_iterator_destroy(&it);
+	return ret;
 }
 
 int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
@@ -1393,12 +1568,12 @@ static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max,
 	if (err < 0)
 		goto done;
 
-	err = reftable_new_reader(&rd, &src, name);
+	err = reftable_reader_new(&rd, &src, name);
 	if (err < 0)
 		goto done;
 
 	update_idx = reftable_reader_max_update_index(rd);
-	reftable_reader_free(rd);
+	reftable_reader_decref(rd);
 
 	if (update_idx <= max) {
 		unlink(table_path.buf);
@@ -1439,7 +1614,7 @@ static int reftable_stack_clean_locked(struct reftable_stack *st)
 int reftable_stack_clean(struct reftable_stack *st)
 {
 	struct reftable_addition *add = NULL;
-	int err = reftable_stack_new_addition(&add, st);
+	int err = reftable_stack_new_addition(&add, st, 0);
 	if (err < 0) {
 		goto done;
 	}
@@ -1455,23 +1630,3 @@ int reftable_stack_clean(struct reftable_stack *st)
 	reftable_addition_destroy(add);
 	return err;
 }
-
-int reftable_stack_print_directory(const char *stackdir, uint32_t hash_id)
-{
-	struct reftable_stack *stack = NULL;
-	struct reftable_write_options opts = { .hash_id = hash_id };
-	struct reftable_merged_table *merged = NULL;
-	struct reftable_table table = { NULL };
-
-	int err = reftable_new_stack(&stack, stackdir, &opts);
-	if (err < 0)
-		goto done;
-
-	merged = reftable_stack_merged_table(stack);
-	reftable_table_from_merged_table(&table, merged);
-	err = reftable_table_print(&table);
-done:
-	if (stack)
-		reftable_stack_destroy(stack);
-	return err;
-}
diff --git a/reftable/stack_test.c b/reftable/stack_test.c
deleted file mode 100644
index e3c11e6..0000000
--- a/reftable/stack_test.c
+++ /dev/null
@@ -1,1034 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "stack.h"
-
-#include "system.h"
-
-#include "reftable-reader.h"
-#include "merged.h"
-#include "basics.h"
-#include "record.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-#include "reader.h"
-
-#include <sys/types.h>
-#include <dirent.h>
-
-static void clear_dir(const char *dirname)
-{
-	struct strbuf path = STRBUF_INIT;
-	strbuf_addstr(&path, dirname);
-	remove_dir_recursively(&path, 0);
-	strbuf_release(&path);
-}
-
-static int count_dir_entries(const char *dirname)
-{
-	DIR *dir = opendir(dirname);
-	int len = 0;
-	struct dirent *d;
-	if (!dir)
-		return 0;
-
-	while ((d = readdir(dir))) {
-		/*
-		 * Besides skipping over "." and "..", we also need to
-		 * skip over other files that have a leading ".". This
-		 * is due to behaviour of NFS, which will rename files
-		 * to ".nfs*" to emulate delete-on-last-close.
-		 *
-		 * In any case this should be fine as the reftable
-		 * library will never write files with leading dots
-		 * anyway.
-		 */
-		if (starts_with(d->d_name, "."))
-			continue;
-		len++;
-	}
-	closedir(dir);
-	return len;
-}
-
-/*
- * Work linenumber into the tempdir, so we can see which tests forget to
- * cleanup.
- */
-static char *get_tmp_template(int linenumber)
-{
-	const char *tmp = getenv("TMPDIR");
-	static char template[1024];
-	snprintf(template, sizeof(template) - 1, "%s/stack_test-%d.XXXXXX",
-		 tmp ? tmp : "/tmp", linenumber);
-	return template;
-}
-
-static char *get_tmp_dir(int linenumber)
-{
-	char *dir = get_tmp_template(linenumber);
-	EXPECT(mkdtemp(dir));
-	return dir;
-}
-
-static void test_read_file(void)
-{
-	char *fn = get_tmp_template(__LINE__);
-	int fd = mkstemp(fn);
-	char out[1024] = "line1\n\nline2\nline3";
-	int n, err;
-	char **names = NULL;
-	const char *want[] = { "line1", "line2", "line3" };
-	int i = 0;
-
-	EXPECT(fd > 0);
-	n = write_in_full(fd, out, strlen(out));
-	EXPECT(n == strlen(out));
-	err = close(fd);
-	EXPECT(err >= 0);
-
-	err = read_lines(fn, &names);
-	EXPECT_ERR(err);
-
-	for (i = 0; names[i]; i++) {
-		EXPECT(0 == strcmp(want[i], names[i]));
-	}
-	free_names(names);
-	(void) remove(fn);
-}
-
-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);
-	return reftable_writer_add_ref(wr, ref);
-}
-
-struct write_log_arg {
-	struct reftable_log_record *log;
-	uint64_t update_index;
-};
-
-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);
-	return reftable_writer_add_log(wr, wla->log);
-}
-
-static void test_reftable_stack_add_one(void)
-{
-	char *dir = get_tmp_dir(__LINE__);
-	struct strbuf scratch = STRBUF_INIT;
-	int mask = umask(002);
-	struct reftable_write_options opts = {
-		.default_permissions = 0660,
-	};
-	struct reftable_stack *st = NULL;
-	int err;
-	struct reftable_ref_record ref = {
-		.refname = (char *) "HEAD",
-		.update_index = 1,
-		.value_type = REFTABLE_REF_SYMREF,
-		.value.symref = (char *) "master",
-	};
-	struct reftable_ref_record dest = { NULL };
-	struct stat stat_result = { 0 };
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_add(st, &write_test_ref, &ref);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_read_ref(st, ref.refname, &dest);
-	EXPECT_ERR(err);
-	EXPECT(0 == strcmp("master", dest.value.symref));
-	EXPECT(st->readers_len > 0);
-
-	printf("testing print functionality:\n");
-	err = reftable_stack_print_directory(dir, GIT_SHA1_FORMAT_ID);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_print_directory(dir, GIT_SHA256_FORMAT_ID);
-	EXPECT(err == REFTABLE_FORMAT_ERROR);
-
-#ifndef GIT_WINDOWS_NATIVE
-	strbuf_addstr(&scratch, dir);
-	strbuf_addstr(&scratch, "/tables.list");
-	err = stat(scratch.buf, &stat_result);
-	EXPECT(!err);
-	EXPECT((stat_result.st_mode & 0777) == opts.default_permissions);
-
-	strbuf_reset(&scratch);
-	strbuf_addstr(&scratch, dir);
-	strbuf_addstr(&scratch, "/");
-	/* do not try at home; not an external API for reftable. */
-	strbuf_addstr(&scratch, st->readers[0]->name);
-	err = stat(scratch.buf, &stat_result);
-	EXPECT(!err);
-	EXPECT((stat_result.st_mode & 0777) == opts.default_permissions);
-#else
-	(void) stat_result;
-#endif
-
-	reftable_ref_record_release(&dest);
-	reftable_stack_destroy(st);
-	strbuf_release(&scratch);
-	clear_dir(dir);
-	umask(mask);
-}
-
-static void test_reftable_stack_uptodate(void)
-{
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st1 = NULL;
-	struct reftable_stack *st2 = NULL;
-	char *dir = get_tmp_dir(__LINE__);
-
-	int err;
-	struct reftable_ref_record ref1 = {
-		.refname = (char *) "HEAD",
-		.update_index = 1,
-		.value_type = REFTABLE_REF_SYMREF,
-		.value.symref = (char *) "master",
-	};
-	struct reftable_ref_record ref2 = {
-		.refname = (char *) "branch2",
-		.update_index = 2,
-		.value_type = REFTABLE_REF_SYMREF,
-		.value.symref = (char *) "master",
-	};
-
-
-	/* simulate multi-process access to the same stack
-	   by creating two stacks for the same directory.
-	 */
-	err = reftable_new_stack(&st1, dir, &opts);
-	EXPECT_ERR(err);
-
-	err = reftable_new_stack(&st2, dir, &opts);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_add(st1, &write_test_ref, &ref1);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_add(st2, &write_test_ref, &ref2);
-	EXPECT(err == REFTABLE_OUTDATED_ERROR);
-
-	err = reftable_stack_reload(st2);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_add(st2, &write_test_ref, &ref2);
-	EXPECT_ERR(err);
-	reftable_stack_destroy(st1);
-	reftable_stack_destroy(st2);
-	clear_dir(dir);
-}
-
-static void test_reftable_stack_transaction_api(void)
-{
-	char *dir = get_tmp_dir(__LINE__);
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st = NULL;
-	int err;
-	struct reftable_addition *add = NULL;
-
-	struct reftable_ref_record ref = {
-		.refname = (char *) "HEAD",
-		.update_index = 1,
-		.value_type = REFTABLE_REF_SYMREF,
-		.value.symref = (char *) "master",
-	};
-	struct reftable_ref_record dest = { NULL };
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	reftable_addition_destroy(add);
-
-	err = reftable_stack_new_addition(&add, st);
-	EXPECT_ERR(err);
-
-	err = reftable_addition_add(add, &write_test_ref, &ref);
-	EXPECT_ERR(err);
-
-	err = reftable_addition_commit(add);
-	EXPECT_ERR(err);
-
-	reftable_addition_destroy(add);
-
-	err = reftable_stack_read_ref(st, ref.refname, &dest);
-	EXPECT_ERR(err);
-	EXPECT(REFTABLE_REF_SYMREF == dest.value_type);
-	EXPECT(0 == strcmp("master", dest.value.symref));
-
-	reftable_ref_record_release(&dest);
-	reftable_stack_destroy(st);
-	clear_dir(dir);
-}
-
-static void test_reftable_stack_transaction_api_performs_auto_compaction(void)
-{
-	char *dir = get_tmp_dir(__LINE__);
-	struct reftable_write_options opts = {0};
-	struct reftable_addition *add = NULL;
-	struct reftable_stack *st = NULL;
-	int i, n = 20, err;
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	for (i = 0; i <= n; i++) {
-		struct reftable_ref_record ref = {
-			.update_index = reftable_stack_next_update_index(st),
-			.value_type = REFTABLE_REF_SYMREF,
-			.value.symref = (char *) "master",
-		};
-		char name[100];
-
-		snprintf(name, sizeof(name), "branch%04d", i);
-		ref.refname = name;
-
-		/*
-		 * Disable auto-compaction for all but the last runs. Like this
-		 * we can ensure that we indeed honor this setting and have
-		 * better control over when exactly auto compaction runs.
-		 */
-		st->opts.disable_auto_compact = i != n;
-
-		err = reftable_stack_new_addition(&add, st);
-		EXPECT_ERR(err);
-
-		err = reftable_addition_add(add, &write_test_ref, &ref);
-		EXPECT_ERR(err);
-
-		err = reftable_addition_commit(add);
-		EXPECT_ERR(err);
-
-		reftable_addition_destroy(add);
-
-		/*
-		 * The stack length should grow continuously for all runs where
-		 * auto compaction is disabled. When enabled, we should merge
-		 * all tables in the stack.
-		 */
-		if (i != n)
-			EXPECT(st->merged->stack_len == i + 1);
-		else
-			EXPECT(st->merged->stack_len == 1);
-	}
-
-	reftable_stack_destroy(st);
-	clear_dir(dir);
-}
-
-static void test_reftable_stack_auto_compaction_fails_gracefully(void)
-{
-	struct reftable_ref_record ref = {
-		.refname = (char *) "refs/heads/master",
-		.update_index = 1,
-		.value_type = REFTABLE_REF_VAL1,
-		.value.val1 = {0x01},
-	};
-	struct reftable_write_options opts = {0};
-	struct reftable_stack *st;
-	struct strbuf table_path = STRBUF_INIT;
-	char *dir = get_tmp_dir(__LINE__);
-	int err;
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_add(st, write_test_ref, &ref);
-	EXPECT_ERR(err);
-	EXPECT(st->merged->stack_len == 1);
-	EXPECT(st->stats.attempts == 0);
-	EXPECT(st->stats.failures == 0);
-
-	/*
-	 * Lock the newly written table such that it cannot be compacted.
-	 * Adding a new table to the stack should not be impacted by this, even
-	 * though auto-compaction will now fail.
-	 */
-	strbuf_addf(&table_path, "%s/%s.lock", dir, st->readers[0]->name);
-	write_file_buf(table_path.buf, "", 0);
-
-	ref.update_index = 2;
-	err = reftable_stack_add(st, write_test_ref, &ref);
-	EXPECT_ERR(err);
-	EXPECT(st->merged->stack_len == 2);
-	EXPECT(st->stats.attempts == 1);
-	EXPECT(st->stats.failures == 1);
-
-	reftable_stack_destroy(st);
-	strbuf_release(&table_path);
-	clear_dir(dir);
-}
-
-static int write_error(struct reftable_writer *wr, void *arg)
-{
-	return *((int *)arg);
-}
-
-static void test_reftable_stack_update_index_check(void)
-{
-	char *dir = get_tmp_dir(__LINE__);
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st = NULL;
-	int err;
-	struct reftable_ref_record ref1 = {
-		.refname = (char *) "name1",
-		.update_index = 1,
-		.value_type = REFTABLE_REF_SYMREF,
-		.value.symref = (char *) "master",
-	};
-	struct reftable_ref_record ref2 = {
-		.refname = (char *) "name2",
-		.update_index = 1,
-		.value_type = REFTABLE_REF_SYMREF,
-		.value.symref = (char *) "master",
-	};
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_add(st, &write_test_ref, &ref1);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_add(st, &write_test_ref, &ref2);
-	EXPECT(err == REFTABLE_API_ERROR);
-	reftable_stack_destroy(st);
-	clear_dir(dir);
-}
-
-static void test_reftable_stack_lock_failure(void)
-{
-	char *dir = get_tmp_dir(__LINE__);
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st = NULL;
-	int err, i;
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-	for (i = -1; i != REFTABLE_EMPTY_TABLE_ERROR; i--) {
-		err = reftable_stack_add(st, &write_error, &i);
-		EXPECT(err == i);
-	}
-
-	reftable_stack_destroy(st);
-	clear_dir(dir);
-}
-
-static void test_reftable_stack_add(void)
-{
-	int i = 0;
-	int err = 0;
-	struct reftable_write_options opts = {
-		.exact_log_message = 1,
-		.default_permissions = 0660,
-		.disable_auto_compact = 1,
-	};
-	struct reftable_stack *st = NULL;
-	char *dir = get_tmp_dir(__LINE__);
-	struct reftable_ref_record refs[2] = { { NULL } };
-	struct reftable_log_record logs[2] = { { NULL } };
-	struct strbuf path = STRBUF_INIT;
-	struct stat stat_result;
-	int N = ARRAY_SIZE(refs);
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	for (i = 0; i < N; i++) {
-		char buf[256];
-		snprintf(buf, sizeof(buf), "branch%02d", i);
-		refs[i].refname = xstrdup(buf);
-		refs[i].update_index = i + 1;
-		refs[i].value_type = REFTABLE_REF_VAL1;
-		set_test_hash(refs[i].value.val1, i);
-
-		logs[i].refname = xstrdup(buf);
-		logs[i].update_index = N + i + 1;
-		logs[i].value_type = REFTABLE_LOG_UPDATE;
-		logs[i].value.update.email = xstrdup("identity@invalid");
-		set_test_hash(logs[i].value.update.new_hash, i);
-	}
-
-	for (i = 0; i < N; i++) {
-		int err = reftable_stack_add(st, &write_test_ref, &refs[i]);
-		EXPECT_ERR(err);
-	}
-
-	for (i = 0; i < N; i++) {
-		struct write_log_arg arg = {
-			.log = &logs[i],
-			.update_index = reftable_stack_next_update_index(st),
-		};
-		int err = reftable_stack_add(st, &write_test_log, &arg);
-		EXPECT_ERR(err);
-	}
-
-	err = reftable_stack_compact_all(st, NULL);
-	EXPECT_ERR(err);
-
-	for (i = 0; i < N; i++) {
-		struct reftable_ref_record dest = { NULL };
-
-		int err = reftable_stack_read_ref(st, refs[i].refname, &dest);
-		EXPECT_ERR(err);
-		EXPECT(reftable_ref_record_equal(&dest, refs + i,
-						 GIT_SHA1_RAWSZ));
-		reftable_ref_record_release(&dest);
-	}
-
-	for (i = 0; i < N; i++) {
-		struct reftable_log_record dest = { NULL };
-		int err = reftable_stack_read_log(st, refs[i].refname, &dest);
-		EXPECT_ERR(err);
-		EXPECT(reftable_log_record_equal(&dest, logs + i,
-						 GIT_SHA1_RAWSZ));
-		reftable_log_record_release(&dest);
-	}
-
-#ifndef GIT_WINDOWS_NATIVE
-	strbuf_addstr(&path, dir);
-	strbuf_addstr(&path, "/tables.list");
-	err = stat(path.buf, &stat_result);
-	EXPECT(!err);
-	EXPECT((stat_result.st_mode & 0777) == opts.default_permissions);
-
-	strbuf_reset(&path);
-	strbuf_addstr(&path, dir);
-	strbuf_addstr(&path, "/");
-	/* do not try at home; not an external API for reftable. */
-	strbuf_addstr(&path, st->readers[0]->name);
-	err = stat(path.buf, &stat_result);
-	EXPECT(!err);
-	EXPECT((stat_result.st_mode & 0777) == opts.default_permissions);
-#else
-	(void) stat_result;
-#endif
-
-	/* cleanup */
-	reftable_stack_destroy(st);
-	for (i = 0; i < N; i++) {
-		reftable_ref_record_release(&refs[i]);
-		reftable_log_record_release(&logs[i]);
-	}
-	strbuf_release(&path);
-	clear_dir(dir);
-}
-
-static void test_reftable_stack_log_normalize(void)
-{
-	int err = 0;
-	struct reftable_write_options opts = {
-		0,
-	};
-	struct reftable_stack *st = NULL;
-	char *dir = get_tmp_dir(__LINE__);
-	struct reftable_log_record input = {
-		.refname = (char *) "branch",
-		.update_index = 1,
-		.value_type = REFTABLE_LOG_UPDATE,
-		.value = {
-			.update = {
-				.new_hash = { 1 },
-				.old_hash = { 2 },
-			},
-		},
-	};
-	struct reftable_log_record dest = {
-		.update_index = 0,
-	};
-	struct write_log_arg arg = {
-		.log = &input,
-		.update_index = 1,
-	};
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	input.value.update.message = (char *) "one\ntwo";
-	err = reftable_stack_add(st, &write_test_log, &arg);
-	EXPECT(err == REFTABLE_API_ERROR);
-
-	input.value.update.message = (char *) "one";
-	err = reftable_stack_add(st, &write_test_log, &arg);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_read_log(st, input.refname, &dest);
-	EXPECT_ERR(err);
-	EXPECT(0 == strcmp(dest.value.update.message, "one\n"));
-
-	input.value.update.message = (char *) "two\n";
-	arg.update_index = 2;
-	err = reftable_stack_add(st, &write_test_log, &arg);
-	EXPECT_ERR(err);
-	err = reftable_stack_read_log(st, input.refname, &dest);
-	EXPECT_ERR(err);
-	EXPECT(0 == strcmp(dest.value.update.message, "two\n"));
-
-	/* cleanup */
-	reftable_stack_destroy(st);
-	reftable_log_record_release(&dest);
-	clear_dir(dir);
-}
-
-static void test_reftable_stack_tombstone(void)
-{
-	int i = 0;
-	char *dir = get_tmp_dir(__LINE__);
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st = NULL;
-	int err;
-	struct reftable_ref_record refs[2] = { { NULL } };
-	struct reftable_log_record logs[2] = { { NULL } };
-	int N = ARRAY_SIZE(refs);
-	struct reftable_ref_record dest = { NULL };
-	struct reftable_log_record log_dest = { NULL };
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	/* even entries add the refs, odd entries delete them. */
-	for (i = 0; i < N; i++) {
-		const char *buf = "branch";
-		refs[i].refname = xstrdup(buf);
-		refs[i].update_index = i + 1;
-		if (i % 2 == 0) {
-			refs[i].value_type = REFTABLE_REF_VAL1;
-			set_test_hash(refs[i].value.val1, i);
-		}
-
-		logs[i].refname = xstrdup(buf);
-		/* update_index is part of the key. */
-		logs[i].update_index = 42;
-		if (i % 2 == 0) {
-			logs[i].value_type = REFTABLE_LOG_UPDATE;
-			set_test_hash(logs[i].value.update.new_hash, i);
-			logs[i].value.update.email =
-				xstrdup("identity@invalid");
-		}
-	}
-	for (i = 0; i < N; i++) {
-		int err = reftable_stack_add(st, &write_test_ref, &refs[i]);
-		EXPECT_ERR(err);
-	}
-
-	for (i = 0; i < N; i++) {
-		struct write_log_arg arg = {
-			.log = &logs[i],
-			.update_index = reftable_stack_next_update_index(st),
-		};
-		int err = reftable_stack_add(st, &write_test_log, &arg);
-		EXPECT_ERR(err);
-	}
-
-	err = reftable_stack_read_ref(st, "branch", &dest);
-	EXPECT(err == 1);
-	reftable_ref_record_release(&dest);
-
-	err = reftable_stack_read_log(st, "branch", &log_dest);
-	EXPECT(err == 1);
-	reftable_log_record_release(&log_dest);
-
-	err = reftable_stack_compact_all(st, NULL);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_read_ref(st, "branch", &dest);
-	EXPECT(err == 1);
-
-	err = reftable_stack_read_log(st, "branch", &log_dest);
-	EXPECT(err == 1);
-	reftable_ref_record_release(&dest);
-	reftable_log_record_release(&log_dest);
-
-	/* cleanup */
-	reftable_stack_destroy(st);
-	for (i = 0; i < N; i++) {
-		reftable_ref_record_release(&refs[i]);
-		reftable_log_record_release(&logs[i]);
-	}
-	clear_dir(dir);
-}
-
-static void test_reftable_stack_hash_id(void)
-{
-	char *dir = get_tmp_dir(__LINE__);
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st = NULL;
-	int err;
-
-	struct reftable_ref_record ref = {
-		.refname = (char *) "master",
-		.value_type = REFTABLE_REF_SYMREF,
-		.value.symref = (char *) "target",
-		.update_index = 1,
-	};
-	struct reftable_write_options opts32 = { .hash_id = GIT_SHA256_FORMAT_ID };
-	struct reftable_stack *st32 = NULL;
-	struct reftable_write_options opts_default = { 0 };
-	struct reftable_stack *st_default = NULL;
-	struct reftable_ref_record dest = { NULL };
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_add(st, &write_test_ref, &ref);
-	EXPECT_ERR(err);
-
-	/* can't read it with the wrong hash ID. */
-	err = reftable_new_stack(&st32, dir, &opts32);
-	EXPECT(err == REFTABLE_FORMAT_ERROR);
-
-	/* check that we can read it back with default opts too. */
-	err = reftable_new_stack(&st_default, dir, &opts_default);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_read_ref(st_default, "master", &dest);
-	EXPECT_ERR(err);
-
-	EXPECT(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
-	reftable_ref_record_release(&dest);
-	reftable_stack_destroy(st);
-	reftable_stack_destroy(st_default);
-	clear_dir(dir);
-}
-
-static void test_suggest_compaction_segment(void)
-{
-	uint64_t sizes[] = { 512, 64, 17, 16, 9, 9, 9, 16, 2, 16 };
-	struct segment min =
-		suggest_compaction_segment(sizes, ARRAY_SIZE(sizes), 2);
-	EXPECT(min.start == 1);
-	EXPECT(min.end == 10);
-}
-
-static void test_suggest_compaction_segment_nothing(void)
-{
-	uint64_t sizes[] = { 64, 32, 16, 8, 4, 2 };
-	struct segment result =
-		suggest_compaction_segment(sizes, ARRAY_SIZE(sizes), 2);
-	EXPECT(result.start == result.end);
-}
-
-static void test_reflog_expire(void)
-{
-	char *dir = get_tmp_dir(__LINE__);
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st = NULL;
-	struct reftable_log_record logs[20] = { { NULL } };
-	int N = ARRAY_SIZE(logs) - 1;
-	int i = 0;
-	int err;
-	struct reftable_log_expiry_config expiry = {
-		.time = 10,
-	};
-	struct reftable_log_record log = { NULL };
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	for (i = 1; i <= N; i++) {
-		char buf[256];
-		snprintf(buf, sizeof(buf), "branch%02d", i);
-
-		logs[i].refname = xstrdup(buf);
-		logs[i].update_index = i;
-		logs[i].value_type = REFTABLE_LOG_UPDATE;
-		logs[i].value.update.time = i;
-		logs[i].value.update.email = xstrdup("identity@invalid");
-		set_test_hash(logs[i].value.update.new_hash, i);
-	}
-
-	for (i = 1; i <= N; i++) {
-		struct write_log_arg arg = {
-			.log = &logs[i],
-			.update_index = reftable_stack_next_update_index(st),
-		};
-		int err = reftable_stack_add(st, &write_test_log, &arg);
-		EXPECT_ERR(err);
-	}
-
-	err = reftable_stack_compact_all(st, NULL);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_compact_all(st, &expiry);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_read_log(st, logs[9].refname, &log);
-	EXPECT(err == 1);
-
-	err = reftable_stack_read_log(st, logs[11].refname, &log);
-	EXPECT_ERR(err);
-
-	expiry.min_update_index = 15;
-	err = reftable_stack_compact_all(st, &expiry);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_read_log(st, logs[14].refname, &log);
-	EXPECT(err == 1);
-
-	err = reftable_stack_read_log(st, logs[16].refname, &log);
-	EXPECT_ERR(err);
-
-	/* cleanup */
-	reftable_stack_destroy(st);
-	for (i = 0; i <= N; i++) {
-		reftable_log_record_release(&logs[i]);
-	}
-	clear_dir(dir);
-	reftable_log_record_release(&log);
-}
-
-static int write_nothing(struct reftable_writer *wr, void *arg)
-{
-	reftable_writer_set_limits(wr, 1, 1);
-	return 0;
-}
-
-static void test_empty_add(void)
-{
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st = NULL;
-	int err;
-	char *dir = get_tmp_dir(__LINE__);
-	struct reftable_stack *st2 = NULL;
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_add(st, &write_nothing, NULL);
-	EXPECT_ERR(err);
-
-	err = reftable_new_stack(&st2, dir, &opts);
-	EXPECT_ERR(err);
-	clear_dir(dir);
-	reftable_stack_destroy(st);
-	reftable_stack_destroy(st2);
-}
-
-static int fastlog2(uint64_t sz)
-{
-	int l = 0;
-	if (sz == 0)
-		return 0;
-	for (; sz; sz /= 2)
-		l++;
-	return l - 1;
-}
-
-static void test_reftable_stack_auto_compaction(void)
-{
-	struct reftable_write_options opts = {
-		.disable_auto_compact = 1,
-	};
-	struct reftable_stack *st = NULL;
-	char *dir = get_tmp_dir(__LINE__);
-	int err, i;
-	int N = 100;
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	for (i = 0; i < N; i++) {
-		char name[100];
-		struct reftable_ref_record ref = {
-			.refname = name,
-			.update_index = reftable_stack_next_update_index(st),
-			.value_type = REFTABLE_REF_SYMREF,
-			.value.symref = (char *) "master",
-		};
-		snprintf(name, sizeof(name), "branch%04d", i);
-
-		err = reftable_stack_add(st, &write_test_ref, &ref);
-		EXPECT_ERR(err);
-
-		err = reftable_stack_auto_compact(st);
-		EXPECT_ERR(err);
-		EXPECT(i < 3 || st->merged->stack_len < 2 * fastlog2(i));
-	}
-
-	EXPECT(reftable_stack_compaction_stats(st)->entries_written <
-	       (uint64_t)(N * fastlog2(N)));
-
-	reftable_stack_destroy(st);
-	clear_dir(dir);
-}
-
-static void test_reftable_stack_add_performs_auto_compaction(void)
-{
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st = NULL;
-	struct strbuf refname = STRBUF_INIT;
-	char *dir = get_tmp_dir(__LINE__);
-	int err, i, n = 20;
-
-	err = reftable_new_stack(&st, dir, &opts);
-	EXPECT_ERR(err);
-
-	for (i = 0; i <= n; i++) {
-		struct reftable_ref_record ref = {
-			.update_index = reftable_stack_next_update_index(st),
-			.value_type = REFTABLE_REF_SYMREF,
-			.value.symref = (char *) "master",
-		};
-
-		/*
-		 * Disable auto-compaction for all but the last runs. Like this
-		 * we can ensure that we indeed honor this setting and have
-		 * better control over when exactly auto compaction runs.
-		 */
-		st->opts.disable_auto_compact = i != n;
-
-		strbuf_reset(&refname);
-		strbuf_addf(&refname, "branch-%04d", i);
-		ref.refname = refname.buf;
-
-		err = reftable_stack_add(st, &write_test_ref, &ref);
-		EXPECT_ERR(err);
-
-		/*
-		 * The stack length should grow continuously for all runs where
-		 * auto compaction is disabled. When enabled, we should merge
-		 * all tables in the stack.
-		 */
-		if (i != n)
-			EXPECT(st->merged->stack_len == i + 1);
-		else
-			EXPECT(st->merged->stack_len == 1);
-	}
-
-	reftable_stack_destroy(st);
-	strbuf_release(&refname);
-	clear_dir(dir);
-}
-
-static void test_reftable_stack_compaction_concurrent(void)
-{
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st1 = NULL, *st2 = NULL;
-	char *dir = get_tmp_dir(__LINE__);
-	int err, i;
-	int N = 3;
-
-	err = reftable_new_stack(&st1, dir, &opts);
-	EXPECT_ERR(err);
-
-	for (i = 0; i < N; i++) {
-		char name[100];
-		struct reftable_ref_record ref = {
-			.refname = name,
-			.update_index = reftable_stack_next_update_index(st1),
-			.value_type = REFTABLE_REF_SYMREF,
-			.value.symref = (char *) "master",
-		};
-		snprintf(name, sizeof(name), "branch%04d", i);
-
-		err = reftable_stack_add(st1, &write_test_ref, &ref);
-		EXPECT_ERR(err);
-	}
-
-	err = reftable_new_stack(&st2, dir, &opts);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_compact_all(st1, NULL);
-	EXPECT_ERR(err);
-
-	reftable_stack_destroy(st1);
-	reftable_stack_destroy(st2);
-
-	EXPECT(count_dir_entries(dir) == 2);
-	clear_dir(dir);
-}
-
-static void unclean_stack_close(struct reftable_stack *st)
-{
-	/* break abstraction boundary to simulate unclean shutdown. */
-	int i = 0;
-	for (; i < st->readers_len; i++) {
-		reftable_reader_free(st->readers[i]);
-	}
-	st->readers_len = 0;
-	FREE_AND_NULL(st->readers);
-}
-
-static void test_reftable_stack_compaction_concurrent_clean(void)
-{
-	struct reftable_write_options opts = { 0 };
-	struct reftable_stack *st1 = NULL, *st2 = NULL, *st3 = NULL;
-	char *dir = get_tmp_dir(__LINE__);
-	int err, i;
-	int N = 3;
-
-	err = reftable_new_stack(&st1, dir, &opts);
-	EXPECT_ERR(err);
-
-	for (i = 0; i < N; i++) {
-		char name[100];
-		struct reftable_ref_record ref = {
-			.refname = name,
-			.update_index = reftable_stack_next_update_index(st1),
-			.value_type = REFTABLE_REF_SYMREF,
-			.value.symref = (char *) "master",
-		};
-		snprintf(name, sizeof(name), "branch%04d", i);
-
-		err = reftable_stack_add(st1, &write_test_ref, &ref);
-		EXPECT_ERR(err);
-	}
-
-	err = reftable_new_stack(&st2, dir, &opts);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_compact_all(st1, NULL);
-	EXPECT_ERR(err);
-
-	unclean_stack_close(st1);
-	unclean_stack_close(st2);
-
-	err = reftable_new_stack(&st3, dir, &opts);
-	EXPECT_ERR(err);
-
-	err = reftable_stack_clean(st3);
-	EXPECT_ERR(err);
-	EXPECT(count_dir_entries(dir) == 2);
-
-	reftable_stack_destroy(st1);
-	reftable_stack_destroy(st2);
-	reftable_stack_destroy(st3);
-
-	clear_dir(dir);
-}
-
-int stack_test_main(int argc, const char *argv[])
-{
-	RUN_TEST(test_empty_add);
-	RUN_TEST(test_read_file);
-	RUN_TEST(test_reflog_expire);
-	RUN_TEST(test_reftable_stack_add);
-	RUN_TEST(test_reftable_stack_add_one);
-	RUN_TEST(test_reftable_stack_auto_compaction);
-	RUN_TEST(test_reftable_stack_add_performs_auto_compaction);
-	RUN_TEST(test_reftable_stack_compaction_concurrent);
-	RUN_TEST(test_reftable_stack_compaction_concurrent_clean);
-	RUN_TEST(test_reftable_stack_hash_id);
-	RUN_TEST(test_reftable_stack_lock_failure);
-	RUN_TEST(test_reftable_stack_log_normalize);
-	RUN_TEST(test_reftable_stack_tombstone);
-	RUN_TEST(test_reftable_stack_transaction_api);
-	RUN_TEST(test_reftable_stack_transaction_api_performs_auto_compaction);
-	RUN_TEST(test_reftable_stack_auto_compaction_fails_gracefully);
-	RUN_TEST(test_reftable_stack_update_index_check);
-	RUN_TEST(test_reftable_stack_uptodate);
-	RUN_TEST(test_suggest_compaction_segment);
-	RUN_TEST(test_suggest_compaction_segment_nothing);
-	return 0;
-}
diff --git a/reftable/test_framework.c b/reftable/test_framework.c
deleted file mode 100644
index 4066924..0000000
--- a/reftable/test_framework.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "system.h"
-#include "test_framework.h"
-
-
-void set_test_hash(uint8_t *p, int i)
-{
-	memset(p, (uint8_t)i, hash_size(GIT_SHA1_FORMAT_ID));
-}
-
-ssize_t strbuf_add_void(void *b, const void *data, size_t sz)
-{
-	strbuf_add(b, data, sz);
-	return sz;
-}
-
-int noop_flush(void *arg)
-{
-	return 0;
-}
diff --git a/reftable/test_framework.h b/reftable/test_framework.h
deleted file mode 100644
index 687390f..0000000
--- a/reftable/test_framework.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef TEST_FRAMEWORK_H
-#define TEST_FRAMEWORK_H
-
-#include "system.h"
-#include "reftable-error.h"
-
-#define EXPECT_ERR(c)                                                          \
-	do {                                                                   \
-		if (c != 0) {                                                  \
-			fflush(stderr);                                        \
-			fflush(stdout);                                        \
-			fprintf(stderr, "%s: %d: error == %d (%s), want 0\n",  \
-				__FILE__, __LINE__, c, reftable_error_str(c)); \
-			abort();                                               \
-		}                                                              \
-	} while (0)
-
-#define EXPECT_STREQ(a, b)                                                       \
-	do {                                                                     \
-		if (strcmp(a, b)) {                                              \
-			fflush(stderr);                                          \
-			fflush(stdout);                                          \
-			fprintf(stderr, "%s:%d: %s (%s) != %s (%s)\n", __FILE__, \
-				__LINE__, #a, a, #b, b);                         \
-			abort();                                                 \
-		}                                                                \
-	} while (0)
-
-#define EXPECT(c)                                                                  \
-	do {                                                                       \
-		if (!(c)) {                                                        \
-			fflush(stderr);                                            \
-			fflush(stdout);                                            \
-			fprintf(stderr, "%s: %d: failed assertion %s\n", __FILE__, \
-				__LINE__, #c);                                     \
-			abort();                                                   \
-		}                                                                  \
-	} while (0)
-
-#define RUN_TEST(f)                          \
-	fprintf(stderr, "running %s\n", #f); \
-	fflush(stderr);                      \
-	f();
-
-void set_test_hash(uint8_t *p, int i);
-
-/* Like strbuf_add, but suitable for passing to reftable_new_writer
- */
-ssize_t strbuf_add_void(void *b, const void *data, size_t sz);
-
-int noop_flush(void *);
-
-#endif
diff --git a/reftable/tree.c b/reftable/tree.c
index 528f33a..5ffb2e0 100644
--- a/reftable/tree.c
+++ b/reftable/tree.c
@@ -39,25 +39,20 @@ struct tree_node *tree_search(void *key, struct tree_node **rootp,
 void infix_walk(struct tree_node *t, void (*action)(void *arg, void *key),
 		void *arg)
 {
-	if (t->left) {
+	if (t->left)
 		infix_walk(t->left, action, arg);
-	}
 	action(arg, t->key);
-	if (t->right) {
+	if (t->right)
 		infix_walk(t->right, action, arg);
-	}
 }
 
 void tree_free(struct tree_node *t)
 {
-	if (!t) {
+	if (!t)
 		return;
-	}
-	if (t->left) {
+	if (t->left)
 		tree_free(t->left);
-	}
-	if (t->right) {
+	if (t->right)
 		tree_free(t->right);
-	}
 	reftable_free(t);
 }
diff --git a/reftable/tree_test.c b/reftable/tree_test.c
deleted file mode 100644
index 6961a65..0000000
--- a/reftable/tree_test.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "system.h"
-#include "tree.h"
-
-#include "test_framework.h"
-#include "reftable-tests.h"
-
-static int test_compare(const void *a, const void *b)
-{
-	return (char *)a - (char *)b;
-}
-
-struct curry {
-	void *last;
-};
-
-static void check_increasing(void *arg, void *key)
-{
-	struct curry *c = arg;
-	if (c->last) {
-		EXPECT(test_compare(c->last, key) < 0);
-	}
-	c->last = key;
-}
-
-static void test_tree(void)
-{
-	struct tree_node *root = NULL;
-
-	void *values[11] = { NULL };
-	struct tree_node *nodes[11] = { NULL };
-	int i = 1;
-	struct curry c = { NULL };
-	do {
-		nodes[i] = tree_search(values + i, &root, &test_compare, 1);
-		i = (i * 7) % 11;
-	} while (i != 1);
-
-	for (i = 1; i < ARRAY_SIZE(nodes); i++) {
-		EXPECT(values + i == nodes[i]->key);
-		EXPECT(nodes[i] ==
-		       tree_search(values + i, &root, &test_compare, 0));
-	}
-
-	infix_walk(root, check_increasing, &c);
-	tree_free(root);
-}
-
-int tree_test_main(int argc, const char *argv[])
-{
-	RUN_TEST(test_tree);
-	return 0;
-}
diff --git a/reftable/writer.c b/reftable/writer.c
index 45b3e9c..9d5e607 100644
--- a/reftable/writer.c
+++ b/reftable/writer.c
@@ -544,7 +544,7 @@ static void write_object_record(void *void_arg, void *key)
 done:;
 }
 
-static void object_record_free(void *void_arg, void *key)
+static void object_record_free(void *void_arg UNUSED, void *key)
 {
 	struct obj_index_tree_node *entry = key;
 
diff --git a/remote-curl.c b/remote-curl.c
index 4adcf25..9a71e04 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -347,7 +347,7 @@ static struct ref *parse_info_refs(struct discovery *heads)
 		ref->next = refs;
 		refs = ref;
 	} else {
-		free(ref);
+		free_one_ref(ref);
 	}
 
 	return refs;
diff --git a/remote.c b/remote.c
index f43cf5e..e291e8f 100644
--- a/remote.c
+++ b/remote.c
@@ -243,6 +243,17 @@ static struct branch *make_branch(struct remote_state *remote_state,
 	return ret;
 }
 
+static void branch_release(struct branch *branch)
+{
+	free((char *)branch->name);
+	free((char *)branch->refname);
+	free(branch->remote_name);
+	free(branch->pushremote_name);
+	for (int i = 0; i < branch->merge_nr; i++)
+		refspec_item_clear(branch->merge[i]);
+	free(branch->merge);
+}
+
 static struct rewrite *make_rewrite(struct rewrites *r,
 				    const char *base, size_t len)
 {
@@ -263,6 +274,14 @@ static struct rewrite *make_rewrite(struct rewrites *r,
 	return ret;
 }
 
+static void rewrites_release(struct rewrites *r)
+{
+	for (int i = 0; i < r->rewrite_nr; i++)
+		free((char *)r->rewrite[i]->base);
+	free(r->rewrite);
+	memset(r, 0, sizeof(*r));
+}
+
 static void add_instead_of(struct rewrite *rewrite, const char *instead_of)
 {
 	ALLOC_GROW(rewrite->instead_of, rewrite->instead_of_nr + 1, rewrite->instead_of_alloc);
@@ -373,8 +392,10 @@ static int handle_config(const char *key, const char *value,
 			return -1;
 		branch = make_branch(remote_state, name, namelen);
 		if (!strcmp(subkey, "remote")) {
+			FREE_AND_NULL(branch->remote_name);
 			return git_config_string(&branch->remote_name, key, value);
 		} else if (!strcmp(subkey, "pushremote")) {
+			FREE_AND_NULL(branch->pushremote_name);
 			return git_config_string(&branch->pushremote_name, key, value);
 		} else if (!strcmp(subkey, "merge")) {
 			if (!value)
@@ -406,9 +427,11 @@ static int handle_config(const char *key, const char *value,
 		return 0;
 
 	/* Handle remote.* variables */
-	if (!name && !strcmp(subkey, "pushdefault"))
+	if (!name && !strcmp(subkey, "pushdefault")) {
+		FREE_AND_NULL(remote_state->pushremote_name);
 		return git_config_string(&remote_state->pushremote_name, key,
 					 value);
+	}
 
 	if (!name)
 		return 0;
@@ -475,12 +498,15 @@ static int handle_config(const char *key, const char *value,
 		else if (!strcmp(value, "--tags"))
 			remote->fetch_tags = 2;
 	} else if (!strcmp(subkey, "proxy")) {
+		FREE_AND_NULL(remote->http_proxy);
 		return git_config_string(&remote->http_proxy,
 					 key, value);
 	} else if (!strcmp(subkey, "proxyauthmethod")) {
+		FREE_AND_NULL(remote->http_proxy_authmethod);
 		return git_config_string(&remote->http_proxy_authmethod,
 					 key, value);
 	} else if (!strcmp(subkey, "vcs")) {
+		FREE_AND_NULL(remote->foreign_vcs);
 		return git_config_string(&remote->foreign_vcs, key, value);
 	}
 	return 0;
@@ -499,6 +525,7 @@ static void alias_all_urls(struct remote_state *remote_state)
 			if (alias)
 				strvec_replace(&remote_state->remotes[i]->pushurl,
 					       j, alias);
+			free(alias);
 		}
 		add_pushurl_aliases = remote_state->remotes[i]->pushurl.nr == 0;
 		for (j = 0; j < remote_state->remotes[i]->url.nr; j++) {
@@ -512,6 +539,7 @@ static void alias_all_urls(struct remote_state *remote_state)
 			if (alias)
 				strvec_replace(&remote_state->remotes[i]->url,
 					       j, alias);
+			free(alias);
 		}
 	}
 }
@@ -604,7 +632,7 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit)
 static struct remote *remotes_remote_get(struct remote_state *remote_state,
 					 const char *name);
 
-const char *remote_ref_for_branch(struct branch *branch, int for_push)
+char *remote_ref_for_branch(struct branch *branch, int for_push)
 {
 	read_config(the_repository, 0);
 	die_on_missing_branch(the_repository, branch);
@@ -612,11 +640,11 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push)
 	if (branch) {
 		if (!for_push) {
 			if (branch->merge_nr) {
-				return branch->merge_name[0];
+				return xstrdup(branch->merge_name[0]);
 			}
 		} else {
-			const char *dst,
-				*remote_name = remotes_pushremote_for_branch(
+			char *dst;
+			const char *remote_name = remotes_pushremote_for_branch(
 					the_repository->remote_state, branch,
 					NULL);
 			struct remote *remote = remotes_remote_get(
@@ -1095,6 +1123,7 @@ void free_one_ref(struct ref *ref)
 		return;
 	free_one_ref(ref->peer_ref);
 	free(ref->remote_status);
+	free(ref->tracking_ref);
 	free(ref->symref);
 	free(ref);
 }
@@ -1316,18 +1345,21 @@ static int match_explicit(struct ref *src, struct ref *dst,
 			  struct ref ***dst_tail,
 			  struct refspec_item *rs)
 {
-	struct ref *matched_src, *matched_dst;
-	int allocated_src;
+	struct ref *matched_src = NULL, *matched_dst = NULL;
+	int allocated_src = 0, ret;
 
 	const char *dst_value = rs->dst;
 	char *dst_guess;
 
-	if (rs->pattern || rs->matching || rs->negative)
-		return 0;
+	if (rs->pattern || rs->matching || rs->negative) {
+		ret = 0;
+		goto out;
+	}
 
-	matched_src = matched_dst = NULL;
-	if (match_explicit_lhs(src, rs, &matched_src, &allocated_src) < 0)
-		return -1;
+	if (match_explicit_lhs(src, rs, &matched_src, &allocated_src) < 0) {
+		ret = -1;
+		goto out;
+	}
 
 	if (!dst_value) {
 		int flag;
@@ -1366,18 +1398,30 @@ static int match_explicit(struct ref *src, struct ref *dst,
 		      dst_value);
 		break;
 	}
-	if (!matched_dst)
-		return -1;
-	if (matched_dst->peer_ref)
-		return error(_("dst ref %s receives from more than one src"),
-			     matched_dst->name);
-	else {
+
+	if (!matched_dst) {
+		ret = -1;
+		goto out;
+	}
+
+	if (matched_dst->peer_ref) {
+		ret = error(_("dst ref %s receives from more than one src"),
+			    matched_dst->name);
+		goto out;
+	} else {
 		matched_dst->peer_ref = allocated_src ?
 					matched_src :
 					copy_ref(matched_src);
 		matched_dst->force = rs->force;
+		matched_src = NULL;
 	}
-	return 0;
+
+	ret = 0;
+
+out:
+	if (allocated_src)
+		free_one_ref(matched_src);
+	return ret;
 }
 
 static int match_explicit_refs(struct ref *src, struct ref *dst,
@@ -2038,6 +2082,8 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
 		    !ignore_symref_update(expn_name, &scratch)) {
 			struct ref *cpy = copy_ref(ref);
 
+			if (cpy->peer_ref)
+				free_one_ref(cpy->peer_ref);
 			cpy->peer_ref = alloc_ref(expn_name);
 			if (refspec->force)
 				cpy->peer_ref->force = 1;
@@ -2354,7 +2400,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
 	return 1;
 }
 
-static int one_local_ref(const char *refname, const struct object_id *oid,
+static int one_local_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			 int flag UNUSED,
 			 void *cb_data)
 {
@@ -2439,7 +2485,7 @@ struct stale_heads_info {
 	struct refspec *rs;
 };
 
-static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
+static int get_stale_heads_cb(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 			      int flags, void *cb_data)
 {
 	struct stale_heads_info *info = cb_data;
@@ -2498,7 +2544,7 @@ struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map)
 /*
  * Compare-and-swap
  */
-static void clear_cas_option(struct push_cas_option *cas)
+void clear_cas_option(struct push_cas_option *cas)
 {
 	int i;
 
@@ -2575,8 +2621,10 @@ static int remote_tracking(struct remote *remote, const char *refname,
 	dst = apply_refspecs(&remote->fetch, refname);
 	if (!dst)
 		return -1; /* no tracking ref for refname at remote */
-	if (refs_read_ref(get_main_ref_store(the_repository), dst, oid))
+	if (refs_read_ref(get_main_ref_store(the_repository), dst, oid)) {
+		free(dst);
 		return -1; /* we know what the tracking ref is but we cannot read it */
+	}
 
 	*dst_refname = dst;
 	return 0;
@@ -2726,6 +2774,7 @@ static void check_if_includes_upstream(struct ref *remote)
 
 	if (is_reachable_in_reflog(local->name, remote) <= 0)
 		remote->unreachable = 1;
+	free_one_ref(local);
 }
 
 static void apply_cas(struct push_cas_option *cas,
@@ -2795,16 +2844,26 @@ struct remote_state *remote_state_new(void)
 
 void remote_state_clear(struct remote_state *remote_state)
 {
+	struct hashmap_iter iter;
+	struct branch *b;
 	int i;
 
 	for (i = 0; i < remote_state->remotes_nr; i++)
 		remote_clear(remote_state->remotes[i]);
 	FREE_AND_NULL(remote_state->remotes);
+	FREE_AND_NULL(remote_state->pushremote_name);
 	remote_state->remotes_alloc = 0;
 	remote_state->remotes_nr = 0;
 
+	rewrites_release(&remote_state->rewrites);
+	rewrites_release(&remote_state->rewrites_push);
+
 	hashmap_clear_and_free(&remote_state->remotes_hash, struct remote, ent);
-	hashmap_clear_and_free(&remote_state->branches_hash, struct remote, ent);
+	hashmap_for_each_entry(&remote_state->branches_hash, &iter, b, ent) {
+		branch_release(b);
+		free(b);
+	}
+	hashmap_clear(&remote_state->branches_hash);
 }
 
 /*
diff --git a/remote.h b/remote.h
index b901b56..ad4513f 100644
--- a/remote.h
+++ b/remote.h
@@ -329,7 +329,7 @@ struct branch {
 struct branch *branch_get(const char *name);
 const char *remote_for_branch(struct branch *branch, int *explicit);
 const char *pushremote_for_branch(struct branch *branch, int *explicit);
-const char *remote_ref_for_branch(struct branch *branch, int for_push);
+char *remote_ref_for_branch(struct branch *branch, int for_push);
 
 /* returns true if the given branch has merge configuration given. */
 int branch_has_merge_config(struct branch *branch);
@@ -409,6 +409,7 @@ struct push_cas_option {
 };
 
 int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
+void clear_cas_option(struct push_cas_option *);
 
 int is_empty_cas(const struct push_cas_option *);
 void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
diff --git a/replace-object.c b/replace-object.c
index 59252d5..9a3cdd8 100644
--- a/replace-object.c
+++ b/replace-object.c
@@ -9,6 +9,7 @@
 #include "commit.h"
 
 static int register_replace_ref(const char *refname,
+				const char *referent UNUSED,
 				const struct object_id *oid,
 				int flag UNUSED,
 				void *cb_data)
diff --git a/repo-settings.c b/repo-settings.c
index 2b4e687..4699b4b 100644
--- a/repo-settings.c
+++ b/repo-settings.c
@@ -1,5 +1,6 @@
 #include "git-compat-util.h"
 #include "config.h"
+#include "repo-settings.h"
 #include "repository.h"
 #include "midx.h"
 
@@ -19,6 +20,7 @@ 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;
@@ -28,13 +30,11 @@ void prepare_repo_settings(struct repository *r)
 	if (!r->gitdir)
 		BUG("Cannot add settings for uninitialized repository");
 
-	if (r->settings.initialized++)
+	if (r->settings.initialized)
 		return;
 
-	/* Defaults */
-	r->settings.index_version = -1;
-	r->settings.core_untracked_cache = UNTRACKED_CACHE_KEEP;
-	r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE;
+	memcpy(&r->settings, &defaults, sizeof(defaults));
+	r->settings.initialized++;
 
 	/* Booleans config or default, cascades to other settings */
 	repo_cfg_bool(r, "feature.manyfiles", &manyfiles, 0);
@@ -124,3 +124,28 @@ void prepare_repo_settings(struct repository *r)
 	 */
 	r->settings.command_requires_full_index = 1;
 }
+
+enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo)
+{
+	const char *value;
+
+	if (!repo_config_get_string_tmp(repo, "core.logallrefupdates", &value)) {
+		if (value && !strcasecmp(value, "always"))
+			return LOG_REFS_ALWAYS;
+		else if (git_config_bool("core.logallrefupdates", value))
+			return LOG_REFS_NORMAL;
+		else
+			return LOG_REFS_NONE;
+	}
+
+	return LOG_REFS_UNSET;
+}
+
+int repo_settings_get_warn_ambiguous_refs(struct repository *repo)
+{
+	prepare_repo_settings(repo);
+	if (repo->settings.warn_ambiguous_refs < 0)
+		repo_cfg_bool(repo, "core.warnambiguousrefs",
+			      &repo->settings.warn_ambiguous_refs, 1);
+	return repo->settings.warn_ambiguous_refs;
+}
diff --git a/repo-settings.h b/repo-settings.h
new file mode 100644
index 0000000..51d6156
--- /dev/null
+++ b/repo-settings.h
@@ -0,0 +1,75 @@
+#ifndef REPO_SETTINGS_H
+#define REPO_SETTINGS_H
+
+struct fsmonitor_settings;
+struct repository;
+
+enum untracked_cache_setting {
+	UNTRACKED_CACHE_KEEP,
+	UNTRACKED_CACHE_REMOVE,
+	UNTRACKED_CACHE_WRITE,
+};
+
+enum fetch_negotiation_setting {
+	FETCH_NEGOTIATION_CONSECUTIVE,
+	FETCH_NEGOTIATION_SKIPPING,
+	FETCH_NEGOTIATION_NOOP,
+};
+
+enum log_refs_config {
+	LOG_REFS_UNSET = -1,
+	LOG_REFS_NONE = 0,
+	LOG_REFS_NORMAL,
+	LOG_REFS_ALWAYS
+};
+
+struct repo_settings {
+	int initialized;
+
+	int core_commit_graph;
+	int commit_graph_generation_version;
+	int commit_graph_changed_paths_version;
+	int gc_write_commit_graph;
+	int fetch_write_commit_graph;
+	int command_requires_full_index;
+	int sparse_index;
+	int pack_read_reverse_index;
+	int pack_use_bitmap_boundary_traversal;
+	int pack_use_multi_pack_reuse;
+
+	/*
+	 * Does this repository have core.useReplaceRefs=true (on by
+	 * default)? This provides a repository-scoped version of this
+	 * config, though it could be disabled process-wide via some Git
+	 * builtins or the --no-replace-objects option. See
+	 * replace_refs_enabled() for more details.
+	 */
+	int read_replace_refs;
+
+	struct fsmonitor_settings *fsmonitor; /* lazily loaded */
+
+	int index_version;
+	int index_skip_hash;
+	enum untracked_cache_setting core_untracked_cache;
+
+	int pack_use_sparse;
+	enum fetch_negotiation_setting fetch_negotiation_algorithm;
+
+	int core_multi_pack_index;
+	int warn_ambiguous_refs; /* lazily loaded via accessor */
+};
+#define REPO_SETTINGS_INIT { \
+	.index_version = -1, \
+	.core_untracked_cache = UNTRACKED_CACHE_KEEP, \
+	.fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE, \
+	.warn_ambiguous_refs = -1, \
+}
+
+void prepare_repo_settings(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);
+
+#endif /* REPO_SETTINGS_H */
diff --git a/repository.c b/repository.c
index 9825a30..f988b8a 100644
--- a/repository.c
+++ b/repository.c
@@ -54,7 +54,7 @@ void initialize_repository(struct repository *repo)
 {
 	repo->objects = raw_object_store_new();
 	repo->remote_state = remote_state_new();
-	repo->parsed_objects = parsed_object_pool_new();
+	repo->parsed_objects = parsed_object_pool_new(repo);
 	ALLOC_ARRAY(repo->index, 1);
 	index_state_init(repo->index, repo);
 
@@ -91,6 +91,46 @@ static void expand_base_dir(char **out, const char *in,
 		*out = xstrfmt("%s/%s", base_dir, def_in);
 }
 
+const char *repo_get_git_dir(struct repository *repo)
+{
+	if (!repo->gitdir)
+		BUG("repository hasn't been set up");
+	return repo->gitdir;
+}
+
+const char *repo_get_common_dir(struct repository *repo)
+{
+	if (!repo->commondir)
+		BUG("repository hasn't been set up");
+	return repo->commondir;
+}
+
+const char *repo_get_object_directory(struct repository *repo)
+{
+	if (!repo->objects->odb)
+		BUG("repository hasn't been set up");
+	return repo->objects->odb->path;
+}
+
+const char *repo_get_index_file(struct repository *repo)
+{
+	if (!repo->index_file)
+		BUG("repository hasn't been set up");
+	return repo->index_file;
+}
+
+const char *repo_get_graft_file(struct repository *repo)
+{
+	if (!repo->graft_file)
+		BUG("repository hasn't been set up");
+	return repo->graft_file;
+}
+
+const char *repo_get_work_tree(struct repository *repo)
+{
+	return repo->worktree;
+}
+
 static void repo_set_commondir(struct repository *repo,
 			       const char *commondir)
 {
diff --git a/repository.h b/repository.h
index af6ea0a..24a66a4 100644
--- a/repository.h
+++ b/repository.h
@@ -2,9 +2,9 @@
 #define REPOSITORY_H
 
 #include "strmap.h"
+#include "repo-settings.h"
 
 struct config_set;
-struct fsmonitor_settings;
 struct git_hash_algo;
 struct index_state;
 struct lock_file;
@@ -14,59 +14,12 @@ struct submodule_cache;
 struct promisor_remote_config;
 struct remote_state;
 
-enum untracked_cache_setting {
-	UNTRACKED_CACHE_KEEP,
-	UNTRACKED_CACHE_REMOVE,
-	UNTRACKED_CACHE_WRITE,
-};
-
-enum fetch_negotiation_setting {
-	FETCH_NEGOTIATION_CONSECUTIVE,
-	FETCH_NEGOTIATION_SKIPPING,
-	FETCH_NEGOTIATION_NOOP,
-};
-
 enum ref_storage_format {
 	REF_STORAGE_FORMAT_UNKNOWN,
 	REF_STORAGE_FORMAT_FILES,
 	REF_STORAGE_FORMAT_REFTABLE,
 };
 
-struct repo_settings {
-	int initialized;
-
-	int core_commit_graph;
-	int commit_graph_generation_version;
-	int commit_graph_changed_paths_version;
-	int gc_write_commit_graph;
-	int fetch_write_commit_graph;
-	int command_requires_full_index;
-	int sparse_index;
-	int pack_read_reverse_index;
-	int pack_use_bitmap_boundary_traversal;
-	int pack_use_multi_pack_reuse;
-
-	/*
-	 * Does this repository have core.useReplaceRefs=true (on by
-	 * default)? This provides a repository-scoped version of this
-	 * config, though it could be disabled process-wide via some Git
-	 * builtins or the --no-replace-objects option. See
-	 * replace_refs_enabled() for more details.
-	 */
-	int read_replace_refs;
-
-	struct fsmonitor_settings *fsmonitor; /* lazily loaded */
-
-	int index_version;
-	int index_skip_hash;
-	enum untracked_cache_setting core_untracked_cache;
-
-	int pack_use_sparse;
-	enum fetch_negotiation_setting fetch_negotiation_algorithm;
-
-	int core_multi_pack_index;
-};
-
 struct repo_path_cache {
 	char *squash_msg;
 	char *merge_msg;
@@ -206,6 +159,13 @@ struct repository {
 extern struct repository *the_repository;
 #endif
 
+const char *repo_get_git_dir(struct repository *repo);
+const char *repo_get_common_dir(struct repository *repo);
+const char *repo_get_object_directory(struct repository *repo);
+const char *repo_get_index_file(struct repository *repo);
+const char *repo_get_graft_file(struct repository *repo);
+const char *repo_get_work_tree(struct repository *repo);
+
 /*
  * Define a custom repository layout. Any field can be NULL, which
  * will default back to the path according to the default layout.
@@ -266,8 +226,6 @@ int repo_read_index_unmerged(struct repository *);
  */
 void repo_update_index_if_able(struct repository *, struct lock_file *);
 
-void prepare_repo_settings(struct repository *r);
-
 /*
  * Return 1 if upgrade repository format to target_version succeeded,
  * 0 if no upgrade is necessary, and -1 when upgrade is not possible.
diff --git a/rerere.c b/rerere.c
index 3a3888c..d01e98b 100644
--- a/rerere.c
+++ b/rerere.c
@@ -1107,7 +1107,7 @@ static int rerere_forget_one_path(struct index_state *istate,
 
 int rerere_forget(struct repository *r, struct pathspec *pathspec)
 {
-	int i, fd;
+	int i, fd, ret;
 	struct string_list conflict = STRING_LIST_INIT_DUP;
 	struct string_list merge_rr = STRING_LIST_INIT_DUP;
 
@@ -1132,7 +1132,12 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)
 			continue;
 		rerere_forget_one_path(r->index, it->string, &merge_rr);
 	}
-	return write_rr(&merge_rr, fd);
+
+	ret = write_rr(&merge_rr, fd);
+
+	string_list_clear(&conflict, 0);
+	string_list_clear(&merge_rr, 1);
+	return ret;
 }
 
 /*
@@ -1203,8 +1208,10 @@ void rerere_gc(struct repository *r, struct string_list *rr)
 	if (setup_rerere(r, rr, 0) < 0)
 		return;
 
-	git_config_get_expiry_in_days("gc.rerereresolved", &cutoff_resolve, now);
-	git_config_get_expiry_in_days("gc.rerereunresolved", &cutoff_noresolve, now);
+	repo_config_get_expiry_in_days(the_repository, "gc.rerereresolved",
+				       &cutoff_resolve, now);
+	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"));
 	if (!dir)
diff --git a/reset.c b/reset.c
index 9550dea..b22b1be 100644
--- a/reset.c
+++ b/reset.c
@@ -79,7 +79,7 @@ static int update_refs(const struct reset_head_opts *opts,
 						 reflog_head);
 	}
 	if (!ret && run_hook)
-		run_hooks_l("post-checkout",
+		run_hooks_l(the_repository, "post-checkout",
 			    oid_to_hex(head ? head : null_oid()),
 			    oid_to_hex(oid), "1", NULL);
 	strbuf_release(&msg);
diff --git a/revision.c b/revision.c
index 5fecd7e..e79f39e 100644
--- a/revision.c
+++ b/revision.c
@@ -1071,7 +1071,11 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 					ts->treesame[nth_parent] = 1;
 				continue;
 			}
+
+			free_commit_list(parent->next);
 			parent->next = NULL;
+			while (commit->parents != parent)
+				pop_commit(&commit->parents);
 			commit->parents = parent;
 
 			/*
@@ -1103,6 +1107,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 					die("cannot simplify commit %s (invalid %s)",
 					    oid_to_hex(&commit->object.oid),
 					    oid_to_hex(&p->object.oid));
+				free_commit_list(p->parents);
 				p->parents = NULL;
 			}
 		/* fallthrough */
@@ -1648,7 +1653,7 @@ struct all_refs_cb {
 	struct worktree *wt;
 };
 
-static int handle_one_ref(const char *path, const struct object_id *oid,
+static int handle_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
 			  int flag UNUSED,
 			  void *cb_data)
 {
@@ -1872,7 +1877,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
 			continue; /* current index already taken care of */
 
 		if (read_index_from(&istate,
-				    worktree_git_path(wt, "index"),
+				    worktree_git_path(the_repository, wt, "index"),
 				    get_worktree_git_dir(wt)) > 0)
 			do_add_index_objects_to_pending(revs, &istate, flags);
 		discard_index(&istate);
diff --git a/revision.h b/revision.h
index 0e470d1..71e984c 100644
--- a/revision.h
+++ b/revision.h
@@ -549,7 +549,7 @@ int rewrite_parents(struct rev_info *revs,
  * The log machinery saves the original parent list so that
  * get_saved_parents() can later tell what the real parents of the
  * commits are, when commit->parents has been modified by history
- * simpification.
+ * simplification.
  *
  * get_saved_parents() will transparently return commit->parents if
  * history simplification is off.
diff --git a/run-command.c b/run-command.c
index 45ba544..94f2f30 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1808,16 +1808,26 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts)
 
 int prepare_auto_maintenance(int quiet, struct child_process *maint)
 {
-	int enabled;
+	int enabled, auto_detach;
 
 	if (!git_config_get_bool("maintenance.auto", &enabled) &&
 	    !enabled)
 		return 0;
 
+	/*
+	 * When `maintenance.autoDetach` isn't set, then we fall back to
+	 * honoring `gc.autoDetach`. This is somewhat weird, but required to
+	 * retain behaviour from when we used to run git-gc(1) here.
+	 */
+	if (git_config_get_bool("maintenance.autodetach", &auto_detach) &&
+	    git_config_get_bool("gc.autodetach", &auto_detach))
+		auto_detach = 1;
+
 	maint->git_cmd = 1;
 	maint->close_object_store = 1;
 	strvec_pushl(&maint->args, "maintenance", "run", "--auto", NULL);
 	strvec_push(&maint->args, quiet ? "--quiet" : "--no-quiet");
+	strvec_push(&maint->args, auto_detach ? "--detach" : "--no-detach");
 
 	return 1;
 }
diff --git a/run-command.h b/run-command.h
index 03e7222..0df25e4 100644
--- a/run-command.h
+++ b/run-command.h
@@ -535,7 +535,7 @@ enum start_bg_result {
 	/* timeout expired waiting for child to become "ready" */
 	SBGR_TIMEOUT,
 
-	/* child process exited or was signalled before becomming "ready" */
+	/* child process exited or was signalled before becoming "ready" */
 	SBGR_DIED,
 };
 
diff --git a/scalar.c b/scalar.c
index 1fe8a93..73b79a5 100644
--- a/scalar.c
+++ b/scalar.c
@@ -400,7 +400,8 @@ static int delete_enlistment(struct strbuf *enlistment)
  * Dummy implementation; Using `get_version_info()` would cause a link error
  * without this.
  */
-void load_builtin_commands(const char *prefix, struct cmdnames *cmds)
+void load_builtin_commands(const char *prefix UNUSED,
+			   struct cmdnames *cmds UNUSED)
 {
 	die("not implemented");
 }
@@ -409,7 +410,7 @@ static int cmd_clone(int argc, const char **argv)
 {
 	const char *branch = NULL;
 	int full_clone = 0, single_branch = 0, show_progress = isatty(2);
-	int src = 1;
+	int src = 1, tags = 1;
 	struct option clone_options[] = {
 		OPT_STRING('b', "branch", &branch, N_("<branch>"),
 			   N_("branch to checkout after clone")),
@@ -420,11 +421,13 @@ static int cmd_clone(int argc, const char **argv)
 			    "be checked out")),
 		OPT_BOOL(0, "src", &src,
 			 N_("create repository within 'src' directory")),
+		OPT_BOOL(0, "tags", &tags,
+			 N_("specify if tags should be fetched during clone")),
 		OPT_END(),
 	};
 	const char * const clone_usage[] = {
 		N_("scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
-		   "\t[--[no-]src] <url> [<enlistment>]"),
+		   "\t[--[no-]src] [--[no-]tags] <url> [<enlistment>]"),
 		NULL
 	};
 	const char *url;
@@ -503,6 +506,11 @@ static int cmd_clone(int argc, const char **argv)
 		goto cleanup;
 	}
 
+	if (!tags && set_config("remote.origin.tagOpt=--no-tags")) {
+		res = error(_("could not disable tags in '%s'"), dir);
+		goto cleanup;
+	}
+
 	if (!full_clone &&
 	    (res = run_git("sparse-checkout", "init", "--cone", NULL)))
 		goto cleanup;
@@ -512,7 +520,9 @@ static int cmd_clone(int argc, const char **argv)
 
 	if ((res = run_git("fetch", "--quiet",
 				show_progress ? "--progress" : "--no-progress",
-				"origin", NULL))) {
+				"origin",
+				(tags ? NULL : "--no-tags"),
+				NULL))) {
 		warning(_("partial clone failed; attempting full clone"));
 
 		if (set_config("remote.origin.promisor") ||
@@ -723,6 +733,9 @@ static int cmd_reconfigure(int argc, const char **argv)
 
 		the_repository = old_repo;
 
+		if (toggle_maintenance(1) >= 0)
+			succeeded = 1;
+
 loop_end:
 		if (!succeeded) {
 			res = -1;
diff --git a/send-pack.c b/send-pack.c
index fa2f5ee..6677c44 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -75,6 +75,7 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
 	int i;
 	int rc;
 
+	trace2_region_enter("send_pack", "pack_objects", the_repository);
 	strvec_push(&po.args, "pack-objects");
 	strvec_push(&po.args, "--all-progress-implied");
 	strvec_push(&po.args, "--revs");
@@ -146,8 +147,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);
 		return -1;
 	}
+	trace2_region_leave("send_pack", "pack_objects", the_repository);
 	return 0;
 }
 
@@ -170,6 +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);
 	hint = NULL;
 	ret = receive_unpack_status(reader);
 	while (1) {
@@ -268,6 +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);
 	return ret;
 }
 
@@ -348,7 +353,8 @@ static int generate_push_cert(struct strbuf *req_buf,
 {
 	const struct ref *ref;
 	struct string_list_item *item;
-	char *signing_key_id = xstrdup(get_signing_key_id());
+	char *signing_key_id = get_signing_key_id();
+	char *signing_key = get_signing_key();
 	const char *cp, *np;
 	struct strbuf cert = STRBUF_INIT;
 	int update_seen = 0;
@@ -381,7 +387,7 @@ static int generate_push_cert(struct strbuf *req_buf,
 	if (!update_seen)
 		goto free_return;
 
-	if (sign_buffer(&cert, &cert, get_signing_key()))
+	if (sign_buffer(&cert, &cert, signing_key))
 		die(_("failed to sign the push certificate"));
 
 	packet_buf_write(req_buf, "push-cert%c%s", 0, cap_string);
@@ -394,6 +400,7 @@ static int generate_push_cert(struct strbuf *req_buf,
 
 free_return:
 	free(signing_key_id);
+	free(signing_key);
 	strbuf_release(&cert);
 	return update_seen;
 }
@@ -501,19 +508,23 @@ int send_pack(struct send_pack_args *args,
 	unsigned cmds_sent = 0;
 	int ret;
 	struct async demux;
-	const char *push_cert_nonce = NULL;
+	char *push_cert_nonce = NULL;
 	struct packet_reader reader;
 	int use_bitmaps;
 
 	if (!remote_refs) {
 		fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
 			"Perhaps you should specify a branch.\n");
-		return 0;
+		ret = 0;
+		goto out;
 	}
 
 	git_config_get_bool("push.negotiate", &push_negotiate);
-	if (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);
+	}
 
 	if (!git_config_get_bool("push.usebitmaps", &use_bitmaps))
 		args->disable_bitmaps = !use_bitmaps;
@@ -549,10 +560,11 @@ int send_pack(struct send_pack_args *args,
 
 	if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) {
 		size_t len;
-		push_cert_nonce = server_feature_value("push-cert", &len);
-		if (push_cert_nonce) {
-			reject_invalid_nonce(push_cert_nonce, len);
-			push_cert_nonce = xmemdupz(push_cert_nonce, len);
+		const char *nonce = server_feature_value("push-cert", &len);
+
+		if (nonce) {
+			reject_invalid_nonce(nonce, len);
+			push_cert_nonce = xmemdupz(nonce, len);
 		} else if (args->push_cert == SEND_PACK_PUSH_CERT_ALWAYS) {
 			die(_("the receiving end does not support --signed push"));
 		} else if (args->push_cert == SEND_PACK_PUSH_CERT_IF_ASKED) {
@@ -615,12 +627,11 @@ int send_pack(struct send_pack_args *args,
 			 * atomically, abort the whole operation.
 			 */
 			if (use_atomic) {
-				strbuf_release(&req_buf);
-				strbuf_release(&cap_buf);
 				reject_atomic_push(remote_refs, args->send_mirror);
-				error("atomic push failed for ref %s. status: %d\n",
+				error("atomic push failed for ref %s. status: %d",
 				      ref->name, ref->status);
-				return args->porcelain ? 0 : -1;
+				ret = args->porcelain ? 0 : -1;
+				goto out;
 			}
 			/* else fallthrough */
 		default:
@@ -641,10 +652,11 @@ int send_pack(struct send_pack_args *args,
 	/*
 	 * Finally, tell the other end!
 	 */
-	if (!args->dry_run && push_cert_nonce)
+	if (!args->dry_run && push_cert_nonce) {
 		cmds_sent = generate_push_cert(&req_buf, remote_refs, args,
 					       cap_buf.buf, push_cert_nonce);
-	else if (!args->dry_run)
+		trace2_printf("Generated push certificate");
+	} else if (!args->dry_run) {
 		for (ref = remote_refs; ref; ref = ref->next) {
 			char *old_hex, *new_hex;
 
@@ -664,6 +676,7 @@ int send_pack(struct send_pack_args *args,
 						 old_hex, new_hex, ref->name);
 			}
 		}
+	}
 
 	if (use_push_options) {
 		struct string_list_item *item;
@@ -682,8 +695,6 @@ int send_pack(struct send_pack_args *args,
 		write_or_die(out, req_buf.buf, req_buf.len);
 		packet_flush(out);
 	}
-	strbuf_release(&req_buf);
-	strbuf_release(&cap_buf);
 
 	if (use_sideband && cmds_sent) {
 		memset(&demux, 0, sizeof(demux));
@@ -721,7 +732,9 @@ int send_pack(struct send_pack_args *args,
 				finish_async(&demux);
 			}
 			fd[1] = -1;
-			return -1;
+
+			ret = -1;
+			goto out;
 		}
 		if (!args->stateless_rpc)
 			/* Closed by pack_objects() via start_command() */
@@ -746,10 +759,12 @@ int send_pack(struct send_pack_args *args,
 	}
 
 	if (ret < 0)
-		return ret;
+		goto out;
 
-	if (args->porcelain)
-		return 0;
+	if (args->porcelain) {
+		ret = 0;
+		goto out;
+	}
 
 	for (ref = remote_refs; ref; ref = ref->next) {
 		switch (ref->status) {
@@ -758,8 +773,17 @@ int send_pack(struct send_pack_args *args,
 		case REF_STATUS_OK:
 			break;
 		default:
-			return -1;
+			ret = -1;
+			goto out;
 		}
 	}
-	return 0;
+
+	ret = 0;
+
+out:
+	oid_array_clear(&commons);
+	strbuf_release(&req_buf);
+	strbuf_release(&cap_buf);
+	free(push_cert_nonce);
+	return ret;
 }
diff --git a/sequencer.c b/sequencer.c
index a2284ac..8d01cd5 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -303,6 +303,7 @@ static int git_sequencer_config(const char *k, const char *v,
 	}
 
 	if (!strcmp(k, "commit.gpgsign")) {
+		free(opts->gpg_sign);
 		opts->gpg_sign = git_config_bool(k, v) ? xstrdup("") : NULL;
 		return 0;
 	}
@@ -762,7 +763,7 @@ static int do_recursive_merge(struct repository *r,
 
 	repo_read_index(r);
 
-	init_merge_options(&o, r);
+	init_ui_merge_options(&o, r);
 	o.ancestor = base ? base_label : "(empty tree)";
 	o.branch1 = "HEAD";
 	o.branch2 = next ? next_label : "(empty tree)";
@@ -1316,7 +1317,7 @@ static int run_rewrite_hook(const struct object_id *oldoid,
 	struct child_process proc = CHILD_PROCESS_INIT;
 	int code;
 	struct strbuf sb = STRBUF_INIT;
-	const char *hook_path = find_hook("post-rewrite");
+	const char *hook_path = find_hook(the_repository, "post-rewrite");
 
 	if (!hook_path)
 		return 0;
@@ -1614,7 +1615,7 @@ static int try_to_commit(struct repository *r,
 		}
 	}
 
-	if (hook_exists("prepare-commit-msg")) {
+	if (hook_exists(r, "prepare-commit-msg")) {
 		res = run_prepare_commit_msg_hook(r, msg, hook_commit);
 		if (res)
 			goto out;
@@ -3793,12 +3794,13 @@ static int error_failed_squash(struct repository *r,
 	return error_with_patch(r, commit, subject, subject_len, opts, 1, 0);
 }
 
-static int do_exec(struct repository *r, const char *command_line)
+static int do_exec(struct repository *r, const char *command_line, int quiet)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
 	int dirty, status;
 
-	fprintf(stderr, _("Executing: %s\n"), command_line);
+	if (!quiet)
+		fprintf(stderr, _("Executing: %s\n"), command_line);
 	cmd.use_shell = 1;
 	strvec_push(&cmd.args, command_line);
 	strvec_push(&cmd.env, "GIT_CHERRY_PICK_HELP");
@@ -4309,7 +4311,7 @@ static int do_merge(struct repository *r,
 	bases = reverse_commit_list(bases);
 
 	repo_read_index(r);
-	init_merge_options(&o, r);
+	init_ui_merge_options(&o, r);
 	o.branch1 = "HEAD";
 	o.branch2 = ref_name.buf;
 	o.buffer_output = 2;
@@ -5013,7 +5015,7 @@ static int pick_commits(struct repository *r,
 			if (!opts->verbose)
 				term_clear_line();
 			*end_of_arg = '\0';
-			res = do_exec(r, arg);
+			res = do_exec(r, arg, opts->quiet);
 			*end_of_arg = saved;
 
 			if (res) {
@@ -5149,7 +5151,7 @@ static int pick_commits(struct repository *r,
 
 			hook_opt.path_to_stdin = rebase_path_rewritten_list();
 			strvec_push(&hook_opt.args, "rebase");
-			run_hooks_opt("post-rewrite", &hook_opt);
+			run_hooks_opt(r, "post-rewrite", &hook_opt);
 		}
 		apply_autostash(rebase_path_autostash());
 
@@ -5489,8 +5491,10 @@ int sequencer_pick_revisions(struct repository *r,
 	int i, res;
 
 	assert(opts->revs);
-	if (read_and_refresh_cache(r, opts))
-		return -1;
+	if (read_and_refresh_cache(r, opts)) {
+		res = -1;
+		goto out;
+	}
 
 	for (i = 0; i < opts->revs->pending.nr; i++) {
 		struct object_id oid;
@@ -5505,11 +5509,14 @@ int sequencer_pick_revisions(struct repository *r,
 				enum object_type type = oid_object_info(r,
 									&oid,
 									NULL);
-				return error(_("%s: can't cherry-pick a %s"),
-					name, type_name(type));
+				res = error(_("%s: can't cherry-pick a %s"),
+					    name, type_name(type));
+				goto out;
 			}
-		} else
-			return error(_("%s: bad revision"), name);
+		} else {
+			res = error(_("%s: bad revision"), name);
+			goto out;
+		}
 	}
 
 	/*
@@ -5524,14 +5531,23 @@ int sequencer_pick_revisions(struct repository *r,
 	    opts->revs->no_walk &&
 	    !opts->revs->cmdline.rev->flags) {
 		struct commit *cmit;
-		if (prepare_revision_walk(opts->revs))
-			return error(_("revision walk setup failed"));
+
+		if (prepare_revision_walk(opts->revs)) {
+			res = error(_("revision walk setup failed"));
+			goto out;
+		}
+
 		cmit = get_revision(opts->revs);
-		if (!cmit)
-			return error(_("empty commit set passed"));
+		if (!cmit) {
+			res = error(_("empty commit set passed"));
+			goto out;
+		}
+
 		if (get_revision(opts->revs))
 			BUG("unexpected extra commit from walk");
-		return single_pick(r, cmit, opts);
+
+		res = single_pick(r, cmit, opts);
+		goto out;
 	}
 
 	/*
@@ -5541,16 +5557,30 @@ int sequencer_pick_revisions(struct repository *r,
 	 */
 
 	if (walk_revs_populate_todo(&todo_list, opts) ||
-			create_seq_dir(r) < 0)
-		return -1;
-	if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT))
-		return error(_("can't revert as initial commit"));
-	if (save_head(oid_to_hex(&oid)))
-		return -1;
-	if (save_opts(opts))
-		return -1;
+			create_seq_dir(r) < 0) {
+		res = -1;
+		goto out;
+	}
+
+	if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT)) {
+		res = error(_("can't revert as initial commit"));
+		goto out;
+	}
+
+	if (save_head(oid_to_hex(&oid))) {
+		res = -1;
+		goto out;
+	}
+
+	if (save_opts(opts)) {
+		res = -1;
+		goto out;
+	}
+
 	update_abort_safety_file();
 	res = pick_commits(r, &todo_list, opts);
+
+out:
 	todo_list_release(&todo_list);
 	return res;
 }
diff --git a/serve.c b/serve.c
index 884cd84..d674764 100644
--- a/serve.c
+++ b/serve.c
@@ -323,7 +323,7 @@ static int process_request(void)
 		die("no command requested");
 
 	if (client_hash_algo != hash_algo_by_ptr(the_repository->hash_algo))
-		die("mismatched object format: server %s; client %s\n",
+		die("mismatched object format: server %s; client %s",
 		    the_repository->hash_algo->name,
 		    hash_algos[client_hash_algo].name);
 
diff --git a/server-info.c b/server-info.c
index f61296a..c5af4cd 100644
--- a/server-info.c
+++ b/server-info.c
@@ -2,7 +2,6 @@
 
 #include "git-compat-util.h"
 #include "dir.h"
-#include "environment.h"
 #include "hex.h"
 #include "repository.h"
 #include "refs.h"
@@ -147,7 +146,7 @@ static int update_info_file(char *path,
 	return ret;
 }
 
-static int add_info_ref(const char *path, const struct object_id *oid,
+static int add_info_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
 			int flag UNUSED,
 			void *cb_data)
 {
@@ -342,7 +341,8 @@ static int write_pack_info_file(struct update_info_ctx *uic)
 
 static int update_info_packs(int force)
 {
-	char *infofile = mkpathdup("%s/info/packs", get_object_directory());
+	char *infofile = mkpathdup("%s/info/packs",
+				   repo_get_object_directory(the_repository));
 	int ret;
 
 	init_pack_info(infofile, force);
diff --git a/setup.c b/setup.c
index 5f81d9f..94e79b2 100644
--- a/setup.c
+++ b/setup.c
@@ -7,16 +7,22 @@
 #include "exec-cmd.h"
 #include "gettext.h"
 #include "hex.h"
+#include "object-file.h"
 #include "object-name.h"
 #include "refs.h"
+#include "replace-object.h"
 #include "repository.h"
 #include "config.h"
 #include "dir.h"
 #include "setup.h"
+#include "shallow.h"
 #include "string-list.h"
+#include "strvec.h"
 #include "chdir-notify.h"
 #include "path.h"
 #include "quote.h"
+#include "tmp-objdir.h"
+#include "trace.h"
 #include "trace2.h"
 #include "worktree.h"
 #include "exec-cmd.h"
@@ -51,7 +57,7 @@ static int abspath_part_inside_repo(char *path)
 	size_t wtlen;
 	char *path0;
 	int off;
-	const char *work_tree = precompose_string_if_needed(get_git_work_tree());
+	const char *work_tree = precompose_string_if_needed(repo_get_work_tree(the_repository));
 	struct strbuf realpath = STRBUF_INIT;
 
 	if (!work_tree)
@@ -147,9 +153,9 @@ char *prefix_path(const char *prefix, int len, const char *path)
 {
 	char *r = prefix_path_gently(prefix, len, NULL, path);
 	if (!r) {
-		const char *hint_path = get_git_work_tree();
+		const char *hint_path = repo_get_work_tree(the_repository);
 		if (!hint_path)
-			hint_path = get_git_dir();
+			hint_path = repo_get_git_dir(the_repository);
 		die(_("'%s' is outside repository at '%s'"), path,
 		    absolute_path(hint_path));
 	}
@@ -468,14 +474,14 @@ int is_nonbare_repository_dir(struct strbuf *path)
 int is_inside_git_dir(void)
 {
 	if (inside_git_dir < 0)
-		inside_git_dir = is_inside_dir(get_git_dir());
+		inside_git_dir = is_inside_dir(repo_get_git_dir(the_repository));
 	return inside_git_dir;
 }
 
 int is_inside_work_tree(void)
 {
 	if (inside_work_tree < 0)
-		inside_work_tree = is_inside_dir(get_git_work_tree());
+		inside_work_tree = is_inside_dir(repo_get_work_tree(the_repository));
 	return inside_work_tree;
 }
 
@@ -490,7 +496,7 @@ void setup_work_tree(void)
 	if (work_tree_config_is_bogus)
 		die(_("unable to set up work tree using invalid config"));
 
-	work_tree = get_git_work_tree();
+	work_tree = repo_get_work_tree(the_repository);
 	if (!work_tree || chdir_notify(work_tree))
 		die(_("this operation must be run in a work tree"));
 
@@ -518,7 +524,7 @@ static void setup_original_cwd(void)
 	 * directory we inherited from our parent process, which is a
 	 * directory we want to avoid removing.
 	 *
-	 * For convience, we would like to have the path relative to the
+	 * For convenience, we would like to have the path relative to the
 	 * worktree instead of an absolute path.
 	 *
 	 * Yes, startup_info->original_cwd is usually the same as 'prefix',
@@ -547,7 +553,7 @@ static void setup_original_cwd(void)
 	 * Get our worktree; we only protect the current working directory
 	 * if it's in the worktree.
 	 */
-	worktree = get_git_work_tree();
+	worktree = repo_get_work_tree(the_repository);
 	if (!worktree)
 		goto no_prevention_needed;
 
@@ -1062,9 +1068,9 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
 		set_git_work_tree(".");
 
 	/* set_git_work_tree() must have been called by now */
-	worktree = get_git_work_tree();
+	worktree = repo_get_work_tree(the_repository);
 
-	/* both get_git_work_tree() and cwd are already normalized */
+	/* both repo_get_work_tree() and cwd are already normalized */
 	if (!strcmp(cwd->buf, worktree)) { /* cwd == worktree */
 		set_git_dir(gitdirenv, 0);
 		free(gitfile);
@@ -1613,6 +1619,106 @@ enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
 	return result;
 }
 
+void setup_git_env(const char *git_dir)
+{
+	char *git_replace_ref_base;
+	const char *shallow_file;
+	const char *replace_ref_base;
+	struct set_gitdir_args args = { NULL };
+	struct strvec to_free = STRVEC_INIT;
+
+	args.commondir = getenv_safe(&to_free, GIT_COMMON_DIR_ENVIRONMENT);
+	args.object_dir = getenv_safe(&to_free, DB_ENVIRONMENT);
+	args.graft_file = getenv_safe(&to_free, GRAFT_ENVIRONMENT);
+	args.index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT);
+	args.alternate_db = getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT);
+	if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
+		args.disable_ref_updates = 1;
+	}
+
+	repo_set_gitdir(the_repository, git_dir, &args);
+	strvec_clear(&to_free);
+
+	if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
+		disable_replace_refs();
+	replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
+	git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
+							  : "refs/replace/");
+	update_ref_namespace(NAMESPACE_REPLACE, git_replace_ref_base);
+
+	shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
+	if (shallow_file)
+		set_alternate_shallow_file(the_repository, shallow_file, 0);
+
+	if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0))
+		fetch_if_missing = 0;
+}
+
+static void set_git_dir_1(const char *path)
+{
+	xsetenv(GIT_DIR_ENVIRONMENT, path, 1);
+	setup_git_env(path);
+}
+
+static void update_relative_gitdir(const char *name UNUSED,
+				   const char *old_cwd,
+				   const char *new_cwd,
+				   void *data UNUSED)
+{
+	char *path = reparent_relative_path(old_cwd, new_cwd,
+					    repo_get_git_dir(the_repository));
+	struct tmp_objdir *tmp_objdir = tmp_objdir_unapply_primary_odb();
+
+	trace_printf_key(&trace_setup_key,
+			 "setup: move $GIT_DIR to '%s'",
+			 path);
+	set_git_dir_1(path);
+	if (tmp_objdir)
+		tmp_objdir_reapply_primary_odb(tmp_objdir, old_cwd, new_cwd);
+	free(path);
+}
+
+void set_git_dir(const char *path, int make_realpath)
+{
+	struct strbuf realpath = STRBUF_INIT;
+
+	if (make_realpath) {
+		strbuf_realpath(&realpath, path, 1);
+		path = realpath.buf;
+	}
+
+	set_git_dir_1(path);
+	if (!is_absolute_path(path))
+		chdir_notify_register(NULL, update_relative_gitdir, NULL);
+
+	strbuf_release(&realpath);
+}
+
+static int git_work_tree_initialized;
+
+/*
+ * Note.  This works only before you used a work tree.  This was added
+ * primarily to support git-clone to work in a new repository it just
+ * created, and is not meant to flip between different work trees.
+ */
+void set_git_work_tree(const char *new_work_tree)
+{
+	if (git_work_tree_initialized) {
+		struct strbuf realpath = STRBUF_INIT;
+
+		strbuf_realpath(&realpath, new_work_tree, 1);
+		new_work_tree = realpath.buf;
+		if (strcmp(new_work_tree, the_repository->worktree))
+			die("internal error: work tree has already been set\n"
+			    "Current worktree: %s\nNew worktree: %s",
+			    the_repository->worktree, new_work_tree);
+		strbuf_release(&realpath);
+		return;
+	}
+	git_work_tree_initialized = 1;
+	repo_set_worktree(the_repository, new_work_tree);
+}
+
 const char *setup_git_directory_gently(int *nongit_ok)
 {
 	static struct strbuf cwd = STRBUF_INIT;
@@ -1836,7 +1942,7 @@ void check_repository_format(struct repository_format *fmt)
 	struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
 	if (!fmt)
 		fmt = &repo_fmt;
-	check_repository_format_gently(get_git_dir(), fmt, NULL);
+	check_repository_format_gently(repo_get_git_dir(the_repository), fmt, NULL);
 	startup_info->have_repository = 1;
 	repo_set_hash_algo(the_repository, fmt->hash_algo);
 	repo_set_compat_hash_algo(the_repository, fmt->compat_hash_algo);
@@ -1907,7 +2013,7 @@ struct template_dir_cb_data {
 };
 
 static int template_dir_cb(const char *key, const char *value,
-			   const struct config_context *ctx, void *d)
+			   const struct config_context *ctx UNUSED, void *d)
 {
 	struct template_dir_cb_data *data = d;
 
@@ -2068,7 +2174,7 @@ static void copy_templates(const char *option_template)
 		goto close_free_return;
 	}
 
-	strbuf_addstr(&path, get_git_common_dir());
+	strbuf_addstr(&path, repo_get_common_dir(the_repository));
 	strbuf_complete(&path, '/');
 	copy_templates_1(&path, &template_path, dir);
 close_free_return:
@@ -2192,7 +2298,7 @@ static int create_default_files(const char *template_path,
 	char *path;
 	int reinit;
 	int filemode;
-	const char *work_tree = get_git_work_tree();
+	const char *work_tree = repo_get_work_tree(the_repository);
 
 	/*
 	 * First copy the templates -- we might have the default
@@ -2224,7 +2330,7 @@ static int create_default_files(const char *template_path,
 	 * shared-repository settings, we would need to fix them up.
 	 */
 	if (get_shared_repository()) {
-		adjust_shared_perm(get_git_dir());
+		adjust_shared_perm(repo_get_git_dir(the_repository));
 	}
 
 	initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, 0);
@@ -2248,7 +2354,7 @@ static int create_default_files(const char *template_path,
 	else {
 		git_config_set("core.bare", "false");
 		/* allow template config file to override the default */
-		if (log_all_ref_updates == LOG_REFS_UNSET)
+		if (repo_settings_get_log_all_ref_updates(the_repository) == LOG_REFS_UNSET)
 			git_config_set("core.logallrefupdates", "true");
 		if (needs_work_tree_config(original_git_dir, work_tree))
 			git_config_set("core.worktree", work_tree);
@@ -2282,7 +2388,7 @@ static void create_object_directory(void)
 	struct strbuf path = STRBUF_INIT;
 	size_t baselen;
 
-	strbuf_addstr(&path, get_object_directory());
+	strbuf_addstr(&path, repo_get_object_directory(the_repository));
 	baselen = path.len;
 
 	safe_create_dir(path.buf, 1);
@@ -2320,14 +2426,67 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
 	write_file(git_link, "gitdir: %s", git_dir);
 }
 
-static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
+struct default_format_config {
+	int hash;
+	enum ref_storage_format ref_format;
+};
+
+static int read_default_format_config(const char *key, const char *value,
+				      const struct config_context *ctx UNUSED,
+				      void *payload)
 {
-	const char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
+	struct default_format_config *cfg = payload;
+	char *str = NULL;
+	int ret;
+
+	if (!strcmp(key, "init.defaultobjectformat")) {
+		ret = git_config_string(&str, key, value);
+		if (ret)
+			goto out;
+		cfg->hash = hash_algo_by_name(str);
+		if (cfg->hash == GIT_HASH_UNKNOWN)
+			warning(_("unknown hash algorithm '%s'"), str);
+		goto out;
+	}
+
+	if (!strcmp(key, "init.defaultrefformat")) {
+		ret = git_config_string(&str, key, value);
+		if (ret)
+			goto out;
+		cfg->ref_format = ref_storage_format_by_name(str);
+		if (cfg->ref_format == REF_STORAGE_FORMAT_UNKNOWN)
+			warning(_("unknown ref storage format '%s'"), str);
+		goto out;
+	}
+
+	ret = 0;
+out:
+	free(str);
+	return ret;
+}
+
+static void repository_format_configure(struct repository_format *repo_fmt,
+					int hash, enum ref_storage_format ref_format)
+{
+	struct default_format_config cfg = {
+		.hash = GIT_HASH_UNKNOWN,
+		.ref_format = REF_STORAGE_FORMAT_UNKNOWN,
+	};
+	struct config_options opts = {
+		.respect_includes = 1,
+		.ignore_repo = 1,
+		.ignore_worktree = 1,
+	};
+	const char *env;
+
+	config_with_options(read_default_format_config, &cfg, NULL, NULL, &opts);
+
 	/*
 	 * If we already have an initialized repo, don't allow the user to
 	 * specify a different algorithm, as that could cause corruption.
 	 * Otherwise, if the user has specified one on the command line, use it.
 	 */
+	env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
 	if (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
 		die(_("attempt to reinitialize repository with different hash"));
 	else if (hash != GIT_HASH_UNKNOWN)
@@ -2337,26 +2496,27 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash
 		if (env_algo == GIT_HASH_UNKNOWN)
 			die(_("unknown hash algorithm '%s'"), env);
 		repo_fmt->hash_algo = env_algo;
+	} else if (cfg.hash != GIT_HASH_UNKNOWN) {
+		repo_fmt->hash_algo = cfg.hash;
 	}
-}
+	repo_set_hash_algo(the_repository, repo_fmt->hash_algo);
 
-static void validate_ref_storage_format(struct repository_format *repo_fmt,
-					enum ref_storage_format format)
-{
-	const char *name = getenv("GIT_DEFAULT_REF_FORMAT");
-
+	env = getenv("GIT_DEFAULT_REF_FORMAT");
 	if (repo_fmt->version >= 0 &&
-	    format != REF_STORAGE_FORMAT_UNKNOWN &&
-	    format != repo_fmt->ref_storage_format) {
+	    ref_format != REF_STORAGE_FORMAT_UNKNOWN &&
+	    ref_format != repo_fmt->ref_storage_format) {
 		die(_("attempt to reinitialize repository with different reference storage format"));
-	} else if (format != REF_STORAGE_FORMAT_UNKNOWN) {
-		repo_fmt->ref_storage_format = format;
-	} else if (name) {
-		format = ref_storage_format_by_name(name);
-		if (format == REF_STORAGE_FORMAT_UNKNOWN)
-			die(_("unknown ref storage format '%s'"), name);
-		repo_fmt->ref_storage_format = format;
+	} else if (ref_format != REF_STORAGE_FORMAT_UNKNOWN) {
+		repo_fmt->ref_storage_format = ref_format;
+	} else if (env) {
+		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;
+	} else if (cfg.ref_format != REF_STORAGE_FORMAT_UNKNOWN) {
+		repo_fmt->ref_storage_format = cfg.ref_format;
 	}
+	repo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format);
 }
 
 int init_db(const char *git_dir, const char *real_git_dir,
@@ -2380,31 +2540,24 @@ int init_db(const char *git_dir, const char *real_git_dir,
 			die(_("%s already exists"), real_git_dir);
 
 		set_git_dir(real_git_dir, 1);
-		git_dir = get_git_dir();
+		git_dir = repo_get_git_dir(the_repository);
 		separate_git_dir(git_dir, original_git_dir);
 	}
 	else {
 		set_git_dir(git_dir, 1);
-		git_dir = get_git_dir();
+		git_dir = repo_get_git_dir(the_repository);
 	}
 	startup_info->have_repository = 1;
 
-	/* Check to see if the repository version is right.
+	/*
+	 * Check to see if the repository version is right.
 	 * Note that a newly created repository does not have
 	 * config file, so this will not fail.  What we are catching
 	 * is an attempt to reinitialize new repository with an old tool.
 	 */
 	check_repository_format(&repo_fmt);
 
-	validate_hash_algorithm(&repo_fmt, hash);
-	validate_ref_storage_format(&repo_fmt, ref_storage_format);
-
-	/*
-	 * Now that we have set up both the hash algorithm and the ref storage
-	 * format we can update the repository's settings accordingly.
-	 */
-	repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
-	repo_set_ref_storage_format(the_repository, repo_fmt.ref_storage_format);
+	repository_format_configure(&repo_fmt, hash, ref_storage_format);
 
 	/*
 	 * Ensure `core.hidedotfiles` is processed. This must happen after we
diff --git a/setup.h b/setup.h
index cd8dbc2..e496ab3 100644
--- a/setup.h
+++ b/setup.h
@@ -94,6 +94,9 @@ static inline int discover_git_directory(struct strbuf *commondir,
 	return 0;
 }
 
+void set_git_dir(const char *path, int make_realpath);
+void set_git_work_tree(const char *tree);
+
 const char *setup_git_directory_gently(int *);
 const char *setup_git_directory(void);
 char *prefix_path(const char *prefix, int len, const char *path);
@@ -176,7 +179,7 @@ int verify_repository_format(const struct repository_format *format,
 			     struct strbuf *err);
 
 /*
- * Check the repository format version in the path found in get_git_dir(),
+ * Check the repository format version in the path found in repo_get_git_dir(the_repository),
  * and die if it is a version we don't understand. Generally one would
  * set_git_dir() before calling this, and use it only for "are we in a valid
  * repo?".
diff --git a/sha1/openssl.h b/sha1/openssl.h
index 006c1f4..1038af4 100644
--- a/sha1/openssl.h
+++ b/sha1/openssl.h
@@ -40,10 +40,12 @@ static inline void openssl_SHA1_Clone(struct openssl_SHA1_CTX *dst,
 	EVP_MD_CTX_copy_ex(dst->ectx, src->ectx);
 }
 
+#ifndef platform_SHA_CTX
 #define platform_SHA_CTX openssl_SHA1_CTX
 #define platform_SHA1_Init openssl_SHA1_Init
 #define platform_SHA1_Clone openssl_SHA1_Clone
 #define platform_SHA1_Update openssl_SHA1_Update
 #define platform_SHA1_Final openssl_SHA1_Final
+#endif
 
 #endif /* SHA1_OPENSSL_H */
diff --git a/sha1dc_git.h b/sha1dc_git.h
index 60e3ce8..f6f880c 100644
--- a/sha1dc_git.h
+++ b/sha1dc_git.h
@@ -18,7 +18,10 @@ void git_SHA1DCFinal(unsigned char [20], SHA1_CTX *);
 void git_SHA1DCUpdate(SHA1_CTX *ctx, const void *data, unsigned long len);
 
 #define platform_SHA_IS_SHA1DC /* used by "test-tool sha1-is-sha1dc" */
+
+#ifndef platform_SHA_CTX
 #define platform_SHA_CTX SHA1_CTX
 #define platform_SHA1_Init git_SHA1DCInit
 #define platform_SHA1_Update git_SHA1DCUpdate
 #define platform_SHA1_Final git_SHA1DCFinal
+#endif
diff --git a/shallow.c b/shallow.c
index 31a6ca4..4bb1518 100644
--- a/shallow.c
+++ b/shallow.c
@@ -51,6 +51,7 @@ int unregister_shallow(const struct object_id *oid)
 	int pos = commit_graft_pos(the_repository, oid);
 	if (pos < 0)
 		return -1;
+	free(the_repository->parsed_objects->grafts[pos]);
 	if (pos + 1 < the_repository->parsed_objects->grafts_nr)
 		MOVE_ARRAY(the_repository->parsed_objects->grafts + pos,
 			   the_repository->parsed_objects->grafts + pos + 1,
@@ -97,7 +98,7 @@ static void reset_repository_shallow(struct repository *r)
 {
 	r->parsed_objects->is_shallow = -1;
 	stat_validity_clear(r->parsed_objects->shallow_stat);
-	reset_commit_grafts(r);
+	parsed_object_pool_reset_commit_grafts(r->parsed_objects);
 }
 
 int commit_shallow_file(struct repository *r, struct shallow_lock *lk)
@@ -487,6 +488,15 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa)
 
 void clear_shallow_info(struct shallow_info *info)
 {
+	if (info->used_shallow) {
+		for (size_t i = 0; i < info->shallow->nr; i++)
+			free(info->used_shallow[i]);
+		free(info->used_shallow);
+	}
+
+	free(info->need_reachability_test);
+	free(info->reachable);
+	free(info->shallow_ref);
 	free(info->ours);
 	free(info->theirs);
 }
@@ -612,6 +622,7 @@ static void paint_down(struct paint_info *info, const struct object_id *oid,
 }
 
 static int mark_uninteresting(const char *refname UNUSED,
+			      const char *referent UNUSED,
 			      const struct object_id *oid,
 			      int flags UNUSED,
 			      void *cb_data UNUSED)
@@ -727,6 +738,7 @@ struct commit_array {
 };
 
 static int add_ref(const char *refname UNUSED,
+		  const char *referent UNUSED,
 		   const struct object_id *oid,
 		   int flags UNUSED,
 		   void *cb_data)
diff --git a/sideband.c b/sideband.c
index 5d89071..0280557 100644
--- a/sideband.c
+++ b/sideband.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "color.h"
 #include "config.h"
@@ -30,28 +32,27 @@ static int use_sideband_colors(void)
 
 	const char *key = "color.remote";
 	struct strbuf sb = STRBUF_INIT;
-	char *value;
+	const char *value;
 	int i;
 
 	if (use_sideband_colors_cached >= 0)
 		return use_sideband_colors_cached;
 
-	if (!git_config_get_string(key, &value)) {
+	if (!git_config_get_string_tmp(key, &value))
 		use_sideband_colors_cached = git_config_colorbool(key, value);
-	} else if (!git_config_get_string("color.ui", &value)) {
+	else if (!git_config_get_string_tmp("color.ui", &value))
 		use_sideband_colors_cached = git_config_colorbool("color.ui", value);
-	} else {
+	else
 		use_sideband_colors_cached = GIT_COLOR_AUTO;
-	}
 
 	for (i = 0; i < ARRAY_SIZE(keywords); i++) {
 		strbuf_reset(&sb);
 		strbuf_addf(&sb, "%s.%s", key, keywords[i].keyword);
-		if (git_config_get_string(sb.buf, &value))
+		if (git_config_get_string_tmp(sb.buf, &value))
 			continue;
-		if (color_parse(value, keywords[i].color))
-			continue;
+		color_parse(value, keywords[i].color);
 	}
+
 	strbuf_release(&sb);
 	return use_sideband_colors_cached;
 }
@@ -190,7 +191,7 @@ int demultiplex_sideband(const char *me, int status,
 			int linelen = brk - b;
 
 			/*
-			 * For message accross packet boundary, there would have
+			 * For message across packet boundary, there would have
 			 * a nonempty "scratch" buffer from last call of this
 			 * function, and there may have a leading CR/LF in "buf".
 			 * For this case we should add a clear-to-eol suffix to
diff --git a/simple-ipc.h b/simple-ipc.h
index a849d9f..3916eaf 100644
--- a/simple-ipc.h
+++ b/simple-ipc.h
@@ -179,11 +179,20 @@ struct ipc_server_opts
  * When a client IPC message is received, the `application_cb` will be
  * called (possibly on a random thread) to handle the message and
  * optionally compose a reply message.
+ *
+ * This initializes all threads but no actual work will be done until
+ * ipc_server_start_async() is called.
  */
-int ipc_server_run_async(struct ipc_server_data **returned_server_data,
-			 const char *path, const struct ipc_server_opts *opts,
-			 ipc_server_application_cb *application_cb,
-			 void *application_data);
+int ipc_server_init_async(struct ipc_server_data **returned_server_data,
+			  const char *path, const struct ipc_server_opts *opts,
+			  ipc_server_application_cb *application_cb,
+			  void *application_data);
+
+/*
+ * Let an async server start running. This needs to be called only once
+ * after initialization.
+ */
+void ipc_server_start_async(struct ipc_server_data *server_data);
 
 /*
  * Gently signal the IPC server pool to shutdown.  No new client
diff --git a/sparse-index.c b/sparse-index.c
index 9958656..3d7f216 100644
--- a/sparse-index.c
+++ b/sparse-index.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "environment.h"
 #include "gettext.h"
@@ -19,9 +21,10 @@
  * advice for advice.sparseIndexExpanded when expanding a sparse index to a full
  * one. However, this is sometimes done on purpose, such as in the sparse-checkout
  * builtin, even when index.sparse=false. This may be disabled in
- * convert_to_sparse().
+ * convert_to_sparse() or by commands that know they will lead to a full
+ * expansion, but this message is not actionable.
  */
-static int give_advice_on_expansion = 1;
+int give_advice_on_expansion = 1;
 #define ADVICE_MSG \
 	"The sparse index is expanding to a full index, a slow operation.\n"   \
 	"Your working directory likely has contents that are outside of\n"     \
diff --git a/sparse-index.h b/sparse-index.h
index a16f3e6..727034b 100644
--- a/sparse-index.h
+++ b/sparse-index.h
@@ -1,6 +1,13 @@
 #ifndef SPARSE_INDEX_H__
 #define SPARSE_INDEX_H__
 
+/*
+ * If performing an operation where the index is supposed to expand to a
+ * full index, then disable the advice message by setting this global to
+ * zero.
+ */
+extern int give_advice_on_expansion;
+
 struct index_state;
 #define SPARSE_INDEX_MEMORY_ONLY (1 << 0)
 int is_sparse_index_allowed(struct index_state *istate, int flags);
diff --git a/statinfo.c b/statinfo.c
index 3c6bc04..30a164b 100644
--- a/statinfo.c
+++ b/statinfo.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "environment.h"
 #include "statinfo.h"
diff --git a/submodule-config.c b/submodule-config.c
index 9b0bb0b..471637a 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -95,7 +95,7 @@ static void free_one_config(struct submodule_entry *entry)
 	free((void *) entry->config->branch);
 	free((void *) entry->config->url);
 	free((void *) entry->config->ignore);
-	free((void *) entry->config->update_strategy.command);
+	submodule_update_strategy_release(&entry->config->update_strategy);
 	free(entry->config);
 }
 
@@ -899,27 +899,25 @@ static void traverse_tree_submodules(struct repository *r,
 {
 	struct tree_desc tree;
 	struct submodule_tree_entry *st_entry;
-	struct name_entry *name_entry;
+	struct name_entry name_entry;
 	char *tree_path = NULL;
 
-	name_entry = xmalloc(sizeof(*name_entry));
-
 	fill_tree_descriptor(r, &tree, treeish_name);
-	while (tree_entry(&tree, name_entry)) {
+	while (tree_entry(&tree, &name_entry)) {
 		if (prefix)
 			tree_path =
-				mkpathdup("%s/%s", prefix, name_entry->path);
+				mkpathdup("%s/%s", prefix, name_entry.path);
 		else
-			tree_path = xstrdup(name_entry->path);
+			tree_path = xstrdup(name_entry.path);
 
-		if (S_ISGITLINK(name_entry->mode) &&
+		if (S_ISGITLINK(name_entry.mode) &&
 		    is_tree_submodule_active(r, root_tree, tree_path)) {
 			ALLOC_GROW(out->entries, out->entry_nr + 1,
 				   out->entry_alloc);
 			st_entry = &out->entries[out->entry_nr++];
 
 			st_entry->name_entry = xmalloc(sizeof(*st_entry->name_entry));
-			*st_entry->name_entry = *name_entry;
+			*st_entry->name_entry = name_entry;
 			st_entry->submodule =
 				submodule_from_path(r, root_tree, tree_path);
 			st_entry->repo = xmalloc(sizeof(*st_entry->repo));
@@ -927,9 +925,9 @@ static void traverse_tree_submodules(struct repository *r,
 						root_tree))
 				FREE_AND_NULL(st_entry->repo);
 
-		} else if (S_ISDIR(name_entry->mode))
+		} else if (S_ISDIR(name_entry.mode))
 			traverse_tree_submodules(r, root_tree, tree_path,
-						 &name_entry->oid, out);
+						 &name_entry.oid, out);
 		free(tree_path);
 	}
 }
diff --git a/submodule.c b/submodule.c
index ab99a30..74d5766 100644
--- a/submodule.c
+++ b/submodule.c
@@ -159,7 +159,7 @@ int remove_path_from_gitmodules(const char *path)
 	}
 	strbuf_addstr(&sect, "submodule.");
 	strbuf_addstr(&sect, submodule->name);
-	if (git_config_rename_section_in_file(GITMODULES_FILE, sect.buf, NULL) < 0) {
+	if (repo_config_rename_section_in_file(the_repository, GITMODULES_FILE, sect.buf, NULL) < 0) {
 		/* Maybe the user already did that, don't error out here */
 		warning(_("Could not remove .gitmodules entry for %s"), path);
 		strbuf_release(&sect);
@@ -175,11 +175,11 @@ void stage_updated_gitmodules(struct index_state *istate)
 		die(_("staging updated .gitmodules failed"));
 }
 
-static struct string_list added_submodule_odb_paths = STRING_LIST_INIT_NODUP;
+static struct string_list added_submodule_odb_paths = STRING_LIST_INIT_DUP;
 
 void add_submodule_odb_by_path(const char *path)
 {
-	string_list_insert(&added_submodule_odb_paths, xstrdup(path));
+	string_list_insert(&added_submodule_odb_paths, path);
 }
 
 int register_all_submodule_odb_as_alternates(void)
@@ -424,6 +424,11 @@ int parse_submodule_update_strategy(const char *value,
 	return 0;
 }
 
+void submodule_update_strategy_release(struct submodule_update_strategy *strategy)
+{
+	free((char *) strategy->command);
+}
+
 const char *submodule_update_type_to_string(enum submodule_update_type type)
 {
 	switch (type) {
@@ -953,6 +958,7 @@ static void free_submodules_data(struct string_list *submodules)
 }
 
 static int has_remote(const char *refname UNUSED,
+		      const char *referent UNUSED,
 		      const struct object_id *oid UNUSED,
 		      int flags UNUSED, void *cb_data UNUSED)
 {
@@ -1273,6 +1279,7 @@ int push_unpushed_submodules(struct repository *r,
 }
 
 static int append_oid_to_array(const char *ref UNUSED,
+			       const char *referent UNUSED,
 			       const struct object_id *oid,
 			       int flags UNUSED, void *data)
 {
@@ -1496,7 +1503,7 @@ static const struct submodule *get_non_gitmodules_submodule(const char *path)
 	return (const struct submodule *) ret;
 }
 
-static void fetch_task_release(struct fetch_task *p)
+static void fetch_task_free(struct fetch_task *p)
 {
 	if (p->free_sub)
 		free((void*)p->sub);
@@ -1508,6 +1515,7 @@ static void fetch_task_release(struct fetch_task *p)
 	FREE_AND_NULL(p->repo);
 
 	strvec_clear(&p->git_args);
+	free(p);
 }
 
 static struct repository *get_submodule_repo_for(struct repository *r,
@@ -1576,8 +1584,7 @@ static struct fetch_task *fetch_task_create(struct submodule_parallel_fetch *spf
 	return task;
 
  cleanup:
-	fetch_task_release(task);
-	free(task);
+	fetch_task_free(task);
 	return NULL;
 }
 
@@ -1607,8 +1614,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,
 		} else {
 			struct strbuf empty_submodule_path = STRBUF_INIT;
 
-			fetch_task_release(task);
-			free(task);
+			fetch_task_free(task);
 
 			/*
 			 * An empty directory is normal,
@@ -1654,8 +1660,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
 				    cs_data->path,
 				    repo_find_unique_abbrev(the_repository, cs_data->super_oid, DEFAULT_ABBREV));
 
-			fetch_task_release(task);
-			free(task);
+			fetch_task_free(task);
 			continue;
 		}
 
@@ -1763,7 +1768,7 @@ static int fetch_start_failure(struct strbuf *err UNUSED,
 
 	spf->result = 1;
 
-	fetch_task_release(task);
+	fetch_task_free(task);
 	return 0;
 }
 
@@ -1828,8 +1833,7 @@ static int fetch_finish(int retvalue, struct strbuf *err UNUSED,
 	}
 
 out:
-	fetch_task_release(task);
-
+	fetch_task_free(task);
 	return 0;
 }
 
@@ -1883,6 +1887,9 @@ int fetch_submodules(struct repository *r,
 	strvec_clear(&spf.args);
 out:
 	free_submodules_data(&spf.changed_submodule_names);
+	string_list_clear(&spf.seen_submodule_names, 0);
+	strbuf_release(&spf.submodules_with_errors);
+	free(spf.oid_fetch_tasks);
 	return spf.result;
 }
 
@@ -2462,7 +2469,7 @@ void absorb_git_dir_into_superproject(const char *path,
 	} else {
 		/* Is it already absorbed into the superprojects git dir? */
 		char *real_sub_git_dir = real_pathdup(sub_git_dir, 1);
-		char *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);
+		char *real_common_git_dir = real_pathdup(repo_get_common_dir(the_repository), 1);
 
 		if (!starts_with(real_sub_git_dir, real_common_git_dir))
 			relocate_single_git_dir_into_superproject(path, super_prefix);
diff --git a/submodule.h b/submodule.h
index b50d29e..4deb1b5 100644
--- a/submodule.h
+++ b/submodule.h
@@ -41,6 +41,10 @@ struct submodule_update_strategy {
 	.type = SM_UPDATE_UNSPECIFIED, \
 }
 
+int parse_submodule_update_strategy(const char *value,
+				    struct submodule_update_strategy *dst);
+void submodule_update_strategy_release(struct submodule_update_strategy *strategy);
+
 int is_gitmodules_unmerged(struct index_state *istate);
 int is_writing_gitmodules_ok(void);
 int is_staging_gitmodules_ok(struct index_state *istate);
@@ -70,8 +74,6 @@ void die_in_unpopulated_submodule(struct index_state *istate,
 void die_path_inside_submodule(struct index_state *istate,
 			       const struct pathspec *ps);
 enum submodule_update_type parse_submodule_update_type(const char *value);
-int parse_submodule_update_strategy(const char *value,
-				    struct submodule_update_strategy *dst);
 const char *submodule_update_type_to_string(enum submodule_update_type type);
 void handle_ignore_submodules_arg(struct diff_options *, const char *);
 void show_submodule_diff_summary(struct diff_options *o, const char *path,
diff --git a/t/Makefile b/t/Makefile
index 4c30e7c..131ffd7 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -48,6 +48,7 @@
 CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl
 UNIT_TEST_SOURCES = $(wildcard unit-tests/t-*.c)
 UNIT_TEST_PROGRAMS = $(patsubst unit-tests/%.c,unit-tests/bin/%$(X),$(UNIT_TEST_SOURCES))
+UNIT_TEST_PROGRAMS += unit-tests/bin/unit-tests$(X)
 UNIT_TESTS = $(sort $(UNIT_TEST_PROGRAMS))
 UNIT_TESTS_NO_DIR = $(notdir $(UNIT_TESTS))
 
@@ -68,7 +69,8 @@
 	test -z "$$failed" || $(MAKE) $$failed
 
 prove: pre-clean check-chainlint $(TEST_LINT)
-	@echo "*** prove (shell & unit tests) ***"; $(CHAINLINTSUPPRESS) TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS) :: $(GIT_TEST_OPTS)
+	@echo "*** prove (shell & unit tests) ***"
+	@$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)
 	$(MAKE) clean-except-prove-cache
 
 $(T):
diff --git a/t/README b/t/README
index 724ee58..8dcb778 100644
--- a/t/README
+++ b/t/README
@@ -386,6 +386,9 @@
 will run to completion faster, and result in the same failing
 tests.
 
+GIT_TEST_PASSING_SANITIZE_LEAK=check-failing behaves the same as "check",
+but skips all tests which are already marked as leak-free.
+
 GIT_TEST_PROTOCOL_VERSION=<n>, when set, makes 'protocol.version'
 default to n.
 
@@ -445,9 +448,9 @@
 index to be written after every 'git repack' command, and overrides the
 'core.multiPackIndex' setting to true.
 
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=<boolean>, when true, sets the
-'--bitmap' option on all invocations of 'git multi-pack-index write',
-and ignores pack-objects' '--write-bitmap-index'.
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=<boolean>, when true, sets
+the '--incremental' option on all invocations of 'git multi-pack-index
+write'.
 
 GIT_TEST_SIDEBAND_ALL=<boolean>, when true, overrides the
 'uploadpack.allowSidebandAll' setting to true, and when false, forces
diff --git a/t/chainlint.pl b/t/chainlint.pl
index 5361f23..f0598e3 100755
--- a/t/chainlint.pl
+++ b/t/chainlint.pl
@@ -9,9 +9,9 @@
 # Input arguments are pathnames of shell scripts containing test definitions,
 # or globs referencing a collection of scripts. For each problem discovered,
 # the pathname of the script containing the test is printed along with the test
-# name and the test body with a `?!FOO?!` annotation at the location of each
-# detected problem, where "FOO" is a tag such as "AMP" which indicates a broken
-# &&-chain. Returns zero if no problems are discovered, otherwise non-zero.
+# name and the test body with a `?!LINT: ...?!` annotation at the location of
+# each detected problem, where "..." is an explanation of the problem. Returns
+# zero if no problems are discovered, otherwise non-zero.
 
 use warnings;
 use strict;
@@ -181,7 +181,7 @@
 			$self->{lineno} += () = $body =~ /\n/sg;
 			next;
 		}
-		push(@{$self->{parser}->{problems}}, ['UNCLOSED-HEREDOC', $tag]);
+		push(@{$self->{parser}->{problems}}, ['HEREDOC', $tag]);
 		$$b =~ /(?:\G|\n).*\z/gc; # consume rest of input
 		my $body = substr($$b, $start, pos($$b) - $start);
 		$self->{lineno} += () = $body =~ /\n/sg;
@@ -238,6 +238,7 @@
 		stop => [],
 		output => [],
 		heredocs => {},
+		insubshell => 0,
 	} => $class;
 	$self->{lexer} = Lexer->new($self, $s);
 	return $self;
@@ -296,8 +297,11 @@
 
 sub parse_subshell {
 	my $self = shift @_;
-	return ($self->parse(qr/^\)$/),
-		$self->expect(')'));
+	$self->{insubshell}++;
+	my @tokens = ($self->parse(qr/^\)$/),
+		      $self->expect(')'));
+	$self->{insubshell}--;
+	return @tokens;
 }
 
 sub parse_case_pattern {
@@ -528,7 +532,7 @@
 	return @tokens if ends_with(\@tokens, [qr/^\|\|$/, "\n", qr/^echo$/, qr/^.+$/]);
 	# flag missing "return/exit" handling explicit failure in loop body
 	my $n = find_non_nl(\@tokens);
-	push(@{$self->{problems}}, ['LOOP', $tokens[$n]]);
+	push(@{$self->{problems}}, [$self->{insubshell} ? 'LOOPEXIT' : 'LOOPRETURN', $tokens[$n]]);
 	return @tokens;
 }
 
@@ -587,6 +591,7 @@
 	my $class = shift @_;
 	my $self = $class->SUPER::new(@_);
 	$self->{ntests} = 0;
+	$self->{nerrs} = 0;
 	return $self;
 }
 
@@ -619,6 +624,15 @@
 	return $s
 }
 
+sub format_problem {
+	local $_ = shift;
+	/^AMP$/ && return "missing '&&'";
+	/^LOOPRETURN$/ && return "missing '|| return 1'";
+	/^LOOPEXIT$/ && return "missing '|| exit 1'";
+	/^HEREDOC$/ && return 'unclosed heredoc';
+	die("unrecognized problem type '$_'\n");
+}
+
 sub check_test {
 	my $self = shift @_;
 	my $title = unwrap(shift @_);
@@ -634,22 +648,26 @@
 	my $parser = TestParser->new(\$body);
 	my @tokens = $parser->parse();
 	my $problems = $parser->{problems};
+	$self->{nerrs} += @$problems;
 	return unless $emit_all || @$problems;
 	my $c = main::fd_colors(1);
+	my ($erropen, $errclose) = -t 1 ? ("$c->{rev}$c->{red}", $c->{reset}) : ('?!', '?!');
 	my $start = 0;
 	my $checked = '';
 	for (sort {$a->[1]->[2] <=> $b->[1]->[2]} @$problems) {
 		my ($label, $token) = @$_;
 		my $pos = $token->[2];
-		$checked .= substr($body, $start, $pos - $start) . " ?!$label?! ";
+		my $err = format_problem($label);
+		$checked .= substr($body, $start, $pos - $start);
+		$checked .= ' ' unless $checked =~ /\s$/;
+		$checked .= "${erropen}LINT: $err$errclose";
+		$checked .= ' ' unless $pos >= length($body) ||
+		    substr($body, $pos, 1) =~ /^\s/;
 		$start = $pos;
 	}
 	$checked .= substr($body, $start);
 	$checked =~ s/^/$lineno++ . ' '/mge;
 	$checked =~ s/^\d+ \n//;
-	$checked =~ s/(\s) \?!/$1?!/mg;
-	$checked =~ s/\?! (\s)/?!$1/mg;
-	$checked =~ s/(\?![^?]+\?!)/$c->{rev}$c->{red}$1$c->{reset}/mg;
 	$checked =~ s/^\d+/$c->{dim}$&$c->{reset}/mg;
 	$checked .= "\n" unless $checked =~ /\n$/;
 	push(@{$self->{output}}, "$c->{blue}# chainlint: $title$c->{reset}\n$checked");
@@ -791,9 +809,9 @@
 			my $c = fd_colors(1);
 			my $s = join('', @{$parser->{output}});
 			$emit->("$c->{bold}$c->{blue}# chainlint: $path$c->{reset}\n" . $s);
-			$nerrs += () = $s =~ /\?![^?]+\?!/g;
 		}
 		$ntests += $parser->{ntests};
+		$nerrs += $parser->{nerrs};
 	}
 	return [$id, $nscripts, $ntests, $nerrs];
 }
diff --git a/t/chainlint/arithmetic-expansion.expect b/t/chainlint/arithmetic-expansion.expect
index 338ecd5..5677e16 100644
--- a/t/chainlint/arithmetic-expansion.expect
+++ b/t/chainlint/arithmetic-expansion.expect
@@ -4,6 +4,6 @@
 5 	baz
 6 ) &&
 7 (
-8 	bar=$((42 + 1)) ?!AMP?!
+8 	bar=$((42 + 1)) ?!LINT: missing '&&'?!
 9 	baz
 10 )
diff --git a/t/chainlint/block.expect b/t/chainlint/block.expect
index b62e3d5..3d3f854 100644
--- a/t/chainlint/block.expect
+++ b/t/chainlint/block.expect
@@ -1,20 +1,20 @@
 2 (
 3 	foo &&
 4 	{
-5 		echo a ?!AMP?!
+5 		echo a ?!LINT: missing '&&'?!
 6 		echo b
 7 	} &&
 8 	bar &&
 9 	{
 10 		echo c
-11 	} ?!AMP?!
+11 	} ?!LINT: missing '&&'?!
 12 	baz
 13 ) &&
 14 
 15 {
-16 	echo a; ?!AMP?! echo b
+16 	echo a; ?!LINT: missing '&&'?! echo b
 17 } &&
-18 { echo a; ?!AMP?! echo b; } &&
+18 { echo a; ?!LINT: missing '&&'?! echo b; } &&
 19 
 20 {
 21 	echo "${var}9" &&
diff --git a/t/chainlint/broken-chain.expect b/t/chainlint/broken-chain.expect
index 9a18387..b7b1ce8 100644
--- a/t/chainlint/broken-chain.expect
+++ b/t/chainlint/broken-chain.expect
@@ -1,6 +1,6 @@
 2 (
 3 	foo &&
-4 	bar ?!AMP?!
+4 	bar ?!LINT: missing '&&'?!
 5 	baz &&
 6 	wop
 7 )
diff --git a/t/chainlint/case.expect b/t/chainlint/case.expect
index c04c61f..0a3b09e 100644
--- a/t/chainlint/case.expect
+++ b/t/chainlint/case.expect
@@ -9,11 +9,11 @@
 10 	case "$x" in
 11 	x) foo ;;
 12 	*) bar ;;
-13 	esac ?!AMP?!
+13 	esac ?!LINT: missing '&&'?!
 14 	foobar
 15 ) &&
 16 (
 17 	case "$x" in 1) true;; esac &&
-18 	case "$y" in 2) false;; esac ?!AMP?!
+18 	case "$y" in 2) false;; esac ?!LINT: missing '&&'?!
 19 	foobar
 20 )
diff --git a/t/chainlint/chain-break-false.expect b/t/chainlint/chain-break-false.expect
index 4f815f8..f6a0a30 100644
--- a/t/chainlint/chain-break-false.expect
+++ b/t/chainlint/chain-break-false.expect
@@ -4,6 +4,6 @@
 5 	echo failed!
 6 	false
 7 else
-8 	echo it went okay ?!AMP?!
+8 	echo it went okay ?!LINT: missing '&&'?!
 9 	congratulate user
 10 fi
diff --git a/t/chainlint/chained-block.expect b/t/chainlint/chained-block.expect
index a546b71..f2501bb 100644
--- a/t/chainlint/chained-block.expect
+++ b/t/chainlint/chained-block.expect
@@ -1,5 +1,5 @@
 2 echo nobody home && {
-3 	test the doohicky ?!AMP?!
+3 	test the doohicky ?!LINT: missing '&&'?!
 4 	right now
 5 } &&
 6 
diff --git a/t/chainlint/chained-subshell.expect b/t/chainlint/chained-subshell.expect
index f78b268..93fb1a6 100644
--- a/t/chainlint/chained-subshell.expect
+++ b/t/chainlint/chained-subshell.expect
@@ -1,10 +1,10 @@
 2 mkdir sub && (
 3 	cd sub &&
-4 	foo the bar ?!AMP?!
+4 	foo the bar ?!LINT: missing '&&'?!
 5 	nuff said
 6 ) &&
 7 
 8 cut "-d " -f actual | (read s1 s2 s3 &&
-9 test -f $s1 ?!AMP?!
+9 test -f $s1 ?!LINT: missing '&&'?!
 10 test $(cat $s2) = tree2path1 &&
 11 test $(cat $s3) = tree3path1)
diff --git a/t/chainlint/command-substitution.expect b/t/chainlint/command-substitution.expect
index 5e31b36..73809fd 100644
--- a/t/chainlint/command-substitution.expect
+++ b/t/chainlint/command-substitution.expect
@@ -4,6 +4,6 @@
 5 	baz
 6 ) &&
 7 (
-8 	bar=$(gobble blocks) ?!AMP?!
+8 	bar=$(gobble blocks) ?!LINT: missing '&&'?!
 9 	baz
 10 )
diff --git a/t/chainlint/complex-if-in-cuddled-loop.expect b/t/chainlint/complex-if-in-cuddled-loop.expect
index 3a74010..e66bb2d 100644
--- a/t/chainlint/complex-if-in-cuddled-loop.expect
+++ b/t/chainlint/complex-if-in-cuddled-loop.expect
@@ -4,6 +4,6 @@
 5      :
 6    else
 7      echo >file
-8    fi ?!LOOP?!
+8    fi ?!LINT: missing '|| exit 1'?!
 9  done) &&
 10 test ! -f file
diff --git a/t/chainlint/cuddled.expect b/t/chainlint/cuddled.expect
index b06d638..1864b3f 100644
--- a/t/chainlint/cuddled.expect
+++ b/t/chainlint/cuddled.expect
@@ -2,7 +2,7 @@
 3 	bar
 4 ) &&
 5 
-6 (cd foo ?!AMP?!
+6 (cd foo ?!LINT: missing '&&'?!
 7 	bar
 8 ) &&
 9 
@@ -13,5 +13,5 @@
 14 (cd foo &&
 15 	bar) &&
 16 
-17 (cd foo ?!AMP?!
+17 (cd foo ?!LINT: missing '&&'?!
 18 	bar)
diff --git a/t/chainlint/for-loop.expect b/t/chainlint/for-loop.expect
index 908aeedf..5029eac 100644
--- a/t/chainlint/for-loop.expect
+++ b/t/chainlint/for-loop.expect
@@ -1,14 +1,14 @@
 2 (
 3 	for i in a b c
 4 	do
-5 		echo $i ?!AMP?!
-6 		cat <<-\EOF ?!LOOP?!
+5 		echo $i ?!LINT: missing '&&'?!
+6 		cat <<-\EOF ?!LINT: missing '|| exit 1'?!
 7 		bar
 8 		EOF
-9 	done ?!AMP?!
+9 	done ?!LINT: missing '&&'?!
 10 
 11 	for i in a b c; do
 12 		echo $i &&
-13 		cat $i ?!LOOP?!
+13 		cat $i ?!LINT: missing '|| exit 1'?!
 14 	done
 15 )
diff --git a/t/chainlint/function.expect b/t/chainlint/function.expect
index c226246..9e46a35 100644
--- a/t/chainlint/function.expect
+++ b/t/chainlint/function.expect
@@ -4,8 +4,8 @@
 5 
 6 remove_object() {
 7 	file=$(sha1_file "$*") &&
-8 	test -e "$file" ?!AMP?!
+8 	test -e "$file" ?!LINT: missing '&&'?!
 9 	rm -f "$file"
-10 } ?!AMP?!
+10 } ?!LINT: missing '&&'?!
 11 
 12 sha1_file arg && remove_object arg
diff --git a/t/chainlint/here-doc-body-indent.expect b/t/chainlint/here-doc-body-indent.expect
index 4323acc..4306fae 100644
--- a/t/chainlint/here-doc-body-indent.expect
+++ b/t/chainlint/here-doc-body-indent.expect
@@ -1,2 +1,2 @@
-2 	echo "we should find this" ?!AMP?!
+2 	echo "we should find this" ?!LINT: missing '&&'?!
 3 	echo "even though our heredoc has its indent stripped"
diff --git a/t/chainlint/here-doc-body-pathological.expect b/t/chainlint/here-doc-body-pathological.expect
index a93a1fa..2f8ea03 100644
--- a/t/chainlint/here-doc-body-pathological.expect
+++ b/t/chainlint/here-doc-body-pathological.expect
@@ -1,7 +1,7 @@
-2 	echo "outer here-doc does not allow indented end-tag" ?!AMP?!
+2 	echo "outer here-doc does not allow indented end-tag" ?!LINT: missing '&&'?!
 3 	cat >file <<-\EOF &&
 4 	but this inner here-doc
 5 	does allow indented EOF
 6 	EOF
-7 	echo "missing chain after" ?!AMP?!
+7 	echo "missing chain after" ?!LINT: missing '&&'?!
 8 	echo "but this line is OK because it's the end"
diff --git a/t/chainlint/here-doc-body.expect b/t/chainlint/here-doc-body.expect
index ddf1c41..df8d79b 100644
--- a/t/chainlint/here-doc-body.expect
+++ b/t/chainlint/here-doc-body.expect
@@ -1,7 +1,7 @@
-2 	echo "missing chain before" ?!AMP?!
+2 	echo "missing chain before" ?!LINT: missing '&&'?!
 3 	cat >file <<-\EOF &&
 4 	inside inner here-doc
 5 	these are not shell commands
 6 	EOF
-7 	echo "missing chain after" ?!AMP?!
+7 	echo "missing chain after" ?!LINT: missing '&&'?!
 8 	echo "but this line is OK because it's the end"
diff --git a/t/chainlint/here-doc-double.expect b/t/chainlint/here-doc-double.expect
index 20dba4b..e5e9818 100644
--- a/t/chainlint/here-doc-double.expect
+++ b/t/chainlint/here-doc-double.expect
@@ -1,2 +1,2 @@
-8 	echo "actual test commands" ?!AMP?!
+8 	echo "actual test commands" ?!LINT: missing '&&'?!
 9 	echo "that should be checked"
diff --git a/t/chainlint/here-doc-indent-operator.expect b/t/chainlint/here-doc-indent-operator.expect
index 277a112..ec0e615 100644
--- a/t/chainlint/here-doc-indent-operator.expect
+++ b/t/chainlint/here-doc-indent-operator.expect
@@ -4,7 +4,7 @@
 5 chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data
 6 EOF
 7 
-8 cat >expect << -EOF ?!AMP?!
+8 cat >expect << -EOF ?!LINT: missing '&&'?!
 9 this is not indented
 10 -EOF
 11 
diff --git a/t/chainlint/here-doc-multi-line-command-subst.expect b/t/chainlint/here-doc-multi-line-command-subst.expect
index 41b55f6..8128f15 100644
--- a/t/chainlint/here-doc-multi-line-command-subst.expect
+++ b/t/chainlint/here-doc-multi-line-command-subst.expect
@@ -3,6 +3,6 @@
 4 		fossil
 5 		vegetable
 6 		END
-7 		wiffle) ?!AMP?!
+7 		wiffle) ?!LINT: missing '&&'?!
 8 	echo $x
 9 )
diff --git a/t/chainlint/here-doc-multi-line-string.expect b/t/chainlint/here-doc-multi-line-string.expect
index c718285..a03a04f 100644
--- a/t/chainlint/here-doc-multi-line-string.expect
+++ b/t/chainlint/here-doc-multi-line-string.expect
@@ -1,6 +1,6 @@
 2 (
 3 	cat <<-\TXT && echo "multi-line
-4 	string" ?!AMP?!
+4 	string" ?!LINT: missing '&&'?!
 5 	fizzle
 6 	TXT
 7 	bap
diff --git a/t/chainlint/if-condition-split.expect b/t/chainlint/if-condition-split.expect
index 9daf3d2..6d2a03d 100644
--- a/t/chainlint/if-condition-split.expect
+++ b/t/chainlint/if-condition-split.expect
@@ -2,6 +2,6 @@
 3    marcia ||
 4    kevin
 5 then
-6 	echo "nomads" ?!AMP?!
+6 	echo "nomads" ?!LINT: missing '&&'?!
 7 	echo "for sure"
 8 fi
diff --git a/t/chainlint/if-in-loop.expect b/t/chainlint/if-in-loop.expect
index ff8c60d..7e3ba74 100644
--- a/t/chainlint/if-in-loop.expect
+++ b/t/chainlint/if-in-loop.expect
@@ -5,8 +5,8 @@
 6 		then
 7 			echo "err"
 8 			exit 1
-9 		fi ?!AMP?!
+9 		fi ?!LINT: missing '&&'?!
 10 		foo
-11 	done ?!AMP?!
+11 	done ?!LINT: missing '&&'?!
 12 	bar
 13 )
diff --git a/t/chainlint/if-then-else.expect b/t/chainlint/if-then-else.expect
index 965d7e4..924caa2 100644
--- a/t/chainlint/if-then-else.expect
+++ b/t/chainlint/if-then-else.expect
@@ -1,7 +1,7 @@
 2 (
 3 	if test -n ""
 4 	then
-5 		echo very ?!AMP?!
+5 		echo very ?!LINT: missing '&&'?!
 6 		echo empty
 7 	elif test -z ""
 8 	then
@@ -11,7 +11,7 @@
 12 		cat <<-\EOF
 13 		bar
 14 		EOF
-15 	fi ?!AMP?!
+15 	fi ?!LINT: missing '&&'?!
 16 	echo poodle
 17 ) &&
 18 (
diff --git a/t/chainlint/inline-comment.expect b/t/chainlint/inline-comment.expect
index 0285c0b..4b40801 100644
--- a/t/chainlint/inline-comment.expect
+++ b/t/chainlint/inline-comment.expect
@@ -1,6 +1,6 @@
 2 (
 3 	foobar && # comment 1
-4 	barfoo ?!AMP?! # wrong position for &&
+4 	barfoo ?!LINT: missing '&&'?! # wrong position for &&
 5 	flibble "not a # comment"
 6 ) &&
 7 
diff --git a/t/chainlint/loop-detect-failure.expect b/t/chainlint/loop-detect-failure.expect
index 40c06f0..7d846b8 100644
--- a/t/chainlint/loop-detect-failure.expect
+++ b/t/chainlint/loop-detect-failure.expect
@@ -11,5 +11,5 @@
 12 do
 13 	printf "%"$n"s" X > r2/large.$n &&
 14 	git -C r2 add large.$n &&
-15 	git -C r2 commit -m "$n" ?!LOOP?!
+15 	git -C r2 commit -m "$n" ?!LINT: missing '|| return 1'?!
 16 done
diff --git a/t/chainlint/loop-in-if.expect b/t/chainlint/loop-in-if.expect
index 4e8c67c..32e076a 100644
--- a/t/chainlint/loop-in-if.expect
+++ b/t/chainlint/loop-in-if.expect
@@ -3,10 +3,10 @@
 4 	then
 5 		while true
 6 		do
-7 			echo "pop" ?!AMP?!
-8 			echo "glup" ?!LOOP?!
-9 		done ?!AMP?!
+7 			echo "pop" ?!LINT: missing '&&'?!
+8 			echo "glup" ?!LINT: missing '|| exit 1'?!
+9 		done ?!LINT: missing '&&'?!
 10 		foo
-11 	fi ?!AMP?!
+11 	fi ?!LINT: missing '&&'?!
 12 	bar
 13 )
diff --git a/t/chainlint/multi-line-string.expect b/t/chainlint/multi-line-string.expect
index 62c54e3..9d33297 100644
--- a/t/chainlint/multi-line-string.expect
+++ b/t/chainlint/multi-line-string.expect
@@ -3,7 +3,7 @@
 4 		line 2
 5 		line 3" &&
 6 	y="line 1
-7 		line2" ?!AMP?!
+7 		line2" ?!LINT: missing '&&'?!
 8 	foobar
 9 ) &&
 10 (
diff --git a/t/chainlint/negated-one-liner.expect b/t/chainlint/negated-one-liner.expect
index a6ce52a..0a6f3c2 100644
--- a/t/chainlint/negated-one-liner.expect
+++ b/t/chainlint/negated-one-liner.expect
@@ -1,5 +1,5 @@
 2 ! (foo && bar) &&
 3 ! (foo && bar) >baz &&
 4 
-5 ! (foo; ?!AMP?! bar) &&
-6 ! (foo; ?!AMP?! bar) >baz
+5 ! (foo; ?!LINT: missing '&&'?! bar) &&
+6 ! (foo; ?!LINT: missing '&&'?! bar) >baz
diff --git a/t/chainlint/nested-cuddled-subshell.expect b/t/chainlint/nested-cuddled-subshell.expect
index 0191c9c..fec2c74 100644
--- a/t/chainlint/nested-cuddled-subshell.expect
+++ b/t/chainlint/nested-cuddled-subshell.expect
@@ -5,7 +5,7 @@
 6 
 7 	(cd foo &&
 8 		bar
-9 	) ?!AMP?!
+9 	) ?!LINT: missing '&&'?!
 10 
 11 	(
 12 		cd foo &&
@@ -13,13 +13,13 @@
 14 
 15 	(
 16 		cd foo &&
-17 		bar) ?!AMP?!
+17 		bar) ?!LINT: missing '&&'?!
 18 
 19 	(cd foo &&
 20 		bar) &&
 21 
 22 	(cd foo &&
-23 		bar) ?!AMP?!
+23 		bar) ?!LINT: missing '&&'?!
 24 
 25 	foobar
 26 )
diff --git a/t/chainlint/nested-here-doc.expect b/t/chainlint/nested-here-doc.expect
index 70d9b68..571f4c9 100644
--- a/t/chainlint/nested-here-doc.expect
+++ b/t/chainlint/nested-here-doc.expect
@@ -18,7 +18,7 @@
 19 	toink
 20 	INPUT_END
 21 
-22 	cat <<-\EOT ?!AMP?!
+22 	cat <<-\EOT ?!LINT: missing '&&'?!
 23 	text goes here
 24 	data <<EOF
 25 		data goes here
diff --git a/t/chainlint/nested-loop-detect-failure.expect b/t/chainlint/nested-loop-detect-failure.expect
index c13c4d2..b4aaa62 100644
--- a/t/chainlint/nested-loop-detect-failure.expect
+++ b/t/chainlint/nested-loop-detect-failure.expect
@@ -2,8 +2,8 @@
 3 do
 4 	for j in 0 1 2 3 4 5 6 7 8 9;
 5 	do
-6 		echo "$i$j" >"path$i$j" ?!LOOP?!
-7 	done ?!LOOP?!
+6 		echo "$i$j" >"path$i$j" ?!LINT: missing '|| return 1'?!
+7 	done ?!LINT: missing '|| return 1'?!
 8 done &&
 9 
 10 for i in 0 1 2 3 4 5 6 7 8 9;
@@ -18,7 +18,7 @@
 19 do
 20 	for j in 0 1 2 3 4 5 6 7 8 9;
 21 	do
-22 		echo "$i$j" >"path$i$j" ?!LOOP?!
+22 		echo "$i$j" >"path$i$j" ?!LINT: missing '|| return 1'?!
 23 	done || return 1
 24 done &&
 25 
diff --git a/t/chainlint/nested-subshell-comment.expect b/t/chainlint/nested-subshell-comment.expect
index f89a8d0..078c6f2 100644
--- a/t/chainlint/nested-subshell-comment.expect
+++ b/t/chainlint/nested-subshell-comment.expect
@@ -6,6 +6,6 @@
 7 		# minor numbers of cows (or do they?)
 8 		baz &&
 9 		snaff
-10 	) ?!AMP?!
+10 	) ?!LINT: missing '&&'?!
 11 	fuzzy
 12 )
diff --git a/t/chainlint/nested-subshell.expect b/t/chainlint/nested-subshell.expect
index 811e8a7..a8d85d5 100644
--- a/t/chainlint/nested-subshell.expect
+++ b/t/chainlint/nested-subshell.expect
@@ -7,7 +7,7 @@
 8 
 9 	cd foo &&
 10 	(
-11 		echo a ?!AMP?!
+11 		echo a ?!LINT: missing '&&'?!
 12 		echo b
 13 	) >file
 14 )
diff --git a/t/chainlint/not-heredoc.expect b/t/chainlint/not-heredoc.expect
index 611b7b7..5d51705 100644
--- a/t/chainlint/not-heredoc.expect
+++ b/t/chainlint/not-heredoc.expect
@@ -9,6 +9,6 @@
 10 	echo ourside &&
 11 	echo "=======" &&
 12 	echo theirside &&
-13 	echo ">>>>>>> theirs" ?!AMP?!
+13 	echo ">>>>>>> theirs" ?!LINT: missing '&&'?!
 14 	poodle
 15 ) >merged
diff --git a/t/chainlint/one-liner-for-loop.expect b/t/chainlint/one-liner-for-loop.expect
index 49dcf06..e1fcbd3 100644
--- a/t/chainlint/one-liner-for-loop.expect
+++ b/t/chainlint/one-liner-for-loop.expect
@@ -3,7 +3,7 @@
 4 	cd dir-rename-and-content &&
 5 	test_write_lines 1 2 3 4 5 >foo &&
 6 	mkdir olddir &&
-7 	for i in a b c; do echo $i >olddir/$i; ?!LOOP?! done ?!AMP?!
+7 	for i in a b c; do echo $i >olddir/$i; ?!LINT: missing '|| exit 1'?! done ?!LINT: missing '&&'?!
 8 	git add foo olddir &&
 9 	git commit -m "original" &&
 10 )
diff --git a/t/chainlint/one-liner.expect b/t/chainlint/one-liner.expect
index 9861811..5deeb05 100644
--- a/t/chainlint/one-liner.expect
+++ b/t/chainlint/one-liner.expect
@@ -2,8 +2,8 @@
 3 (foo && bar) |
 4 (foo && bar) >baz &&
 5 
-6 (foo; ?!AMP?! bar) &&
-7 (foo; ?!AMP?! bar) |
-8 (foo; ?!AMP?! bar) >baz &&
+6 (foo; ?!LINT: missing '&&'?! bar) &&
+7 (foo; ?!LINT: missing '&&'?! bar) |
+8 (foo; ?!LINT: missing '&&'?! bar) >baz &&
 9 
 10 (foo "bar; baz")
diff --git a/t/chainlint/pipe.expect b/t/chainlint/pipe.expect
index 1bbe5a2..d947c76 100644
--- a/t/chainlint/pipe.expect
+++ b/t/chainlint/pipe.expect
@@ -4,7 +4,7 @@
 5 	baz &&
 6 
 7 	fish |
-8 	cow ?!AMP?!
+8 	cow ?!LINT: missing '&&'?!
 9 
 10 	sunder
 11 )
diff --git a/t/chainlint/semicolon.expect b/t/chainlint/semicolon.expect
index 8664383..2b499fb 100644
--- a/t/chainlint/semicolon.expect
+++ b/t/chainlint/semicolon.expect
@@ -1,19 +1,19 @@
 2 (
-3 	cat foo ; ?!AMP?! echo bar ?!AMP?!
-4 	cat foo ; ?!AMP?! echo bar
+3 	cat foo ; ?!LINT: missing '&&'?! echo bar ?!LINT: missing '&&'?!
+4 	cat foo ; ?!LINT: missing '&&'?! echo bar
 5 ) &&
 6 (
-7 	cat foo ; ?!AMP?! echo bar &&
-8 	cat foo ; ?!AMP?! echo bar
+7 	cat foo ; ?!LINT: missing '&&'?! echo bar &&
+8 	cat foo ; ?!LINT: missing '&&'?! echo bar
 9 ) &&
 10 (
 11 	echo "foo; bar" &&
-12 	cat foo; ?!AMP?! echo bar
+12 	cat foo; ?!LINT: missing '&&'?! echo bar
 13 ) &&
 14 (
 15 	foo;
 16 ) &&
 17 (cd foo &&
 18 	for i in a b c; do
-19 		echo; ?!LOOP?!
+19 		echo; ?!LINT: missing '|| exit 1'?!
 20 	done)
diff --git a/t/chainlint/subshell-here-doc.expect b/t/chainlint/subshell-here-doc.expect
index 5647500..e450caf 100644
--- a/t/chainlint/subshell-here-doc.expect
+++ b/t/chainlint/subshell-here-doc.expect
@@ -6,7 +6,7 @@
 7 	nevermore...
 8 	EOF
 9 
-10 	cat <<EOF >bip ?!AMP?!
+10 	cat <<EOF >bip ?!LINT: missing '&&'?!
 11 	fish fly high
 12 EOF
 13 
diff --git a/t/chainlint/subshell-one-liner.expect b/t/chainlint/subshell-one-liner.expect
index 214316c..265d996 100644
--- a/t/chainlint/subshell-one-liner.expect
+++ b/t/chainlint/subshell-one-liner.expect
@@ -3,17 +3,17 @@
 4 	(foo && bar) |
 5 	(foo && bar) >baz &&
 6 
-7 	(foo; ?!AMP?! bar) &&
-8 	(foo; ?!AMP?! bar) |
-9 	(foo; ?!AMP?! bar) >baz &&
+7 	(foo; ?!LINT: missing '&&'?! bar) &&
+8 	(foo; ?!LINT: missing '&&'?! bar) |
+9 	(foo; ?!LINT: missing '&&'?! bar) >baz &&
 10 
 11 	(foo || exit 1) &&
 12 	(foo || exit 1) |
 13 	(foo || exit 1) >baz &&
 14 
-15 	(foo && bar) ?!AMP?!
+15 	(foo && bar) ?!LINT: missing '&&'?!
 16 
-17 	(foo && bar; ?!AMP?! baz) ?!AMP?!
+17 	(foo && bar; ?!LINT: missing '&&'?! baz) ?!LINT: missing '&&'?!
 18 
 19 	foobar
 20 )
diff --git a/t/chainlint/token-pasting.expect b/t/chainlint/token-pasting.expect
index 64f3235..387189b 100644
--- a/t/chainlint/token-pasting.expect
+++ b/t/chainlint/token-pasting.expect
@@ -2,13 +2,13 @@
 3 git config filter.rot13.clean ./rot13.sh &&
 4 
 5 {
-6     echo "*.t filter=rot13" ?!AMP?!
+6     echo "*.t filter=rot13" ?!LINT: missing '&&'?!
 7     echo "*.i ident"
 8 } >.gitattributes &&
 9 
 10 {
-11     echo a b c d e f g h i j k l m ?!AMP?!
-12     echo n o p q r s t u v w x y z ?!AMP?!
+11     echo a b c d e f g h i j k l m ?!LINT: missing '&&'?!
+12     echo n o p q r s t u v w x y z ?!LINT: missing '&&'?!
 13     echo '$Id$'
 14 } >test &&
 15 cat test >test.t &&
@@ -19,7 +19,7 @@
 20 git checkout -- test test.t test.i &&
 21 
 22 echo "content-test2" >test2.o &&
-23 echo "content-test3 - filename with special characters" >"test3 'sq',$x=.o" ?!AMP?!
+23 echo "content-test3 - filename with special characters" >"test3 'sq',$x=.o" ?!LINT: missing '&&'?!
 24 
 25 downstream_url_for_sed=$(
 26 	printf "%sn" "$downstream_url" |
diff --git a/t/chainlint/unclosed-here-doc-indent.expect b/t/chainlint/unclosed-here-doc-indent.expect
index f78e23c..156906c 100644
--- a/t/chainlint/unclosed-here-doc-indent.expect
+++ b/t/chainlint/unclosed-here-doc-indent.expect
@@ -1,4 +1,4 @@
 2 command_which_is_run &&
-3 cat >expect <<-\EOF ?!UNCLOSED-HEREDOC?! &&
+3 cat >expect <<-\EOF ?!LINT: unclosed heredoc?! &&
 4 we forget to end the here-doc
 5 command_which_is_gobbled
diff --git a/t/chainlint/unclosed-here-doc.expect b/t/chainlint/unclosed-here-doc.expect
index 5130467..752c608 100644
--- a/t/chainlint/unclosed-here-doc.expect
+++ b/t/chainlint/unclosed-here-doc.expect
@@ -1,5 +1,5 @@
 2 command_which_is_run &&
-3 cat >expect <<\EOF ?!UNCLOSED-HEREDOC?! &&
+3 cat >expect <<\EOF ?!LINT: unclosed heredoc?! &&
 4 	we try to end the here-doc below,
 5 	but the indentation throws us off
 6 	since the operator is not "<<-".
diff --git a/t/chainlint/while-loop.expect b/t/chainlint/while-loop.expect
index 5ffabd5..2ba5582 100644
--- a/t/chainlint/while-loop.expect
+++ b/t/chainlint/while-loop.expect
@@ -1,14 +1,14 @@
 2 (
 3 	while true
 4 	do
-5 		echo foo ?!AMP?!
-6 		cat <<-\EOF ?!LOOP?!
+5 		echo foo ?!LINT: missing '&&'?!
+6 		cat <<-\EOF ?!LINT: missing '|| exit 1'?!
 7 		bar
 8 		EOF
-9 	done ?!AMP?!
+9 	done ?!LINT: missing '&&'?!
 10 
 11 	while true; do
 12 		echo foo &&
-13 		cat bar ?!LOOP?!
+13 		cat bar ?!LINT: missing '|| exit 1'?!
 14 	done
 15 )
diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl
index b2b28c2..6ee7700 100755
--- a/t/check-non-portable-shell.pl
+++ b/t/check-non-portable-shell.pl
@@ -49,8 +49,8 @@
 	/\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)';
 	/\blocal\s+[A-Za-z0-9_]*=\$([A-Za-z0-9_{]|[(][^(])/ and
 		err q(quote "$val" in 'local var=$val');
-	/^\s*([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and
-		err '"FOO=bar shell_func" assignment extends beyond "shell_func"';
+	/\b([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and !/test_env.+=/ and exists($func{$4}) and
+		err '"FOO=bar shell_func" is not portable (use test_env FOO=bar shell_func)';
 	$line = '';
 	# this resets our $. for each file
 	close ARGV if eof;
diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c
index 8a3fd00..6967c8e 100644
--- a/t/helper/test-advise.c
+++ b/t/helper/test-advise.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "test-tool.h"
 #include "advice.h"
 #include "config.h"
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index ed444ca..33247f0 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "test-tool.h"
 #include "config.h"
 #include "setup.h"
@@ -94,7 +96,8 @@ int cmd__config(int argc, const char **argv)
 	struct config_set cs;
 
 	if (argc == 3 && !strcmp(argv[1], "read_early_config")) {
-		read_early_config(early_config_cb, (void *)argv[2]);
+		read_early_config(the_repository, early_config_cb,
+				  (void *)argv[2]);
 		return 0;
 	}
 
diff --git a/t/helper/test-example-tap.c b/t/helper/test-example-tap.c
index d072ad5..229d495 100644
--- a/t/helper/test-example-tap.c
+++ b/t/helper/test-example-tap.c
@@ -70,8 +70,10 @@ static void t_empty(void)
 	; /* empty */
 }
 
-int cmd__example_tap(int argc, const char **argv)
+int cmd__example_tap(int argc UNUSED, const char **argv UNUSED)
 {
+	check(1);
+
 	test_res = TEST(check_res = check_int(1, ==, 1), "passing test");
 	TEST(t_res(1), "passing test and assertion return 1");
 	test_res = TEST(check_res = check_int(1, ==, 2), "failing test");
@@ -92,5 +94,38 @@ int cmd__example_tap(int argc, const char **argv)
 	test_res = TEST(t_empty(), "test with no checks");
 	TEST(check_int(test_res, ==, 0), "test with no checks returns 0");
 
+	if_test ("if_test passing test")
+		check_int(1, ==, 1);
+	if_test ("if_test failing test")
+		check_int(1, ==, 2);
+	if_test ("if_test passing TEST_TODO()")
+		TEST_TODO(check(0));
+	if_test ("if_test failing TEST_TODO()")
+		TEST_TODO(check(1));
+	if_test ("if_test test_skip()") {
+		check(0);
+		test_skip("missing prerequisite");
+		check(1);
+	}
+	if_test ("if_test test_skip() inside TEST_TODO()")
+		TEST_TODO((test_skip("missing prerequisite"), 1));
+	if_test ("if_test TEST_TODO() after failing check") {
+		check(0);
+		TEST_TODO(check(0));
+	}
+	if_test ("if_test failing check after TEST_TODO()") {
+		check(1);
+		TEST_TODO(check(0));
+		check(0);
+	}
+	if_test ("if_test messages from failing string and char comparison") {
+		check_str("\thello\\", "there\"\n");
+		check_str("NULL", NULL);
+		check_char('a', ==, '\n');
+		check_char('\\', ==, '\'');
+	}
+	if_test ("if_test test with no checks")
+		; /* nothing */
+
 	return test_done();
 }
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index 2912899..7782ae5 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -12,11 +12,6 @@ struct test_entry
 	char key[FLEX_ARRAY];
 };
 
-static const char *get_value(const struct test_entry *e)
-{
-	return e->key + strlen(e->key) + 1;
-}
-
 static int test_entry_cmp(const void *cmp_data,
 			  const struct hashmap_entry *eptr,
 			  const struct hashmap_entry *entry_or_key,
@@ -141,30 +136,16 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
 /*
  * Read stdin line by line and print result of commands to stdout:
  *
- * hash key -> strhash(key) memhash(key) strihash(key) memihash(key)
- * put key value -> NULL / old value
- * get key -> NULL / value
- * remove key -> NULL / old value
- * iterate -> key1 value1\nkey2 value2\n...
- * size -> tablesize numentries
- *
  * perfhashmap method rounds -> test hashmap.[ch] performance
  */
-int cmd__hashmap(int argc, const char **argv)
+int cmd__hashmap(int argc UNUSED, const char **argv UNUSED)
 {
 	struct string_list parts = STRING_LIST_INIT_NODUP;
 	struct strbuf line = STRBUF_INIT;
-	int icase;
-	struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase);
-
-	/* init hash map */
-	icase = argc > 1 && !strcmp("ignorecase", argv[1]);
 
 	/* process commands from stdin */
 	while (strbuf_getline(&line, stdin) != EOF) {
 		char *cmd, *p1, *p2;
-		unsigned int hash = 0;
-		struct test_entry *entry;
 
 		/* break line into command and up to two parameters */
 		string_list_setlen(&parts, 0);
@@ -180,84 +161,8 @@ int cmd__hashmap(int argc, const char **argv)
 		cmd = parts.items[0].string;
 		p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
 		p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
-		if (p1)
-			hash = icase ? strihash(p1) : strhash(p1);
 
-		if (!strcmp("add", cmd) && p1 && p2) {
-
-			/* create entry with key = p1, value = p2 */
-			entry = alloc_test_entry(hash, p1, p2);
-
-			/* add to hashmap */
-			hashmap_add(&map, &entry->ent);
-
-		} else if (!strcmp("put", cmd) && p1 && p2) {
-
-			/* create entry with key = p1, value = p2 */
-			entry = alloc_test_entry(hash, p1, p2);
-
-			/* add / replace entry */
-			entry = hashmap_put_entry(&map, entry, ent);
-
-			/* print and free replaced entry, if any */
-			puts(entry ? get_value(entry) : "NULL");
-			free(entry);
-
-		} else if (!strcmp("get", cmd) && p1) {
-			/* lookup entry in hashmap */
-			entry = hashmap_get_entry_from_hash(&map, hash, p1,
-							struct test_entry, ent);
-
-			/* print result */
-			if (!entry)
-				puts("NULL");
-			hashmap_for_each_entry_from(&map, entry, ent)
-				puts(get_value(entry));
-
-		} else if (!strcmp("remove", cmd) && p1) {
-
-			/* setup static key */
-			struct hashmap_entry key;
-			struct hashmap_entry *rm;
-			hashmap_entry_init(&key, hash);
-
-			/* remove entry from hashmap */
-			rm = hashmap_remove(&map, &key, p1);
-			entry = rm ? container_of(rm, struct test_entry, ent)
-					: NULL;
-
-			/* print result and free entry*/
-			puts(entry ? get_value(entry) : "NULL");
-			free(entry);
-
-		} else if (!strcmp("iterate", cmd)) {
-			struct hashmap_iter iter;
-
-			hashmap_for_each_entry(&map, &iter, entry,
-						ent /* member name */)
-				printf("%s %s\n", entry->key, get_value(entry));
-
-		} else if (!strcmp("size", cmd)) {
-
-			/* print table sizes */
-			printf("%u %u\n", map.tablesize,
-			       hashmap_get_size(&map));
-
-		} else if (!strcmp("intern", cmd) && p1) {
-
-			/* test that strintern works */
-			const char *i1 = strintern(p1);
-			const char *i2 = strintern(p1);
-			if (strcmp(i1, p1))
-				printf("strintern(%s) returns %s\n", p1, i1);
-			else if (i1 == p1)
-				printf("strintern(%s) returns input pointer\n", p1);
-			else if (i1 != i2)
-				printf("strintern(%s) != strintern(%s)", i1, i2);
-			else
-				printf("%s\n", i1);
-
-		} else if (!strcmp("perfhashmap", cmd) && p1 && p2) {
+		if (!strcmp("perfhashmap", cmd) && p1 && p2) {
 
 			perf_hashmap(atoi(p1), atoi(p2));
 
@@ -270,6 +175,5 @@ int cmd__hashmap(int argc, const char **argv)
 
 	string_list_clear(&parts, 0);
 	strbuf_release(&line);
-	hashmap_clear_and_free(&map, struct test_entry, ent);
 	return 0;
 }
diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c
index 42ccc87..328bfe2 100644
--- a/t/helper/test-mergesort.c
+++ b/t/helper/test-mergesort.c
@@ -122,7 +122,7 @@ static const struct dist *get_dist_by_name(const char *name)
 	return NULL;
 }
 
-static void mode_copy(int *arr, int n)
+static void mode_copy(int *arr UNUSED, int n UNUSED)
 {
 	/* nothing */
 }
diff --git a/t/helper/test-oid-array.c b/t/helper/test-oid-array.c
deleted file mode 100644
index 076b849..0000000
--- a/t/helper/test-oid-array.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
-#include "test-tool.h"
-#include "hex.h"
-#include "oid-array.h"
-#include "setup.h"
-#include "strbuf.h"
-
-static int print_oid(const struct object_id *oid, void *data UNUSED)
-{
-	puts(oid_to_hex(oid));
-	return 0;
-}
-
-int cmd__oid_array(int argc UNUSED, const char **argv UNUSED)
-{
-	struct oid_array array = OID_ARRAY_INIT;
-	struct strbuf line = STRBUF_INIT;
-	int nongit_ok;
-
-	setup_git_directory_gently(&nongit_ok);
-	if (nongit_ok)
-		repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
-
-	while (strbuf_getline(&line, stdin) != EOF) {
-		const char *arg;
-		struct object_id oid;
-
-		if (skip_prefix(line.buf, "append ", &arg)) {
-			if (get_oid_hex(arg, &oid))
-				die("not a hexadecimal oid: %s", arg);
-			oid_array_append(&array, &oid);
-		} else if (skip_prefix(line.buf, "lookup ", &arg)) {
-			if (get_oid_hex(arg, &oid))
-				die("not a hexadecimal oid: %s", arg);
-			printf("%d\n", oid_array_lookup(&array, &oid));
-		} else if (!strcmp(line.buf, "clear"))
-			oid_array_clear(&array);
-		else if (!strcmp(line.buf, "for_each_unique"))
-			oid_array_for_each_unique(&array, print_oid, NULL);
-		else
-			die("unknown command: %s", line.buf);
-	}
-
-	strbuf_release(&line);
-	oid_array_clear(&array);
-
-	return 0;
-}
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index bf0e23e..3129aa2 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "test-tool.h"
 #include "abspath.h"
 #include "environment.h"
@@ -38,7 +40,7 @@ static void normalize_argv_string(const char **var, const char *input)
 		*var = input;
 
 	if (*var && (**var == '<' || **var == '('))
-		die("Bad value: %s\n", input);
+		die("Bad value: %s", input);
 }
 
 struct test_data {
@@ -78,12 +80,12 @@ static int test_function(struct test_data *data, char *(*func)(char *input),
 		if (!strcmp(to, data[i].to))
 			continue;
 		if (!data[i].alternative)
-			error("FAIL: %s(%s) => '%s' != '%s'\n",
+			error("FAIL: %s(%s) => '%s' != '%s'",
 				funcname, data[i].from, to, data[i].to);
 		else if (!strcmp(to, data[i].alternative))
 			continue;
 		else
-			error("FAIL: %s(%s) => '%s' != '%s', '%s'\n",
+			error("FAIL: %s(%s) => '%s' != '%s', '%s'",
 				funcname, data[i].from, to, data[i].to,
 				data[i].alternative);
 		failed = 1;
diff --git a/t/helper/test-progress.c b/t/helper/test-progress.c
index 66acb6a..44be264 100644
--- a/t/helper/test-progress.c
+++ b/t/helper/test-progress.c
@@ -62,13 +62,13 @@ int cmd__progress(int argc, const char **argv)
 			else if (*end == ' ')
 				title = string_list_insert(&titles, end + 1)->string;
 			else
-				die("invalid input: '%s'\n", line.buf);
+				die("invalid input: '%s'", line.buf);
 
 			progress = start_progress(title, total);
 		} else if (skip_prefix(line.buf, "progress ", (const char **) &end)) {
 			uint64_t item_count = strtoull(end, &end, 10);
 			if (*end != '\0')
-				die("invalid input: '%s'\n", line.buf);
+				die("invalid input: '%s'", line.buf);
 			display_progress(progress, item_count);
 		} else if (skip_prefix(line.buf, "throughput ",
 				       (const char **) &end)) {
@@ -76,10 +76,10 @@ int cmd__progress(int argc, const char **argv)
 
 			byte_count = strtoull(end, &end, 10);
 			if (*end != ' ')
-				die("invalid input: '%s'\n", line.buf);
+				die("invalid input: '%s'", line.buf);
 			test_ms = strtoull(end + 1, &end, 10);
 			if (*end != '\0')
-				die("invalid input: '%s'\n", line.buf);
+				die("invalid input: '%s'", line.buf);
 			progress_test_ns = test_ms * 1000 * 1000;
 			display_throughput(progress, byte_count);
 		} else if (!strcmp(line.buf, "update")) {
@@ -87,7 +87,7 @@ int cmd__progress(int argc, const char **argv)
 		} else if (!strcmp(line.buf, "stop")) {
 			stop_progress(&progress);
 		} else {
-			die("invalid input: '%s'\n", line.buf);
+			die("invalid input: '%s'", line.buf);
 		}
 	}
 	strbuf_release(&line);
diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c
index 5dd3743..995e382 100644
--- a/t/helper/test-reach.c
+++ b/t/helper/test-reach.c
@@ -67,13 +67,13 @@ int cmd__reach(int ac, const char **av)
 		peeled = deref_tag_noverify(the_repository, orig);
 
 		if (!peeled)
-			die("failed to load commit for input %s resulting in oid %s\n",
+			die("failed to load commit for input %s resulting in oid %s",
 			    buf.buf, oid_to_hex(&oid));
 
 		c = object_as_type(peeled, OBJ_COMMIT, 0);
 
 		if (!c)
-			die("failed to load commit for input %s resulting in oid %s\n",
+			die("failed to load commit for input %s resulting in oid %s",
 			    buf.buf, oid_to_hex(&oid));
 
 		switch (buf.buf[0]) {
@@ -116,6 +116,8 @@ int cmd__reach(int ac, const char **av)
 		       repo_in_merge_bases_many(the_repository, A, X_nr, X_array, 0));
 	else if (!strcmp(av[1], "is_descendant_of"))
 		printf("%s(A,X):%d\n", av[1], repo_is_descendant_of(r, A, X));
+	else if (!strcmp(av[1], "get_branch_base_for_tip"))
+		printf("%s(A,X):%d\n", av[1], get_branch_base_for_tip(r, A, X_array, X_nr));
 	else if (!strcmp(av[1], "get_merge_bases_many")) {
 		struct commit_list *list = NULL;
 		if (repo_get_merge_bases_many(the_repository,
diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c
index 83effc2..438fb9f 100644
--- a/t/helper/test-read-midx.c
+++ b/t/helper/test-read-midx.c
@@ -9,8 +9,10 @@
 #include "packfile.h"
 #include "setup.h"
 #include "gettext.h"
+#include "pack-revindex.h"
 
-static int read_midx_file(const char *object_dir, int show_objects)
+static int read_midx_file(const char *object_dir, const char *checksum,
+			  int show_objects)
 {
 	uint32_t i;
 	struct multi_pack_index *m;
@@ -21,6 +23,13 @@ static int read_midx_file(const char *object_dir, int show_objects)
 	if (!m)
 		return 1;
 
+	if (checksum) {
+		while (m && strcmp(hash_to_hex(get_midx_checksum(m)), checksum))
+			m = m->base_midx;
+		if (!m)
+			return 1;
+	}
+
 	printf("header: %08x %d %d %d %d\n",
 	       m->signature,
 	       m->version,
@@ -54,7 +63,8 @@ static int read_midx_file(const char *object_dir, int show_objects)
 		struct pack_entry e;
 
 		for (i = 0; i < m->num_objects; i++) {
-			nth_midxed_object_oid(&oid, m, i);
+			nth_midxed_object_oid(&oid, m,
+					      i + m->num_objects_in_base);
 			fill_midx_entry(the_repository, &oid, &e, m);
 
 			printf("%s %"PRIu64"\t%s\n",
@@ -76,6 +86,8 @@ static int read_midx_checksum(const char *object_dir)
 	if (!m)
 		return 1;
 	printf("%s\n", hash_to_hex(get_midx_checksum(m)));
+
+	close_midx(m);
 	return 0;
 }
 
@@ -92,10 +104,12 @@ static int read_midx_preferred_pack(const char *object_dir)
 
 	if (midx_preferred_pack(midx, &preferred_pack) < 0) {
 		warning(_("could not determine MIDX preferred pack"));
+		close_midx(midx);
 		return 1;
 	}
 
 	printf("%s\n", midx->pack_names[preferred_pack]);
+	close_midx(midx);
 	return 0;
 }
 
@@ -111,9 +125,11 @@ static int read_midx_bitmapped_packs(const char *object_dir)
 	if (!midx)
 		return 1;
 
-	for (i = 0; i < midx->num_packs; i++) {
-		if (nth_bitmapped_pack(the_repository, midx, &pack, i) < 0)
+	for (i = 0; i < midx->num_packs + midx->num_packs_in_base; i++) {
+		if (nth_bitmapped_pack(the_repository, midx, &pack, i) < 0) {
+			close_midx(midx);
 			return 1;
+		}
 
 		printf("%s\n", pack_basename(pack.p));
 		printf("  bitmap_pos: %"PRIuMAX"\n", (uintmax_t)pack.bitmap_pos);
@@ -127,16 +143,16 @@ static int read_midx_bitmapped_packs(const char *object_dir)
 
 int cmd__read_midx(int argc, const char **argv)
 {
-	if (!(argc == 2 || argc == 3))
-		usage("read-midx [--show-objects|--checksum|--preferred-pack|--bitmap] <object-dir>");
+	if (!(argc == 2 || argc == 3 || argc == 4))
+		usage("read-midx [--show-objects|--checksum|--preferred-pack|--bitmap] <object-dir> <checksum>");
 
 	if (!strcmp(argv[1], "--show-objects"))
-		return read_midx_file(argv[2], 1);
+		return read_midx_file(argv[2], argv[3], 1);
 	else if (!strcmp(argv[1], "--checksum"))
 		return read_midx_checksum(argv[2]);
 	else if (!strcmp(argv[1], "--preferred-pack"))
 		return read_midx_preferred_pack(argv[2]);
 	else if (!strcmp(argv[1], "--bitmap"))
 		return read_midx_bitmapped_packs(argv[2]);
-	return read_midx_file(argv[1], 0);
+	return read_midx_file(argv[1], argv[2], 0);
 }
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 637b8b2..65346de 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -156,7 +156,7 @@ static int cmd_rename_ref(struct ref_store *refs, const char **argv)
 	return refs_rename_ref(refs, oldref, newref, logmsg);
 }
 
-static int each_ref(const char *refname, const struct object_id *oid,
+static int each_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 		    int flags, void *cb_data UNUSED)
 {
 	printf("%s %s 0x%x\n", oid_to_hex(oid), refname, flags);
diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c
index aa6538a..29d4e9a 100644
--- a/t/helper/test-reftable.c
+++ b/t/helper/test-reftable.c
@@ -1,20 +1,194 @@
+#include "git-compat-util.h"
+#include "hash.h"
+#include "hex.h"
 #include "reftable/system.h"
-#include "reftable/reftable-tests.h"
+#include "reftable/reftable-error.h"
+#include "reftable/reftable-merged.h"
+#include "reftable/reftable-reader.h"
+#include "reftable/reftable-stack.h"
 #include "test-tool.h"
 
-int cmd__reftable(int argc, const char **argv)
+static void print_help(void)
 {
-	/* test from simple to complex. */
-	block_test_main(argc, argv);
-	tree_test_main(argc, argv);
-	pq_test_main(argc, argv);
-	readwrite_test_main(argc, argv);
-	merged_test_main(argc, argv);
-	stack_test_main(argc, argv);
+	printf("usage: dump [-st] arg\n\n"
+	       "options: \n"
+	       "  -b dump blocks\n"
+	       "  -t dump table\n"
+	       "  -s dump stack\n"
+	       "  -6 sha256 hash format\n"
+	       "  -h this help\n"
+	       "\n");
+}
+
+static int dump_table(struct reftable_merged_table *mt)
+{
+	struct reftable_iterator it = { NULL };
+	struct reftable_ref_record ref = { NULL };
+	struct reftable_log_record log = { NULL };
+	const struct git_hash_algo *algop;
+	int err;
+
+	reftable_merged_table_init_ref_iterator(mt, &it);
+	err = reftable_iterator_seek_ref(&it, "");
+	if (err < 0)
+		return err;
+
+	algop = &hash_algos[hash_algo_by_id(reftable_merged_table_hash_id(mt))];
+
+	while (1) {
+		err = reftable_iterator_next_ref(&it, &ref);
+		if (err > 0)
+			break;
+		if (err < 0)
+			return err;
+
+		printf("ref{%s(%" PRIu64 ") ", ref.refname, ref.update_index);
+		switch (ref.value_type) {
+		case REFTABLE_REF_SYMREF:
+			printf("=> %s", ref.value.symref);
+			break;
+		case REFTABLE_REF_VAL2:
+			printf("val 2 %s", hash_to_hex_algop(ref.value.val2.value, algop));
+			printf("(T %s)", hash_to_hex_algop(ref.value.val2.target_value, algop));
+			break;
+		case REFTABLE_REF_VAL1:
+			printf("val 1 %s", hash_to_hex_algop(ref.value.val1, algop));
+			break;
+		case REFTABLE_REF_DELETION:
+			printf("delete");
+			break;
+		}
+		printf("}\n");
+	}
+	reftable_iterator_destroy(&it);
+	reftable_ref_record_release(&ref);
+
+	reftable_merged_table_init_log_iterator(mt, &it);
+	err = reftable_iterator_seek_log(&it, "");
+	if (err < 0)
+		return err;
+
+	while (1) {
+		err = reftable_iterator_next_log(&it, &log);
+		if (err > 0)
+			break;
+		if (err < 0)
+			return err;
+
+		switch (log.value_type) {
+		case REFTABLE_LOG_DELETION:
+			printf("log{%s(%" PRIu64 ") delete\n", log.refname,
+			       log.update_index);
+			break;
+		case REFTABLE_LOG_UPDATE:
+			printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n",
+			       log.refname, log.update_index,
+			       log.value.update.name ? log.value.update.name : "",
+			       log.value.update.email ? log.value.update.email : "",
+			       log.value.update.time,
+			       log.value.update.tz_offset);
+			printf("%s => ", hash_to_hex_algop(log.value.update.old_hash, algop));
+			printf("%s\n\n%s\n}\n", hash_to_hex_algop(log.value.update.new_hash, algop),
+			       log.value.update.message ? log.value.update.message : "");
+			break;
+		}
+	}
+	reftable_iterator_destroy(&it);
+	reftable_log_record_release(&log);
 	return 0;
 }
 
+static int dump_stack(const char *stackdir, uint32_t hash_id)
+{
+	struct reftable_stack *stack = NULL;
+	struct reftable_write_options opts = { .hash_id = hash_id };
+	struct reftable_merged_table *merged = NULL;
+
+	int err = reftable_new_stack(&stack, stackdir, &opts);
+	if (err < 0)
+		goto done;
+
+	merged = reftable_stack_merged_table(stack);
+	err = dump_table(merged);
+done:
+	if (stack)
+		reftable_stack_destroy(stack);
+	return err;
+}
+
+static int dump_reftable(const char *tablename)
+{
+	struct reftable_block_source src = { 0 };
+	struct reftable_merged_table *mt = NULL;
+	struct reftable_reader *r = NULL;
+	int err;
+
+	err = reftable_block_source_from_file(&src, tablename);
+	if (err < 0)
+		goto done;
+
+	err = reftable_reader_new(&r, &src, tablename);
+	if (err < 0)
+		goto done;
+
+	err = reftable_merged_table_new(&mt, &r, 1,
+					reftable_reader_hash_id(r));
+	if (err < 0)
+		goto done;
+
+	err = dump_table(mt);
+
+done:
+	reftable_merged_table_free(mt);
+	reftable_reader_decref(r);
+	return err;
+}
+
 int cmd__dump_reftable(int argc, const char **argv)
 {
-	return reftable_dump_main(argc, (char *const *)argv);
+	int err = 0;
+	int opt_dump_blocks = 0;
+	int opt_dump_table = 0;
+	int opt_dump_stack = 0;
+	uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID;
+	const char *arg = NULL, *argv0 = argv[0];
+
+	for (; argc > 1; argv++, argc--)
+		if (*argv[1] != '-')
+			break;
+		else if (!strcmp("-b", argv[1]))
+			opt_dump_blocks = 1;
+		else if (!strcmp("-t", argv[1]))
+			opt_dump_table = 1;
+		else if (!strcmp("-6", argv[1]))
+			opt_hash_id = GIT_SHA256_FORMAT_ID;
+		else if (!strcmp("-s", argv[1]))
+			opt_dump_stack = 1;
+		else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) {
+			print_help();
+			return 2;
+		}
+
+	if (argc != 2) {
+		fprintf(stderr, "need argument\n");
+		print_help();
+		return 2;
+	}
+
+	arg = argv[1];
+
+	if (opt_dump_blocks) {
+		err = reftable_reader_print_blocks(arg);
+	} else if (opt_dump_table) {
+		err = dump_reftable(arg);
+	} else if (opt_dump_stack) {
+		err = dump_stack(arg, opt_hash_id);
+	}
+
+	if (err < 0) {
+		fprintf(stderr, "%s: %s: %s\n", argv0, arg,
+			reftable_error_str(err));
+		return 1;
+	}
+	return 0;
 }
diff --git a/t/helper/test-repository.c b/t/helper/test-repository.c
index c6a074d..63c37de 100644
--- a/t/helper/test-repository.c
+++ b/t/helper/test-repository.c
@@ -19,7 +19,7 @@ static void test_parse_commit_in_graph(const char *gitdir, const char *worktree,
 
 	setup_git_env(gitdir);
 
-	memset(the_repository, 0, sizeof(*the_repository));
+	repo_clear(the_repository);
 
 	if (repo_init(&r, gitdir, worktree))
 		die("Couldn't init repo");
@@ -49,7 +49,7 @@ static void test_get_commit_tree_in_graph(const char *gitdir,
 
 	setup_git_env(gitdir);
 
-	memset(the_repository, 0, sizeof(*the_repository));
+	repo_clear(the_repository);
 
 	if (repo_init(&r, gitdir, worktree))
 		die("Couldn't init repo");
diff --git a/t/helper/test-rot13-filter.c b/t/helper/test-rot13-filter.c
index 7e1d9e0..ff407b5 100644
--- a/t/helper/test-rot13-filter.c
+++ b/t/helper/test-rot13-filter.c
@@ -9,7 +9,7 @@
  * ("clean", "smudge", etc).
  *
  * When --always-delay is given all pathnames with the "can-delay" flag
- * that don't appear on the list bellow are delayed with a count of 1
+ * that don't appear on the list below are delayed with a count of 1
  * (see more below).
  *
  * This implementation supports special test cases:
diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c
index 6ca069c..6dce957 100644
--- a/t/helper/test-submodule-nested-repo-config.c
+++ b/t/helper/test-submodule-nested-repo-config.c
@@ -29,6 +29,6 @@ int cmd__submodule_nested_repo_config(int argc, const char **argv)
 	print_config_from_gitmodules(&subrepo, argv[2]);
 
 	submodule_free(the_repository);
-
+	repo_clear(&subrepo);
 	return 0;
 }
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index da3e691..1ebb69a 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -26,6 +26,7 @@ static struct test_cmd cmds[] = {
 	{ "drop-caches", cmd__drop_caches },
 	{ "dump-cache-tree", cmd__dump_cache_tree },
 	{ "dump-fsmonitor", cmd__dump_fsmonitor },
+	{ "dump-reftable", cmd__dump_reftable },
 	{ "dump-split-index", cmd__dump_split_index },
 	{ "dump-untracked-cache", cmd__dump_untracked_cache },
 	{ "env-helper", cmd__env_helper },
@@ -43,7 +44,6 @@ static struct test_cmd cmds[] = {
 	{ "match-trees", cmd__match_trees },
 	{ "mergesort", cmd__mergesort },
 	{ "mktemp", cmd__mktemp },
-	{ "oid-array", cmd__oid_array },
 	{ "online-cpus", cmd__online_cpus },
 	{ "pack-mtimes", cmd__pack_mtimes },
 	{ "parse-options", cmd__parse_options },
@@ -61,9 +61,7 @@ static struct test_cmd cmds[] = {
 	{ "read-graph", cmd__read_graph },
 	{ "read-midx", cmd__read_midx },
 	{ "ref-store", cmd__ref_store },
-	{ "reftable", cmd__reftable },
 	{ "rot13-filter", cmd__rot13_filter },
-	{ "dump-reftable", cmd__dump_reftable },
 	{ "regex", cmd__regex },
 	{ "repository", cmd__repository },
 	{ "revision-walking", cmd__revision_walking },
@@ -83,7 +81,6 @@ static struct test_cmd cmds[] = {
 	{ "trace2", cmd__trace2 },
 	{ "truncate", cmd__truncate },
 	{ "userdiff", cmd__userdiff },
-	{ "urlmatch-normalization", cmd__urlmatch_normalization },
 	{ "xml-encode", cmd__xml_encode },
 	{ "wildmatch", cmd__wildmatch },
 #ifdef GIT_WINDOWS_NATIVE
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 642a345..21802ac 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -55,7 +55,6 @@ int cmd__read_graph(int argc, const char **argv);
 int cmd__read_midx(int argc, const char **argv);
 int cmd__ref_store(int argc, const char **argv);
 int cmd__rot13_filter(int argc, const char **argv);
-int cmd__reftable(int argc, const char **argv);
 int cmd__regex(int argc, const char **argv);
 int cmd__repository(int argc, const char **argv);
 int cmd__revision_walking(int argc, const char **argv);
@@ -64,7 +63,6 @@ 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__oid_array(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);
@@ -76,7 +74,6 @@ int cmd__subprocess(int argc, const char **argv);
 int cmd__trace2(int argc, const char **argv);
 int cmd__truncate(int argc, const char **argv);
 int cmd__userdiff(int argc, const char **argv);
-int cmd__urlmatch_normalization(int argc, const char **argv);
 int cmd__xml_encode(int argc, const char **argv);
 int cmd__wildmatch(int argc, const char **argv);
 #ifdef GIT_WINDOWS_NATIVE
diff --git a/t/helper/test-urlmatch-normalization.c b/t/helper/test-urlmatch-normalization.c
deleted file mode 100644
index 86edd45..0000000
--- a/t/helper/test-urlmatch-normalization.c
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "test-tool.h"
-#include "git-compat-util.h"
-#include "urlmatch.h"
-
-int cmd__urlmatch_normalization(int argc, const char **argv)
-{
-	const char usage[] = "test-tool urlmatch-normalization [-p | -l] <url1> | <url1> <url2>";
-	char *url1 = NULL, *url2 = NULL;
-	int opt_p = 0, opt_l = 0;
-	int ret = 0;
-
-	/*
-	 * For one url, succeed if url_normalize succeeds on it, fail otherwise.
-	 * For two urls, succeed only if url_normalize succeeds on both and
-	 * the results compare equal with strcmp.  If -p is given (one url only)
-	 * and url_normalize succeeds, print the result followed by "\n".  If
-	 * -l is given (one url only) and url_normalize succeeds, print the
-	 * returned length in decimal followed by "\n".
-	 */
-
-	if (argc > 1 && !strcmp(argv[1], "-p")) {
-		opt_p = 1;
-		argc--;
-		argv++;
-	} else if (argc > 1 && !strcmp(argv[1], "-l")) {
-		opt_l = 1;
-		argc--;
-		argv++;
-	}
-
-	if (argc < 2 || argc > 3)
-		die("%s", usage);
-
-	if (argc == 2) {
-		struct url_info info;
-		url1 = url_normalize(argv[1], &info);
-		if (!url1)
-			return 1;
-		if (opt_p)
-			printf("%s\n", url1);
-		if (opt_l)
-			printf("%u\n", (unsigned)info.url_len);
-		goto cleanup;
-	}
-
-	if (opt_p || opt_l)
-		die("%s", usage);
-
-	url1 = url_normalize(argv[1], NULL);
-	url2 = url_normalize(argv[2], NULL);
-	ret = (url1 && url2 && !strcmp(url1, url2)) ? 0 : 1;
-cleanup:
-	free(url1);
-	free(url2);
-	return ret;
-}
diff --git a/t/helper/test-userdiff.c b/t/helper/test-userdiff.c
index 0ce31ce..94c48ab 100644
--- a/t/helper/test-userdiff.c
+++ b/t/helper/test-userdiff.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "test-tool.h"
 #include "setup.h"
 #include "userdiff.h"
diff --git a/t/interop/README b/t/interop/README
index 72d42bd..4e0608f 100644
--- a/t/interop/README
+++ b/t/interop/README
@@ -83,3 +83,10 @@
      should create one with the appropriate version of git.
 
 At the end of the script, call test_done as usual.
+
+Some older versions may need a few build knobs tweaked (e.g., ancient
+versions of Git no longer build with modern OpenSSL). Your script can
+set MAKE_OPTS_A and MAKE_OPTS_B, which will be passed alongside
+GIT_INTEROP_MAKE_OPTS. Users can override them per-script by setting
+GIT_INTEROP_MAKE_OPTS_{A,B} in the environment, just like they can set
+GIT_TEST_VERSION_{A,B}.
diff --git a/t/interop/i5500-git-daemon.sh b/t/interop/i5500-git-daemon.sh
index 4d22e42..88712d1 100755
--- a/t/interop/i5500-git-daemon.sh
+++ b/t/interop/i5500-git-daemon.sh
@@ -2,6 +2,7 @@
 
 VERSION_A=.
 VERSION_B=v1.0.0
+MAKE_OPTS_B="NO_OPENSSL=TooOld"
 
 : ${LIB_GIT_DAEMON_PORT:=5500}
 LIB_GIT_DAEMON_COMMAND='git.a daemon'
diff --git a/t/interop/interop-lib.sh b/t/interop/interop-lib.sh
index 62f4481..1b5864d 100644
--- a/t/interop/interop-lib.sh
+++ b/t/interop/interop-lib.sh
@@ -45,7 +45,7 @@
 
 	(
 		cd "$dir" &&
-		make $GIT_INTEROP_MAKE_OPTS >&2 &&
+		make $2 $GIT_INTEROP_MAKE_OPTS >&2 &&
 		touch .built
 	) || return 1
 
@@ -76,9 +76,11 @@
 
 VERSION_A=${GIT_TEST_VERSION_A:-$VERSION_A}
 VERSION_B=${GIT_TEST_VERSION_B:-$VERSION_B}
+MAKE_OPTS_A=${GIT_INTEROP_MAKE_OPTS_A:-$MAKE_OPTS_A}
+MAKE_OPTS_B=${GIT_INTEROP_MAKE_OPTS_B:-$MAKE_OPTS_B}
 
-if ! DIR_A=$(build_version "$VERSION_A") ||
-   ! DIR_B=$(build_version "$VERSION_B")
+if ! DIR_A=$(build_version "$VERSION_A" "$MAKE_OPTS_A") ||
+   ! DIR_B=$(build_version "$VERSION_B" "$MAKE_OPTS_B")
 then
 	echo >&2 "fatal: unable to build git versions"
 	exit 1
diff --git a/t/lib-bitmap.sh b/t/lib-bitmap.sh
index f595937..62aa674 100644
--- a/t/lib-bitmap.sh
+++ b/t/lib-bitmap.sh
@@ -1,6 +1,8 @@
 # Helpers for scripts testing bitmap functionality; see t5310 for
 # example usage.
 
+. "$TEST_DIRECTORY"/lib-midx.sh
+
 objdir=.git/objects
 midx=$objdir/pack/multi-pack-index
 
@@ -264,10 +266,6 @@
 	test_cmp expect actual
 }
 
-midx_checksum () {
-	test-tool read-midx --checksum "$1"
-}
-
 # midx_pack_source <obj>
 midx_pack_source () {
 	test-tool read-midx --show-objects .git/objects | grep "^$1 " | cut -f2
diff --git a/t/lib-bundle.sh b/t/lib-bundle.sh
index cf7ed81..62b7bb1 100644
--- a/t/lib-bundle.sh
+++ b/t/lib-bundle.sh
@@ -11,7 +11,7 @@
 }
 
 # Check count of objects in a bundle file.
-# We can use "--thin" opiton to check thin pack, which must be fixed by
+# We can use "--thin" option to check thin pack, which must be fixed by
 # command `git-index-pack --fix-thin --stdin`.
 test_bundle_object_count () {
 	thin=
diff --git a/t/lib-midx.sh b/t/lib-midx.sh
index 1261994..e38c609 100644
--- a/t/lib-midx.sh
+++ b/t/lib-midx.sh
@@ -6,3 +6,31 @@
 	test_cmp expect actual &&
 	git multi-pack-index --object-dir=$1 verify
 }
+
+midx_checksum () {
+	test-tool read-midx --checksum "$1"
+}
+
+midx_git_two_modes () {
+	git -c core.multiPackIndex=false $1 >expect &&
+	git -c core.multiPackIndex=true $1 >actual &&
+	if [ "$2" = "sorted" ]
+	then
+		sort <expect >expect.sorted &&
+		mv expect.sorted expect &&
+		sort <actual >actual.sorted &&
+		mv actual.sorted actual
+	fi &&
+	test_cmp expect actual
+}
+
+compare_results_with_midx () {
+	MSG=$1
+	test_expect_success "check normal git operations: $MSG" '
+		midx_git_two_modes "rev-list --objects --all" &&
+		midx_git_two_modes "log --raw" &&
+		midx_git_two_modes "count-objects --verbose" &&
+		midx_git_two_modes "cat-file --batch-all-objects --batch-check" &&
+		midx_git_two_modes "cat-file --batch-all-objects --batch-check --unordered" sorted
+	'
+}
diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index 11d2dc9..0dd7643 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -187,7 +187,7 @@
 			exit 1
 		fi
 	fi &&
-	# There should be no uncommited changes
+	# There should be no uncommitted changes
 	git diff --exit-code HEAD &&
 	# The todo-list should be re-read after a reword
 	GIT_SEQUENCE_EDITOR="\"$PWD/reword-sequence-editor.sh\"" \
diff --git a/t/lib-sudo.sh b/t/lib-sudo.sh
index b4d7788..477e0fd 100644
--- a/t/lib-sudo.sh
+++ b/t/lib-sudo.sh
@@ -6,7 +6,7 @@
 	local RUN="$TEST_DIRECTORY/$$.sh"
 	write_script "$RUN" "$TEST_SHELL_PATH"
 	# avoid calling "$RUN" directly so sudo doesn't get a chance to
-	# override the shell, add aditional restrictions or even reject
+	# override the shell, add additional restrictions or even reject
 	# running the script because its security policy deem it unsafe
 	sudo "$TEST_SHELL_PATH" -c "\"$RUN\""
 	ret=$?
diff --git a/t/lib-unicode-nfc-nfd.sh b/t/lib-unicode-nfc-nfd.sh
index 2223224..aed0a4d 100755
--- a/t/lib-unicode-nfc-nfd.sh
+++ b/t/lib-unicode-nfc-nfd.sh
@@ -74,7 +74,7 @@
 # Yielding:   \xcf \x89  +  \xcc \x94  +  \xcd \x82
 #
 # Note that I've used the canonical ordering of the
-# combinining characters.  It is also possible to
+# combining characters.  It is also possible to
 # swap them.  My testing shows that that non-standard
 # ordering also causes a collision in mkdir.  However,
 # the resulting names don't draw correctly on the
diff --git a/t/perf/p1500-graph-walks.sh b/t/perf/p1500-graph-walks.sh
index e14e762..5b23ce5 100755
--- a/t/perf/p1500-graph-walks.sh
+++ b/t/perf/p1500-graph-walks.sh
@@ -20,6 +20,21 @@
 		echo tag-$ref ||
 		return 1
 	done >tags &&
+
+	echo "A:HEAD" >test-tool-refs &&
+	for line in $(cat refs)
+	do
+		echo "X:$line" >>test-tool-refs || return 1
+	done &&
+	echo "A:HEAD" >test-tool-tags &&
+	for line in $(cat tags)
+	do
+		echo "X:$line" >>test-tool-tags || return 1
+	done &&
+
+	commit=$(git commit-tree $(git rev-parse HEAD^{tree})) &&
+	git update-ref refs/heads/disjoint-base $commit &&
+
 	git commit-graph write --reachable
 '
 
@@ -47,4 +62,20 @@
 	xargs git tag --merged=HEAD <tags
 '
 
+test_perf 'is-base check: test-tool reach (refs)' '
+	test-tool reach get_branch_base_for_tip <test-tool-refs
+'
+
+test_perf 'is-base check: test-tool reach (tags)' '
+	test-tool reach get_branch_base_for_tip <test-tool-tags
+'
+
+test_perf 'is-base check: git for-each-ref' '
+	git for-each-ref --format="%(is-base:HEAD)" --stdin <refs
+'
+
+test_perf 'is-base check: git for-each-ref (disjoint-base)' '
+	git for-each-ref --format="%(is-base:refs/heads/disjoint-base)" --stdin <refs
+'
+
 test_done
diff --git a/t/perf/p7527-builtin-fsmonitor.sh b/t/perf/p7527-builtin-fsmonitor.sh
index c3f9a4c..9016432 100755
--- a/t/perf/p7527-builtin-fsmonitor.sh
+++ b/t/perf/p7527-builtin-fsmonitor.sh
@@ -95,7 +95,7 @@
 # time is not useful.
 #
 # Create a temp branch and do all work relative to it so that we don't
-# accidentially alter the real ballast branch.
+# accidentally alter the real ballast branch.
 #
 test_expect_success "Setup borrowed repo (temp ballast branch)" "
 	test_might_fail git -C $REPO checkout $BALLAST_BR &&
diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh
index ab0c763..8ab6d9c 100644
--- a/t/perf/perf-lib.sh
+++ b/t/perf/perf-lib.sh
@@ -282,7 +282,7 @@
 #	Run the performance test script specified in perf-test with
 #	optional prerequisite and setup steps.
 # Options:
-#	--prereq prerequisites: Skip the test if prequisites aren't met
+#	--prereq prerequisites: Skip the test if prerequisites aren't met
 #	--setup "setup-steps": Run setup steps prior to each measured iteration
 #
 test_perf () {
@@ -309,7 +309,7 @@
 #	prerequisites and setup steps. Returns the numeric value
 #	returned by size-test.
 # Options:
-#	--prereq prerequisites: Skip the test if prequisites aren't met
+#	--prereq prerequisites: Skip the test if prerequisites aren't met
 #	--setup "setup-steps": Run setup steps prior to the size measurement
 
 test_size () {
diff --git a/t/run-test.sh b/t/run-test.sh
index 13c353b..63328ac 100755
--- a/t/run-test.sh
+++ b/t/run-test.sh
@@ -10,7 +10,7 @@
 		echo >&2 "ERROR: TEST_SHELL_PATH is empty or not set"
 		exit 1
 	fi
-	exec "${TEST_SHELL_PATH}" "$@"
+	exec "${TEST_SHELL_PATH}" "$@" ${TEST_OPTIONS}
 	;;
 *)
 	exec "$@"
diff --git a/t/socks4-proxy.pl b/t/socks4-proxy.pl
new file mode 100644
index 0000000..4c3a35c
--- /dev/null
+++ b/t/socks4-proxy.pl
@@ -0,0 +1,48 @@
+use strict;
+use IO::Select;
+use IO::Socket::UNIX;
+use IO::Socket::INET;
+
+my $path = shift;
+
+unlink($path);
+my $server = IO::Socket::UNIX->new(Listen => 1, Local => $path)
+	or die "unable to listen on $path: $!";
+
+$| = 1;
+print "ready\n";
+
+while (my $client = $server->accept()) {
+	sysread $client, my $buf, 8;
+	my ($version, $cmd, $port, $ip) = unpack 'CCnN', $buf;
+	next unless $version == 4; # socks4
+	next unless $cmd == 1; # TCP stream connection
+
+	# skip NUL-terminated id
+	while (sysread $client, my $char, 1) {
+		last unless ord($char);
+	}
+
+	# version(0), reply(5a == granted), port (ignored), ip (ignored)
+	syswrite $client, "\x00\x5a\x00\x00\x00\x00\x00\x00";
+
+	my $remote = IO::Socket::INET->new(PeerHost => $ip, PeerPort => $port)
+		or die "unable to connect to $ip/$port: $!";
+
+	my $io = IO::Select->new($client, $remote);
+	while ($io->count) {
+		for my $fh ($io->can_read(0)) {
+			for my $pair ([$client, $remote], [$remote, $client]) {
+				my ($from, $to) = @$pair;
+				next unless $fh == $from;
+
+				my $r = sysread $from, my $buf, 1024;
+				if (!defined $r || $r <= 0) {
+					$io->remove($from);
+					next;
+				}
+				syswrite $to, $buf;
+			}
+		}
+	}
+}
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 49e9bf7..0178aa6 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -500,6 +500,7 @@
 '
 
 test_expect_success 'init honors GIT_DEFAULT_HASH' '
+	test_when_finished "rm -rf sha1 sha256" &&
 	GIT_DEFAULT_HASH=sha1 git init sha1 &&
 	git -C sha1 rev-parse --show-object-format >actual &&
 	echo sha1 >expected &&
@@ -511,6 +512,7 @@
 '
 
 test_expect_success 'init honors --object-format' '
+	test_when_finished "rm -rf explicit-sha1 explicit-sha256" &&
 	git init --object-format=sha1 explicit-sha1 &&
 	git -C explicit-sha1 rev-parse --show-object-format >actual &&
 	echo sha1 >expected &&
@@ -521,7 +523,58 @@
 	test_cmp expected actual
 '
 
+test_expect_success 'init honors init.defaultObjectFormat' '
+	test_when_finished "rm -rf sha1 sha256" &&
+
+	test_config_global init.defaultObjectFormat sha1 &&
+	(
+		sane_unset GIT_DEFAULT_HASH &&
+		git init sha1 &&
+		git -C sha1 rev-parse --show-object-format >actual &&
+		echo sha1 >expected &&
+		test_cmp expected actual
+	) &&
+
+	test_config_global init.defaultObjectFormat sha256 &&
+	(
+		sane_unset GIT_DEFAULT_HASH &&
+		git init sha256 &&
+		git -C sha256 rev-parse --show-object-format >actual &&
+		echo sha256 >expected &&
+		test_cmp expected actual
+	)
+'
+
+test_expect_success 'init warns about invalid init.defaultObjectFormat' '
+	test_when_finished "rm -rf repo" &&
+	test_config_global init.defaultObjectFormat garbage &&
+
+	echo "warning: unknown hash algorithm ${SQ}garbage${SQ}" >expect &&
+	git init repo 2>err &&
+	test_cmp expect err &&
+
+	git -C repo rev-parse --show-object-format >actual &&
+	echo $GIT_DEFAULT_HASH >expected &&
+	test_cmp expected actual
+'
+
+test_expect_success '--object-format overrides GIT_DEFAULT_HASH' '
+	test_when_finished "rm -rf repo" &&
+	GIT_DEFAULT_HASH=sha1 git init --object-format=sha256 repo &&
+	git -C repo rev-parse --show-object-format >actual &&
+	echo sha256 >expected
+'
+
+test_expect_success 'GIT_DEFAULT_HASH overrides init.defaultObjectFormat' '
+	test_when_finished "rm -rf repo" &&
+	test_config_global init.defaultObjectFormat sha1 &&
+	GIT_DEFAULT_HASH=sha256 git init repo &&
+	git -C repo rev-parse --show-object-format >actual &&
+	echo sha256 >expected
+'
+
 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 &&
 	git -C explicit-v0 config core.repositoryformatversion 0 &&
 	test_must_fail git -C explicit-v0 rev-parse --show-object-format
@@ -558,15 +611,6 @@
 	grep "invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}" err
 '
 
-test_expect_success DEFAULT_REPO_FORMAT 'init with GIT_DEFAULT_REF_FORMAT=files' '
-	test_when_finished "rm -rf refformat" &&
-	GIT_DEFAULT_REF_FORMAT=files git init refformat &&
-	echo 0 >expect &&
-	git -C refformat config core.repositoryformatversion >actual &&
-	test_cmp expect actual &&
-	test_must_fail git -C refformat config extensions.refstorage
-'
-
 test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '
 	test_when_finished "rm -rf refformat" &&
 	cat >expect <<-EOF &&
@@ -576,15 +620,90 @@
 	test_cmp expect err
 '
 
-test_expect_success 'init with --ref-format=files' '
+test_expect_success 'init warns about invalid init.defaultRefFormat' '
+	test_when_finished "rm -rf repo" &&
+	test_config_global init.defaultRefFormat garbage &&
+
+	echo "warning: unknown ref storage format ${SQ}garbage${SQ}" >expect &&
+	git init repo 2>err &&
+	test_cmp expect err &&
+
+	git -C repo rev-parse --show-ref-format >actual &&
+	echo $GIT_DEFAULT_REF_FORMAT >expected &&
+	test_cmp expected actual
+'
+
+backends="files reftable"
+for format in $backends
+do
+	test_expect_success DEFAULT_REPO_FORMAT "init with GIT_DEFAULT_REF_FORMAT=$format" '
+		test_when_finished "rm -rf refformat" &&
+		GIT_DEFAULT_REF_FORMAT=$format git init refformat &&
+
+		if test $format = files
+		then
+			test_must_fail git -C refformat config extensions.refstorage &&
+			echo 0 >expect
+		else
+			git -C refformat config extensions.refstorage &&
+			echo 1 >expect
+		fi &&
+		git -C refformat config core.repositoryformatversion >actual &&
+		test_cmp expect actual &&
+
+		echo $format >expect &&
+		git -C refformat rev-parse --show-ref-format >actual &&
+		test_cmp expect actual
+	'
+
+	test_expect_success "init with --ref-format=$format" '
+		test_when_finished "rm -rf refformat" &&
+		git init --ref-format=$format refformat &&
+		echo $format >expect &&
+		git -C refformat rev-parse --show-ref-format >actual &&
+		test_cmp expect actual
+	'
+
+	test_expect_success "init with init.defaultRefFormat=$format" '
+		test_when_finished "rm -rf refformat" &&
+		test_config_global init.defaultRefFormat $format &&
+		(
+			sane_unset GIT_DEFAULT_REF_FORMAT &&
+			git init refformat
+		) &&
+
+		echo $format >expect &&
+		git -C refformat rev-parse --show-ref-format >actual &&
+		test_cmp expect actual
+	'
+
+	test_expect_success "--ref-format=$format overrides GIT_DEFAULT_REF_FORMAT" '
+		test_when_finished "rm -rf refformat" &&
+		GIT_DEFAULT_REF_FORMAT=garbage git init --ref-format=$format refformat &&
+		echo $format >expect &&
+		git -C refformat rev-parse --show-ref-format >actual &&
+		test_cmp expect actual
+	'
+done
+
+test_expect_success "--ref-format= overrides GIT_DEFAULT_REF_FORMAT" '
 	test_when_finished "rm -rf refformat" &&
-	git init --ref-format=files refformat &&
-	echo files >expect &&
+	GIT_DEFAULT_REF_FORMAT=files git init --ref-format=reftable refformat &&
+	echo reftable >expect &&
 	git -C refformat rev-parse --show-ref-format >actual &&
 	test_cmp expect actual
 '
 
-backends="files reftable"
+test_expect_success "GIT_DEFAULT_REF_FORMAT= overrides init.defaultRefFormat" '
+	test_when_finished "rm -rf refformat" &&
+	test_config_global init.defaultRefFormat files &&
+
+	GIT_DEFAULT_REF_FORMAT=reftable git init refformat &&
+	echo reftable >expect &&
+	git -C refformat rev-parse --show-ref-format >actual &&
+	test_cmp expect actual
+'
+
 for from_format in $backends
 do
 	test_expect_success "re-init with same format ($from_format)" '
diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh
deleted file mode 100755
index 46e74ad..0000000
--- a/t/t0011-hashmap.sh
+++ /dev/null
@@ -1,260 +0,0 @@
-#!/bin/sh
-
-test_description='test hashmap and string hash functions'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-test_hashmap() {
-	echo "$1" | test-tool hashmap $3 > actual &&
-	echo "$2" > expect &&
-	test_cmp expect actual
-}
-
-test_expect_success 'put' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-put foobarfrotz value4
-size" "NULL
-NULL
-NULL
-NULL
-64 4"
-
-'
-
-test_expect_success 'put (case insensitive)' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-size" "NULL
-NULL
-NULL
-64 3" ignorecase
-
-'
-
-test_expect_success 'replace' '
-
-test_hashmap "put key1 value1
-put key1 value2
-put fooBarFrotz value3
-put fooBarFrotz value4
-size" "NULL
-value1
-NULL
-value3
-64 2"
-
-'
-
-test_expect_success 'replace (case insensitive)' '
-
-test_hashmap "put key1 value1
-put Key1 value2
-put fooBarFrotz value3
-put foobarfrotz value4
-size" "NULL
-value1
-NULL
-value3
-64 2" ignorecase
-
-'
-
-test_expect_success 'get' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-put foobarfrotz value4
-get key1
-get key2
-get fooBarFrotz
-get notInMap" "NULL
-NULL
-NULL
-NULL
-value1
-value2
-value3
-NULL"
-
-'
-
-test_expect_success 'get (case insensitive)' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-get Key1
-get keY2
-get foobarfrotz
-get notInMap" "NULL
-NULL
-NULL
-value1
-value2
-value3
-NULL" ignorecase
-
-'
-
-test_expect_success 'add' '
-
-test_hashmap "add key1 value1
-add key1 value2
-add fooBarFrotz value3
-add fooBarFrotz value4
-get key1
-get fooBarFrotz
-get notInMap" "value2
-value1
-value4
-value3
-NULL"
-
-'
-
-test_expect_success 'add (case insensitive)' '
-
-test_hashmap "add key1 value1
-add Key1 value2
-add fooBarFrotz value3
-add foobarfrotz value4
-get key1
-get Foobarfrotz
-get notInMap" "value2
-value1
-value4
-value3
-NULL" ignorecase
-
-'
-
-test_expect_success 'remove' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-remove key1
-remove key2
-remove notInMap
-size" "NULL
-NULL
-NULL
-value1
-value2
-NULL
-64 1"
-
-'
-
-test_expect_success 'remove (case insensitive)' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-remove Key1
-remove keY2
-remove notInMap
-size" "NULL
-NULL
-NULL
-value1
-value2
-NULL
-64 1" ignorecase
-
-'
-
-test_expect_success 'iterate' '
-	test-tool hashmap >actual.raw <<-\EOF &&
-	put key1 value1
-	put key2 value2
-	put fooBarFrotz value3
-	iterate
-	EOF
-
-	cat >expect <<-\EOF &&
-	NULL
-	NULL
-	NULL
-	fooBarFrotz value3
-	key1 value1
-	key2 value2
-	EOF
-
-	sort <actual.raw >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'iterate (case insensitive)' '
-	test-tool hashmap ignorecase >actual.raw <<-\EOF &&
-	put key1 value1
-	put key2 value2
-	put fooBarFrotz value3
-	iterate
-	EOF
-
-	cat >expect <<-\EOF &&
-	NULL
-	NULL
-	NULL
-	fooBarFrotz value3
-	key1 value1
-	key2 value2
-	EOF
-
-	sort <actual.raw >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'grow / shrink' '
-
-	rm -f in &&
-	rm -f expect &&
-	for n in $(test_seq 51)
-	do
-		echo put key$n value$n >> in &&
-		echo NULL >> expect || return 1
-	done &&
-	echo size >> in &&
-	echo 64 51 >> expect &&
-	echo put key52 value52 >> in &&
-	echo NULL >> expect &&
-	echo size >> in &&
-	echo 256 52 >> expect &&
-	for n in $(test_seq 12)
-	do
-		echo remove key$n >> in &&
-		echo value$n >> expect || return 1
-	done &&
-	echo size >> in &&
-	echo 256 40 >> expect &&
-	echo remove key40 >> in &&
-	echo value40 >> expect &&
-	echo size >> in &&
-	echo 64 39 >> expect &&
-	test-tool hashmap <in >out &&
-	test_cmp expect out
-
-'
-
-test_expect_success 'string interning' '
-
-test_hashmap "intern value1
-intern Value1
-intern value2
-intern value2
-" "value1
-Value1
-value2
-value2"
-
-'
-
-test_done
diff --git a/t/t0012-help.sh b/t/t0012-help.sh
index 1d273d9..9eae0d8 100755
--- a/t/t0012-help.sh
+++ b/t/t0012-help.sh
@@ -2,6 +2,7 @@
 
 test_description='help'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 configure_help () {
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 0b49970..eeb2714 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
diff --git a/t/t0032-reftable-unittest.sh b/t/t0032-reftable-unittest.sh
deleted file mode 100755
index 471cb37..0000000
--- a/t/t0032-reftable-unittest.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2020 Google LLC
-#
-
-test_description='reftable unittests'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-test_expect_success 'unittests' '
-	TMPDIR=$(pwd) && export TMPDIR &&
-	test-tool reftable
-'
-
-test_done
diff --git a/t/t0064-oid-array.sh b/t/t0064-oid-array.sh
deleted file mode 100755
index de74b69..0000000
--- a/t/t0064-oid-array.sh
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/bin/sh
-
-test_description='basic tests for the oid array implementation'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-echoid () {
-	prefix="${1:+$1 }"
-	shift
-	while test $# -gt 0
-	do
-		echo "$prefix$ZERO_OID" | sed -e "s/00/$1/g"
-		shift
-	done
-}
-
-test_expect_success 'without repository' '
-	cat >expect <<-EOF &&
-	4444444444444444444444444444444444444444
-	5555555555555555555555555555555555555555
-	8888888888888888888888888888888888888888
-	aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-	EOF
-	cat >input <<-EOF &&
-	append 4444444444444444444444444444444444444444
-	append 5555555555555555555555555555555555555555
-	append 8888888888888888888888888888888888888888
-	append aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-	for_each_unique
-	EOF
-	nongit test-tool oid-array <input >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'ordered enumeration' '
-	echoid "" 44 55 88 aa >expect &&
-	{
-		echoid append 88 44 aa 55 &&
-		echo for_each_unique
-	} | test-tool oid-array >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'ordered enumeration with duplicate suppression' '
-	echoid "" 44 55 88 aa >expect &&
-	{
-		echoid append 88 44 aa 55 &&
-		echoid append 88 44 aa 55 &&
-		echoid append 88 44 aa 55 &&
-		echo for_each_unique
-	} | test-tool oid-array >actual &&
-	test_cmp expect actual
-'
-
-test_expect_success 'lookup' '
-	{
-		echoid append 88 44 aa 55 &&
-		echoid lookup 55
-	} | test-tool oid-array >actual &&
-	n=$(cat actual) &&
-	test "$n" -eq 1
-'
-
-test_expect_success 'lookup non-existing entry' '
-	{
-		echoid append 88 44 aa 55 &&
-		echoid lookup 33
-	} | test-tool oid-array >actual &&
-	n=$(cat actual) &&
-	test "$n" -lt 0
-'
-
-test_expect_success 'lookup with duplicates' '
-	{
-		echoid append 88 44 aa 55 &&
-		echoid append 88 44 aa 55 &&
-		echoid append 88 44 aa 55 &&
-		echoid lookup 55
-	} | test-tool oid-array >actual &&
-	n=$(cat actual) &&
-	test "$n" -ge 3 &&
-	test "$n" -le 5
-'
-
-test_expect_success 'lookup non-existing entry with duplicates' '
-	{
-		echoid append 88 44 aa 55 &&
-		echoid append 88 44 aa 55 &&
-		echoid append 88 44 aa 55 &&
-		echoid lookup 66
-	} | test-tool oid-array >actual &&
-	n=$(cat actual) &&
-	test "$n" -lt 0
-'
-
-test_expect_success 'lookup with almost duplicate values' '
-	# n-1 5s
-	root=$(echoid "" 55) &&
-	root=${root%5} &&
-	{
-		id1="${root}5" &&
-		id2="${root}f" &&
-		echo "append $id1" &&
-		echo "append $id2" &&
-		echoid lookup 55
-	} | test-tool oid-array >actual &&
-	n=$(cat actual) &&
-	test "$n" -eq 0
-'
-
-test_expect_success 'lookup with single duplicate value' '
-	{
-		echoid append 55 55 &&
-		echoid lookup 55
-	} | test-tool oid-array >actual &&
-	n=$(cat actual) &&
-	test "$n" -ge 0 &&
-	test "$n" -le 1
-'
-
-test_done
diff --git a/t/t0080-unit-test-output.sh b/t/t0080-unit-test-output.sh
index 7bbb065..3c369c8 100755
--- a/t/t0080-unit-test-output.sh
+++ b/t/t0080-unit-test-output.sh
@@ -5,23 +5,24 @@
 TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
-test_expect_success 'TAP output from unit tests' '
+test_expect_success 'TAP output from unit tests' - <<\EOT
 	cat >expect <<-EOF &&
+	# BUG: check outside of test at t/helper/test-example-tap.c:75
 	ok 1 - passing test
 	ok 2 - passing test and assertion return 1
-	# check "1 == 2" failed at t/helper/test-example-tap.c:77
+	# check "1 == 2" failed at t/helper/test-example-tap.c:79
 	#    left: 1
 	#   right: 2
 	not ok 3 - failing test
 	ok 4 - failing test and assertion return 0
 	not ok 5 - passing TEST_TODO() # TODO
 	ok 6 - passing TEST_TODO() returns 1
-	# todo check ${SQ}check(x)${SQ} succeeded at t/helper/test-example-tap.c:26
+	# todo check 'check(x)' succeeded at t/helper/test-example-tap.c:26
 	not ok 7 - failing TEST_TODO()
 	ok 8 - failing TEST_TODO() returns 0
 	# check "0" failed at t/helper/test-example-tap.c:31
 	# skipping test - missing prerequisite
-	# skipping check ${SQ}1${SQ} at t/helper/test-example-tap.c:33
+	# skipping check '1' at t/helper/test-example-tap.c:33
 	ok 9 - test_skip() # SKIP
 	ok 10 - skipped test returns 1
 	# skipping test - missing prerequisite
@@ -39,21 +40,54 @@
 	# check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:63
 	#    left: "NULL"
 	#   right: NULL
-	# check "${SQ}a${SQ} == ${SQ}\n${SQ}" failed at t/helper/test-example-tap.c:64
-	#    left: ${SQ}a${SQ}
-	#   right: ${SQ}\012${SQ}
-	# check "${SQ}\\\\${SQ} == ${SQ}\\${SQ}${SQ}" failed at t/helper/test-example-tap.c:65
-	#    left: ${SQ}\\\\${SQ}
-	#   right: ${SQ}\\${SQ}${SQ}
+	# check "'a' == '\n'" failed at t/helper/test-example-tap.c:64
+	#    left: 'a'
+	#   right: '\012'
+	# check "'\\\\' == '\\''" failed at t/helper/test-example-tap.c:65
+	#    left: '\\\\'
+	#   right: '\\''
 	not ok 17 - messages from failing string and char comparison
-	# BUG: test has no checks at t/helper/test-example-tap.c:92
+	# BUG: test has no checks at t/helper/test-example-tap.c:94
 	not ok 18 - test with no checks
 	ok 19 - test with no checks returns 0
-	1..19
+	ok 20 - if_test passing test
+	# check "1 == 2" failed at t/helper/test-example-tap.c:100
+	#    left: 1
+	#   right: 2
+	not ok 21 - if_test failing test
+	not ok 22 - if_test passing TEST_TODO() # TODO
+	# todo check 'check(1)' succeeded at t/helper/test-example-tap.c:104
+	not ok 23 - if_test failing TEST_TODO()
+	# check "0" failed at t/helper/test-example-tap.c:106
+	# skipping test - missing prerequisite
+	# skipping check '1' at t/helper/test-example-tap.c:108
+	ok 24 - if_test test_skip() # SKIP
+	# skipping test - missing prerequisite
+	ok 25 - if_test test_skip() inside TEST_TODO() # SKIP
+	# check "0" failed at t/helper/test-example-tap.c:113
+	not ok 26 - if_test TEST_TODO() after failing check
+	# check "0" failed at t/helper/test-example-tap.c:119
+	not ok 27 - if_test failing check after TEST_TODO()
+	# check "!strcmp("\thello\\\\", "there\"\n")" failed at t/helper/test-example-tap.c:122
+	#    left: "\011hello\\\\"
+	#   right: "there\"\012"
+	# check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:123
+	#    left: "NULL"
+	#   right: NULL
+	# check "'a' == '\n'" failed at t/helper/test-example-tap.c:124
+	#    left: 'a'
+	#   right: '\012'
+	# check "'\\\\' == '\\''" failed at t/helper/test-example-tap.c:125
+	#    left: '\\\\'
+	#   right: '\\''
+	not ok 28 - if_test messages from failing string and char comparison
+	# BUG: test has no checks at t/helper/test-example-tap.c:127
+	not ok 29 - if_test test with no checks
+	1..29
 	EOF
 
 	! test-tool example-tap >actual &&
 	test_cmp expect actual
-'
+EOT
 
 test_done
diff --git a/t/t0110-urlmatch-normalization.sh b/t/t0110-urlmatch-normalization.sh
deleted file mode 100755
index 12d817f..0000000
--- a/t/t0110-urlmatch-normalization.sh
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/bin/sh
-
-test_description='urlmatch URL normalization'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-# The base name of the test url files
-tu="$TEST_DIRECTORY/t0110/url"
-
-# Note that only file: URLs should be allowed without a host
-
-test_expect_success 'url scheme' '
-	! test-tool urlmatch-normalization "" &&
-	! test-tool urlmatch-normalization "_" &&
-	! test-tool urlmatch-normalization "scheme" &&
-	! test-tool urlmatch-normalization "scheme:" &&
-	! test-tool urlmatch-normalization "scheme:/" &&
-	! test-tool urlmatch-normalization "scheme://" &&
-	! test-tool urlmatch-normalization "file" &&
-	! test-tool urlmatch-normalization "file:" &&
-	! test-tool urlmatch-normalization "file:/" &&
-	test-tool urlmatch-normalization "file://" &&
-	! test-tool urlmatch-normalization "://acme.co" &&
-	! test-tool urlmatch-normalization "x_test://acme.co" &&
-	! test-tool urlmatch-normalization "-test://acme.co" &&
-	! test-tool urlmatch-normalization "0test://acme.co" &&
-	! test-tool urlmatch-normalization "+test://acme.co" &&
-	! test-tool urlmatch-normalization ".test://acme.co" &&
-	! test-tool urlmatch-normalization "schem%6e://" &&
-	test-tool urlmatch-normalization "x-Test+v1.0://acme.co" &&
-	test "$(test-tool urlmatch-normalization -p "AbCdeF://x.Y")" = "abcdef://x.y/"
-'
-
-test_expect_success 'url authority' '
-	! test-tool urlmatch-normalization "scheme://user:pass@" &&
-	! test-tool urlmatch-normalization "scheme://?" &&
-	! test-tool urlmatch-normalization "scheme://#" &&
-	! test-tool urlmatch-normalization "scheme:///" &&
-	! test-tool urlmatch-normalization "scheme://:" &&
-	! test-tool urlmatch-normalization "scheme://:555" &&
-	test-tool urlmatch-normalization "file://user:pass@" &&
-	test-tool urlmatch-normalization "file://?" &&
-	test-tool urlmatch-normalization "file://#" &&
-	test-tool urlmatch-normalization "file:///" &&
-	test-tool urlmatch-normalization "file://:" &&
-	! test-tool urlmatch-normalization "file://:555" &&
-	test-tool urlmatch-normalization "scheme://user:pass@host" &&
-	test-tool urlmatch-normalization "scheme://@host" &&
-	test-tool urlmatch-normalization "scheme://%00@host" &&
-	! test-tool urlmatch-normalization "scheme://%%@host" &&
-	test-tool urlmatch-normalization "scheme://host_" &&
-	test-tool urlmatch-normalization "scheme://user:pass@host/" &&
-	test-tool urlmatch-normalization "scheme://@host/" &&
-	test-tool urlmatch-normalization "scheme://host/" &&
-	test-tool urlmatch-normalization "scheme://host?x" &&
-	test-tool urlmatch-normalization "scheme://host#x" &&
-	test-tool urlmatch-normalization "scheme://host/@" &&
-	test-tool urlmatch-normalization "scheme://host?@x" &&
-	test-tool urlmatch-normalization "scheme://host#@x" &&
-	test-tool urlmatch-normalization "scheme://[::1]" &&
-	test-tool urlmatch-normalization "scheme://[::1]/" &&
-	! test-tool urlmatch-normalization "scheme://hos%41/" &&
-	test-tool urlmatch-normalization "scheme://[invalid....:/" &&
-	test-tool urlmatch-normalization "scheme://invalid....:]/" &&
-	! test-tool urlmatch-normalization "scheme://invalid....:[/" &&
-	! test-tool urlmatch-normalization "scheme://invalid....:["
-'
-
-test_expect_success 'url port checks' '
-	test-tool urlmatch-normalization "xyz://q@some.host:" &&
-	test-tool urlmatch-normalization "xyz://q@some.host:456/" &&
-	! test-tool urlmatch-normalization "xyz://q@some.host:0" &&
-	! test-tool urlmatch-normalization "xyz://q@some.host:0000000" &&
-	test-tool urlmatch-normalization "xyz://q@some.host:0000001?" &&
-	test-tool urlmatch-normalization "xyz://q@some.host:065535#" &&
-	test-tool urlmatch-normalization "xyz://q@some.host:65535" &&
-	! test-tool urlmatch-normalization "xyz://q@some.host:65536" &&
-	! test-tool urlmatch-normalization "xyz://q@some.host:99999" &&
-	! test-tool urlmatch-normalization "xyz://q@some.host:100000" &&
-	! test-tool urlmatch-normalization "xyz://q@some.host:100001" &&
-	test-tool urlmatch-normalization "http://q@some.host:80" &&
-	test-tool urlmatch-normalization "https://q@some.host:443" &&
-	test-tool urlmatch-normalization "http://q@some.host:80/" &&
-	test-tool urlmatch-normalization "https://q@some.host:443?" &&
-	! test-tool urlmatch-normalization "http://q@:8008" &&
-	! test-tool urlmatch-normalization "http://:8080" &&
-	! test-tool urlmatch-normalization "http://:" &&
-	test-tool urlmatch-normalization "xyz://q@some.host:456/" &&
-	test-tool urlmatch-normalization "xyz://[::1]:456/" &&
-	test-tool urlmatch-normalization "xyz://[::1]:/" &&
-	! test-tool urlmatch-normalization "xyz://[::1]:000/" &&
-	! test-tool urlmatch-normalization "xyz://[::1]:0%300/" &&
-	! test-tool urlmatch-normalization "xyz://[::1]:0x80/" &&
-	! test-tool urlmatch-normalization "xyz://[::1]:4294967297/" &&
-	! test-tool urlmatch-normalization "xyz://[::1]:030f/"
-'
-
-test_expect_success 'url port normalization' '
-	test "$(test-tool urlmatch-normalization -p "http://x:800")" = "http://x:800/" &&
-	test "$(test-tool urlmatch-normalization -p "http://x:0800")" = "http://x:800/" &&
-	test "$(test-tool urlmatch-normalization -p "http://x:00000800")" = "http://x:800/" &&
-	test "$(test-tool urlmatch-normalization -p "http://x:065535")" = "http://x:65535/" &&
-	test "$(test-tool urlmatch-normalization -p "http://x:1")" = "http://x:1/" &&
-	test "$(test-tool urlmatch-normalization -p "http://x:80")" = "http://x/" &&
-	test "$(test-tool urlmatch-normalization -p "http://x:080")" = "http://x/" &&
-	test "$(test-tool urlmatch-normalization -p "http://x:000000080")" = "http://x/" &&
-	test "$(test-tool urlmatch-normalization -p "https://x:443")" = "https://x/" &&
-	test "$(test-tool urlmatch-normalization -p "https://x:0443")" = "https://x/" &&
-	test "$(test-tool urlmatch-normalization -p "https://x:000000443")" = "https://x/"
-'
-
-test_expect_success 'url general escapes' '
-	! test-tool urlmatch-normalization "http://x.y?%fg" &&
-	test "$(test-tool urlmatch-normalization -p "X://W/%7e%41^%3a")" = "x://w/~A%5E%3A" &&
-	test "$(test-tool urlmatch-normalization -p "X://W/:/?#[]@")" = "x://w/:/?#[]@" &&
-	test "$(test-tool urlmatch-normalization -p "X://W/$&()*+,;=")" = "x://w/$&()*+,;=" &&
-	test "$(test-tool urlmatch-normalization -p "X://W/'\''")" = "x://w/'\''" &&
-	test "$(test-tool urlmatch-normalization -p "X://W?'\!'")" = "x://w/?'\!'"
-'
-
-test_expect_success !MINGW 'url high-bit escapes' '
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-1")")" = "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12" &&
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-2")")" = "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F" &&
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-3")")" = "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F" &&
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-4")")" = "x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F" &&
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-5")")" = "x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF" &&
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-6")")" = "x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF" &&
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-7")")" = "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF" &&
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-8")")" = "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF" &&
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-9")")" = "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF" &&
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-10")")" = "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF"
-'
-
-test_expect_success 'url utf-8 escapes' '
-	test "$(test-tool urlmatch-normalization -p "$(cat "$tu-11")")" = "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD"
-'
-
-test_expect_success 'url username/password escapes' '
-	test "$(test-tool urlmatch-normalization -p "x://%41%62(^):%70+d@foo")" = "x://Ab(%5E):p+d@foo/"
-'
-
-test_expect_success 'url normalized lengths' '
-	test "$(test-tool urlmatch-normalization -l "Http://%4d%65:%4d^%70@The.Host")" = 25 &&
-	test "$(test-tool urlmatch-normalization -l "http://%41:%42@x.y/%61/")" = 17 &&
-	test "$(test-tool urlmatch-normalization -l "http://@x.y/^")" = 15
-'
-
-test_expect_success 'url . and .. segments' '
-	test "$(test-tool urlmatch-normalization -p "x://y/.")" = "x://y/" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/./")" = "x://y/" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/a/.")" = "x://y/a" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/a/./")" = "x://y/a/" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/.?")" = "x://y/?" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/./?")" = "x://y/?" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/a/.?")" = "x://y/a?" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/a/./?")" = "x://y/a/?" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/a/./b/.././../c")" = "x://y/c" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/a/./b/../.././c/")" = "x://y/c/" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/a/./b/.././../c/././.././.")" = "x://y/" &&
-	! test-tool urlmatch-normalization "x://y/a/./b/.././../c/././.././.." &&
-	test "$(test-tool urlmatch-normalization -p "x://y/a/./?/././..")" = "x://y/a/?/././.." &&
-	test "$(test-tool urlmatch-normalization -p "x://y/%2e/")" = "x://y/" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/%2E/")" = "x://y/" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/a/%2e./")" = "x://y/" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/b/.%2E/")" = "x://y/" &&
-	test "$(test-tool urlmatch-normalization -p "x://y/c/%2e%2E/")" = "x://y/"
-'
-
-# http://@foo specifies an empty user name but does not specify a password
-# http://foo  specifies neither a user name nor a password
-# So they should not be equivalent
-test_expect_success 'url equivalents' '
-	test-tool urlmatch-normalization "httP://x" "Http://X/" &&
-	test-tool urlmatch-normalization "Http://%4d%65:%4d^%70@The.Host" "hTTP://Me:%4D^p@the.HOST:80/" &&
-	! test-tool urlmatch-normalization "https://@x.y/^" "httpS://x.y:443/^" &&
-	test-tool urlmatch-normalization "https://@x.y/^" "httpS://@x.y:0443/^" &&
-	test-tool urlmatch-normalization "https://@x.y/^/../abc" "httpS://@x.y:0443/abc" &&
-	test-tool urlmatch-normalization "https://@x.y/^/.." "httpS://@x.y:0443/"
-'
-
-test_done
diff --git a/t/t0110/README b/t/t0110/README
deleted file mode 100644
index ad4a50e..0000000
--- a/t/t0110/README
+++ /dev/null
@@ -1,9 +0,0 @@
-The url data files in this directory contain URLs with characters
-in the range 0x01-0x1f and 0x7f-0xff to test the proper normalization
-of unprintable characters.
-
-A select few characters in the 0x01-0x1f range are skipped to help
-avoid problems running the test itself.
-
-The urls are in test files in this directory rather than being
-embedded in the test script for portability.
diff --git a/t/t0110/url-1 b/t/t0110/url-1
deleted file mode 100644
index 519019c..0000000
--- a/t/t0110/url-1
+++ /dev/null
@@ -1 +0,0 @@
-x://q/
diff --git a/t/t0110/url-10 b/t/t0110/url-10
deleted file mode 100644
index b9965de..0000000
--- a/t/t0110/url-10
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ðñòóôõö÷øùúûüýþÿ
diff --git a/t/t0110/url-11 b/t/t0110/url-11
deleted file mode 100644
index f0a50f1..0000000
--- a/t/t0110/url-11
+++ /dev/null
@@ -1 +0,0 @@
-x://q/€߿ࠀ�𐀀𯿽
diff --git a/t/t0110/url-2 b/t/t0110/url-2
deleted file mode 100644
index 43334b0..0000000
--- a/t/t0110/url-2
+++ /dev/null
@@ -1 +0,0 @@
-x://q/
diff --git a/t/t0110/url-3 b/t/t0110/url-3
deleted file mode 100644
index 7378c7b..0000000
--- a/t/t0110/url-3
+++ /dev/null
@@ -1 +0,0 @@
-x://q/€‚ƒ„…†‡ˆ‰Š‹ŒŽ
diff --git a/t/t0110/url-4 b/t/t0110/url-4
deleted file mode 100644
index 220b198..0000000
--- a/t/t0110/url-4
+++ /dev/null
@@ -1 +0,0 @@
-x://q/‘’“”•–—˜™š›œžŸ
diff --git a/t/t0110/url-5 b/t/t0110/url-5
deleted file mode 100644
index 1ccd927..0000000
--- a/t/t0110/url-5
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ ¡¢£¤¥¦§¨©ª«¬­®¯
diff --git a/t/t0110/url-6 b/t/t0110/url-6
deleted file mode 100644
index e8283aa..0000000
--- a/t/t0110/url-6
+++ /dev/null
@@ -1 +0,0 @@
-x://q/°±²³´µ¶·¸¹º»¼½¾¿
diff --git a/t/t0110/url-7 b/t/t0110/url-7
deleted file mode 100644
index fa7c10b..0000000
--- a/t/t0110/url-7
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
diff --git a/t/t0110/url-8 b/t/t0110/url-8
deleted file mode 100644
index 79a0ba8..0000000
--- a/t/t0110/url-8
+++ /dev/null
@@ -1 +0,0 @@
-x://q/ÐÑÒÓÔÕÖרÙÚÛÜÝÞß
diff --git a/t/t0110/url-9 b/t/t0110/url-9
deleted file mode 100644
index 8b44bec..0000000
--- a/t/t0110/url-9
+++ /dev/null
@@ -1 +0,0 @@
-x://q/àáâãäåæçèéêëìíîï
diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index c312657..b9adc94 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -2,7 +2,7 @@
 
 test_description='test trace2 facility (normal target)'
 
-TEST_PASSES_SANITIZE_LEAK=false
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Turn off any inherited trace2 settings for this test.
diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh
index c10e359..5d5b642 100755
--- a/t/t0301-credential-cache.sh
+++ b/t/t0301-credential-cache.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='credential-cache tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-credential.sh
 
diff --git a/t/t0302-credential-store.sh b/t/t0302-credential-store.sh
index 716bf1a..f83db65 100755
--- a/t/t0302-credential-store.sh
+++ b/t/t0302-credential-store.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='credential-store tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-credential.sh
 
diff --git a/t/t0303-credential-external.sh b/t/t0303-credential-external.sh
index 72ae405..8aadbe8 100755
--- a/t/t0303-credential-external.sh
+++ b/t/t0303-credential-external.sh
@@ -29,6 +29,7 @@
 commands.
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-credential.sh
 
diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh
index 2c30c86..34bdb3a 100755
--- a/t/t0410-partial-clone.sh
+++ b/t/t0410-partial-clone.sh
@@ -5,8 +5,6 @@
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-# missing promisor objects cause repacks which write bitmaps to fail
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 # When enabled, some commands will write commit-graphs. This causes fsck
 # to fail when delete_object() is called because fsck will attempt to
 # verify the out-of-sync commit graph.
diff --git a/t/t0601-reffiles-pack-refs.sh b/t/t0601-reffiles-pack-refs.sh
index 60a544b..d8cbd3f 100755
--- a/t/t0601-reffiles-pack-refs.sh
+++ b/t/t0601-reffiles-pack-refs.sh
@@ -161,13 +161,6 @@
 	git pack-refs --include "refs/heads/pack*" --exclude "refs/heads/pack*" &&
 	test -f .git/refs/heads/dont_pack5'
 
-test_expect_success '--auto packs and prunes refs as usual' '
-	git branch auto &&
-	test_path_is_file .git/refs/heads/auto &&
-	git pack-refs --auto --all &&
-	test_path_is_missing .git/refs/heads/auto
-'
-
 test_expect_success 'see if up-to-date packed refs are preserved' '
 	git branch q &&
 	git pack-refs --all --prune &&
@@ -367,14 +360,90 @@
 	test_cmp expect actual
 '
 
-test_expect_success 'maintenance --auto unconditionally packs loose refs' '
-	git update-ref refs/heads/something HEAD &&
-	test_path_is_file .git/refs/heads/something &&
-	git rev-parse refs/heads/something >expect &&
-	git maintenance run --task=pack-refs --auto &&
-	test_path_is_missing .git/refs/heads/something &&
-	git rev-parse refs/heads/something >actual &&
-	test_cmp expect actual
-'
+for command in "git pack-refs --all --auto" "git maintenance run --task=pack-refs --auto"
+do
+	test_expect_success "$command does not repack below 16 refs without packed-refs" '
+		test_when_finished "rm -rf repo" &&
+		git init repo &&
+		(
+			cd repo &&
+			git config set maintenance.auto false &&
+			git commit --allow-empty --message "initial" &&
+
+			# Create 14 additional references, which brings us to
+			# 15 together with the default branch.
+			printf "create refs/heads/loose-%d HEAD\n" $(test_seq 14) >stdin &&
+			git update-ref --stdin <stdin &&
+			test_path_is_missing .git/packed-refs &&
+			git pack-refs --auto --all &&
+			test_path_is_missing .git/packed-refs &&
+
+			# Create the 16th reference, which should cause us to repack.
+			git update-ref refs/heads/loose-15 HEAD &&
+			git pack-refs --auto --all &&
+			test_path_is_file .git/packed-refs
+		)
+	'
+
+	test_expect_success "$command does not repack below 16 refs with small packed-refs" '
+		test_when_finished "rm -rf repo" &&
+		git init repo &&
+		(
+			cd repo &&
+			git config set maintenance.auto false &&
+			git commit --allow-empty --message "initial" &&
+
+			git pack-refs --all &&
+			test_line_count = 2 .git/packed-refs &&
+
+			# Create 15 loose references.
+			printf "create refs/heads/loose-%d HEAD\n" $(test_seq 15) >stdin &&
+			git update-ref --stdin <stdin &&
+			git pack-refs --auto --all &&
+			test_line_count = 2 .git/packed-refs &&
+
+			# Create the 16th loose reference, which should cause us to repack.
+			git update-ref refs/heads/loose-17 HEAD &&
+			git pack-refs --auto --all &&
+			test_line_count = 18 .git/packed-refs
+		)
+	'
+
+	test_expect_success "$command scales with size of packed-refs" '
+		test_when_finished "rm -rf repo" &&
+		git init repo &&
+		(
+			cd repo &&
+			git config set maintenance.auto false &&
+			git commit --allow-empty --message "initial" &&
+
+			# Create 99 packed refs. This should cause the heuristic
+			# to require more than the minimum amount of loose refs.
+			test_seq 99 |
+			while read i
+			do
+				printf "create refs/heads/packed-%d HEAD\n" $i || return 1
+			done >stdin &&
+			git update-ref --stdin <stdin &&
+			git pack-refs --all &&
+			test_line_count = 101 .git/packed-refs &&
+
+			# Create 24 loose refs, which should not yet cause us to repack.
+			printf "create refs/heads/loose-%d HEAD\n" $(test_seq 24) >stdin &&
+			git update-ref --stdin <stdin &&
+			git pack-refs --auto --all &&
+			test_line_count = 101 .git/packed-refs &&
+
+			# Create another handful of refs to cross the border.
+			# Note that we explicitly do not check for strict
+			# boundaries here, as this also depends on the size of
+			# the object hash.
+			printf "create refs/heads/addn-%d HEAD\n" $(test_seq 10) >stdin &&
+			git update-ref --stdin <stdin &&
+			git pack-refs --auto --all &&
+			test_line_count = 135 .git/packed-refs
+		)
+	'
+done
 
 test_done
diff --git a/t/t0602-reffiles-fsck.sh b/t/t0602-reffiles-fsck.sh
new file mode 100755
index 0000000..71a4d1a
--- /dev/null
+++ b/t/t0602-reffiles-fsck.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+test_description='Test reffiles backend consistency check'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+GIT_TEST_DEFAULT_REF_FORMAT=files
+export GIT_TEST_DEFAULT_REF_FORMAT
+TEST_PASSES_SANITIZE_LEAK=true
+
+. ./test-lib.sh
+
+test_expect_success 'ref name should be checked' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	branch_dir_prefix=.git/refs/heads &&
+	tag_dir_prefix=.git/refs/tags &&
+	cd repo &&
+
+	git commit --allow-empty -m initial &&
+	git checkout -b branch-1 &&
+	git tag tag-1 &&
+	git commit --allow-empty -m second &&
+	git checkout -b branch-2 &&
+	git tag tag-2 &&
+	git tag multi_hierarchy/tag-2 &&
+
+	cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 &&
+	test_must_fail git refs verify 2>err &&
+	cat >expect <<-EOF &&
+	error: refs/heads/.branch-1: badRefName: invalid refname format
+	EOF
+	rm $branch_dir_prefix/.branch-1 &&
+	test_cmp expect err &&
+
+	cp $branch_dir_prefix/branch-1 $branch_dir_prefix/@ &&
+	test_must_fail git refs verify 2>err &&
+	cat >expect <<-EOF &&
+	error: refs/heads/@: badRefName: invalid refname format
+	EOF
+	rm $branch_dir_prefix/@ &&
+	test_cmp expect err &&
+
+	cp $tag_dir_prefix/multi_hierarchy/tag-2 $tag_dir_prefix/multi_hierarchy/@ &&
+	test_must_fail git refs verify 2>err &&
+	cat >expect <<-EOF &&
+	error: refs/tags/multi_hierarchy/@: badRefName: invalid refname format
+	EOF
+	rm $tag_dir_prefix/multi_hierarchy/@ &&
+	test_cmp expect err &&
+
+	cp $tag_dir_prefix/tag-1 $tag_dir_prefix/tag-1.lock &&
+	git refs verify 2>err &&
+	rm $tag_dir_prefix/tag-1.lock &&
+	test_must_be_empty err &&
+
+	cp $tag_dir_prefix/tag-1 $tag_dir_prefix/.lock &&
+	test_must_fail git refs verify 2>err &&
+	cat >expect <<-EOF &&
+	error: refs/tags/.lock: badRefName: invalid refname format
+	EOF
+	rm $tag_dir_prefix/.lock &&
+	test_cmp expect err
+'
+
+test_expect_success 'ref name check should be adapted into fsck messages' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	branch_dir_prefix=.git/refs/heads &&
+	tag_dir_prefix=.git/refs/tags &&
+	cd repo &&
+	git commit --allow-empty -m initial &&
+	git checkout -b branch-1 &&
+	git tag tag-1 &&
+	git commit --allow-empty -m second &&
+	git checkout -b branch-2 &&
+	git tag tag-2 &&
+
+	cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 &&
+	git -c fsck.badRefName=warn refs verify 2>err &&
+	cat >expect <<-EOF &&
+	warning: refs/heads/.branch-1: badRefName: invalid refname format
+	EOF
+	rm $branch_dir_prefix/.branch-1 &&
+	test_cmp expect err &&
+
+	cp $branch_dir_prefix/branch-1 $branch_dir_prefix/@ &&
+	git -c fsck.badRefName=ignore refs verify 2>err &&
+	test_must_be_empty err
+'
+
+test_done
diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index b06c469..babec79 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -423,6 +423,71 @@
 	)
 '
 
+test_expect_success 'ref transaction: timeout acquiring tables.list lock' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+		test_commit initial &&
+		>.git/reftable/tables.list.lock &&
+		test_must_fail git update-ref refs/heads/branch HEAD 2>err &&
+		test_grep "cannot lock references" err
+	)
+'
+
+test_expect_success 'ref transaction: retry acquiring tables.list lock' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+		test_commit initial &&
+		LOCK=.git/reftable/tables.list.lock &&
+		>$LOCK &&
+		{
+			( sleep 1 && rm -f $LOCK ) &
+		} &&
+		git -c reftable.lockTimeout=5000 update-ref refs/heads/branch HEAD
+	)
+'
+
+# This test fails most of the time on Windows systems. The root cause is
+# that Windows does not allow us to rename the "tables.list.lock" file into
+# place when "tables.list" is open for reading by a concurrent process.
+test_expect_success !WINDOWS 'ref transaction: many concurrent writers' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+		# Set a high timeout. While a couple of seconds should be
+		# plenty, using the address sanitizer will significantly slow
+		# us down here. So we are aiming way higher than you would ever
+		# think is necessary just to keep us from flaking. We could
+		# also lock indefinitely by passing -1, but that could
+		# potentially block CI jobs indefinitely if there was a bug
+		# here.
+		git config set reftable.lockTimeout 300000 &&
+		test_commit --no-tag initial &&
+
+		head=$(git rev-parse HEAD) &&
+		for i in $(test_seq 100)
+		do
+			printf "%s commit\trefs/heads/branch-%s\n" "$head" "$i" ||
+			return 1
+		done >expect &&
+		printf "%s commit\trefs/heads/main\n" "$head" >>expect &&
+
+		for i in $(test_seq 100)
+		do
+			{ git update-ref refs/heads/branch-$i HEAD& } ||
+			return 1
+		done &&
+
+		wait &&
+		git for-each-ref --sort=v:refname >actual &&
+		test_cmp expect actual
+	)
+'
+
 test_expect_success 'pack-refs: compacts tables' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
@@ -478,19 +543,26 @@
 
 		test_oid blob17_2 | git hash-object -w --stdin &&
 
-		# Lock all tables write some refs. Auto-compaction will be
-		# unable to compact tables and thus fails gracefully, leaving
-		# the stack in a sub-optimal state.
-		ls .git/reftable/*.ref |
+		# Lock all tables, write some refs. Auto-compaction will be
+		# unable to compact tables and thus fails gracefully,
+		# compacting only those tables which are not locked.
+		ls .git/reftable/*.ref | sort |
 		while read table
 		do
-			touch "$table.lock" || exit 1
+			touch "$table.lock" &&
+			basename "$table" >>tables.expect || exit 1
 		done &&
+		test_line_count = 2 .git/reftable/tables.list &&
 		git branch B &&
 		git branch C &&
-		rm .git/reftable/*.lock &&
-		test_line_count = 4 .git/reftable/tables.list &&
 
+		# The new tables are auto-compacted, but the locked tables are
+		# left intact.
+		test_line_count = 3 .git/reftable/tables.list &&
+		head -n 2 .git/reftable/tables.list >tables.head &&
+		test_cmp tables.expect tables.head &&
+
+		rm .git/reftable/*.lock &&
 		git $command --auto &&
 		test_line_count = 1 .git/reftable/tables.list
 	)
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index ff9bf21..d36cd7c 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -2,6 +2,7 @@
 
 test_description='git cat-file'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_cmdmode_usage () {
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index c71932b..ed638f6 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -3,6 +3,7 @@
 
 test_description='adding and checking out large blobs'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'core.bigFileThreshold must be non-negative' '
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index a2c0e1b..6e230b5 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -179,22 +179,26 @@
 }
 
 run_on_sparse () {
+	cat >run-on-sparse-input &&
+
 	(
 		cd sparse-checkout &&
 		GIT_PROGRESS_DELAY=100000 "$@" >../sparse-checkout-out 2>../sparse-checkout-err
-	) &&
+	) <run-on-sparse-input &&
 	(
 		cd sparse-index &&
 		GIT_PROGRESS_DELAY=100000 "$@" >../sparse-index-out 2>../sparse-index-err
-	)
+	) <run-on-sparse-input
 }
 
 run_on_all () {
+	cat >run-on-all-input &&
+
 	(
 		cd full-checkout &&
 		GIT_PROGRESS_DELAY=100000 "$@" >../full-checkout-out 2>../full-checkout-err
-	) &&
-	run_on_sparse "$@"
+	) <run-on-all-input &&
+	run_on_sparse "$@" <run-on-all-input
 }
 
 test_all_match () {
@@ -221,7 +225,7 @@
 	done
 }
 
-# Usage: test_sprase_checkout_set "<c1> ... <cN>" "<s1> ... <sM>"
+# Usage: test_sparse_checkout_set "<c1> ... <cN>" "<s1> ... <sM>"
 # Verifies that "git sparse-checkout set <c1> ... <cN>" succeeds and
 # leaves the sparse index in a state where <s1> ... <sM> are sparse
 # directories (and <c1> ... <cN> are not).
@@ -803,6 +807,8 @@
 	test_sparse_match git diff --cached --name-status &&
 	test_cmp expect sparse-checkout-out &&
 
+	test_sparse_match git diff-index --cached HEAD &&
+
 	# Reset the state
 	test_all_match git reset --hard &&
 
@@ -812,6 +818,8 @@
 	test_sparse_match git diff --cached --name-status &&
 	test_must_be_empty sparse-checkout-out &&
 
+	test_sparse_match git diff-index --cached HEAD &&
+
 	# Reset the state
 	test_all_match git reset --hard &&
 
@@ -823,7 +831,9 @@
 	D	folder1/a
 	EOF
 	test_sparse_match git diff --cached --name-status &&
-	test_cmp expect sparse-checkout-out
+	test_cmp expect sparse-checkout-out &&
+
+	test_sparse_match git diff-index --cached HEAD
 '
 
 test_expect_success 'update-index with directories' '
@@ -1551,7 +1561,7 @@
 	ensure_not_expanded describe
 '
 
-test_expect_success 'sparse index is not expanded: diff' '
+test_expect_success 'sparse index is not expanded: diff and diff-index' '
 	init_repos &&
 
 	write_script edit-contents <<-\EOF &&
@@ -1568,6 +1578,7 @@
 	test_all_match git diff --cached &&
 	ensure_not_expanded diff &&
 	ensure_not_expanded diff --cached &&
+	ensure_not_expanded diff-index --cached HEAD &&
 
 	# Add file outside cone
 	test_all_match git reset --hard &&
@@ -1582,6 +1593,7 @@
 	test_all_match git diff --cached &&
 	ensure_not_expanded diff &&
 	ensure_not_expanded diff --cached &&
+	ensure_not_expanded diff-index --cached HEAD &&
 
 	# Merge conflict outside cone
 	# The sparse checkout will report a warning that is not in the
@@ -1594,7 +1606,8 @@
 	test_all_match git diff &&
 	test_all_match git diff --cached &&
 	ensure_not_expanded diff &&
-	ensure_not_expanded diff --cached
+	ensure_not_expanded diff --cached &&
+	ensure_not_expanded diff-index --cached HEAD
 '
 
 test_expect_success 'sparse index is not expanded: show and rev-parse' '
@@ -2342,7 +2355,46 @@
 	mkdir -p sparse-index/deep/deeper2/deepest &&
 	touch sparse-index/deep/deeper2/deepest/bogus &&
 	git -C sparse-index status 2>err &&
-	grep "The sparse index is expanding to a full index" err
+	grep "The sparse index is expanding to a full index" err &&
+
+	git -C sparse-index sparse-checkout disable 2>err &&
+	test_line_count = 0 err
+'
+
+test_expect_success 'cat-file -p' '
+	init_repos &&
+	echo "new content" >>full-checkout/deep/a &&
+	echo "new content" >>sparse-checkout/deep/a &&
+	echo "new content" >>sparse-index/deep/a &&
+	run_on_all git add deep/a &&
+
+	test_all_match git cat-file -p :deep/a &&
+	ensure_not_expanded cat-file -p :deep/a &&
+	test_all_match git cat-file -p :folder1/a &&
+	ensure_expanded cat-file -p :folder1/a
+'
+
+test_expect_success 'cat-file --batch' '
+	init_repos &&
+	echo "new content" >>full-checkout/deep/a &&
+	echo "new content" >>sparse-checkout/deep/a &&
+	echo "new content" >>sparse-index/deep/a &&
+	run_on_all git add deep/a &&
+
+	echo ":deep/a" >in &&
+	test_all_match git cat-file --batch <in &&
+	ensure_not_expanded cat-file --batch <in &&
+
+	echo ":folder1/a" >in &&
+	test_all_match git cat-file --batch <in &&
+	ensure_expanded cat-file --batch <in &&
+
+	cat >in <<-\EOF &&
+	:deep/a
+	:folder1/a
+	EOF
+	test_all_match git cat-file --batch <in &&
+	ensure_expanded cat-file --batch <in
 '
 
 test_done
diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh
index 5cde79e..517d6c8 100755
--- a/t/t1305-config-include.sh
+++ b/t/t1305-config-include.sh
@@ -357,4 +357,44 @@
 	grep "exceeded maximum include depth" stderr
 '
 
+test_expect_success 'onbranch with unborn branch' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+		git config set includeIf.onbranch:"*".path config.inc &&
+		git config set -f .git/config.inc foo.bar baz &&
+		git config get foo.bar
+	)
+'
+
+test_expect_success 'onbranch with detached HEAD' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+		git config set "includeIf.onbranch:*.path" config.inc &&
+		git config set -f .git/config.inc foo.bar baz &&
+		test_commit initial &&
+		git switch --detach HEAD &&
+		test_must_fail git config get foo.bar
+	)
+'
+
+test_expect_success 'onbranch without repository' '
+	test_when_finished "rm -f .gitconfig config.inc" &&
+	git config set -f .gitconfig "includeIf.onbranch:**.path" config.inc &&
+	git config set -f config.inc foo.bar baz &&
+	git config get foo.bar &&
+	test_must_fail nongit git config get foo.bar
+'
+
+test_expect_success 'onbranch without repository but explicit nonexistent Git directory' '
+	test_when_finished "rm -f .gitconfig config.inc" &&
+	git config set -f .gitconfig "includeIf.onbranch:**.path" config.inc &&
+	git config set -f config.inc foo.bar baz &&
+	git config get foo.bar &&
+	test_must_fail nongit git --git-dir=nonexistent config get foo.bar
+'
+
 test_done
diff --git a/t/t1414-reflog-walk.sh b/t/t1414-reflog-walk.sh
index be6c3f4..49d2816 100755
--- a/t/t1414-reflog-walk.sh
+++ b/t/t1414-reflog-walk.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'set up some reflog entries' '
diff --git a/t/t1419-exclude-refs.sh b/t/t1419-exclude-refs.sh
index 1359574..3256e44 100755
--- a/t/t1419-exclude-refs.sh
+++ b/t/t1419-exclude-refs.sh
@@ -8,12 +8,6 @@
 TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
-if test_have_prereq !REFFILES
-then
-	skip_all='skipping `git for-each-ref --exclude` tests; need files backend'
-	test_done
-fi
-
 for_each_ref__exclude () {
 	GIT_TRACE2_PERF=1 test-tool ref-store main \
 		for-each-ref--exclude "$@" >actual.raw
@@ -28,7 +22,14 @@
 	local nr="$1"
 	local trace="$2"
 
-	grep -q "name:jumps_made value:$nr$" $trace
+	case "$GIT_DEFAULT_REF_FORMAT" in
+	files)
+		grep -q "name:jumps_made value:$nr$" $trace;;
+	reftable)
+		grep -q "name:reseeks_made value:$nr$" $trace;;
+	*)
+		BUG "unhandled ref format $GIT_DEFAULT_REF_FORMAT";;
+	esac
 }
 
 assert_no_jumps () {
@@ -89,7 +90,14 @@
 	for_each_ref refs/heads/foo refs/heads/quux >expect &&
 
 	test_cmp expect actual &&
-	assert_jumps 1 perf
+	case "$GIT_DEFAULT_REF_FORMAT" in
+	files)
+		assert_jumps 1 perf;;
+	reftable)
+		assert_jumps 2 perf;;
+	*)
+		BUG "unhandled ref format $GIT_DEFAULT_REF_FORMAT";;
+	esac
 '
 
 test_expect_success 'overlapping excluded regions' '
@@ -106,7 +114,30 @@
 	for_each_ref refs/heads/quux >expect &&
 
 	test_cmp expect actual &&
-	assert_jumps 1 perf
+	case "$GIT_DEFAULT_REF_FORMAT" in
+	files)
+		assert_jumps 1 perf;;
+	reftable)
+		assert_jumps 3 perf;;
+	*)
+		BUG "unhandled ref format $GIT_DEFAULT_REF_FORMAT";;
+	esac
+'
+
+test_expect_success 'unordered excludes' '
+	for_each_ref__exclude refs/heads \
+		refs/heads/foo refs/heads/baz >actual 2>perf &&
+	for_each_ref refs/heads/bar refs/heads/quux >expect &&
+
+	test_cmp expect actual &&
+	case "$GIT_DEFAULT_REF_FORMAT" in
+	files)
+		assert_jumps 1 perf;;
+	reftable)
+		assert_jumps 2 perf;;
+	*)
+		BUG "unhandled ref format $GIT_DEFAULT_REF_FORMAT";;
+	esac
 '
 
 test_expect_success 'non-matching excluded section' '
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 8a456b1..280cbf3 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -6,6 +6,7 @@
 * (main) A
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index b754b9f..5eaa642 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test git rev-parse --parseopt'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check_invalid_long_option () {
diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh
index 6ecfed8..e7e78a4 100755
--- a/t/t1511-rev-parse-caret.sh
+++ b/t/t1511-rev-parse-caret.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t1601-index-bogus.sh b/t/t1601-index-bogus.sh
index 4171f1e..5dcc101 100755
--- a/t/t1601-index-bogus.sh
+++ b/t/t1601-index-bogus.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test handling of bogus index entries'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'create tree with null sha1' '
diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh
index be3fcdd..b3f6bc9 100755
--- a/t/t2030-unresolve-info.sh
+++ b/t/t2030-unresolve-info.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check_resolve_undo () {
diff --git a/t/t2080-parallel-checkout-basics.sh b/t/t2080-parallel-checkout-basics.sh
index 5ffe1a4..59e5570 100755
--- a/t/t2080-parallel-checkout-basics.sh
+++ b/t/t2080-parallel-checkout-basics.sh
@@ -8,6 +8,7 @@
 '
 
 TEST_NO_CREATE_REPO=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-parallel-checkout.sh"
 
diff --git a/t/t2082-parallel-checkout-attributes.sh b/t/t2082-parallel-checkout-attributes.sh
index f3511cd..aec5549 100755
--- a/t/t2082-parallel-checkout-attributes.sh
+++ b/t/t2082-parallel-checkout-attributes.sh
@@ -10,6 +10,7 @@
 '
 
 TEST_NO_CREATE_REPO=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-parallel-checkout.sh"
 . "$TEST_DIRECTORY/lib-encoding.sh"
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index ba320dc..cfc4aeb 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -6,6 +6,7 @@
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t2501-cwd-empty.sh b/t/t2501-cwd-empty.sh
index f6d8d7d..8af4e8c 100755
--- a/t/t2501-cwd-empty.sh
+++ b/t/t2501-cwd-empty.sh
@@ -2,6 +2,7 @@
 
 test_description='Test handling of the current working directory becoming empty'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t3011-common-prefixes-and-directory-traversal.sh b/t/t3011-common-prefixes-and-directory-traversal.sh
index 3da5b2b..69e44c3 100755
--- a/t/t3011-common-prefixes-and-directory-traversal.sh
+++ b/t/t3011-common-prefixes-and-directory-traversal.sh
@@ -2,6 +2,7 @@
 
 test_description='directory traversal handling, especially with common prefixes'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh
index 800fc33..6e587d2 100755
--- a/t/t3201-branch-contains.sh
+++ b/t/t3201-branch-contains.sh
@@ -2,6 +2,7 @@
 
 test_description='branch --contains <commit>, --no-contains <commit> --merged, and --no-merged'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t3202-show-branch.sh b/t/t3202-show-branch.sh
index a1139f7..3b6dad0 100755
--- a/t/t3202-show-branch.sh
+++ b/t/t3202-show-branch.sh
@@ -2,6 +2,7 @@
 
 test_description='test show-branch'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'error descriptions on empty repository' '
diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh
index a767c35..8601093 100755
--- a/t/t3206-range-diff.sh
+++ b/t/t3206-range-diff.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Note that because of the range-diff's heuristics, test_commit does more
@@ -533,9 +534,9 @@
 for prev in topic main..topic
 do
 	test_expect_success "format-patch --range-diff=$prev" '
+		test_when_finished "rm -f 000?-*" &&
 		git format-patch --cover-letter --range-diff=$prev \
 			main..unmodified >actual &&
-		test_when_finished "rm 000?-*" &&
 		test_line_count = 5 actual &&
 		test_grep "^Range-diff:$" 0000-* &&
 		grep "= 1: .* s/5/A" 0000-* &&
@@ -560,32 +561,32 @@
 '
 
 test_expect_success 'format-patch --range-diff as commentary' '
+	test_when_finished "rm -f 0001-*" &&
 	git format-patch --range-diff=HEAD~1 HEAD~1 >actual &&
-	test_when_finished "rm 0001-*" &&
 	test_line_count = 1 actual &&
 	test_grep "^Range-diff:$" 0001-* &&
 	grep "> 1: .* new message" 0001-*
 '
 
 test_expect_success 'format-patch --range-diff reroll-count with a non-integer' '
+	test_when_finished "rm -f v2.9-0001-*" &&
 	git format-patch --range-diff=HEAD~1 -v2.9 HEAD~1 >actual &&
-	test_when_finished "rm v2.9-0001-*" &&
 	test_line_count = 1 actual &&
 	test_grep "^Range-diff:$" v2.9-0001-* &&
 	grep "> 1: .* new message" v2.9-0001-*
 '
 
 test_expect_success 'format-patch --range-diff reroll-count with a integer' '
+	test_when_finished "rm -f v2-0001-*" &&
 	git format-patch --range-diff=HEAD~1 -v2 HEAD~1 >actual &&
-	test_when_finished "rm v2-0001-*" &&
 	test_line_count = 1 actual &&
 	test_grep "^Range-diff ..* v1:$" v2-0001-* &&
 	grep "> 1: .* new message" v2-0001-*
 '
 
 test_expect_success 'format-patch --range-diff with v0' '
+	test_when_finished "rm -f v0-0001-*" &&
 	git format-patch --range-diff=HEAD~1 -v0 HEAD~1 >actual &&
-	test_when_finished "rm v0-0001-*" &&
 	test_line_count = 1 actual &&
 	test_grep "^Range-diff:$" v0-0001-* &&
 	grep "> 1: .* new message" v0-0001-*
@@ -606,9 +607,9 @@
 '
 
 test_expect_success 'range-diff compares notes by default' '
+	test_when_finished "git notes remove topic unmodified || :" &&
 	git notes add -m "topic note" topic &&
 	git notes add -m "unmodified note" unmodified &&
-	test_when_finished git notes remove topic unmodified &&
 	git range-diff --no-color main..topic main..unmodified \
 		>actual &&
 	sed s/Z/\ /g >expect <<-EOF &&
@@ -630,9 +631,9 @@
 '
 
 test_expect_success 'range-diff with --no-notes' '
+	test_when_finished "git notes remove topic unmodified || :" &&
 	git notes add -m "topic note" topic &&
 	git notes add -m "unmodified note" unmodified &&
-	test_when_finished git notes remove topic unmodified &&
 	git range-diff --no-color --no-notes main..topic main..unmodified \
 		>actual &&
 	cat >expect <<-EOF &&
@@ -645,12 +646,12 @@
 '
 
 test_expect_success 'range-diff with multiple --notes' '
+	test_when_finished "git notes --ref=note1 remove topic unmodified || :" &&
 	git notes --ref=note1 add -m "topic note1" topic &&
 	git notes --ref=note1 add -m "unmodified note1" unmodified &&
-	test_when_finished git notes --ref=note1 remove topic unmodified &&
+	test_when_finished "git notes --ref=note2 remove topic unmodified || :" &&
 	git notes --ref=note2 add -m "topic note2" topic &&
 	git notes --ref=note2 add -m "unmodified note2" unmodified &&
-	test_when_finished git notes --ref=note2 remove topic unmodified &&
 	git range-diff --no-color --notes=note1 --notes=note2 main..topic main..unmodified \
 		>actual &&
 	sed s/Z/\ /g >expect <<-EOF &&
@@ -678,12 +679,12 @@
 
 # `range-diff` should act like `log` with regards to notes
 test_expect_success 'range-diff with --notes=custom does not show default notes' '
+	test_when_finished "git notes remove topic unmodified || :" &&
 	git notes add -m "topic note" topic &&
 	git notes add -m "unmodified note" unmodified &&
+	test_when_finished "git notes --ref=custom remove topic unmodified || :" &&
 	git notes --ref=custom add -m "topic note" topic &&
 	git notes --ref=custom add -m "unmodified note" unmodified &&
-	test_when_finished git notes remove topic unmodified &&
-	test_when_finished git notes --ref=custom remove topic unmodified &&
 	git range-diff --notes=custom main..topic main..unmodified \
 		>actual &&
 	! grep "## Notes ##" actual &&
@@ -691,12 +692,12 @@
 '
 
 test_expect_success 'format-patch --range-diff does not compare notes by default' '
+	test_when_finished "git notes remove topic unmodified || :" &&
 	git notes add -m "topic note" topic &&
 	git notes add -m "unmodified note" unmodified &&
-	test_when_finished git notes remove topic unmodified &&
+	test_when_finished "rm -f 000?-*" &&
 	git format-patch --cover-letter --range-diff=$prev \
 		main..unmodified >actual &&
-	test_when_finished "rm 000?-*" &&
 	test_line_count = 5 actual &&
 	test_grep "^Range-diff:$" 0000-* &&
 	grep "= 1: .* s/5/A" 0000-* &&
@@ -708,26 +709,26 @@
 '
 
 test_expect_success 'format-patch --notes=custom --range-diff only compares custom notes' '
+	test_when_finished "git notes remove topic unmodified || :" &&
 	git notes add -m "topic note" topic &&
-	git notes --ref=custom add -m "topic note (custom)" topic &&
 	git notes add -m "unmodified note" unmodified &&
+	test_when_finished "git notes --ref=custom remove topic unmodified || :" &&
+	git notes --ref=custom add -m "topic note (custom)" topic &&
 	git notes --ref=custom add -m "unmodified note (custom)" unmodified &&
-	test_when_finished git notes remove topic unmodified &&
-	test_when_finished git notes --ref=custom remove topic unmodified &&
+	test_when_finished "rm -f 000?-*" &&
 	git format-patch --notes=custom --cover-letter --range-diff=$prev \
 		main..unmodified >actual &&
-	test_when_finished "rm 000?-*" &&
 	grep "## Notes (custom) ##" 0000-* &&
 	! grep "## Notes ##" 0000-*
 '
 
 test_expect_success 'format-patch --range-diff with --no-notes' '
+	test_when_finished "git notes remove topic unmodified || :" &&
 	git notes add -m "topic note" topic &&
 	git notes add -m "unmodified note" unmodified &&
-	test_when_finished git notes remove topic unmodified &&
+	test_when_finished "rm -f 000?-*" &&
 	git format-patch --no-notes --cover-letter --range-diff=$prev \
 		main..unmodified >actual &&
-	test_when_finished "rm 000?-*" &&
 	test_line_count = 5 actual &&
 	test_grep "^Range-diff:$" 0000-* &&
 	grep "= 1: .* s/5/A" 0000-* &&
@@ -739,12 +740,12 @@
 '
 
 test_expect_success 'format-patch --range-diff with --notes' '
+	test_when_finished "git notes remove topic unmodified || :" &&
 	git notes add -m "topic note" topic &&
 	git notes add -m "unmodified note" unmodified &&
-	test_when_finished git notes remove topic unmodified &&
+	test_when_finished "rm -f 000?-*" &&
 	git format-patch --notes --cover-letter --range-diff=$prev \
 		main..unmodified >actual &&
-	test_when_finished "rm 000?-*" &&
 	test_line_count = 5 actual &&
 	test_grep "^Range-diff:$" 0000-* &&
 	grep "= 1: .* s/5/A" 0000-* &&
@@ -767,13 +768,13 @@
 '
 
 test_expect_success 'format-patch --range-diff with format.notes config' '
+	test_when_finished "git notes remove topic unmodified || :" &&
 	git notes add -m "topic note" topic &&
 	git notes add -m "unmodified note" unmodified &&
-	test_when_finished git notes remove topic unmodified &&
 	test_config format.notes true &&
+	test_when_finished "rm -f 000?-*" &&
 	git format-patch --cover-letter --range-diff=$prev \
 		main..unmodified >actual &&
-	test_when_finished "rm 000?-*" &&
 	test_line_count = 5 actual &&
 	test_grep "^Range-diff:$" 0000-* &&
 	grep "= 1: .* s/5/A" 0000-* &&
@@ -796,15 +797,15 @@
 '
 
 test_expect_success 'format-patch --range-diff with multiple notes' '
+	test_when_finished "git notes --ref=note1 remove topic unmodified || :" &&
 	git notes --ref=note1 add -m "topic note1" topic &&
 	git notes --ref=note1 add -m "unmodified note1" unmodified &&
-	test_when_finished git notes --ref=note1 remove topic unmodified &&
+	test_when_finished "git notes --ref=note2 remove topic unmodified || :" &&
 	git notes --ref=note2 add -m "topic note2" topic &&
 	git notes --ref=note2 add -m "unmodified note2" unmodified &&
-	test_when_finished git notes --ref=note2 remove topic unmodified &&
+	test_when_finished "rm -f 000?-*" &&
 	git format-patch --notes=note1 --notes=note2 --cover-letter --range-diff=$prev \
 		main..unmodified >actual &&
-	test_when_finished "rm 000?-*" &&
 	test_line_count = 5 actual &&
 	test_grep "^Range-diff:$" 0000-* &&
 	grep "= 1: .* s/5/A" 0000-* &&
diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh
index 597df5e..04866b8 100755
--- a/t/t3310-notes-merge-manual-resolve.sh
+++ b/t/t3310-notes-merge-manual-resolve.sh
@@ -5,6 +5,7 @@
 
 test_description='Test notes merging with manual conflict resolution'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Set up a notes merge scenario with different kinds of conflicts
diff --git a/t/t3311-notes-merge-fanout.sh b/t/t3311-notes-merge-fanout.sh
index 5b67541..ce4144d 100755
--- a/t/t3311-notes-merge-fanout.sh
+++ b/t/t3311-notes-merge-fanout.sh
@@ -5,6 +5,7 @@
 
 test_description='Test notes merging at various fanout levels'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 verify_notes () {
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index ae34bfa..09f230e 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -145,7 +145,9 @@
 	test_when_finished "rm -f B" &&
 	test_must_fail git rebase topic 2>output.err >output.out &&
 	test_grep "The following untracked working tree files would be overwritten by checkout:" output.err &&
-	test_grep B output.err
+	test_grep B output.err &&
+	test_must_fail git rebase --quit 2>err &&
+	test_grep "no rebase in progress" err
 '
 
 test_expect_success 'fail when upstream arg is missing and not on branch' '
@@ -235,6 +237,12 @@
 	test_must_be_empty output.out
 '
 
+test_expect_success 'rebase --exec -q is quiet' '
+	git checkout -B quiet topic &&
+	git rebase --exec true -q main >output.out 2>&1 &&
+	test_must_be_empty output.out
+'
+
 test_expect_success 'Rebase a commit that sprinkles CRs in' '
 	(
 		echo "One" &&
@@ -422,7 +430,9 @@
 	git checkout main &&
 	git worktree add wt &&
 	test_must_fail git -C wt rebase main main 2>err &&
-	test_grep "already used by worktree at" err
+	test_grep "already used by worktree at" err &&
+	test_must_fail git -C wt rebase --quit 2>err &&
+	test_grep "no rebase in progress" err
 '
 
 test_expect_success 'rebase when inside worktree subdirectory' '
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index f92baad..f171af3 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -26,6 +26,7 @@
  touch file "conflict".
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh
index e845683..426ff09 100755
--- a/t/t3413-rebase-hook.sh
+++ b/t/t3413-rebase-hook.sh
@@ -110,7 +110,9 @@
 	git reset --hard side &&
 	test_must_fail git rebase main &&
 	test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
-	test 0 = $(git rev-list HEAD...side | wc -l)
+	test 0 = $(git rev-list HEAD...side | wc -l) &&
+	test_must_fail git rebase --quit 2>err &&
+	test_grep "no rebase in progress" err
 '
 
 test_expect_success 'pre-rebase hook stops rebase (2)' '
diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh
index 63e400b..b43046b 100755
--- a/t/t3420-rebase-autostash.sh
+++ b/t/t3420-rebase-autostash.sh
@@ -82,6 +82,46 @@
 	type=$1
 	dotest=$2
 
+	test_expect_success "rebase$type: restore autostash when pre-rebase hook fails" '
+		git checkout -f feature-branch &&
+		test_hook pre-rebase <<-\EOF &&
+		exit 1
+		EOF
+
+		echo changed >file0 &&
+		test_must_fail git rebase $type --autostash -f HEAD^ &&
+		test_must_fail git rebase --quit 2>err &&
+		test_grep "no rebase in progress" err &&
+		echo changed >expect &&
+		test_cmp expect file0
+	'
+
+	test_expect_success "rebase$type: restore autostash when checkout onto fails" '
+		git checkout -f --detach feature-branch &&
+		echo uncommitted-content >file0 &&
+		echo untracked >file4 &&
+		test_when_finished "rm file4" &&
+		test_must_fail git rebase $type --autostash \
+							unrelated-onto-branch &&
+		test_must_fail git rebase --quit 2>err &&
+		test_grep "no rebase in progress" err &&
+		echo uncommitted-content >expect &&
+		test_cmp expect file0
+	'
+
+	test_expect_success "rebase$type: restore autostash when branch checkout fails" '
+		git checkout -f unrelated-onto-branch^ &&
+		echo uncommitted-content >file0 &&
+		echo untracked >file4 &&
+		test_when_finished "rm file4" &&
+		test_must_fail git rebase $type --autostash HEAD \
+							unrelated-onto-branch &&
+		test_must_fail git rebase --quit 2>err &&
+		test_grep "no rebase in progress" err &&
+		echo uncommitted-content >expect &&
+		test_cmp expect file0
+	'
+
 	test_expect_success "rebase$type: dirty worktree, --no-autostash" '
 		test_config rebase.autostash true &&
 		git reset --hard &&
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index 36ca126..2aa8593 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -392,8 +392,7 @@
 
 test_expect_success 'root commits' '
 	git checkout --orphan unrelated &&
-	(GIT_AUTHOR_NAME="Parsnip" GIT_AUTHOR_EMAIL="root@example.com" \
-	 test_commit second-root) &&
+	test_commit --author "Parsnip <root@example.com>" second-root &&
 	test_commit third-root &&
 	cat >script-from-scratch <<-\EOF &&
 	pick third-root
diff --git a/t/t3435-rebase-gpg-sign.sh b/t/t3435-rebase-gpg-sign.sh
index 6aa2aeb..6e329fe 100755
--- a/t/t3435-rebase-gpg-sign.sh
+++ b/t/t3435-rebase-gpg-sign.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-rebase.sh"
 . "$TEST_DIRECTORY/lib-gpg.sh"
diff --git a/t/t3436-rebase-more-options.sh b/t/t3436-rebase-more-options.sh
index 94671d3..4d9744e 100755
--- a/t/t3436-rebase-more-options.sh
+++ b/t/t3436-rebase-more-options.sh
@@ -5,6 +5,7 @@
 
 test_description='tests to ensure compatibility between am and interactive backends'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index f3947b4..10e9c91 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -13,6 +13,7 @@
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 pristine_detach () {
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 7eb52b1..93c725b 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -12,6 +12,7 @@
 
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Repeat first match 10 times
diff --git a/t/t3650-replay-basics.sh b/t/t3650-replay-basics.sh
index 3896702..12bd3db 100755
--- a/t/t3650-replay-basics.sh
+++ b/t/t3650-replay-basics.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 GIT_AUTHOR_NAME=author@name
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index 9a48933..718438f 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -575,6 +575,54 @@
 	test_cmp expect actual.trimmed
 '
 
+test_expect_success 'print again the hunk' '
+	test_when_finished "git reset" &&
+	tr _ " " >expect <<-EOF &&
+	+15
+	 20
+	(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? @@ -1,2 +1,3 @@
+	 10
+	+15
+	 20
+	(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_
+	EOF
+	test_write_lines s y g 1 p | git add -p >actual &&
+	tail -n 7 <actual >actual.trimmed &&
+	test_cmp expect actual.trimmed
+'
+
+test_expect_success TTY 'print again the hunk (PAGER)' '
+	test_when_finished "git reset" &&
+	cat >expect <<-EOF &&
+	<GREEN>+<RESET><GREEN>15<RESET>
+	 20<RESET>
+	<BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET>PAGER <CYAN>@@ -1,2 +1,3 @@<RESET>
+	PAGER  10<RESET>
+	PAGER <GREEN>+<RESET><GREEN>15<RESET>
+	PAGER  20<RESET>
+	<BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET>
+	EOF
+	test_write_lines s y g 1 P |
+	(
+		GIT_PAGER="sed s/^/PAGER\ /" &&
+		export GIT_PAGER &&
+		test_terminal git add -p >actual
+	) &&
+	tail -n 7 <actual | test_decode_color >actual.trimmed &&
+	test_cmp expect actual.trimmed
+'
+
+test_expect_success TTY 'P handles SIGPIPE when writing to pager' '
+	test_when_finished "rm -f huge_file; git reset" &&
+	printf "\n%2500000s" Y >huge_file &&
+	git add -N huge_file &&
+	test_write_lines P q | (
+		GIT_PAGER="head -n 1" &&
+		export GIT_PAGER &&
+		test_terminal git add -p
+	)
+'
+
 test_expect_success 'split hunk "add -p (edit)"' '
 	# Split, say Edit and do nothing.  Then:
 	#
diff --git a/t/t3705-add-sparse-checkout.sh b/t/t3705-add-sparse-checkout.sh
index 2bade9e..6ae45a7 100755
--- a/t/t3705-add-sparse-checkout.sh
+++ b/t/t3705-add-sparse-checkout.sh
@@ -2,6 +2,7 @@
 
 test_description='git add in sparse checked out working trees'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 SPARSE_ENTRY_BLOB=""
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 74666ff..c87592e 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-unique-files.sh
 
diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh
index 368fc2a..aa5019f 100755
--- a/t/t3904-stash-patch.sh
+++ b/t/t3904-stash-patch.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='stash -p'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./lib-patch-mode.sh
 
 test_expect_success 'setup' '
diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh
index 1289ae3..a1733f4 100755
--- a/t/t3905-stash-include-untracked.sh
+++ b/t/t3905-stash-include-untracked.sh
@@ -5,6 +5,7 @@
 
 test_description='Test git stash --include-untracked'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'stash save --include-untracked some dirty working directory' '
diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh
index 562aaf3..b0ef002 100755
--- a/t/t4008-diff-break-rewrite.sh
+++ b/t/t4008-diff-break-rewrite.sh
@@ -21,6 +21,8 @@
 
 Further, with -B and -M together, these should turn into two renames.
 '
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash
 
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 3855d68..87d248d 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh
 
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 884f83f..1c46e96 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh
index d644310..1cea73e 100755
--- a/t/t4017-diff-retval.sh
+++ b/t/t4017-diff-retval.sh
@@ -145,6 +145,14 @@
 
 for option in --exit-code --quiet
 do
+	test_expect_success "git diff $option returns 1 for changed binary file" "
+		test_when_finished 'rm -f .gitattributes' &&
+		git reset --hard &&
+		echo a binary >.gitattributes &&
+		echo 2 >>a &&
+		test_expect_code 1 git diff $option
+	"
+
 	test_expect_success "git diff $option returns 1 for copied file" "
 		git reset --hard &&
 		cp a copy &&
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index e026fac..8128c30 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -5,6 +5,7 @@
 
 test_description='Test custom diff function name patterns'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t4022-diff-rewrite.sh b/t/t4022-diff-rewrite.sh
index 6fed993..77bc36d 100755
--- a/t/t4022-diff-rewrite.sh
+++ b/t/t4022-diff-rewrite.sh
@@ -2,6 +2,7 @@
 
 test_description='rewrite diff'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff-data.sh
 
diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh
index 787605c..e6f4fe4 100755
--- a/t/t4023-diff-rename-typechange.sh
+++ b/t/t4023-diff-rename-typechange.sh
@@ -2,6 +2,7 @@
 
 test_description='typechange rename detection'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh
 
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index a39a626..29f6d61 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='diff.*.textconv tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 find_diff() {
diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh
index c4394a2..1b8cd3e 100755
--- a/t/t4031-diff-rewrite-binary.sh
+++ b/t/t4031-diff-rewrite-binary.sh
@@ -2,6 +2,7 @@
 
 test_description='rewrite diff on binary file'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # We must be large enough to meet the MINIMUM_BREAK_SIZE
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index 74586f3..4dcd7e9 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -70,7 +70,7 @@
 		word_diff --color-words
 	'
 	test_expect_success "diff driver '$lang' in Islandic" '
-		LANG=is_IS.UTF-8 LANGUAGE=is LC_ALL="$is_IS_locale" \
+		test_env LANG=is_IS.UTF-8 LANGUAGE=is LC_ALL="$is_IS_locale" \
 		word_diff --color-words
 	'
 }
diff --git a/t/t4042-diff-textconv-caching.sh b/t/t4042-diff-textconv-caching.sh
index 8ebfa3c..a179205 100755
--- a/t/t4042-diff-textconv-caching.sh
+++ b/t/t4042-diff-textconv-caching.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test textconv caching'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 cat >helper <<'EOF'
diff --git a/t/t4048-diff-combined-binary.sh b/t/t4048-diff-combined-binary.sh
index 0260cf6..f399484 100755
--- a/t/t4048-diff-combined-binary.sh
+++ b/t/t4048-diff-combined-binary.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup binary merge conflict' '
diff --git a/t/t4056-diff-order.sh b/t/t4056-diff-order.sh
index aec1d9d..32c5fcb 100755
--- a/t/t4056-diff-order.sh
+++ b/t/t4056-diff-order.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 create_files () {
diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh
index 2501c89..18e5ac8 100755
--- a/t/t4058-diff-duplicates.sh
+++ b/t/t4058-diff-duplicates.sh
@@ -10,6 +10,8 @@
 #   that the diff output isn't wildly unreasonable.
 
 test_description='test tree diff when trees have duplicate entries'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # make_tree_entry <mode> <mode> <sha1>
@@ -132,22 +134,23 @@
 	rm commit_id up final
 '
 
-test_expect_failure 'git read-tree does not segfault' '
-	test_when_finished rm .git/index.lock &&
-	test_might_fail git read-tree --reset base
+test_expect_success 'git read-tree does not segfault' '
+	test_must_fail git read-tree --reset base 2>err &&
+	test_grep "error: corrupted cache-tree has entries not present in index" err
 '
 
-test_expect_failure 'reset --hard does not segfault' '
-	test_when_finished rm .git/index.lock &&
+test_expect_success 'reset --hard does not segfault' '
 	git checkout base &&
-	test_might_fail git reset --hard
+	test_must_fail git reset --hard 2>err &&
+	test_grep "error: corrupted cache-tree has entries not present in index" err
 '
 
-test_expect_failure 'git diff HEAD does not segfault' '
+test_expect_success 'git diff HEAD does not segfault' '
 	git checkout base &&
 	GIT_TEST_CHECK_CACHE_TREE=false &&
 	git reset --hard &&
-	test_might_fail git diff HEAD
+	test_must_fail git diff HEAD 2>err &&
+	test_grep "error: corrupted cache-tree has entries not present in index" err
 '
 
 test_expect_failure 'can switch to another branch when status is empty' '
diff --git a/t/t4064-diff-oidfind.sh b/t/t4064-diff-oidfind.sh
index 6d8c898..846f285 100755
--- a/t/t4064-diff-oidfind.sh
+++ b/t/t4064-diff-oidfind.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test finding specific blobs in the revision walking'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup ' '
diff --git a/t/t4065-diff-anchored.sh b/t/t4065-diff-anchored.sh
index b3f510f..647537c 100755
--- a/t/t4065-diff-anchored.sh
+++ b/t/t4065-diff-anchored.sh
@@ -2,6 +2,7 @@
 
 test_description='anchored diff algorithm'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success '--anchored' '
diff --git a/t/t4068-diff-symmetric-merge-base.sh b/t/t4068-diff-symmetric-merge-base.sh
index eff63c1..4d6565e 100755
--- a/t/t4068-diff-symmetric-merge-base.sh
+++ b/t/t4068-diff-symmetric-merge-base.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # build these situations:
diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh
index ca8f999..df34285 100755
--- a/t/t4069-remerge-diff.sh
+++ b/t/t4069-remerge-diff.sh
@@ -2,6 +2,7 @@
 
 test_description='remerge-diff handling'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # This test is ort-specific
diff --git a/t/t4107-apply-ignore-whitespace.sh b/t/t4107-apply-ignore-whitespace.sh
index ac72eea..5e6e203 100755
--- a/t/t4107-apply-ignore-whitespace.sh
+++ b/t/t4107-apply-ignore-whitespace.sh
@@ -3,9 +3,9 @@
 # Copyright (c) 2009 Giuseppe Bilotta
 #
 
-test_description='git-apply --ignore-whitespace.
+test_description='git-apply --ignore-whitespace.'
 
-'
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # This primes main.c file that indents without using HT at all.
diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh
index c558282..c630216 100755
--- a/t/t4108-apply-threeway.sh
+++ b/t/t4108-apply-threeway.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 print_sanitized_conflicted_diff () {
@@ -81,6 +82,46 @@
 	test_apply_with_3way
 '
 
+test_apply_with_3way_favoritism () {
+	apply_arg=$1
+	merge_arg=$2
+
+	# Merging side should be similar to applying this patch
+	git diff ...side >P.diff &&
+
+	# The corresponding conflicted merge
+	git reset --hard &&
+	git checkout main^0 &&
+	git merge --no-commit $merge_arg side &&
+	git ls-files -s >expect.ls &&
+	print_sanitized_conflicted_diff >expect.diff &&
+
+	# should apply successfully
+	git reset --hard &&
+	git checkout main^0 &&
+	git apply --index --3way $apply_arg P.diff &&
+	git ls-files -s >actual.ls &&
+	print_sanitized_conflicted_diff >actual.diff &&
+
+	# The result should resemble the corresponding merge
+	test_cmp expect.ls actual.ls &&
+	test_cmp expect.diff actual.diff
+}
+
+test_expect_success 'apply with --3way --ours' '
+	test_apply_with_3way_favoritism --ours -Xours
+'
+
+test_expect_success 'apply with --3way --theirs' '
+	test_apply_with_3way_favoritism --theirs -Xtheirs
+'
+
+test_expect_success 'apply with --3way --union' '
+	echo "* merge=union" >.gitattributes &&
+	test_apply_with_3way_favoritism --union &&
+	rm .gitattributes
+'
+
 test_expect_success 'apply with --3way with rerere enabled' '
 	test_config rerere.enabled true &&
 
diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh
index 485c7d2..cdffee0 100755
--- a/t/t4124-apply-ws-rule.sh
+++ b/t/t4124-apply-ws-rule.sh
@@ -2,6 +2,7 @@
 
 test_description='core.whitespace rules and git apply'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 prepare_test_file () {
diff --git a/t/t4125-apply-ws-fuzz.sh b/t/t4125-apply-ws-fuzz.sh
index 090987c..f248cc2 100755
--- a/t/t4125-apply-ws-fuzz.sh
+++ b/t/t4125-apply-ws-fuzz.sh
@@ -2,6 +2,7 @@
 
 test_description='applying patch that has broken whitespaces in context'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t4138-apply-ws-expansion.sh b/t/t4138-apply-ws-expansion.sh
index 8bbf826..7981931 100755
--- a/t/t4138-apply-ws-expansion.sh
+++ b/t/t4138-apply-ws-expansion.sh
@@ -5,6 +5,7 @@
 
 test_description='git apply test patches with whitespace expansion.'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 5e2b6c8..232e139 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup: messages' '
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index b0a3e84..213b36f 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -25,6 +25,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index f698d0c..c20c885 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -9,6 +9,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 79e5f42..2265ff8 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -72,12 +72,46 @@
 	test_cmp expect actual
 '
 
-test_expect_success 'check-mailmap bogus contact' '
-	test_must_fail git check-mailmap bogus
+test_expect_success 'check-mailmap simple address: mapping' '
+	test_when_finished "rm .mailmap" &&
+	cat >.mailmap <<-EOF &&
+	New Name <$GIT_AUTHOR_EMAIL>
+	EOF
+	cat .mailmap >expect &&
+	git check-mailmap "$GIT_AUTHOR_EMAIL" >actual &&
+	test_cmp expect actual
 '
 
-test_expect_success 'check-mailmap bogus contact --stdin' '
-	test_must_fail git check-mailmap --stdin bogus </dev/null
+test_expect_success 'check-mailmap --stdin simple address: mapping' '
+	test_when_finished "rm .mailmap" &&
+	cat >.mailmap <<-EOF &&
+	New Name <$GIT_AUTHOR_EMAIL>
+	EOF
+	cat >stdin <<-EOF &&
+	$GIT_AUTHOR_EMAIL
+	EOF
+	cat .mailmap >expect &&
+	git check-mailmap --stdin <stdin >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'check-mailmap simple address: no mapping' '
+	cat >expect <<-EOF &&
+	<bugs@company.xx>
+	EOF
+	git check-mailmap "bugs@company.xx" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'check-mailmap --stdin simple address: no mapping' '
+	cat >expect <<-EOF &&
+	<bugs@company.xx>
+	EOF
+	cat >stdin <<-EOF &&
+	bugs@company.xx
+	EOF
+	git check-mailmap --stdin <stdin >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'No mailmap' '
diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh
index 605faea..8e0f283 100755
--- a/t/t4204-patch-id.sh
+++ b/t/t4204-patch-id.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 158b49d..eb63ce0 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -5,6 +5,8 @@
 #
 
 test_description='Test pretty formats'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Tested non-UTF-8 encoding
diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh
index 64e1623..b42fdc5 100755
--- a/t/t4209-log-pickaxe.sh
+++ b/t/t4209-log-pickaxe.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='log --grep/--author/--regexp-ignore-case/-S/-G'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_log () {
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index 02d76dc..950451c 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -337,4 +337,32 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'show line-log with graph' '
+	qz_to_tab_space >expect <<-EOF &&
+	* $head_oid Modify func2() in file.c
+	|Z
+	| diff --git a/file.c b/file.c
+	| --- a/file.c
+	| +++ b/file.c
+	| @@ -6,4 +6,4 @@
+	|  int func2()
+	|  {
+	| -    return F2;
+	| +    return F2 + 2;
+	|  }
+	* $root_oid Add func1() and func2() in file.c
+	ZZ
+	  diff --git a/file.c b/file.c
+	  --- /dev/null
+	  +++ b/file.c
+	  @@ -0,0 +6,4 @@
+	  +int func2()
+	  +{
+	  +    return F2;
+	  +}
+	EOF
+	git log --graph --oneline -L:func2:file.c >actual &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
index eea1990..37f1cd7 100755
--- a/t/t4301-merge-tree-write-tree.sh
+++ b/t/t4301-merge-tree-write-tree.sh
@@ -2,6 +2,7 @@
 
 test_description='git merge-tree --write-tree'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # This test is ort-specific
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 72b8d0f..b9fda97 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -25,6 +25,7 @@
 '
 
 TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 SUBSTFORMAT=%H%n
@@ -136,6 +137,8 @@
 
 test_expect_success 'populate workdir' '
 	mkdir a &&
+	echo "a files_named_a" >.gitattributes &&
+	git add .gitattributes &&
 	echo simple textfile >a/a &&
 	ten=0123456789 &&
 	hundred="$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten" &&
@@ -449,6 +452,16 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'attr pathspec in bare repo' '
+	test_expect_code 0 git --git-dir=bare.git archive -v HEAD \
+		":(attr:files_named_a)" >/dev/null 2>actual &&
+	cat >expect <<-\EOF &&
+	a/
+	a/a
+	EOF
+	test_cmp expect actual
+'
+
 # Pull the size and date of each entry in a tarfile using the system tar.
 #
 # We'll pull out only the year from the date; that avoids any question of
diff --git a/t/t5003-archive-zip.sh b/t/t5003-archive-zip.sh
index 961c6aa..01f591c 100755
--- a/t/t5003-archive-zip.sh
+++ b/t/t5003-archive-zip.sh
@@ -3,6 +3,7 @@
 test_description='git archive --format=zip test'
 
 TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 SUBSTFORMAT=%H%n
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index c8d0655..065156c 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -5,6 +5,7 @@
 
 test_description='git mailinfo and git mailsplit test'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 DATA="$TEST_DIRECTORY/t5100"
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
index 61469ef..e6a43ec 100755
--- a/t/t5303-pack-corruption-resilience.sh
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -44,9 +44,14 @@
 }
 
 do_repack() {
+    for f in $pack.*
+    do
+	    mv $f "$(echo $f | sed -e 's/pack-/pack-corrupt-/')" || return 1
+    done &&
     pack=$(printf "$blob_1\n$blob_2\n$blob_3\n" |
           git pack-objects $@ .git/objects/pack/pack) &&
-    pack=".git/objects/pack/pack-${pack}"
+    pack=".git/objects/pack/pack-${pack}" &&
+    rm -f .git/objects/pack/pack-corrupt-*
 }
 
 do_corrupt_object() {
diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh
index 1f1f664..e641df0 100755
--- a/t/t5304-prune.sh
+++ b/t/t5304-prune.sh
@@ -7,6 +7,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 day=$((60*60*24))
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index d7fd713..7044c7d 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -2,13 +2,10 @@
 
 test_description='exercise basic bitmap functionality'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-bitmap.sh
 
-# t5310 deals only with single-pack bitmaps, so don't write MIDX bitmaps in
-# their place.
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
-
 # Likewise, allow individual tests to control whether or not they use
 # the boundary-based traversal.
 sane_unset GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL
diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh
index ceaa670..86fc73f 100755
--- a/t/t5313-pack-bounds-checks.sh
+++ b/t/t5313-pack-bounds-checks.sh
@@ -7,11 +7,11 @@
 
 clear_base () {
 	test_when_finished 'restore_base' &&
-	rm -f $base
+	rm -r -f $base
 }
 
 restore_base () {
-	cp base-backup/* .git/objects/pack/
+	cp -r base-backup/* .git/objects/pack/
 }
 
 do_pack () {
@@ -64,9 +64,9 @@
 	git commit -m base &&
 	git repack -ad &&
 	base=$(echo .git/objects/pack/*) &&
-	chmod +w $base &&
+	chmod -R +w $base &&
 	mkdir base-backup &&
-	cp $base base-backup/ &&
+	cp -r $base base-backup/ &&
 	object=$(git rev-parse HEAD:file)
 '
 
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index a2b4442..2916c07 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='commit graph'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-chunk.sh
 
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index ace5ac3..fbbc218 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -1,10 +1,15 @@
 #!/bin/sh
 
 test_description='multi-pack-indexes'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-chunk.sh
+. "$TEST_DIRECTORY"/lib-midx.sh
 
 GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
 objdir=.git/objects
 
 HASH_LEN=$(test_oid rawsz)
@@ -107,30 +112,6 @@
 	midx_read_expect 1 18 4 $objdir
 '
 
-midx_git_two_modes () {
-	git -c core.multiPackIndex=false $1 >expect &&
-	git -c core.multiPackIndex=true $1 >actual &&
-	if [ "$2" = "sorted" ]
-	then
-		sort <expect >expect.sorted &&
-		mv expect.sorted expect &&
-		sort <actual >actual.sorted &&
-		mv actual.sorted actual
-	fi &&
-	test_cmp expect actual
-}
-
-compare_results_with_midx () {
-	MSG=$1
-	test_expect_success "check normal git operations: $MSG" '
-		midx_git_two_modes "rev-list --objects --all" &&
-		midx_git_two_modes "log --raw" &&
-		midx_git_two_modes "count-objects --verbose" &&
-		midx_git_two_modes "cat-file --batch-all-objects --batch-check" &&
-		midx_git_two_modes "cat-file --batch-all-objects --batch-check --unordered" sorted
-	'
-}
-
 test_expect_success 'write midx with one v2 pack' '
 	git pack-objects --index-version=2,0x40 $objdir/pack/test <obj-list &&
 	git multi-pack-index --object-dir=$objdir write &&
@@ -600,8 +581,7 @@
 compare_results_with_midx "after repack"
 
 test_expect_success 'multi-pack-index and pack-bitmap' '
-	GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
-		git -c repack.writeBitmaps=true repack -ad &&
+	git -c repack.writeBitmaps=true repack -ad &&
 	git multi-pack-index write &&
 	git rev-list --test-bitmap HEAD
 '
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 916da38..6eaa692 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -1,13 +1,15 @@
 #!/bin/sh
 
 test_description='exercise basic multi-pack bitmap functionality'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "${TEST_DIRECTORY}/lib-bitmap.sh"
 
-# We'll be writing our own midx and bitmaps, so avoid getting confused by the
+# We'll be writing our own MIDX, so avoid getting confused by the
 # automatic ones.
 GIT_TEST_MULTI_PACK_INDEX=0
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
 
 # This test exercise multi-pack bitmap functionality where the object order is
 # stored and read from a special chunk within the MIDX, so use the default
diff --git a/t/t5327-multi-pack-bitmaps-rev.sh b/t/t5327-multi-pack-bitmaps-rev.sh
index e65e311..9cac03a 100755
--- a/t/t5327-multi-pack-bitmaps-rev.sh
+++ b/t/t5327-multi-pack-bitmaps-rev.sh
@@ -5,10 +5,10 @@
 . ./test-lib.sh
 . "${TEST_DIRECTORY}/lib-bitmap.sh"
 
-# We'll be writing our own midx and bitmaps, so avoid getting confused by the
-# automatic ones.
+# We'll be writing our own MIDX, so avoid getting confused by the automatic
+# ones.
 GIT_TEST_MULTI_PACK_INDEX=0
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
 
 # Unlike t5326, this test exercise multi-pack bitmap functionality where the
 # object order is stored in a separate .rev file.
diff --git a/t/t5329-pack-objects-cruft.sh b/t/t5329-pack-objects-cruft.sh
index fc5fedb..445739d 100755
--- a/t/t5329-pack-objects-cruft.sh
+++ b/t/t5329-pack-objects-cruft.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='cruft pack related pack-objects tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 objdir=.git/objects
diff --git a/t/t5332-multi-pack-reuse.sh b/t/t5332-multi-pack-reuse.sh
index ed823f3..955ea42 100755
--- a/t/t5332-multi-pack-reuse.sh
+++ b/t/t5332-multi-pack-reuse.sh
@@ -6,6 +6,8 @@
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-bitmap.sh
 
+GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
 objdir=.git/objects
 packdir=$objdir/pack
 
@@ -29,20 +31,24 @@
 	: >trace2.txt &&
 	GIT_TRACE2_EVENT="$PWD/trace2.txt" \
 		git pack-objects --stdout --revs --all --delta-base-offset \
-		>/dev/null &&
+		>got.pack &&
 
 	test_pack_reused "$1" <trace2.txt &&
-	test_packs_reused "$2" <trace2.txt
+	test_packs_reused "$2" <trace2.txt &&
+
+	git index-pack --strict -o got.idx got.pack
 }
 
 # test_pack_objects_reused <pack-reused> <packs-reused>
 test_pack_objects_reused () {
 	: >trace2.txt &&
 	GIT_TRACE2_EVENT="$PWD/trace2.txt" \
-		git pack-objects --stdout --revs >/dev/null &&
+		git pack-objects --stdout --revs >got.pack &&
 
 	test_pack_reused "$1" <trace2.txt &&
-	test_packs_reused "$2" <trace2.txt
+	test_packs_reused "$2" <trace2.txt &&
+
+	git index-pack --strict -o got.idx got.pack
 }
 
 test_expect_success 'preferred pack is reused for single-pack reuse' '
@@ -230,4 +236,27 @@
 	test_pack_objects_reused_all $(wc -l <expect) 1
 '
 
+test_expect_success 'duplicate objects' '
+	git init duplicate-objects &&
+	(
+		cd duplicate-objects &&
+
+		git config pack.allowPackReuse multi &&
+
+		test_commit base &&
+
+		git repack -a &&
+
+		git rev-parse HEAD^{tree} >in &&
+		p="$(git pack-objects $packdir/pack <in)" &&
+
+		git multi-pack-index write --bitmap --preferred-pack=pack-$p.idx &&
+
+		objects_nr="$(git rev-list --count --all --objects)" &&
+		packs_nr="$(find $packdir -type f -name "pack-*.pack" | wc -l)" &&
+
+		test_pack_objects_reused_all $objects_nr $packs_nr
+	)
+'
+
 test_done
diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh
index f052f39..1dd6284 100755
--- a/t/t5333-pseudo-merge-bitmaps.sh
+++ b/t/t5333-pseudo-merge-bitmaps.sh
@@ -390,4 +390,60 @@
 	)
 '
 
+test_expect_success 'empty pseudo-merge group' '
+	git init pseudo-merge-empty-group &&
+	(
+		cd pseudo-merge-empty-group &&
+
+		# Ensure that a pseudo-merge group with no unstable
+		# commits does not generate an empty pseudo-merge
+		# bitmap.
+		git config bitmapPseudoMerge.empty.pattern refs/ &&
+
+		test_commit base &&
+		git repack -adb &&
+
+		test-tool bitmap dump-pseudo-merges >merges &&
+		test_line_count = 1 merges &&
+
+		test 0 -eq "$(grep -c commits=0 <merges)"
+	)
+'
+
+test_expect_success 'pseudo-merge closure' '
+	git init pseudo-merge-closure &&
+	(
+		cd pseudo-merge-closure &&
+
+		test_commit A &&
+		git repack -d &&
+
+		test_commit B &&
+
+		# Note that the contents of A is packed, but B is not. A
+		# (and the objects reachable from it) are thus visible
+		# to the MIDX, but the same is not true for B and its
+		# objects.
+		#
+		# Ensure that we do not attempt to create a pseudo-merge
+		# for B, depsite it matching the below pseudo-merge
+		# group pattern, as doing so would result in a failure
+		# to write a non-closed bitmap.
+		git config bitmapPseudoMerge.test.pattern refs/ &&
+		git config bitmapPseudoMerge.test.threshold now &&
+
+		git multi-pack-index write --bitmap &&
+
+		test-tool bitmap dump-pseudo-merges >pseudo-merges &&
+		test_line_count = 1 pseudo-merges &&
+
+		git rev-parse A >expect &&
+
+		test-tool bitmap list-commits >actual &&
+		test_cmp expect actual &&
+		test-tool bitmap dump-pseudo-merge-commits 0 >actual &&
+		test_cmp expect actual
+	)
+'
+
 test_done
diff --git a/t/t5334-incremental-multi-pack-index.sh b/t/t5334-incremental-multi-pack-index.sh
new file mode 100755
index 0000000..c3b08ac
--- /dev/null
+++ b/t/t5334-incremental-multi-pack-index.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+test_description='incremental multi-pack-index'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-midx.sh
+
+GIT_TEST_MULTI_PACK_INDEX=0
+export GIT_TEST_MULTI_PACK_INDEX
+
+objdir=.git/objects
+packdir=$objdir/pack
+midxdir=$packdir/multi-pack-index.d
+midx_chain=$midxdir/multi-pack-index-chain
+
+test_expect_success 'convert non-incremental MIDX to incremental' '
+	test_commit base &&
+	git repack -ad &&
+	git multi-pack-index write &&
+
+	test_path_is_file $packdir/multi-pack-index &&
+	old_hash="$(midx_checksum $objdir)" &&
+
+	test_commit other &&
+	git repack -d &&
+	git multi-pack-index write --incremental &&
+
+	test_path_is_missing $packdir/multi-pack-index &&
+	test_path_is_file $midx_chain &&
+	test_line_count = 2 $midx_chain &&
+	grep $old_hash $midx_chain
+'
+
+compare_results_with_midx 'incremental MIDX'
+
+test_expect_success 'convert incremental to non-incremental' '
+	test_commit squash &&
+	git repack -d &&
+	git multi-pack-index write &&
+
+	test_path_is_file $packdir/multi-pack-index &&
+	test_dir_is_empty $midxdir
+'
+
+compare_results_with_midx 'non-incremental MIDX conversion'
+
+test_done
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 3f81f16..248c74d 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -9,6 +9,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 cnt=64
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
index d8cadee..3c1ea60 100755
--- a/t/t5401-update-hooks.sh
+++ b/t/t5401-update-hooks.sh
@@ -4,6 +4,8 @@
 #
 
 test_description='Test the update hook infrastructure.'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t5408-send-pack-stdin.sh b/t/t5408-send-pack-stdin.sh
index e8737df..c3695a4 100755
--- a/t/t5408-send-pack-stdin.sh
+++ b/t/t5408-send-pack-stdin.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='send-pack --stdin tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 create_ref () {
diff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh
index fa5de45..516b22f 100755
--- a/t/t5409-colorize-remote-messages.sh
+++ b/t/t5409-colorize-remote-messages.sh
@@ -2,6 +2,7 @@
 
 test_description='remote messages are colorized on the client'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 585ea0e..605f172 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Test fetch-pack/upload-pack pair.
diff --git a/t/t5501-fetch-push-alternates.sh b/t/t5501-fetch-push-alternates.sh
index 66f19a4..0c8668a 100755
--- a/t/t5501-fetch-push-alternates.sh
+++ b/t/t5501-fetch-push-alternates.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 count_objects () {
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 08424e8..5320359 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -2,6 +2,7 @@
 
 test_description='git remote porcelain-ish'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 setup_repository () {
diff --git a/t/t5509-fetch-push-namespaces.sh b/t/t5509-fetch-push-namespaces.sh
index 31553b4..f029ae0 100755
--- a/t/t5509-fetch-push-namespaces.sh
+++ b/t/t5509-fetch-push-namespaces.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
@@ -95,6 +96,7 @@
 '
 
 test_expect_success 'check that transfer.hideRefs does not match unstripped refs' '
+	git -C pushee pack-refs --all &&
 	GIT_NAMESPACE=namespace \
 		git -C pushee -c transfer.hideRefs=refs/namespaces/namespace/refs/tags \
 		ls-remote "ext::git %s ." >actual &&
@@ -122,6 +124,14 @@
 	git -C original push pushee-namespaced main
 '
 
+test_expect_success 'git-receive-pack(1) with transfer.hideRefs does not match unstripped refs during advertisement' '
+	git -C pushee update-ref refs/namespaces/namespace/refs/heads/foo/1 refs/namespaces/namespace/refs/heads/main &&
+	git -C pushee pack-refs --all &&
+	test_config -C pushee transfer.hideRefs refs/namespaces/namespace/refs/heads/foo &&
+	GIT_TRACE_PACKET="$(pwd)/trace" git -C original push pushee-namespaced main &&
+	test_grep refs/heads/foo/1 trace
+'
+
 test_expect_success 'try to update a hidden full ref' '
 	test_config -C pushee transfer.hideRefs "^refs/namespaces/namespace/refs/heads/main" &&
 	test_must_fail git -C original push pushee-namespaced main
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 3b3991a..0890b9f 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -5,6 +5,7 @@
 
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-bundle.sh
 
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index bc442ec..64b3491 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 generate_references () {
@@ -405,6 +406,7 @@
 test_expect_success 'helper with refspec capability fails gracefully' '
 	mkdir test-bin &&
 	write_script test-bin/git-remote-foo <<-EOF &&
+	read capabilities
 	echo import
 	echo refspec ${SQ}*:*${SQ}
 	EOF
diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh
index 25772c8..579872c 100755
--- a/t/t5514-fetch-multiple.sh
+++ b/t/t5514-fetch-multiple.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 setup_repository () {
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 9d693eb..331778b 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -19,6 +19,7 @@
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 D=$(pwd)
diff --git a/t/t5519-push-alternates.sh b/t/t5519-push-alternates.sh
index 20ba604..72e97b1 100755
--- a/t/t5519-push-alternates.sh
+++ b/t/t5519-push-alternates.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index 47534f1..1098cbd 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 modify () {
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index 5e56620..2cfb5bd 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -6,6 +6,7 @@
 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
 export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 pwd=$(pwd)
diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh
index 14f7ece..bc2bada 100755
--- a/t/t5528-push-default.sh
+++ b/t/t5528-push-default.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup bare remotes' '
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
index f3fff55..1358236 100755
--- a/t/t5531-deep-submodule-push.sh
+++ b/t/t5531-deep-submodule-push.sh
@@ -8,6 +8,7 @@
 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
 export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t5533-push-cas.sh b/t/t5533-push-cas.sh
index cba26a8..6365d99 100755
--- a/t/t5533-push-cas.sh
+++ b/t/t5533-push-cas.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 setup_srcdst_basic () {
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index c91a62b..d43aee0 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-gpg.sh
 
diff --git a/t/t5535-fetch-push-symref.sh b/t/t5535-fetch-push-symref.sh
index e8f6d23..7122af7 100755
--- a/t/t5535-fetch-push-symref.sh
+++ b/t/t5535-fetch-push-symref.sh
@@ -2,6 +2,7 @@
 
 test_description='avoiding conflicting update through symref aliasing'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t5536-fetch-conflicts.sh b/t/t5536-fetch-conflicts.sh
index 23bf696..2dcbe79 100755
--- a/t/t5536-fetch-conflicts.sh
+++ b/t/t5536-fetch-conflicts.sh
@@ -2,6 +2,7 @@
 
 test_description='fetch handles conflicting refspecs correctly'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 D=$(pwd)
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 37f7547..cae4d40 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 commit() {
diff --git a/t/t5538-push-shallow.sh b/t/t5538-push-shallow.sh
index e91fcc1..6adc3a2 100755
--- a/t/t5538-push-shallow.sh
+++ b/t/t5538-push-shallow.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 commit() {
diff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh
index 3ea75d3..82fe09d 100755
--- a/t/t5539-fetch-http-shallow.sh
+++ b/t/t5539-fetch-http-shallow.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
diff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh
index 37db3de..27389b0 100755
--- a/t/t5540-http-push-webdav.sh
+++ b/t/t5540-http-push-webdav.sh
@@ -10,6 +10,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 if git http-push > /dev/null 2>&1 || [ $? -eq 128 ]
diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
index 538b603..d65829c 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -7,6 +7,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 ROOT_PATH="$PWD"
diff --git a/t/t5542-push-http-shallow.sh b/t/t5542-push-http-shallow.sh
index c2cc831..07624a1 100755
--- a/t/t5542-push-http-shallow.sh
+++ b/t/t5542-push-http-shallow.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh
index 04b47ad..479d103 100755
--- a/t/t5543-atomic-push.sh
+++ b/t/t5543-atomic-push.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 mk_repo_pair () {
diff --git a/t/t5548-push-porcelain.sh b/t/t5548-push-porcelain.sh
index 6282728..ecb3877 100755
--- a/t/t5548-push-porcelain.sh
+++ b/t/t5548-push-porcelain.sh
@@ -4,6 +4,7 @@
 #
 test_description='Test git push porcelain output'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Create commits in <repo> and assign each commit's oid to shell variables
diff --git a/t/t5549-fetch-push-http.sh b/t/t5549-fetch-push-http.sh
index 2cdebcb..6377fb6 100755
--- a/t/t5549-fetch-push-http.sh
+++ b/t/t5549-fetch-push-http.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh
index 8fc346a..e2ce70e 100755
--- a/t/t5550-http-fetch-dumb.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 if test_have_prereq !REFFILES
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index af1ff43..3bb8f28 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-httpd.sh
 test "$HTTP_PROTO" = "HTTP/2" && enable_http2
@@ -186,6 +187,28 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'credential.interactive=false skips askpass' '
+	set_askpass bogus nonsense &&
+	(
+		GIT_TRACE2_EVENT="$(pwd)/interactive-true" &&
+		export GIT_TRACE2_EVENT &&
+		test_must_fail git clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-true-dir &&
+		test_region credential interactive interactive-true &&
+
+		GIT_TRACE2_EVENT="$(pwd)/interactive-false" &&
+		export GIT_TRACE2_EVENT &&
+		test_must_fail git -c credential.interactive=false \
+			clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-false-dir &&
+		test_region ! credential interactive interactive-false &&
+
+		GIT_TRACE2_EVENT="$(pwd)/interactive-never" &&
+		export GIT_TRACE2_EVENT &&
+		test_must_fail git -c credential.interactive=never \
+			clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-never-dir &&
+		test_region ! credential interactive interactive-never
+	)
+'
+
 test_expect_success 'clone from auth-only-for-push repository' '
 	echo two >expect &&
 	set_askpass wrong &&
diff --git a/t/t5552-skipping-fetch-negotiator.sh b/t/t5552-skipping-fetch-negotiator.sh
index b55a9f6..4f2e5ae 100755
--- a/t/t5552-skipping-fetch-negotiator.sh
+++ b/t/t5552-skipping-fetch-negotiator.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test skipping fetch negotiator'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'fetch.negotiationalgorithm config' '
diff --git a/t/t5553-set-upstream.sh b/t/t5553-set-upstream.sh
index 70e3376..33e919a 100755
--- a/t/t5553-set-upstream.sh
+++ b/t/t5553-set-upstream.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check_config () {
diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh
index bb35b87..4aef99b 100755
--- a/t/t5564-http-proxy.sh
+++ b/t/t5564-http-proxy.sh
@@ -39,4 +39,59 @@
 	expect_askpass pass proxuser
 '
 
+start_socks() {
+	mkfifo socks_output &&
+	{
+		"$PERL_PATH" "$TEST_DIRECTORY/socks4-proxy.pl" "$1" >socks_output &
+		echo $! > "$TRASH_DIRECTORY/socks.pid"
+	} &&
+	read line <socks_output &&
+	test "$line" = ready
+}
+
+# The %30 tests that the correct amount of percent-encoding is applied to the
+# proxy string passed to curl.
+test_lazy_prereq SOCKS_PROXY '
+	test_have_prereq PERL &&
+	start_socks "$TRASH_DIRECTORY/%30.sock"
+'
+
+test_atexit '
+	test ! -e "$TRASH_DIRECTORY/socks.pid" ||
+	kill "$(cat "$TRASH_DIRECTORY/socks.pid")"
+'
+
+# The below tests morally ought to be gated on a prerequisite that Git is
+# linked with a libcurl that supports Unix socket paths for proxies (7.84 or
+# later), but this is not easy to test right now. Instead, we || the tests with
+# this function.
+old_libcurl_error() {
+	grep -Fx "fatal: libcurl 7.84 or later is required to support paths in proxy URLs" "$1"
+}
+
+test_expect_success SOCKS_PROXY 'clone via Unix socket' '
+	test_when_finished "rm -rf clone" &&
+	test_config_global http.proxy "socks4://localhost$PWD/%2530.sock" && {
+		{
+			GIT_TRACE_CURL=$PWD/trace git clone "$HTTPD_URL/smart/repo.git" clone 2>err &&
+			grep -i "SOCKS4 request granted" trace
+		} ||
+		old_libcurl_error err
+	}
+'
+
+test_expect_success 'Unix socket requires socks*:' - <<\EOT
+	! git clone -c http.proxy=localhost/path https://example.com/repo.git 2>err && {
+		grep -Fx "fatal: Invalid proxy URL 'localhost/path': only SOCKS proxies support paths" err ||
+		old_libcurl_error err
+	}
+EOT
+
+test_expect_success 'Unix socket requires localhost' - <<\EOT
+	! git clone -c http.proxy=socks4://127.0.0.1/path https://example.com/repo.git 2>err && {
+		grep -Fx "fatal: Invalid proxy URL 'socks4://127.0.0.1/path': host must be localhost if a path is present" err ||
+		old_libcurl_error err
+	}
+EOT
+
 test_done
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
index f9a9bf9..c5f08b6 100755
--- a/t/t5570-git-daemon.sh
+++ b/t/t5570-git-daemon.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 . "$TEST_DIRECTORY"/lib-git-daemon.sh
diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh
index 5174452..9b6cf8d 100755
--- a/t/t5572-pull-submodule.sh
+++ b/t/t5572-pull-submodule.sh
@@ -5,6 +5,7 @@
 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
 export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-submodule-update.sh
 
@@ -229,6 +230,7 @@
 
 	test_create_repo a-submodule &&
 	test_commit -C a-submodule foo &&
+	test_commit -C a-submodule bar &&
 
 	test_create_repo parent &&
 	git -C parent submodule add "$(pwd)/a-submodule" &&
@@ -245,4 +247,23 @@
 	git -C child pull --recurse-submodules --rebase
 '
 
+test_expect_success 'fetch submodule remote of different name from superproject' '
+	git -C child remote rename origin o1 &&
+	git -C child submodule update --init &&
+
+	# Needs to create unreachable commit from current master branch.
+	git -C a-submodule checkout -b newmain HEAD^ &&
+	test_commit -C a-submodule echo &&
+	test_commit -C a-submodule moreecho &&
+	subc=$(git -C a-submodule rev-parse --short HEAD) &&
+
+	git -C parent/a-submodule fetch &&
+	git -C parent/a-submodule checkout "$subc" &&
+	git -C parent commit -m "update submodule" a-submodule &&
+	git -C a-submodule reset --hard HEAD^^ &&
+
+	git -C child pull --no-recurse-submodules &&
+	git -C child submodule update
+'
+
 test_done
diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh
index 5883839..f770732 100755
--- a/t/t5574-fetch-output.sh
+++ b/t/t5574-fetch-output.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'fetch with invalid output format configuration' '
diff --git a/t/t5582-fetch-negative-refspec.sh b/t/t5582-fetch-negative-refspec.sh
index 7a80e47..7fa54a4 100755
--- a/t/t5582-fetch-negative-refspec.sh
+++ b/t/t5582-fetch-negative-refspec.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 2da7291..c53e93b 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # create a normal "src" repo where we can later create new commits.
@@ -229,7 +230,7 @@
 
 	GIT_TRACE2_EVENT="$PWD/trace1.event" \
 	git -C pc1 fetch --refetch origin &&
-	test_subcommand git maintenance run --auto --no-quiet <trace1.event &&
+	test_subcommand git maintenance run --auto --no-quiet --detach <trace1.event &&
 	grep \"param\":\"gc.autopacklimit\",\"value\":\"1\" trace1.event &&
 	grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"-1\" trace1.event &&
 
@@ -238,7 +239,7 @@
 		-c gc.autoPackLimit=0 \
 		-c maintenance.incremental-repack.auto=1234 \
 		-C pc1 fetch --refetch origin &&
-	test_subcommand git maintenance run --auto --no-quiet <trace2.event &&
+	test_subcommand git maintenance run --auto --no-quiet --detach <trace2.event &&
 	grep \"param\":\"gc.autopacklimit\",\"value\":\"0\" trace2.event &&
 	grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"-1\" trace2.event &&
 
@@ -247,7 +248,7 @@
 		-c gc.autoPackLimit=1234 \
 		-c maintenance.incremental-repack.auto=0 \
 		-C pc1 fetch --refetch origin &&
-	test_subcommand git maintenance run --auto --no-quiet <trace3.event &&
+	test_subcommand git maintenance run --auto --no-quiet --detach <trace3.event &&
 	grep \"param\":\"gc.autopacklimit\",\"value\":\"1\" trace3.event &&
 	grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"0\" trace3.event
 '
diff --git a/t/t5619-clone-local-ambiguous-transport.sh b/t/t5619-clone-local-ambiguous-transport.sh
index cce62bf..1d4efe4 100755
--- a/t/t5619-clone-local-ambiguous-transport.sh
+++ b/t/t5619-clone-local-ambiguous-transport.sh
@@ -2,6 +2,7 @@
 
 test_description='test local clone with ambiguous transport'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-httpd.sh"
 
diff --git a/t/t5700-protocol-v1.sh b/t/t5700-protocol-v1.sh
index a73b4d4..985e04d 100755
--- a/t/t5700-protocol-v1.sh
+++ b/t/t5700-protocol-v1.sh
@@ -11,6 +11,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Test protocol v1 with 'git://' transport
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index 1910971..f75fae5 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -2,6 +2,7 @@
 
 test_description='upload-pack ref-in-want'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 get_actual_refs () {
diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh
index 20f43f7..d218771 100755
--- a/t/t5801-remote-helpers.sh
+++ b/t/t5801-remote-helpers.sh
@@ -344,4 +344,15 @@
 	compare_refs local v1.0 server v1.0
 '
 
+test_expect_success 'totally broken helper reports failure message' '
+	write_script git-remote-broken <<-\EOF &&
+	read cap_cmd
+	exit 1
+	EOF
+	test_must_fail \
+		env PATH="$PWD:$PATH" \
+		git clone broken://example.com/foo.git 2>stderr &&
+	grep aborted stderr
+'
+
 test_done
diff --git a/t/t5802-connect-helper.sh b/t/t5802-connect-helper.sh
index c6c2661..dd3e623 100755
--- a/t/t5802-connect-helper.sh
+++ b/t/t5802-connect-helper.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='ext::cmd remote "connect" helper'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t5812-proto-disable-http.sh b/t/t5812-proto-disable-http.sh
index 769c717..f69959c 100755
--- a/t/t5812-proto-disable-http.sh
+++ b/t/t5812-proto-disable-http.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test disabling of git-over-http in clone/fetch'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-proto-disable.sh"
 . "$TEST_DIRECTORY/lib-httpd.sh"
diff --git a/t/t5814-proto-disable-ext.sh b/t/t5814-proto-disable-ext.sh
index 9d6f7df..6fe1a98 100755
--- a/t/t5814-proto-disable-ext.sh
+++ b/t/t5814-proto-disable-ext.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test disabling of remote-helper paths in clone/fetch'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-proto-disable.sh"
 
diff --git a/t/t5815-submodule-protos.sh b/t/t5815-submodule-protos.sh
index 4d5956c..fe899ee 100755
--- a/t/t5815-submodule-protos.sh
+++ b/t/t5815-submodule-protos.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test protocol filtering with submodules'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-proto-disable.sh
 
diff --git a/t/t6004-rev-list-path-optim.sh b/t/t6004-rev-list-path-optim.sh
index cd4f420..5416241 100755
--- a/t/t6004-rev-list-path-optim.sh
+++ b/t/t6004-rev-list-path-optim.sh
@@ -16,6 +16,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index 6f3e543..2d337d7 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # A---B---D---F
diff --git a/t/t6010-merge-base.sh b/t/t6010-merge-base.sh
index 44c726e..f96ea82 100755
--- a/t/t6010-merge-base.sh
+++ b/t/t6010-merge-base.sh
@@ -6,6 +6,7 @@
 test_description='Merge base and parent list computation.
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 M=1130000000
diff --git a/t/t6019-rev-list-ancestry-path.sh b/t/t6019-rev-list-ancestry-path.sh
index 738da23..1aabab6 100755
--- a/t/t6019-rev-list-ancestry-path.sh
+++ b/t/t6019-rev-list-ancestry-path.sh
@@ -29,6 +29,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_merge () {
diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh
index c6e9b33..d7702fc 100755
--- a/t/t6050-replace.sh
+++ b/t/t6050-replace.sh
@@ -7,6 +7,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-gpg.sh"
 
diff --git a/t/t6111-rev-list-treesame.sh b/t/t6111-rev-list-treesame.sh
index 90ff141..f63bc8d 100755
--- a/t/t6111-rev-list-treesame.sh
+++ b/t/t6111-rev-list-treesame.sh
@@ -16,6 +16,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 note () {
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 79e0f19..05ed251 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -14,6 +14,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check_describe () {
diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh
index 9fdafeb..f31c09c 100755
--- a/t/t6132-pathspec-exclude.sh
+++ b/t/t6132-pathspec-exclude.sh
@@ -2,6 +2,7 @@
 
 test_description='test case exclude pathspec'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t6133-pathspec-rev-dwim.sh b/t/t6133-pathspec-rev-dwim.sh
index a290ffc..6dd4bbb 100755
--- a/t/t6133-pathspec-rev-dwim.sh
+++ b/t/t6133-pathspec-rev-dwim.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test dwim of revs versus pathspecs in revision parser'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t6135-pathspec-with-attrs.sh b/t/t6135-pathspec-with-attrs.sh
index 120dcd7..794bc7d 100755
--- a/t/t6135-pathspec-with-attrs.sh
+++ b/t/t6135-pathspec-with-attrs.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test labels in pathspecs'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup a tree' '
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index 5a221f8..ac57b0e 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-gpg.sh"
 
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index eb6c820..b316362 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -5,6 +5,7 @@
 
 test_description='for-each-ref test'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY"/lib-gpg.sh
@@ -1560,6 +1561,25 @@
 	Reviewed-by,A U Thor <author@example.com>,Signed-off-by,A U Thor <author@example.com>
 	EOF
 
+test_expect_success 'multiple %(trailers) use their own options' '
+	git tag -F - tag-with-trailers <<-\EOF &&
+	body
+
+	one: foo
+	one: bar
+	two: baz
+	two: qux
+	EOF
+	t1="%(trailers:key=one,key_value_separator=W,separator=X)" &&
+	t2="%(trailers:key=two,key_value_separator=Y,separator=Z)" &&
+	git for-each-ref --format="$t1%0a$t2" refs/tags/tag-with-trailers >actual &&
+	cat >expect <<-\EOF &&
+	oneWfooXoneWbar
+	twoYbazZtwoYqux
+	EOF
+	test_cmp expect actual
+'
+
 test_failing_trailer_option () {
 	title=$1 option=$2
 	cat >expect
@@ -1835,6 +1855,24 @@
 sig_crlf=${sig_crlf%dummy}
 test_atom refs/tags/fake-sig-crlf contents:signature "$sig_crlf"
 
+test_expect_success 'set up tag with signature and trailers' '
+	git tag -F - fake-sig-trailer <<-\EOF
+	this is the subject
+
+	this is the body
+
+	My-Trailer: foo
+	-----BEGIN PGP SIGNATURE-----
+
+	not a real signature, but we just care about the
+	subject/body/trailer parsing.
+	-----END PGP SIGNATURE-----
+	EOF
+'
+
+# use "separator=" here to suppress the terminating newline
+test_atom refs/tags/fake-sig-trailer trailers:separator= 'My-Trailer: foo'
+
 test_expect_success 'git for-each-ref --stdin: empty' '
 	>in &&
 	git for-each-ref --format="%(refname)" --stdin <in >actual &&
@@ -1907,6 +1945,15 @@
 	test_cmp expect actual
 '
 
+test_expect_success 'is-base atom with non-commits' '
+	git for-each-ref --format="%(is-base:HEAD) %(refname)" >out 2>err &&
+	grep "(HEAD) refs/heads/main" out &&
+
+	test_line_count = 2 err &&
+	grep "error: object .* is a commit, not a blob" err &&
+	grep "error: bad tag pointer to" err
+'
+
 GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
 TRUSTLEVEL_FORMAT="%(signature:trustlevel)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
 
@@ -1994,8 +2041,7 @@
 		--format="$GRADE_FORMAT" >actual &&
 	test_cmp expect actual
 '
-test_expect_success GPGSSH 'show good signature with custom format
-			    with ssh' '
+test_expect_success GPGSSH 'show good signature with custom format with ssh' '
 	test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
 	FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") &&
 	cat >expect.tmpl <<-\EOF &&
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index 163c378..7f44d3c 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -2,6 +2,7 @@
 
 test_description='test for-each-refs usage of ref-filter APIs'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-gpg.sh
 
diff --git a/t/t6409-merge-subtree.sh b/t/t6409-merge-subtree.sh
index e9ba6f1..528615b 100755
--- a/t/t6409-merge-subtree.sh
+++ b/t/t6409-merge-subtree.sh
@@ -5,6 +5,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
diff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh
index b99f29e..30349a4 100755
--- a/t/t6421-merge-partial-clone.sh
+++ b/t/t6421-merge-partial-clone.sh
@@ -26,6 +26,7 @@
 #                     underscore notation is to differentiate different
 #                     files that might be renamed into each other's paths.)
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-merge.sh
 
diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh
index 88d1cf2..4aaaf38 100755
--- a/t/t6423-merge-rename-directories.sh
+++ b/t/t6423-merge-rename-directories.sh
@@ -25,6 +25,7 @@
 #                     underscore notation is to differentiate different
 #                     files that might be renamed into each other's paths.)
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-merge.sh
 
diff --git a/t/t6428-merge-conflicts-sparse.sh b/t/t6428-merge-conflicts-sparse.sh
index 9919c3f..8a79bc2 100755
--- a/t/t6428-merge-conflicts-sparse.sh
+++ b/t/t6428-merge-conflicts-sparse.sh
@@ -22,6 +22,7 @@
 #                     underscore notation is to differentiate different
 #                     files that might be renamed into each other's paths.)
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-merge.sh
 
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index 1b5909d..ee074b9 100755
--- a/t/t6500-gc.sh
+++ b/t/t6500-gc.sh
@@ -3,6 +3,7 @@
 test_description='basic git gc tests
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
@@ -338,14 +339,14 @@
 	test_subcommand $cruft_max_size_opts --max-cruft-size=3145728 <trace2.txt
 '
 
-run_and_wait_for_auto_gc () {
+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
 	# variable assignment from a command substitution preserves the
 	# exit status of the main gc process.
 	# Note: this fd trickery doesn't work on Windows, but there is no
 	# need to, because on Win the auto gc always runs in the foreground.
-	doesnt_matter=$(git gc --auto 9>&1)
+	doesnt_matter=$(git gc "$@" 9>&1)
 }
 
 test_expect_success 'background auto gc does not run if gc.log is present and recent but does if it is old' '
@@ -361,7 +362,7 @@
 	test-tool chmtime =-345600 .git/gc.log &&
 	git gc --auto &&
 	test_config gc.logexpiry 2.days &&
-	run_and_wait_for_auto_gc &&
+	run_and_wait_for_gc --auto &&
 	ls .git/objects/pack/pack-*.pack >packs &&
 	test_line_count = 1 packs
 '
@@ -391,11 +392,48 @@
 	printf "%d %s" "$shell_pid" "$hostname" >.git/gc.pid &&
 
 	# our gc should exit zero without doing anything
-	run_and_wait_for_auto_gc &&
+	run_and_wait_for_gc --auto &&
 	(ls -1 .git/refs/heads .git/reftable >actual || true) &&
 	test_cmp expect actual
 '
 
+test_expect_success '--detach overrides gc.autoDetach=false' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+
+		# Prepare the repository such that git-gc(1) ends up repacking.
+		test_commit "$(test_oid blob17_1)" &&
+		test_commit "$(test_oid blob17_2)" &&
+		git config gc.autodetach false &&
+		git config gc.auto 2 &&
+
+		# Note that we cannot use `test_cmp` here to compare stderr
+		# because it may contain output from `set -x`.
+		run_and_wait_for_gc --auto --detach 2>actual &&
+		test_grep "Auto packing the repository in background for optimum performance." actual
+	)
+'
+
+test_expect_success '--no-detach overrides gc.autoDetach=true' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+
+		# Prepare the repository such that git-gc(1) ends up repacking.
+		test_commit "$(test_oid blob17_1)" &&
+		test_commit "$(test_oid blob17_2)" &&
+		git config gc.autodetach true &&
+		git config gc.auto 2 &&
+
+		GIT_PROGRESS_DELAY=0 git gc --auto --no-detach 2>output &&
+		test_grep "Auto packing the repository for optimum performance." output &&
+		test_grep "Collecting referenced commits: 2, done." output
+	)
+'
+
 # DO NOT leave a detached auto gc process running near the end of the
 # test script: it can run long enough in the background to racily
 # interfere with the cleanup in 'test_done'.
diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh
index b330945..2591f8b 100755
--- a/t/t6600-test-reach.sh
+++ b/t/t6600-test-reach.sh
@@ -612,4 +612,125 @@
 		--format="%(refname)" --stdin
 '
 
+# For get_branch_base_for_tip, we only care about
+# first-parent history. Here is the test graph with
+# second parents removed:
+#
+#             (10,10)
+#            /
+#         (10,9)    (9,10)
+#        /         /
+#    (10,8)    (9,9)      (8,10)
+#   /         /          /
+#         ( continued...)
+#   \     /        /           /
+#    (3,1)     (2,2)      (1,3)
+#        \     /          /
+#         (2,1)      (1,2)
+#              \    /
+#              (1,1)
+#
+# In short, for a commit (i,j), the first-parent history
+# walks all commits (i, k) with k from j to 1, then the
+# commits (l, 1) with l from i to 1.
+
+test_expect_success 'get_branch_base_for_tip: none reach' '
+	# (2,3) branched from the first tip (i,4) in X with i > 2
+	cat >input <<-\EOF &&
+		A:commit-2-3
+		X:commit-1-2
+		X:commit-1-4
+		X:commit-4-4
+		X:commit-8-4
+		X:commit-10-4
+	EOF
+	echo "get_branch_base_for_tip(A,X):2" >expect &&
+	test_all_modes get_branch_base_for_tip
+'
+
+test_expect_success 'get_branch_base_for_tip: equal to tip' '
+	# (2,3) branched from the first tip (i,4) in X with i > 2
+	cat >input <<-\EOF &&
+		A:commit-8-4
+		X:commit-1-2
+		X:commit-1-4
+		X:commit-4-4
+		X:commit-8-4
+		X:commit-10-4
+	EOF
+	echo "get_branch_base_for_tip(A,X):3" >expect &&
+	test_all_modes get_branch_base_for_tip
+'
+
+test_expect_success 'get_branch_base_for_tip: all reach tip' '
+	# (2,3) branched from the first tip (i,4) in X with i > 2
+	cat >input <<-\EOF &&
+		A:commit-4-1
+		X:commit-4-2
+		X:commit-5-1
+	EOF
+	echo "get_branch_base_for_tip(A,X):0" >expect &&
+	test_all_modes get_branch_base_for_tip
+'
+
+test_expect_success 'for-each-ref is-base: none reach' '
+	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-2:(commit-2-3)
+	refs/heads/commit-4-4:
+	refs/heads/commit-8-4:
+	EOF
+	run_all_modes git for-each-ref \
+		--format="%(refname):%(is-base:commit-2-3)" --stdin
+'
+
+test_expect_success 'for-each-ref is-base: all reach' '
+	cat >input <<-\EOF &&
+	refs/heads/commit-4-2
+	refs/heads/commit-5-1
+	EOF
+	cat >expect <<-\EOF &&
+	refs/heads/commit-4-2:(commit-4-1)
+	refs/heads/commit-5-1:
+	EOF
+	run_all_modes git for-each-ref \
+		--format="%(refname):%(is-base:commit-4-1)" --stdin
+'
+
+test_expect_success 'for-each-ref is-base: equal to tip' '
+	cat >input <<-\EOF &&
+	refs/heads/commit-4-2
+	refs/heads/commit-5-1
+	EOF
+	cat >expect <<-\EOF &&
+	refs/heads/commit-4-2:(commit-4-2)
+	refs/heads/commit-5-1:
+	EOF
+	run_all_modes git for-each-ref \
+		--format="%(refname):%(is-base:commit-4-2)" --stdin
+'
+
+test_expect_success 'for-each-ref is-base:multiple' '
+	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-2[(commit-2-3)-]
+	refs/heads/commit-4-4[-]
+	refs/heads/commit-8-4[-(commit-6-5)]
+	EOF
+	run_all_modes git for-each-ref \
+		--format="%(refname)[%(is-base:commit-2-3)-%(is-base:commit-6-5)]" --stdin
+'
+
 test_done
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index fa6336e..b1316e6 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -61,8 +61,9 @@
 	)
 '
 
-test_expect_success 'looking for a tag in an empty tree should fail' \
-	'! (tag_exists mytag)'
+test_expect_success 'looking for a tag in an empty tree should fail' '
+	! (tag_exists mytag)
+'
 
 test_expect_success 'creating a tag in an empty tree should fail' '
 	test_must_fail git tag mynotag &&
@@ -129,10 +130,10 @@
 	git tag
 '
 
-cat >expect <<EOF
-mytag
-EOF
 test_expect_success 'Multiple -l or --list options are equivalent to one -l option' '
+	cat >expect <<-\EOF &&
+	mytag
+	EOF
 	git tag -l -l >actual &&
 	test_cmp expect actual &&
 	git tag --list --list >actual &&
@@ -148,32 +149,33 @@
 
 # pattern matching:
 
-test_expect_success 'listing a tag using a matching pattern should succeed' \
-	'git tag -l mytag'
+test_expect_success 'listing a tag using a matching pattern should succeed' '
+	git tag -l mytag
+'
 
-test_expect_success 'listing a tag with --ignore-case' \
-	'test $(git tag -l --ignore-case MYTAG) = mytag'
+test_expect_success 'listing a tag with --ignore-case' '
+	test $(git tag -l --ignore-case MYTAG) = mytag
+'
 
-test_expect_success \
-	'listing a tag using a matching pattern should output that tag' \
-	'test $(git tag -l mytag) = mytag'
+test_expect_success 'listing a tag using a matching pattern should output that tag' '
+	test $(git tag -l mytag) = mytag
+'
 
-test_expect_success \
-	'listing tags using a non-matching pattern should succeed' \
-	'git tag -l xxx'
+test_expect_success 'listing tags using a non-matching pattern should succeed' '
+	git tag -l xxx
+'
 
-test_expect_success \
-	'listing tags using a non-matching pattern should output nothing' \
-	'test $(git tag -l xxx | wc -l) -eq 0'
+test_expect_success 'listing tags using a non-matching pattern should output nothing' '
+	test $(git tag -l xxx | wc -l) -eq 0
+'
 
 # special cases for creating tags:
 
-test_expect_success \
-	'trying to create a tag with the name of one existing should fail' \
-	'test_must_fail git tag mytag'
+test_expect_success 'trying to create a tag with the name of one existing should fail' '
+	test_must_fail git tag mytag
+'
 
-test_expect_success \
-	'trying to create a tag with a non-valid name should fail' '
+test_expect_success 'trying to create a tag with a non-valid name should fail' '
 	test $(git tag -l | wc -l) -eq 1 &&
 	test_must_fail git tag "" &&
 	test_must_fail git tag .othertag &&
@@ -207,19 +209,19 @@
 	test_must_fail git tag -d unknown-tag
 '
 
-cat >expect <<EOF
-myhead
-mytag
-EOF
-test_expect_success \
-	'trying to delete tags without params should succeed and do nothing' '
-	git tag -l > actual && test_cmp expect actual &&
+test_expect_success 'trying to delete tags without params should succeed and do nothing' '
+	cat >expect <<-\EOF &&
+	myhead
+	mytag
+	EOF
+	git tag -l >actual &&
+	test_cmp expect actual &&
 	git tag -d &&
-	git tag -l > actual && test_cmp expect actual
+	git tag -l >actual &&
+	test_cmp expect actual
 '
 
-test_expect_success \
-	'deleting two existing tags in one command should succeed' '
+test_expect_success 'deleting two existing tags in one command should succeed' '
 	tag_exists mytag &&
 	tag_exists myhead &&
 	git tag -d mytag myhead &&
@@ -227,15 +229,13 @@
 	! tag_exists myhead
 '
 
-test_expect_success \
-	'creating a tag with the name of another deleted one should succeed' '
+test_expect_success 'creating a tag with the name of another deleted one should succeed' '
 	! tag_exists mytag &&
 	git tag mytag &&
 	tag_exists mytag
 '
 
-test_expect_success \
-	'trying to delete two tags, existing and not, should fail in the 2nd' '
+test_expect_success 'trying to delete two tags, existing and not, should fail in the 2nd' '
 	tag_exists mytag &&
 	! tag_exists nonexistingtag &&
 	test_must_fail git tag -d mytag nonexistingtag &&
@@ -243,23 +243,24 @@
 	! tag_exists nonexistingtag
 '
 
-test_expect_success 'trying to delete an already deleted tag should fail' \
-	'test_must_fail git tag -d mytag'
+test_expect_success 'trying to delete an already deleted tag should fail' '
+	test_must_fail git tag -d mytag
+'
 
 # listing various tags with pattern matching:
 
-cat >expect <<EOF
-a1
-aa1
-cba
-t210
-t211
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-EOF
 test_expect_success 'listing all tags should print them ordered' '
+	cat >expect <<-\EOF &&
+	a1
+	aa1
+	cba
+	t210
+	t211
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	EOF
 	git tag v1.0.1 &&
 	git tag t211 &&
 	git tag aa1 &&
@@ -269,91 +270,89 @@
 	git tag a1 &&
 	git tag v1.0 &&
 	git tag t210 &&
-	git tag -l > actual &&
+	git tag -l >actual &&
 	test_cmp expect actual &&
-	git tag > actual &&
+	git tag >actual &&
 	test_cmp expect actual
 '
 
-cat >expect <<EOF
-a1
-aa1
-cba
-EOF
-test_expect_success \
-	'listing tags with substring as pattern must print those matching' '
+test_expect_success 'listing tags with substring as pattern must print those matching' '
+	cat >expect <<-\EOF &&
+	a1
+	aa1
+	cba
+	EOF
 	rm *a* &&
-	git tag -l "*a*" > current &&
+	git tag -l "*a*" >current &&
 	test_cmp expect current
 '
 
-cat >expect <<EOF
-v0.2.1
-v1.0.1
-EOF
-test_expect_success \
-	'listing tags with a suffix as pattern must print those matching' '
-	git tag -l "*.1" > actual &&
+test_expect_success 'listing tags with a suffix as pattern must print those matching' '
+	cat >expect <<-\EOF &&
+	v0.2.1
+	v1.0.1
+	EOF
+	git tag -l "*.1" >actual &&
 	test_cmp expect actual
 '
 
-cat >expect <<EOF
-t210
-t211
-EOF
-test_expect_success \
-	'listing tags with a prefix as pattern must print those matching' '
-	git tag -l "t21*" > actual &&
+test_expect_success 'listing tags with a prefix as pattern must print those matching' '
+	cat >expect <<-\EOF &&
+	t210
+	t211
+	EOF
+	git tag -l "t21*" >actual &&
 	test_cmp expect actual
 '
 
-cat >expect <<EOF
-a1
-EOF
-test_expect_success \
-	'listing tags using a name as pattern must print that one matching' '
-	git tag -l a1 > actual &&
+test_expect_success 'listing tags using a name as pattern must print that one matching' '
+	cat >expect <<-\EOF &&
+	a1
+	EOF
+	git tag -l a1 >actual &&
 	test_cmp expect actual
 '
 
-cat >expect <<EOF
-v1.0
-EOF
-test_expect_success \
-	'listing tags using a name as pattern must print that one matching' '
-	git tag -l v1.0 > actual &&
+test_expect_success 'listing tags using a name as pattern must print that one matching' '
+	cat >expect <<-\EOF &&
+	v1.0
+	EOF
+	git tag -l v1.0 >actual &&
 	test_cmp expect actual
 '
 
-cat >expect <<EOF
-v1.0.1
-v1.1.3
-EOF
-test_expect_success \
-	'listing tags with ? in the pattern should print those matching' '
-	git tag -l "v1.?.?" > actual &&
+test_expect_success 'listing tags with ? in the pattern should print those matching' '
+	cat >expect <<-\EOF &&
+	v1.0.1
+	v1.1.3
+	EOF
+	git tag -l "v1.?.?" >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success \
-	'listing tags using v.* should print nothing because none have v.' '
-	git tag -l "v.*" > actual &&
+test_expect_success 'listing tags using v.* should print nothing because none have v.' '
+	git tag -l "v.*" >actual &&
 	test_must_be_empty actual
 '
 
-cat >expect <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-EOF
-test_expect_success \
-	'listing tags using v* should print only those having v' '
-	git tag -l "v*" > actual &&
+test_expect_success 'listing tags using v* should print only those having v' '
+	cat >expect <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	EOF
+	git tag -l "v*" >actual &&
 	test_cmp expect actual
 '
 
 test_expect_success 'tag -l can accept multiple patterns' '
+	cat >expect <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	EOF
 	git tag -l "v1*" "v0*" >actual &&
 	test_cmp expect actual
 '
@@ -367,16 +366,22 @@
 # out if we're going to break this long-documented form of taking
 # multiple patterns.
 test_expect_success 'tag -l <pattern> -l <pattern> works, as our buggy documentation previously suggested' '
+	cat >expect <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	EOF
 	git tag -l "v1*" -l "v0*" >actual &&
 	test_cmp expect actual
 '
 
 test_expect_success 'listing tags in column' '
 	COLUMNS=41 git tag -l --column=row >actual &&
-	cat >expected <<\EOF &&
-a1      aa1     cba     t210    t211
-v0.2.1  v1.0    v1.0.1  v1.1.3
-EOF
+	cat >expected <<-\EOF &&
+	a1      aa1     cba     t210    t211
+	v0.2.1  v1.0    v1.0.1  v1.1.3
+	EOF
 	test_cmp expected actual
 '
 
@@ -384,10 +389,10 @@
 	test_config column.tag row &&
 	test_config column.ui dense &&
 	COLUMNS=40 git tag -l >actual &&
-	cat >expected <<\EOF &&
-a1      aa1   cba     t210    t211
-v0.2.1  v1.0  v1.0.1  v1.1.3
-EOF
+	cat >expected <<-\EOF &&
+	a1      aa1   cba     t210    t211
+	v0.2.1  v1.0  v1.0.1  v1.1.3
+	EOF
 	test_cmp expected actual
 '
 
@@ -398,39 +403,39 @@
 test_expect_success 'listing tags -n in column with column.ui ignored' '
 	test_config column.ui "row dense" &&
 	COLUMNS=40 git tag -l -n >actual &&
-	cat >expected <<\EOF &&
-a1              Foo
-aa1             Foo
-cba             Foo
-t210            Foo
-t211            Foo
-v0.2.1          Foo
-v1.0            Foo
-v1.0.1          Foo
-v1.1.3          Foo
-EOF
+	cat >expected <<-\EOF &&
+	a1              Foo
+	aa1             Foo
+	cba             Foo
+	t210            Foo
+	t211            Foo
+	v0.2.1          Foo
+	v1.0            Foo
+	v1.0.1          Foo
+	v1.1.3          Foo
+	EOF
 	test_cmp expected actual
 '
 
 # creating and verifying lightweight tags:
 
-test_expect_success \
-	'a non-annotated tag created without parameters should point to HEAD' '
+test_expect_success 'a non-annotated tag created without parameters should point to HEAD' '
 	git tag non-annotated-tag &&
 	test $(git cat-file -t non-annotated-tag) = commit &&
 	test $(git rev-parse non-annotated-tag) = $(git rev-parse HEAD)
 '
 
-test_expect_success 'trying to verify an unknown tag should fail' \
-	'test_must_fail git tag -v unknown-tag'
+test_expect_success 'trying to verify an unknown tag should fail' '
+	test_must_fail git tag -v unknown-tag
+'
 
-test_expect_success \
-	'trying to verify a non-annotated and non-signed tag should fail' \
-	'test_must_fail git tag -v non-annotated-tag'
+test_expect_success 'trying to verify a non-annotated and non-signed tag should fail' '
+	test_must_fail git tag -v non-annotated-tag
+'
 
-test_expect_success \
-	'trying to verify many non-annotated or unknown tags, should fail' \
-	'test_must_fail git tag -v unknown-tag1 non-annotated-tag unknown-tag2'
+test_expect_success 'trying to verify many non-annotated or unknown tags, should fail' '
+	test_must_fail git tag -v unknown-tag1 non-annotated-tag unknown-tag2
+'
 
 # creating annotated tags:
 
@@ -449,83 +454,78 @@
 EOF
 }
 
-commit=$(git rev-parse HEAD)
-time=$test_tick
-
-get_tag_header annotated-tag $commit commit $time >expect
-echo "A message" >>expect
-test_expect_success \
-	'creating an annotated tag with -m message should succeed' '
+test_expect_success 'creating an annotated tag with -m message should succeed' '
+	commit=$(git rev-parse HEAD) &&
+	time=$test_tick &&
+	get_tag_header annotated-tag $commit commit $time >expect &&
+	echo "A message" >>expect &&
 	git tag -m "A message" annotated-tag &&
 	get_tag_msg annotated-tag >actual &&
 	test_cmp expect actual
 '
 
-get_tag_header annotated-tag-edit $commit commit $time >expect
-echo "An edited message" >>expect
 test_expect_success 'set up editor' '
 	write_script fakeeditor <<-\EOF
 	sed -e "s/A message/An edited message/g" <"$1" >"$1-"
 	mv "$1-" "$1"
 	EOF
 '
-test_expect_success \
-	'creating an annotated tag with -m message --edit should succeed' '
+
+test_expect_success 'creating an annotated tag with -m message --edit should succeed' '
+	get_tag_header annotated-tag-edit $commit commit $time >expect &&
+	echo "An edited message" >>expect &&
 	GIT_EDITOR=./fakeeditor git tag -m "A message" --edit annotated-tag-edit &&
 	get_tag_msg annotated-tag-edit >actual &&
 	test_cmp expect actual
 '
 
-cat >msgfile <<EOF
-Another message
-in a file.
-EOF
-get_tag_header file-annotated-tag $commit commit $time >expect
-cat msgfile >>expect
-test_expect_success \
-	'creating an annotated tag with -F messagefile should succeed' '
+test_expect_success 'creating an annotated tag with -F messagefile should succeed' '
+	cat >msgfile <<-\EOF &&
+	Another message
+	in a file.
+	EOF
+	get_tag_header file-annotated-tag $commit commit $time >expect &&
+	cat msgfile >>expect &&
 	git tag -F msgfile file-annotated-tag &&
 	get_tag_msg file-annotated-tag >actual &&
 	test_cmp expect actual
 '
 
-get_tag_header file-annotated-tag-edit $commit commit $time >expect
-sed -e "s/Another message/Another edited message/g" msgfile >>expect
 test_expect_success 'set up editor' '
 	write_script fakeeditor <<-\EOF
 	sed -e "s/Another message/Another edited message/g" <"$1" >"$1-"
 	mv "$1-" "$1"
 	EOF
 '
-test_expect_success \
-	'creating an annotated tag with -F messagefile --edit should succeed' '
+
+test_expect_success 'creating an annotated tag with -F messagefile --edit should succeed' '
+	get_tag_header file-annotated-tag-edit $commit commit $time >expect &&
+	sed -e "s/Another message/Another edited message/g" msgfile >>expect &&
 	GIT_EDITOR=./fakeeditor git tag -F msgfile --edit file-annotated-tag-edit &&
 	get_tag_msg file-annotated-tag-edit >actual &&
 	test_cmp expect actual
 '
 
-cat >inputmsg <<EOF
-A message from the
-standard input
-EOF
-get_tag_header stdin-annotated-tag $commit commit $time >expect
-cat inputmsg >>expect
 test_expect_success 'creating an annotated tag with -F - should succeed' '
+	cat >inputmsg <<-\EOF &&
+	A message from the
+	standard input
+	EOF
+	get_tag_header stdin-annotated-tag $commit commit $time >expect &&
+	cat inputmsg >>expect &&
 	git tag -F - stdin-annotated-tag <inputmsg &&
 	get_tag_msg stdin-annotated-tag >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success \
-	'trying to create a tag with a non-existing -F file should fail' '
+test_expect_success 'trying to create a tag with a non-existing -F file should fail' '
 	! test -f nonexistingfile &&
 	! tag_exists notag &&
 	test_must_fail git tag -F nonexistingfile notag &&
 	! tag_exists notag
 '
 
-test_expect_success \
-	'trying to create tags giving both -m or -F options should fail' '
+test_expect_success 'trying to create tags giving both -m or -F options should fail' '
 	echo "message file 1" >msgfile1 &&
 	! tag_exists msgtag &&
 	test_must_fail git tag -m "message 1" -F msgfile1 msgtag &&
@@ -539,67 +539,61 @@
 
 # blank and empty messages:
 
-get_tag_header empty-annotated-tag $commit commit $time >expect
-test_expect_success \
-	'creating a tag with an empty -m message should succeed' '
+test_expect_success 'creating a tag with an empty -m message should succeed' '
+	get_tag_header empty-annotated-tag $commit commit $time >expect &&
 	git tag -m "" empty-annotated-tag &&
 	get_tag_msg empty-annotated-tag >actual &&
 	test_cmp expect actual
 '
 
->emptyfile
-get_tag_header emptyfile-annotated-tag $commit commit $time >expect
-test_expect_success \
-	'creating a tag with an empty -F messagefile should succeed' '
+test_expect_success 'creating a tag with an empty -F messagefile should succeed' '
+	>emptyfile &&
+	get_tag_header emptyfile-annotated-tag $commit commit $time >expect &&
 	git tag -F emptyfile emptyfile-annotated-tag &&
 	get_tag_msg emptyfile-annotated-tag >actual &&
 	test_cmp expect actual
 '
 
-printf '\n\n  \n\t\nLeading blank lines\n' >blanksfile
-printf '\n\t \t  \nRepeated blank lines\n' >>blanksfile
-printf '\n\n\nTrailing spaces      \t  \n' >>blanksfile
-printf '\nTrailing blank lines\n\n\t \n\n' >>blanksfile
-get_tag_header blanks-annotated-tag $commit commit $time >expect
-cat >>expect <<EOF
-Leading blank lines
+test_expect_success 'extra blanks in the message for an annotated tag should be removed' '
+	printf "\n\n  \n\t\nLeading blank lines\n" >blanksfile &&
+	printf "\n\t \t  \nRepeated blank lines\n" >>blanksfile &&
+	printf "\n\n\nTrailing spaces      \t  \n" >>blanksfile &&
+	printf "\nTrailing blank lines\n\n\t \n\n" >>blanksfile &&
+	get_tag_header blanks-annotated-tag $commit commit $time >expect &&
+	cat >>expect <<-\EOF &&
+	Leading blank lines
 
-Repeated blank lines
+	Repeated blank lines
 
-Trailing spaces
+	Trailing spaces
 
-Trailing blank lines
-EOF
-test_expect_success \
-	'extra blanks in the message for an annotated tag should be removed' '
+	Trailing blank lines
+	EOF
 	git tag -F blanksfile blanks-annotated-tag &&
 	get_tag_msg blanks-annotated-tag >actual &&
 	test_cmp expect actual
 '
 
-get_tag_header blank-annotated-tag $commit commit $time >expect
-test_expect_success \
-	'creating a tag with blank -m message with spaces should succeed' '
+test_expect_success 'creating a tag with blank -m message with spaces should succeed' '
+	get_tag_header blank-annotated-tag $commit commit $time >expect &&
 	git tag -m "     " blank-annotated-tag &&
 	get_tag_msg blank-annotated-tag >actual &&
 	test_cmp expect actual
 '
 
-echo '     ' >blankfile
-echo ''      >>blankfile
-echo '  '    >>blankfile
-get_tag_header blankfile-annotated-tag $commit commit $time >expect
-test_expect_success \
-	'creating a tag with blank -F messagefile with spaces should succeed' '
+test_expect_success 'creating a tag with blank -F messagefile with spaces should succeed' '
+	echo "     " >blankfile &&
+	echo ""      >>blankfile &&
+	echo "  "    >>blankfile &&
+	get_tag_header blankfile-annotated-tag $commit commit $time >expect &&
 	git tag -F blankfile blankfile-annotated-tag &&
 	get_tag_msg blankfile-annotated-tag >actual &&
 	test_cmp expect actual
 '
 
-printf '      ' >blanknonlfile
-get_tag_header blanknonlfile-annotated-tag $commit commit $time >expect
-test_expect_success \
-	'creating a tag with -F file of spaces and no newline should succeed' '
+test_expect_success 'creating a tag with -F file of spaces and no newline should succeed' '
+	printf "      " >blanknonlfile &&
+	get_tag_header blanknonlfile-annotated-tag $commit commit $time >expect &&
 	git tag -F blanknonlfile blanknonlfile-annotated-tag &&
 	get_tag_msg blanknonlfile-annotated-tag >actual &&
 	test_cmp expect actual
@@ -607,62 +601,58 @@
 
 # messages with commented lines:
 
-cat >commentsfile <<EOF
-# A comment
+test_expect_success 'creating a tag using a -F messagefile with #comments should succeed' '
+	cat >commentsfile <<-\EOF &&
+	# A comment
 
-############
-The message.
-############
-One line.
+	############
+	The message.
+	############
+	One line.
 
 
-# commented lines
-# commented lines
+	# commented lines
+	# commented lines
 
-Another line.
-# comments
+	Another line.
+	# comments
 
-Last line.
-EOF
-get_tag_header comments-annotated-tag $commit commit $time >expect
-cat >>expect <<EOF
-The message.
-One line.
+	Last line.
+	EOF
+	get_tag_header comments-annotated-tag $commit commit $time >expect &&
+	cat >>expect <<-\EOF &&
+	The message.
+	One line.
 
-Another line.
+	Another line.
 
-Last line.
-EOF
-test_expect_success \
-	'creating a tag using a -F messagefile with #comments should succeed' '
+	Last line.
+	EOF
 	git tag -F commentsfile comments-annotated-tag &&
 	get_tag_msg comments-annotated-tag >actual &&
 	test_cmp expect actual
 '
 
-get_tag_header comment-annotated-tag $commit commit $time >expect
-test_expect_success \
-	'creating a tag with a #comment in the -m message should succeed' '
+test_expect_success 'creating a tag with a #comment in the -m message should succeed' '
+	get_tag_header comment-annotated-tag $commit commit $time >expect &&
 	git tag -m "#comment" comment-annotated-tag &&
 	get_tag_msg comment-annotated-tag >actual &&
 	test_cmp expect actual
 '
 
-echo '#comment' >commentfile
-echo ''         >>commentfile
-echo '####'     >>commentfile
-get_tag_header commentfile-annotated-tag $commit commit $time >expect
-test_expect_success \
-	'creating a tag with #comments in the -F messagefile should succeed' '
+test_expect_success 'creating a tag with #comments in the -F messagefile should succeed' '
+	echo "#comment" >commentfile &&
+	echo ""         >>commentfile &&
+	echo "####"     >>commentfile &&
+	get_tag_header commentfile-annotated-tag $commit commit $time >expect &&
 	git tag -F commentfile commentfile-annotated-tag &&
 	get_tag_msg commentfile-annotated-tag >actual &&
 	test_cmp expect actual
 '
 
-printf '#comment' >commentnonlfile
-get_tag_header commentnonlfile-annotated-tag $commit commit $time >expect
-test_expect_success \
-	'creating a tag with a file of #comment and no newline should succeed' '
+test_expect_success 'creating a tag with a file of #comment and no newline should succeed' '
+	printf "#comment" >commentnonlfile &&
+	get_tag_header commentnonlfile-annotated-tag $commit commit $time >expect &&
 	git tag -F commentnonlfile commentnonlfile-annotated-tag &&
 	get_tag_msg commentnonlfile-annotated-tag >actual &&
 	test_cmp expect actual
@@ -779,8 +769,7 @@
 
 # listing messages for annotated non-signed tags:
 
-test_expect_success \
-	'listing the one-line message of a non-signed tag should succeed' '
+test_expect_success 'listing the one-line message of a non-signed tag should succeed' '
 	git tag -m "A msg" tag-one-line &&
 
 	echo "tag-one-line" >expect &&
@@ -819,8 +808,7 @@
 	test_cmp expect actual
 '
 
-test_expect_success \
-	'listing the zero-lines message of a non-signed tag should succeed' '
+test_expect_success 'listing the zero-lines message of a non-signed tag should succeed' '
 	git tag -m "" tag-zero-lines &&
 
 	echo "tag-zero-lines" >expect &&
@@ -844,11 +832,10 @@
 	test_cmp expect actual
 '
 
-echo 'tag line one' >annotagmsg
-echo 'tag line two' >>annotagmsg
-echo 'tag line three' >>annotagmsg
-test_expect_success \
-	'listing many message lines of a non-signed tag should succeed' '
+test_expect_success 'listing many message lines of a non-signed tag should succeed' '
+	echo "tag line one" >annotagmsg &&
+	echo "tag line two" >>annotagmsg &&
+	echo "tag line three" >>annotagmsg  &&
 	git tag -F annotagmsg tag-lines &&
 
 	echo "tag-lines" >expect &&
@@ -936,40 +923,37 @@
 
 # trying to verify annotated non-signed tags:
 
-test_expect_success GPG \
-	'trying to verify an annotated non-signed tag should fail' '
+test_expect_success GPG 'trying to verify an annotated non-signed tag should fail' '
 	tag_exists annotated-tag &&
 	test_must_fail git tag -v annotated-tag
 '
 
-test_expect_success GPG \
-	'trying to verify a file-annotated non-signed tag should fail' '
+test_expect_success GPG 'trying to verify a file-annotated non-signed tag should fail' '
 	tag_exists file-annotated-tag &&
 	test_must_fail git tag -v file-annotated-tag
 '
 
-test_expect_success GPG \
-	'trying to verify two annotated non-signed tags should fail' '
+test_expect_success GPG 'trying to verify two annotated non-signed tags should fail' '
 	tag_exists annotated-tag file-annotated-tag &&
 	test_must_fail git tag -v annotated-tag file-annotated-tag
 '
 
 # creating and verifying signed tags:
 
-get_tag_header signed-tag $commit commit $time >expect
-echo 'A signed tag message' >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
 test_expect_success GPG 'creating a signed tag with -m message should succeed' '
+	get_tag_header signed-tag $commit commit $time >expect &&
+	echo "A signed tag message" >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -m "A signed tag message" signed-tag &&
 	get_tag_msg signed-tag >actual &&
 	test_cmp expect actual
 '
 
-get_tag_header u-signed-tag $commit commit $time >expect
-echo 'Another message' >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
 test_expect_success GPG 'sign with a given key id' '
 
+	get_tag_header u-signed-tag $commit commit $time >expect &&
+	echo "Another message" >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -u committer@example.com -m "Another message" u-signed-tag &&
 	get_tag_msg u-signed-tag >actual &&
 	test_cmp expect actual
@@ -989,137 +973,128 @@
 
 '
 
-cat >fakeeditor <<'EOF'
-#!/bin/sh
-test -n "$1" && exec >"$1"
-echo A signed tag message
-echo from a fake editor.
-EOF
-chmod +x fakeeditor
-
-get_tag_header implied-sign $commit commit $time >expect
-./fakeeditor >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
 test_expect_success GPG '-u implies signed tag' '
+	write_script fakeeditor <<-\EOF &&
+	test -n "$1" && exec >"$1"
+	echo A signed tag message
+	echo from a fake editor.
+	EOF
+
+	get_tag_header implied-sign $commit commit $time >expect &&
+	./fakeeditor >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	GIT_EDITOR=./fakeeditor git tag -u CDDE430D implied-sign &&
 	get_tag_msg implied-sign >actual &&
 	test_cmp expect actual
 '
 
-cat >sigmsgfile <<EOF
-Another signed tag
-message in a file.
-EOF
-get_tag_header file-signed-tag $commit commit $time >expect
-cat sigmsgfile >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag with -F messagefile should succeed' '
+test_expect_success GPG 'creating a signed tag with -F messagefile should succeed' '
+	cat >sigmsgfile <<-\EOF &&
+	Another signed tag
+	message in a file.
+	EOF
+	get_tag_header file-signed-tag $commit commit $time >expect &&
+	cat sigmsgfile >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -F sigmsgfile file-signed-tag &&
 	get_tag_msg file-signed-tag >actual &&
 	test_cmp expect actual
 '
 
-cat >siginputmsg <<EOF
-A signed tag message from
-the standard input
-EOF
-get_tag_header stdin-signed-tag $commit commit $time >expect
-cat siginputmsg >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
 test_expect_success GPG 'creating a signed tag with -F - should succeed' '
+	cat >siginputmsg <<-\EOF &&
+	A signed tag message from
+	the standard input
+	EOF
+	get_tag_header stdin-signed-tag $commit commit $time >expect &&
+	cat siginputmsg >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -F - stdin-signed-tag <siginputmsg &&
 	get_tag_msg stdin-signed-tag >actual &&
 	test_cmp expect actual
 '
 
-get_tag_header implied-annotate $commit commit $time >expect
-./fakeeditor >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
 test_expect_success GPG '-s implies annotated tag' '
+	get_tag_header implied-annotate $commit commit $time >expect &&
+	./fakeeditor >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	GIT_EDITOR=./fakeeditor git tag -s implied-annotate &&
 	get_tag_msg implied-annotate >actual &&
 	test_cmp expect actual
 '
 
-get_tag_header forcesignannotated-implied-sign $commit commit $time >expect
-echo "A message" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'git tag -s implied if configured with tag.forcesignannotated' \
-	'test_config tag.forcesignannotated true &&
+test_expect_success GPG 'git tag -s implied if configured with tag.forcesignannotated' '
+	get_tag_header forcesignannotated-implied-sign $commit commit $time >expect &&
+	echo "A message" >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
+	test_config tag.forcesignannotated true &&
 	git tag -m "A message" forcesignannotated-implied-sign &&
 	get_tag_msg forcesignannotated-implied-sign >actual &&
 	test_cmp expect actual
 '
 
-test_expect_success GPG \
-	'lightweight with no message when configured with tag.forcesignannotated' \
-	'test_config tag.forcesignannotated true &&
+test_expect_success GPG 'lightweight with no message when configured with tag.forcesignannotated' '
+	test_config tag.forcesignannotated true &&
 	git tag forcesignannotated-lightweight &&
 	tag_exists forcesignannotated-lightweight &&
 	test_must_fail git tag -v forcesignannotated-no-message
 '
 
-get_tag_header forcesignannotated-annotate $commit commit $time >expect
-echo "A message" >>expect
-test_expect_success GPG \
-	'git tag -a disable configured tag.forcesignannotated' \
-	'test_config tag.forcesignannotated true &&
+test_expect_success GPG 'git tag -a disable configured tag.forcesignannotated' '
+	get_tag_header forcesignannotated-annotate $commit commit $time >expect &&
+	echo "A message" >>expect &&
+	test_config tag.forcesignannotated true &&
 	git tag -a -m "A message" forcesignannotated-annotate &&
 	get_tag_msg forcesignannotated-annotate >actual &&
 	test_cmp expect actual &&
 	test_must_fail git tag -v forcesignannotated-annotate
 '
 
-get_tag_header forcesignannotated-disabled $commit commit $time >expect
-echo "A message" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'git tag --sign enable GPG sign' \
-	'test_config tag.forcesignannotated false &&
+test_expect_success GPG 'git tag --sign enable GPG sign' '
+	get_tag_header forcesignannotated-disabled $commit commit $time >expect &&
+	echo "A message" >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
+	test_config tag.forcesignannotated false &&
 	git tag --sign -m "A message" forcesignannotated-disabled &&
 	get_tag_msg forcesignannotated-disabled >actual &&
 	test_cmp expect actual
 '
 
-get_tag_header gpgsign-enabled $commit commit $time >expect
-echo "A message" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'git tag configured tag.gpgsign enables GPG sign' \
-	'test_config tag.gpgsign true &&
+test_expect_success GPG 'git tag configured tag.gpgsign enables GPG sign' '
+	get_tag_header gpgsign-enabled $commit commit $time >expect &&
+	echo "A message" >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
+	test_config tag.gpgsign true &&
 	git tag -m "A message" gpgsign-enabled &&
 	get_tag_msg gpgsign-enabled>actual &&
 	test_cmp expect actual
 '
 
-get_tag_header no-sign $commit commit $time >expect
-echo "A message" >>expect
-test_expect_success GPG \
-	'git tag --no-sign configured tag.gpgsign skip GPG sign' \
-	'test_config tag.gpgsign true &&
+test_expect_success GPG 'git tag --no-sign configured tag.gpgsign skip GPG sign' '
+	get_tag_header no-sign $commit commit $time >expect &&
+	echo "A message" >>expect &&
+	test_config tag.gpgsign true &&
 	git tag -a --no-sign -m "A message" no-sign &&
 	get_tag_msg no-sign>actual &&
 	test_cmp expect actual
 '
 
-test_expect_success GPG \
-	'trying to create a signed tag with non-existing -F file should fail' '
+test_expect_success GPG 'trying to create a signed tag with non-existing -F file should fail' '
 	! test -f nonexistingfile &&
 	! tag_exists nosigtag &&
 	test_must_fail git tag -s -F nonexistingfile nosigtag &&
 	! tag_exists nosigtag
 '
 
-test_expect_success GPG 'verifying a signed tag should succeed' \
-	'git tag -v signed-tag'
+test_expect_success GPG 'verifying a signed tag should succeed' '
+	git tag -v signed-tag
+'
 
-test_expect_success GPG 'verifying two signed tags in one command should succeed' \
-	'git tag -v signed-tag file-signed-tag'
+test_expect_success GPG 'verifying two signed tags in one command should succeed' '
+	git tag -v signed-tag file-signed-tag
+'
 
-test_expect_success GPG \
-	'verifying many signed and non-signed tags should fail' '
+test_expect_success GPG 'verifying many signed and non-signed tags should fail' '
 	test_must_fail git tag -v signed-tag annotated-tag &&
 	test_must_fail git tag -v file-annotated-tag file-signed-tag &&
 	test_must_fail git tag -v annotated-tag \
@@ -1150,78 +1125,72 @@
 
 # blank and empty messages for signed tags:
 
-get_tag_header empty-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag with an empty -m message should succeed' '
+test_expect_success GPG 'creating a signed tag with an empty -m message should succeed' '
+	get_tag_header empty-signed-tag $commit commit $time >expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -m "" empty-signed-tag &&
 	get_tag_msg empty-signed-tag >actual &&
 	test_cmp expect actual &&
 	git tag -v empty-signed-tag
 '
 
->sigemptyfile
-get_tag_header emptyfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag with an empty -F messagefile should succeed' '
+test_expect_success GPG 'creating a signed tag with an empty -F messagefile should succeed' '
+	>sigemptyfile &&
+	get_tag_header emptyfile-signed-tag $commit commit $time >expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -F sigemptyfile emptyfile-signed-tag &&
 	get_tag_msg emptyfile-signed-tag >actual &&
 	test_cmp expect actual &&
 	git tag -v emptyfile-signed-tag
 '
 
-printf '\n\n  \n\t\nLeading blank lines\n' > sigblanksfile
-printf '\n\t \t  \nRepeated blank lines\n' >>sigblanksfile
-printf '\n\n\nTrailing spaces      \t  \n' >>sigblanksfile
-printf '\nTrailing blank lines\n\n\t \n\n' >>sigblanksfile
-get_tag_header blanks-signed-tag $commit commit $time >expect
-cat >>expect <<EOF
-Leading blank lines
+test_expect_success GPG 'extra blanks in the message for a signed tag should be removed' '
+	printf "\n\n  \n\t\nLeading blank lines\n" >sigblanksfile &&
+	printf "\n\t \t  \nRepeated blank lines\n" >>sigblanksfile &&
+	printf "\n\n\nTrailing spaces      \t  \n" >>sigblanksfile &&
+	printf "\nTrailing blank lines\n\n\t \n\n" >>sigblanksfile &&
+	get_tag_header blanks-signed-tag $commit commit $time >expect &&
+	cat >>expect <<-\EOF &&
+	Leading blank lines
 
-Repeated blank lines
+	Repeated blank lines
 
-Trailing spaces
+	Trailing spaces
 
-Trailing blank lines
-EOF
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'extra blanks in the message for a signed tag should be removed' '
+	Trailing blank lines
+	EOF
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -F sigblanksfile blanks-signed-tag &&
 	get_tag_msg blanks-signed-tag >actual &&
 	test_cmp expect actual &&
 	git tag -v blanks-signed-tag
 '
 
-get_tag_header blank-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag with a blank -m message should succeed' '
+test_expect_success GPG 'creating a signed tag with a blank -m message should succeed' '
+	get_tag_header blank-signed-tag $commit commit $time >expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -m "     " blank-signed-tag &&
 	get_tag_msg blank-signed-tag >actual &&
 	test_cmp expect actual &&
 	git tag -v blank-signed-tag
 '
 
-echo '     ' >sigblankfile
-echo ''      >>sigblankfile
-echo '  '    >>sigblankfile
-get_tag_header blankfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag with blank -F file with spaces should succeed' '
+test_expect_success GPG 'creating a signed tag with blank -F file with spaces should succeed' '
+	echo "     " >sigblankfile &&
+	echo ""      >>sigblankfile &&
+	echo "  "    >>sigblankfile &&
+	get_tag_header blankfile-signed-tag $commit commit $time >expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -F sigblankfile blankfile-signed-tag &&
 	get_tag_msg blankfile-signed-tag >actual &&
 	test_cmp expect actual &&
 	git tag -v blankfile-signed-tag
 '
 
-printf '      ' >sigblanknonlfile
-get_tag_header blanknonlfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag with spaces and no newline should succeed' '
+test_expect_success GPG 'creating a signed tag with spaces and no newline should succeed' '
+	printf "      " >sigblanknonlfile &&
+	get_tag_header blanknonlfile-signed-tag $commit commit $time >expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -F sigblanknonlfile blanknonlfile-signed-tag &&
 	get_tag_msg blanknonlfile-signed-tag >actual &&
 	test_cmp expect actual &&
@@ -1241,69 +1210,65 @@
 
 # messages with commented lines for signed tags:
 
-cat >sigcommentsfile <<EOF
-# A comment
+test_expect_success GPG 'creating a signed tag with a -F file with #comments should succeed' '
+	cat >sigcommentsfile <<-\EOF &&
+	# A comment
 
-############
-The message.
-############
-One line.
+	############
+	The message.
+	############
+	One line.
 
 
-# commented lines
-# commented lines
+	# commented lines
+	# commented lines
 
-Another line.
-# comments
+	Another line.
+	# comments
 
-Last line.
-EOF
-get_tag_header comments-signed-tag $commit commit $time >expect
-cat >>expect <<EOF
-The message.
-One line.
+	Last line.
+	EOF
+	get_tag_header comments-signed-tag $commit commit $time >expect &&
+	cat >>expect <<-\EOF &&
+	The message.
+	One line.
 
-Another line.
+	Another line.
 
-Last line.
-EOF
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag with a -F file with #comments should succeed' '
+	Last line.
+	EOF
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -F sigcommentsfile comments-signed-tag &&
 	get_tag_msg comments-signed-tag >actual &&
 	test_cmp expect actual &&
 	git tag -v comments-signed-tag
 '
 
-get_tag_header comment-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag with #commented -m message should succeed' '
+test_expect_success GPG 'creating a signed tag with #commented -m message should succeed' '
+	get_tag_header comment-signed-tag $commit commit $time >expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -m "#comment" comment-signed-tag &&
 	get_tag_msg comment-signed-tag >actual &&
 	test_cmp expect actual &&
 	git tag -v comment-signed-tag
 '
 
-echo '#comment' >sigcommentfile
-echo ''         >>sigcommentfile
-echo '####'     >>sigcommentfile
-get_tag_header commentfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag with #commented -F messagefile should succeed' '
+test_expect_success GPG 'creating a signed tag with #commented -F messagefile should succeed' '
+	echo "#comment" >sigcommentfile &&
+	echo ""         >>sigcommentfile &&
+	echo "####"     >>sigcommentfile &&
+	get_tag_header commentfile-signed-tag $commit commit $time >expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -F sigcommentfile commentfile-signed-tag &&
 	get_tag_msg commentfile-signed-tag >actual &&
 	test_cmp expect actual &&
 	git tag -v commentfile-signed-tag
 '
 
-printf '#comment' >sigcommentnonlfile
-get_tag_header commentnonlfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag with a #comment and no newline should succeed' '
+test_expect_success GPG 'creating a signed tag with a #comment and no newline should succeed' '
+	printf "#comment" >sigcommentnonlfile &&
+	get_tag_header commentnonlfile-signed-tag $commit commit $time >expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -F sigcommentnonlfile commentnonlfile-signed-tag &&
 	get_tag_msg commentnonlfile-signed-tag >actual &&
 	test_cmp expect actual &&
@@ -1312,8 +1277,7 @@
 
 # listing messages for signed tags:
 
-test_expect_success GPG \
-	'listing the one-line message of a signed tag should succeed' '
+test_expect_success GPG 'listing the one-line message of a signed tag should succeed' '
 	git tag -s -m "A message line signed" stag-one-line &&
 
 	echo "stag-one-line" >expect &&
@@ -1337,8 +1301,7 @@
 	test_cmp expect actual
 '
 
-test_expect_success GPG \
-	'listing the zero-lines message of a signed tag should succeed' '
+test_expect_success GPG 'listing the zero-lines message of a signed tag should succeed' '
 	git tag -s -m "" stag-zero-lines &&
 
 	echo "stag-zero-lines" >expect &&
@@ -1362,11 +1325,10 @@
 	test_cmp expect actual
 '
 
-echo 'stag line one' >sigtagmsg
-echo 'stag line two' >>sigtagmsg
-echo 'stag line three' >>sigtagmsg
-test_expect_success GPG \
-	'listing many message lines of a signed tag should succeed' '
+test_expect_success GPG 'listing many message lines of a signed tag should succeed' '
+	echo "stag line one" >sigtagmsg &&
+	echo "stag line two" >>sigtagmsg &&
+	echo "stag line three" >>sigtagmsg &&
 	git tag -s -F sigtagmsg stag-lines &&
 
 	echo "stag-lines" >expect &&
@@ -1408,74 +1370,64 @@
 
 # tags pointing to objects different from commits:
 
-tree=$(git rev-parse HEAD^{tree})
-blob=$(git rev-parse HEAD:foo)
-tag=$(git rev-parse signed-tag 2>/dev/null)
-
-get_tag_header tree-signed-tag $tree tree $time >expect
-echo "A message for a tree" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag pointing to a tree should succeed' '
+test_expect_success GPG 'creating a signed tag pointing to a tree should succeed' '
+	tree=$(git rev-parse HEAD^{tree}) &&
+	get_tag_header tree-signed-tag $tree tree $time >expect &&
+	echo "A message for a tree" >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -m "A message for a tree" tree-signed-tag HEAD^{tree} &&
 	get_tag_msg tree-signed-tag >actual &&
 	test_cmp expect actual
 '
 
-get_tag_header blob-signed-tag $blob blob $time >expect
-echo "A message for a blob" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag pointing to a blob should succeed' '
+test_expect_success GPG 'creating a signed tag pointing to a blob should succeed' '
+	blob=$(git rev-parse HEAD:foo) &&
+	get_tag_header blob-signed-tag $blob blob $time >expect &&
+	echo "A message for a blob" >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -m "A message for a blob" blob-signed-tag HEAD:foo &&
 	get_tag_msg blob-signed-tag >actual &&
 	test_cmp expect actual
 '
 
-get_tag_header tag-signed-tag $tag tag $time >expect
-echo "A message for another tag" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
-	'creating a signed tag pointing to another tag should succeed' '
+test_expect_success GPG 'creating a signed tag pointing to another tag should succeed' '
+	tag=$(git rev-parse signed-tag 2>/dev/null) &&
+	get_tag_header tag-signed-tag $tag tag $time >expect &&
+	echo "A message for another tag" >>expect &&
+	echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
 	git tag -s -m "A message for another tag" tag-signed-tag signed-tag &&
 	get_tag_msg tag-signed-tag >actual &&
 	test_cmp expect actual
 '
 
 # usage with rfc1991 signatures
-get_tag_header rfc1991-signed-tag $commit commit $time >expect
-echo "RFC1991 signed tag" >>expect
-echo '-----BEGIN PGP MESSAGE-----' >>expect
-test_expect_success GPG,RFC1991 \
-	'creating a signed tag with rfc1991' '
+
+test_expect_success GPG,RFC1991 'creating a signed tag with rfc1991' '
+	get_tag_header rfc1991-signed-tag $commit commit $time >expect &&
+	echo "RFC1991 signed tag" >>expect &&
+	echo "-----BEGIN PGP MESSAGE-----" >>expect &&
 	echo "rfc1991" >gpghome/gpg.conf &&
 	git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit &&
 	get_tag_msg rfc1991-signed-tag >actual &&
 	test_cmp expect actual
 '
 
-cat >fakeeditor <<'EOF'
-#!/bin/sh
-cp "$1" actual
-EOF
-chmod +x fakeeditor
-
-test_expect_success GPG,RFC1991 \
-	'reediting a signed tag body omits signature' '
+test_expect_success GPG,RFC1991 'reediting a signed tag body omits signature' '
+	write_script fakeeditor <<-\EOF &&
+	cp "$1" actual
+	EOF
 	echo "rfc1991" >gpghome/gpg.conf &&
 	echo "RFC1991 signed tag" >expect &&
 	GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
 	test_cmp expect actual
 '
 
-test_expect_success GPG,RFC1991 \
-	'verifying rfc1991 signature' '
+test_expect_success GPG,RFC1991 'verifying rfc1991 signature' '
 	echo "rfc1991" >gpghome/gpg.conf &&
 	git tag -v rfc1991-signed-tag
 '
 
-test_expect_success GPG,RFC1991 \
-	'list tag with rfc1991 signature' '
+test_expect_success GPG,RFC1991 'list tag with rfc1991 signature' '
 	echo "rfc1991" >gpghome/gpg.conf &&
 	echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
 	git tag -l -n1 rfc1991-signed-tag >actual &&
@@ -1486,15 +1438,12 @@
 	test_cmp expect actual
 '
 
-rm -f gpghome/gpg.conf
-
-test_expect_success GPG,RFC1991 \
-	'verifying rfc1991 signature without --rfc1991' '
+test_expect_success GPG,RFC1991 'verifying rfc1991 signature without --rfc1991' '
+	rm -f gpghome/gpg.conf &&
 	git tag -v rfc1991-signed-tag
 '
 
-test_expect_success GPG,RFC1991 \
-	'list tag with rfc1991 signature without --rfc1991' '
+test_expect_success GPG,RFC1991 'list tag with rfc1991 signature without --rfc1991' '
 	echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
 	git tag -l -n1 rfc1991-signed-tag >actual &&
 	test_cmp expect actual &&
@@ -1504,24 +1453,23 @@
 	test_cmp expect actual
 '
 
-test_expect_success GPG,RFC1991 \
-	'reediting a signed tag body omits signature' '
+test_expect_success GPG,RFC1991 'reediting a signed tag body omits signature' '
 	echo "RFC1991 signed tag" >expect &&
 	GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
 	test_cmp expect actual
 '
 
 # try to sign with bad user.signingkey
-test_expect_success GPG \
-	'git tag -s fails if gpg is misconfigured (bad key)' \
-	'test_config user.signingkey BobTheMouse &&
-	test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPG 'git tag -s fails if gpg is misconfigured (bad key)' '
+	test_config user.signingkey BobTheMouse &&
+	test_must_fail git tag -s -m tail tag-gpg-failure
+'
 
 # try to produce invalid signature
-test_expect_success GPG \
-	'git tag -s fails if gpg is misconfigured (bad signature format)' \
-	'test_config gpg.program echo &&
-	 test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPG 'git tag -s fails if gpg is misconfigured (bad signature format)' '
+	test_config gpg.program echo &&
+	test_must_fail git tag -s -m tail tag-gpg-failure
+'
 
 # try to produce invalid signature
 test_expect_success GPG 'git verifies tag is valid with double signature' '
@@ -1542,34 +1490,32 @@
 '
 
 # try to sign with bad user.signingkey
-test_expect_success GPGSM \
-	'git tag -s fails if gpgsm is misconfigured (bad key)' \
-	'test_config user.signingkey BobTheMouse &&
-	 test_config gpg.format x509 &&
-	 test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPGSM 'git tag -s fails if gpgsm is misconfigured (bad key)' '
+	test_config user.signingkey BobTheMouse &&
+	test_config gpg.format x509 &&
+	test_must_fail git tag -s -m tail tag-gpg-failure
+'
 
 # try to produce invalid signature
-test_expect_success GPGSM \
-	'git tag -s fails if gpgsm is misconfigured (bad signature format)' \
-	'test_config gpg.x509.program echo &&
-	 test_config gpg.format x509 &&
-	 test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPGSM 'git tag -s fails if gpgsm is misconfigured (bad signature format)' '
+	test_config gpg.x509.program echo &&
+	test_config gpg.format x509 &&
+	test_must_fail git tag -s -m tail tag-gpg-failure
+'
 
 # try to verify without gpg:
 
-rm -rf gpghome
-test_expect_success GPG \
-	'verify signed tag fails when public key is not present' \
-	'test_must_fail git tag -v signed-tag'
+test_expect_success GPG 'verify signed tag fails when public key is not present' '
+	rm -rf gpghome &&
+	test_must_fail git tag -v signed-tag
+'
 
-test_expect_success \
-	'git tag -a fails if tag annotation is empty' '
+test_expect_success 'git tag -a fails if tag annotation is empty' '
 	! (GIT_EDITOR=cat git tag -a initial-comment)
 '
 
-test_expect_success \
-	'message in editor has initial comment' '
-	! (GIT_EDITOR=cat git tag -a initial-comment > actual)
+test_expect_success 'message in editor has initial comment' '
+	! (GIT_EDITOR=cat git tag -a initial-comment >actual)
 '
 
 test_expect_success 'message in editor has initial comment: first line' '
@@ -1579,17 +1525,15 @@
 	test_cmp first.expect first.actual
 '
 
-test_expect_success \
-	'message in editor has initial comment: remainder' '
+test_expect_success 'message in editor has initial comment: remainder' '
 	# remove commented lines from the remainder -- should be empty
 	sed -e 1d -e "/^#/d" <actual >rest.actual &&
 	test_must_be_empty rest.actual
 '
 
-get_tag_header reuse $commit commit $time >expect
-echo "An annotation to be reused" >> expect
-test_expect_success \
-	'overwriting an annotated tag should use its previous body' '
+test_expect_success 'overwriting an annotated tag should use its previous body' '
+	get_tag_header reuse $commit commit $time >expect &&
+	echo "An annotation to be reused" >>expect &&
 	git tag -a -m "An annotation to be reused" reuse &&
 	GIT_EDITOR=true git tag -f -a reuse &&
 	get_tag_msg reuse >actual &&
@@ -1618,192 +1562,202 @@
 
 # create a few more commits to test --contains
 
-hash1=$(git rev-parse HEAD)
-
 test_expect_success 'creating second commit and tag' '
+	hash1=$(git rev-parse HEAD) &&
 	echo foo-2.0 >foo &&
 	git add foo &&
 	git commit -m second &&
 	git tag v2.0
 '
 
-hash2=$(git rev-parse HEAD)
-
 test_expect_success 'creating third commit without tag' '
+	hash2=$(git rev-parse HEAD) &&
 	echo foo-dev >foo &&
 	git add foo &&
 	git commit -m third
 '
 
-hash3=$(git rev-parse HEAD)
-
 # simple linear checks of --continue
 
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-EOF
-
-test_expect_success 'checking that first commit is in all tags (hash)' "
+test_expect_success 'checking that first commit is in all tags (hash)' '
+	hash3=$(git rev-parse HEAD) &&
+	cat >expected <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	v2.0
+	EOF
 	git tag -l --contains $hash1 v* >actual &&
 	test_cmp expected actual
-"
+'
 
 # other ways of specifying the commit
-test_expect_success 'checking that first commit is in all tags (tag)' "
+test_expect_success 'checking that first commit is in all tags (tag)' '
+	cat >expected <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	v2.0
+	EOF
 	git tag -l --contains v1.0 v* >actual &&
 	test_cmp expected actual
-"
+'
 
-test_expect_success 'checking that first commit is in all tags (relative)' "
+test_expect_success 'checking that first commit is in all tags (relative)' '
+	cat >expected <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	v2.0
+	EOF
 	git tag -l --contains HEAD~2 v* >actual &&
 	test_cmp expected actual
-"
+'
 
 # All the --contains tests above, but with --no-contains
-test_expect_success 'checking that first commit is not listed in any tag with --no-contains  (hash)' "
+test_expect_success 'checking that first commit is not listed in any tag with --no-contains  (hash)' '
 	git tag -l --no-contains $hash1 v* >actual &&
 	test_must_be_empty actual
-"
+'
 
-test_expect_success 'checking that first commit is in all tags (tag)' "
+test_expect_success 'checking that first commit is in all tags (tag)' '
 	git tag -l --no-contains v1.0 v* >actual &&
 	test_must_be_empty actual
-"
+'
 
-test_expect_success 'checking that first commit is in all tags (relative)' "
+test_expect_success 'checking that first commit is in all tags (relative)' '
 	git tag -l --no-contains HEAD~2 v* >actual &&
 	test_must_be_empty actual
-"
+'
 
-cat > expected <<EOF
-v2.0
-EOF
-
-test_expect_success 'checking that second commit only has one tag' "
+test_expect_success 'checking that second commit only has one tag' '
+	cat >expected <<-\EOF &&
+	v2.0
+	EOF
 	git tag -l --contains $hash2 v* >actual &&
 	test_cmp expected actual
-"
+'
 
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-EOF
-
-test_expect_success 'inverse of the last test, with --no-contains' "
+test_expect_success 'inverse of the last test, with --no-contains' '
+	cat >expected <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	EOF
 	git tag -l --no-contains $hash2 v* >actual &&
 	test_cmp expected actual
-"
+'
 
-test_expect_success 'checking that third commit has no tags' "
+test_expect_success 'checking that third commit has no tags' '
 	git tag -l --contains $hash3 v* >actual &&
 	test_must_be_empty actual
-"
+'
 
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-EOF
-
-test_expect_success 'conversely --no-contains on the third commit lists all tags' "
+test_expect_success 'conversely --no-contains on the third commit lists all tags' '
+	cat >expected <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	v2.0
+	EOF
 	git tag -l --no-contains $hash3 v* >actual &&
 	test_cmp expected actual
-"
+'
 
 # how about a simple merge?
 
 test_expect_success 'creating simple branch' '
 	git branch stable v2.0 &&
         git checkout stable &&
-	echo foo-3.0 > foo &&
+	echo foo-3.0 >foo &&
 	git commit foo -m fourth &&
 	git tag v3.0
 '
 
-hash4=$(git rev-parse HEAD)
-
-cat > expected <<EOF
-v3.0
-EOF
-
-test_expect_success 'checking that branch head only has one tag' "
+test_expect_success 'checking that branch head only has one tag' '
+	hash4=$(git rev-parse HEAD) &&
+	cat >expected <<-\EOF &&
+	v3.0
+	EOF
 	git tag -l --contains $hash4 v* >actual &&
 	test_cmp expected actual
-"
+'
 
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-EOF
-
-test_expect_success 'checking that branch head with --no-contains lists all but one tag' "
+test_expect_success 'checking that branch head with --no-contains lists all but one tag' '
+	cat >expected <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	v2.0
+	EOF
 	git tag -l --no-contains $hash4 v* >actual &&
 	test_cmp expected actual
-"
+'
 
 test_expect_success 'merging original branch into this branch' '
 	git merge --strategy=ours main &&
         git tag v4.0
 '
 
-cat > expected <<EOF
-v4.0
-EOF
-
-test_expect_success 'checking that original branch head has one tag now' "
+test_expect_success 'checking that original branch head has one tag now' '
+	cat >expected <<-\EOF &&
+	v4.0
+	EOF
 	git tag -l --contains $hash3 v* >actual &&
 	test_cmp expected actual
-"
+'
 
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-v3.0
-EOF
-
-test_expect_success 'checking that original branch head with --no-contains lists all but one tag now' "
+test_expect_success 'checking that original branch head with --no-contains lists all but one tag now' '
+	cat >expected <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	v2.0
+	v3.0
+	EOF
 	git tag -l --no-contains $hash3 v* >actual &&
 	test_cmp expected actual
-"
+'
 
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-v3.0
-v4.0
-EOF
-
-test_expect_success 'checking that initial commit is in all tags' "
+test_expect_success 'checking that initial commit is in all tags' '
+	cat >expected <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	v2.0
+	v3.0
+	v4.0
+	EOF
 	git tag -l --contains $hash1 v* >actual &&
 	test_cmp expected actual
-"
+'
 
 test_expect_success 'checking that --contains can be used in non-list mode' '
+	cat >expected <<-\EOF &&
+	v0.2.1
+	v1.0
+	v1.0.1
+	v1.1.3
+	v2.0
+	v3.0
+	v4.0
+	EOF
 	git tag --contains $hash1 v* >actual &&
 	test_cmp expected actual
 '
 
-test_expect_success 'checking that initial commit is in all tags with --no-contains' "
+test_expect_success 'checking that initial commit is in all tags with --no-contains' '
 	git tag -l --no-contains $hash1 v* >actual &&
 	test_must_be_empty actual
-"
+'
 
 # mixing modes and options:
 
@@ -1840,16 +1794,16 @@
 
 for option in --contains --with --no-contains --without --merged --no-merged --points-at
 do
-	test_expect_success "mixing incompatible modes with $option is forbidden" "
+	test_expect_success "mixing incompatible modes with $option is forbidden" '
 		test_must_fail git tag -d $option HEAD &&
 		test_must_fail git tag -d $option HEAD some-tag &&
 		test_must_fail git tag -v $option HEAD
-	"
-	test_expect_success "Doing 'git tag --list-like $option <commit> <pattern> is permitted" "
+	'
+	test_expect_success "Doing 'git tag --list-like $option <commit> <pattern> is permitted" '
 		git tag -n $option HEAD HEAD &&
 		git tag $option HEAD HEAD &&
 		git tag $option
-	"
+	'
 done
 
 # check points-at
@@ -2225,7 +2179,7 @@
 	test_must_fail git tag -l --format="%(rest)" "v1*"
 '
 
-test_expect_success "set up color tests" '
+test_expect_success 'set up color tests' '
 	echo "<RED>v1.0<RESET>" >expect.color &&
 	echo "v1.0" >expect.bare &&
 	color_args="--format=%(color:red)%(refname:short) --list v1.0"
diff --git a/t/t7008-filter-branch-null-sha1.sh b/t/t7008-filter-branch-null-sha1.sh
index 93fbc92..0ce8fd2 100755
--- a/t/t7008-filter-branch-null-sha1.sh
+++ b/t/t7008-filter-branch-null-sha1.sh
@@ -2,6 +2,7 @@
 
 test_description='filter-branch removal of trees with null sha1'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup: base commits' '
diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh
index 6f526c3..effa826 100755
--- a/t/t7030-verify-tag.sh
+++ b/t/t7030-verify-tag.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-gpg.sh"
 
diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh
index 2f9bea9..64145a0 100755
--- a/t/t7061-wtstatus-ignore.sh
+++ b/t/t7061-wtstatus-ignore.sh
@@ -2,6 +2,7 @@
 
 test_description='git-status ignored files'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 cat >expected <<\EOF
diff --git a/t/t7064-wtstatus-pv2.sh b/t/t7064-wtstatus-pv2.sh
index 11884d2..06c1301 100755
--- a/t/t7064-wtstatus-pv2.sh
+++ b/t/t7064-wtstatus-pv2.sh
@@ -4,6 +4,7 @@
 
 This test exercises porcelain V2 output for git status.'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 9814888..098d883 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -12,6 +12,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup - enable local submodules' '
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 297c6c3..0f0c86f 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -12,6 +12,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 8d7b234..9f68893 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -12,6 +12,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index d6040e0..7e1afa9 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -4,6 +4,8 @@
 #
 
 test_description='test clone --reference'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 base_dir=$(pwd)
diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh
index 31271f8..af0de49 100755
--- a/t/t7411-submodule-config.sh
+++ b/t/t7411-submodule-config.sh
@@ -10,6 +10,7 @@
 '
 
 TEST_NO_CREATE_REPO=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t7418-submodule-sparse-gitmodules.sh b/t/t7418-submodule-sparse-gitmodules.sh
index dde11ec..e1d9bf2 100755
--- a/t/t7418-submodule-sparse-gitmodules.sh
+++ b/t/t7418-submodule-sparse-gitmodules.sh
@@ -15,6 +15,7 @@
 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
 export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t7420-submodule-set-url.sh b/t/t7420-submodule-set-url.sh
index bf7f15e..d7fe910 100755
--- a/t/t7420-submodule-set-url.sh
+++ b/t/t7420-submodule-set-url.sh
@@ -10,6 +10,7 @@
 '
 
 TEST_NO_CREATE_REPO=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t7422-submodule-output.sh b/t/t7422-submodule-output.sh
index ab946ec..c1686d6 100755
--- a/t/t7422-submodule-output.sh
+++ b/t/t7422-submodule-output.sh
@@ -167,4 +167,11 @@
 	'
 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)"
+'
+
 test_done
diff --git a/t/t7424-submodule-mixed-ref-formats.sh b/t/t7424-submodule-mixed-ref-formats.sh
new file mode 100755
index 0000000..b43ef2b
--- /dev/null
+++ b/t/t7424-submodule-mixed-ref-formats.sh
@@ -0,0 +1,144 @@
+#!/bin/sh
+
+test_description='submodules handle mixed ref storage formats'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_ref_format () {
+	echo "$2" >expect &&
+	git -C "$1" rev-parse --show-ref-format >actual &&
+	test_cmp expect actual
+}
+
+for OTHER_FORMAT in files reftable
+do
+	if test "$OTHER_FORMAT" = "$GIT_DEFAULT_REF_FORMAT"
+	then
+		continue
+	fi
+
+test_expect_success 'setup' '
+	git config set --global protocol.file.allow always &&
+	# Some tests migrate the ref storage format, which does not work with
+	# reflogs at the time of writing these tests.
+	git config set --global core.logAllRefUpdates false
+'
+
+test_expect_success 'add existing repository with different ref storage format' '
+	test_when_finished "rm -rf parent" &&
+
+	git init parent &&
+	(
+		cd parent &&
+		test_commit parent &&
+		git init --ref-format=$OTHER_FORMAT submodule &&
+		test_commit -C submodule submodule &&
+		git submodule add ./submodule
+	)
+'
+
+test_expect_success 'add submodules with different ref storage format' '
+	test_when_finished "rm -rf submodule upstream" &&
+
+	git init submodule &&
+	test_commit -C submodule submodule-initial &&
+	git init upstream &&
+	test_ref_format upstream "$GIT_DEFAULT_REF_FORMAT" &&
+	git -C upstream submodule add --ref-format="$OTHER_FORMAT" "file://$(pwd)/submodule" &&
+	test_ref_format upstream/submodule "$OTHER_FORMAT"
+'
+
+test_expect_success 'recursive clone propagates ref storage format' '
+	test_when_finished "rm -rf submodule upstream downstream" &&
+
+	git init submodule &&
+	test_commit -C submodule submodule-initial &&
+	git init upstream &&
+	git -C upstream submodule add "file://$(pwd)/submodule" &&
+	git -C upstream commit -am "add submodule" &&
+
+	# The upstream repository and its submodule should be using the default
+	# ref format.
+	test_ref_format upstream "$GIT_DEFAULT_REF_FORMAT" &&
+	test_ref_format upstream/submodule "$GIT_DEFAULT_REF_FORMAT" &&
+
+	# The cloned repositories should use the other ref format that we have
+	# specified via `--ref-format`. The option should propagate to cloned
+	# submodules.
+	git clone --ref-format=$OTHER_FORMAT --recurse-submodules \
+		upstream downstream &&
+	test_ref_format downstream "$OTHER_FORMAT" &&
+	test_ref_format downstream/submodule "$OTHER_FORMAT"
+'
+
+test_expect_success 'clone submodules with different ref storage format' '
+	test_when_finished "rm -rf submodule upstream downstream" &&
+
+	git init submodule &&
+	test_commit -C submodule submodule-initial &&
+	git init upstream &&
+	git -C upstream submodule add "file://$(pwd)/submodule" &&
+	git -C upstream commit -m "upstream submodule" &&
+
+	git clone --no-recurse-submodules "file://$(pwd)/upstream" downstream &&
+	test_ref_format downstream "$GIT_DEFAULT_REF_FORMAT" &&
+	git -C downstream submodule update --init --ref-format=$OTHER_FORMAT &&
+	test_ref_format downstream/submodule "$OTHER_FORMAT"
+'
+
+test_expect_success 'status with mixed submodule ref storages' '
+	test_when_finished "rm -rf submodule main" &&
+
+	git init submodule &&
+	test_commit -C submodule submodule-initial &&
+	git init main &&
+	git -C main submodule add "file://$(pwd)/submodule" &&
+	git -C main commit -m "add submodule" &&
+	git -C main/submodule refs migrate --ref-format=$OTHER_FORMAT &&
+
+	# The main repository should use the default ref format now, whereas
+	# the submodule should use the other format.
+	test_ref_format main "$GIT_DEFAULT_REF_FORMAT" &&
+	test_ref_format main/submodule "$OTHER_FORMAT" &&
+
+	cat >expect <<-EOF &&
+	 $(git -C main/submodule rev-parse HEAD) submodule (submodule-initial)
+	EOF
+	git -C main submodule status >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'recursive pull with mixed formats' '
+	test_when_finished "rm -rf submodule upstream downstream" &&
+
+	# Set up the initial structure with an upstream repository that has a
+	# submodule, as well as a downstream clone of the upstream repository.
+	git init submodule &&
+	test_commit -C submodule submodule-initial &&
+	git init upstream &&
+	git -C upstream submodule add "file://$(pwd)/submodule" &&
+	git -C upstream commit -m "upstream submodule" &&
+
+	# Clone the upstream repository such that the main repo and its
+	# submodules have different formats.
+	git clone --no-recurse-submodules "file://$(pwd)/upstream" downstream &&
+	git -C downstream submodule update --init --ref-format=$OTHER_FORMAT &&
+	test_ref_format downstream "$GIT_DEFAULT_REF_FORMAT" &&
+	test_ref_format downstream/submodule "$OTHER_FORMAT" &&
+
+	# Update the upstream submodule as well as the owning repository such
+	# that we can do a recursive pull.
+	test_commit -C submodule submodule-update &&
+	git -C upstream/submodule pull &&
+	git -C upstream commit -am "update the submodule" &&
+
+	git -C downstream pull --recurse-submodules &&
+	git -C upstream/submodule rev-parse HEAD >expect &&
+	git -C downstream/submodule rev-parse HEAD >actual &&
+	test_cmp expect actual
+'
+
+done
+
+test_done
diff --git a/t/t7521-ignored-mode.sh b/t/t7521-ignored-mode.sh
index a88b02b..edce10f 100755
--- a/t/t7521-ignored-mode.sh
+++ b/t/t7521-ignored-mode.sh
@@ -2,6 +2,7 @@
 
 test_description='git status ignored modes'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup initial commit and ignore file' '
diff --git a/t/t7524-commit-summary.sh b/t/t7524-commit-summary.sh
index 47b2f1d..a8fceb6 100755
--- a/t/t7524-commit-summary.sh
+++ b/t/t7524-commit-summary.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='git commit summary'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
index 730f3c7..9b15baa 100755
--- a/t/t7527-builtin-fsmonitor.sh
+++ b/t/t7527-builtin-fsmonitor.sh
@@ -907,6 +907,57 @@
 	test_subcommand git fsmonitor--daemon start <super-sub.trace
 '
 
+start_git_in_background () {
+	git "$@" &
+	git_pid=$!
+	git_pgid=$(ps -o pgid= -p $git_pid)
+	nr_tries_left=10
+	while true
+	do
+		if test $nr_tries_left -eq 0
+		then
+			kill -- -$git_pgid
+			exit 1
+		fi
+		sleep 1
+		nr_tries_left=$(($nr_tries_left - 1))
+	done >/dev/null 2>&1 &
+	watchdog_pid=$!
+	wait $git_pid
+}
+
+stop_git () {
+	while kill -0 -- -$git_pgid
+	do
+		kill -- -$git_pgid
+		sleep 1
+	done
+}
+
+stop_watchdog () {
+	while kill -0 $watchdog_pid
+	do
+		kill $watchdog_pid
+		sleep 1
+	done
+}
+
+test_expect_success !MINGW "submodule implicitly starts daemon by pull" '
+	test_atexit "stop_watchdog" &&
+	test_when_finished "stop_git; rm -rf cloned super sub" &&
+
+	create_super super &&
+	create_sub sub &&
+
+	git -C super submodule add ../sub ./dir_1/dir_2/sub &&
+	git -C super commit -m "add sub" &&
+	git clone --recurse-submodules super cloned &&
+
+	git -C cloned/dir_1/dir_2/sub config core.fsmonitor true &&
+	set -m &&
+	start_git_in_background -C cloned pull --recurse-submodules
+'
+
 # On a case-insensitive file system, confirm that the daemon
 # notices when the .git directory is moved/renamed/deleted
 # regardless of how it is spelled in the FS event.
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index a94387a..7fd8c08 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -4,6 +4,7 @@
 
 Testing pull.* configuration parsing and other things.'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t7615-diff-algo-with-mergy-operations.sh b/t/t7615-diff-algo-with-mergy-operations.sh
new file mode 100755
index 0000000..9a83be5
--- /dev/null
+++ b/t/t7615-diff-algo-with-mergy-operations.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+test_description='git merge and other operations that rely on merge
+
+Testing the influence of the diff algorithm on the merge output.'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	cp "$TEST_DIRECTORY"/t7615/base.c file.c &&
+	git add file.c &&
+	git commit -m c0 &&
+	git tag c0 &&
+	cp "$TEST_DIRECTORY"/t7615/ours.c file.c &&
+	git add file.c &&
+	git commit -m c1 &&
+	git tag c1 &&
+	git reset --hard c0 &&
+	cp "$TEST_DIRECTORY"/t7615/theirs.c file.c &&
+	git add file.c &&
+	git commit -m c2 &&
+	git tag c2
+'
+
+GIT_TEST_MERGE_ALGORITHM=recursive
+
+test_expect_success 'merge c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' '
+	git reset --hard c1 &&
+	test_must_fail git merge -s recursive c2
+'
+
+test_expect_success 'merge c2 to c1 with recursive merge strategy succeeds with -Xdiff-algorithm=histogram' '
+	git reset --hard c1 &&
+	git merge --strategy recursive -Xdiff-algorithm=histogram c2
+'
+
+test_expect_success 'merge c2 to c1 with recursive merge strategy succeeds with diff.algorithm = histogram' '
+	git reset --hard c1 &&
+	git config diff.algorithm histogram &&
+	git merge --strategy recursive c2
+'
+
+test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' '
+	git reset --hard c1 &&
+	test_must_fail git cherry-pick -s recursive c2
+'
+
+test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy succeeds with -Xdiff-algorithm=histogram' '
+	git reset --hard c1 &&
+	git cherry-pick --strategy recursive -Xdiff-algorithm=histogram c2
+'
+
+test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy succeeds with diff.algorithm = histogram' '
+	git reset --hard c1 &&
+	git config diff.algorithm histogram &&
+	git cherry-pick --strategy recursive c2
+'
+
+test_done
diff --git a/t/t7615/base.c b/t/t7615/base.c
new file mode 100644
index 0000000..c64abc5
--- /dev/null
+++ b/t/t7615/base.c
@@ -0,0 +1,17 @@
+int f(int x, int y)
+{
+        if (x == 0)
+        {
+                return y;
+        }
+        return x;
+}
+
+int g(size_t u)
+{
+        while (u < 30)
+        {
+                u++;
+        }
+        return u;
+}
diff --git a/t/t7615/ours.c b/t/t7615/ours.c
new file mode 100644
index 0000000..44d8251
--- /dev/null
+++ b/t/t7615/ours.c
@@ -0,0 +1,17 @@
+int g(size_t u)
+{
+        while (u < 30)
+        {
+                u++;
+        }
+        return u;
+}
+
+int h(int x, int y, int z)
+{
+        if (z == 0)
+        {
+                return x;
+        }
+        return y;
+}
diff --git a/t/t7615/theirs.c b/t/t7615/theirs.c
new file mode 100644
index 0000000..85f0214
--- /dev/null
+++ b/t/t7615/theirs.c
@@ -0,0 +1,17 @@
+int f(int x, int y)
+{
+        if (x == 0)
+        {
+                return y;
+        }
+        return x;
+}
+
+int g(size_t u)
+{
+        while (u > 34)
+        {
+                u--;
+        }
+        return u;
+}
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index 127efe9..c4c3d1a 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -2,11 +2,15 @@
 
 test_description='git repack works correctly'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "${TEST_DIRECTORY}/lib-bitmap.sh"
 . "${TEST_DIRECTORY}/lib-midx.sh"
 . "${TEST_DIRECTORY}/lib-terminal.sh"
 
+GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
+
 commit_and_pack () {
 	test_commit "$@" 1>&2 &&
 	incrpackid=$(git pack-objects --all --unpacked --incremental .git/objects/pack/pack </dev/null) &&
@@ -70,14 +74,13 @@
 
 test_expect_success 'writing bitmaps via command-line can duplicate .keep objects' '
 	# build on $oid, $packid, and .keep state from previous
-	GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 git repack -Adbl &&
+	git repack -Adbl &&
 	test_has_duplicate_object true
 '
 
 test_expect_success 'writing bitmaps via config can duplicate .keep objects' '
 	# build on $oid, $packid, and .keep state from previous
-	GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
-		git -c repack.writebitmaps=true repack -Adl &&
+	git -c repack.writebitmaps=true repack -Adl &&
 	test_has_duplicate_object true
 '
 
@@ -118,7 +121,7 @@
 	(
 		cd member &&
 		test_commit "object" &&
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adl --write-bitmap-index 2>err &&
+		git repack -Adl --write-bitmap-index 2>err &&
 		cat >expect <<-EOF &&
 		warning: disabling bitmap writing, as some objects are not being packed
 		EOF
@@ -284,8 +287,7 @@
 test_expect_success 'bitmaps are created by default in bare repos' '
 	git clone --bare .git bare.git &&
 	rm -f bare.git/objects/pack/*.bitmap &&
-	GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
-		git -C bare.git repack -ad &&
+	git -C bare.git repack -ad &&
 	bitmap=$(ls bare.git/objects/pack/*.bitmap) &&
 	test_path_is_file "$bitmap"
 '
@@ -296,8 +298,7 @@
 '
 
 test_expect_success 'bitmaps can be disabled on bare repos' '
-	GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
-		git -c repack.writeBitmaps=false -C bare.git repack -ad &&
+	git -c repack.writeBitmaps=false -C bare.git repack -ad &&
 	bitmap=$(ls bare.git/objects/pack/*.bitmap || :) &&
 	test -z "$bitmap"
 '
@@ -308,8 +309,7 @@
 	keep=${pack%.pack}.keep &&
 	test_when_finished "rm -f \"\$keep\"" &&
 	>"$keep" &&
-	GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
-		git -C bare.git repack -ad 2>stderr &&
+	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
@@ -320,8 +320,7 @@
 	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_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
-		git -C bare.git repack -ad 2>stderr &&
+	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
@@ -342,9 +341,7 @@
 '
 
 test_expect_success '--filter fails with --write-bitmap-index' '
-	test_must_fail \
-		env GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
-		git -C bare.git repack -a -d --write-bitmap-index --filter=blob:none
+	test_must_fail git -C bare.git repack -a -d --write-bitmap-index --filter=blob:none
 '
 
 test_expect_success 'repacking with two filters works' '
@@ -540,11 +537,11 @@
 test_expect_success '--write-midx unchanged' '
 	(
 		cd midx &&
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack &&
+		git repack &&
 		test_path_is_missing $midx &&
 		test_path_is_missing $midx-*.bitmap &&
 
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack --write-midx &&
+		git repack --write-midx &&
 
 		test_path_is_file $midx &&
 		test_path_is_missing $midx-*.bitmap &&
@@ -557,7 +554,7 @@
 		cd midx &&
 		test_commit loose &&
 
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack --write-midx &&
+		git repack --write-midx &&
 
 		test_path_is_file $midx &&
 		test_path_is_missing $midx-*.bitmap &&
@@ -568,7 +565,7 @@
 test_expect_success '--write-midx with -b' '
 	(
 		cd midx &&
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack -mb &&
+		git repack -mb &&
 
 		test_path_is_file $midx &&
 		test_path_is_file $midx-*.bitmap &&
@@ -581,7 +578,7 @@
 		cd midx &&
 		test_commit repack &&
 
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ad --write-midx &&
+		git repack -Ad --write-midx &&
 
 		test_path_is_file $midx &&
 		test_path_is_missing $midx-*.bitmap &&
@@ -594,21 +591,21 @@
 		cd midx &&
 
 		test_commit repack-2 &&
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx &&
+		git repack -Adb --write-midx &&
 
 		checksum=$(midx_checksum $objdir) &&
 		test_path_is_file $midx &&
 		test_path_is_file $midx-$checksum.bitmap &&
 
 		test_commit repack-3 &&
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx &&
+		git repack -Adb --write-midx &&
 
 		test_path_is_file $midx &&
 		test_path_is_missing $midx-$checksum.bitmap &&
 		test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
 
 		test_commit repack-4 &&
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb &&
+		git repack -Adb &&
 
 		find $objdir/pack -type f -name "multi-pack-index*" >files &&
 		test_must_be_empty files
@@ -629,7 +626,6 @@
 		git log --format="create refs/tags/%s/%s %H" HEAD >refs &&
 		git update-ref --stdin <refs &&
 
-		GIT_TEST_MULTI_PACK_INDEX=0 \
 		git repack --write-midx --write-bitmap-index &&
 		test_path_is_file $midx &&
 		test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
@@ -721,13 +717,13 @@
 	(
 		cd repo &&
 		test_commit base &&
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ab &&
+		git repack -Ab &&
 
 		pack_bitmap=$(ls $objdir/pack/pack-*.bitmap) &&
 		test_path_is_file "$pack_bitmap" &&
 
 		test_commit tip &&
-		GIT_TEST_MULTI_PACK_INDEX=0 git repack -bm &&
+		git repack -bm &&
 
 		test_path_is_file $midx &&
 		test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
@@ -750,7 +746,6 @@
 		keep="$objdir/pack/pack-$one.keep" &&
 		touch "$keep" &&
 
-		GIT_TEST_MULTI_PACK_INDEX=0 \
 		git repack --write-midx --write-bitmap-index --geometric=2 -d \
 			--pack-kept-objects &&
 
diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh
index 9fc1626..8877aea 100755
--- a/t/t7703-repack-geometric.sh
+++ b/t/t7703-repack-geometric.sh
@@ -2,6 +2,7 @@
 
 test_description='git repack --geometric works correctly'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 GIT_TEST_MULTI_PACK_INDEX=0
diff --git a/t/t7704-repack-cruft.sh b/t/t7704-repack-cruft.sh
index 71e1ef3..5db9f4e 100755
--- a/t/t7704-repack-cruft.sh
+++ b/t/t7704-repack-cruft.sh
@@ -2,6 +2,7 @@
 
 test_description='git repack works correctly'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 objdir=.git/objects
@@ -330,7 +331,7 @@
 		# repack (and prune) with a --max-cruft-size to ensure
 		# that we appropriately split the resulting set of packs
 		git repack -d --cruft --max-cruft-size=1M \
-			--cruft-expiration=10.seconds.ago &&
+			--cruft-expiration=1000.seconds.ago &&
 		ls $packdir/pack-*.mtimes | sort >cruft.after &&
 
 		for cruft in $(cat cruft.after)
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index cc917b2..f67b934 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -11,6 +11,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 difftool_test_setup ()
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 875dcfd..af2cf2f 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -31,6 +31,7 @@
 	return 0;
 	/* char ?? */
 }
+
 EOF
 
 test_expect_success setup '
diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh
index 167fe66..55ed630 100755
--- a/t/t7814-grep-recurse-submodules.sh
+++ b/t/t7814-grep-recurse-submodules.sh
@@ -7,6 +7,7 @@
 '
 
 TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
diff --git a/t/t7817-grep-sparse-checkout.sh b/t/t7817-grep-sparse-checkout.sh
index eb59564..0ba7817 100755
--- a/t/t7817-grep-sparse-checkout.sh
+++ b/t/t7817-grep-sparse-checkout.sh
@@ -33,6 +33,7 @@
 But note that sub2 should have the SKIP_WORKTREE bit set.
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index 8595489..c224c84 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -2,6 +2,7 @@
 
 test_description='git maintenance builtin'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 GIT_TEST_COMMIT_GRAPH=0
@@ -49,22 +50,47 @@
 		git maintenance run --auto 2>/dev/null &&
 	GIT_TRACE2_EVENT="$(pwd)/run-no-quiet.txt" \
 		git maintenance run --no-quiet 2>/dev/null &&
-	test_subcommand git gc --quiet <run-no-auto.txt &&
-	test_subcommand ! git gc --auto --quiet <run-auto.txt &&
-	test_subcommand git gc --no-quiet <run-no-quiet.txt
+	test_subcommand git gc --quiet --no-detach <run-no-auto.txt &&
+	test_subcommand ! git gc --auto --quiet --no-detach <run-auto.txt &&
+	test_subcommand git gc --no-quiet --no-detach <run-no-quiet.txt
 '
 
 test_expect_success 'maintenance.auto config option' '
 	GIT_TRACE2_EVENT="$(pwd)/default" git commit --quiet --allow-empty -m 1 &&
-	test_subcommand git maintenance run --auto --quiet <default &&
+	test_subcommand git maintenance run --auto --quiet --detach <default &&
 	GIT_TRACE2_EVENT="$(pwd)/true" \
 		git -c maintenance.auto=true \
 		commit --quiet --allow-empty -m 2 &&
-	test_subcommand git maintenance run --auto --quiet  <true &&
+	test_subcommand git maintenance run --auto --quiet --detach <true &&
 	GIT_TRACE2_EVENT="$(pwd)/false" \
 		git -c maintenance.auto=false \
 		commit --quiet --allow-empty -m 3 &&
-	test_subcommand ! git maintenance run --auto --quiet  <false
+	test_subcommand ! git maintenance run --auto --quiet --detach <false
+'
+
+for cfg in maintenance.autoDetach gc.autoDetach
+do
+	test_expect_success "$cfg=true config option" '
+		test_when_finished "rm -f trace" &&
+		test_config $cfg true &&
+		GIT_TRACE2_EVENT="$(pwd)/trace" git commit --quiet --allow-empty -m 1 &&
+		test_subcommand git maintenance run --auto --quiet --detach <trace
+	'
+
+	test_expect_success "$cfg=false config option" '
+		test_when_finished "rm -f trace" &&
+		test_config $cfg false &&
+		GIT_TRACE2_EVENT="$(pwd)/trace" git commit --quiet --allow-empty -m 1 &&
+		test_subcommand git maintenance run --auto --quiet --no-detach <trace
+	'
+done
+
+test_expect_success "maintenance.autoDetach overrides gc.autoDetach" '
+	test_when_finished "rm -f trace" &&
+	test_config maintenance.autoDetach false &&
+	test_config gc.autoDetach true &&
+	GIT_TRACE2_EVENT="$(pwd)/trace" git commit --quiet --allow-empty -m 1 &&
+	test_subcommand git maintenance run --auto --quiet --no-detach <trace
 '
 
 test_expect_success 'register uses XDG_CONFIG_HOME config if it exists' '
@@ -129,9 +155,9 @@
 		git maintenance run --task=commit-graph 2>/dev/null &&
 	GIT_TRACE2_EVENT="$(pwd)/run-both.txt" \
 		git maintenance run --task=commit-graph --task=gc 2>/dev/null &&
-	test_subcommand ! git gc --quiet <run-commit-graph.txt &&
-	test_subcommand git gc --quiet <run-gc.txt &&
-	test_subcommand git gc --quiet <run-both.txt &&
+	test_subcommand ! git gc --quiet --no-detach <run-commit-graph.txt &&
+	test_subcommand git gc --quiet --no-detach <run-gc.txt &&
+	test_subcommand git gc --quiet --no-detach <run-both.txt &&
 	test_subcommand git commit-graph write --split --reachable --no-progress <run-commit-graph.txt &&
 	test_subcommand ! git commit-graph write --split --reachable --no-progress <run-gc.txt &&
 	test_subcommand git commit-graph write --split --reachable --no-progress <run-both.txt
@@ -620,6 +646,22 @@
 		maintenance.repo "$(pwd)/$META"
 '
 
+test_expect_success 'start without GIT_TEST_MAINT_SCHEDULER' '
+	test_when_finished "rm -rf systemctl.log script repo" &&
+	mkdir script &&
+	write_script script/systemctl <<-\EOF &&
+	echo "$*" >>../systemctl.log
+	EOF
+	git init repo &&
+	(
+		cd repo &&
+		sane_unset GIT_TEST_MAINT_SCHEDULER &&
+		PATH="$PWD/../script:$PATH" git maintenance start --scheduler=systemd
+	) &&
+	test_grep -- "--user list-timers" systemctl.log &&
+	test_grep -- "enable --now git-maintenance@" systemctl.log
+'
+
 test_expect_success 'start --scheduler=<scheduler>' '
 	test_expect_code 129 git maintenance start --scheduler=foo 2>err &&
 	test_grep "unrecognized --scheduler argument" err &&
@@ -800,6 +842,9 @@
 	test_systemd_analyze_verify "systemd/user/git-maintenance@daily.service" &&
 	test_systemd_analyze_verify "systemd/user/git-maintenance@weekly.service" &&
 
+	grep "core.askPass=true" "systemd/user/git-maintenance@.service" &&
+	grep "credential.interactive=false" "systemd/user/git-maintenance@.service" &&
+
 	printf -- "--user enable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
 	test_cmp expect args &&
 
@@ -908,4 +953,62 @@
 	done
 '
 
+test_expect_success '--no-detach causes maintenance to not run in background' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+
+		# Prepare the repository such that git-maintenance(1) ends up
+		# outputting something.
+		test_commit something &&
+		git config set maintenance.gc.enabled false &&
+		git config set maintenance.loose-objects.enabled true &&
+		git config set maintenance.loose-objects.auto 1 &&
+		git config set maintenance.incremental-repack.enabled true &&
+
+		GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+			git maintenance run --no-detach >out 2>&1 &&
+		! test_region maintenance detach trace.txt
+	)
+'
+
+test_expect_success '--detach causes maintenance to run in background' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+
+		test_commit something &&
+		git config set maintenance.gc.enabled false &&
+		git config set maintenance.loose-objects.enabled true &&
+		git config set maintenance.loose-objects.auto 1 &&
+		git config set maintenance.incremental-repack.enabled true &&
+
+		# The extra file descriptor gets inherited to the child
+		# process, and by reading stdout we thus essentially wait for
+		# that descriptor to get closed, which indicates that the child
+		# is done, too.
+		does_not_matter=$(GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+			git maintenance run --detach 9>&1) &&
+		test_region maintenance detach trace.txt
+	)
+'
+
+test_expect_success 'repacking loose objects is quiet' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+
+		test_commit something &&
+		git config set maintenance.gc.enabled false &&
+		git config set maintenance.loose-objects.enabled true &&
+		git config set maintenance.loose-objects.auto 1 &&
+
+		git maintenance run --quiet >out 2>&1 &&
+		test_must_be_empty out
+	)
+'
+
 test_done
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 64a4ab3..e2430f7 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -1324,7 +1324,7 @@
 	Reviewed-by: Füñný Nâmé <odd_?=mail@example.com>
 	Reported-by: bugger on Jira
 	Reported-by: Douglas Reporter <doug@example.com> [from Jira profile]
-	BugID: 12345
+	BugID: 12345should-not-appear
 	Co-developed-by: "C. O. Developer" <codev@example.com>
 	Signed-off-by: A. U. Thor <thor.au@example.com>
 	EOF
@@ -1337,7 +1337,7 @@
 " <odd_?=mail@example.com>" actual-show-all-headers &&
 	test_grep "^(body) Ignoring Reported-by .* bugger on Jira" actual-show-all-headers &&
 	test_grep "^(body) Adding cc: Douglas Reporter <doug@example.com>" actual-show-all-headers &&
-	test_grep ! "12345" actual-show-all-headers &&
+	test_grep ! "12345should-not-appear" actual-show-all-headers &&
 	test_grep "^(body) Adding cc: \"C. O. Developer\" <codev@example.com>" actual-show-all-headers &&
 	test_grep "^(body) Adding cc: \"A. U. Thor\" <thor.au@example.com>" actual-show-all-headers
 '
@@ -2084,22 +2084,24 @@
 	'bob' \
 	'chloe' \
 	'eve' <<-\EOF
-	alias alice   Alice W Land <awol@example.com>
-	alias eve     Eve <eve@example.com>
-	alias bob     Robert Bobbyton <bob@example.com>
+	alias alice   "Alice W Land <awol@example.com>"
+	alias eve     "Eve <eve@example.com>"
+	alias bob     "Robert Bobbyton <bob@example.com>"
 	alias chloe   chloe@example.com
 	EOF
 
 test_dump_aliases '--dump-aliases pine format' \
 	'pine' \
 	'alice' \
+	'bcgrp' \
 	'bob' \
 	'chloe' \
 	'eve' <<-\EOF
-	alice	Alice W Land	<awol@example.com>
-	eve	Eve	<eve@example.com>
-	bob	Robert	Bobbyton <bob@example.com>
+	alice	Alice W Land	awol@example.com		Friend
+	eve	Eve	eve@example.com
+	bob	Robert Bobbyton	bob@example.com
 	chloe		chloe@example.com
+	bcgrp		(bob, chloe, Other <o@example.com>)
 	EOF
 
 test_dump_aliases '--dump-aliases gnus format' \
@@ -2118,6 +2120,110 @@
 	test_must_fail git send-email --dump-aliases --to=janice@example.com -1 refs/heads/accounting
 '
 
+test_translate_aliases () {
+	msg="$1" && shift &&
+	filetype="$1" && shift &&
+	aliases="$1" && shift &&
+	printf '%s\n' "$@" >expect &&
+	cat >.tmp-email-aliases &&
+	printf '%s\n' "$aliases" >aliases &&
+
+	test_expect_success $PREREQ "$msg" '
+		clean_fake_sendmail && rm -fr outdir &&
+		git config --replace-all sendemail.aliasesfile \
+			"$(pwd)/.tmp-email-aliases" &&
+		git config sendemail.aliasfiletype "$filetype" &&
+		git send-email --translate-aliases <aliases 2>errors >actual &&
+		test_cmp expect actual
+	'
+}
+
+test_translate_aliases '--translate-aliases sendmail format' \
+	'sendmail' \
+	'alice bcgrp' \
+	'Alice W Land <awol@example.com>' \
+	'Robert Bobbyton <bob@example.com>' \
+	'chloe@example.com' \
+	'Other <o@example.com>' <<-\EOF
+	alice: Alice W Land <awol@example.com>
+	bob: Robert Bobbyton <bob@example.com>
+	chloe: chloe@example.com
+	abgroup: alice, bob
+	bcgrp: bob, chloe, Other <o@example.com>
+	EOF
+
+test_translate_aliases '--translate-aliases mutt format' \
+	'mutt' \
+	'donald bob' \
+	'Donald C Carlton <donc@example.com>' \
+	'Robert Bobbyton <bob@example.com>' <<-\EOF
+	alias alice Alice W Land <awol@example.com>
+	alias donald Donald C Carlton <donc@example.com>
+	alias bob Robert Bobbyton <bob@example.com>
+	alias chloe chloe@example.com
+	EOF
+
+test_translate_aliases '--translate-aliases mailrc format' \
+	'mailrc' \
+	'chloe eve alice' \
+	'chloe@example.com' \
+	'Eve <eve@example.com>' \
+	'Alice W Land <awol@example.com>' <<-\EOF
+	alias alice   "Alice W Land <awol@example.com>"
+	alias eve     "Eve <eve@example.com>"
+	alias bob     "Robert Bobbyton <bob@example.com>"
+	alias chloe   chloe@example.com
+	EOF
+
+test_translate_aliases '--translate-aliases pine format' \
+	'pine' \
+	'eve bob bcgrp' \
+	'eve@example.com' \
+	'bob@example.com' \
+	'bob@example.com' \
+	'chloe@example.com' \
+	'Other <o@example.com>' <<-\EOF
+	alice	Alice W Land	awol@example.com		Friend
+	eve	Eve	eve@example.com
+	bob	Robert Bobbyton	bob@example.com
+	chloe		chloe@example.com
+	bcgrp		(bob, chloe, Other <o@example.com>)
+	EOF
+
+test_translate_aliases '--translate-aliases gnus format' \
+	'gnus' \
+	'alice chloe eve' \
+	'awol@example.com' \
+	'chloe@example.com' \
+	'eve@example.com' <<-\EOF
+	(define-mail-alias "alice" "awol@example.com")
+	(define-mail-alias "eve" "eve@example.com")
+	(define-mail-alias "bob" "bob@example.com")
+	(define-mail-alias "chloe" "chloe@example.com")
+	EOF
+
+test_expect_success $PREREQ '--translate-aliases passes valid addresses through' '
+	cat >expect <<-\EOF &&
+	Other <o@example.com>
+	EOF
+	cat >aliases <<-\EOF &&
+	Other <o@example.com>
+	EOF
+	git send-email --translate-aliases <aliases >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success $PREREQ '--translate-aliases passes unknown aliases through' '
+	cat >expect <<-\EOF &&
+	blargh
+	EOF
+	cat >aliases <<-\EOF &&
+	blargh
+	EOF
+	git send-email --translate-aliases <aliases >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success $PREREQ 'aliases and sendemail.identity' '
 	test_must_fail git \
 		-c sendemail.identity=cloud \
@@ -2379,6 +2485,128 @@
 	test_cmp expected-list actual-list
 '
 
+test_expect_success $PREREQ 'mailmap support with --to' '
+	clean_fake_sendmail &&
+	test_config mailmap.file "mailmap.test" &&
+	cat >mailmap.test <<-EOF &&
+	Some Body <someone@example.com> <someone@example.org>
+	EOF
+	git format-patch --stdout -1 >a.patch &&
+	git send-email \
+		--from="Example <nobody@example.com>" \
+		--smtp-server="$(pwd)/fake.sendmail" \
+		--to=someone@example.org \
+		--mailmap \
+		a.patch \
+		2>errors >out &&
+	grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.mailmap configuration' '
+	clean_fake_sendmail &&
+	test_config mailmap.file "mailmap.test" &&
+	test_config sendemail.mailmap "true" &&
+	cat >mailmap.test <<-EOF &&
+	Some Body <someone@example.com> <someone@example.org>
+	EOF
+	git format-patch --stdout -1 >a.patch &&
+	git send-email \
+		--from="Example <nobody@example.com>" \
+		--smtp-server="$(pwd)/fake.sendmail" \
+		--to=someone@example.org \
+		a.patch \
+		2>errors >out &&
+	grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.mailmap.file configuration' '
+	clean_fake_sendmail &&
+	test_config sendemail.mailmap.file "mailmap.test" &&
+	test_config sendemail.mailmap "true" &&
+	cat >mailmap.test <<-EOF &&
+	Some Body <someone@example.com> <someone@example.org>
+	EOF
+	git format-patch --stdout -1 >a.patch &&
+	git send-email \
+		--from="Example <nobody@example.com>" \
+		--smtp-server="$(pwd)/fake.sendmail" \
+		--to=someone@example.org \
+		a.patch \
+		2>errors >out &&
+	grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'sendemail.mailmap identity overrides configuration' '
+	clean_fake_sendmail &&
+	test_config sendemail.cloud.mailmap.file "mailmap.test" &&
+	test_config sendemail.mailmap "false" &&
+	test_config sendemail.cloud.mailmap "true" &&
+	cat >mailmap.test <<-EOF &&
+	Some Body <someone@example.com> <someone@example.org>
+	EOF
+	git format-patch --stdout -1 >a.patch &&
+	git send-email \
+		--from="Example <nobody@example.com>" \
+		--smtp-server="$(pwd)/fake.sendmail" \
+		--identity=cloud \
+		--to=someone@example.org \
+		a.patch \
+		2>errors >out &&
+	grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ '--no-mailmap overrides configuration' '
+	clean_fake_sendmail &&
+	test_config sendemail.cloud.mailmap.file "mailmap.test" &&
+	test_config sendemail.mailmap "false" &&
+	test_config sendemail.cloud.mailmap "true" &&
+	cat >mailmap.test <<-EOF &&
+	Some Body <someone@example.com> <someone@example.org>
+	EOF
+	git format-patch --stdout -1 >a.patch &&
+	git send-email \
+		--from="Example <nobody@example.com>" \
+		--smtp-server="$(pwd)/fake.sendmail" \
+		--identity=cloud \
+		--to=someone@example.org \
+		--no-mailmap \
+		a.patch \
+		2>errors >out &&
+	grep "^!someone@example\.org!$" commandline1
+'
+
+test_expect_success $PREREQ 'mailmap support in To header' '
+	clean_fake_sendmail &&
+	test_config mailmap.file "mailmap.test" &&
+	cat >mailmap.test <<-EOF &&
+	<someone@example.com> <someone@example.org>
+	EOF
+	git format-patch --stdout -1 --to=someone@example.org >a.patch &&
+	git send-email \
+		--from="Example <nobody@example.com>" \
+		--smtp-server="$(pwd)/fake.sendmail" \
+		--mailmap \
+		a.patch \
+		2>errors >out &&
+	grep "^!someone@example\.com!$" commandline1
+'
+
+test_expect_success $PREREQ 'mailmap support in Cc header' '
+	clean_fake_sendmail &&
+	test_config mailmap.file "mailmap.test" &&
+	cat >mailmap.test <<-EOF &&
+	<someone@example.com> <someone@example.org>
+	EOF
+	git format-patch --stdout -1 --cc=someone@example.org >a.patch &&
+	git send-email \
+		--from="Example <nobody@example.com>" \
+		--smtp-server="$(pwd)/fake.sendmail" \
+		--mailmap \
+		a.patch \
+		2>errors >out &&
+	grep "^!someone@example\.com!$" commandline1
+'
+
 test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '
 	clean_fake_sendmail &&
 	PATH="$PWD:$PATH" \
diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh
index a41b4fc..027235d 100755
--- a/t/t9210-scalar.sh
+++ b/t/t9210-scalar.sh
@@ -169,6 +169,24 @@
 	)
 '
 
+test_expect_success 'scalar clone --no-... opts' '
+	# Note: redirect stderr always to avoid having a verbose test
+	# run result in a difference in the --[no-]progress option.
+	GIT_TRACE2_EVENT="$(pwd)/no-opt-trace" scalar clone \
+		--no-tags --no-src \
+		"file://$(pwd)" no-opts --single-branch 2>/dev/null &&
+
+	test_subcommand git fetch --quiet --no-progress \
+			origin --no-tags <no-opt-trace &&
+	(
+		cd no-opts &&
+
+		test_cmp_config --no-tags remote.origin.tagopt &&
+		git for-each-ref --format="%(refname)" refs/tags/ >tags &&
+		test_line_count = 0 tags
+	)
+'
+
 test_expect_success 'scalar reconfigure' '
 	git init one/src &&
 	scalar register one &&
@@ -176,8 +194,11 @@
 	scalar reconfigure one &&
 	test true = "$(git -C one/src config core.preloadIndex)" &&
 	git -C one/src config core.preloadIndex false &&
-	scalar reconfigure -a &&
-	test true = "$(git -C one/src config core.preloadIndex)"
+	rm one/src/cron.txt &&
+	GIT_TRACE2_EVENT="$(pwd)/reconfigure" scalar reconfigure -a &&
+	test_path_is_file one/src/cron.txt &&
+	test true = "$(git -C one/src config core.preloadIndex)" &&
+	test_subcommand git maintenance start <reconfigure
 '
 
 test_expect_success 'scalar reconfigure --all with includeIf.onbranch' '
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 1e68426..3b3c371 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -7,6 +7,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash
 
diff --git a/t/t9304-fast-import-marks.sh b/t/t9304-fast-import-marks.sh
index 410a871..1f776a8 100755
--- a/t/t9304-fast-import-marks.sh
+++ b/t/t9304-fast-import-marks.sh
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test exotic situations with marks'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup dump of basic history' '
diff --git a/t/t9351-fast-export-anonymize.sh b/t/t9351-fast-export-anonymize.sh
index 156a647..c0d9d7b 100755
--- a/t/t9351-fast-export-anonymize.sh
+++ b/t/t9351-fast-export-anonymize.sh
@@ -4,6 +4,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup simple repo' '
diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh
index ccc8212..4431697 100755
--- a/t/t9700-perl-git.sh
+++ b/t/t9700-perl-git.sh
@@ -45,7 +45,8 @@
 '
 
 test_expect_success 'set up bare repository' '
-	git init --bare bare.git
+	git init --bare bare.git &&
+	git -C bare.git --work-tree=. commit --allow-empty -m "bare commit"
 '
 
 test_expect_success 'use t9700/test.pl to test Git.pm' '
diff --git a/t/t9700/test.pl b/t/t9700/test.pl
index d8e8548..2e1d50d 100755
--- a/t/t9700/test.pl
+++ b/t/t9700/test.pl
@@ -147,6 +147,11 @@
 unlink $tmpfile3;
 chdir($abs_repo_dir);
 
+# open alternate bare repo
+my $r4 = Git->repository(Directory => "$abs_repo_dir/bare.git");
+is($r4->command_oneline(qw(log --format=%s)), "bare commit",
+	"log of bare repo works");
+
 # unquoting paths
 is(Git::unquote_path('abc'), 'abc', 'unquote unquoted path');
 is(Git::unquote_path('"abc def"'), 'abc def', 'unquote simple quoted path');
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 932d5ad..cc6aa9f 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -16,6 +16,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./lib-bash.sh
 
 complete ()
diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh
index d667dda..95e9955 100755
--- a/t/t9903-bash-prompt.sh
+++ b/t/t9903-bash-prompt.sh
@@ -8,6 +8,7 @@
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./lib-bash.sh
 
 . "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh"
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index fde9bf5..78e054a 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -926,7 +926,8 @@
 		test_body_or_stdin test_body "$2"
 		test -n "$test_skip_test_preamble" ||
 		say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $test_body"
-		if test_run_ "$test_body"
+		if test_run_ "$test_body" &&
+		   check_test_results_san_file_empty_
 		then
 			test_ok_ "$1"
 		else
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 5424760..b1a8ee5 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -322,7 +322,6 @@
 TEST_RESULTS_SAN_DIR_SFX=leak
 TEST_RESULTS_SAN_FILE=
 TEST_RESULTS_SAN_DIR="$TEST_RESULTS_DIR/$TEST_NAME.$TEST_RESULTS_SAN_DIR_SFX"
-TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=
 TRASH_DIRECTORY="trash directory.$TEST_NAME$TEST_STRESS_JOB_SFX"
 test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY"
 case "$TRASH_DIRECTORY" in
@@ -848,6 +847,7 @@
 			GIT_EXIT_OK=t
 			exit 0
 		fi
+		check_test_results_san_file_ "$test_failure"
 		_error_exit
 	fi
 	finalize_test_case_output failure "$failure_label" "$@"
@@ -1215,42 +1215,16 @@
 	teardown_malloc_check
 }
 
-sanitize_leak_log_message_ () {
-	local new="$1" &&
-	local old="$2" &&
-	local file="$3" &&
-
-	printf "With SANITIZE=leak at exit we have %d leak logs, but started with %d
-
-This means that we have a blindspot where git is leaking but we're
-losing the exit code somewhere, or not propagating it appropriately
-upwards!
-
-See the logs at \"%s.*\";
-those logs are reproduced below." \
-	       "$new" "$old" "$file"
+check_test_results_san_file_empty_ () {
+	test -z "$TEST_RESULTS_SAN_FILE" ||
+	test "$(nr_san_dir_leaks_)" = 0
 }
 
 check_test_results_san_file_ () {
-	if test -z "$TEST_RESULTS_SAN_FILE"
+	if check_test_results_san_file_empty_
 	then
 		return
 	fi &&
-	local old="$TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP" &&
-	local new="$(nr_san_dir_leaks_)" &&
-
-	if test $new -le $old
-	then
-		return
-	fi &&
-	local out="$(sanitize_leak_log_message_ "$new" "$old" "$TEST_RESULTS_SAN_FILE")" &&
-	say_color error "$out" &&
-	if test "$old" != 0
-	then
-		echo &&
-		say_color error "The logs include output from past runs to avoid" &&
-		say_color error "that remove 'test-results' between runs."
-	fi &&
 	say_color error "$(cat "$TEST_RESULTS_SAN_FILE".*)" &&
 
 	if test -n "$passes_sanitize_leak" && test "$test_failure" = 0
@@ -1558,8 +1532,16 @@
 		passes_sanitize_leak=t
 	fi
 
-	if test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check"
+	if test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check" ||
+	   test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check-failing"
 	then
+		if test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check-failing" &&
+		   test -n "$passes_sanitize_leak"
+		then
+			skip_all="skipping leak-free $this_test under GIT_TEST_PASSING_SANITIZE_LEAK=check-failing"
+			test_done
+		fi
+
 		sanitize_leak_check=t
 		if test -n "$invert_exit_code"
 		then
@@ -1578,16 +1560,13 @@
 		test_done
 	fi
 
+	rm -rf "$TEST_RESULTS_SAN_DIR"
 	if ! mkdir -p "$TEST_RESULTS_SAN_DIR"
 	then
 		BAIL_OUT "cannot create $TEST_RESULTS_SAN_DIR"
 	fi &&
 	TEST_RESULTS_SAN_FILE="$TEST_RESULTS_SAN_DIR/$TEST_RESULTS_SAN_FILE_PFX"
 
-	# In case "test-results" is left over from a previous
-	# run: Only report if new leaks show up.
-	TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=$(nr_san_dir_leaks_)
-
 	# Don't litter *.leak dirs if there was nothing to report
 	test_atexit "rmdir \"$TEST_RESULTS_SAN_DIR\" 2>/dev/null || :"
 
@@ -1597,6 +1576,7 @@
 	export LSAN_OPTIONS
 
 elif test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check" ||
+     test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check-failing" ||
      test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
 then
 	BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_PASSING_SANITIZE_LEAK=true"
@@ -1606,7 +1586,7 @@
    test "${GIT_TEST_EXT_CHAIN_LINT:-1}" != 0
 then
 	"$PERL_PATH" "$TEST_DIRECTORY/chainlint.pl" "$0" ||
-		BUG "lint error (see '?!...!? annotations above)"
+		BUG "lint error (see 'LINT' annotations above)"
 fi
 
 # Last-minute variable setup
diff --git a/t/unit-tests/.gitignore b/t/unit-tests/.gitignore
index 5e56e04..d0632ec 100644
--- a/t/unit-tests/.gitignore
+++ b/t/unit-tests/.gitignore
@@ -1 +1,3 @@
 /bin
+/clar.suite
+/clar-decls.h
diff --git a/t/unit-tests/clar-generate.awk b/t/unit-tests/clar-generate.awk
new file mode 100644
index 0000000..ab71ce6
--- /dev/null
+++ b/t/unit-tests/clar-generate.awk
@@ -0,0 +1,50 @@
+function add_suite(suite, initialize, cleanup, count) {
+       if (!suite) return
+       suite_count++
+       callback_count += count
+       suites = suites "    {\n"
+       suites = suites "        \"" suite "\",\n"
+       suites = suites "        " initialize ",\n"
+       suites = suites "        " cleanup ",\n"
+       suites = suites "        _clar_cb_" suite ", " count ", 1\n"
+       suites = suites "    },\n"
+}
+
+BEGIN {
+       suites = "static struct clar_suite _clar_suites[] = {\n"
+}
+
+{
+       print
+       name = $3; sub(/\(.*$/, "", name)
+       suite = name; sub(/^test_/, "", suite); sub(/__.*$/, "", suite)
+       short_name = name; sub(/^.*__/, "", short_name)
+       cb = "{ \"" short_name "\", &" name " }"
+       if (suite != prev_suite) {
+               add_suite(prev_suite, initialize, cleanup, count)
+               if (callbacks) callbacks = callbacks "};\n"
+               callbacks = callbacks "static const struct clar_func _clar_cb_" suite "[] = {\n"
+               initialize = "{ NULL, NULL }"
+               cleanup = "{ NULL, NULL }"
+               count = 0
+               prev_suite = suite
+       }
+       if (short_name == "initialize") {
+               initialize = cb
+       } else if (short_name == "cleanup") {
+               cleanup = cb
+       } else {
+               callbacks = callbacks "    " cb ",\n"
+               count++
+       }
+}
+
+END {
+       add_suite(suite, initialize, cleanup, count)
+       suites = suites "};"
+       if (callbacks) callbacks = callbacks "};"
+       print callbacks
+       print suites
+       print "static const size_t _clar_suite_count = " suite_count ";"
+       print "static const size_t _clar_callback_count = " callback_count ";"
+}
diff --git a/t/unit-tests/clar/.github/workflows/ci.yml b/t/unit-tests/clar/.github/workflows/ci.yml
new file mode 100644
index 0000000..b1ac2de
--- /dev/null
+++ b/t/unit-tests/clar/.github/workflows/ci.yml
@@ -0,0 +1,23 @@
+name: CI
+
+on:
+  push:
+    branches: [ main ]
+  pull_request:
+    branches: [ main ]
+
+jobs:
+  build:
+    strategy:
+      matrix:
+        os: [ ubuntu-latest, macos-latest ]
+
+    runs-on: ${{ matrix.os }}
+
+    steps:
+    - name: Check out
+      uses: actions/checkout@v2
+    - name: Build
+      run: |
+        cd test
+        make
diff --git a/t/unit-tests/clar/COPYING b/t/unit-tests/clar/COPYING
new file mode 100644
index 0000000..8983817
--- /dev/null
+++ b/t/unit-tests/clar/COPYING
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2011-2015 Vicent Marti
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/t/unit-tests/clar/README.md b/t/unit-tests/clar/README.md
new file mode 100644
index 0000000..a8961c5
--- /dev/null
+++ b/t/unit-tests/clar/README.md
@@ -0,0 +1,329 @@
+Come out and Clar
+=================
+
+In Catalan, "clar" means clear, easy to perceive.  Using clar will make it
+easy to test and make clear the quality of your code.
+
+> _Historical note_
+>
+> Originally the clar project was named "clay" because the word "test" has its
+> roots in the latin word *"testum"*, meaning "earthen pot", and *"testa"*,
+> meaning "piece of burned clay"?
+>
+> This is because historically, testing implied melting metal in a pot to
+> check its quality.  Clay is what tests are made of.
+
+## Quick Usage Overview
+
+Clar is a minimal C unit testing framework. It's been written to replace the
+old framework in [libgit2][libgit2], but it's both very versatile and
+straightforward to use.
+
+Can you count to funk?
+
+- **Zero: Initialize test directory**
+
+    ~~~~ sh
+    $ mkdir tests
+    $ cp -r $CLAR_ROOT/clar* tests
+    $ cp $CLAR_ROOT/test/clar_test.h tests
+    $ cp $CLAR_ROOT/test/main.c.sample tests/main.c
+    ~~~~
+
+- **One: Write some tests**
+
+    File: tests/adding.c:
+
+    ~~~~ c
+    /* adding.c for the "Adding" suite */
+    #include "clar.h"
+
+    static int *answer;
+
+    void test_adding__initialize(void)
+    {
+        answer = malloc(sizeof(int));
+        cl_assert_(answer != NULL, "No memory left?");
+        *answer = 42;
+    }
+
+    void test_adding__cleanup(void)
+    {
+        free(answer);
+    }
+
+    void test_adding__make_sure_math_still_works(void)
+    {
+        cl_assert_(5 > 3, "Five should probably be greater than three");
+        cl_assert_(-5 < 2, "Negative numbers are small, I think");
+        cl_assert_(*answer == 42, "The universe is doing OK. And the initializer too.");
+    }
+    ~~~~~
+
+- **Two: Build the test executable**
+
+    ~~~~ sh
+    $ cd tests
+    $ $CLAR_PATH/generate.py .
+    Written `clar.suite` (1 suites)
+    $ gcc -I. clar.c main.c adding.c -o testit
+    ~~~~
+
+- **Funk: Funk it.**
+
+    ~~~~ sh
+    $ ./testit
+    ~~~~
+
+## The Clar Test Suite
+
+Writing a test suite is pretty straightforward. Each test suite is a `*.c`
+file with a descriptive name: this encourages modularity.
+
+Each test suite has optional initialize and cleanup methods. These methods
+will be called before and after running **each** test in the suite, even if
+such test fails. As a rule of thumb, if a test needs a different initializer
+or cleanup method than another test in the same module, that means it
+doesn't belong in that module. Keep that in mind when grouping tests
+together.
+
+The `initialize` and `cleanup` methods have the following syntax, with
+`suitename` being the current suite name, e.g. `adding` for the `adding.c`
+suite.
+
+~~~~ c
+void test_suitename__initialize(void)
+{
+    /* init */
+}
+
+void test_suitename__cleanup(void)
+{
+    /* cleanup */
+}
+~~~~
+
+These methods are encouraged to use static, global variables to store the state
+that will be used by all tests inside the suite.
+
+~~~~ c
+static git_repository *_repository;
+
+void test_status__initialize(void)
+{
+    create_tmp_repo(STATUS_REPO);
+    git_repository_open(_repository, STATUS_REPO);
+}
+
+void test_status__cleanup(void)
+{
+    git_repository_close(_repository);
+    git_path_rm(STATUS_REPO);
+}
+
+void test_status__simple_test(void)
+{
+    /* do something with _repository */
+}
+~~~~
+
+Writing the actual tests is just as straightforward. Tests have the
+`void test_suitename__test_name(void)` signature, and they should **not**
+be static. Clar will automatically detect and list them.
+
+Tests are run as they appear on their original suites: they have no return
+value. A test is considered "passed" if it doesn't raise any errors. Check
+the "Clar API" section to see the various helper functions to check and
+raise errors during test execution.
+
+__Caution:__ If you use assertions inside of `test_suitename__initialize`,
+make sure that you do not rely on `__initialize` being completely run
+inside your `test_suitename__cleanup` function. Otherwise you might
+encounter ressource cleanup twice.
+
+## How does Clar work?
+
+To use Clar:
+
+1. copy the Clar boilerplate to your test directory
+2. copy (and probably modify) the sample `main.c` (from
+   `$CLAR_PATH/test/main.c.sample`)
+3. run the Clar mixer (a.k.a. `generate.py`) to scan your test directory and
+   write out the test suite metadata.
+4. compile your test files and the Clar boilerplate into a single test
+   executable
+5. run the executable to test!
+
+The Clar boilerplate gives you a set of useful test assertions and features
+(like accessing or making sandbox copies of fixture data).  It consists of
+the `clar.c` and `clar.h` files, plus the code in the `clar/` subdirectory.
+You should not need to edit these files.
+
+The sample `main.c` (i.e. `$CLAR_PATH/test/main.c.sample`) file invokes
+`clar_test(argc, argv)` to run the tests.  Usually, you will edit this file
+to perform any framework specific initialization and teardown that you need.
+
+The Clar mixer (`generate.py`) recursively scans your test directory for
+any `.c` files, parses them, and writes the `clar.suite` file with all of
+the metadata about your tests.  When you build, the `clar.suite` file is
+included into `clar.c`.
+
+The mixer can be run with **Python 2.5, 2.6, 2.7, 3.0, 3.1, 3.2 and PyPy 1.6**.
+
+Commandline usage of the mixer is as follows:
+
+    $ ./generate.py .
+
+Where `.` is the folder where all the test suites can be found. The mixer
+will automatically locate all the relevant source files and build the
+testing metadata. The metadata will be written to `clar.suite`, in the same
+folder as all the test suites. This file is included by `clar.c` and so
+must be accessible via `#include` when building the test executable.
+
+    $ gcc -I. clar.c main.c suite1.c test2.c -o run_tests
+
+**Note that the Clar mixer only needs to be ran when adding new tests to a
+suite, in order to regenerate the metadata**. As a result, the `clar.suite`
+file can be checked into version control if you wish to be able to build
+your test suite without having to re-run the mixer.
+
+This is handy when e.g. generating tests in a local computer, and then
+building and testing them on an embedded device or a platform where Python
+is not available.
+
+### Fixtures
+
+Clar can create sandboxed fixtures for you to use in your test. You'll need to compile *clar.c* with an additional `CFLAG`, `-DCLAR_FIXTURE_PATH`. This should be an absolute path to your fixtures directory.
+
+Once that's done, you can use the fixture API as defined below.
+
+## The Clar API
+
+Clar makes the following methods available from all functions in a test
+suite.
+
+-   `cl_must_pass(call)`, `cl_must_pass_(call, message)`: Verify that the given
+    function call passes, in the POSIX sense (returns a value greater or equal
+    to 0).
+
+-   `cl_must_fail(call)`, `cl_must_fail_(call, message)`: Verify that the given
+    function call fails, in the POSIX sense (returns a value less than 0).
+
+-   `cl_assert(expr)`, `cl_assert_(expr, message)`: Verify that `expr` is true.
+
+-   `cl_check_pass(call)`, `cl_check_pass_(call, message)`: Verify that the
+    given function call passes, in the POSIX sense (returns a value greater or
+    equal to 0). If the function call doesn't succeed, a test failure will be
+    logged but the test's execution will continue.
+
+-   `cl_check_fail(call)`, `cl_check_fail_(call, message)`: Verify that the
+    given function call fails, in the POSIX sense (returns a value less than
+    0). If the function call doesn't fail, a test failure will be logged but
+    the test's execution will continue.
+
+-   `cl_check(expr)`: Verify that `expr` is true. If `expr` is not
+    true, a test failure will be logged but the test's execution will continue.
+
+-   `cl_fail(message)`: Fail the current test with the given message.
+
+-   `cl_warning(message)`: Issue a warning. This warning will be
+    logged as a test failure but the test's execution will continue.
+
+-   `cl_set_cleanup(void (*cleanup)(void *), void *opaque)`: Set the cleanup
+    method for a single test. This method will be called with `opaque` as its
+    argument before the test returns (even if the test has failed).
+    If a global cleanup method is also available, the local cleanup will be
+    called first, and then the global.
+
+-   `cl_assert_equal_i(int,int)`: Verify that two integer values are equal.
+    The advantage of this over a simple `cl_assert` is that it will format
+    a much nicer error report if the values are not equal.
+
+-   `cl_assert_equal_s(const char *,const char *)`: Verify that two strings
+    are equal.  The expected value can also be NULL and this will correctly
+    test for that.
+
+-   `cl_fixture_sandbox(const char *)`: Sets up a sandbox for a fixture
+    so that you can mutate the file directly.
+
+-   `cl_fixture_cleanup(const char *)`: Tears down the previous fixture
+    sandbox.
+
+-   `cl_fixture(const char *)`: Gets the full path to a fixture file.
+
+Please do note that these methods are *always* available whilst running a
+test, even when calling auxiliary/static functions inside the same file.
+
+It's strongly encouraged to perform test assertions in auxiliary methods,
+instead of returning error values. This is considered good Clar style.
+
+Style Example:
+
+~~~~ c
+/*
+ * Bad style: auxiliary functions return an error code
+ */
+
+static int check_string(const char *str)
+{
+    const char *aux = process_string(str);
+
+    if (aux == NULL)
+        return -1;
+
+    return strcmp(my_function(aux), str) == 0 ? 0 : -1;
+}
+
+void test_example__a_test_with_auxiliary_methods(void)
+{
+    cl_must_pass_(
+        check_string("foo"),
+        "String differs after processing"
+    );
+
+    cl_must_pass_(
+        check_string("bar"),
+        "String differs after processing"
+    );
+}
+~~~~
+
+~~~~ c
+/*
+ * Good style: auxiliary functions perform assertions
+ */
+
+static void check_string(const char *str)
+{
+    const char *aux = process_string(str);
+
+    cl_assert_(
+        aux != NULL,
+        "String processing failed"
+    );
+
+    cl_assert_(
+        strcmp(my_function(aux), str) == 0,
+        "String differs after processing"
+    );
+}
+
+void test_example__a_test_with_auxiliary_methods(void)
+{
+    check_string("foo");
+    check_string("bar");
+}
+~~~~
+
+About Clar
+==========
+
+Clar has been written from scratch by [Vicent Martí](https://github.com/vmg),
+to replace the old testing framework in [libgit2][libgit2].
+
+Do you know what languages are *in* on the SF startup scene? Node.js *and*
+Latin.  Follow [@vmg](https://www.twitter.com/vmg) on Twitter to
+receive more lessons on word etymology. You can be hip too.
+
+
+[libgit2]: https://github.com/libgit2/libgit2
diff --git a/t/unit-tests/clar/clar.c b/t/unit-tests/clar/clar.c
new file mode 100644
index 0000000..cef0f02
--- /dev/null
+++ b/t/unit-tests/clar/clar.c
@@ -0,0 +1,842 @@
+/*
+ * Copyright (c) Vicent Marti. All rights reserved.
+ *
+ * This file is part of clar, distributed under the ISC license.
+ * For full terms see the included COPYING file.
+ */
+#include <assert.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <time.h>
+
+/* required for sandboxing */
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#	define WIN32_LEAN_AND_MEAN
+#	include <windows.h>
+#	include <io.h>
+#	include <direct.h>
+
+#	define _MAIN_CC __cdecl
+
+#	ifndef stat
+#		define stat(path, st) _stat(path, st)
+#	endif
+#	ifndef mkdir
+#		define mkdir(path, mode) _mkdir(path)
+#	endif
+#	ifndef chdir
+#		define chdir(path) _chdir(path)
+#	endif
+#	ifndef access
+#		define access(path, mode) _access(path, mode)
+#	endif
+#	ifndef strdup
+#		define strdup(str) _strdup(str)
+#	endif
+#	ifndef strcasecmp
+#		define strcasecmp(a,b) _stricmp(a,b)
+#	endif
+
+#	ifndef __MINGW32__
+#		pragma comment(lib, "shell32")
+#		ifndef strncpy
+#			define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE)
+#		endif
+#		ifndef W_OK
+#			define W_OK 02
+#		endif
+#		ifndef S_ISDIR
+#			define S_ISDIR(x) ((x & _S_IFDIR) != 0)
+#		endif
+#		define p_snprintf(buf,sz,fmt,...) _snprintf_s(buf,sz,_TRUNCATE,fmt,__VA_ARGS__)
+#	else
+#		define p_snprintf snprintf
+#	endif
+
+#	ifndef PRIuZ
+#		define PRIuZ "Iu"
+#	endif
+#	ifndef PRIxZ
+#		define PRIxZ "Ix"
+#	endif
+
+#	if defined(_MSC_VER) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
+	typedef struct stat STAT_T;
+#	else
+	typedef struct _stat STAT_T;
+#	endif
+#else
+#	include <sys/wait.h> /* waitpid(2) */
+#	include <unistd.h>
+#	define _MAIN_CC
+#	define p_snprintf snprintf
+#	ifndef PRIuZ
+#		define PRIuZ "zu"
+#	endif
+#	ifndef PRIxZ
+#		define PRIxZ "zx"
+#	endif
+	typedef struct stat STAT_T;
+#endif
+
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+#include "clar.h"
+
+static void fs_rm(const char *_source);
+static void fs_copy(const char *_source, const char *dest);
+
+#ifdef CLAR_FIXTURE_PATH
+static const char *
+fixture_path(const char *base, const char *fixture_name);
+#endif
+
+struct clar_error {
+	const char *file;
+	const char *function;
+	size_t line_number;
+	const char *error_msg;
+	char *description;
+
+	struct clar_error *next;
+};
+
+struct clar_explicit {
+	size_t suite_idx;
+	const char *filter;
+
+	struct clar_explicit *next;
+};
+
+struct clar_report {
+	const char *test;
+	int test_number;
+	const char *suite;
+
+	enum cl_test_status status;
+	time_t start;
+	double elapsed;
+
+	struct clar_error *errors;
+	struct clar_error *last_error;
+
+	struct clar_report *next;
+};
+
+struct clar_summary {
+	const char *filename;
+	FILE *fp;
+};
+
+static struct {
+	enum cl_test_status test_status;
+
+	const char *active_test;
+	const char *active_suite;
+
+	int total_skipped;
+	int total_errors;
+
+	int tests_ran;
+	int suites_ran;
+
+	enum cl_output_format output_format;
+
+	int report_errors_only;
+	int exit_on_error;
+	int verbosity;
+
+	int write_summary;
+	char *summary_filename;
+	struct clar_summary *summary;
+
+	struct clar_explicit *explicit;
+	struct clar_explicit *last_explicit;
+
+	struct clar_report *reports;
+	struct clar_report *last_report;
+
+	void (*local_cleanup)(void *);
+	void *local_cleanup_payload;
+
+	jmp_buf trampoline;
+	int trampoline_enabled;
+
+	cl_trace_cb *pfn_trace_cb;
+	void *trace_payload;
+
+} _clar;
+
+struct clar_func {
+	const char *name;
+	void (*ptr)(void);
+};
+
+struct clar_suite {
+	const char *name;
+	struct clar_func initialize;
+	struct clar_func cleanup;
+	const struct clar_func *tests;
+	size_t test_count;
+	int enabled;
+};
+
+/* From clar_print_*.c */
+static void clar_print_init(int test_count, int suite_count, const char *suite_names);
+static void clar_print_shutdown(int test_count, int suite_count, int error_count);
+static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error);
+static void clar_print_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status failed);
+static void clar_print_onsuite(const char *suite_name, int suite_index);
+static void clar_print_onabort(const char *msg, ...);
+
+/* From clar_sandbox.c */
+static void clar_unsandbox(void);
+static int clar_sandbox(void);
+
+/* From summary.h */
+static struct clar_summary *clar_summary_init(const char *filename);
+static int clar_summary_shutdown(struct clar_summary *fp);
+
+/* Load the declarations for the test suite */
+#include "clar.suite"
+
+
+#define CL_TRACE(ev)													\
+	do {																\
+		if (_clar.pfn_trace_cb)											\
+			_clar.pfn_trace_cb(ev,										\
+							   _clar.active_suite,						\
+							   _clar.active_test,						\
+							   _clar.trace_payload);					\
+	} while (0)
+
+void cl_trace_register(cl_trace_cb *cb, void *payload)
+{
+	_clar.pfn_trace_cb = cb;
+	_clar.trace_payload = payload;
+}
+
+
+/* Core test functions */
+static void
+clar_report_errors(struct clar_report *report)
+{
+	struct clar_error *error;
+	int i = 1;
+
+	for (error = report->errors; error; error = error->next)
+		clar_print_error(i++, _clar.last_report, error);
+}
+
+static void
+clar_report_all(void)
+{
+	struct clar_report *report;
+	struct clar_error *error;
+	int i = 1;
+
+	for (report = _clar.reports; report; report = report->next) {
+		if (report->status != CL_TEST_FAILURE)
+			continue;
+
+		for (error = report->errors; error; error = error->next)
+			clar_print_error(i++, report, error);
+	}
+}
+
+#ifdef WIN32
+# define clar_time DWORD
+
+static void clar_time_now(clar_time *out)
+{
+	*out = GetTickCount();
+}
+
+static double clar_time_diff(clar_time *start, clar_time *end)
+{
+	return ((double)*end - (double)*start) / 1000;
+}
+#else
+# include <sys/time.h>
+
+# define clar_time struct timeval
+
+static void clar_time_now(clar_time *out)
+{
+	struct timezone tz;
+
+	gettimeofday(out, &tz);
+}
+
+static double clar_time_diff(clar_time *start, clar_time *end)
+{
+	return ((double)end->tv_sec + (double)end->tv_usec / 1.0E6) -
+	       ((double)start->tv_sec + (double)start->tv_usec / 1.0E6);
+}
+#endif
+
+static void
+clar_run_test(
+	const struct clar_suite *suite,
+	const struct clar_func *test,
+	const struct clar_func *initialize,
+	const struct clar_func *cleanup)
+{
+	clar_time start, end;
+
+	_clar.trampoline_enabled = 1;
+
+	CL_TRACE(CL_TRACE__TEST__BEGIN);
+
+	_clar.last_report->start = time(NULL);
+	clar_time_now(&start);
+
+	if (setjmp(_clar.trampoline) == 0) {
+		if (initialize->ptr != NULL)
+			initialize->ptr();
+
+		CL_TRACE(CL_TRACE__TEST__RUN_BEGIN);
+		test->ptr();
+		CL_TRACE(CL_TRACE__TEST__RUN_END);
+	}
+
+	clar_time_now(&end);
+
+	_clar.trampoline_enabled = 0;
+
+	if (_clar.last_report->status == CL_TEST_NOTRUN)
+		_clar.last_report->status = CL_TEST_OK;
+
+	_clar.last_report->elapsed = clar_time_diff(&start, &end);
+
+	if (_clar.local_cleanup != NULL)
+		_clar.local_cleanup(_clar.local_cleanup_payload);
+
+	if (cleanup->ptr != NULL)
+		cleanup->ptr();
+
+	CL_TRACE(CL_TRACE__TEST__END);
+
+	_clar.tests_ran++;
+
+	/* remove any local-set cleanup methods */
+	_clar.local_cleanup = NULL;
+	_clar.local_cleanup_payload = NULL;
+
+	if (_clar.report_errors_only) {
+		clar_report_errors(_clar.last_report);
+	} else {
+		clar_print_ontest(suite->name, test->name, _clar.tests_ran, _clar.last_report->status);
+	}
+}
+
+static void
+clar_run_suite(const struct clar_suite *suite, const char *filter)
+{
+	const struct clar_func *test = suite->tests;
+	size_t i, matchlen;
+	struct clar_report *report;
+	int exact = 0;
+
+	if (!suite->enabled)
+		return;
+
+	if (_clar.exit_on_error && _clar.total_errors)
+		return;
+
+	if (!_clar.report_errors_only)
+		clar_print_onsuite(suite->name, ++_clar.suites_ran);
+
+	_clar.active_suite = suite->name;
+	_clar.active_test = NULL;
+	CL_TRACE(CL_TRACE__SUITE_BEGIN);
+
+	if (filter) {
+		size_t suitelen = strlen(suite->name);
+		matchlen = strlen(filter);
+		if (matchlen <= suitelen) {
+			filter = NULL;
+		} else {
+			filter += suitelen;
+			while (*filter == ':')
+				++filter;
+			matchlen = strlen(filter);
+
+			if (matchlen && filter[matchlen - 1] == '$') {
+				exact = 1;
+				matchlen--;
+			}
+		}
+	}
+
+	for (i = 0; i < suite->test_count; ++i) {
+		if (filter && strncmp(test[i].name, filter, matchlen))
+			continue;
+
+		if (exact && strlen(test[i].name) != matchlen)
+			continue;
+
+		_clar.active_test = test[i].name;
+
+		report = calloc(1, sizeof(struct clar_report));
+		report->suite = _clar.active_suite;
+		report->test = _clar.active_test;
+		report->test_number = _clar.tests_ran;
+		report->status = CL_TEST_NOTRUN;
+
+		if (_clar.reports == NULL)
+			_clar.reports = report;
+
+		if (_clar.last_report != NULL)
+			_clar.last_report->next = report;
+
+		_clar.last_report = report;
+
+		clar_run_test(suite, &test[i], &suite->initialize, &suite->cleanup);
+
+		if (_clar.exit_on_error && _clar.total_errors)
+			return;
+	}
+
+	_clar.active_test = NULL;
+	CL_TRACE(CL_TRACE__SUITE_END);
+}
+
+static void
+clar_usage(const char *arg)
+{
+	printf("Usage: %s [options]\n\n", arg);
+	printf("Options:\n");
+	printf("  -sname        Run only the suite with `name` (can go to individual test name)\n");
+	printf("  -iname        Include the suite with `name`\n");
+	printf("  -xname        Exclude the suite with `name`\n");
+	printf("  -v            Increase verbosity (show suite names)\n");
+	printf("  -q            Only report tests that had an error\n");
+	printf("  -Q            Quit as soon as a test fails\n");
+	printf("  -t            Display results in tap format\n");
+	printf("  -l            Print suite names\n");
+	printf("  -r[filename]  Write summary file (to the optional filename)\n");
+	exit(-1);
+}
+
+static void
+clar_parse_args(int argc, char **argv)
+{
+	int i;
+
+	/* Verify options before execute */
+	for (i = 1; i < argc; ++i) {
+		char *argument = argv[i];
+
+		if (argument[0] != '-' || argument[1] == '\0'
+		    || strchr("sixvqQtlr", argument[1]) == NULL) {
+			clar_usage(argv[0]);
+		}
+	}
+
+	for (i = 1; i < argc; ++i) {
+		char *argument = argv[i];
+
+		switch (argument[1]) {
+		case 's':
+		case 'i':
+		case 'x': { /* given suite name */
+			int offset = (argument[2] == '=') ? 3 : 2, found = 0;
+			char action = argument[1];
+			size_t j, arglen, suitelen, cmplen;
+
+			argument += offset;
+			arglen = strlen(argument);
+
+			if (arglen == 0)
+				clar_usage(argv[0]);
+
+			for (j = 0; j < _clar_suite_count; ++j) {
+				suitelen = strlen(_clar_suites[j].name);
+				cmplen = (arglen < suitelen) ? arglen : suitelen;
+
+				if (strncmp(argument, _clar_suites[j].name, cmplen) == 0) {
+					int exact = (arglen >= suitelen);
+
+					/* Do we have a real suite prefix separated by a
+					 * trailing '::' or just a matching substring? */
+					if (arglen > suitelen && (argument[suitelen] != ':'
+						    || argument[suitelen + 1] != ':'))
+					    continue;
+
+					++found;
+
+					if (!exact)
+						_clar.verbosity = MAX(_clar.verbosity, 1);
+
+					switch (action) {
+					case 's': {
+						struct clar_explicit *explicit =
+							calloc(1, sizeof(struct clar_explicit));
+						assert(explicit);
+
+						explicit->suite_idx = j;
+						explicit->filter = argument;
+
+						if (_clar.explicit == NULL)
+							_clar.explicit = explicit;
+
+						if (_clar.last_explicit != NULL)
+							_clar.last_explicit->next = explicit;
+
+						_clar_suites[j].enabled = 1;
+						_clar.last_explicit = explicit;
+						break;
+					}
+					case 'i': _clar_suites[j].enabled = 1; break;
+					case 'x': _clar_suites[j].enabled = 0; break;
+					}
+
+					if (exact)
+						break;
+				}
+			}
+
+			if (!found) {
+				clar_print_onabort("No suite matching '%s' found.\n", argument);
+				exit(-1);
+			}
+			break;
+		}
+
+		case 'q':
+			_clar.report_errors_only = 1;
+			break;
+
+		case 'Q':
+			_clar.exit_on_error = 1;
+			break;
+
+		case 't':
+			_clar.output_format = CL_OUTPUT_TAP;
+			break;
+
+		case 'l': {
+			size_t j;
+			printf("Test suites (use -s<name> to run just one):\n");
+			for (j = 0; j < _clar_suite_count; ++j)
+				printf(" %3d: %s\n", (int)j, _clar_suites[j].name);
+
+			exit(0);
+		}
+
+		case 'v':
+			_clar.verbosity++;
+			break;
+
+		case 'r':
+			_clar.write_summary = 1;
+			free(_clar.summary_filename);
+			_clar.summary_filename = *(argument + 2) ? strdup(argument + 2) : NULL;
+			break;
+
+		default:
+			assert(!"Unexpected commandline argument!");
+		}
+	}
+}
+
+void
+clar_test_init(int argc, char **argv)
+{
+	const char *summary_env;
+
+	if (argc > 1)
+		clar_parse_args(argc, argv);
+
+	clar_print_init(
+		(int)_clar_callback_count,
+		(int)_clar_suite_count,
+		""
+	);
+
+	if (!_clar.summary_filename &&
+	    (summary_env = getenv("CLAR_SUMMARY")) != NULL) {
+		_clar.write_summary = 1;
+		_clar.summary_filename = strdup(summary_env);
+	}
+
+	if (_clar.write_summary && !_clar.summary_filename)
+		_clar.summary_filename = strdup("summary.xml");
+
+	if (_clar.write_summary &&
+	    !(_clar.summary = clar_summary_init(_clar.summary_filename))) {
+		clar_print_onabort("Failed to open the summary file\n");
+		exit(-1);
+	}
+
+	if (clar_sandbox() < 0) {
+		clar_print_onabort("Failed to sandbox the test runner.\n");
+		exit(-1);
+	}
+}
+
+int
+clar_test_run(void)
+{
+	size_t i;
+	struct clar_explicit *explicit;
+
+	if (_clar.explicit) {
+		for (explicit = _clar.explicit; explicit; explicit = explicit->next)
+			clar_run_suite(&_clar_suites[explicit->suite_idx], explicit->filter);
+	} else {
+		for (i = 0; i < _clar_suite_count; ++i)
+			clar_run_suite(&_clar_suites[i], NULL);
+	}
+
+	return _clar.total_errors;
+}
+
+void
+clar_test_shutdown(void)
+{
+	struct clar_explicit *explicit, *explicit_next;
+	struct clar_report *report, *report_next;
+
+	clar_print_shutdown(
+		_clar.tests_ran,
+		(int)_clar_suite_count,
+		_clar.total_errors
+	);
+
+	clar_unsandbox();
+
+	if (_clar.write_summary && clar_summary_shutdown(_clar.summary) < 0) {
+		clar_print_onabort("Failed to write the summary file\n");
+		exit(-1);
+	}
+
+	for (explicit = _clar.explicit; explicit; explicit = explicit_next) {
+		explicit_next = explicit->next;
+		free(explicit);
+	}
+
+	for (report = _clar.reports; report; report = report_next) {
+		report_next = report->next;
+		free(report);
+	}
+
+	free(_clar.summary_filename);
+}
+
+int
+clar_test(int argc, char **argv)
+{
+	int errors;
+
+	clar_test_init(argc, argv);
+	errors = clar_test_run();
+	clar_test_shutdown();
+
+	return errors;
+}
+
+static void abort_test(void)
+{
+	if (!_clar.trampoline_enabled) {
+		clar_print_onabort(
+				"Fatal error: a cleanup method raised an exception.");
+		clar_report_errors(_clar.last_report);
+		exit(-1);
+	}
+
+	CL_TRACE(CL_TRACE__TEST__LONGJMP);
+	longjmp(_clar.trampoline, -1);
+}
+
+void clar__skip(void)
+{
+	_clar.last_report->status = CL_TEST_SKIP;
+	_clar.total_skipped++;
+	abort_test();
+}
+
+void clar__fail(
+	const char *file,
+	const char *function,
+	size_t line,
+	const char *error_msg,
+	const char *description,
+	int should_abort)
+{
+	struct clar_error *error = calloc(1, sizeof(struct clar_error));
+
+	if (_clar.last_report->errors == NULL)
+		_clar.last_report->errors = error;
+
+	if (_clar.last_report->last_error != NULL)
+		_clar.last_report->last_error->next = error;
+
+	_clar.last_report->last_error = error;
+
+	error->file = file;
+	error->function = function;
+	error->line_number = line;
+	error->error_msg = error_msg;
+
+	if (description != NULL)
+		error->description = strdup(description);
+
+	_clar.total_errors++;
+	_clar.last_report->status = CL_TEST_FAILURE;
+
+	if (should_abort)
+		abort_test();
+}
+
+void clar__assert(
+	int condition,
+	const char *file,
+	const char *function,
+	size_t line,
+	const char *error_msg,
+	const char *description,
+	int should_abort)
+{
+	if (condition)
+		return;
+
+	clar__fail(file, function, line, error_msg, description, should_abort);
+}
+
+void clar__assert_equal(
+	const char *file,
+	const char *function,
+	size_t line,
+	const char *err,
+	int should_abort,
+	const char *fmt,
+	...)
+{
+	va_list args;
+	char buf[4096];
+	int is_equal = 1;
+
+	va_start(args, fmt);
+
+	if (!strcmp("%s", fmt)) {
+		const char *s1 = va_arg(args, const char *);
+		const char *s2 = va_arg(args, const char *);
+		is_equal = (!s1 || !s2) ? (s1 == s2) : !strcmp(s1, s2);
+
+		if (!is_equal) {
+			if (s1 && s2) {
+				int pos;
+				for (pos = 0; s1[pos] == s2[pos] && s1[pos] && s2[pos]; ++pos)
+					/* find differing byte offset */;
+				p_snprintf(buf, sizeof(buf), "'%s' != '%s' (at byte %d)",
+					s1, s2, pos);
+			} else {
+				p_snprintf(buf, sizeof(buf), "'%s' != '%s'", s1, s2);
+			}
+		}
+	}
+	else if(!strcmp("%.*s", fmt)) {
+		const char *s1 = va_arg(args, const char *);
+		const char *s2 = va_arg(args, const char *);
+		int len = va_arg(args, int);
+		is_equal = (!s1 || !s2) ? (s1 == s2) : !strncmp(s1, s2, len);
+
+		if (!is_equal) {
+			if (s1 && s2) {
+				int pos;
+				for (pos = 0; s1[pos] == s2[pos] && pos < len; ++pos)
+					/* find differing byte offset */;
+				p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s' (at byte %d)",
+					len, s1, len, s2, pos);
+			} else {
+				p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s'", len, s1, len, s2);
+			}
+		}
+	}
+	else if (!strcmp("%ls", fmt)) {
+		const wchar_t *wcs1 = va_arg(args, const wchar_t *);
+		const wchar_t *wcs2 = va_arg(args, const wchar_t *);
+		is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcscmp(wcs1, wcs2);
+
+		if (!is_equal) {
+			if (wcs1 && wcs2) {
+				int pos;
+				for (pos = 0; wcs1[pos] == wcs2[pos] && wcs1[pos] && wcs2[pos]; ++pos)
+					/* find differing byte offset */;
+				p_snprintf(buf, sizeof(buf), "'%ls' != '%ls' (at byte %d)",
+					wcs1, wcs2, pos);
+			} else {
+				p_snprintf(buf, sizeof(buf), "'%ls' != '%ls'", wcs1, wcs2);
+			}
+		}
+	}
+	else if(!strcmp("%.*ls", fmt)) {
+		const wchar_t *wcs1 = va_arg(args, const wchar_t *);
+		const wchar_t *wcs2 = va_arg(args, const wchar_t *);
+		int len = va_arg(args, int);
+		is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcsncmp(wcs1, wcs2, len);
+
+		if (!is_equal) {
+			if (wcs1 && wcs2) {
+				int pos;
+				for (pos = 0; wcs1[pos] == wcs2[pos] && pos < len; ++pos)
+					/* find differing byte offset */;
+				p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls' (at byte %d)",
+					len, wcs1, len, wcs2, pos);
+			} else {
+				p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls'", len, wcs1, len, wcs2);
+			}
+		}
+	}
+	else if (!strcmp("%"PRIuZ, fmt) || !strcmp("%"PRIxZ, fmt)) {
+		size_t sz1 = va_arg(args, size_t), sz2 = va_arg(args, size_t);
+		is_equal = (sz1 == sz2);
+		if (!is_equal) {
+			int offset = p_snprintf(buf, sizeof(buf), fmt, sz1);
+			strncat(buf, " != ", sizeof(buf) - offset);
+			p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, sz2);
+		}
+	}
+	else if (!strcmp("%p", fmt)) {
+		void *p1 = va_arg(args, void *), *p2 = va_arg(args, void *);
+		is_equal = (p1 == p2);
+		if (!is_equal)
+			p_snprintf(buf, sizeof(buf), "%p != %p", p1, p2);
+	}
+	else {
+		int i1 = va_arg(args, int), i2 = va_arg(args, int);
+		is_equal = (i1 == i2);
+		if (!is_equal) {
+			int offset = p_snprintf(buf, sizeof(buf), fmt, i1);
+			strncat(buf, " != ", sizeof(buf) - offset);
+			p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, i2);
+		}
+	}
+
+	va_end(args);
+
+	if (!is_equal)
+		clar__fail(file, function, line, err, buf, should_abort);
+}
+
+void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
+{
+	_clar.local_cleanup = cleanup;
+	_clar.local_cleanup_payload = opaque;
+}
+
+#include "clar/sandbox.h"
+#include "clar/fixtures.h"
+#include "clar/fs.h"
+#include "clar/print.h"
+#include "clar/summary.h"
diff --git a/t/unit-tests/clar/clar.h b/t/unit-tests/clar/clar.h
new file mode 100644
index 0000000..8c22382
--- /dev/null
+++ b/t/unit-tests/clar/clar.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) Vicent Marti. All rights reserved.
+ *
+ * This file is part of clar, distributed under the ISC license.
+ * For full terms see the included COPYING file.
+ */
+#ifndef __CLAR_TEST_H__
+#define __CLAR_TEST_H__
+
+#include <stdlib.h>
+
+enum cl_test_status {
+	CL_TEST_OK,
+	CL_TEST_FAILURE,
+	CL_TEST_SKIP,
+	CL_TEST_NOTRUN,
+};
+
+enum cl_output_format {
+	CL_OUTPUT_CLAP,
+	CL_OUTPUT_TAP,
+};
+
+/** Setup clar environment */
+void clar_test_init(int argc, char *argv[]);
+int clar_test_run(void);
+void clar_test_shutdown(void);
+
+/** One shot setup & run */
+int clar_test(int argc, char *argv[]);
+
+const char *clar_sandbox_path(void);
+
+void cl_set_cleanup(void (*cleanup)(void *), void *opaque);
+void cl_fs_cleanup(void);
+
+/**
+ * cl_trace_* is a hook to provide a simple global tracing
+ * mechanism.
+ *
+ * The goal here is to let main() provide clar-proper
+ * with a callback to optionally write log info for
+ * test operations into the same stream used by their
+ * actual tests.  This would let them print test names
+ * and maybe performance data as they choose.
+ *
+ * The goal is NOT to alter the flow of control or to
+ * override test selection/skipping.  (So the callback
+ * does not return a value.)
+ *
+ * The goal is NOT to duplicate the existing
+ * pass/fail/skip reporting.  (So the callback
+ * does not accept a status/errorcode argument.)
+ *
+ */
+typedef enum cl_trace_event {
+	CL_TRACE__SUITE_BEGIN,
+	CL_TRACE__SUITE_END,
+	CL_TRACE__TEST__BEGIN,
+	CL_TRACE__TEST__END,
+	CL_TRACE__TEST__RUN_BEGIN,
+	CL_TRACE__TEST__RUN_END,
+	CL_TRACE__TEST__LONGJMP,
+} cl_trace_event;
+
+typedef void (cl_trace_cb)(
+	cl_trace_event ev,
+	const char *suite_name,
+	const char *test_name,
+	void *payload);
+
+/**
+ * Register a callback into CLAR to send global trace events.
+ * Pass NULL to disable.
+ */
+void cl_trace_register(cl_trace_cb *cb, void *payload);
+
+
+#ifdef CLAR_FIXTURE_PATH
+const char *cl_fixture(const char *fixture_name);
+void cl_fixture_sandbox(const char *fixture_name);
+void cl_fixture_cleanup(const char *fixture_name);
+const char *cl_fixture_basename(const char *fixture_name);
+#endif
+
+/**
+ * Assertion macros with explicit error message
+ */
+#define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 1)
+#define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 1)
+#define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 1)
+
+/**
+ * Check macros with explicit error message
+ */
+#define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 0)
+#define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 0)
+#define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 0)
+
+/**
+ * Assertion macros with no error message
+ */
+#define cl_must_pass(expr) cl_must_pass_(expr, NULL)
+#define cl_must_fail(expr) cl_must_fail_(expr, NULL)
+#define cl_assert(expr) cl_assert_(expr, NULL)
+
+/**
+ * Check macros with no error message
+ */
+#define cl_check_pass(expr) cl_check_pass_(expr, NULL)
+#define cl_check_fail(expr) cl_check_fail_(expr, NULL)
+#define cl_check(expr) cl_check_(expr, NULL)
+
+/**
+ * Forced failure/warning
+ */
+#define cl_fail(desc) clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1)
+#define cl_warning(desc) clar__fail(__FILE__, __func__, __LINE__, "Warning during test execution:", desc, 0)
+
+#define cl_skip() clar__skip()
+
+/**
+ * Typed assertion macros
+ */
+#define cl_assert_equal_s(s1,s2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2))
+#define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2))
+
+#define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2))
+#define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2))
+
+#define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len))
+#define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len))
+
+#define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len))
+#define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len))
+
+#define cl_assert_equal_i(i1,i2) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
+#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2))
+#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2))
+
+#define cl_assert_equal_b(b1,b2) clar__assert_equal(__FILE__,__func__,__LINE__,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0))
+
+#define cl_assert_equal_p(p1,p2) clar__assert_equal(__FILE__,__func__,__LINE__,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2))
+
+void clar__skip(void);
+
+void clar__fail(
+	const char *file,
+	const char *func,
+	size_t line,
+	const char *error,
+	const char *description,
+	int should_abort);
+
+void clar__assert(
+	int condition,
+	const char *file,
+	const char *func,
+	size_t line,
+	const char *error,
+	const char *description,
+	int should_abort);
+
+void clar__assert_equal(
+	const char *file,
+	const char *func,
+	size_t line,
+	const char *err,
+	int should_abort,
+	const char *fmt,
+	...);
+
+#endif
diff --git a/t/unit-tests/clar/clar/fixtures.h b/t/unit-tests/clar/clar/fixtures.h
new file mode 100644
index 0000000..6ec6423
--- /dev/null
+++ b/t/unit-tests/clar/clar/fixtures.h
@@ -0,0 +1,50 @@
+#ifdef CLAR_FIXTURE_PATH
+static const char *
+fixture_path(const char *base, const char *fixture_name)
+{
+	static char _path[4096];
+	size_t root_len;
+
+	root_len = strlen(base);
+	strncpy(_path, base, sizeof(_path));
+
+	if (_path[root_len - 1] != '/')
+		_path[root_len++] = '/';
+
+	if (fixture_name[0] == '/')
+		fixture_name++;
+
+	strncpy(_path + root_len,
+		fixture_name,
+		sizeof(_path) - root_len);
+
+	return _path;
+}
+
+const char *cl_fixture(const char *fixture_name)
+{
+	return fixture_path(CLAR_FIXTURE_PATH, fixture_name);
+}
+
+void cl_fixture_sandbox(const char *fixture_name)
+{
+	fs_copy(cl_fixture(fixture_name), _clar_path);
+}
+
+const char *cl_fixture_basename(const char *fixture_name)
+{
+	const char *p;
+
+	for (p = fixture_name; *p; p++) {
+		if (p[0] == '/' && p[1] && p[1] != '/')
+			fixture_name = p+1;
+	}
+
+	return fixture_name;
+}
+
+void cl_fixture_cleanup(const char *fixture_name)
+{
+	fs_rm(fixture_path(_clar_path, cl_fixture_basename(fixture_name)));
+}
+#endif
diff --git a/t/unit-tests/clar/clar/fs.h b/t/unit-tests/clar/clar/fs.h
new file mode 100644
index 0000000..8b20617
--- /dev/null
+++ b/t/unit-tests/clar/clar/fs.h
@@ -0,0 +1,524 @@
+/*
+ * By default, use a read/write loop to copy files on POSIX systems.
+ * On Linux, use sendfile by default as it's slightly faster.  On
+ * macOS, we avoid fcopyfile by default because it's slightly slower.
+ */
+#undef USE_FCOPYFILE
+#define USE_SENDFILE 1
+
+#ifdef _WIN32
+
+#ifdef CLAR_WIN32_LONGPATHS
+# define CLAR_MAX_PATH 4096
+#else
+# define CLAR_MAX_PATH MAX_PATH
+#endif
+
+#define RM_RETRY_COUNT	5
+#define RM_RETRY_DELAY	10
+
+#ifdef __MINGW32__
+
+/* These security-enhanced functions are not available
+ * in MinGW, so just use the vanilla ones */
+#define wcscpy_s(a, b, c) wcscpy((a), (c))
+#define wcscat_s(a, b, c) wcscat((a), (c))
+
+#endif /* __MINGW32__ */
+
+static int
+fs__dotordotdot(WCHAR *_tocheck)
+{
+	return _tocheck[0] == '.' &&
+		(_tocheck[1] == '\0' ||
+		 (_tocheck[1] == '.' && _tocheck[2] == '\0'));
+}
+
+static int
+fs_rmdir_rmdir(WCHAR *_wpath)
+{
+	unsigned retries = 1;
+
+	while (!RemoveDirectoryW(_wpath)) {
+		/* Only retry when we have retries remaining, and the
+		 * error was ERROR_DIR_NOT_EMPTY. */
+		if (retries++ > RM_RETRY_COUNT ||
+			ERROR_DIR_NOT_EMPTY != GetLastError())
+			return -1;
+
+		/* Give whatever has a handle to a child item some time
+		 * to release it before trying again */
+		Sleep(RM_RETRY_DELAY * retries * retries);
+	}
+
+	return 0;
+}
+
+static void translate_path(WCHAR *path, size_t path_size)
+{
+    size_t path_len, i;
+
+    if (wcsncmp(path, L"\\\\?\\", 4) == 0)
+	return;
+
+    path_len = wcslen(path);
+    cl_assert(path_size > path_len + 4);
+
+    for (i = path_len; i > 0; i--) {
+	WCHAR c = path[i - 1];
+
+	if (c == L'/')
+	    path[i + 3] = L'\\';
+	else
+	    path[i + 3] = path[i - 1];
+    }
+
+    path[0] = L'\\';
+    path[1] = L'\\';
+    path[2] = L'?';
+    path[3] = L'\\';
+    path[path_len + 4] = L'\0';
+}
+
+static void
+fs_rmdir_helper(WCHAR *_wsource)
+{
+	WCHAR buffer[CLAR_MAX_PATH];
+	HANDLE find_handle;
+	WIN32_FIND_DATAW find_data;
+	size_t buffer_prefix_len;
+
+	/* Set up the buffer and capture the length */
+	wcscpy_s(buffer, CLAR_MAX_PATH, _wsource);
+	translate_path(buffer, CLAR_MAX_PATH);
+	wcscat_s(buffer, CLAR_MAX_PATH, L"\\");
+	buffer_prefix_len = wcslen(buffer);
+
+	/* FindFirstFile needs a wildcard to match multiple items */
+	wcscat_s(buffer, CLAR_MAX_PATH, L"*");
+	find_handle = FindFirstFileW(buffer, &find_data);
+	cl_assert(INVALID_HANDLE_VALUE != find_handle);
+
+	do {
+		/* FindFirstFile/FindNextFile gives back . and ..
+		 * entries at the beginning */
+		if (fs__dotordotdot(find_data.cFileName))
+			continue;
+
+		wcscpy_s(buffer + buffer_prefix_len, CLAR_MAX_PATH - buffer_prefix_len, find_data.cFileName);
+
+		if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes)
+			fs_rmdir_helper(buffer);
+		else {
+			/* If set, the +R bit must be cleared before deleting */
+			if (FILE_ATTRIBUTE_READONLY & find_data.dwFileAttributes)
+				cl_assert(SetFileAttributesW(buffer, find_data.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY));
+
+			cl_assert(DeleteFileW(buffer));
+		}
+	}
+	while (FindNextFileW(find_handle, &find_data));
+
+	/* Ensure that we successfully completed the enumeration */
+	cl_assert(ERROR_NO_MORE_FILES == GetLastError());
+
+	/* Close the find handle */
+	FindClose(find_handle);
+
+	/* Now that the directory is empty, remove it */
+	cl_assert(0 == fs_rmdir_rmdir(_wsource));
+}
+
+static int
+fs_rm_wait(WCHAR *_wpath)
+{
+	unsigned retries = 1;
+	DWORD last_error;
+
+	do {
+		if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(_wpath))
+			last_error = GetLastError();
+		else
+			last_error = ERROR_SUCCESS;
+
+		/* Is the item gone? */
+		if (ERROR_FILE_NOT_FOUND == last_error ||
+			ERROR_PATH_NOT_FOUND == last_error)
+			return 0;
+
+		Sleep(RM_RETRY_DELAY * retries * retries);
+	}
+	while (retries++ <= RM_RETRY_COUNT);
+
+	return -1;
+}
+
+static void
+fs_rm(const char *_source)
+{
+	WCHAR wsource[CLAR_MAX_PATH];
+	DWORD attrs;
+
+	/* The input path is UTF-8. Convert it to wide characters
+	 * for use with the Windows API */
+	cl_assert(MultiByteToWideChar(CP_UTF8,
+				MB_ERR_INVALID_CHARS,
+				_source,
+				-1, /* Indicates NULL termination */
+				wsource,
+				CLAR_MAX_PATH));
+
+	translate_path(wsource, CLAR_MAX_PATH);
+
+	/* Does the item exist? If not, we have no work to do */
+	attrs = GetFileAttributesW(wsource);
+
+	if (INVALID_FILE_ATTRIBUTES == attrs)
+		return;
+
+	if (FILE_ATTRIBUTE_DIRECTORY & attrs)
+		fs_rmdir_helper(wsource);
+	else {
+		/* The item is a file. Strip the +R bit */
+		if (FILE_ATTRIBUTE_READONLY & attrs)
+			cl_assert(SetFileAttributesW(wsource, attrs & ~FILE_ATTRIBUTE_READONLY));
+
+		cl_assert(DeleteFileW(wsource));
+	}
+
+	/* Wait for the DeleteFile or RemoveDirectory call to complete */
+	cl_assert(0 == fs_rm_wait(wsource));
+}
+
+static void
+fs_copydir_helper(WCHAR *_wsource, WCHAR *_wdest)
+{
+	WCHAR buf_source[CLAR_MAX_PATH], buf_dest[CLAR_MAX_PATH];
+	HANDLE find_handle;
+	WIN32_FIND_DATAW find_data;
+	size_t buf_source_prefix_len, buf_dest_prefix_len;
+
+	wcscpy_s(buf_source, CLAR_MAX_PATH, _wsource);
+	wcscat_s(buf_source, CLAR_MAX_PATH, L"\\");
+	translate_path(buf_source, CLAR_MAX_PATH);
+	buf_source_prefix_len = wcslen(buf_source);
+
+	wcscpy_s(buf_dest, CLAR_MAX_PATH, _wdest);
+	wcscat_s(buf_dest, CLAR_MAX_PATH, L"\\");
+	translate_path(buf_dest, CLAR_MAX_PATH);
+	buf_dest_prefix_len = wcslen(buf_dest);
+
+	/* Get an enumerator for the items in the source. */
+	wcscat_s(buf_source, CLAR_MAX_PATH, L"*");
+	find_handle = FindFirstFileW(buf_source, &find_data);
+	cl_assert(INVALID_HANDLE_VALUE != find_handle);
+
+	/* Create the target directory. */
+	cl_assert(CreateDirectoryW(_wdest, NULL));
+
+	do {
+		/* FindFirstFile/FindNextFile gives back . and ..
+		 * entries at the beginning */
+		if (fs__dotordotdot(find_data.cFileName))
+			continue;
+
+		wcscpy_s(buf_source + buf_source_prefix_len, CLAR_MAX_PATH - buf_source_prefix_len, find_data.cFileName);
+		wcscpy_s(buf_dest + buf_dest_prefix_len, CLAR_MAX_PATH - buf_dest_prefix_len, find_data.cFileName);
+
+		if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes)
+			fs_copydir_helper(buf_source, buf_dest);
+		else
+			cl_assert(CopyFileW(buf_source, buf_dest, TRUE));
+	}
+	while (FindNextFileW(find_handle, &find_data));
+
+	/* Ensure that we successfully completed the enumeration */
+	cl_assert(ERROR_NO_MORE_FILES == GetLastError());
+
+	/* Close the find handle */
+	FindClose(find_handle);
+}
+
+static void
+fs_copy(const char *_source, const char *_dest)
+{
+	WCHAR wsource[CLAR_MAX_PATH], wdest[CLAR_MAX_PATH];
+	DWORD source_attrs, dest_attrs;
+	HANDLE find_handle;
+	WIN32_FIND_DATAW find_data;
+
+	/* The input paths are UTF-8. Convert them to wide characters
+	 * for use with the Windows API. */
+	cl_assert(MultiByteToWideChar(CP_UTF8,
+				MB_ERR_INVALID_CHARS,
+				_source,
+				-1,
+				wsource,
+				CLAR_MAX_PATH));
+
+	cl_assert(MultiByteToWideChar(CP_UTF8,
+				MB_ERR_INVALID_CHARS,
+				_dest,
+				-1,
+				wdest,
+				CLAR_MAX_PATH));
+
+	translate_path(wsource, CLAR_MAX_PATH);
+	translate_path(wdest, CLAR_MAX_PATH);
+
+	/* Check the source for existence */
+	source_attrs = GetFileAttributesW(wsource);
+	cl_assert(INVALID_FILE_ATTRIBUTES != source_attrs);
+
+	/* Check the target for existence */
+	dest_attrs = GetFileAttributesW(wdest);
+
+	if (INVALID_FILE_ATTRIBUTES != dest_attrs) {
+		/* Target exists; append last path part of source to target.
+		 * Use FindFirstFile to parse the path */
+		find_handle = FindFirstFileW(wsource, &find_data);
+		cl_assert(INVALID_HANDLE_VALUE != find_handle);
+		wcscat_s(wdest, CLAR_MAX_PATH, L"\\");
+		wcscat_s(wdest, CLAR_MAX_PATH, find_data.cFileName);
+		FindClose(find_handle);
+
+		/* Check the new target for existence */
+		cl_assert(INVALID_FILE_ATTRIBUTES == GetFileAttributesW(wdest));
+	}
+
+	if (FILE_ATTRIBUTE_DIRECTORY & source_attrs)
+		fs_copydir_helper(wsource, wdest);
+	else
+		cl_assert(CopyFileW(wsource, wdest, TRUE));
+}
+
+void
+cl_fs_cleanup(void)
+{
+#ifdef CLAR_FIXTURE_PATH
+	fs_rm(fixture_path(_clar_path, "*"));
+#else
+	((void)fs_copy); /* unused */
+#endif
+}
+
+#else
+
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(__linux__)
+# include <sys/sendfile.h>
+#endif
+
+#if defined(__APPLE__)
+# include <copyfile.h>
+#endif
+
+static void basename_r(const char **out, int *out_len, const char *in)
+{
+	size_t in_len = strlen(in), start_pos;
+
+	for (in_len = strlen(in); in_len; in_len--) {
+		if (in[in_len - 1] != '/')
+			break;
+	}
+
+	for (start_pos = in_len; start_pos; start_pos--) {
+		if (in[start_pos - 1] == '/')
+			break;
+	}
+
+	cl_assert(in_len - start_pos < INT_MAX);
+
+	if (in_len - start_pos > 0) {
+		*out = &in[start_pos];
+		*out_len = (in_len - start_pos);
+	} else {
+		*out = "/";
+		*out_len = 1;
+	}
+}
+
+static char *joinpath(const char *dir, const char *base, int base_len)
+{
+	char *out;
+	int len;
+
+	if (base_len == -1) {
+		size_t bl = strlen(base);
+
+		cl_assert(bl < INT_MAX);
+		base_len = (int)bl;
+	}
+
+	len = strlen(dir) + base_len + 2;
+	cl_assert(len > 0);
+
+	cl_assert(out = malloc(len));
+	cl_assert(snprintf(out, len, "%s/%.*s", dir, base_len, base) < len);
+
+	return out;
+}
+
+static void
+fs_copydir_helper(const char *source, const char *dest, int dest_mode)
+{
+	DIR *source_dir;
+	struct dirent *d;
+
+	mkdir(dest, dest_mode);
+
+	cl_assert_(source_dir = opendir(source), "Could not open source dir");
+	while ((d = (errno = 0, readdir(source_dir))) != NULL) {
+		char *child;
+
+		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+			continue;
+
+		child = joinpath(source, d->d_name, -1);
+		fs_copy(child, dest);
+		free(child);
+	}
+
+	cl_assert_(errno == 0, "Failed to iterate source dir");
+
+	closedir(source_dir);
+}
+
+static void
+fs_copyfile_helper(const char *source, size_t source_len, const char *dest, int dest_mode)
+{
+	int in, out;
+
+	cl_must_pass((in = open(source, O_RDONLY)));
+	cl_must_pass((out = open(dest, O_WRONLY|O_CREAT|O_TRUNC, dest_mode)));
+
+#if USE_FCOPYFILE && defined(__APPLE__)
+	((void)(source_len)); /* unused */
+	cl_must_pass(fcopyfile(in, out, 0, COPYFILE_DATA));
+#elif USE_SENDFILE && defined(__linux__)
+	{
+		ssize_t ret = 0;
+
+		while (source_len && (ret = sendfile(out, in, NULL, source_len)) > 0) {
+			source_len -= (size_t)ret;
+		}
+		cl_assert(ret >= 0);
+	}
+#else
+	{
+		char buf[131072];
+		ssize_t ret;
+
+		((void)(source_len)); /* unused */
+
+		while ((ret = read(in, buf, sizeof(buf))) > 0) {
+			size_t len = (size_t)ret;
+
+			while (len && (ret = write(out, buf, len)) > 0) {
+				cl_assert(ret <= (ssize_t)len);
+				len -= ret;
+			}
+			cl_assert(ret >= 0);
+		}
+		cl_assert(ret == 0);
+	}
+#endif
+
+	close(in);
+	close(out);
+}
+
+static void
+fs_copy(const char *source, const char *_dest)
+{
+	char *dbuf = NULL;
+	const char *dest = NULL;
+	struct stat source_st, dest_st;
+
+	cl_must_pass_(lstat(source, &source_st), "Failed to stat copy source");
+
+	if (lstat(_dest, &dest_st) == 0) {
+		const char *base;
+		int base_len;
+
+		/* Target exists and is directory; append basename */
+		cl_assert(S_ISDIR(dest_st.st_mode));
+
+		basename_r(&base, &base_len, source);
+		cl_assert(base_len < INT_MAX);
+
+		dbuf = joinpath(_dest, base, base_len);
+		dest = dbuf;
+	} else if (errno != ENOENT) {
+		cl_fail("Cannot copy; cannot stat destination");
+	} else {
+		dest = _dest;
+	}
+
+	if (S_ISDIR(source_st.st_mode)) {
+		fs_copydir_helper(source, dest, source_st.st_mode);
+	} else {
+		fs_copyfile_helper(source, source_st.st_size, dest, source_st.st_mode);
+	}
+
+	free(dbuf);
+}
+
+static void
+fs_rmdir_helper(const char *path)
+{
+	DIR *dir;
+	struct dirent *d;
+
+	cl_assert_(dir = opendir(path), "Could not open dir");
+	while ((d = (errno = 0, readdir(dir))) != NULL) {
+		char *child;
+
+		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+			continue;
+
+		child = joinpath(path, d->d_name, -1);
+		fs_rm(child);
+		free(child);
+	}
+
+	cl_assert_(errno == 0, "Failed to iterate source dir");
+	closedir(dir);
+
+	cl_must_pass_(rmdir(path), "Could not remove directory");
+}
+
+static void
+fs_rm(const char *path)
+{
+	struct stat st;
+
+	if (lstat(path, &st)) {
+		if (errno == ENOENT)
+			return;
+
+		cl_fail("Cannot copy; cannot stat destination");
+	}
+
+	if (S_ISDIR(st.st_mode)) {
+		fs_rmdir_helper(path);
+	} else {
+		cl_must_pass(unlink(path));
+	}
+}
+
+void
+cl_fs_cleanup(void)
+{
+	clar_unsandbox();
+	clar_sandbox();
+}
+#endif
diff --git a/t/unit-tests/clar/clar/print.h b/t/unit-tests/clar/clar/print.h
new file mode 100644
index 0000000..c17e2f6
--- /dev/null
+++ b/t/unit-tests/clar/clar/print.h
@@ -0,0 +1,211 @@
+/* clap: clar protocol, the traditional clar output format */
+
+static void clar_print_clap_init(int test_count, int suite_count, const char *suite_names)
+{
+	(void)test_count;
+	printf("Loaded %d suites: %s\n", (int)suite_count, suite_names);
+	printf("Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')\n");
+}
+
+static void clar_print_clap_shutdown(int test_count, int suite_count, int error_count)
+{
+	(void)test_count;
+	(void)suite_count;
+	(void)error_count;
+
+	printf("\n\n");
+	clar_report_all();
+}
+
+static void clar_print_clap_error(int num, const struct clar_report *report, const struct clar_error *error)
+{
+	printf("  %d) Failure:\n", num);
+
+	printf("%s::%s [%s:%"PRIuZ"]\n",
+		report->suite,
+		report->test,
+		error->file,
+		error->line_number);
+
+	printf("  %s\n", error->error_msg);
+
+	if (error->description != NULL)
+		printf("  %s\n", error->description);
+
+	printf("\n");
+	fflush(stdout);
+}
+
+static void clar_print_clap_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status status)
+{
+	(void)test_name;
+	(void)test_number;
+
+	if (_clar.verbosity > 1) {
+		printf("%s::%s: ", suite_name, test_name);
+
+		switch (status) {
+		case CL_TEST_OK: printf("ok\n"); break;
+		case CL_TEST_FAILURE: printf("fail\n"); break;
+		case CL_TEST_SKIP: printf("skipped"); break;
+		case CL_TEST_NOTRUN: printf("notrun"); break;
+		}
+	} else {
+		switch (status) {
+		case CL_TEST_OK: printf("."); break;
+		case CL_TEST_FAILURE: printf("F"); break;
+		case CL_TEST_SKIP: printf("S"); break;
+		case CL_TEST_NOTRUN: printf("N"); break;
+		}
+
+		fflush(stdout);
+	}
+}
+
+static void clar_print_clap_onsuite(const char *suite_name, int suite_index)
+{
+	if (_clar.verbosity == 1)
+		printf("\n%s", suite_name);
+
+	(void)suite_index;
+}
+
+static void clar_print_clap_onabort(const char *fmt, va_list arg)
+{
+	vfprintf(stderr, fmt, arg);
+}
+
+/* tap: test anywhere protocol format */
+
+static void clar_print_tap_init(int test_count, int suite_count, const char *suite_names)
+{
+	(void)test_count;
+	(void)suite_count;
+	(void)suite_names;
+	printf("TAP version 13\n");
+}
+
+static void clar_print_tap_shutdown(int test_count, int suite_count, int error_count)
+{
+	(void)suite_count;
+	(void)error_count;
+
+	printf("1..%d\n", test_count);
+}
+
+static void clar_print_tap_error(int num, const struct clar_report *report, const struct clar_error *error)
+{
+	(void)num;
+	(void)report;
+	(void)error;
+}
+
+static void print_escaped(const char *str)
+{
+	char *c;
+
+	while ((c = strchr(str, '\'')) != NULL) {
+		printf("%.*s", (int)(c - str), str);
+		printf("''");
+		str = c + 1;
+	}
+
+	printf("%s", str);
+}
+
+static void clar_print_tap_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status status)
+{
+	const struct clar_error *error = _clar.last_report->errors;
+
+	(void)test_name;
+	(void)test_number;
+
+	switch(status) {
+	case CL_TEST_OK:
+		printf("ok %d - %s::%s\n", test_number, suite_name, test_name);
+		break;
+	case CL_TEST_FAILURE:
+		printf("not ok %d - %s::%s\n", test_number, suite_name, test_name);
+
+		printf("    ---\n");
+		printf("    reason: |\n");
+		printf("      %s\n", error->error_msg);
+
+		if (error->description)
+			printf("      %s\n", error->description);
+
+		printf("    at:\n");
+		printf("      file: '"); print_escaped(error->file); printf("'\n");
+		printf("      line: %" PRIuZ "\n", error->line_number);
+		printf("      function: '%s'\n", error->function);
+		printf("    ---\n");
+
+		break;
+	case CL_TEST_SKIP:
+	case CL_TEST_NOTRUN:
+		printf("ok %d - # SKIP %s::%s\n", test_number, suite_name, test_name);
+		break;
+	}
+
+	fflush(stdout);
+}
+
+static void clar_print_tap_onsuite(const char *suite_name, int suite_index)
+{
+	printf("# start of suite %d: %s\n", suite_index, suite_name);
+}
+
+static void clar_print_tap_onabort(const char *fmt, va_list arg)
+{
+	printf("Bail out! ");
+	vprintf(fmt, arg);
+	fflush(stdout);
+}
+
+/* indirection between protocol output selection */
+
+#define PRINT(FN, ...) do { \
+		switch (_clar.output_format) { \
+			case CL_OUTPUT_CLAP: \
+				clar_print_clap_##FN (__VA_ARGS__); \
+				break; \
+			case CL_OUTPUT_TAP: \
+				clar_print_tap_##FN (__VA_ARGS__); \
+				break; \
+			default: \
+				abort(); \
+		} \
+	} while (0)
+
+static void clar_print_init(int test_count, int suite_count, const char *suite_names)
+{
+	PRINT(init, test_count, suite_count, suite_names);
+}
+
+static void clar_print_shutdown(int test_count, int suite_count, int error_count)
+{
+	PRINT(shutdown, test_count, suite_count, error_count);
+}
+
+static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error)
+{
+	PRINT(error, num, report, error);
+}
+
+static void clar_print_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status status)
+{
+	PRINT(ontest, suite_name, test_name, test_number, status);
+}
+
+static void clar_print_onsuite(const char *suite_name, int suite_index)
+{
+	PRINT(onsuite, suite_name, suite_index);
+}
+
+static void clar_print_onabort(const char *msg, ...)
+{
+	va_list argp;
+	va_start(argp, msg);
+	PRINT(onabort, msg, argp);
+	va_end(argp);
+}
diff --git a/t/unit-tests/clar/clar/sandbox.h b/t/unit-tests/clar/clar/sandbox.h
new file mode 100644
index 0000000..e25057b
--- /dev/null
+++ b/t/unit-tests/clar/clar/sandbox.h
@@ -0,0 +1,159 @@
+#ifdef __APPLE__
+#include <sys/syslimits.h>
+#endif
+
+static char _clar_path[4096 + 1];
+
+static int
+is_valid_tmp_path(const char *path)
+{
+	STAT_T st;
+
+	if (stat(path, &st) != 0)
+		return 0;
+
+	if (!S_ISDIR(st.st_mode))
+		return 0;
+
+	return (access(path, W_OK) == 0);
+}
+
+static int
+find_tmp_path(char *buffer, size_t length)
+{
+#ifndef _WIN32
+	static const size_t var_count = 5;
+	static const char *env_vars[] = {
+		"CLAR_TMP", "TMPDIR", "TMP", "TEMP", "USERPROFILE"
+	};
+
+	size_t i;
+
+	for (i = 0; i < var_count; ++i) {
+		const char *env = getenv(env_vars[i]);
+		if (!env)
+			continue;
+
+		if (is_valid_tmp_path(env)) {
+#ifdef __APPLE__
+			if (length >= PATH_MAX && realpath(env, buffer) != NULL)
+				return 0;
+#endif
+			strncpy(buffer, env, length - 1);
+			buffer[length - 1] = '\0';
+			return 0;
+		}
+	}
+
+	/* If the environment doesn't say anything, try to use /tmp */
+	if (is_valid_tmp_path("/tmp")) {
+#ifdef __APPLE__
+		if (length >= PATH_MAX && realpath("/tmp", buffer) != NULL)
+			return 0;
+#endif
+		strncpy(buffer, "/tmp", length - 1);
+		buffer[length - 1] = '\0';
+		return 0;
+	}
+
+#else
+	DWORD env_len = GetEnvironmentVariable("CLAR_TMP", buffer, (DWORD)length);
+	if (env_len > 0 && env_len < (DWORD)length)
+		return 0;
+
+	if (GetTempPath((DWORD)length, buffer))
+		return 0;
+#endif
+
+	/* This system doesn't like us, try to use the current directory */
+	if (is_valid_tmp_path(".")) {
+		strncpy(buffer, ".", length - 1);
+		buffer[length - 1] = '\0';
+		return 0;
+	}
+
+	return -1;
+}
+
+static void clar_unsandbox(void)
+{
+	if (_clar_path[0] == '\0')
+		return;
+
+	cl_must_pass(chdir(".."));
+
+	fs_rm(_clar_path);
+}
+
+static int build_sandbox_path(void)
+{
+#ifdef CLAR_TMPDIR
+	const char path_tail[] = CLAR_TMPDIR "_XXXXXX";
+#else
+	const char path_tail[] = "clar_tmp_XXXXXX";
+#endif
+
+	size_t len;
+
+	if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0)
+		return -1;
+
+	len = strlen(_clar_path);
+
+#ifdef _WIN32
+	{ /* normalize path to POSIX forward slashes */
+		size_t i;
+		for (i = 0; i < len; ++i) {
+			if (_clar_path[i] == '\\')
+				_clar_path[i] = '/';
+		}
+	}
+#endif
+
+	if (_clar_path[len - 1] != '/') {
+		_clar_path[len++] = '/';
+	}
+
+	strncpy(_clar_path + len, path_tail, sizeof(_clar_path) - len);
+
+#if defined(__MINGW32__)
+	if (_mktemp(_clar_path) == NULL)
+		return -1;
+
+	if (mkdir(_clar_path, 0700) != 0)
+		return -1;
+#elif defined(__TANDEM)
+	if (mktemp(_clar_path) == NULL)
+		return -1;
+
+	if (mkdir(_clar_path, 0700) != 0)
+		return -1;
+#elif defined(_WIN32)
+	if (_mktemp_s(_clar_path, sizeof(_clar_path)) != 0)
+		return -1;
+
+	if (mkdir(_clar_path, 0700) != 0)
+		return -1;
+#else
+	if (mkdtemp(_clar_path) == NULL)
+		return -1;
+#endif
+
+	return 0;
+}
+
+static int clar_sandbox(void)
+{
+	if (_clar_path[0] == '\0' && build_sandbox_path() < 0)
+		return -1;
+
+	if (chdir(_clar_path) != 0)
+		return -1;
+
+	return 0;
+}
+
+const char *clar_sandbox_path(void)
+{
+	return _clar_path;
+}
diff --git a/t/unit-tests/clar/clar/summary.h b/t/unit-tests/clar/clar/summary.h
new file mode 100644
index 0000000..4dd352e
--- /dev/null
+++ b/t/unit-tests/clar/clar/summary.h
@@ -0,0 +1,143 @@
+
+#include <stdio.h>
+#include <time.h>
+
+static int clar_summary_close_tag(
+    struct clar_summary *summary, const char *tag, int indent)
+{
+	const char *indt;
+
+	if (indent == 0) indt = "";
+	else if (indent == 1) indt = "\t";
+	else indt = "\t\t";
+
+	return fprintf(summary->fp, "%s</%s>\n", indt, tag);
+}
+
+static int clar_summary_testsuites(struct clar_summary *summary)
+{
+	return fprintf(summary->fp, "<testsuites>\n");
+}
+
+static int clar_summary_testsuite(struct clar_summary *summary,
+    int idn, const char *name, time_t timestamp,
+    int test_count, int fail_count, int error_count)
+{
+	struct tm *tm = localtime(&timestamp);
+	char iso_dt[20];
+
+	if (strftime(iso_dt, sizeof(iso_dt), "%Y-%m-%dT%H:%M:%S", tm) == 0)
+		return -1;
+
+	return fprintf(summary->fp, "\t<testsuite"
+		       " id=\"%d\""
+		       " name=\"%s\""
+		       " hostname=\"localhost\""
+		       " timestamp=\"%s\""
+		       " tests=\"%d\""
+		       " failures=\"%d\""
+		       " errors=\"%d\">\n",
+		       idn, name, iso_dt, test_count, fail_count, error_count);
+}
+
+static int clar_summary_testcase(struct clar_summary *summary,
+    const char *name, const char *classname, double elapsed)
+{
+	return fprintf(summary->fp,
+	    "\t\t<testcase name=\"%s\" classname=\"%s\" time=\"%.2f\">\n",
+		name, classname, elapsed);
+}
+
+static int clar_summary_failure(struct clar_summary *summary,
+    const char *type, const char *message, const char *desc)
+{
+	return fprintf(summary->fp,
+	    "\t\t\t<failure type=\"%s\"><![CDATA[%s\n%s]]></failure>\n",
+	    type, message, desc);
+}
+
+static int clar_summary_skipped(struct clar_summary *summary)
+{
+	return fprintf(summary->fp, "\t\t\t<skipped />\n");
+}
+
+struct clar_summary *clar_summary_init(const char *filename)
+{
+	struct clar_summary *summary;
+	FILE *fp;
+
+	if ((fp = fopen(filename, "w")) == NULL) {
+		perror("fopen");
+		return NULL;
+	}
+
+	if ((summary = malloc(sizeof(struct clar_summary))) == NULL) {
+		perror("malloc");
+		fclose(fp);
+		return NULL;
+	}
+
+	summary->filename = filename;
+	summary->fp = fp;
+
+	return summary;
+}
+
+int clar_summary_shutdown(struct clar_summary *summary)
+{
+	struct clar_report *report;
+	const char *last_suite = NULL;
+
+	if (clar_summary_testsuites(summary) < 0)
+		goto on_error;
+
+	report = _clar.reports;
+	while (report != NULL) {
+		struct clar_error *error = report->errors;
+
+		if (last_suite == NULL || strcmp(last_suite, report->suite) != 0) {
+			if (clar_summary_testsuite(summary, 0, report->suite,
+			    report->start, _clar.tests_ran, _clar.total_errors, 0) < 0)
+				goto on_error;
+		}
+
+		last_suite = report->suite;
+
+		clar_summary_testcase(summary, report->test, report->suite, report->elapsed);
+
+		while (error != NULL) {
+			if (clar_summary_failure(summary, "assert",
+			    error->error_msg, error->description) < 0)
+				goto on_error;
+
+			error = error->next;
+		}
+
+		if (report->status == CL_TEST_SKIP)
+			clar_summary_skipped(summary);
+
+		if (clar_summary_close_tag(summary, "testcase", 2) < 0)
+			goto on_error;
+
+		report = report->next;
+
+		if (!report || strcmp(last_suite, report->suite) != 0) {
+			if (clar_summary_close_tag(summary, "testsuite", 1) < 0)
+				goto on_error;
+		}
+	}
+
+	if (clar_summary_close_tag(summary, "testsuites", 0) < 0 ||
+	    fclose(summary->fp) != 0)
+		goto on_error;
+
+	printf("written summary file to %s\n", summary->filename);
+
+	free(summary);
+	return 0;
+
+on_error:
+	fclose(summary->fp);
+	free(summary);
+	return -1;
+}
diff --git a/t/unit-tests/clar/generate.py b/t/unit-tests/clar/generate.py
new file mode 100755
index 0000000..80996ac
--- /dev/null
+++ b/t/unit-tests/clar/generate.py
@@ -0,0 +1,266 @@
+#!/usr/bin/env python
+#
+# Copyright (c) Vicent Marti. All rights reserved.
+#
+# This file is part of clar, distributed under the ISC license.
+# For full terms see the included COPYING file.
+#
+
+from __future__ import with_statement
+from string import Template
+import re, fnmatch, os, sys, codecs, pickle
+
+class Module(object):
+    class Template(object):
+        def __init__(self, module):
+            self.module = module
+
+        def _render_callback(self, cb):
+            if not cb:
+                return '    { NULL, NULL }'
+            return '    { "%s", &%s }' % (cb['short_name'], cb['symbol'])
+
+    class DeclarationTemplate(Template):
+        def render(self):
+            out = "\n".join("extern %s;" % cb['declaration'] for cb in self.module.callbacks) + "\n"
+
+            for initializer in self.module.initializers:
+                out += "extern %s;\n" % initializer['declaration']
+
+            if self.module.cleanup:
+                out += "extern %s;\n" % self.module.cleanup['declaration']
+
+            return out
+
+    class CallbacksTemplate(Template):
+        def render(self):
+            out = "static const struct clar_func _clar_cb_%s[] = {\n" % self.module.name
+            out += ",\n".join(self._render_callback(cb) for cb in self.module.callbacks)
+            out += "\n};\n"
+            return out
+
+    class InfoTemplate(Template):
+        def render(self):
+            templates = []
+
+            initializers = self.module.initializers
+            if len(initializers) == 0:
+                initializers = [ None ]
+
+            for initializer in initializers:
+                name = self.module.clean_name()
+                if initializer and initializer['short_name'].startswith('initialize_'):
+                    variant = initializer['short_name'][len('initialize_'):]
+                    name += " (%s)" % variant.replace('_', ' ')
+
+                template = Template(
+            r"""
+    {
+        "${clean_name}",
+    ${initialize},
+    ${cleanup},
+        ${cb_ptr}, ${cb_count}, ${enabled}
+    }"""
+                ).substitute(
+                    clean_name = name,
+                    initialize = self._render_callback(initializer),
+                    cleanup = self._render_callback(self.module.cleanup),
+                    cb_ptr = "_clar_cb_%s" % self.module.name,
+                    cb_count = len(self.module.callbacks),
+                    enabled = int(self.module.enabled)
+                )
+                templates.append(template)
+
+            return ','.join(templates)
+
+    def __init__(self, name):
+        self.name = name
+
+        self.mtime = None
+        self.enabled = True
+        self.modified = False
+
+    def clean_name(self):
+        return self.name.replace("_", "::")
+
+    def _skip_comments(self, text):
+        SKIP_COMMENTS_REGEX = re.compile(
+            r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
+            re.DOTALL | re.MULTILINE)
+
+        def _replacer(match):
+            s = match.group(0)
+            return "" if s.startswith('/') else s
+
+        return re.sub(SKIP_COMMENTS_REGEX, _replacer, text)
+
+    def parse(self, contents):
+        TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\s*\(\s*void\s*\))\s*\{"
+
+        contents = self._skip_comments(contents)
+        regex = re.compile(TEST_FUNC_REGEX % self.name, re.MULTILINE)
+
+        self.callbacks = []
+        self.initializers = []
+        self.cleanup = None
+
+        for (declaration, symbol, short_name) in regex.findall(contents):
+            data = {
+                "short_name" : short_name,
+                "declaration" : declaration,
+                "symbol" : symbol
+            }
+
+            if short_name.startswith('initialize'):
+                self.initializers.append(data)
+            elif short_name == 'cleanup':
+                self.cleanup = data
+            else:
+                self.callbacks.append(data)
+
+        return self.callbacks != []
+
+    def refresh(self, path):
+        self.modified = False
+
+        try:
+            st = os.stat(path)
+
+            # Not modified
+            if st.st_mtime == self.mtime:
+                return True
+
+            self.modified = True
+            self.mtime = st.st_mtime
+
+            with codecs.open(path, encoding='utf-8') as fp:
+                raw_content = fp.read()
+
+        except IOError:
+            return False
+
+        return self.parse(raw_content)
+
+class TestSuite(object):
+
+    def __init__(self, path, output):
+        self.path = path
+        self.output = output
+
+    def should_generate(self, path):
+        if not os.path.isfile(path):
+            return True
+
+        if any(module.modified for module in self.modules.values()):
+            return True
+
+        return False
+
+    def find_modules(self):
+        modules = []
+        for root, _, files in os.walk(self.path):
+            module_root = root[len(self.path):]
+            module_root = [c for c in module_root.split(os.sep) if c]
+
+            tests_in_module = fnmatch.filter(files, "*.c")
+
+            for test_file in tests_in_module:
+                full_path = os.path.join(root, test_file)
+                module_name = "_".join(module_root + [test_file[:-2]]).replace("-", "_")
+
+                modules.append((full_path, module_name))
+
+        return modules
+
+    def load_cache(self):
+        path = os.path.join(self.output, '.clarcache')
+        cache = {}
+
+        try:
+            fp = open(path, 'rb')
+            cache = pickle.load(fp)
+            fp.close()
+        except (IOError, ValueError):
+            pass
+
+        return cache
+
+    def save_cache(self):
+        path = os.path.join(self.output, '.clarcache')
+        with open(path, 'wb') as cache:
+            pickle.dump(self.modules, cache)
+
+    def load(self, force = False):
+        module_data = self.find_modules()
+        self.modules = {} if force else self.load_cache()
+
+        for path, name in module_data:
+            if name not in self.modules:
+                self.modules[name] = Module(name)
+
+            if not self.modules[name].refresh(path):
+                del self.modules[name]
+
+    def disable(self, excluded):
+        for exclude in excluded:
+            for module in self.modules.values():
+                name = module.clean_name()
+                if name.startswith(exclude):
+                    module.enabled = False
+                    module.modified = True
+
+    def suite_count(self):
+        return sum(max(1, len(m.initializers)) for m in self.modules.values())
+
+    def callback_count(self):
+        return sum(len(module.callbacks) for module in self.modules.values())
+
+    def write(self):
+        output = os.path.join(self.output, 'clar.suite')
+
+        if not self.should_generate(output):
+            return False
+
+        with open(output, 'w') as data:
+            modules = sorted(self.modules.values(), key=lambda module: module.name)
+
+            for module in modules:
+                t = Module.DeclarationTemplate(module)
+                data.write(t.render())
+
+            for module in modules:
+                t = Module.CallbacksTemplate(module)
+                data.write(t.render())
+
+            suites = "static struct clar_suite _clar_suites[] = {" + ','.join(
+                Module.InfoTemplate(module).render() for module in modules
+            ) + "\n};\n"
+
+            data.write(suites)
+
+            data.write("static const size_t _clar_suite_count = %d;\n" % self.suite_count())
+            data.write("static const size_t _clar_callback_count = %d;\n" % self.callback_count())
+
+        self.save_cache()
+        return True
+
+if __name__ == '__main__':
+    from optparse import OptionParser
+
+    parser = OptionParser()
+    parser.add_option('-f', '--force', action="store_true", dest='force', default=False)
+    parser.add_option('-x', '--exclude', dest='excluded', action='append', default=[])
+    parser.add_option('-o', '--output', dest='output')
+
+    options, args = parser.parse_args()
+    if len(args) > 1:
+        print("More than one path given")
+        sys.exit(1)
+
+    path = args.pop() if args else '.'
+    output = options.output or path
+    suite = TestSuite(path, output)
+    suite.load(options.force)
+    suite.disable(options.excluded)
+    if suite.write():
+        print("Written `clar.suite` (%d tests in %d suites)" % (suite.callback_count(), suite.suite_count()))
diff --git a/t/unit-tests/clar/test/.gitignore b/t/unit-tests/clar/test/.gitignore
new file mode 100644
index 0000000..a477d0c
--- /dev/null
+++ b/t/unit-tests/clar/test/.gitignore
@@ -0,0 +1,4 @@
+clar.suite
+.clarcache
+clar_test
+*.o
diff --git a/t/unit-tests/clar/test/Makefile b/t/unit-tests/clar/test/Makefile
new file mode 100644
index 0000000..93c6b2a
--- /dev/null
+++ b/t/unit-tests/clar/test/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (c) Vicent Marti. All rights reserved.
+#
+# This file is part of clar, distributed under the ISC license.
+# For full terms see the included COPYING file.
+#
+
+#
+# Set up the path to the clar sources and to the fixtures directory
+#
+# The fixture path needs to be an absolute path so it can be used
+# even after we have chdir'ed into the test directory while testing.
+#
+CURRENT_MAKEFILE  := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
+TEST_DIRECTORY    := $(abspath $(dir $(CURRENT_MAKEFILE)))
+CLAR_PATH         := $(dir $(TEST_DIRECTORY))
+CLAR_FIXTURE_PATH := $(TEST_DIRECTORY)/resources/
+
+CFLAGS=-g -I.. -I. -Wall -DCLAR_FIXTURE_PATH=\"$(CLAR_FIXTURE_PATH)\"
+
+.PHONY: clean
+
+# list the objects that go into our test
+objects = main.o sample.o
+
+# build the test executable itself
+clar_test: $(objects) clar_test.h clar.suite $(CLAR_PATH)clar.c
+	$(CC) $(CFLAGS) -o $@ "$(CLAR_PATH)clar.c" $(objects)
+
+# test object files depend on clar macros
+$(objects) : $(CLAR_PATH)clar.h
+
+# build the clar.suite file of test metadata
+clar.suite:
+	python "$(CLAR_PATH)generate.py" .
+
+# remove all generated files
+clean:
+	$(RM) -rf *.o clar.suite .clarcache clar_test clar_test.dSYM
diff --git a/t/unit-tests/clar/test/clar_test.h b/t/unit-tests/clar/test/clar_test.h
new file mode 100644
index 0000000..0fcaa63
--- /dev/null
+++ b/t/unit-tests/clar/test/clar_test.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) Vicent Marti. All rights reserved.
+ *
+ * This file is part of clar, distributed under the ISC license.
+ * For full terms see the included COPYING file.
+ */
+#ifndef __CLAR_TEST__
+#define __CLAR_TEST__
+
+/* Import the standard clar helper functions */
+#include "clar.h"
+
+/* Your custom shared includes / defines here */
+extern int global_test_counter;
+
+#endif
diff --git a/t/unit-tests/clar/test/main.c b/t/unit-tests/clar/test/main.c
new file mode 100644
index 0000000..59e56ad
--- /dev/null
+++ b/t/unit-tests/clar/test/main.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) Vicent Marti. All rights reserved.
+ *
+ * This file is part of clar, distributed under the ISC license.
+ * For full terms see the included COPYING file.
+ */
+
+#include "clar_test.h"
+
+/*
+ * Sample main() for clar tests.
+ *
+ * You should write your own main routine for clar tests that does specific
+ * setup and teardown as necessary for your application.  The only required
+ * line is the call to `clar_test(argc, argv)`, which will execute the test
+ * suite.  If you want to check the return value of the test application,
+ * your main() should return the same value returned by clar_test().
+ */
+
+int global_test_counter = 0;
+
+#ifdef _WIN32
+int __cdecl main(int argc, char *argv[])
+#else
+int main(int argc, char *argv[])
+#endif
+{
+	int ret;
+
+	/* Your custom initialization here */
+	global_test_counter = 0;
+
+	/* Run the test suite */
+	ret = clar_test(argc, argv);
+
+	/* Your custom cleanup here */
+	cl_assert_equal_i(8, global_test_counter);
+
+	return ret;
+}
diff --git a/t/unit-tests/clar/test/main.c.sample b/t/unit-tests/clar/test/main.c.sample
new file mode 100644
index 0000000..a4d91b7
--- /dev/null
+++ b/t/unit-tests/clar/test/main.c.sample
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) Vicent Marti. All rights reserved.
+ *
+ * This file is part of clar, distributed under the ISC license.
+ * For full terms see the included COPYING file.
+ */
+
+#include "clar_test.h"
+
+/*
+ * Minimal main() for clar tests.
+ *
+ * Modify this with any application specific setup or teardown that you need.
+ * The only required line is the call to `clar_test(argc, argv)`, which will
+ * execute the test suite.  If you want to check the return value of the test
+ * application, main() should return the same value returned by clar_test().
+ */
+
+#ifdef _WIN32
+int __cdecl main(int argc, char *argv[])
+#else
+int main(int argc, char *argv[])
+#endif
+{
+	/* Run the test suite */
+	return clar_test(argc, argv);
+}
diff --git a/t/unit-tests/clar/test/resources/test/file b/t/unit-tests/clar/test/resources/test/file
new file mode 100644
index 0000000..220f4aa
--- /dev/null
+++ b/t/unit-tests/clar/test/resources/test/file
@@ -0,0 +1 @@
+File
diff --git a/t/unit-tests/clar/test/sample.c b/t/unit-tests/clar/test/sample.c
new file mode 100644
index 0000000..faa1209
--- /dev/null
+++ b/t/unit-tests/clar/test/sample.c
@@ -0,0 +1,84 @@
+#include "clar_test.h"
+#include <sys/stat.h>
+
+static int file_size(const char *filename)
+{
+	struct stat st;
+
+	if (stat(filename, &st) == 0)
+		return (int)st.st_size;
+	return -1;
+}
+
+void test_sample__initialize(void)
+{
+	global_test_counter++;
+}
+
+void test_sample__cleanup(void)
+{
+	cl_fixture_cleanup("test");
+
+	cl_assert(file_size("test/file") == -1);
+}
+
+void test_sample__1(void)
+{
+	cl_assert(1);
+	cl_must_pass(0);  /* 0 == success */
+	cl_must_fail(-1); /* <0 == failure */
+	cl_must_pass(-1); /* demonstrate a failing call */
+}
+
+void test_sample__2(void)
+{
+	cl_fixture_sandbox("test");
+
+	cl_assert(file_size("test/nonexistent") == -1);
+	cl_assert(file_size("test/file") > 0);
+	cl_assert(100 == 101);
+}
+
+void test_sample__strings(void)
+{
+	const char *actual = "expected";
+	cl_assert_equal_s("expected", actual);
+	cl_assert_equal_s_("expected", actual, "second try with annotation");
+	cl_assert_equal_s_("mismatched", actual, "this one fails");
+}
+
+void test_sample__strings_with_length(void)
+{
+	const char *actual = "expected";
+	cl_assert_equal_strn("expected_", actual, 8);
+	cl_assert_equal_strn("exactly", actual, 2);
+	cl_assert_equal_strn_("expected_", actual, 8, "with annotation");
+	cl_assert_equal_strn_("exactly", actual, 3, "this one fails");
+}
+
+void test_sample__int(void)
+{
+	int value = 100;
+	cl_assert_equal_i(100, value);
+	cl_assert_equal_i_(101, value, "extra note on failing test");
+}
+
+void test_sample__int_fmt(void)
+{
+	int value = 100;
+	cl_assert_equal_i_fmt(022, value, "%04o");
+}
+
+void test_sample__bool(void)
+{
+	int value = 100;
+	cl_assert_equal_b(1, value);       /* test equality as booleans */
+	cl_assert_equal_b(0, value);
+}
+
+void test_sample__ptr(void)
+{
+	const char *actual = "expected";
+	cl_assert_equal_p(actual, actual); /* pointers to same object */
+	cl_assert_equal_p(&actual, actual);
+}
diff --git a/t/unit-tests/t-ctype.c b/t/unit-tests/ctype.c
similarity index 68%
rename from t/unit-tests/t-ctype.c
rename to t/unit-tests/ctype.c
index d6ac1fe..32e6586 100644
--- a/t/unit-tests/t-ctype.c
+++ b/t/unit-tests/ctype.c
@@ -1,18 +1,16 @@
-#include "test-lib.h"
+#include "unit-test.h"
 
 #define TEST_CHAR_CLASS(class, string) do { \
 	size_t len = ARRAY_SIZE(string) - 1 + \
 		BUILD_ASSERT_OR_ZERO(ARRAY_SIZE(string) > 0) + \
 		BUILD_ASSERT_OR_ZERO(sizeof(string[0]) == sizeof(char)); \
-	int skip = test__run_begin(); \
-	if (!skip) { \
-		for (int i = 0; i < 256; i++) { \
-			if (!check_int(class(i), ==, !!memchr(string, i, len)))\
-				test_msg("      i: 0x%02x", i); \
-		} \
-		check(!class(EOF)); \
+	for (int i = 0; i < 256; i++) { \
+		int actual = class(i), expect = !!memchr(string, i, len); \
+		if (actual != expect) \
+			cl_failf("0x%02x is classified incorrectly: expected %d, got %d", \
+				 i, expect, actual); \
 	} \
-	test__run_end(!skip, TEST_LOCATION(), #class " works"); \
+	cl_assert(!class(EOF)); \
 } while (0)
 
 #define DIGIT "0123456789"
@@ -33,21 +31,72 @@
 	"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
 	"\x7f"
 
-int cmd_main(int argc, const char **argv) {
+void test_ctype__isspace(void)
+{
 	TEST_CHAR_CLASS(isspace, " \n\r\t");
-	TEST_CHAR_CLASS(isdigit, DIGIT);
-	TEST_CHAR_CLASS(isalpha, LOWER UPPER);
-	TEST_CHAR_CLASS(isalnum, LOWER UPPER DIGIT);
-	TEST_CHAR_CLASS(is_glob_special, "*?[\\");
-	TEST_CHAR_CLASS(is_regex_special, "$()*+.?[\\^{|");
-	TEST_CHAR_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~");
-	TEST_CHAR_CLASS(isascii, ASCII);
-	TEST_CHAR_CLASS(islower, LOWER);
-	TEST_CHAR_CLASS(isupper, UPPER);
-	TEST_CHAR_CLASS(iscntrl, CNTRL);
-	TEST_CHAR_CLASS(ispunct, PUNCT);
-	TEST_CHAR_CLASS(isxdigit, DIGIT "abcdefABCDEF");
-	TEST_CHAR_CLASS(isprint, LOWER UPPER DIGIT PUNCT " ");
+}
 
-	return test_done();
+void test_ctype__isdigit(void)
+{
+	TEST_CHAR_CLASS(isdigit, DIGIT);
+}
+
+void test_ctype__isalpha(void)
+{
+	TEST_CHAR_CLASS(isalpha, LOWER UPPER);
+}
+
+void test_ctype__isalnum(void)
+{
+	TEST_CHAR_CLASS(isalnum, LOWER UPPER DIGIT);
+}
+
+void test_ctype__is_glob_special(void)
+{
+	TEST_CHAR_CLASS(is_glob_special, "*?[\\");
+}
+
+void test_ctype__is_regex_special(void)
+{
+	TEST_CHAR_CLASS(is_regex_special, "$()*+.?[\\^{|");
+}
+
+void test_ctype__is_pathspec_magic(void)
+{
+	TEST_CHAR_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~");
+}
+
+void test_ctype__isascii(void)
+{
+	TEST_CHAR_CLASS(isascii, ASCII);
+}
+
+void test_ctype__islower(void)
+{
+	TEST_CHAR_CLASS(islower, LOWER);
+}
+
+void test_ctype__isupper(void)
+{
+	TEST_CHAR_CLASS(isupper, UPPER);
+}
+
+void test_ctype__iscntrl(void)
+{
+	TEST_CHAR_CLASS(iscntrl, CNTRL);
+}
+
+void test_ctype__ispunct(void)
+{
+	TEST_CHAR_CLASS(ispunct, PUNCT);
+}
+
+void test_ctype__isxdigit(void)
+{
+	TEST_CHAR_CLASS(isxdigit, DIGIT "abcdefABCDEF");
+}
+
+void test_ctype__isprint(void)
+{
+	TEST_CHAR_CLASS(isprint, LOWER UPPER DIGIT PUNCT " ");
 }
diff --git a/t/unit-tests/lib-oid.c b/t/unit-tests/lib-oid.c
index 37105f0..8f0ccac 100644
--- a/t/unit-tests/lib-oid.c
+++ b/t/unit-tests/lib-oid.c
@@ -3,7 +3,7 @@
 #include "strbuf.h"
 #include "hex.h"
 
-static int init_hash_algo(void)
+int init_hash_algo(void)
 {
 	static int algo = -1;
 
diff --git a/t/unit-tests/lib-oid.h b/t/unit-tests/lib-oid.h
index 8d2acca..4e77c04 100644
--- a/t/unit-tests/lib-oid.h
+++ b/t/unit-tests/lib-oid.h
@@ -13,5 +13,13 @@
  * environment variable.
  */
 int get_oid_arbitrary_hex(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
+ * GIT_TEST_DEFAULT_HASH's value is valid or not.
+ */
+int init_hash_algo(void);
 
 #endif /* LIB_OID_H */
diff --git a/t/unit-tests/lib-reftable.c b/t/unit-tests/lib-reftable.c
new file mode 100644
index 0000000..ab1fa44
--- /dev/null
+++ b/t/unit-tests/lib-reftable.c
@@ -0,0 +1,93 @@
+#include "lib-reftable.h"
+#include "test-lib.h"
+#include "reftable/constants.h"
+#include "reftable/writer.h"
+
+void t_reftable_set_hash(uint8_t *p, int i, uint32_t id)
+{
+	memset(p, (uint8_t)i, hash_size(id));
+}
+
+static ssize_t strbuf_writer_write(void *b, const void *data, size_t sz)
+{
+	strbuf_add(b, data, sz);
+	return sz;
+}
+
+static int strbuf_writer_flush(void *arg UNUSED)
+{
+	return 0;
+}
+
+struct reftable_writer *t_reftable_strbuf_writer(struct strbuf *buf,
+						 struct reftable_write_options *opts)
+{
+	return reftable_new_writer(&strbuf_writer_write,
+				   &strbuf_writer_flush,
+				   buf, opts);
+}
+
+void t_reftable_write_to_buf(struct strbuf *buf,
+			     struct reftable_ref_record *refs,
+			     size_t nrefs,
+			     struct reftable_log_record *logs,
+			     size_t nlogs,
+			     struct reftable_write_options *_opts)
+{
+	struct reftable_write_options opts = { 0 };
+	const struct reftable_stats *stats;
+	struct reftable_writer *writer;
+	uint64_t min = 0xffffffff;
+	uint64_t max = 0;
+	int ret;
+
+	if (_opts)
+		opts = *_opts;
+
+	for (size_t i = 0; i < nrefs; i++) {
+		uint64_t ui = refs[i].update_index;
+		if (ui > max)
+			max = ui;
+		if (ui < min)
+			min = ui;
+	}
+	for (size_t i = 0; i < nlogs; i++) {
+		uint64_t ui = logs[i].update_index;
+		if (ui > max)
+			max = ui;
+		if (ui < min)
+			min = ui;
+	}
+
+	writer = t_reftable_strbuf_writer(buf, &opts);
+	reftable_writer_set_limits(writer, min, max);
+
+	if (nrefs) {
+		ret = reftable_writer_add_refs(writer, refs, nrefs);
+		check_int(ret, ==, 0);
+	}
+
+	if (nlogs) {
+		ret = reftable_writer_add_logs(writer, logs, nlogs);
+		check_int(ret, ==, 0);
+	}
+
+	ret = reftable_writer_close(writer);
+	check_int(ret, ==, 0);
+
+	stats = reftable_writer_stats(writer);
+	for (size_t i = 0; i < stats->ref_stats.blocks; i++) {
+		size_t off = i * (opts.block_size ? opts.block_size
+						  : DEFAULT_BLOCK_SIZE);
+		if (!off)
+			off = header_size(opts.hash_id == GIT_SHA256_FORMAT_ID ? 2 : 1);
+		check_char(buf->buf[off], ==, 'r');
+	}
+
+	if (nrefs)
+		check_int(stats->ref_stats.blocks, >, 0);
+	if (nlogs)
+		check_int(stats->log_stats.blocks, >, 0);
+
+	reftable_writer_free(writer);
+}
diff --git a/t/unit-tests/lib-reftable.h b/t/unit-tests/lib-reftable.h
new file mode 100644
index 0000000..d115419
--- /dev/null
+++ b/t/unit-tests/lib-reftable.h
@@ -0,0 +1,20 @@
+#ifndef LIB_REFTABLE_H
+#define LIB_REFTABLE_H
+
+#include "git-compat-util.h"
+#include "strbuf.h"
+#include "reftable/reftable-writer.h"
+
+void t_reftable_set_hash(uint8_t *p, int i, uint32_t id);
+
+struct reftable_writer *t_reftable_strbuf_writer(struct strbuf *buf,
+						 struct reftable_write_options *opts);
+
+void t_reftable_write_to_buf(struct strbuf *buf,
+			     struct reftable_ref_record *refs,
+			     size_t nrecords,
+			     struct reftable_log_record *logs,
+			     size_t nlogs,
+			     struct reftable_write_options *opts);
+
+#endif
diff --git a/t/unit-tests/strvec.c b/t/unit-tests/strvec.c
new file mode 100644
index 0000000..bf4c0cb
--- /dev/null
+++ b/t/unit-tests/strvec.c
@@ -0,0 +1,241 @@
+#include "unit-test.h"
+#include "strbuf.h"
+#include "strvec.h"
+
+#define check_strvec(vec, ...) \
+	do { \
+		const char *expect[] = { __VA_ARGS__ }; \
+		size_t expect_len = ARRAY_SIZE(expect); \
+		cl_assert(expect_len > 0); \
+		cl_assert_equal_p(expect[expect_len - 1], NULL); \
+		cl_assert_equal_i((vec)->nr, expect_len - 1); \
+		cl_assert((vec)->nr <= (vec)->alloc); \
+		for (size_t i = 0; i < expect_len; i++) \
+			cl_assert_equal_s((vec)->v[i], expect[i]); \
+	} while (0)
+
+void test_strvec__init(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	cl_assert_equal_p(vec.v, empty_strvec);
+	cl_assert_equal_i(vec.nr, 0);
+	cl_assert_equal_i(vec.alloc, 0);
+}
+
+void test_strvec__dynamic_init(void)
+{
+	struct strvec vec;
+
+	strvec_init(&vec);
+	cl_assert_equal_p(vec.v, empty_strvec);
+	cl_assert_equal_i(vec.nr, 0);
+	cl_assert_equal_i(vec.alloc, 0);
+}
+
+void test_strvec__clear(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_push(&vec, "foo");
+	strvec_clear(&vec);
+	cl_assert_equal_p(vec.v, empty_strvec);
+	cl_assert_equal_i(vec.nr, 0);
+	cl_assert_equal_i(vec.alloc, 0);
+}
+
+void test_strvec__push(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_push(&vec, "foo");
+	check_strvec(&vec, "foo", NULL);
+
+	strvec_push(&vec, "bar");
+	check_strvec(&vec, "foo", "bar", NULL);
+
+	strvec_clear(&vec);
+}
+
+void test_strvec__pushf(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushf(&vec, "foo: %d", 1);
+	check_strvec(&vec, "foo: 1", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__pushl(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	check_strvec(&vec, "foo", "bar", "baz", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__pushv(void)
+{
+	const char *strings[] = {
+		"foo", "bar", "baz", NULL,
+	};
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushv(&vec, strings);
+	check_strvec(&vec, "foo", "bar", "baz", NULL);
+
+	strvec_clear(&vec);
+}
+
+void test_strvec__replace_at_head(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_replace(&vec, 0, "replaced");
+	check_strvec(&vec, "replaced", "bar", "baz", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__replace_at_tail(void)
+{
+	struct strvec vec = STRVEC_INIT;
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_replace(&vec, 2, "replaced");
+	check_strvec(&vec, "foo", "bar", "replaced", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__replace_in_between(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_replace(&vec, 1, "replaced");
+	check_strvec(&vec, "foo", "replaced", "baz", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__replace_with_substring(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushl(&vec, "foo", NULL);
+	strvec_replace(&vec, 0, vec.v[0] + 1);
+	check_strvec(&vec, "oo", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__remove_at_head(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_remove(&vec, 0);
+	check_strvec(&vec, "bar", "baz", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__remove_at_tail(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_remove(&vec, 2);
+	check_strvec(&vec, "foo", "bar", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__remove_in_between(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_remove(&vec, 1);
+	check_strvec(&vec, "foo", "baz", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__pop_empty_array(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pop(&vec);
+	check_strvec(&vec, NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__pop_non_empty_array(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_pop(&vec);
+	check_strvec(&vec, "foo", "bar", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__split_empty_string(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_split(&vec, "");
+	check_strvec(&vec, NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__split_single_item(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_split(&vec, "foo");
+	check_strvec(&vec, "foo", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__split_multiple_items(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_split(&vec, "foo bar baz");
+	check_strvec(&vec, "foo", "bar", "baz", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__split_whitespace_only(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_split(&vec, " \t\n");
+	check_strvec(&vec, NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__split_multiple_consecutive_whitespaces(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_split(&vec, "foo\n\t bar");
+	check_strvec(&vec, "foo", "bar", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__detach(void)
+{
+	struct strvec vec = STRVEC_INIT;
+	const char **detached;
+
+	strvec_push(&vec, "foo");
+
+	detached = strvec_detach(&vec);
+	cl_assert_equal_s(detached[0], "foo");
+	cl_assert_equal_p(detached[1], NULL);
+
+	cl_assert_equal_p(vec.v, empty_strvec);
+	cl_assert_equal_i(vec.nr, 0);
+	cl_assert_equal_i(vec.alloc, 0);
+
+	free((char *) detached[0]);
+	free(detached);
+}
diff --git a/t/unit-tests/t-hash.c b/t/unit-tests/t-hash.c
index e9a78bf..e626470 100644
--- a/t/unit-tests/t-hash.c
+++ b/t/unit-tests/t-hash.c
@@ -38,7 +38,7 @@ static void check_hash_data(const void *data, size_t data_length,
 		     "SHA1 and SHA256 (%s) works", #literal); \
 	} while (0)
 
-int cmd_main(int argc, const char **argv)
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
 {
 	struct strbuf aaaaaaaaaa_100000 = STRBUF_INIT;
 	struct strbuf alphabet_100000 = STRBUF_INIT;
diff --git a/t/unit-tests/t-hashmap.c b/t/unit-tests/t-hashmap.c
new file mode 100644
index 0000000..83b79df
--- /dev/null
+++ b/t/unit-tests/t-hashmap.c
@@ -0,0 +1,361 @@
+#include "test-lib.h"
+#include "hashmap.h"
+#include "strbuf.h"
+
+struct test_entry {
+	int padding; /* hashmap entry no longer needs to be the first member */
+	struct hashmap_entry ent;
+	/* key and value as two \0-terminated strings */
+	char key[FLEX_ARRAY];
+};
+
+static int test_entry_cmp(const void *cmp_data,
+			  const struct hashmap_entry *eptr,
+			  const struct hashmap_entry *entry_or_key,
+			  const void *keydata)
+{
+	const unsigned int ignore_case = cmp_data ? *((int *)cmp_data) : 0;
+	const struct test_entry *e1, *e2;
+	const char *key = keydata;
+
+	e1 = container_of(eptr, const struct test_entry, ent);
+	e2 = container_of(entry_or_key, const struct test_entry, ent);
+
+	if (ignore_case)
+		return strcasecmp(e1->key, key ? key : e2->key);
+	else
+		return strcmp(e1->key, key ? key : e2->key);
+}
+
+static const char *get_value(const struct test_entry *e)
+{
+	return e->key + strlen(e->key) + 1;
+}
+
+static struct test_entry *alloc_test_entry(const char *key, const char *value,
+					   unsigned int ignore_case)
+{
+	size_t klen = strlen(key);
+	size_t vlen = strlen(value);
+	unsigned int hash = ignore_case ? strihash(key) : strhash(key);
+	struct test_entry *entry = xmalloc(st_add4(sizeof(*entry), klen, vlen, 2));
+
+	hashmap_entry_init(&entry->ent, hash);
+	memcpy(entry->key, key, klen + 1);
+	memcpy(entry->key + klen + 1, value, vlen + 1);
+	return entry;
+}
+
+static struct test_entry *get_test_entry(struct hashmap *map, const char *key,
+					 unsigned int ignore_case)
+{
+	return hashmap_get_entry_from_hash(
+		map, ignore_case ? strihash(key) : strhash(key), key,
+		struct test_entry, ent);
+}
+
+static int key_val_contains(const char *key_val[][2], char seen[], size_t n,
+			    struct test_entry *entry)
+{
+	for (size_t i = 0; i < n; i++) {
+		if (!strcmp(entry->key, key_val[i][0]) &&
+		    !strcmp(get_value(entry), key_val[i][1])) {
+			if (seen[i])
+				return 2;
+			seen[i] = 1;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static void setup(void (*f)(struct hashmap *map, unsigned int ignore_case),
+		  unsigned int ignore_case)
+{
+	struct hashmap map = HASHMAP_INIT(test_entry_cmp, &ignore_case);
+
+	f(&map, ignore_case);
+	hashmap_clear_and_free(&map, struct test_entry, ent);
+}
+
+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);
+
+	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");
+	free(entry);
+
+	entry = alloc_test_entry("fooBarFrotz", "value3", ignore_case);
+	check_pointer_eq(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");
+	free(entry);
+}
+
+static void t_get(struct hashmap *map, unsigned int ignore_case)
+{
+	struct test_entry *entry;
+	const char *key_val[][2] = { { "key1", "value1" },
+				     { "key2", "value2" },
+				     { "fooBarFrotz", "value3" },
+				     { ignore_case ? "key4" : "foobarfrotz",
+				       "value4" } };
+	const char *query[][2] = {
+		{ ignore_case ? "Key1" : "key1", "value1" },
+		{ ignore_case ? "keY2" : "key2", "value2" },
+		{ ignore_case ? "FOObarFrotz" : "fooBarFrotz", "value3" },
+		{ ignore_case ? "FOObarFrotz" : "foobarfrotz",
+		  ignore_case ? "value3" : "value4" }
+	};
+
+	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);
+	}
+
+	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]);
+	}
+
+	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));
+}
+
+static void t_add(struct hashmap *map, unsigned int ignore_case)
+{
+	struct test_entry *entry;
+	const char *key_val[][2] = {
+		{ "key1", "value1" },
+		{ ignore_case ? "Key1" : "key1", "value2" },
+		{ "fooBarFrotz", "value3" },
+		{ ignore_case ? "FOObarFrotz" : "fooBarFrotz", "value4" }
+	};
+	const char *query_keys[] = { "key1", ignore_case ? "FOObarFrotz" :
+							   "fooBarFrotz" };
+	char seen[ARRAY_SIZE(key_val)] = { 0 };
+
+	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);
+		hashmap_add(map, &entry->ent);
+	}
+
+	for (size_t i = 0; i < ARRAY_SIZE(query_keys); i++) {
+		int count = 0;
+		entry = hashmap_get_entry_from_hash(map,
+			ignore_case ? strihash(query_keys[i]) :
+				      strhash(query_keys[i]),
+			query_keys[i], struct test_entry, ent);
+
+		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++;
+			}
+		}
+		check_int(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]);
+	}
+
+	check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+	check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL);
+}
+
+static void t_remove(struct hashmap *map, unsigned int ignore_case)
+{
+	struct test_entry *entry, *removed;
+	const char *key_val[][2] = { { "key1", "value1" },
+				     { "key2", "value2" },
+				     { "fooBarFrotz", "value3" } };
+	const char *remove[][2] = { { ignore_case ? "Key1" : "key1", "value1" },
+				    { ignore_case ? "keY2" : "key2", "value2" } };
+
+	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);
+	}
+
+	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]);
+		free(entry);
+		free(removed);
+	}
+
+	entry = alloc_test_entry("notInMap", "", ignore_case);
+	check_pointer_eq(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));
+}
+
+static void t_iterate(struct hashmap *map, unsigned int ignore_case)
+{
+	struct test_entry *entry;
+	struct hashmap_iter iter;
+	const char *key_val[][2] = { { "key1", "value1" },
+				     { "key2", "value2" },
+				     { "fooBarFrotz", "value3" } };
+	char seen[ARRAY_SIZE(key_val)] = { 0 };
+
+	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);
+	}
+
+	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;
+			}
+		}
+	}
+
+	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]);
+	}
+
+	check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+}
+
+static void t_alloc(struct hashmap *map, unsigned int ignore_case)
+{
+	struct test_entry *entry, *removed;
+
+	for (int i = 1; i <= 51; i++) {
+		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);
+		free(key);
+		free(value);
+	}
+	check_int(map->tablesize, ==, 64);
+	check_int(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);
+
+	for (int i = 1; i <= 12; i++) {
+		char *key = xstrfmt("key%d", i);
+		char *value = xstrfmt("value%d", i);
+
+		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));
+		free(key);
+		free(value);
+		free(entry);
+		free(removed);
+	}
+	check_int(map->tablesize, ==, 256);
+	check_int(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);
+	free(entry);
+	free(removed);
+}
+
+static void t_intern(void)
+{
+	const char *values[] = { "value1", "Value1", "value2", "value2" };
+
+	for (size_t i = 0; i < ARRAY_SIZE(values); i++) {
+		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]);
+	}
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+	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();
+}
diff --git a/t/unit-tests/t-mem-pool.c b/t/unit-tests/t-mem-pool.c
index a0d57df..fe500c7 100644
--- a/t/unit-tests/t-mem-pool.c
+++ b/t/unit-tests/t-mem-pool.c
@@ -20,7 +20,7 @@ static void t_calloc_100(struct mem_pool *pool)
 	check(pool->mp_block->end != NULL);
 }
 
-int cmd_main(int argc, const char **argv)
+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");
diff --git a/t/unit-tests/t-oid-array.c b/t/unit-tests/t-oid-array.c
new file mode 100644
index 0000000..45b59a2
--- /dev/null
+++ b/t/unit-tests/t-oid-array.c
@@ -0,0 +1,126 @@
+#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-prio-queue.c b/t/unit-tests/t-prio-queue.c
index 7a4e578..fe6ae37 100644
--- a/t/unit-tests/t-prio-queue.c
+++ b/t/unit-tests/t-prio-queue.c
@@ -69,7 +69,7 @@ static void test_prio_queue(int *input, size_t input_size,
 #define TEST_INPUT(input, result) \
 	test_prio_queue(input, ARRAY_SIZE(input), result, ARRAY_SIZE(result))
 
-int cmd_main(int argc, const char **argv)
+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 })),
diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c
index 4e80bdf..a9a9f88 100644
--- a/t/unit-tests/t-reftable-basics.c
+++ b/t/unit-tests/t-reftable-basics.c
@@ -20,141 +20,125 @@ static int integer_needle_lesseq(size_t i, void *_args)
 	return args->needle <= args->haystack[i];
 }
 
-static void test_binsearch(void)
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
 {
-	int haystack[] = { 2, 4, 6, 8, 10 };
-	struct {
-		int needle;
-		size_t expected_idx;
-	} testcases[] = {
-		{-9000, 0},
-		{-1, 0},
-		{0, 0},
-		{2, 0},
-		{3, 1},
-		{4, 1},
-		{7, 3},
-		{9, 4},
-		{10, 4},
-		{11, 5},
-		{9000, 5},
-	};
-
-	for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) {
-		struct integer_needle_lesseq_args args = {
-			.haystack = haystack,
-			.needle = testcases[i].needle,
+	if_test ("binary search with binsearch works") {
+		int haystack[] = { 2, 4, 6, 8, 10 };
+		struct {
+			int needle;
+			size_t expected_idx;
+		} testcases[] = {
+			{-9000, 0},
+			{-1, 0},
+			{0, 0},
+			{2, 0},
+			{3, 1},
+			{4, 1},
+			{7, 3},
+			{9, 4},
+			{10, 4},
+			{11, 5},
+			{9000, 5},
 		};
-		size_t idx;
 
-		idx = binsearch(ARRAY_SIZE(haystack), &integer_needle_lesseq, &args);
-		check_int(idx, ==, testcases[i].expected_idx);
+		for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) {
+			struct integer_needle_lesseq_args args = {
+				.haystack = haystack,
+				.needle = testcases[i].needle,
+			};
+			size_t idx;
+
+			idx = binsearch(ARRAY_SIZE(haystack),
+					&integer_needle_lesseq, &args);
+			check_int(idx, ==, testcases[i].expected_idx);
+		}
 	}
-}
 
-static void test_names_length(void)
-{
-	const char *a[] = { "a", "b", NULL };
-	check_int(names_length(a), ==, 2);
-}
-
-static void test_names_equal(void)
-{
-	const char *a[] = { "a", "b", "c", NULL };
-	const char *b[] = { "a", "b", "d", NULL };
-	const char *c[] = { "a", "b", NULL };
-
-	check(names_equal(a, a));
-	check(!names_equal(a, b));
-	check(!names_equal(a, c));
-}
-
-static void test_parse_names_normal(void)
-{
-	char in1[] = "line\n";
-	char in2[] = "a\nb\nc";
-	char **out = NULL;
-	parse_names(in1, strlen(in1), &out);
-	check_str(out[0], "line");
-	check(!out[1]);
-	free_names(out);
-
-	parse_names(in2, strlen(in2), &out);
-	check_str(out[0], "a");
-	check_str(out[1], "b");
-	check_str(out[2], "c");
-	check(!out[3]);
-	free_names(out);
-}
-
-static void test_parse_names_drop_empty(void)
-{
-	char in[] = "a\n\nb\n";
-	char **out = NULL;
-	parse_names(in, strlen(in), &out);
-	check_str(out[0], "a");
-	/* simply '\n' should be dropped as empty string */
-	check_str(out[1], "b");
-	check(!out[2]);
-	free_names(out);
-}
-
-static void test_common_prefix(void)
-{
-	struct strbuf a = STRBUF_INIT;
-	struct strbuf b = STRBUF_INIT;
-	struct {
-		const char *a, *b;
-		int want;
-	} cases[] = {
-		{"abcdef", "abc", 3},
-		{ "abc", "ab", 2 },
-		{ "", "abc", 0 },
-		{ "abc", "abd", 2 },
-		{ "abc", "pqr", 0 },
-	};
-
-	for (size_t i = 0; i < ARRAY_SIZE(cases); i++) {
-		strbuf_addstr(&a, cases[i].a);
-		strbuf_addstr(&b, cases[i].b);
-		check_int(common_prefix_size(&a, &b), ==, cases[i].want);
-		strbuf_reset(&a);
-		strbuf_reset(&b);
+	if_test ("names_length returns size of a NULL-terminated string array") {
+		const char *a[] = { "a", "b", NULL };
+		check_int(names_length(a), ==, 2);
 	}
-	strbuf_release(&a);
-	strbuf_release(&b);
-}
 
-static void test_u24_roundtrip(void)
-{
-	uint32_t in = 0x112233;
-	uint8_t dest[3];
-	uint32_t out;
-	put_be24(dest, in);
-	out = get_be24(dest);
-	check_int(in, ==, out);
-}
+	if_test ("names_equal compares NULL-terminated string arrays") {
+		const char *a[] = { "a", "b", "c", NULL };
+		const char *b[] = { "a", "b", "d", NULL };
+		const char *c[] = { "a", "b", NULL };
 
-static void test_u16_roundtrip(void)
-{
-	uint32_t in = 0xfef1;
-	uint8_t dest[3];
-	uint32_t out;
-	put_be16(dest, in);
-	out = get_be16(dest);
-	check_int(in, ==, out);
-}
+		check(names_equal(a, a));
+		check(!names_equal(a, b));
+		check(!names_equal(a, c));
+	}
 
-int cmd_main(int argc, const char *argv[])
-{
-	TEST(test_common_prefix(), "common_prefix_size works");
-	TEST(test_parse_names_normal(), "parse_names works for basic input");
-	TEST(test_parse_names_drop_empty(), "parse_names drops empty string");
-	TEST(test_binsearch(), "binary search with binsearch works");
-	TEST(test_names_length(), "names_length retuns size of a NULL-terminated string array");
-	TEST(test_names_equal(), "names_equal compares NULL-terminated string arrays");
-	TEST(test_u24_roundtrip(), "put_be24 and get_be24 work");
-	TEST(test_u16_roundtrip(), "put_be16 and get_be16 work");
+	if_test ("parse_names works for basic input") {
+		char in1[] = "line\n";
+		char in2[] = "a\nb\nc";
+		char **out = NULL;
+		parse_names(in1, strlen(in1), &out);
+		check_str(out[0], "line");
+		check(!out[1]);
+		free_names(out);
+
+		parse_names(in2, strlen(in2), &out);
+		check_str(out[0], "a");
+		check_str(out[1], "b");
+		check_str(out[2], "c");
+		check(!out[3]);
+		free_names(out);
+	}
+
+	if_test ("parse_names drops empty string") {
+		char in[] = "a\n\nb\n";
+		char **out = NULL;
+		parse_names(in, strlen(in), &out);
+		check_str(out[0], "a");
+		/* simply '\n' should be dropped as empty string */
+		check_str(out[1], "b");
+		check(!out[2]);
+		free_names(out);
+	}
+
+	if_test ("common_prefix_size works") {
+		struct strbuf a = STRBUF_INIT;
+		struct strbuf b = STRBUF_INIT;
+		struct {
+			const char *a, *b;
+			int want;
+		} cases[] = {
+			{"abcdef", "abc", 3},
+			{ "abc", "ab", 2 },
+			{ "", "abc", 0 },
+			{ "abc", "abd", 2 },
+			{ "abc", "pqr", 0 },
+		};
+
+		for (size_t i = 0; i < ARRAY_SIZE(cases); i++) {
+			strbuf_addstr(&a, cases[i].a);
+			strbuf_addstr(&b, cases[i].b);
+			check_int(common_prefix_size(&a, &b), ==, cases[i].want);
+			strbuf_reset(&a);
+			strbuf_reset(&b);
+		}
+		strbuf_release(&a);
+		strbuf_release(&b);
+	}
+
+	if_test ("put_be24 and get_be24 work") {
+		uint32_t in = 0x112233;
+		uint8_t dest[3];
+		uint32_t out;
+		put_be24(dest, in);
+		out = get_be24(dest);
+		check_int(in, ==, out);
+	}
+
+	if_test ("put_be16 and get_be16 work") {
+		uint32_t in = 0xfef1;
+		uint8_t dest[3];
+		uint32_t out;
+		put_be16(dest, in);
+		out = get_be16(dest);
+		check_int(in, ==, out);
+	}
 
 	return test_done();
 }
diff --git a/t/unit-tests/t-reftable-block.c b/t/unit-tests/t-reftable-block.c
new file mode 100644
index 0000000..f1a4948
--- /dev/null
+++ b/t/unit-tests/t-reftable-block.c
@@ -0,0 +1,371 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "reftable/block.h"
+#include "reftable/blocksource.h"
+#include "reftable/constants.h"
+#include "reftable/reftable-error.h"
+
+static void t_ref_block_read_write(void)
+{
+	const int header_off = 21; /* random */
+	struct reftable_record recs[30];
+	const size_t N = ARRAY_SIZE(recs);
+	const size_t block_size = 1024;
+	struct reftable_block block = { 0 };
+	struct block_writer bw = {
+		.last_key = STRBUF_INIT,
+	};
+	struct reftable_record rec = {
+		.type = BLOCK_TYPE_REF,
+	};
+	size_t i = 0;
+	int ret;
+	struct block_reader br = { 0 };
+	struct block_iter it = BLOCK_ITER_INIT;
+	struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
+
+	REFTABLE_CALLOC_ARRAY(block.data, block_size);
+	block.len = block_size;
+	block_source_from_strbuf(&block.source ,&buf);
+	block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
+			  header_off, hash_size(GIT_SHA1_FORMAT_ID));
+
+	rec.u.ref.refname = (char *) "";
+	rec.u.ref.value_type = REFTABLE_REF_DELETION;
+	ret = block_writer_add(&bw, &rec);
+	check_int(ret, ==, REFTABLE_API_ERROR);
+
+	for (i = 0; i < N; i++) {
+		rec.u.ref.refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i);
+		rec.u.ref.value_type = REFTABLE_REF_VAL1;
+		memset(rec.u.ref.value.val1, i, GIT_SHA1_RAWSZ);
+
+		recs[i] = rec;
+		ret = block_writer_add(&bw, &rec);
+		rec.u.ref.refname = NULL;
+		rec.u.ref.value_type = REFTABLE_REF_DELETION;
+		check_int(ret, ==, 0);
+	}
+
+	ret = block_writer_finish(&bw);
+	check_int(ret, >, 0);
+
+	block_writer_release(&bw);
+
+	block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+	block_iter_seek_start(&it, &br);
+
+	for (i = 0; ; i++) {
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, >=, 0);
+		if (ret > 0) {
+			check_int(i, ==, N);
+			break;
+		}
+		check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+	}
+
+	for (i = 0; i < N; i++) {
+		block_iter_reset(&it);
+		reftable_record_key(&recs[i], &want);
+
+		ret = block_iter_seek_key(&it, &br, &want);
+		check_int(ret, ==, 0);
+
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, ==, 0);
+
+		check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+
+		want.len--;
+		ret = block_iter_seek_key(&it, &br, &want);
+		check_int(ret, ==, 0);
+
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, ==, 0);
+		check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+	}
+
+	block_reader_release(&br);
+	block_iter_close(&it);
+	reftable_record_release(&rec);
+	reftable_block_done(&br.block);
+	strbuf_release(&want);
+	strbuf_release(&buf);
+	for (i = 0; i < N; i++)
+		reftable_record_release(&recs[i]);
+}
+
+static void t_log_block_read_write(void)
+{
+	const int header_off = 21;
+	struct reftable_record recs[30];
+	const size_t N = ARRAY_SIZE(recs);
+	const size_t block_size = 2048;
+	struct reftable_block block = { 0 };
+	struct block_writer bw = {
+		.last_key = STRBUF_INIT,
+	};
+	struct reftable_record rec = {
+		.type = BLOCK_TYPE_LOG,
+	};
+	size_t i = 0;
+	int ret;
+	struct block_reader br = { 0 };
+	struct block_iter it = BLOCK_ITER_INIT;
+	struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
+
+	REFTABLE_CALLOC_ARRAY(block.data, block_size);
+	block.len = block_size;
+	block_source_from_strbuf(&block.source ,&buf);
+	block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
+			  header_off, hash_size(GIT_SHA1_FORMAT_ID));
+
+	for (i = 0; i < N; i++) {
+		rec.u.log.refname = xstrfmt("branch%02"PRIuMAX , (uintmax_t)i);
+		rec.u.log.update_index = i;
+		rec.u.log.value_type = REFTABLE_LOG_UPDATE;
+
+		recs[i] = rec;
+		ret = block_writer_add(&bw, &rec);
+		rec.u.log.refname = NULL;
+		rec.u.log.value_type = REFTABLE_LOG_DELETION;
+		check_int(ret, ==, 0);
+	}
+
+	ret = block_writer_finish(&bw);
+	check_int(ret, >, 0);
+
+	block_writer_release(&bw);
+
+	block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+	block_iter_seek_start(&it, &br);
+
+	for (i = 0; ; i++) {
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, >=, 0);
+		if (ret > 0) {
+			check_int(i, ==, N);
+			break;
+		}
+		check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+	}
+
+	for (i = 0; i < N; i++) {
+		block_iter_reset(&it);
+		strbuf_reset(&want);
+		strbuf_addstr(&want, recs[i].u.log.refname);
+
+		ret = block_iter_seek_key(&it, &br, &want);
+		check_int(ret, ==, 0);
+
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, ==, 0);
+
+		check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+
+		want.len--;
+		ret = block_iter_seek_key(&it, &br, &want);
+		check_int(ret, ==, 0);
+
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, ==, 0);
+		check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+	}
+
+	block_reader_release(&br);
+	block_iter_close(&it);
+	reftable_record_release(&rec);
+	reftable_block_done(&br.block);
+	strbuf_release(&want);
+	strbuf_release(&buf);
+	for (i = 0; i < N; i++)
+		reftable_record_release(&recs[i]);
+}
+
+static void t_obj_block_read_write(void)
+{
+	const int header_off = 21;
+	struct reftable_record recs[30];
+	const size_t N = ARRAY_SIZE(recs);
+	const size_t block_size = 1024;
+	struct reftable_block block = { 0 };
+	struct block_writer bw = {
+		.last_key = STRBUF_INIT,
+	};
+	struct reftable_record rec = {
+		.type = BLOCK_TYPE_OBJ,
+	};
+	size_t i = 0;
+	int ret;
+	struct block_reader br = { 0 };
+	struct block_iter it = BLOCK_ITER_INIT;
+	struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
+
+	REFTABLE_CALLOC_ARRAY(block.data, block_size);
+	block.len = block_size;
+	block_source_from_strbuf(&block.source, &buf);
+	block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
+			  header_off, hash_size(GIT_SHA1_FORMAT_ID));
+
+	for (i = 0; i < N; i++) {
+		uint8_t bytes[] = { i, i + 1, i + 2, i + 3, i + 5 }, *allocated;
+		DUP_ARRAY(allocated, bytes, ARRAY_SIZE(bytes));
+
+		rec.u.obj.hash_prefix = allocated;
+		rec.u.obj.hash_prefix_len = 5;
+
+		recs[i] = rec;
+		ret = block_writer_add(&bw, &rec);
+		rec.u.obj.hash_prefix = NULL;
+		rec.u.obj.hash_prefix_len = 0;
+		check_int(ret, ==, 0);
+	}
+
+	ret = block_writer_finish(&bw);
+	check_int(ret, >, 0);
+
+	block_writer_release(&bw);
+
+	block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+	block_iter_seek_start(&it, &br);
+
+	for (i = 0; ; i++) {
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, >=, 0);
+		if (ret > 0) {
+			check_int(i, ==, N);
+			break;
+		}
+		check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+	}
+
+	for (i = 0; i < N; i++) {
+		block_iter_reset(&it);
+		reftable_record_key(&recs[i], &want);
+
+		ret = block_iter_seek_key(&it, &br, &want);
+		check_int(ret, ==, 0);
+
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, ==, 0);
+
+		check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+	}
+
+	block_reader_release(&br);
+	block_iter_close(&it);
+	reftable_record_release(&rec);
+	reftable_block_done(&br.block);
+	strbuf_release(&want);
+	strbuf_release(&buf);
+	for (i = 0; i < N; i++)
+		reftable_record_release(&recs[i]);
+}
+
+static void t_index_block_read_write(void)
+{
+	const int header_off = 21;
+	struct reftable_record recs[30];
+	const size_t N = ARRAY_SIZE(recs);
+	const size_t block_size = 1024;
+	struct reftable_block block = { 0 };
+	struct block_writer bw = {
+		.last_key = STRBUF_INIT,
+	};
+	struct reftable_record rec = {
+		.type = BLOCK_TYPE_INDEX,
+		.u.idx.last_key = STRBUF_INIT,
+	};
+	size_t i = 0;
+	int ret;
+	struct block_reader br = { 0 };
+	struct block_iter it = BLOCK_ITER_INIT;
+	struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
+
+	REFTABLE_CALLOC_ARRAY(block.data, block_size);
+	block.len = block_size;
+	block_source_from_strbuf(&block.source, &buf);
+	block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
+			  header_off, hash_size(GIT_SHA1_FORMAT_ID));
+
+	for (i = 0; i < N; i++) {
+		strbuf_init(&recs[i].u.idx.last_key, 9);
+
+		recs[i].type = BLOCK_TYPE_INDEX;
+		strbuf_addf(&recs[i].u.idx.last_key, "branch%02"PRIuMAX, (uintmax_t)i);
+		recs[i].u.idx.offset = i;
+
+		ret = block_writer_add(&bw, &recs[i]);
+		check_int(ret, ==, 0);
+	}
+
+	ret = block_writer_finish(&bw);
+	check_int(ret, >, 0);
+
+	block_writer_release(&bw);
+
+	block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ);
+
+	block_iter_seek_start(&it, &br);
+
+	for (i = 0; ; i++) {
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, >=, 0);
+		if (ret > 0) {
+			check_int(i, ==, N);
+			break;
+		}
+		check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+	}
+
+	for (i = 0; i < N; i++) {
+		block_iter_reset(&it);
+		reftable_record_key(&recs[i], &want);
+
+		ret = block_iter_seek_key(&it, &br, &want);
+		check_int(ret, ==, 0);
+
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, ==, 0);
+
+		check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ));
+
+		want.len--;
+		ret = block_iter_seek_key(&it, &br, &want);
+		check_int(ret, ==, 0);
+
+		ret = block_iter_next(&it, &rec);
+		check_int(ret, ==, 0);
+		check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ));
+	}
+
+	block_reader_release(&br);
+	block_iter_close(&it);
+	reftable_record_release(&rec);
+	reftable_block_done(&br.block);
+	strbuf_release(&want);
+	strbuf_release(&buf);
+	for (i = 0; i < N; i++)
+		reftable_record_release(&recs[i]);
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+	TEST(t_index_block_read_write(), "read-write operations on index blocks work");
+	TEST(t_log_block_read_write(), "read-write operations on log blocks work");
+	TEST(t_obj_block_read_write(), "read-write operations on obj blocks work");
+	TEST(t_ref_block_read_write(), "read-write operations on ref blocks work");
+
+	return test_done();
+}
diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/t-reftable-merged.c
new file mode 100644
index 0000000..109d3b0
--- /dev/null
+++ b/t/unit-tests/t-reftable-merged.c
@@ -0,0 +1,465 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "lib-reftable.h"
+#include "reftable/blocksource.h"
+#include "reftable/constants.h"
+#include "reftable/merged.h"
+#include "reftable/reader.h"
+#include "reftable/reftable-error.h"
+#include "reftable/reftable-merged.h"
+#include "reftable/reftable-writer.h"
+
+static struct reftable_merged_table *
+merged_table_from_records(struct reftable_ref_record **refs,
+			  struct reftable_block_source **source,
+			  struct reftable_reader ***readers, const size_t *sizes,
+			  struct strbuf *buf, const size_t n)
+{
+	struct reftable_merged_table *mt = NULL;
+	struct reftable_write_options opts = {
+		.block_size = 256,
+	};
+	int err;
+
+	REFTABLE_CALLOC_ARRAY(*readers, n);
+	REFTABLE_CALLOC_ARRAY(*source, n);
+
+	for (size_t i = 0; i < n; i++) {
+		t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts);
+		block_source_from_strbuf(&(*source)[i], &buf[i]);
+
+		err = reftable_reader_new(&(*readers)[i], &(*source)[i],
+					  "name");
+		check(!err);
+	}
+
+	err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID);
+	check(!err);
+	return mt;
+}
+
+static void readers_destroy(struct reftable_reader **readers, const size_t n)
+{
+	for (size_t i = 0; i < n; i++)
+		reftable_reader_decref(readers[i]);
+	reftable_free(readers);
+}
+
+static void t_merged_single_record(void)
+{
+	struct reftable_ref_record r1[] = { {
+		.refname = (char *) "b",
+		.update_index = 1,
+		.value_type = REFTABLE_REF_VAL1,
+		.value.val1 = { 1, 2, 3, 0 },
+	} };
+	struct reftable_ref_record r2[] = { {
+		.refname = (char *) "a",
+		.update_index = 2,
+		.value_type = REFTABLE_REF_DELETION,
+	} };
+	struct reftable_ref_record r3[] = { {
+		.refname = (char *) "c",
+		.update_index = 3,
+		.value_type = REFTABLE_REF_DELETION,
+	} };
+
+	struct reftable_ref_record *refs[] = { r1, r2, r3 };
+	size_t sizes[] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) };
+	struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT };
+	struct reftable_block_source *bs = NULL;
+	struct reftable_reader **readers = NULL;
+	struct reftable_merged_table *mt =
+		merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3);
+	struct reftable_ref_record ref = { 0 };
+	struct reftable_iterator it = { 0 };
+	int err;
+
+	merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
+	err = reftable_iterator_seek_ref(&it, "a");
+	check(!err);
+
+	err = reftable_iterator_next_ref(&it, &ref);
+	check(!err);
+	check(reftable_ref_record_equal(&r2[0], &ref, GIT_SHA1_RAWSZ));
+	reftable_ref_record_release(&ref);
+	reftable_iterator_destroy(&it);
+	readers_destroy(readers, 3);
+	reftable_merged_table_free(mt);
+	for (size_t i = 0; i < ARRAY_SIZE(bufs); i++)
+		strbuf_release(&bufs[i]);
+	reftable_free(bs);
+}
+
+static void t_merged_refs(void)
+{
+	struct reftable_ref_record r1[] = {
+		{
+			.refname = (char *) "a",
+			.update_index = 1,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 1 },
+		},
+		{
+			.refname = (char *) "b",
+			.update_index = 1,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 1 },
+		},
+		{
+			.refname = (char *) "c",
+			.update_index = 1,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 1 },
+		}
+	};
+	struct reftable_ref_record r2[] = { {
+		.refname = (char *) "a",
+		.update_index = 2,
+		.value_type = REFTABLE_REF_DELETION,
+	} };
+	struct reftable_ref_record r3[] = {
+		{
+			.refname = (char *) "c",
+			.update_index = 3,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 2 },
+		},
+		{
+			.refname = (char *) "d",
+			.update_index = 3,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 1 },
+		},
+	};
+
+	struct reftable_ref_record *want[] = {
+		&r2[0],
+		&r1[1],
+		&r3[0],
+		&r3[1],
+	};
+
+	struct reftable_ref_record *refs[] = { r1, r2, r3 };
+	size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) };
+	struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT };
+	struct reftable_block_source *bs = NULL;
+	struct reftable_reader **readers = NULL;
+	struct reftable_merged_table *mt =
+		merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3);
+	struct reftable_iterator it = { 0 };
+	int err;
+	struct reftable_ref_record *out = NULL;
+	size_t len = 0;
+	size_t cap = 0;
+	size_t i;
+
+	merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
+	err = reftable_iterator_seek_ref(&it, "a");
+	check(!err);
+	check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID);
+	check_int(reftable_merged_table_min_update_index(mt), ==, 1);
+	check_int(reftable_merged_table_max_update_index(mt), ==, 3);
+
+	while (len < 100) { /* cap loops/recursion. */
+		struct reftable_ref_record ref = { 0 };
+		int err = reftable_iterator_next_ref(&it, &ref);
+		if (err > 0)
+			break;
+
+		REFTABLE_ALLOC_GROW(out, len + 1, cap);
+		out[len++] = ref;
+	}
+	reftable_iterator_destroy(&it);
+
+	check_int(ARRAY_SIZE(want), ==, len);
+	for (i = 0; i < len; i++)
+		check(reftable_ref_record_equal(want[i], &out[i],
+						 GIT_SHA1_RAWSZ));
+	for (i = 0; i < len; i++)
+		reftable_ref_record_release(&out[i]);
+	reftable_free(out);
+
+	for (i = 0; i < 3; i++)
+		strbuf_release(&bufs[i]);
+	readers_destroy(readers, 3);
+	reftable_merged_table_free(mt);
+	reftable_free(bs);
+}
+
+static void t_merged_seek_multiple_times(void)
+{
+	struct reftable_ref_record r1[] = {
+		{
+			.refname = (char *) "a",
+			.update_index = 1,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 1 },
+		},
+		{
+			.refname = (char *) "c",
+			.update_index = 1,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 2 },
+		}
+	};
+	struct reftable_ref_record r2[] = {
+		{
+			.refname = (char *) "b",
+			.update_index = 2,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 3 },
+		},
+		{
+			.refname = (char *) "d",
+			.update_index = 2,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 4 },
+		},
+	};
+	struct reftable_ref_record *refs[] = {
+		r1, r2,
+	};
+	size_t sizes[] = {
+		ARRAY_SIZE(r1), ARRAY_SIZE(r2),
+	};
+	struct strbuf bufs[] = {
+		STRBUF_INIT, STRBUF_INIT,
+	};
+	struct reftable_block_source *sources = NULL;
+	struct reftable_reader **readers = NULL;
+	struct reftable_ref_record rec = { 0 };
+	struct reftable_iterator it = { 0 };
+	struct reftable_merged_table *mt;
+
+	mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2);
+	merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
+
+	for (size_t i = 0; i < 5; i++) {
+		int err = reftable_iterator_seek_ref(&it, "c");
+		check(!err);
+
+		err = reftable_iterator_next_ref(&it, &rec);
+		check(!err);
+		err = reftable_ref_record_equal(&rec, &r1[1], GIT_SHA1_RAWSZ);
+		check(err == 1);
+
+		err = reftable_iterator_next_ref(&it, &rec);
+		check(!err);
+		err = reftable_ref_record_equal(&rec, &r2[1], GIT_SHA1_RAWSZ);
+		check(err == 1);
+
+		err = reftable_iterator_next_ref(&it, &rec);
+		check(err > 0);
+	}
+
+	for (size_t i = 0; i < ARRAY_SIZE(bufs); i++)
+		strbuf_release(&bufs[i]);
+	readers_destroy(readers, ARRAY_SIZE(refs));
+	reftable_ref_record_release(&rec);
+	reftable_iterator_destroy(&it);
+	reftable_merged_table_free(mt);
+	reftable_free(sources);
+}
+
+static struct reftable_merged_table *
+merged_table_from_log_records(struct reftable_log_record **logs,
+			      struct reftable_block_source **source,
+			      struct reftable_reader ***readers, const size_t *sizes,
+			      struct strbuf *buf, const size_t n)
+{
+	struct reftable_merged_table *mt = NULL;
+	struct reftable_write_options opts = {
+		.block_size = 256,
+		.exact_log_message = 1,
+	};
+	int err;
+
+	REFTABLE_CALLOC_ARRAY(*readers, n);
+	REFTABLE_CALLOC_ARRAY(*source, n);
+
+	for (size_t i = 0; i < n; i++) {
+		t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts);
+		block_source_from_strbuf(&(*source)[i], &buf[i]);
+
+		err = reftable_reader_new(&(*readers)[i], &(*source)[i],
+					  "name");
+		check(!err);
+	}
+
+	err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID);
+	check(!err);
+	return mt;
+}
+
+static void t_merged_logs(void)
+{
+	struct reftable_log_record r1[] = {
+		{
+			.refname = (char *) "a",
+			.update_index = 2,
+			.value_type = REFTABLE_LOG_UPDATE,
+			.value.update = {
+				.old_hash = { 2 },
+				/* deletion */
+				.name = (char *) "jane doe",
+				.email = (char *) "jane@invalid",
+				.message = (char *) "message2",
+			}
+		},
+		{
+			.refname = (char *) "a",
+			.update_index = 1,
+			.value_type = REFTABLE_LOG_UPDATE,
+			.value.update = {
+				.old_hash = { 1 },
+				.new_hash = { 2 },
+				.name = (char *) "jane doe",
+				.email = (char *) "jane@invalid",
+				.message = (char *) "message1",
+			}
+		},
+	};
+	struct reftable_log_record r2[] = {
+		{
+			.refname = (char *) "a",
+			.update_index = 3,
+			.value_type = REFTABLE_LOG_UPDATE,
+			.value.update = {
+				.new_hash = { 3 },
+				.name = (char *) "jane doe",
+				.email = (char *) "jane@invalid",
+				.message = (char *) "message3",
+			}
+		},
+	};
+	struct reftable_log_record r3[] = {
+		{
+			.refname = (char *) "a",
+			.update_index = 2,
+			.value_type = REFTABLE_LOG_DELETION,
+		},
+	};
+	struct reftable_log_record *want[] = {
+		&r2[0],
+		&r3[0],
+		&r1[1],
+	};
+
+	struct reftable_log_record *logs[] = { r1, r2, r3 };
+	size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) };
+	struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT };
+	struct reftable_block_source *bs = NULL;
+	struct reftable_reader **readers = NULL;
+	struct reftable_merged_table *mt = merged_table_from_log_records(
+		logs, &bs, &readers, sizes, bufs, 3);
+	struct reftable_iterator it = { 0 };
+	int err;
+	struct reftable_log_record *out = NULL;
+	size_t len = 0;
+	size_t cap = 0;
+	size_t i;
+
+	merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
+	err = reftable_iterator_seek_log(&it, "a");
+	check(!err);
+	check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID);
+	check_int(reftable_merged_table_min_update_index(mt), ==, 1);
+	check_int(reftable_merged_table_max_update_index(mt), ==, 3);
+
+	while (len < 100) { /* cap loops/recursion. */
+		struct reftable_log_record log = { 0 };
+		int err = reftable_iterator_next_log(&it, &log);
+		if (err > 0)
+			break;
+
+		REFTABLE_ALLOC_GROW(out, len + 1, cap);
+		out[len++] = log;
+	}
+	reftable_iterator_destroy(&it);
+
+	check_int(ARRAY_SIZE(want), ==, len);
+	for (i = 0; i < len; i++)
+		check(reftable_log_record_equal(want[i], &out[i],
+						 GIT_SHA1_RAWSZ));
+
+	merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
+	err = reftable_iterator_seek_log_at(&it, "a", 2);
+	check(!err);
+	reftable_log_record_release(&out[0]);
+	err = reftable_iterator_next_log(&it, &out[0]);
+	check(!err);
+	check(reftable_log_record_equal(&out[0], &r3[0], GIT_SHA1_RAWSZ));
+	reftable_iterator_destroy(&it);
+
+	for (i = 0; i < len; i++)
+		reftable_log_record_release(&out[i]);
+	reftable_free(out);
+
+	for (i = 0; i < 3; i++)
+		strbuf_release(&bufs[i]);
+	readers_destroy(readers, 3);
+	reftable_merged_table_free(mt);
+	reftable_free(bs);
+}
+
+static void t_default_write_opts(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+	struct reftable_ref_record rec = {
+		.refname = (char *) "master",
+		.update_index = 1,
+	};
+	int err;
+	struct reftable_block_source source = { 0 };
+	uint32_t hash_id;
+	struct reftable_reader *rd = NULL;
+	struct reftable_merged_table *merged = NULL;
+
+	reftable_writer_set_limits(w, 1, 1);
+
+	err = reftable_writer_add_ref(w, &rec);
+	check(!err);
+
+	err = reftable_writer_close(w);
+	check(!err);
+	reftable_writer_free(w);
+
+	block_source_from_strbuf(&source, &buf);
+
+	err = reftable_reader_new(&rd, &source, "filename");
+	check(!err);
+
+	hash_id = reftable_reader_hash_id(rd);
+	check_int(hash_id, ==, GIT_SHA1_FORMAT_ID);
+
+	err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA256_FORMAT_ID);
+	check_int(err, ==, REFTABLE_FORMAT_ERROR);
+	err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA1_FORMAT_ID);
+	check(!err);
+
+	reftable_reader_decref(rd);
+	reftable_merged_table_free(merged);
+	strbuf_release(&buf);
+}
+
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+	TEST(t_default_write_opts(), "merged table with default write opts");
+	TEST(t_merged_logs(), "merged table with multiple log updates for same ref");
+	TEST(t_merged_refs(), "merged table with multiple updates to same ref");
+	TEST(t_merged_seek_multiple_times(), "merged table can seek multiple times");
+	TEST(t_merged_single_record(), "ref occurring in only one record can be fetched");
+
+	return test_done();
+}
diff --git a/t/unit-tests/t-reftable-pq.c b/t/unit-tests/t-reftable-pq.c
new file mode 100644
index 0000000..ada4c19
--- /dev/null
+++ b/t/unit-tests/t-reftable-pq.c
@@ -0,0 +1,152 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "reftable/constants.h"
+#include "reftable/pq.h"
+
+static void merged_iter_pqueue_check(const struct merged_iter_pqueue *pq)
+{
+	for (size_t i = 1; i < pq->len; i++) {
+		size_t parent = (i - 1) / 2;
+		check(pq_less(&pq->heap[parent], &pq->heap[i]));
+	}
+}
+
+static int pq_entry_equal(struct pq_entry *a, struct pq_entry *b)
+{
+	return !reftable_record_cmp(a->rec, b->rec) && (a->index == b->index);
+}
+
+static void t_pq_record(void)
+{
+	struct merged_iter_pqueue pq = { 0 };
+	struct reftable_record recs[54];
+	size_t N = ARRAY_SIZE(recs) - 1, i;
+	char *last = NULL;
+
+	for (i = 0; i < N; i++) {
+		reftable_record_init(&recs[i], BLOCK_TYPE_REF);
+		recs[i].u.ref.refname = xstrfmt("%02"PRIuMAX, (uintmax_t)i);
+	}
+
+	i = 1;
+	do {
+		struct pq_entry e = {
+			.rec = &recs[i],
+		};
+
+		merged_iter_pqueue_add(&pq, &e);
+		merged_iter_pqueue_check(&pq);
+		i = (i * 7) % N;
+	} while (i != 1);
+
+	while (!merged_iter_pqueue_is_empty(pq)) {
+		struct pq_entry top = merged_iter_pqueue_top(pq);
+		struct pq_entry e = merged_iter_pqueue_remove(&pq);
+		merged_iter_pqueue_check(&pq);
+
+		check(pq_entry_equal(&top, &e));
+		check(reftable_record_type(e.rec) == BLOCK_TYPE_REF);
+		if (last)
+			check_int(strcmp(last, e.rec->u.ref.refname), <, 0);
+		last = e.rec->u.ref.refname;
+	}
+
+	for (i = 0; i < N; i++)
+		reftable_record_release(&recs[i]);
+	merged_iter_pqueue_release(&pq);
+}
+
+static void t_pq_index(void)
+{
+	struct merged_iter_pqueue pq = { 0 };
+	struct reftable_record recs[13];
+	char *last = NULL;
+	size_t N = ARRAY_SIZE(recs), i;
+
+	for (i = 0; i < N; i++) {
+		reftable_record_init(&recs[i], BLOCK_TYPE_REF);
+		recs[i].u.ref.refname = (char *) "refs/heads/master";
+	}
+
+	i = 1;
+	do {
+		struct pq_entry e = {
+			.rec = &recs[i],
+			.index = i,
+		};
+
+		merged_iter_pqueue_add(&pq, &e);
+		merged_iter_pqueue_check(&pq);
+		i = (i * 7) % N;
+	} while (i != 1);
+
+	for (i = N - 1; i > 0; i--) {
+		struct pq_entry top = merged_iter_pqueue_top(pq);
+		struct pq_entry e = merged_iter_pqueue_remove(&pq);
+		merged_iter_pqueue_check(&pq);
+
+		check(pq_entry_equal(&top, &e));
+		check(reftable_record_type(e.rec) == BLOCK_TYPE_REF);
+		check_int(e.index, ==, i);
+		if (last)
+			check_str(last, e.rec->u.ref.refname);
+		last = e.rec->u.ref.refname;
+	}
+
+	merged_iter_pqueue_release(&pq);
+}
+
+static void t_merged_iter_pqueue_top(void)
+{
+	struct merged_iter_pqueue pq = { 0 };
+	struct reftable_record recs[13];
+	size_t N = ARRAY_SIZE(recs), i;
+
+	for (i = 0; i < N; i++) {
+		reftable_record_init(&recs[i], BLOCK_TYPE_REF);
+		recs[i].u.ref.refname = (char *) "refs/heads/master";
+	}
+
+	i = 1;
+	do {
+		struct pq_entry e = {
+			.rec = &recs[i],
+			.index = i,
+		};
+
+		merged_iter_pqueue_add(&pq, &e);
+		merged_iter_pqueue_check(&pq);
+		i = (i * 7) % N;
+	} while (i != 1);
+
+	for (i = N - 1; i > 0; i--) {
+		struct pq_entry top = merged_iter_pqueue_top(pq);
+		struct pq_entry e = merged_iter_pqueue_remove(&pq);
+
+		merged_iter_pqueue_check(&pq);
+		check(pq_entry_equal(&top, &e));
+		check(reftable_record_equal(top.rec, &recs[i], GIT_SHA1_RAWSZ));
+		for (size_t j = 0; i < pq.len; j++) {
+			check(pq_less(&top, &pq.heap[j]));
+			check_int(top.index, >, j);
+		}
+	}
+
+	merged_iter_pqueue_release(&pq);
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+	TEST(t_pq_record(), "pq works with record-based comparison");
+	TEST(t_pq_index(), "pq works with index-based comparison");
+	TEST(t_merged_iter_pqueue_top(), "merged_iter_pqueue_top works");
+
+	return test_done();
+}
diff --git a/t/unit-tests/t-reftable-reader.c b/t/unit-tests/t-reftable-reader.c
new file mode 100644
index 0000000..eea8696
--- /dev/null
+++ b/t/unit-tests/t-reftable-reader.c
@@ -0,0 +1,96 @@
+#include "test-lib.h"
+#include "lib-reftable.h"
+#include "reftable/blocksource.h"
+#include "reftable/reader.h"
+
+static int t_reader_seek_once(void)
+{
+	struct reftable_ref_record records[] = {
+		{
+			.refname = (char *) "refs/heads/main",
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 42 },
+		},
+	};
+	struct reftable_block_source source = { 0 };
+	struct reftable_ref_record ref = { 0 };
+	struct reftable_iterator it = { 0 };
+	struct reftable_reader *reader;
+	struct strbuf buf = STRBUF_INIT;
+	int ret;
+
+	t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL);
+	block_source_from_strbuf(&source, &buf);
+
+	ret = reftable_reader_new(&reader, &source, "name");
+	check(!ret);
+
+	reftable_reader_init_ref_iterator(reader, &it);
+	ret = reftable_iterator_seek_ref(&it, "");
+	check(!ret);
+	ret = reftable_iterator_next_ref(&it, &ref);
+	check(!ret);
+
+	ret = reftable_ref_record_equal(&ref, &records[0], GIT_SHA1_RAWSZ);
+	check_int(ret, ==, 1);
+
+	ret = reftable_iterator_next_ref(&it, &ref);
+	check_int(ret, ==, 1);
+
+	reftable_ref_record_release(&ref);
+	reftable_iterator_destroy(&it);
+	reftable_reader_decref(reader);
+	strbuf_release(&buf);
+	return 0;
+}
+
+static int t_reader_reseek(void)
+{
+	struct reftable_ref_record records[] = {
+		{
+			.refname = (char *) "refs/heads/main",
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { 42 },
+		},
+	};
+	struct reftable_block_source source = { 0 };
+	struct reftable_ref_record ref = { 0 };
+	struct reftable_iterator it = { 0 };
+	struct reftable_reader *reader;
+	struct strbuf buf = STRBUF_INIT;
+	int ret;
+
+	t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL);
+	block_source_from_strbuf(&source, &buf);
+
+	ret = reftable_reader_new(&reader, &source, "name");
+	check(!ret);
+
+	reftable_reader_init_ref_iterator(reader, &it);
+
+	for (size_t i = 0; i < 5; i++) {
+		ret = reftable_iterator_seek_ref(&it, "");
+		check(!ret);
+		ret = reftable_iterator_next_ref(&it, &ref);
+		check(!ret);
+
+		ret = reftable_ref_record_equal(&ref, &records[0], GIT_SHA1_RAWSZ);
+		check_int(ret, ==, 1);
+
+		ret = reftable_iterator_next_ref(&it, &ref);
+		check_int(ret, ==, 1);
+	}
+
+	reftable_ref_record_release(&ref);
+	reftable_iterator_destroy(&it);
+	reftable_reader_decref(reader);
+	strbuf_release(&buf);
+	return 0;
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+	TEST(t_reader_seek_once(), "reader can seek once");
+	TEST(t_reader_reseek(), "reader can reseek multiple times");
+	return test_done();
+}
diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c
new file mode 100644
index 0000000..e1b235a
--- /dev/null
+++ b/t/unit-tests/t-reftable-readwrite.c
@@ -0,0 +1,926 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "lib-reftable.h"
+#include "reftable/basics.h"
+#include "reftable/blocksource.h"
+#include "reftable/reader.h"
+#include "reftable/reftable-error.h"
+#include "reftable/reftable-writer.h"
+
+static const int update_index = 5;
+
+static void t_buffer(void)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_block_source source = { 0 };
+	struct reftable_block out = { 0 };
+	int n;
+	uint8_t in[] = "hello";
+	strbuf_add(&buf, in, sizeof(in));
+	block_source_from_strbuf(&source, &buf);
+	check_int(block_source_size(&source), ==, 6);
+	n = block_source_read_block(&source, &out, 0, sizeof(in));
+	check_int(n, ==, sizeof(in));
+	check(!memcmp(in, out.data, n));
+	reftable_block_done(&out);
+
+	n = block_source_read_block(&source, &out, 1, 2);
+	check_int(n, ==, 2);
+	check(!memcmp(out.data, "el", 2));
+
+	reftable_block_done(&out);
+	block_source_close(&source);
+	strbuf_release(&buf);
+}
+
+static void write_table(char ***names, struct strbuf *buf, int N,
+			int block_size, uint32_t hash_id)
+{
+	struct reftable_write_options opts = {
+		.block_size = block_size,
+		.hash_id = hash_id,
+	};
+	struct reftable_ref_record *refs;
+	struct reftable_log_record *logs;
+	int i;
+
+	REFTABLE_CALLOC_ARRAY(*names, N + 1);
+	REFTABLE_CALLOC_ARRAY(refs, N);
+	REFTABLE_CALLOC_ARRAY(logs, N);
+
+	for (i = 0; i < N; i++) {
+		refs[i].refname = (*names)[i] = xstrfmt("refs/heads/branch%02d", i);
+		refs[i].update_index = update_index;
+		refs[i].value_type = REFTABLE_REF_VAL1;
+		t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID);
+	}
+
+	for (i = 0; i < N; i++) {
+		logs[i].refname = (*names)[i];
+		logs[i].update_index = update_index;
+		logs[i].value_type = REFTABLE_LOG_UPDATE;
+		t_reftable_set_hash(logs[i].value.update.new_hash, i,
+				    GIT_SHA1_FORMAT_ID);
+		logs[i].value.update.message = (char *) "message";
+	}
+
+	t_reftable_write_to_buf(buf, refs, N, logs, N, &opts);
+
+	free(refs);
+	free(logs);
+}
+
+static void t_log_buffer_size(void)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_write_options opts = {
+		.block_size = 4096,
+	};
+	int err;
+	int i;
+	struct reftable_log_record
+		log = { .refname = (char *) "refs/heads/master",
+			.update_index = 0xa,
+			.value_type = REFTABLE_LOG_UPDATE,
+			.value = { .update = {
+					   .name = (char *) "Han-Wen Nienhuys",
+					   .email = (char *) "hanwen@google.com",
+					   .tz_offset = 100,
+					   .time = 0x5e430672,
+					   .message = (char *) "commit: 9\n",
+				   } } };
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+
+	/* This tests buffer extension for log compression. Must use a random
+	   hash, to ensure that the compressed part is larger than the original.
+	*/
+	for (i = 0; i < GIT_SHA1_RAWSZ; i++) {
+		log.value.update.old_hash[i] = (uint8_t)(git_rand() % 256);
+		log.value.update.new_hash[i] = (uint8_t)(git_rand() % 256);
+	}
+	reftable_writer_set_limits(w, update_index, update_index);
+	err = reftable_writer_add_log(w, &log);
+	check(!err);
+	err = reftable_writer_close(w);
+	check(!err);
+	reftable_writer_free(w);
+	strbuf_release(&buf);
+}
+
+static void t_log_overflow(void)
+{
+	struct strbuf buf = STRBUF_INIT;
+	char msg[256] = { 0 };
+	struct reftable_write_options opts = {
+		.block_size = ARRAY_SIZE(msg),
+	};
+	int err;
+	struct reftable_log_record log = {
+		.refname = (char *) "refs/heads/master",
+		.update_index = 0xa,
+		.value_type = REFTABLE_LOG_UPDATE,
+		.value = {
+			.update = {
+				.old_hash = { 1 },
+				.new_hash = { 2 },
+				.name = (char *) "Han-Wen Nienhuys",
+				.email = (char *) "hanwen@google.com",
+				.tz_offset = 100,
+				.time = 0x5e430672,
+				.message = msg,
+			},
+		},
+	};
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+
+	memset(msg, 'x', sizeof(msg) - 1);
+	reftable_writer_set_limits(w, update_index, update_index);
+	err = reftable_writer_add_log(w, &log);
+	check_int(err, ==, REFTABLE_ENTRY_TOO_BIG_ERROR);
+	reftable_writer_free(w);
+	strbuf_release(&buf);
+}
+
+static void t_log_write_read(void)
+{
+	int N = 2;
+	char **names = reftable_calloc(N + 1, sizeof(*names));
+	int err;
+	struct reftable_write_options opts = {
+		.block_size = 256,
+	};
+	struct reftable_ref_record ref = { 0 };
+	int i = 0;
+	struct reftable_log_record log = { 0 };
+	int n;
+	struct reftable_iterator it = { 0 };
+	struct reftable_reader *reader;
+	struct reftable_block_source source = { 0 };
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+	const struct reftable_stats *stats = NULL;
+	reftable_writer_set_limits(w, 0, N);
+	for (i = 0; i < N; i++) {
+		char name[256];
+		struct reftable_ref_record ref = { 0 };
+		snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7);
+		names[i] = xstrdup(name);
+		ref.refname = name;
+		ref.update_index = i;
+
+		err = reftable_writer_add_ref(w, &ref);
+		check(!err);
+	}
+	for (i = 0; i < N; i++) {
+		struct reftable_log_record log = { 0 };
+
+		log.refname = names[i];
+		log.update_index = i;
+		log.value_type = REFTABLE_LOG_UPDATE;
+		t_reftable_set_hash(log.value.update.old_hash, i,
+				    GIT_SHA1_FORMAT_ID);
+		t_reftable_set_hash(log.value.update.new_hash, i + 1,
+				    GIT_SHA1_FORMAT_ID);
+
+		err = reftable_writer_add_log(w, &log);
+		check(!err);
+	}
+
+	n = reftable_writer_close(w);
+	check_int(n, ==, 0);
+
+	stats = reftable_writer_stats(w);
+	check_int(stats->log_stats.blocks, >, 0);
+	reftable_writer_free(w);
+	w = NULL;
+
+	block_source_from_strbuf(&source, &buf);
+
+	err = reftable_reader_new(&reader, &source, "file.log");
+	check(!err);
+
+	reftable_reader_init_ref_iterator(reader, &it);
+
+	err = reftable_iterator_seek_ref(&it, names[N - 1]);
+	check(!err);
+
+	err = reftable_iterator_next_ref(&it, &ref);
+	check(!err);
+
+	/* end of iteration. */
+	err = reftable_iterator_next_ref(&it, &ref);
+	check_int(err, >, 0);
+
+	reftable_iterator_destroy(&it);
+	reftable_ref_record_release(&ref);
+
+	reftable_reader_init_log_iterator(reader, &it);
+
+	err = reftable_iterator_seek_log(&it, "");
+	check(!err);
+
+	for (i = 0; ; i++) {
+		int err = reftable_iterator_next_log(&it, &log);
+		if (err > 0)
+			break;
+		check(!err);
+		check_str(names[i], log.refname);
+		check_int(i, ==, log.update_index);
+		reftable_log_record_release(&log);
+	}
+
+	check_int(i, ==, N);
+	reftable_iterator_destroy(&it);
+
+	/* cleanup. */
+	strbuf_release(&buf);
+	free_names(names);
+	reftable_reader_decref(reader);
+}
+
+static void t_log_zlib_corruption(void)
+{
+	struct reftable_write_options opts = {
+		.block_size = 256,
+	};
+	struct reftable_iterator it = { 0 };
+	struct reftable_reader *reader;
+	struct reftable_block_source source = { 0 };
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+	const struct reftable_stats *stats = NULL;
+	char message[100] = { 0 };
+	int err, i, n;
+	struct reftable_log_record log = {
+		.refname = (char *) "refname",
+		.value_type = REFTABLE_LOG_UPDATE,
+		.value = {
+			.update = {
+				.new_hash = { 1 },
+				.old_hash = { 2 },
+				.name = (char *) "My Name",
+				.email = (char *) "myname@invalid",
+				.message = message,
+			},
+		},
+	};
+
+	for (i = 0; i < sizeof(message) - 1; i++)
+		message[i] = (uint8_t)(git_rand() % 64 + ' ');
+
+	reftable_writer_set_limits(w, 1, 1);
+
+	err = reftable_writer_add_log(w, &log);
+	check(!err);
+
+	n = reftable_writer_close(w);
+	check_int(n, ==, 0);
+
+	stats = reftable_writer_stats(w);
+	check_int(stats->log_stats.blocks, >, 0);
+	reftable_writer_free(w);
+	w = NULL;
+
+	/* corrupt the data. */
+	buf.buf[50] ^= 0x99;
+
+	block_source_from_strbuf(&source, &buf);
+
+	err = reftable_reader_new(&reader, &source, "file.log");
+	check(!err);
+
+	reftable_reader_init_log_iterator(reader, &it);
+	err = reftable_iterator_seek_log(&it, "refname");
+	check_int(err, ==, REFTABLE_ZLIB_ERROR);
+
+	reftable_iterator_destroy(&it);
+
+	/* cleanup. */
+	reftable_reader_decref(reader);
+	strbuf_release(&buf);
+}
+
+static void t_table_read_write_sequential(void)
+{
+	char **names;
+	struct strbuf buf = STRBUF_INIT;
+	int N = 50;
+	struct reftable_iterator it = { 0 };
+	struct reftable_block_source source = { 0 };
+	struct reftable_reader *reader;
+	int err = 0;
+	int j = 0;
+
+	write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
+
+	block_source_from_strbuf(&source, &buf);
+
+	err = reftable_reader_new(&reader, &source, "file.ref");
+	check(!err);
+
+	reftable_reader_init_ref_iterator(reader, &it);
+	err = reftable_iterator_seek_ref(&it, "");
+	check(!err);
+
+	for (j = 0; ; j++) {
+		struct reftable_ref_record ref = { 0 };
+		int r = reftable_iterator_next_ref(&it, &ref);
+		check_int(r, >=, 0);
+		if (r > 0)
+			break;
+		check_str(names[j], ref.refname);
+		check_int(update_index, ==, ref.update_index);
+		reftable_ref_record_release(&ref);
+	}
+	check_int(j, ==, N);
+
+	reftable_iterator_destroy(&it);
+	reftable_reader_decref(reader);
+	strbuf_release(&buf);
+	free_names(names);
+}
+
+static void t_table_write_small_table(void)
+{
+	char **names;
+	struct strbuf buf = STRBUF_INIT;
+	int N = 1;
+	write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID);
+	check_int(buf.len, <, 200);
+	strbuf_release(&buf);
+	free_names(names);
+}
+
+static void t_table_read_api(void)
+{
+	char **names;
+	struct strbuf buf = STRBUF_INIT;
+	int N = 50;
+	struct reftable_reader *reader;
+	struct reftable_block_source source = { 0 };
+	int err;
+	struct reftable_log_record log = { 0 };
+	struct reftable_iterator it = { 0 };
+
+	write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
+
+	block_source_from_strbuf(&source, &buf);
+
+	err = reftable_reader_new(&reader, &source, "file.ref");
+	check(!err);
+
+	reftable_reader_init_ref_iterator(reader, &it);
+	err = reftable_iterator_seek_ref(&it, names[0]);
+	check(!err);
+
+	err = reftable_iterator_next_log(&it, &log);
+	check_int(err, ==, REFTABLE_API_ERROR);
+
+	strbuf_release(&buf);
+	free_names(names);
+	reftable_iterator_destroy(&it);
+	reftable_reader_decref(reader);
+	strbuf_release(&buf);
+}
+
+static void t_table_read_write_seek(int index, int hash_id)
+{
+	char **names;
+	struct strbuf buf = STRBUF_INIT;
+	int N = 50;
+	struct reftable_reader *reader;
+	struct reftable_block_source source = { 0 };
+	int err;
+	int i = 0;
+
+	struct reftable_iterator it = { 0 };
+	struct strbuf pastLast = STRBUF_INIT;
+	struct reftable_ref_record ref = { 0 };
+
+	write_table(&names, &buf, N, 256, hash_id);
+
+	block_source_from_strbuf(&source, &buf);
+
+	err = reftable_reader_new(&reader, &source, "file.ref");
+	check(!err);
+	check_int(hash_id, ==, reftable_reader_hash_id(reader));
+
+	if (!index) {
+		reader->ref_offsets.index_offset = 0;
+	} else {
+		check_int(reader->ref_offsets.index_offset, >, 0);
+	}
+
+	for (i = 1; i < N; i++) {
+		reftable_reader_init_ref_iterator(reader, &it);
+		err = reftable_iterator_seek_ref(&it, names[i]);
+		check(!err);
+		err = reftable_iterator_next_ref(&it, &ref);
+		check(!err);
+		check_str(names[i], ref.refname);
+		check_int(REFTABLE_REF_VAL1, ==, ref.value_type);
+		check_int(i, ==, ref.value.val1[0]);
+
+		reftable_ref_record_release(&ref);
+		reftable_iterator_destroy(&it);
+	}
+
+	strbuf_addstr(&pastLast, names[N - 1]);
+	strbuf_addstr(&pastLast, "/");
+
+	reftable_reader_init_ref_iterator(reader, &it);
+	err = reftable_iterator_seek_ref(&it, pastLast.buf);
+	if (err == 0) {
+		struct reftable_ref_record ref = { 0 };
+		int err = reftable_iterator_next_ref(&it, &ref);
+		check_int(err, >, 0);
+	} else {
+		check_int(err, >, 0);
+	}
+
+	strbuf_release(&pastLast);
+	reftable_iterator_destroy(&it);
+
+	strbuf_release(&buf);
+	free_names(names);
+	reftable_reader_decref(reader);
+}
+
+static void t_table_read_write_seek_linear(void)
+{
+	t_table_read_write_seek(0, GIT_SHA1_FORMAT_ID);
+}
+
+static void t_table_read_write_seek_linear_sha256(void)
+{
+	t_table_read_write_seek(0, GIT_SHA256_FORMAT_ID);
+}
+
+static void t_table_read_write_seek_index(void)
+{
+	t_table_read_write_seek(1, GIT_SHA1_FORMAT_ID);
+}
+
+static void t_table_refs_for(int indexed)
+{
+	int N = 50;
+	char **want_names = reftable_calloc(N + 1, sizeof(*want_names));
+	int want_names_len = 0;
+	uint8_t want_hash[GIT_SHA1_RAWSZ];
+
+	struct reftable_write_options opts = {
+		.block_size = 256,
+	};
+	struct reftable_ref_record ref = { 0 };
+	int i = 0;
+	int n;
+	int err;
+	struct reftable_reader *reader;
+	struct reftable_block_source source = { 0 };
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+	struct reftable_iterator it = { 0 };
+	int j;
+
+	t_reftable_set_hash(want_hash, 4, GIT_SHA1_FORMAT_ID);
+
+	for (i = 0; i < N; i++) {
+		uint8_t hash[GIT_SHA1_RAWSZ];
+		char fill[51] = { 0 };
+		char name[100];
+		struct reftable_ref_record ref = { 0 };
+
+		memset(hash, i, sizeof(hash));
+		memset(fill, 'x', 50);
+		/* Put the variable part in the start */
+		snprintf(name, sizeof(name), "br%02d%s", i, fill);
+		name[40] = 0;
+		ref.refname = name;
+
+		ref.value_type = REFTABLE_REF_VAL2;
+		t_reftable_set_hash(ref.value.val2.value, i / 4,
+				    GIT_SHA1_FORMAT_ID);
+		t_reftable_set_hash(ref.value.val2.target_value, 3 + i / 4,
+				    GIT_SHA1_FORMAT_ID);
+
+		/* 80 bytes / entry, so 3 entries per block. Yields 17
+		 */
+		/* blocks. */
+		n = reftable_writer_add_ref(w, &ref);
+		check_int(n, ==, 0);
+
+		if (!memcmp(ref.value.val2.value, want_hash, GIT_SHA1_RAWSZ) ||
+		    !memcmp(ref.value.val2.target_value, want_hash, GIT_SHA1_RAWSZ))
+			want_names[want_names_len++] = xstrdup(name);
+	}
+
+	n = reftable_writer_close(w);
+	check_int(n, ==, 0);
+
+	reftable_writer_free(w);
+	w = NULL;
+
+	block_source_from_strbuf(&source, &buf);
+
+	err = reftable_reader_new(&reader, &source, "file.ref");
+	check(!err);
+	if (!indexed)
+		reader->obj_offsets.is_present = 0;
+
+	reftable_reader_init_ref_iterator(reader, &it);
+	err = reftable_iterator_seek_ref(&it, "");
+	check(!err);
+	reftable_iterator_destroy(&it);
+
+	err = reftable_reader_refs_for(reader, &it, want_hash);
+	check(!err);
+
+	for (j = 0; ; j++) {
+		int err = reftable_iterator_next_ref(&it, &ref);
+		check_int(err, >=, 0);
+		if (err > 0)
+			break;
+		check_int(j, <, want_names_len);
+		check_str(ref.refname, want_names[j]);
+		reftable_ref_record_release(&ref);
+	}
+	check_int(j, ==, want_names_len);
+
+	strbuf_release(&buf);
+	free_names(want_names);
+	reftable_iterator_destroy(&it);
+	reftable_reader_decref(reader);
+}
+
+static void t_table_refs_for_no_index(void)
+{
+	t_table_refs_for(0);
+}
+
+static void t_table_refs_for_obj_index(void)
+{
+	t_table_refs_for(1);
+}
+
+static void t_write_empty_table(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+	struct reftable_block_source source = { 0 };
+	struct reftable_reader *rd = NULL;
+	struct reftable_ref_record rec = { 0 };
+	struct reftable_iterator it = { 0 };
+	int err;
+
+	reftable_writer_set_limits(w, 1, 1);
+
+	err = reftable_writer_close(w);
+	check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR);
+	reftable_writer_free(w);
+
+	check_int(buf.len, ==, header_size(1) + footer_size(1));
+
+	block_source_from_strbuf(&source, &buf);
+
+	err = reftable_reader_new(&rd, &source, "filename");
+	check(!err);
+
+	reftable_reader_init_ref_iterator(rd, &it);
+	err = reftable_iterator_seek_ref(&it, "");
+	check(!err);
+
+	err = reftable_iterator_next_ref(&it, &rec);
+	check_int(err, >, 0);
+
+	reftable_iterator_destroy(&it);
+	reftable_reader_decref(rd);
+	strbuf_release(&buf);
+}
+
+static void t_write_object_id_min_length(void)
+{
+	struct reftable_write_options opts = {
+		.block_size = 75,
+	};
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+	struct reftable_ref_record ref = {
+		.update_index = 1,
+		.value_type = REFTABLE_REF_VAL1,
+		.value.val1 = {42},
+	};
+	int err;
+	int i;
+
+	reftable_writer_set_limits(w, 1, 1);
+
+	/* Write the same hash in many refs. If there is only 1 hash, the
+	 * disambiguating prefix is length 0 */
+	for (i = 0; i < 256; i++) {
+		char name[256];
+		snprintf(name, sizeof(name), "ref%05d", i);
+		ref.refname = name;
+		err = reftable_writer_add_ref(w, &ref);
+		check(!err);
+	}
+
+	err = reftable_writer_close(w);
+	check(!err);
+	check_int(reftable_writer_stats(w)->object_id_len, ==, 2);
+	reftable_writer_free(w);
+	strbuf_release(&buf);
+}
+
+static void t_write_object_id_length(void)
+{
+	struct reftable_write_options opts = {
+		.block_size = 75,
+	};
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+	struct reftable_ref_record ref = {
+		.update_index = 1,
+		.value_type = REFTABLE_REF_VAL1,
+		.value.val1 = {42},
+	};
+	int err;
+	int i;
+
+	reftable_writer_set_limits(w, 1, 1);
+
+	/* Write the same hash in many refs. If there is only 1 hash, the
+	 * disambiguating prefix is length 0 */
+	for (i = 0; i < 256; i++) {
+		char name[256];
+		snprintf(name, sizeof(name), "ref%05d", i);
+		ref.refname = name;
+		ref.value.val1[15] = i;
+		err = reftable_writer_add_ref(w, &ref);
+		check(!err);
+	}
+
+	err = reftable_writer_close(w);
+	check(!err);
+	check_int(reftable_writer_stats(w)->object_id_len, ==, 16);
+	reftable_writer_free(w);
+	strbuf_release(&buf);
+}
+
+static void t_write_empty_key(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+	struct reftable_ref_record ref = {
+		.refname = (char *) "",
+		.update_index = 1,
+		.value_type = REFTABLE_REF_DELETION,
+	};
+	int err;
+
+	reftable_writer_set_limits(w, 1, 1);
+	err = reftable_writer_add_ref(w, &ref);
+	check_int(err, ==, REFTABLE_API_ERROR);
+
+	err = reftable_writer_close(w);
+	check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR);
+	reftable_writer_free(w);
+	strbuf_release(&buf);
+}
+
+static void t_write_key_order(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
+	struct reftable_ref_record refs[2] = {
+		{
+			.refname = (char *) "b",
+			.update_index = 1,
+			.value_type = REFTABLE_REF_SYMREF,
+			.value = {
+				.symref = (char *) "target",
+			},
+		}, {
+			.refname = (char *) "a",
+			.update_index = 1,
+			.value_type = REFTABLE_REF_SYMREF,
+			.value = {
+				.symref = (char *) "target",
+			},
+		}
+	};
+	int err;
+
+	reftable_writer_set_limits(w, 1, 1);
+	err = reftable_writer_add_ref(w, &refs[0]);
+	check(!err);
+	err = reftable_writer_add_ref(w, &refs[1]);
+	check_int(err, ==, REFTABLE_API_ERROR);
+
+	refs[0].update_index = 2;
+	err = reftable_writer_add_ref(w, &refs[0]);
+	check_int(err, ==, REFTABLE_API_ERROR);
+
+	reftable_writer_close(w);
+	reftable_writer_free(w);
+	strbuf_release(&buf);
+}
+
+static void t_write_multiple_indices(void)
+{
+	struct reftable_write_options opts = {
+		.block_size = 100,
+	};
+	struct strbuf writer_buf = STRBUF_INIT, buf = STRBUF_INIT;
+	struct reftable_block_source source = { 0 };
+	struct reftable_iterator it = { 0 };
+	const struct reftable_stats *stats;
+	struct reftable_writer *writer;
+	struct reftable_reader *reader;
+	int err, i;
+
+	writer = t_reftable_strbuf_writer(&writer_buf, &opts);
+	reftable_writer_set_limits(writer, 1, 1);
+	for (i = 0; i < 100; i++) {
+		struct reftable_ref_record ref = {
+			.update_index = 1,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = {i},
+		};
+
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "refs/heads/%04d", i);
+		ref.refname = buf.buf,
+
+		err = reftable_writer_add_ref(writer, &ref);
+		check(!err);
+	}
+
+	for (i = 0; i < 100; i++) {
+		struct reftable_log_record log = {
+			.update_index = 1,
+			.value_type = REFTABLE_LOG_UPDATE,
+			.value.update = {
+				.old_hash = { i },
+				.new_hash = { i },
+			},
+		};
+
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "refs/heads/%04d", i);
+		log.refname = buf.buf,
+
+		err = reftable_writer_add_log(writer, &log);
+		check(!err);
+	}
+
+	reftable_writer_close(writer);
+
+	/*
+	 * The written data should be sufficiently large to result in indices
+	 * for each of the block types.
+	 */
+	stats = reftable_writer_stats(writer);
+	check_int(stats->ref_stats.index_offset, >, 0);
+	check_int(stats->obj_stats.index_offset, >, 0);
+	check_int(stats->log_stats.index_offset, >, 0);
+
+	block_source_from_strbuf(&source, &writer_buf);
+	err = reftable_reader_new(&reader, &source, "filename");
+	check(!err);
+
+	/*
+	 * Seeking the log uses the log index now. In case there is any
+	 * confusion regarding indices we would notice here.
+	 */
+	reftable_reader_init_log_iterator(reader, &it);
+	err = reftable_iterator_seek_log(&it, "");
+	check(!err);
+
+	reftable_iterator_destroy(&it);
+	reftable_writer_free(writer);
+	reftable_reader_decref(reader);
+	strbuf_release(&writer_buf);
+	strbuf_release(&buf);
+}
+
+static void t_write_multi_level_index(void)
+{
+	struct reftable_write_options opts = {
+		.block_size = 100,
+	};
+	struct strbuf writer_buf = STRBUF_INIT, buf = STRBUF_INIT;
+	struct reftable_block_source source = { 0 };
+	struct reftable_iterator it = { 0 };
+	const struct reftable_stats *stats;
+	struct reftable_writer *writer;
+	struct reftable_reader *reader;
+	int err;
+
+	writer = t_reftable_strbuf_writer(&writer_buf, &opts);
+	reftable_writer_set_limits(writer, 1, 1);
+	for (size_t i = 0; i < 200; i++) {
+		struct reftable_ref_record ref = {
+			.update_index = 1,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = {i},
+		};
+
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "refs/heads/%03" PRIuMAX, (uintmax_t)i);
+		ref.refname = buf.buf,
+
+		err = reftable_writer_add_ref(writer, &ref);
+		check(!err);
+	}
+	reftable_writer_close(writer);
+
+	/*
+	 * The written refs should be sufficiently large to result in a
+	 * multi-level index.
+	 */
+	stats = reftable_writer_stats(writer);
+	check_int(stats->ref_stats.max_index_level, ==, 2);
+
+	block_source_from_strbuf(&source, &writer_buf);
+	err = reftable_reader_new(&reader, &source, "filename");
+	check(!err);
+
+	/*
+	 * Seeking the last ref should work as expected.
+	 */
+	reftable_reader_init_ref_iterator(reader, &it);
+	err = reftable_iterator_seek_ref(&it, "refs/heads/199");
+	check(!err);
+
+	reftable_iterator_destroy(&it);
+	reftable_writer_free(writer);
+	reftable_reader_decref(reader);
+	strbuf_release(&writer_buf);
+	strbuf_release(&buf);
+}
+
+static void t_corrupt_table_empty(void)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_block_source source = { 0 };
+	struct reftable_reader *reader;
+	int err;
+
+	block_source_from_strbuf(&source, &buf);
+	err = reftable_reader_new(&reader, &source, "file.log");
+	check_int(err, ==, REFTABLE_FORMAT_ERROR);
+}
+
+static void t_corrupt_table(void)
+{
+	uint8_t zeros[1024] = { 0 };
+	struct strbuf buf = STRBUF_INIT;
+	struct reftable_block_source source = { 0 };
+	struct reftable_reader *reader;
+	int err;
+	strbuf_add(&buf, zeros, sizeof(zeros));
+
+	block_source_from_strbuf(&source, &buf);
+	err = reftable_reader_new(&reader, &source, "file.log");
+	check_int(err, ==, REFTABLE_FORMAT_ERROR);
+
+	strbuf_release(&buf);
+}
+
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
+{
+	TEST(t_buffer(), "strbuf works as blocksource");
+	TEST(t_corrupt_table(), "read-write on corrupted table");
+	TEST(t_corrupt_table_empty(), "read-write on an empty table");
+	TEST(t_log_buffer_size(), "buffer extension for log compression");
+	TEST(t_log_overflow(), "log overflow returns expected error");
+	TEST(t_log_write_read(), "read-write on log records");
+	TEST(t_log_zlib_corruption(), "reading corrupted log record returns expected error");
+	TEST(t_table_read_api(), "read on a table");
+	TEST(t_table_read_write_seek_index(), "read-write on a table with index");
+	TEST(t_table_read_write_seek_linear(), "read-write on a table without index (SHA1)");
+	TEST(t_table_read_write_seek_linear_sha256(), "read-write on a table without index (SHA256)");
+	TEST(t_table_read_write_sequential(), "sequential read-write on a table");
+	TEST(t_table_refs_for_no_index(), "refs-only table with no index");
+	TEST(t_table_refs_for_obj_index(), "refs-only table with index");
+	TEST(t_table_write_small_table(), "write_table works");
+	TEST(t_write_empty_key(), "write on refs with empty keys");
+	TEST(t_write_empty_table(), "read-write on empty tables");
+	TEST(t_write_key_order(), "refs must be written in increasing order");
+	TEST(t_write_multi_level_index(), "table with multi-level index");
+	TEST(t_write_multiple_indices(), "table with indices for multiple block types");
+	TEST(t_write_object_id_length(), "prefix compression on writing refs");
+	TEST(t_write_object_id_min_length(), "prefix compression on writing refs");
+
+	return test_done();
+}
diff --git a/t/unit-tests/t-reftable-record.c b/t/unit-tests/t-reftable-record.c
index cb649ee..a7f67d4 100644
--- a/t/unit-tests/t-reftable-record.c
+++ b/t/unit-tests/t-reftable-record.c
@@ -532,7 +532,7 @@ static void t_reftable_index_record_roundtrip(void)
 	strbuf_release(&in.u.idx.last_key);
 }
 
-int cmd_main(int argc, const char *argv[])
+int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
 {
 	TEST(t_reftable_ref_record_comparison(), "comparison operations work on ref record");
 	TEST(t_reftable_log_record_comparison(), "comparison operations work on log record");
diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c
new file mode 100644
index 0000000..31d563d
--- /dev/null
+++ b/t/unit-tests/t-reftable-stack.c
@@ -0,0 +1,1386 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "lib-reftable.h"
+#include "reftable/merged.h"
+#include "reftable/reader.h"
+#include "reftable/reftable-error.h"
+#include "reftable/stack.h"
+#include <dirent.h>
+
+static void clear_dir(const char *dirname)
+{
+	struct strbuf path = STRBUF_INIT;
+	strbuf_addstr(&path, dirname);
+	remove_dir_recursively(&path, 0);
+	strbuf_release(&path);
+}
+
+static int count_dir_entries(const char *dirname)
+{
+	DIR *dir = opendir(dirname);
+	int len = 0;
+	struct dirent *d;
+	if (!dir)
+		return 0;
+
+	while ((d = readdir(dir))) {
+		/*
+		 * Besides skipping over "." and "..", we also need to
+		 * skip over other files that have a leading ".". This
+		 * is due to behaviour of NFS, which will rename files
+		 * to ".nfs*" to emulate delete-on-last-close.
+		 *
+		 * In any case this should be fine as the reftable
+		 * library will never write files with leading dots
+		 * anyway.
+		 */
+		if (starts_with(d->d_name, "."))
+			continue;
+		len++;
+	}
+	closedir(dir);
+	return len;
+}
+
+/*
+ * Work linenumber into the tempdir, so we can see which tests forget to
+ * cleanup.
+ */
+static char *get_tmp_template(int linenumber)
+{
+	const char *tmp = getenv("TMPDIR");
+	static char template[1024];
+	snprintf(template, sizeof(template) - 1, "%s/stack_test-%d.XXXXXX",
+		 tmp ? tmp : "/tmp", linenumber);
+	return template;
+}
+
+static char *get_tmp_dir(int linenumber)
+{
+	char *dir = get_tmp_template(linenumber);
+	check(mkdtemp(dir) != NULL);
+	return dir;
+}
+
+static void t_read_file(void)
+{
+	char *fn = get_tmp_template(__LINE__);
+	struct tempfile *tmp = mks_tempfile(fn);
+	int fd = get_tempfile_fd(tmp);
+	char out[1024] = "line1\n\nline2\nline3";
+	int n, err;
+	char **names = NULL;
+	const char *want[] = { "line1", "line2", "line3" };
+
+	check_int(fd, >, 0);
+	n = write_in_full(fd, out, strlen(out));
+	check_int(n, ==, strlen(out));
+	err = close(fd);
+	check_int(err, >=, 0);
+
+	err = read_lines(fn, &names);
+	check(!err);
+
+	for (size_t i = 0; names[i]; i++)
+		check_str(want[i], names[i]);
+	free_names(names);
+	(void) remove(fn);
+	delete_tempfile(&tmp);
+}
+
+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);
+	return reftable_writer_add_ref(wr, ref);
+}
+
+static void write_n_ref_tables(struct reftable_stack *st,
+			       size_t n)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int disable_auto_compact;
+	int err;
+
+	disable_auto_compact = st->opts.disable_auto_compact;
+	st->opts.disable_auto_compact = 1;
+
+	for (size_t i = 0; i < n; i++) {
+		struct reftable_ref_record ref = {
+			.update_index = reftable_stack_next_update_index(st),
+			.value_type = REFTABLE_REF_VAL1,
+		};
+
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "refs/heads/branch-%04"PRIuMAX, (uintmax_t)i);
+		ref.refname = buf.buf;
+		t_reftable_set_hash(ref.value.val1, i, GIT_SHA1_FORMAT_ID);
+
+		err = reftable_stack_add(st, &write_test_ref, &ref);
+		check(!err);
+	}
+
+	st->opts.disable_auto_compact = disable_auto_compact;
+	strbuf_release(&buf);
+}
+
+struct write_log_arg {
+	struct reftable_log_record *log;
+	uint64_t update_index;
+};
+
+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);
+	return reftable_writer_add_log(wr, wla->log);
+}
+
+static void t_reftable_stack_add_one(void)
+{
+	char *dir = get_tmp_dir(__LINE__);
+	struct strbuf scratch = STRBUF_INIT;
+	int mask = umask(002);
+	struct reftable_write_options opts = {
+		.default_permissions = 0660,
+	};
+	struct reftable_stack *st = NULL;
+	int err;
+	struct reftable_ref_record ref = {
+		.refname = (char *) "HEAD",
+		.update_index = 1,
+		.value_type = REFTABLE_REF_SYMREF,
+		.value.symref = (char *) "master",
+	};
+	struct reftable_ref_record dest = { 0 };
+	struct stat stat_result = { 0 };
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	err = reftable_stack_add(st, write_test_ref, &ref);
+	check(!err);
+
+	err = reftable_stack_read_ref(st, ref.refname, &dest);
+	check(!err);
+	check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
+	check_int(st->readers_len, >, 0);
+
+#ifndef GIT_WINDOWS_NATIVE
+	strbuf_addstr(&scratch, dir);
+	strbuf_addstr(&scratch, "/tables.list");
+	err = stat(scratch.buf, &stat_result);
+	check(!err);
+	check_int((stat_result.st_mode & 0777), ==, opts.default_permissions);
+
+	strbuf_reset(&scratch);
+	strbuf_addstr(&scratch, dir);
+	strbuf_addstr(&scratch, "/");
+	/* do not try at home; not an external API for reftable. */
+	strbuf_addstr(&scratch, st->readers[0]->name);
+	err = stat(scratch.buf, &stat_result);
+	check(!err);
+	check_int((stat_result.st_mode & 0777), ==, opts.default_permissions);
+#else
+	(void) stat_result;
+#endif
+
+	reftable_ref_record_release(&dest);
+	reftable_stack_destroy(st);
+	strbuf_release(&scratch);
+	clear_dir(dir);
+	umask(mask);
+}
+
+static void t_reftable_stack_uptodate(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st1 = NULL;
+	struct reftable_stack *st2 = NULL;
+	char *dir = get_tmp_dir(__LINE__);
+
+	int err;
+	struct reftable_ref_record ref1 = {
+		.refname = (char *) "HEAD",
+		.update_index = 1,
+		.value_type = REFTABLE_REF_SYMREF,
+		.value.symref = (char *) "master",
+	};
+	struct reftable_ref_record ref2 = {
+		.refname = (char *) "branch2",
+		.update_index = 2,
+		.value_type = REFTABLE_REF_SYMREF,
+		.value.symref = (char *) "master",
+	};
+
+
+	/* simulate multi-process access to the same stack
+	   by creating two stacks for the same directory.
+	 */
+	err = reftable_new_stack(&st1, dir, &opts);
+	check(!err);
+
+	err = reftable_new_stack(&st2, dir, &opts);
+	check(!err);
+
+	err = reftable_stack_add(st1, write_test_ref, &ref1);
+	check(!err);
+
+	err = reftable_stack_add(st2, write_test_ref, &ref2);
+	check_int(err, ==, REFTABLE_OUTDATED_ERROR);
+
+	err = reftable_stack_reload(st2);
+	check(!err);
+
+	err = reftable_stack_add(st2, write_test_ref, &ref2);
+	check(!err);
+	reftable_stack_destroy(st1);
+	reftable_stack_destroy(st2);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_transaction_api(void)
+{
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st = NULL;
+	int err;
+	struct reftable_addition *add = NULL;
+
+	struct reftable_ref_record ref = {
+		.refname = (char *) "HEAD",
+		.update_index = 1,
+		.value_type = REFTABLE_REF_SYMREF,
+		.value.symref = (char *) "master",
+	};
+	struct reftable_ref_record dest = { 0 };
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	reftable_addition_destroy(add);
+
+	err = reftable_stack_new_addition(&add, st, 0);
+	check(!err);
+
+	err = reftable_addition_add(add, write_test_ref, &ref);
+	check(!err);
+
+	err = reftable_addition_commit(add);
+	check(!err);
+
+	reftable_addition_destroy(add);
+
+	err = reftable_stack_read_ref(st, ref.refname, &dest);
+	check(!err);
+	check_int(REFTABLE_REF_SYMREF, ==, dest.value_type);
+	check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
+
+	reftable_ref_record_release(&dest);
+	reftable_stack_destroy(st);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_transaction_with_reload(void)
+{
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_stack *st1 = NULL, *st2 = NULL;
+	int err;
+	struct reftable_addition *add = NULL;
+	struct reftable_ref_record refs[2] = {
+		{
+			.refname = (char *) "refs/heads/a",
+			.update_index = 1,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { '1' },
+		},
+		{
+			.refname = (char *) "refs/heads/b",
+			.update_index = 2,
+			.value_type = REFTABLE_REF_VAL1,
+			.value.val1 = { '1' },
+		},
+	};
+	struct reftable_ref_record ref = { 0 };
+
+	err = reftable_new_stack(&st1, dir, NULL);
+	check(!err);
+	err = reftable_new_stack(&st2, dir, NULL);
+	check(!err);
+
+	err = reftable_stack_new_addition(&add, st1, 0);
+	check(!err);
+	err = reftable_addition_add(add, write_test_ref, &refs[0]);
+	check(!err);
+	err = reftable_addition_commit(add);
+	check(!err);
+	reftable_addition_destroy(add);
+
+	/*
+	 * The second stack is now outdated, which we should notice. We do not
+	 * create the addition and lock the stack by default, but allow the
+	 * reload to happen when REFTABLE_STACK_NEW_ADDITION_RELOAD is set.
+	 */
+	err = reftable_stack_new_addition(&add, st2, 0);
+	check_int(err, ==, REFTABLE_OUTDATED_ERROR);
+	err = reftable_stack_new_addition(&add, st2, REFTABLE_STACK_NEW_ADDITION_RELOAD);
+	check(!err);
+	err = reftable_addition_add(add, write_test_ref, &refs[1]);
+	check(!err);
+	err = reftable_addition_commit(add);
+	check(!err);
+	reftable_addition_destroy(add);
+
+	for (size_t i = 0; i < ARRAY_SIZE(refs); i++) {
+		err = reftable_stack_read_ref(st2, refs[i].refname, &ref);
+		check(!err);
+		check(reftable_ref_record_equal(&refs[i], &ref, GIT_SHA1_RAWSZ));
+	}
+
+	reftable_ref_record_release(&ref);
+	reftable_stack_destroy(st1);
+	reftable_stack_destroy(st2);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_transaction_api_performs_auto_compaction(void)
+{
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_write_options opts = {0};
+	struct reftable_addition *add = NULL;
+	struct reftable_stack *st = NULL;
+	size_t n = 20;
+	int err;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	for (size_t i = 0; i <= n; i++) {
+		struct reftable_ref_record ref = {
+			.update_index = reftable_stack_next_update_index(st),
+			.value_type = REFTABLE_REF_SYMREF,
+			.value.symref = (char *) "master",
+		};
+		char name[100];
+
+		snprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i);
+		ref.refname = name;
+
+		/*
+		 * Disable auto-compaction for all but the last runs. Like this
+		 * we can ensure that we indeed honor this setting and have
+		 * better control over when exactly auto compaction runs.
+		 */
+		st->opts.disable_auto_compact = i != n;
+
+		err = reftable_stack_new_addition(&add, st, 0);
+		check(!err);
+
+		err = reftable_addition_add(add, write_test_ref, &ref);
+		check(!err);
+
+		err = reftable_addition_commit(add);
+		check(!err);
+
+		reftable_addition_destroy(add);
+
+		/*
+		 * The stack length should grow continuously for all runs where
+		 * auto compaction is disabled. When enabled, we should merge
+		 * all tables in the stack.
+		 */
+		if (i != n)
+			check_int(st->merged->readers_len, ==, i + 1);
+		else
+			check_int(st->merged->readers_len, ==, 1);
+	}
+
+	reftable_stack_destroy(st);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_auto_compaction_fails_gracefully(void)
+{
+	struct reftable_ref_record ref = {
+		.refname = (char *) "refs/heads/master",
+		.update_index = 1,
+		.value_type = REFTABLE_REF_VAL1,
+		.value.val1 = {0x01},
+	};
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st;
+	struct strbuf table_path = STRBUF_INIT;
+	char *dir = get_tmp_dir(__LINE__);
+	int err;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	err = reftable_stack_add(st, write_test_ref, &ref);
+	check(!err);
+	check_int(st->merged->readers_len, ==, 1);
+	check_int(st->stats.attempts, ==, 0);
+	check_int(st->stats.failures, ==, 0);
+
+	/*
+	 * Lock the newly written table such that it cannot be compacted.
+	 * Adding a new table to the stack should not be impacted by this, even
+	 * though auto-compaction will now fail.
+	 */
+	strbuf_addf(&table_path, "%s/%s.lock", dir, st->readers[0]->name);
+	write_file_buf(table_path.buf, "", 0);
+
+	ref.update_index = 2;
+	err = reftable_stack_add(st, write_test_ref, &ref);
+	check(!err);
+	check_int(st->merged->readers_len, ==, 2);
+	check_int(st->stats.attempts, ==, 1);
+	check_int(st->stats.failures, ==, 1);
+
+	reftable_stack_destroy(st);
+	strbuf_release(&table_path);
+	clear_dir(dir);
+}
+
+static int write_error(struct reftable_writer *wr UNUSED, void *arg)
+{
+	return *((int *)arg);
+}
+
+static void t_reftable_stack_update_index_check(void)
+{
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st = NULL;
+	int err;
+	struct reftable_ref_record ref1 = {
+		.refname = (char *) "name1",
+		.update_index = 1,
+		.value_type = REFTABLE_REF_SYMREF,
+		.value.symref = (char *) "master",
+	};
+	struct reftable_ref_record ref2 = {
+		.refname = (char *) "name2",
+		.update_index = 1,
+		.value_type = REFTABLE_REF_SYMREF,
+		.value.symref = (char *) "master",
+	};
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	err = reftable_stack_add(st, write_test_ref, &ref1);
+	check(!err);
+
+	err = reftable_stack_add(st, write_test_ref, &ref2);
+	check_int(err, ==, REFTABLE_API_ERROR);
+	reftable_stack_destroy(st);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_lock_failure(void)
+{
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st = NULL;
+	int err, i;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+	for (i = -1; i != REFTABLE_EMPTY_TABLE_ERROR; i--) {
+		err = reftable_stack_add(st, write_error, &i);
+		check_int(err, ==, i);
+	}
+
+	reftable_stack_destroy(st);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_add(void)
+{
+	int err = 0;
+	struct reftable_write_options opts = {
+		.exact_log_message = 1,
+		.default_permissions = 0660,
+		.disable_auto_compact = 1,
+	};
+	struct reftable_stack *st = NULL;
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_ref_record refs[2] = { 0 };
+	struct reftable_log_record logs[2] = { 0 };
+	struct strbuf path = STRBUF_INIT;
+	struct stat stat_result;
+	size_t i, N = ARRAY_SIZE(refs);
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	for (i = 0; i < N; i++) {
+		char buf[256];
+		snprintf(buf, sizeof(buf), "branch%02"PRIuMAX, (uintmax_t)i);
+		refs[i].refname = xstrdup(buf);
+		refs[i].update_index = i + 1;
+		refs[i].value_type = REFTABLE_REF_VAL1;
+		t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID);
+
+		logs[i].refname = xstrdup(buf);
+		logs[i].update_index = N + i + 1;
+		logs[i].value_type = REFTABLE_LOG_UPDATE;
+		logs[i].value.update.email = xstrdup("identity@invalid");
+		t_reftable_set_hash(logs[i].value.update.new_hash, i, GIT_SHA1_FORMAT_ID);
+	}
+
+	for (i = 0; i < N; i++) {
+		int err = reftable_stack_add(st, write_test_ref, &refs[i]);
+		check(!err);
+	}
+
+	for (i = 0; i < N; i++) {
+		struct write_log_arg arg = {
+			.log = &logs[i],
+			.update_index = reftable_stack_next_update_index(st),
+		};
+		int err = reftable_stack_add(st, write_test_log, &arg);
+		check(!err);
+	}
+
+	err = reftable_stack_compact_all(st, NULL);
+	check(!err);
+
+	for (i = 0; i < N; i++) {
+		struct reftable_ref_record dest = { 0 };
+
+		int err = reftable_stack_read_ref(st, refs[i].refname, &dest);
+		check(!err);
+		check(reftable_ref_record_equal(&dest, refs + i,
+						 GIT_SHA1_RAWSZ));
+		reftable_ref_record_release(&dest);
+	}
+
+	for (i = 0; i < N; i++) {
+		struct reftable_log_record dest = { 0 };
+		int err = reftable_stack_read_log(st, refs[i].refname, &dest);
+		check(!err);
+		check(reftable_log_record_equal(&dest, logs + i,
+						 GIT_SHA1_RAWSZ));
+		reftable_log_record_release(&dest);
+	}
+
+#ifndef GIT_WINDOWS_NATIVE
+	strbuf_addstr(&path, dir);
+	strbuf_addstr(&path, "/tables.list");
+	err = stat(path.buf, &stat_result);
+	check(!err);
+	check_int((stat_result.st_mode & 0777), ==, opts.default_permissions);
+
+	strbuf_reset(&path);
+	strbuf_addstr(&path, dir);
+	strbuf_addstr(&path, "/");
+	/* do not try at home; not an external API for reftable. */
+	strbuf_addstr(&path, st->readers[0]->name);
+	err = stat(path.buf, &stat_result);
+	check(!err);
+	check_int((stat_result.st_mode & 0777), ==, opts.default_permissions);
+#else
+	(void) stat_result;
+#endif
+
+	/* cleanup */
+	reftable_stack_destroy(st);
+	for (i = 0; i < N; i++) {
+		reftable_ref_record_release(&refs[i]);
+		reftable_log_record_release(&logs[i]);
+	}
+	strbuf_release(&path);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_iterator(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st = NULL;
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_ref_record refs[10] = { 0 };
+	struct reftable_log_record logs[10] = { 0 };
+	struct reftable_iterator it = { 0 };
+	size_t N = ARRAY_SIZE(refs), i;
+	int err;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	for (i = 0; i < N; i++) {
+		refs[i].refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i);
+		refs[i].update_index = i + 1;
+		refs[i].value_type = REFTABLE_REF_VAL1;
+		t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID);
+
+		logs[i].refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i);
+		logs[i].update_index = i + 1;
+		logs[i].value_type = REFTABLE_LOG_UPDATE;
+		logs[i].value.update.email = xstrdup("johndoe@invalid");
+		logs[i].value.update.message = xstrdup("commit\n");
+		t_reftable_set_hash(logs[i].value.update.new_hash, i, GIT_SHA1_FORMAT_ID);
+	}
+
+	for (i = 0; i < N; i++) {
+		err = reftable_stack_add(st, write_test_ref, &refs[i]);
+		check(!err);
+	}
+
+	for (i = 0; i < N; i++) {
+		struct write_log_arg arg = {
+			.log = &logs[i],
+			.update_index = reftable_stack_next_update_index(st),
+		};
+
+		err = reftable_stack_add(st, write_test_log, &arg);
+		check(!err);
+	}
+
+	reftable_stack_init_ref_iterator(st, &it);
+	reftable_iterator_seek_ref(&it, refs[0].refname);
+	for (i = 0; ; i++) {
+		struct reftable_ref_record ref = { 0 };
+
+		err = reftable_iterator_next_ref(&it, &ref);
+		if (err > 0)
+			break;
+		check(!err);
+		check(reftable_ref_record_equal(&ref, &refs[i], GIT_SHA1_RAWSZ));
+		reftable_ref_record_release(&ref);
+	}
+	check_int(i, ==, N);
+
+	reftable_iterator_destroy(&it);
+
+	reftable_stack_init_log_iterator(st, &it);
+	reftable_iterator_seek_log(&it, logs[0].refname);
+	for (i = 0; ; i++) {
+		struct reftable_log_record log = { 0 };
+
+		err = reftable_iterator_next_log(&it, &log);
+		if (err > 0)
+			break;
+		check(!err);
+		check(reftable_log_record_equal(&log, &logs[i], GIT_SHA1_RAWSZ));
+		reftable_log_record_release(&log);
+	}
+	check_int(i, ==, N);
+
+	reftable_stack_destroy(st);
+	reftable_iterator_destroy(&it);
+	for (i = 0; i < N; i++) {
+		reftable_ref_record_release(&refs[i]);
+		reftable_log_record_release(&logs[i]);
+	}
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_log_normalize(void)
+{
+	int err = 0;
+	struct reftable_write_options opts = {
+		0,
+	};
+	struct reftable_stack *st = NULL;
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_log_record input = {
+		.refname = (char *) "branch",
+		.update_index = 1,
+		.value_type = REFTABLE_LOG_UPDATE,
+		.value = {
+			.update = {
+				.new_hash = { 1 },
+				.old_hash = { 2 },
+			},
+		},
+	};
+	struct reftable_log_record dest = {
+		.update_index = 0,
+	};
+	struct write_log_arg arg = {
+		.log = &input,
+		.update_index = 1,
+	};
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	input.value.update.message = (char *) "one\ntwo";
+	err = reftable_stack_add(st, write_test_log, &arg);
+	check_int(err, ==, REFTABLE_API_ERROR);
+
+	input.value.update.message = (char *) "one";
+	err = reftable_stack_add(st, write_test_log, &arg);
+	check(!err);
+
+	err = reftable_stack_read_log(st, input.refname, &dest);
+	check(!err);
+	check_str(dest.value.update.message, "one\n");
+
+	input.value.update.message = (char *) "two\n";
+	arg.update_index = 2;
+	err = reftable_stack_add(st, write_test_log, &arg);
+	check(!err);
+	err = reftable_stack_read_log(st, input.refname, &dest);
+	check(!err);
+	check_str(dest.value.update.message, "two\n");
+
+	/* cleanup */
+	reftable_stack_destroy(st);
+	reftable_log_record_release(&dest);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_tombstone(void)
+{
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st = NULL;
+	int err;
+	struct reftable_ref_record refs[2] = { 0 };
+	struct reftable_log_record logs[2] = { 0 };
+	size_t i, N = ARRAY_SIZE(refs);
+	struct reftable_ref_record dest = { 0 };
+	struct reftable_log_record log_dest = { 0 };
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	/* even entries add the refs, odd entries delete them. */
+	for (i = 0; i < N; i++) {
+		const char *buf = "branch";
+		refs[i].refname = xstrdup(buf);
+		refs[i].update_index = i + 1;
+		if (i % 2 == 0) {
+			refs[i].value_type = REFTABLE_REF_VAL1;
+			t_reftable_set_hash(refs[i].value.val1, i,
+					    GIT_SHA1_FORMAT_ID);
+		}
+
+		logs[i].refname = xstrdup(buf);
+		/* update_index is part of the key. */
+		logs[i].update_index = 42;
+		if (i % 2 == 0) {
+			logs[i].value_type = REFTABLE_LOG_UPDATE;
+			t_reftable_set_hash(logs[i].value.update.new_hash, i,
+					    GIT_SHA1_FORMAT_ID);
+			logs[i].value.update.email =
+				xstrdup("identity@invalid");
+		}
+	}
+	for (i = 0; i < N; i++) {
+		int err = reftable_stack_add(st, write_test_ref, &refs[i]);
+		check(!err);
+	}
+
+	for (i = 0; i < N; i++) {
+		struct write_log_arg arg = {
+			.log = &logs[i],
+			.update_index = reftable_stack_next_update_index(st),
+		};
+		int err = reftable_stack_add(st, write_test_log, &arg);
+		check(!err);
+	}
+
+	err = reftable_stack_read_ref(st, "branch", &dest);
+	check_int(err, ==, 1);
+	reftable_ref_record_release(&dest);
+
+	err = reftable_stack_read_log(st, "branch", &log_dest);
+	check_int(err, ==, 1);
+	reftable_log_record_release(&log_dest);
+
+	err = reftable_stack_compact_all(st, NULL);
+	check(!err);
+
+	err = reftable_stack_read_ref(st, "branch", &dest);
+	check_int(err, ==, 1);
+
+	err = reftable_stack_read_log(st, "branch", &log_dest);
+	check_int(err, ==, 1);
+	reftable_ref_record_release(&dest);
+	reftable_log_record_release(&log_dest);
+
+	/* cleanup */
+	reftable_stack_destroy(st);
+	for (i = 0; i < N; i++) {
+		reftable_ref_record_release(&refs[i]);
+		reftable_log_record_release(&logs[i]);
+	}
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_hash_id(void)
+{
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st = NULL;
+	int err;
+
+	struct reftable_ref_record ref = {
+		.refname = (char *) "master",
+		.value_type = REFTABLE_REF_SYMREF,
+		.value.symref = (char *) "target",
+		.update_index = 1,
+	};
+	struct reftable_write_options opts32 = { .hash_id = GIT_SHA256_FORMAT_ID };
+	struct reftable_stack *st32 = NULL;
+	struct reftable_write_options opts_default = { 0 };
+	struct reftable_stack *st_default = NULL;
+	struct reftable_ref_record dest = { 0 };
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	err = reftable_stack_add(st, write_test_ref, &ref);
+	check(!err);
+
+	/* can't read it with the wrong hash ID. */
+	err = reftable_new_stack(&st32, dir, &opts32);
+	check_int(err, ==, REFTABLE_FORMAT_ERROR);
+
+	/* check that we can read it back with default opts too. */
+	err = reftable_new_stack(&st_default, dir, &opts_default);
+	check(!err);
+
+	err = reftable_stack_read_ref(st_default, "master", &dest);
+	check(!err);
+
+	check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ));
+	reftable_ref_record_release(&dest);
+	reftable_stack_destroy(st);
+	reftable_stack_destroy(st_default);
+	clear_dir(dir);
+}
+
+static void t_suggest_compaction_segment(void)
+{
+	uint64_t sizes[] = { 512, 64, 17, 16, 9, 9, 9, 16, 2, 16 };
+	struct segment min =
+		suggest_compaction_segment(sizes, ARRAY_SIZE(sizes), 2);
+	check_int(min.start, ==, 1);
+	check_int(min.end, ==, 10);
+}
+
+static void t_suggest_compaction_segment_nothing(void)
+{
+	uint64_t sizes[] = { 64, 32, 16, 8, 4, 2 };
+	struct segment result =
+		suggest_compaction_segment(sizes, ARRAY_SIZE(sizes), 2);
+	check_int(result.start, ==, result.end);
+}
+
+static void t_reflog_expire(void)
+{
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st = NULL;
+	struct reftable_log_record logs[20] = { 0 };
+	size_t i, N = ARRAY_SIZE(logs) - 1;
+	int err;
+	struct reftable_log_expiry_config expiry = {
+		.time = 10,
+	};
+	struct reftable_log_record log = { 0 };
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	for (i = 1; i <= N; i++) {
+		char buf[256];
+		snprintf(buf, sizeof(buf), "branch%02"PRIuMAX, (uintmax_t)i);
+
+		logs[i].refname = xstrdup(buf);
+		logs[i].update_index = i;
+		logs[i].value_type = REFTABLE_LOG_UPDATE;
+		logs[i].value.update.time = i;
+		logs[i].value.update.email = xstrdup("identity@invalid");
+		t_reftable_set_hash(logs[i].value.update.new_hash, i,
+				    GIT_SHA1_FORMAT_ID);
+	}
+
+	for (i = 1; i <= N; i++) {
+		struct write_log_arg arg = {
+			.log = &logs[i],
+			.update_index = reftable_stack_next_update_index(st),
+		};
+		int err = reftable_stack_add(st, write_test_log, &arg);
+		check(!err);
+	}
+
+	err = reftable_stack_compact_all(st, NULL);
+	check(!err);
+
+	err = reftable_stack_compact_all(st, &expiry);
+	check(!err);
+
+	err = reftable_stack_read_log(st, logs[9].refname, &log);
+	check_int(err, ==, 1);
+
+	err = reftable_stack_read_log(st, logs[11].refname, &log);
+	check(!err);
+
+	expiry.min_update_index = 15;
+	err = reftable_stack_compact_all(st, &expiry);
+	check(!err);
+
+	err = reftable_stack_read_log(st, logs[14].refname, &log);
+	check_int(err, ==, 1);
+
+	err = reftable_stack_read_log(st, logs[16].refname, &log);
+	check(!err);
+
+	/* cleanup */
+	reftable_stack_destroy(st);
+	for (i = 0; i <= N; i++)
+		reftable_log_record_release(&logs[i]);
+	clear_dir(dir);
+	reftable_log_record_release(&log);
+}
+
+static int write_nothing(struct reftable_writer *wr, void *arg UNUSED)
+{
+	reftable_writer_set_limits(wr, 1, 1);
+	return 0;
+}
+
+static void t_empty_add(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st = NULL;
+	int err;
+	char *dir = get_tmp_dir(__LINE__);
+	struct reftable_stack *st2 = NULL;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	err = reftable_stack_add(st, write_nothing, NULL);
+	check(!err);
+
+	err = reftable_new_stack(&st2, dir, &opts);
+	check(!err);
+	clear_dir(dir);
+	reftable_stack_destroy(st);
+	reftable_stack_destroy(st2);
+}
+
+static int fastlogN(uint64_t sz, uint64_t N)
+{
+	int l = 0;
+	if (sz == 0)
+		return 0;
+	for (; sz; sz /= N)
+		l++;
+	return l - 1;
+}
+
+static void t_reftable_stack_auto_compaction(void)
+{
+	struct reftable_write_options opts = {
+		.disable_auto_compact = 1,
+	};
+	struct reftable_stack *st = NULL;
+	char *dir = get_tmp_dir(__LINE__);
+	int err;
+	size_t i, N = 100;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	for (i = 0; i < N; i++) {
+		char name[100];
+		struct reftable_ref_record ref = {
+			.refname = name,
+			.update_index = reftable_stack_next_update_index(st),
+			.value_type = REFTABLE_REF_SYMREF,
+			.value.symref = (char *) "master",
+		};
+		snprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i);
+
+		err = reftable_stack_add(st, write_test_ref, &ref);
+		check(!err);
+
+		err = reftable_stack_auto_compact(st);
+		check(!err);
+		check(i < 2 || st->merged->readers_len < 2 * fastlogN(i, 2));
+	}
+
+	check_int(reftable_stack_compaction_stats(st)->entries_written, <,
+	       (uint64_t)(N * fastlogN(N, 2)));
+
+	reftable_stack_destroy(st);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_auto_compaction_factor(void)
+{
+	struct reftable_write_options opts = {
+		.auto_compaction_factor = 5,
+	};
+	struct reftable_stack *st = NULL;
+	char *dir = get_tmp_dir(__LINE__);
+	int err;
+	size_t N = 100;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	for (size_t i = 0; i < N; i++) {
+		char name[20];
+		struct reftable_ref_record ref = {
+			.refname = name,
+			.update_index = reftable_stack_next_update_index(st),
+			.value_type = REFTABLE_REF_VAL1,
+		};
+		xsnprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i);
+
+		err = reftable_stack_add(st, &write_test_ref, &ref);
+		check(!err);
+
+		check(i < 5 || st->merged->readers_len < 5 * fastlogN(i, 5));
+	}
+
+	reftable_stack_destroy(st);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_auto_compaction_with_locked_tables(void)
+{
+	struct reftable_write_options opts = {
+		.disable_auto_compact = 1,
+	};
+	struct reftable_stack *st = NULL;
+	struct strbuf buf = STRBUF_INIT;
+	char *dir = get_tmp_dir(__LINE__);
+	int err;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	write_n_ref_tables(st, 5);
+	check_int(st->merged->readers_len, ==, 5);
+
+	/*
+	 * Given that all tables we have written should be roughly the same
+	 * size, we expect that auto-compaction will want to compact all of the
+	 * tables. Locking any of the tables will keep it from doing so.
+	 */
+	strbuf_reset(&buf);
+	strbuf_addf(&buf, "%s/%s.lock", dir, st->readers[2]->name);
+	write_file_buf(buf.buf, "", 0);
+
+	/*
+	 * When parts of the stack are locked, then auto-compaction does a best
+	 * effort compaction of those tables which aren't locked. So while this
+	 * would in theory compact all tables, due to the preexisting lock we
+	 * only compact the newest two tables.
+	 */
+	err = reftable_stack_auto_compact(st);
+	check(!err);
+	check_int(st->stats.failures, ==, 0);
+	check_int(st->merged->readers_len, ==, 4);
+
+	reftable_stack_destroy(st);
+	strbuf_release(&buf);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_add_performs_auto_compaction(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st = NULL;
+	struct strbuf refname = STRBUF_INIT;
+	char *dir = get_tmp_dir(__LINE__);
+	int err;
+	size_t i, n = 20;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	for (i = 0; i <= n; i++) {
+		struct reftable_ref_record ref = {
+			.update_index = reftable_stack_next_update_index(st),
+			.value_type = REFTABLE_REF_SYMREF,
+			.value.symref = (char *) "master",
+		};
+
+		/*
+		 * Disable auto-compaction for all but the last runs. Like this
+		 * we can ensure that we indeed honor this setting and have
+		 * better control over when exactly auto compaction runs.
+		 */
+		st->opts.disable_auto_compact = i != n;
+
+		strbuf_reset(&refname);
+		strbuf_addf(&refname, "branch-%04"PRIuMAX, (uintmax_t)i);
+		ref.refname = refname.buf;
+
+		err = reftable_stack_add(st, write_test_ref, &ref);
+		check(!err);
+
+		/*
+		 * The stack length should grow continuously for all runs where
+		 * auto compaction is disabled. When enabled, we should merge
+		 * all tables in the stack.
+		 */
+		if (i != n)
+			check_int(st->merged->readers_len, ==, i + 1);
+		else
+			check_int(st->merged->readers_len, ==, 1);
+	}
+
+	reftable_stack_destroy(st);
+	strbuf_release(&refname);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_compaction_with_locked_tables(void)
+{
+	struct reftable_write_options opts = {
+		.disable_auto_compact = 1,
+	};
+	struct reftable_stack *st = NULL;
+	struct strbuf buf = STRBUF_INIT;
+	char *dir = get_tmp_dir(__LINE__);
+	int err;
+
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+
+	write_n_ref_tables(st, 3);
+	check_int(st->merged->readers_len, ==, 3);
+
+	/* Lock one of the tables that we're about to compact. */
+	strbuf_reset(&buf);
+	strbuf_addf(&buf, "%s/%s.lock", dir, st->readers[1]->name);
+	write_file_buf(buf.buf, "", 0);
+
+	/*
+	 * Compaction is expected to fail given that we were not able to
+	 * compact all tables.
+	 */
+	err = reftable_stack_compact_all(st, NULL);
+	check_int(err, ==, REFTABLE_LOCK_ERROR);
+	check_int(st->stats.failures, ==, 1);
+	check_int(st->merged->readers_len, ==, 3);
+
+	reftable_stack_destroy(st);
+	strbuf_release(&buf);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_compaction_concurrent(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st1 = NULL, *st2 = NULL;
+	char *dir = get_tmp_dir(__LINE__);
+	int err;
+
+	err = reftable_new_stack(&st1, dir, &opts);
+	check(!err);
+	write_n_ref_tables(st1, 3);
+
+	err = reftable_new_stack(&st2, dir, &opts);
+	check(!err);
+
+	err = reftable_stack_compact_all(st1, NULL);
+	check(!err);
+
+	reftable_stack_destroy(st1);
+	reftable_stack_destroy(st2);
+
+	check_int(count_dir_entries(dir), ==, 2);
+	clear_dir(dir);
+}
+
+static void unclean_stack_close(struct reftable_stack *st)
+{
+	/* break abstraction boundary to simulate unclean shutdown. */
+	for (size_t i = 0; i < st->readers_len; i++)
+		reftable_reader_decref(st->readers[i]);
+	st->readers_len = 0;
+	FREE_AND_NULL(st->readers);
+}
+
+static void t_reftable_stack_compaction_concurrent_clean(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st1 = NULL, *st2 = NULL, *st3 = NULL;
+	char *dir = get_tmp_dir(__LINE__);
+	int err;
+
+	err = reftable_new_stack(&st1, dir, &opts);
+	check(!err);
+	write_n_ref_tables(st1, 3);
+
+	err = reftable_new_stack(&st2, dir, &opts);
+	check(!err);
+
+	err = reftable_stack_compact_all(st1, NULL);
+	check(!err);
+
+	unclean_stack_close(st1);
+	unclean_stack_close(st2);
+
+	err = reftable_new_stack(&st3, dir, &opts);
+	check(!err);
+
+	err = reftable_stack_clean(st3);
+	check(!err);
+	check_int(count_dir_entries(dir), ==, 2);
+
+	reftable_stack_destroy(st1);
+	reftable_stack_destroy(st2);
+	reftable_stack_destroy(st3);
+
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_read_across_reload(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st1 = NULL, *st2 = NULL;
+	struct reftable_ref_record rec = { 0 };
+	struct reftable_iterator it = { 0 };
+	char *dir = get_tmp_dir(__LINE__);
+	int err;
+
+	/* Create a first stack and set up an iterator for it. */
+	err = reftable_new_stack(&st1, dir, &opts);
+	check(!err);
+	write_n_ref_tables(st1, 2);
+	check_int(st1->merged->readers_len, ==, 2);
+	reftable_stack_init_ref_iterator(st1, &it);
+	err = reftable_iterator_seek_ref(&it, "");
+	check(!err);
+
+	/* Set up a second stack for the same directory and compact it. */
+	err = reftable_new_stack(&st2, dir, &opts);
+	check(!err);
+	check_int(st2->merged->readers_len, ==, 2);
+	err = reftable_stack_compact_all(st2, NULL);
+	check(!err);
+	check_int(st2->merged->readers_len, ==, 1);
+
+	/*
+	 * Verify that we can continue to use the old iterator even after we
+	 * have reloaded its stack.
+	 */
+	err = reftable_stack_reload(st1);
+	check(!err);
+	check_int(st1->merged->readers_len, ==, 1);
+	err = reftable_iterator_next_ref(&it, &rec);
+	check(!err);
+	check_str(rec.refname, "refs/heads/branch-0000");
+	err = reftable_iterator_next_ref(&it, &rec);
+	check(!err);
+	check_str(rec.refname, "refs/heads/branch-0001");
+	err = reftable_iterator_next_ref(&it, &rec);
+	check_int(err, >, 0);
+
+	reftable_ref_record_release(&rec);
+	reftable_iterator_destroy(&it);
+	reftable_stack_destroy(st1);
+	reftable_stack_destroy(st2);
+	clear_dir(dir);
+}
+
+static void t_reftable_stack_reload_with_missing_table(void)
+{
+	struct reftable_write_options opts = { 0 };
+	struct reftable_stack *st = NULL;
+	struct reftable_ref_record rec = { 0 };
+	struct reftable_iterator it = { 0 };
+	struct strbuf table_path = STRBUF_INIT, content = STRBUF_INIT;
+	char *dir = get_tmp_dir(__LINE__);
+	int err;
+
+	/* Create a first stack and set up an iterator for it. */
+	err = reftable_new_stack(&st, dir, &opts);
+	check(!err);
+	write_n_ref_tables(st, 2);
+	check_int(st->merged->readers_len, ==, 2);
+	reftable_stack_init_ref_iterator(st, &it);
+	err = reftable_iterator_seek_ref(&it, "");
+	check(!err);
+
+	/*
+	 * Update the tables.list file with some garbage data, while reusing
+	 * our old readers. This should trigger a partial reload of the stack,
+	 * where we try to reuse our old readers.
+	*/
+	strbuf_addf(&content, "%s\n", st->readers[0]->name);
+	strbuf_addf(&content, "%s\n", st->readers[1]->name);
+	strbuf_addstr(&content, "garbage\n");
+	strbuf_addf(&table_path, "%s.lock", st->list_file);
+	write_file_buf(table_path.buf, content.buf, content.len);
+	err = rename(table_path.buf, st->list_file);
+	check(!err);
+
+	err = reftable_stack_reload(st);
+	check_int(err, ==, -4);
+	check_int(st->merged->readers_len, ==, 2);
+
+	/*
+	 * Even though the reload has failed, we should be able to continue
+	 * using the iterator.
+	*/
+	err = reftable_iterator_next_ref(&it, &rec);
+	check(!err);
+	check_str(rec.refname, "refs/heads/branch-0000");
+	err = reftable_iterator_next_ref(&it, &rec);
+	check(!err);
+	check_str(rec.refname, "refs/heads/branch-0001");
+	err = reftable_iterator_next_ref(&it, &rec);
+	check_int(err, >, 0);
+
+	reftable_ref_record_release(&rec);
+	reftable_iterator_destroy(&it);
+	reftable_stack_destroy(st);
+	strbuf_release(&table_path);
+	strbuf_release(&content);
+	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_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");
+	TEST(t_reftable_stack_auto_compaction(), "stack must form geometric sequence after compaction");
+	TEST(t_reftable_stack_auto_compaction_factor(), "auto-compaction with non-default geometric factor");
+	TEST(t_reftable_stack_auto_compaction_fails_gracefully(), "failure on auto-compaction");
+	TEST(t_reftable_stack_auto_compaction_with_locked_tables(), "auto compaction with locked tables");
+	TEST(t_reftable_stack_compaction_concurrent(), "compaction with concurrent stack");
+	TEST(t_reftable_stack_compaction_concurrent_clean(), "compaction with unclean stack shutdown");
+	TEST(t_reftable_stack_compaction_with_locked_tables(), "compaction with locked tables");
+	TEST(t_reftable_stack_hash_id(), "read stack with wrong hash ID");
+	TEST(t_reftable_stack_iterator(), "log and ref iterator for reftable stack");
+	TEST(t_reftable_stack_lock_failure(), "stack addition with lockfile failure");
+	TEST(t_reftable_stack_log_normalize(), "log messages should be normalized");
+	TEST(t_reftable_stack_read_across_reload(), "stack iterators work across reloads");
+	TEST(t_reftable_stack_reload_with_missing_table(), "stack iteration with garbage tables");
+	TEST(t_reftable_stack_tombstone(), "'tombstone' refs in stack");
+	TEST(t_reftable_stack_transaction_api(), "update transaction to stack");
+	TEST(t_reftable_stack_transaction_with_reload(), "transaction with reload");
+	TEST(t_reftable_stack_transaction_api_performs_auto_compaction(), "update transaction triggers auto-compaction");
+	TEST(t_reftable_stack_update_index_check(), "update transactions with equal update indices");
+	TEST(t_reftable_stack_uptodate(), "stack must be reloaded before ref update");
+	TEST(t_suggest_compaction_segment(), "suggest_compaction_segment with basic input");
+	TEST(t_suggest_compaction_segment_nothing(), "suggest_compaction_segment with pre-compacted input");
+
+	return test_done();
+}
diff --git a/t/unit-tests/t-reftable-tree.c b/t/unit-tests/t-reftable-tree.c
new file mode 100644
index 0000000..700479d
--- /dev/null
+++ b/t/unit-tests/t-reftable-tree.c
@@ -0,0 +1,84 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "test-lib.h"
+#include "reftable/tree.h"
+
+static int t_compare(const void *a, const void *b)
+{
+	return (char *)a - (char *)b;
+}
+
+struct curry {
+	void **arr;
+	size_t len;
+};
+
+static void store(void *arg, void *key)
+{
+	struct curry *c = arg;
+	c->arr[c->len++] = key;
+}
+
+static void t_tree_search(void)
+{
+	struct tree_node *root = NULL;
+	void *values[11] = { 0 };
+	struct tree_node *nodes[11] = { 0 };
+	size_t i = 1;
+
+	/*
+	 * Pseudo-randomly insert the pointers for elements between
+	 * values[1] and values[10] (inclusive) in the tree.
+	 */
+	do {
+		nodes[i] = tree_search(&values[i], &root, &t_compare, 1);
+		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(&values[i], &root, &t_compare, 0));
+	}
+
+	check(!tree_search(values, &root, t_compare, 0));
+	tree_free(root);
+}
+
+static void t_infix_walk(void)
+{
+	struct tree_node *root = NULL;
+	void *values[11] = { 0 };
+	void *out[11] = { 0 };
+	struct curry c = {
+		.arr = (void **) &out,
+	};
+	size_t i = 1;
+	size_t count = 0;
+
+	do {
+		tree_search(&values[i], &root, t_compare, 1);
+		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);
+	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/t-strbuf.c b/t/unit-tests/t-strbuf.c
index 6027daf..3f4044d 100644
--- a/t/unit-tests/t-strbuf.c
+++ b/t/unit-tests/t-strbuf.c
@@ -105,7 +105,7 @@ static void t_addstr(struct strbuf *buf, const void *data)
 	check_str(buf->buf + orig_len, text);
 }
 
-int cmd_main(int argc, const char **argv)
+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");
diff --git a/t/unit-tests/t-strcmp-offset.c b/t/unit-tests/t-strcmp-offset.c
index fe4c270..6880f21 100644
--- a/t/unit-tests/t-strcmp-offset.c
+++ b/t/unit-tests/t-strcmp-offset.c
@@ -24,7 +24,7 @@ static void check_strcmp_offset(const char *string1, const char *string2,
 				 expect_offset),                           \
 	     "strcmp_offset(%s, %s) works", #string1, #string2)
 
-int cmd_main(int argc, const char **argv)
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
 {
 	TEST_STRCMP_OFFSET("abc", "abc", 0, 3);
 	TEST_STRCMP_OFFSET("abc", "def", -1, 0);
diff --git a/t/unit-tests/t-strvec.c b/t/unit-tests/t-strvec.c
deleted file mode 100644
index d4615ab..0000000
--- a/t/unit-tests/t-strvec.c
+++ /dev/null
@@ -1,272 +0,0 @@
-#include "test-lib.h"
-#include "strbuf.h"
-#include "strvec.h"
-
-#define check_strvec(vec, ...) \
-	check_strvec_loc(TEST_LOCATION(), vec, __VA_ARGS__)
-LAST_ARG_MUST_BE_NULL
-static void check_strvec_loc(const char *loc, struct strvec *vec, ...)
-{
-	va_list ap;
-	size_t nr = 0;
-
-	va_start(ap, vec);
-	while (1) {
-		const char *str = va_arg(ap, const char *);
-		if (!str)
-			break;
-
-		if (!check_uint(vec->nr, >, nr) ||
-		    !check_uint(vec->alloc, >, nr) ||
-		    !check_str(vec->v[nr], str)) {
-			struct strbuf msg = STRBUF_INIT;
-			strbuf_addf(&msg, "strvec index %"PRIuMAX, (uintmax_t) nr);
-			test_assert(loc, msg.buf, 0);
-			strbuf_release(&msg);
-			va_end(ap);
-			return;
-		}
-
-		nr++;
-	}
-	va_end(ap);
-
-	check_uint(vec->nr, ==, nr);
-	check_uint(vec->alloc, >=, nr);
-	check_pointer_eq(vec->v[nr], NULL);
-}
-
-static void t_static_init(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	check_pointer_eq(vec.v, empty_strvec);
-	check_uint(vec.nr, ==, 0);
-	check_uint(vec.alloc, ==, 0);
-}
-
-static void t_dynamic_init(void)
-{
-	struct strvec vec;
-	strvec_init(&vec);
-	check_pointer_eq(vec.v, empty_strvec);
-	check_uint(vec.nr, ==, 0);
-	check_uint(vec.alloc, ==, 0);
-}
-
-static void t_clear(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_push(&vec, "foo");
-	strvec_clear(&vec);
-	check_pointer_eq(vec.v, empty_strvec);
-	check_uint(vec.nr, ==, 0);
-	check_uint(vec.alloc, ==, 0);
-}
-
-static void t_push(void)
-{
-	struct strvec vec = STRVEC_INIT;
-
-	strvec_push(&vec, "foo");
-	check_strvec(&vec, "foo", NULL);
-
-	strvec_push(&vec, "bar");
-	check_strvec(&vec, "foo", "bar", NULL);
-
-	strvec_clear(&vec);
-}
-
-static void t_pushf(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pushf(&vec, "foo: %d", 1);
-	check_strvec(&vec, "foo: 1", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_pushl(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
-	check_strvec(&vec, "foo", "bar", "baz", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_pushv(void)
-{
-	const char *strings[] = {
-		"foo", "bar", "baz", NULL,
-	};
-	struct strvec vec = STRVEC_INIT;
-
-	strvec_pushv(&vec, strings);
-	check_strvec(&vec, "foo", "bar", "baz", NULL);
-
-	strvec_clear(&vec);
-}
-
-static void t_replace_at_head(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
-	strvec_replace(&vec, 0, "replaced");
-	check_strvec(&vec, "replaced", "bar", "baz", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_replace_at_tail(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
-	strvec_replace(&vec, 2, "replaced");
-	check_strvec(&vec, "foo", "bar", "replaced", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_replace_in_between(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
-	strvec_replace(&vec, 1, "replaced");
-	check_strvec(&vec, "foo", "replaced", "baz", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_replace_with_substring(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pushl(&vec, "foo", NULL);
-	strvec_replace(&vec, 0, vec.v[0] + 1);
-	check_strvec(&vec, "oo", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_remove_at_head(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
-	strvec_remove(&vec, 0);
-	check_strvec(&vec, "bar", "baz", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_remove_at_tail(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
-	strvec_remove(&vec, 2);
-	check_strvec(&vec, "foo", "bar", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_remove_in_between(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
-	strvec_remove(&vec, 1);
-	check_strvec(&vec, "foo", "baz", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_pop_empty_array(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pop(&vec);
-	check_strvec(&vec, NULL);
-	strvec_clear(&vec);
-}
-
-static void t_pop_non_empty_array(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
-	strvec_pop(&vec);
-	check_strvec(&vec, "foo", "bar", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_split_empty_string(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_split(&vec, "");
-	check_strvec(&vec, NULL);
-	strvec_clear(&vec);
-}
-
-static void t_split_single_item(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_split(&vec, "foo");
-	check_strvec(&vec, "foo", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_split_multiple_items(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_split(&vec, "foo bar baz");
-	check_strvec(&vec, "foo", "bar", "baz", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_split_whitespace_only(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_split(&vec, " \t\n");
-	check_strvec(&vec, NULL);
-	strvec_clear(&vec);
-}
-
-static void t_split_multiple_consecutive_whitespaces(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	strvec_split(&vec, "foo\n\t bar");
-	check_strvec(&vec, "foo", "bar", NULL);
-	strvec_clear(&vec);
-}
-
-static void t_detach(void)
-{
-	struct strvec vec = STRVEC_INIT;
-	const char **detached;
-
-	strvec_push(&vec, "foo");
-
-	detached = strvec_detach(&vec);
-	check_str(detached[0], "foo");
-	check_pointer_eq(detached[1], NULL);
-
-	check_pointer_eq(vec.v, empty_strvec);
-	check_uint(vec.nr, ==, 0);
-	check_uint(vec.alloc, ==, 0);
-
-	free((char *) detached[0]);
-	free(detached);
-}
-
-int cmd_main(int argc, const char **argv)
-{
-	TEST(t_static_init(), "static initialization");
-	TEST(t_dynamic_init(), "dynamic initialization");
-	TEST(t_clear(), "clear");
-	TEST(t_push(), "push");
-	TEST(t_pushf(), "pushf");
-	TEST(t_pushl(), "pushl");
-	TEST(t_pushv(), "pushv");
-	TEST(t_replace_at_head(), "replace at head");
-	TEST(t_replace_in_between(), "replace in between");
-	TEST(t_replace_at_tail(), "replace at tail");
-	TEST(t_replace_with_substring(), "replace with substring");
-	TEST(t_remove_at_head(), "remove at head");
-	TEST(t_remove_in_between(), "remove in between");
-	TEST(t_remove_at_tail(), "remove at tail");
-	TEST(t_pop_empty_array(), "pop with empty array");
-	TEST(t_pop_non_empty_array(), "pop with non-empty array");
-	TEST(t_split_empty_string(), "split empty string");
-	TEST(t_split_single_item(), "split single item");
-	TEST(t_split_multiple_items(), "split multiple items");
-	TEST(t_split_whitespace_only(), "split whitespace only");
-	TEST(t_split_multiple_consecutive_whitespaces(), "split multiple consecutive whitespaces");
-	TEST(t_detach(), "detach");
-	return test_done();
-}
diff --git a/t/unit-tests/t-trailer.c b/t/unit-tests/t-trailer.c
index 2ecca35..e1c6ad7 100644
--- a/t/unit-tests/t-trailer.c
+++ b/t/unit-tests/t-trailer.c
@@ -308,7 +308,7 @@ static void run_t_trailer_iterator(void)
 	}
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
 {
 	run_t_trailer_iterator();
 	return test_done();
diff --git a/t/unit-tests/t-urlmatch-normalization.c b/t/unit-tests/t-urlmatch-normalization.c
new file mode 100644
index 0000000..1769c35
--- /dev/null
+++ b/t/unit-tests/t-urlmatch-normalization.c
@@ -0,0 +1,271 @@
+#include "test-lib.h"
+#include "urlmatch.h"
+
+static void check_url_normalizable(const char *url, unsigned int normalizable)
+{
+	char *url_norm = url_normalize(url, NULL);
+
+	if (!check_int(normalizable, ==, url_norm ? 1 : 0))
+		test_msg("input url: %s", url);
+	free(url_norm);
+}
+
+static void check_normalized_url(const char *url, const char *expect)
+{
+	char *url_norm = url_normalize(url, NULL);
+
+	if (!check_str(url_norm, expect))
+		test_msg("input url: %s", url);
+	free(url_norm);
+}
+
+static void compare_normalized_urls(const char *url1, const char *url2,
+				    unsigned int equal)
+{
+	char *url1_norm = url_normalize(url1, NULL);
+	char *url2_norm = url_normalize(url2, NULL);
+
+	if (equal) {
+		if (!check_str(url1_norm, url2_norm))
+			test_msg("input url1: %s\n  input url2: %s", url1,
+				 url2);
+	} else if (!check_int(strcmp(url1_norm, url2_norm), !=, 0)) {
+		test_msg(" normalized url1: %s\n   normalized url2: %s\n"
+			 "  input url1: %s\n  input url2: %s",
+			 url1_norm, url2_norm, url1, url2);
+	}
+	free(url1_norm);
+	free(url2_norm);
+}
+
+static void check_normalized_url_length(const char *url, size_t len)
+{
+	struct url_info info;
+	char *url_norm = url_normalize(url, &info);
+
+	if (!check_int(info.url_len, ==, len))
+		test_msg("     input url: %s\n  normalized url: %s", url,
+			 url_norm);
+	free(url_norm);
+}
+
+/* Note that only "file:" URLs should be allowed without a host */
+static void t_url_scheme(void)
+{
+	check_url_normalizable("", 0);
+	check_url_normalizable("_", 0);
+	check_url_normalizable("scheme", 0);
+	check_url_normalizable("scheme:", 0);
+	check_url_normalizable("scheme:/", 0);
+	check_url_normalizable("scheme://", 0);
+	check_url_normalizable("file", 0);
+	check_url_normalizable("file:", 0);
+	check_url_normalizable("file:/", 0);
+	check_url_normalizable("file://", 1);
+	check_url_normalizable("://acme.co", 0);
+	check_url_normalizable("x_test://acme.co", 0);
+	check_url_normalizable("-test://acme.co", 0);
+	check_url_normalizable("0test://acme.co", 0);
+	check_url_normalizable("+test://acme.co", 0);
+	check_url_normalizable(".test://acme.co", 0);
+	check_url_normalizable("schem%6e://", 0);
+	check_url_normalizable("x-Test+v1.0://acme.co", 1);
+	check_normalized_url("AbCdeF://x.Y", "abcdef://x.y/");
+}
+
+static void t_url_authority(void)
+{
+	check_url_normalizable("scheme://user:pass@", 0);
+	check_url_normalizable("scheme://?", 0);
+	check_url_normalizable("scheme://#", 0);
+	check_url_normalizable("scheme:///", 0);
+	check_url_normalizable("scheme://:", 0);
+	check_url_normalizable("scheme://:555", 0);
+	check_url_normalizable("file://user:pass@", 1);
+	check_url_normalizable("file://?", 1);
+	check_url_normalizable("file://#", 1);
+	check_url_normalizable("file:///", 1);
+	check_url_normalizable("file://:", 1);
+	check_url_normalizable("file://:555", 0);
+	check_url_normalizable("scheme://user:pass@host", 1);
+	check_url_normalizable("scheme://@host", 1);
+	check_url_normalizable("scheme://%00@host", 1);
+	check_url_normalizable("scheme://%%@host", 0);
+	check_url_normalizable("scheme://host_", 1);
+	check_url_normalizable("scheme://user:pass@host/", 1);
+	check_url_normalizable("scheme://@host/", 1);
+	check_url_normalizable("scheme://host/", 1);
+	check_url_normalizable("scheme://host?x", 1);
+	check_url_normalizable("scheme://host#x", 1);
+	check_url_normalizable("scheme://host/@", 1);
+	check_url_normalizable("scheme://host?@x", 1);
+	check_url_normalizable("scheme://host#@x", 1);
+	check_url_normalizable("scheme://[::1]", 1);
+	check_url_normalizable("scheme://[::1]/", 1);
+	check_url_normalizable("scheme://hos%41/", 0);
+	check_url_normalizable("scheme://[invalid....:/", 1);
+	check_url_normalizable("scheme://invalid....:]/", 1);
+	check_url_normalizable("scheme://invalid....:[/", 0);
+	check_url_normalizable("scheme://invalid....:[", 0);
+}
+
+static void t_url_port(void)
+{
+	check_url_normalizable("xyz://q@some.host:", 1);
+	check_url_normalizable("xyz://q@some.host:456/", 1);
+	check_url_normalizable("xyz://q@some.host:0", 0);
+	check_url_normalizable("xyz://q@some.host:0000000", 0);
+	check_url_normalizable("xyz://q@some.host:0000001?", 1);
+	check_url_normalizable("xyz://q@some.host:065535#", 1);
+	check_url_normalizable("xyz://q@some.host:65535", 1);
+	check_url_normalizable("xyz://q@some.host:65536", 0);
+	check_url_normalizable("xyz://q@some.host:99999", 0);
+	check_url_normalizable("xyz://q@some.host:100000", 0);
+	check_url_normalizable("xyz://q@some.host:100001", 0);
+	check_url_normalizable("http://q@some.host:80", 1);
+	check_url_normalizable("https://q@some.host:443", 1);
+	check_url_normalizable("http://q@some.host:80/", 1);
+	check_url_normalizable("https://q@some.host:443?", 1);
+	check_url_normalizable("http://q@:8008", 0);
+	check_url_normalizable("http://:8080", 0);
+	check_url_normalizable("http://:", 0);
+	check_url_normalizable("xyz://q@some.host:456/", 1);
+	check_url_normalizable("xyz://[::1]:456/", 1);
+	check_url_normalizable("xyz://[::1]:/", 1);
+	check_url_normalizable("xyz://[::1]:000/", 0);
+	check_url_normalizable("xyz://[::1]:0%300/", 0);
+	check_url_normalizable("xyz://[::1]:0x80/", 0);
+	check_url_normalizable("xyz://[::1]:4294967297/", 0);
+	check_url_normalizable("xyz://[::1]:030f/", 0);
+}
+
+static void t_url_port_normalization(void)
+{
+	check_normalized_url("http://x:800", "http://x:800/");
+	check_normalized_url("http://x:0800", "http://x:800/");
+	check_normalized_url("http://x:00000800", "http://x:800/");
+	check_normalized_url("http://x:065535", "http://x:65535/");
+	check_normalized_url("http://x:1", "http://x:1/");
+	check_normalized_url("http://x:80", "http://x/");
+	check_normalized_url("http://x:080", "http://x/");
+	check_normalized_url("http://x:000000080", "http://x/");
+	check_normalized_url("https://x:443", "https://x/");
+	check_normalized_url("https://x:0443", "https://x/");
+	check_normalized_url("https://x:000000443", "https://x/");
+}
+
+static void t_url_general_escape(void)
+{
+	check_url_normalizable("http://x.y?%fg", 0);
+	check_normalized_url("X://W/%7e%41^%3a", "x://w/~A%5E%3A");
+	check_normalized_url("X://W/:/?#[]@", "x://w/:/?#[]@");
+	check_normalized_url("X://W/$&()*+,;=", "x://w/$&()*+,;=");
+	check_normalized_url("X://W/'", "x://w/'");
+	check_normalized_url("X://W?!", "x://w/?!");
+}
+
+static void t_url_high_bit(void)
+{
+	check_normalized_url(
+		"x://q/\x01\x02\x03\x04\x05\x06\x07\x08\x0e\x0f\x10\x11\x12",
+		"x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12");
+	check_normalized_url(
+		"x://q/\x13\x14\x15\x16\x17\x18\x19\x1b\x1c\x1d\x1e\x1f\x7f",
+		"x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F");
+	check_normalized_url(
+		"x://q/\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f",
+		"x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F");
+	check_normalized_url(
+		"x://q/\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
+		"x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F");
+	check_normalized_url(
+		"x://q/\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
+		"x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF");
+	check_normalized_url(
+		"x://q/\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf",
+		"x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF");
+	check_normalized_url(
+		"x://q/\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
+		"x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF");
+	check_normalized_url(
+		"x://q/\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf",
+		"x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF");
+	check_normalized_url(
+		"x://q/\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
+		"x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF");
+	check_normalized_url(
+		"x://q/\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+		"x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF");
+}
+
+static void t_url_utf8_escape(void)
+{
+	check_normalized_url(
+		"x://q/\xc2\x80\xdf\xbf\xe0\xa0\x80\xef\xbf\xbd\xf0\x90\x80\x80\xf0\xaf\xbf\xbd",
+		"x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD");
+}
+
+static void t_url_username_pass(void)
+{
+	check_normalized_url("x://%41%62(^):%70+d@foo", "x://Ab(%5E):p+d@foo/");
+}
+
+static void t_url_length(void)
+{
+	check_normalized_url_length("Http://%4d%65:%4d^%70@The.Host", 25);
+	check_normalized_url_length("http://%41:%42@x.y/%61/", 17);
+	check_normalized_url_length("http://@x.y/^", 15);
+}
+
+static void t_url_dots(void)
+{
+	check_normalized_url("x://y/.", "x://y/");
+	check_normalized_url("x://y/./", "x://y/");
+	check_normalized_url("x://y/a/.", "x://y/a");
+	check_normalized_url("x://y/a/./", "x://y/a/");
+	check_normalized_url("x://y/.?", "x://y/?");
+	check_normalized_url("x://y/./?", "x://y/?");
+	check_normalized_url("x://y/a/.?", "x://y/a?");
+	check_normalized_url("x://y/a/./?", "x://y/a/?");
+	check_normalized_url("x://y/a/./b/.././../c", "x://y/c");
+	check_normalized_url("x://y/a/./b/../.././c/", "x://y/c/");
+	check_normalized_url("x://y/a/./b/.././../c/././.././.", "x://y/");
+	check_url_normalizable("x://y/a/./b/.././../c/././.././..", 0);
+	check_normalized_url("x://y/a/./?/././..", "x://y/a/?/././..");
+	check_normalized_url("x://y/%2e/", "x://y/");
+	check_normalized_url("x://y/%2E/", "x://y/");
+	check_normalized_url("x://y/a/%2e./", "x://y/");
+	check_normalized_url("x://y/b/.%2E/", "x://y/");
+	check_normalized_url("x://y/c/%2e%2E/", "x://y/");
+}
+
+/*
+ * "http://@foo" specifies an empty user name but does not specify a password.
+ * "http://foo" specifies neither a user name nor a password.
+ * So they should not be equivalent.
+ */
+static void t_url_equivalents(void)
+{
+	compare_normalized_urls("httP://x", "Http://X/", 1);
+	compare_normalized_urls("Http://%4d%65:%4d^%70@The.Host", "hTTP://Me:%4D^p@the.HOST:80/", 1);
+	compare_normalized_urls("https://@x.y/^", "httpS://x.y:443/^", 0);
+	compare_normalized_urls("https://@x.y/^", "httpS://@x.y:0443/^", 1);
+	compare_normalized_urls("https://@x.y/^/../abc", "httpS://@x.y:0443/abc", 1);
+	compare_normalized_urls("https://@x.y/^/..", "httpS://@x.y:0443/", 1);
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+	TEST(t_url_scheme(), "url scheme");
+	TEST(t_url_authority(), "url authority");
+	TEST(t_url_port(), "url port checks");
+	TEST(t_url_port_normalization(), "url port normalization");
+	TEST(t_url_general_escape(), "url general escapes");
+	TEST(t_url_high_bit(), "url high-bit escapes");
+	TEST(t_url_utf8_escape(), "url utf8 escapes");
+	TEST(t_url_username_pass(), "url username/password escapes");
+	TEST(t_url_length(), "url normalized lengths");
+	TEST(t_url_dots(), "url . and .. segments");
+	TEST(t_url_equivalents(), "url equivalents");
+	return test_done();
+}
diff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c
index 3c513ce..fa1f959 100644
--- a/t/unit-tests/test-lib.c
+++ b/t/unit-tests/test-lib.c
@@ -16,6 +16,8 @@ static struct {
 	unsigned running :1;
 	unsigned skip_all :1;
 	unsigned todo :1;
+	char location[100];
+	char description[100];
 } ctx = {
 	.lazy_plan = 1,
 	.result = RESULT_NONE,
@@ -125,6 +127,8 @@ void test_plan(int count)
 
 int test_done(void)
 {
+	if (ctx.running && ctx.location[0] && ctx.description[0])
+		test__run_end(1, ctx.location, "%s", ctx.description);
 	assert(!ctx.running);
 
 	if (ctx.lazy_plan)
@@ -167,13 +171,38 @@ void test_skip_all(const char *format, ...)
 	va_end(ap);
 }
 
+void test__run_describe(const char *location, const char *format, ...)
+{
+	va_list ap;
+	int len;
+
+	assert(ctx.running);
+	assert(!ctx.location[0]);
+	assert(!ctx.description[0]);
+
+	xsnprintf(ctx.location, sizeof(ctx.location), "%s",
+		  make_relative(location));
+
+	va_start(ap, format);
+	len = vsnprintf(ctx.description, sizeof(ctx.description), format, ap);
+	va_end(ap);
+	if (len < 0)
+		die("unable to format message: %s", format);
+	if (len >= sizeof(ctx.description))
+		BUG("ctx.description too small to format %s", format);
+}
+
 int test__run_begin(void)
 {
+	if (ctx.running && ctx.location[0] && ctx.description[0])
+		test__run_end(1, ctx.location, "%s", ctx.description);
 	assert(!ctx.running);
 
 	ctx.count++;
 	ctx.result = RESULT_NONE;
 	ctx.running = 1;
+	ctx.location[0] = '\0';
+	ctx.description[0] = '\0';
 
 	return ctx.skip_all;
 }
@@ -264,7 +293,12 @@ static void test_todo(void)
 
 int test_assert(const char *location, const char *check, int ok)
 {
-	assert(ctx.running);
+	if (!ctx.running) {
+		test_msg("BUG: check outside of test at %s",
+			 make_relative(location));
+		ctx.failed = 1;
+		return 0;
+	}
 
 	if (ctx.result == RESULT_SKIP) {
 		test_msg("skipping check '%s' at %s", check,
diff --git a/t/unit-tests/test-lib.h b/t/unit-tests/test-lib.h
index c59f646..e4b2346 100644
--- a/t/unit-tests/test-lib.h
+++ b/t/unit-tests/test-lib.h
@@ -15,6 +15,23 @@
 		      TEST_LOCATION(),  __VA_ARGS__)
 
 /*
+ * Run a test unless test_skip_all() has been called.  Acts like a
+ * conditional; the test body is expected as a statement or block after
+ * the closing parenthesis.  The description for each test should be
+ * unique.  E.g.:
+ *
+ *  if_test ("something else %d %d", arg1, arg2) {
+ *          prepare();
+ *          test_something_else(arg1, arg2);
+ *          cleanup();
+ *  }
+ */
+#define if_test(...)							\
+	if (test__run_begin() ?						\
+	    (test__run_end(0, TEST_LOCATION(),  __VA_ARGS__), 0) :	\
+	    (test__run_describe(TEST_LOCATION(),  __VA_ARGS__), 1))
+
+/*
  * Print a test plan, should be called before any tests. If the number
  * of tests is not known in advance test_done() will automatically
  * print a plan at the end of the test program.
@@ -154,6 +171,9 @@ union test__tmp {
 
 extern union test__tmp test__tmp[2];
 
+__attribute__((format (printf, 2, 3)))
+void test__run_describe(const char *, const char *, ...);
+
 int test__run_begin(void);
 __attribute__((format (printf, 3, 4)))
 int test__run_end(int, const char *, const char *, ...);
diff --git a/t/unit-tests/unit-test.c b/t/unit-tests/unit-test.c
new file mode 100644
index 0000000..a474cdc
--- /dev/null
+++ b/t/unit-tests/unit-test.c
@@ -0,0 +1,47 @@
+#include "unit-test.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "strvec.h"
+
+static const char * const unit_test_usage[] = {
+	N_("unit-test [<options>]"),
+	NULL,
+};
+
+int cmd_main(int argc, const char **argv)
+{
+	struct string_list run_args = STRING_LIST_INIT_NODUP;
+	struct string_list exclude_args = STRING_LIST_INIT_NODUP;
+	int immediate = 0;
+	struct option options[] = {
+		OPT_BOOL('i', "immediate", &immediate,
+			 N_("immediately exit upon the first failed test")),
+		OPT_STRING_LIST('r', "run", &run_args, N_("suite[::test]"),
+				N_("run only test suite or individual test <suite[::test]>")),
+		OPT_STRING_LIST('x', "exclude", &exclude_args, N_("suite"),
+				N_("exclude test suite <suite>")),
+		OPT_END(),
+	};
+	struct strvec args = STRVEC_INIT;
+	int ret;
+
+	argc = parse_options(argc, argv, NULL, options,
+			     unit_test_usage, PARSE_OPT_KEEP_ARGV0);
+	if (argc > 1)
+		usagef(_("extra command line parameter '%s'"), argv[0]);
+
+	strvec_push(&args, argv[0]);
+	strvec_push(&args, "-t");
+	if (immediate)
+		strvec_push(&args, "-Q");
+	for (size_t i = 0; i < run_args.nr; i++)
+		strvec_pushf(&args, "-s%s", run_args.items[i].string);
+	for (size_t i = 0; i < exclude_args.nr; i++)
+		strvec_pushf(&args, "-x%s", exclude_args.items[i].string);
+
+	ret = clar_test(args.nr, (char **) args.v);
+
+	string_list_clear(&run_args, 0);
+	strvec_clear(&args);
+	return ret;
+}
diff --git a/t/unit-tests/unit-test.h b/t/unit-tests/unit-test.h
new file mode 100644
index 0000000..85e5d6a
--- /dev/null
+++ b/t/unit-tests/unit-test.h
@@ -0,0 +1,10 @@
+#include "git-compat-util.h"
+#include "clar/clar.h"
+#include "clar-decls.h"
+#include "strbuf.h"
+
+#define cl_failf(fmt, ...) do { \
+	char desc[4096]; \
+	snprintf(desc, sizeof(desc), fmt, __VA_ARGS__); \
+	clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1); \
+} while (0)
diff --git a/tmp-objdir.c b/tmp-objdir.c
index a8e4553..9da0071 100644
--- a/tmp-objdir.c
+++ b/tmp-objdir.c
@@ -13,6 +13,7 @@
 #include "strvec.h"
 #include "quote.h"
 #include "object-store-ll.h"
+#include "repository.h"
 
 struct tmp_objdir {
 	struct strbuf path;
@@ -132,7 +133,8 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix)
 	 * can recognize any stale objdirs left behind by a crash and delete
 	 * them.
 	 */
-	strbuf_addf(&t->path, "%s/tmp_objdir-%s-XXXXXX", get_object_directory(), prefix);
+	strbuf_addf(&t->path, "%s/tmp_objdir-%s-XXXXXX",
+		    repo_get_object_directory(the_repository), prefix);
 
 	if (!mkdtemp(t->path.buf)) {
 		/* free, not destroy, as we never touched the filesystem */
@@ -152,7 +154,7 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix)
 	}
 
 	env_append(&t->env, ALTERNATE_DB_ENVIRONMENT,
-		   absolute_path(get_object_directory()));
+		   absolute_path(repo_get_object_directory(the_repository)));
 	env_replace(&t->env, DB_ENVIRONMENT, absolute_path(t->path.buf));
 	env_replace(&t->env, GIT_QUARANTINE_ENVIRONMENT,
 		    absolute_path(t->path.buf));
@@ -204,9 +206,11 @@ 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 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 strbuf *src, struct strbuf *dst,
+		       enum finalize_object_file_flags flags)
 {
 	struct stat st;
 
@@ -218,12 +222,18 @@ static int migrate_one(struct strbuf *src, struct strbuf *dst)
 				return -1;
 		} else if (errno != EEXIST)
 			return -1;
-		return migrate_paths(src, dst);
+		return migrate_paths(src, dst, flags);
 	}
-	return finalize_object_file(src->buf, dst->buf);
+	return finalize_object_file_flags(src->buf, dst->buf, flags);
 }
 
-static int migrate_paths(struct strbuf *src, struct strbuf *dst)
+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,
+			 enum finalize_object_file_flags flags)
 {
 	size_t src_len = src->len, dst_len = dst->len;
 	struct string_list paths = STRING_LIST_INIT_DUP;
@@ -237,11 +247,15 @@ static int migrate_paths(struct strbuf *src, struct strbuf *dst)
 
 	for (i = 0; i < paths.nr; i++) {
 		const char *name = paths.items[i].string;
+		enum finalize_object_file_flags flags_copy = flags;
 
 		strbuf_addf(src, "/%s", name);
 		strbuf_addf(dst, "/%s", name);
 
-		ret |= migrate_one(src, dst);
+		if (is_loose_object_shard(name))
+			flags_copy |= FOF_SKIP_COLLISION_CHECK;
+
+		ret |= migrate_one(src, dst, flags_copy);
 
 		strbuf_setlen(src, src_len);
 		strbuf_setlen(dst, dst_len);
@@ -267,9 +281,9 @@ int tmp_objdir_migrate(struct tmp_objdir *t)
 	}
 
 	strbuf_addbuf(&src, &t->path);
-	strbuf_addstr(&dst, get_object_directory());
+	strbuf_addstr(&dst, repo_get_object_directory(the_repository));
 
-	ret = migrate_paths(&src, &dst);
+	ret = migrate_paths(&src, &dst, 0);
 
 	strbuf_release(&src);
 	strbuf_release(&dst);
diff --git a/trace.c b/trace.c
index 8669ddf..d8c4377 100644
--- a/trace.c
+++ b/trace.c
@@ -21,9 +21,11 @@
  *  along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "abspath.h"
-#include "environment.h"
+#include "repository.h"
 #include "quote.h"
 #include "setup.h"
 #include "trace.h"
@@ -305,14 +307,14 @@ void trace_repo_setup(void)
 
 	cwd = xgetcwd();
 
-	if (!(git_work_tree = get_git_work_tree()))
+	if (!(git_work_tree = repo_get_work_tree(the_repository)))
 		git_work_tree = "(null)";
 
 	if (!startup_info->prefix)
 		prefix = "(null)";
 
-	trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
-	trace_printf_key(&trace_setup_key, "setup: git_common_dir: %s\n", quote_crnl(get_git_common_dir()));
+	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: 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/trace2.h b/trace2.h
index 19e04bf..901f392 100644
--- a/trace2.h
+++ b/trace2.h
@@ -554,6 +554,7 @@ enum trace2_counter_id {
 	TRACE2_COUNTER_ID_TEST2,     /* emits summary and thread events */
 
 	TRACE2_COUNTER_ID_PACKED_REFS_JUMPS, /* counts number of jumps */
+	TRACE2_COUNTER_ID_REFTABLE_RESEEKS, /* counts number of re-seeks */
 
 	/* counts number of fsyncs */
 	TRACE2_COUNTER_ID_FSYNC_WRITEOUT_ONLY,
diff --git a/trace2/tr2_cfg.c b/trace2/tr2_cfg.c
index d96d908..22a99a0 100644
--- a/trace2/tr2_cfg.c
+++ b/trace2/tr2_cfg.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "strbuf.h"
@@ -124,7 +126,7 @@ void tr2_cfg_list_config_fl(const char *file, int line)
 	struct tr2_cfg_data data = { file, line };
 
 	if (tr2_cfg_load_patterns() > 0)
-		read_early_config(tr2_cfg_cb, &data);
+		read_early_config(the_repository, tr2_cfg_cb, &data);
 }
 
 void tr2_list_env_vars_fl(const char *file, int line)
diff --git a/trace2/tr2_ctr.c b/trace2/tr2_ctr.c
index d3a3371..ee17bfa 100644
--- a/trace2/tr2_ctr.c
+++ b/trace2/tr2_ctr.c
@@ -4,7 +4,7 @@
 #include "trace2/tr2_ctr.h"
 
 /*
- * A global counter block to aggregrate values from the partial sums
+ * A global counter block to aggregate values from the partial sums
  * from each thread.
  */
 static struct tr2_counter_block final_counter_block; /* access under tr2tls_mutex */
@@ -31,6 +31,11 @@ static struct tr2_counter_metadata tr2_counter_metadata[TRACE2_NUMBER_OF_COUNTER
 		.name = "jumps_made",
 		.want_per_thread_events = 0,
 	},
+	[TRACE2_COUNTER_ID_REFTABLE_RESEEKS] = {
+		.category = "reftable",
+		.name = "reseeks_made",
+		.want_per_thread_events = 0,
+	},
 	[TRACE2_COUNTER_ID_FSYNC_WRITEOUT_ONLY] = {
 		.category = "fsync",
 		.name = "writeout-only",
diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c
index 59910a1..45b0850 100644
--- a/trace2/tr2_tgt_event.c
+++ b/trace2/tr2_tgt_event.c
@@ -24,7 +24,7 @@ static struct tr2_dst tr2dst_event = {
  * a new field to an existing event, do not require an increment to the EVENT
  * format version.
  */
-#define TR2_EVENT_VERSION "3"
+#define TR2_EVENT_VERSION "4"
 
 /*
  * Region nesting limit for messages written to the event target.
@@ -622,6 +622,24 @@ static void fn_data_json_fl(const char *file, int line,
 	}
 }
 
+static void fn_printf_va_fl(const char *file, int line,
+			    uint64_t us_elapsed_absolute,
+			    const char *fmt, va_list ap)
+{
+	const char *event_name = "printf";
+	struct json_writer jw = JSON_WRITER_INIT;
+	double t_abs = (double)us_elapsed_absolute / 1000000.0;
+
+	jw_object_begin(&jw, 0);
+	event_fmt_prepare(event_name, file, line, NULL, &jw);
+	jw_object_double(&jw, "t_abs", 6, t_abs);
+	maybe_add_string_va(&jw, "msg", fmt, ap);
+	jw_end(&jw);
+
+	tr2_dst_write_line(&tr2dst_event, &jw.json);
+	jw_release(&jw);
+}
+
 static void fn_timer(const struct tr2_timer_metadata *meta,
 		     const struct tr2_timer *timer,
 		     int is_final_data)
@@ -694,7 +712,7 @@ struct tr2_tgt tr2_tgt_event = {
 	.pfn_region_leave_printf_va_fl = fn_region_leave_printf_va_fl,
 	.pfn_data_fl = fn_data_fl,
 	.pfn_data_json_fl = fn_data_json_fl,
-	.pfn_printf_va_fl = NULL,
+	.pfn_printf_va_fl = fn_printf_va_fl,
 	.pfn_timer = fn_timer,
 	.pfn_counter = fn_counter,
 };
diff --git a/trace2/tr2_tls.c b/trace2/tr2_tls.c
index 4f75392..7b023c1 100644
--- a/trace2/tr2_tls.c
+++ b/trace2/tr2_tls.c
@@ -152,11 +152,19 @@ uint64_t tr2tls_absolute_elapsed(uint64_t us)
 	return us - tr2tls_us_start_process;
 }
 
+static void tr2tls_key_destructor(void *payload)
+{
+	struct tr2tls_thread_ctx *ctx = payload;
+	free((char *)ctx->thread_name);
+	free(ctx->array_us_start);
+	free(ctx);
+}
+
 void tr2tls_init(void)
 {
 	tr2tls_start_process_clock();
 
-	pthread_key_create(&tr2tls_key, NULL);
+	pthread_key_create(&tr2tls_key, tr2tls_key_destructor);
 	init_recursive_mutex(&tr2tls_mutex);
 
 	tr2tls_thread_main =
diff --git a/trace2/tr2_tls.h b/trace2/tr2_tls.h
index 3dfe655..3bdbf4d 100644
--- a/trace2/tr2_tls.h
+++ b/trace2/tr2_tls.h
@@ -11,7 +11,7 @@
  */
 
 /*
- * Arbitry limit for thread names for column alignment.
+ * Arbitrary limit for thread names for column alignment.
  */
 #define TR2_MAX_THREAD_NAME (24)
 
diff --git a/trailer.c b/trailer.c
index 72e5136..682d745 100644
--- a/trailer.c
+++ b/trailer.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "environment.h"
diff --git a/transport-helper.c b/transport-helper.c
index 09b3560..013ec79 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -89,11 +89,18 @@ static int recvline(struct helper_data *helper, struct strbuf *buffer)
 	return recvline_fh(helper->out, buffer);
 }
 
-static void write_constant(int fd, const char *str)
+static int write_constant_gently(int fd, const char *str)
 {
 	if (debug)
 		fprintf(stderr, "Debug: Remote helper: -> %s", str);
 	if (write_in_full(fd, str, strlen(str)) < 0)
+		return -1;
+	return 0;
+}
+
+static void write_constant(int fd, const char *str)
+{
+	if (write_constant_gently(fd, str) < 0)
 		die_errno(_("full write to remote helper failed"));
 }
 
@@ -143,7 +150,7 @@ static struct child_process *get_helper(struct transport *transport)
 
 	if (have_git_dir())
 		strvec_pushf(&helper->env, "%s=%s",
-			     GIT_DIR_ENVIRONMENT, get_git_dir());
+			     GIT_DIR_ENVIRONMENT, repo_get_git_dir(the_repository));
 
 	helper->trace2_child_class = helper->args.v[0]; /* "remote-<name>" */
 
@@ -168,13 +175,16 @@ static struct child_process *get_helper(struct transport *transport)
 		die_errno(_("can't dup helper output fd"));
 	data->out = xfdopen(duped, "r");
 
-	write_constant(helper->in, "capabilities\n");
+	sigchain_push(SIGPIPE, SIG_IGN);
+	if (write_constant_gently(helper->in, "capabilities\n") < 0)
+		die("remote helper '%s' aborted session", data->name);
+	sigchain_pop(SIGPIPE);
 
 	while (1) {
 		const char *capname, *arg;
 		int mandatory = 0;
 		if (recvline(data, &buf))
-			exit(128);
+			die("remote helper '%s' aborted session", data->name);
 
 		if (!*buf.buf)
 			break;
@@ -707,8 +717,14 @@ static int fetch_refs(struct transport *transport,
 		return -1;
 	}
 
-	if (!data->get_refs_list_called)
-		get_refs_list_using_list(transport, 0);
+	if (!data->get_refs_list_called) {
+		/*
+		 * We do not care about the list of refs returned, but only
+		 * that the "list" command was sent.
+		 */
+		struct ref *dummy = get_refs_list_using_list(transport, 0);
+		free_refs(dummy);
+	}
 
 	count = 0;
 	for (i = 0; i < nr_heads; i++)
@@ -1013,6 +1029,7 @@ static int push_refs_with_push(struct transport *transport,
 			if (atomic) {
 				reject_atomic_push(remote_refs, mirror);
 				string_list_clear(&cas_options, 0);
+				strbuf_release(&buf);
 				return 0;
 			} else
 				continue;
diff --git a/transport.c b/transport.c
index 12cc5b4..1098bbd 100644
--- a/transport.c
+++ b/transport.c
@@ -189,6 +189,8 @@ static int fetch_refs_from_bundle(struct transport *transport,
 		       &extra_index_pack_args,
 		       fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0);
 	transport->hash_algo = data->header.hash_algo;
+
+	strvec_clear(&extra_index_pack_args);
 	return ret;
 }
 
@@ -412,7 +414,7 @@ static int fetch_refs_via_pack(struct transport *transport,
 	struct git_transport_data *data = transport->data;
 	struct ref *refs = NULL;
 	struct fetch_pack_args args;
-	struct ref *refs_tmp = NULL;
+	struct ref *refs_tmp = NULL, **to_fetch_dup = NULL;
 
 	memset(&args, 0, sizeof(args));
 	args.uploadpack = data->options.uploadpack;
@@ -475,6 +477,14 @@ static int fetch_refs_via_pack(struct transport *transport,
 		goto cleanup;
 	}
 
+	/*
+	 * Create a shallow copy of `sought` so that we can free all of its entries.
+	 * This is because `fetch_pack()` will modify the array to evict some
+	 * entries, but won't free those.
+	 */
+	DUP_ARRAY(to_fetch_dup, to_fetch, nr_heads);
+	to_fetch = to_fetch_dup;
+
 	refs = fetch_pack(&args, data->fd,
 			  refs_tmp ? refs_tmp : transport->remote_refs,
 			  to_fetch, nr_heads, &data->shallow,
@@ -498,6 +508,7 @@ static int fetch_refs_via_pack(struct transport *transport,
 		ret = -1;
 	data->conn = NULL;
 
+	free(to_fetch_dup);
 	free_refs(refs_tmp);
 	free_refs(refs);
 	list_objects_filter_release(&args.filter_options);
@@ -945,7 +956,13 @@ static int disconnect_git(struct transport *transport)
 		finish_connect(data->conn);
 	}
 
+	if (data->options.negotiation_tips) {
+		oid_array_clear(data->options.negotiation_tips);
+		free(data->options.negotiation_tips);
+	}
 	list_objects_filter_release(&data->options.filter_options);
+	oid_array_clear(&data->extra_have);
+	oid_array_clear(&data->shallow);
 	free(data);
 	return 0;
 }
@@ -1115,6 +1132,7 @@ static struct transport_vtable builtin_smart_vtable = {
 struct transport *transport_get(struct remote *remote, const char *url)
 {
 	const char *helper;
+	char *helper_to_free = NULL;
 	const char *p;
 	struct transport *ret = xcalloc(1, sizeof(*ret));
 
@@ -1139,10 +1157,11 @@ struct transport *transport_get(struct remote *remote, const char *url)
 	while (is_urlschemechar(p == url, *p))
 		p++;
 	if (starts_with(p, "::"))
-		helper = xstrndup(url, p - url);
+		helper = helper_to_free = xstrndup(url, p - url);
 
 	if (helper) {
 		transport_helper_init(ret, helper);
+		free(helper_to_free);
 	} else if (starts_with(url, "rsync:")) {
 		die(_("git-over-rsync is no longer supported"));
 	} else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
@@ -1271,7 +1290,7 @@ static int run_pre_push_hook(struct transport *transport,
 	struct ref *r;
 	struct child_process proc = CHILD_PROCESS_INIT;
 	struct strbuf buf;
-	const char *hook_path = find_hook("pre-push");
+	const char *hook_path = find_hook(the_repository, "pre-push");
 
 	if (!hook_path)
 		return 0;
diff --git a/tree-diff.c b/tree-diff.c
index 9252481..5eab8af 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -1,6 +1,9 @@
 /*
  * Helper functions for tree diff generation
  */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "diff.h"
 #include "diffcore.h"
diff --git a/unicode-width.h b/unicode-width.h
index be5bf8c..3ffee12 100644
--- a/unicode-width.h
+++ b/unicode-width.h
@@ -27,7 +27,7 @@
 { 0x0829, 0x082D },
 { 0x0859, 0x085B },
 { 0x0890, 0x0891 },
-{ 0x0898, 0x089F },
+{ 0x0897, 0x089F },
 { 0x08CA, 0x0902 },
 { 0x093A, 0x093A },
 { 0x093C, 0x093C },
@@ -227,8 +227,9 @@
 { 0x10A3F, 0x10A3F },
 { 0x10AE5, 0x10AE6 },
 { 0x10D24, 0x10D27 },
+{ 0x10D69, 0x10D6D },
 { 0x10EAB, 0x10EAC },
-{ 0x10EFD, 0x10EFF },
+{ 0x10EFC, 0x10EFF },
 { 0x10F46, 0x10F50 },
 { 0x10F82, 0x10F85 },
 { 0x11001, 0x11001 },
@@ -261,6 +262,11 @@
 { 0x11340, 0x11340 },
 { 0x11366, 0x1136C },
 { 0x11370, 0x11374 },
+{ 0x113BB, 0x113C0 },
+{ 0x113CE, 0x113CE },
+{ 0x113D0, 0x113D0 },
+{ 0x113D2, 0x113D2 },
+{ 0x113E1, 0x113E2 },
 { 0x11438, 0x1143F },
 { 0x11442, 0x11444 },
 { 0x11446, 0x11446 },
@@ -280,7 +286,8 @@
 { 0x116AD, 0x116AD },
 { 0x116B0, 0x116B5 },
 { 0x116B7, 0x116B7 },
-{ 0x1171D, 0x1171F },
+{ 0x1171D, 0x1171D },
+{ 0x1171F, 0x1171F },
 { 0x11722, 0x11725 },
 { 0x11727, 0x1172B },
 { 0x1182F, 0x11837 },
@@ -319,8 +326,11 @@
 { 0x11F36, 0x11F3A },
 { 0x11F40, 0x11F40 },
 { 0x11F42, 0x11F42 },
+{ 0x11F5A, 0x11F5A },
 { 0x13430, 0x13440 },
 { 0x13447, 0x13455 },
+{ 0x1611E, 0x16129 },
+{ 0x1612D, 0x1612F },
 { 0x16AF0, 0x16AF4 },
 { 0x16B30, 0x16B36 },
 { 0x16F4F, 0x16F4F },
@@ -351,6 +361,7 @@
 { 0x1E2AE, 0x1E2AE },
 { 0x1E2EC, 0x1E2EF },
 { 0x1E4EC, 0x1E4EF },
+{ 0x1E5EE, 0x1E5EF },
 { 0x1E8D0, 0x1E8D6 },
 { 0x1E944, 0x1E94A },
 { 0xE0001, 0xE0001 },
@@ -366,8 +377,10 @@ static const struct interval double_width[] = {
 { 0x23F3, 0x23F3 },
 { 0x25FD, 0x25FE },
 { 0x2614, 0x2615 },
+{ 0x2630, 0x2637 },
 { 0x2648, 0x2653 },
 { 0x267F, 0x267F },
+{ 0x268A, 0x268F },
 { 0x2693, 0x2693 },
 { 0x26A1, 0x26A1 },
 { 0x26AA, 0x26AB },
@@ -401,11 +414,10 @@ static const struct interval double_width[] = {
 { 0x3099, 0x30FF },
 { 0x3105, 0x312F },
 { 0x3131, 0x318E },
-{ 0x3190, 0x31E3 },
+{ 0x3190, 0x31E5 },
 { 0x31EF, 0x321E },
 { 0x3220, 0x3247 },
-{ 0x3250, 0x4DBF },
-{ 0x4E00, 0xA48C },
+{ 0x3250, 0xA48C },
 { 0xA490, 0xA4C6 },
 { 0xA960, 0xA97C },
 { 0xAC00, 0xD7A3 },
@@ -420,7 +432,7 @@ static const struct interval double_width[] = {
 { 0x16FF0, 0x16FF1 },
 { 0x17000, 0x187F7 },
 { 0x18800, 0x18CD5 },
-{ 0x18D00, 0x18D08 },
+{ 0x18CFF, 0x18D08 },
 { 0x1AFF0, 0x1AFF3 },
 { 0x1AFF5, 0x1AFFB },
 { 0x1AFFD, 0x1AFFE },
@@ -430,6 +442,8 @@ static const struct interval double_width[] = {
 { 0x1B155, 0x1B155 },
 { 0x1B164, 0x1B167 },
 { 0x1B170, 0x1B2FB },
+{ 0x1D300, 0x1D356 },
+{ 0x1D360, 0x1D376 },
 { 0x1F004, 0x1F004 },
 { 0x1F0CF, 0x1F0CF },
 { 0x1F18E, 0x1F18E },
@@ -470,11 +484,10 @@ static const struct interval double_width[] = {
 { 0x1F93C, 0x1F945 },
 { 0x1F947, 0x1F9FF },
 { 0x1FA70, 0x1FA7C },
-{ 0x1FA80, 0x1FA88 },
-{ 0x1FA90, 0x1FABD },
-{ 0x1FABF, 0x1FAC5 },
-{ 0x1FACE, 0x1FADB },
-{ 0x1FAE0, 0x1FAE8 },
+{ 0x1FA80, 0x1FA89 },
+{ 0x1FA8F, 0x1FAC6 },
+{ 0x1FACE, 0x1FADC },
+{ 0x1FADF, 0x1FAE9 },
 { 0x1FAF0, 0x1FAF8 },
 { 0x20000, 0x2FFFD },
 { 0x30000, 0x3FFFD }
diff --git a/unpack-trees.c b/unpack-trees.c
index 7dc884f..e10a9d1 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -210,6 +210,7 @@ void clear_unpack_trees_porcelain(struct unpack_trees_options *opts)
 {
 	strvec_clear(&opts->internal.msgs_to_free);
 	memset(opts->internal.msgs, 0, sizeof(opts->internal.msgs));
+	discard_index(&opts->internal.result);
 }
 
 static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
@@ -807,6 +808,8 @@ static int traverse_by_cache_tree(int pos, int nr_entries, int nr_names,
 
 	if (!o->merge)
 		BUG("We need cache-tree to do this optimization");
+	if (nr_entries + pos > o->src_index->cache_nr)
+		return error(_("corrupted cache-tree has entries not present in index"));
 
 	/*
 	 * Do what unpack_callback() and unpack_single_entry() normally
@@ -2069,9 +2072,13 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 	if (o->dst_index) {
 		move_index_extensions(&o->internal.result, o->src_index);
 		if (!ret) {
-			if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
-				cache_tree_verify(the_repository,
-						  &o->internal.result);
+			if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0) &&
+			    cache_tree_verify(the_repository,
+					      &o->internal.result) < 0) {
+				ret = -1;
+				goto done;
+			}
+
 			if (!o->skip_cache_tree_update &&
 			    !cache_tree_fully_valid(o->internal.result.cache_tree))
 				cache_tree_update(&o->internal.result,
@@ -2082,6 +2089,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 		o->internal.result.updated_workdir = 1;
 		discard_index(o->dst_index);
 		*o->dst_index = o->internal.result;
+		memset(&o->internal.result, 0, sizeof(o->internal.result));
 	} else {
 		discard_index(&o->internal.result);
 	}
diff --git a/upload-pack.c b/upload-pack.c
index 0052c6a..6d6e0f9 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -709,10 +709,13 @@ static int get_reachable_list(struct upload_pack_data *data,
 	struct object *o;
 	char namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */
 	const unsigned hexsz = the_hash_algo->hexsz;
+	int ret;
 
 	if (do_reachable_revlist(&cmd, &data->shallows, reachable,
-				 data->allow_uor) < 0)
-		return -1;
+				 data->allow_uor) < 0) {
+		ret = -1;
+		goto out;
+	}
 
 	while ((i = read_in_full(cmd.out, namebuf, hexsz + 1)) == hexsz + 1) {
 		struct object_id oid;
@@ -736,10 +739,16 @@ static int get_reachable_list(struct upload_pack_data *data,
 	}
 	close(cmd.out);
 
-	if (finish_command(&cmd))
-		return -1;
+	if (finish_command(&cmd)) {
+		ret = -1;
+		goto out;
+	}
 
-	return 0;
+	ret = 0;
+
+out:
+	child_process_clear(&cmd);
+	return ret;
 }
 
 static int has_unreachable(struct object_array *src, enum allow_uor allow_uor)
@@ -749,7 +758,7 @@ static int has_unreachable(struct object_array *src, enum allow_uor allow_uor)
 	int i;
 
 	if (do_reachable_revlist(&cmd, src, NULL, allow_uor) < 0)
-		return 1;
+		goto error;
 
 	/*
 	 * The commits out of the rev-list are not ancestors of
@@ -775,6 +784,7 @@ static int has_unreachable(struct object_array *src, enum allow_uor allow_uor)
 error:
 	if (cmd.out >= 0)
 		close(cmd.out);
+	child_process_clear(&cmd);
 	return 1;
 }
 
@@ -857,7 +867,7 @@ static void send_unshallow(struct upload_pack_data *data)
 	}
 }
 
-static int check_ref(const char *refname_full, const struct object_id *oid,
+static int check_ref(const char *refname_full, const char *referent UNUSED, const struct object_id *oid,
 		     int flag, void *cb_data);
 static void deepen(struct upload_pack_data *data, int depth)
 {
@@ -1208,7 +1218,7 @@ static int mark_our_ref(const char *refname, const char *refname_full,
 	return 0;
 }
 
-static int check_ref(const char *refname_full, const struct object_id *oid,
+static int check_ref(const char *refname_full, const char *referent UNUSED,const struct object_id *oid,
 		     int flag UNUSED, void *cb_data)
 {
 	const char *refname = strip_namespace(refname_full);
@@ -1276,14 +1286,14 @@ static void write_v0_ref(struct upload_pack_data *data,
 	return;
 }
 
-static int send_ref(const char *refname, const struct object_id *oid,
+static int send_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
 		    int flag UNUSED, void *cb_data)
 {
 	write_v0_ref(cb_data, refname, strip_namespace(refname), oid);
 	return 0;
 }
 
-static int find_symref(const char *refname,
+static int find_symref(const char *refname, const char *referent UNUSED,
 		       const struct object_id *oid UNUSED,
 		       int flag, void *cb_data)
 {
@@ -1802,7 +1812,7 @@ int upload_pack_v2(struct repository *r, struct packet_reader *request)
 			} else {
 				/*
 				 * Request had 'want's but no 'have's so we can
-				 * immedietly go to construct and send a pack.
+				 * immediately go to construct and send a pack.
 				 */
 				state = FETCH_SEND_PACK;
 			}
diff --git a/userdiff.c b/userdiff.c
index c4ebb9f..d43d836 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "userdiff.h"
@@ -399,8 +401,11 @@ static struct userdiff_driver *userdiff_find_by_namelen(const char *name, size_t
 static int parse_funcname(struct userdiff_funcname *f, const char *k,
 		const char *v, int cflags)
 {
-	if (git_config_string((char **) &f->pattern, k, v) < 0)
+	f->pattern = NULL;
+	FREE_AND_NULL(f->pattern_owned);
+	if (git_config_string(&f->pattern_owned, k, v) < 0)
 		return -1;
+	f->pattern = f->pattern_owned;
 	f->cflags = cflags;
 	return 0;
 }
@@ -444,20 +449,37 @@ int userdiff_config(const char *k, const char *v)
 		return parse_funcname(&drv->funcname, k, v, REG_EXTENDED);
 	if (!strcmp(type, "binary"))
 		return parse_tristate(&drv->binary, k, v);
-	if (!strcmp(type, "command"))
-		return git_config_string((char **) &drv->external.cmd, k, v);
+	if (!strcmp(type, "command")) {
+		FREE_AND_NULL(drv->external.cmd);
+		return git_config_string(&drv->external.cmd, k, v);
+	}
 	if (!strcmp(type, "trustexitcode")) {
 		drv->external.trust_exit_code = git_config_bool(k, v);
 		return 0;
 	}
-	if (!strcmp(type, "textconv"))
-		return git_config_string((char **) &drv->textconv, k, v);
+	if (!strcmp(type, "textconv")) {
+		int ret;
+		FREE_AND_NULL(drv->textconv_owned);
+		ret = git_config_string(&drv->textconv_owned, k, v);
+		drv->textconv = drv->textconv_owned;
+		return ret;
+	}
 	if (!strcmp(type, "cachetextconv"))
 		return parse_bool(&drv->textconv_want_cache, k, v);
-	if (!strcmp(type, "wordregex"))
-		return git_config_string((char **) &drv->word_regex, k, v);
-	if (!strcmp(type, "algorithm"))
-		return git_config_string((char **) &drv->algorithm, k, v);
+	if (!strcmp(type, "wordregex")) {
+		int ret;
+		FREE_AND_NULL(drv->word_regex_owned);
+		ret = git_config_string(&drv->word_regex_owned, k, v);
+		drv->word_regex = drv->word_regex_owned;
+		return ret;
+	}
+	if (!strcmp(type, "algorithm")) {
+		int ret;
+		FREE_AND_NULL(drv->algorithm_owned);
+		ret = git_config_string(&drv->algorithm_owned, k, v);
+		drv->algorithm = drv->algorithm_owned;
+		return ret;
+	}
 
 	return 0;
 }
diff --git a/userdiff.h b/userdiff.h
index 7565930..827361b 100644
--- a/userdiff.h
+++ b/userdiff.h
@@ -8,6 +8,7 @@ struct repository;
 
 struct userdiff_funcname {
 	const char *pattern;
+	char *pattern_owned;
 	int cflags;
 };
 
@@ -20,11 +21,14 @@ struct userdiff_driver {
 	const char *name;
 	struct external_diff external;
 	const char *algorithm;
+	char *algorithm_owned;
 	int binary;
 	struct userdiff_funcname funcname;
 	const char *word_regex;
+	char *word_regex_owned;
 	const char *word_regex_multi_byte;
 	const char *textconv;
+	char *textconv_owned;
 	struct notes_cache *textconv_cache;
 	int textconv_want_cache;
 };
diff --git a/utf8.h b/utf8.h
index 35df760..cf8ecb0 100644
--- a/utf8.h
+++ b/utf8.h
@@ -33,8 +33,9 @@ char *reencode_string_len(const char *in, size_t insz,
 			  const char *in_encoding,
 			  size_t *outsz);
 #else
-static inline char *reencode_string_len(const char *a, size_t b,
-					const char *c, const char *d, size_t *e)
+static inline char *reencode_string_len(const char *a UNUSED, size_t b UNUSED,
+					const char *c UNUSED,
+					const char *d UNUSED, size_t *e)
 { if (e) *e = 0; return NULL; }
 #endif
 
diff --git a/versioncmp.c b/versioncmp.c
index 45e676c..e3b2a6e 100644
--- a/versioncmp.c
+++ b/versioncmp.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "config.h"
 #include "strbuf.h"
diff --git a/walker.c b/walker.c
index 0fafdc9..807a7a3 100644
--- a/walker.c
+++ b/walker.c
@@ -221,6 +221,7 @@ static int interpret_target(struct walker *walker, char *target, struct object_i
 }
 
 static int mark_complete(const char *path UNUSED,
+			const char *referent UNUSED,
 			 const struct object_id *oid,
 			 int flag UNUSED,
 			 void *cb_data UNUSED)
diff --git a/worktree.c b/worktree.c
index f3c4c8e..0f032cc 100644
--- a/worktree.c
+++ b/worktree.c
@@ -57,7 +57,7 @@ static void add_head_info(struct worktree *wt)
 
 static int is_current_worktree(struct worktree *wt)
 {
-	char *git_dir = absolute_pathdup(get_git_dir());
+	char *git_dir = absolute_pathdup(repo_get_git_dir(the_repository));
 	const char *wt_git_dir = get_worktree_git_dir(wt);
 	int is_current = !fspathcmp(git_dir, absolute_path(wt_git_dir));
 	free(git_dir);
@@ -72,7 +72,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)
 	struct worktree *worktree = NULL;
 	struct strbuf worktree_path = STRBUF_INIT;
 
-	strbuf_add_real_path(&worktree_path, get_git_common_dir());
+	strbuf_add_real_path(&worktree_path, repo_get_common_dir(the_repository));
 	strbuf_strip_suffix(&worktree_path, "/.git");
 
 	CALLOC_ARRAY(worktree, 1);
@@ -143,7 +143,7 @@ static struct worktree **get_worktrees_internal(int skip_reading_head)
 
 	list[counter++] = get_main_worktree(skip_reading_head);
 
-	strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
+	strbuf_addf(&path, "%s/worktrees", repo_get_common_dir(the_repository));
 	dir = opendir(path.buf);
 	strbuf_release(&path);
 	if (dir) {
@@ -171,9 +171,9 @@ struct worktree **get_worktrees(void)
 const char *get_worktree_git_dir(const struct worktree *wt)
 {
 	if (!wt)
-		return get_git_dir();
+		return repo_get_git_dir(the_repository);
 	else if (!wt->id)
-		return get_git_common_dir();
+		return repo_get_common_dir(the_repository);
 	else
 		return git_common_path("worktrees/%s", wt->id);
 }
@@ -252,7 +252,7 @@ const char *worktree_lock_reason(struct worktree *wt)
 	if (!wt->lock_reason_valid) {
 		struct strbuf path = STRBUF_INIT;
 
-		strbuf_addstr(&path, worktree_git_path(wt, "locked"));
+		strbuf_addstr(&path, worktree_git_path(the_repository, wt, "locked"));
 		if (file_exists(path.buf)) {
 			struct strbuf lock_reason = STRBUF_INIT;
 			if (strbuf_read_file(&lock_reason, path.buf, 0) < 0)
@@ -546,7 +546,7 @@ int other_head_refs(each_ref_fn fn, void *cb_data)
 					    refname.buf,
 					    RESOLVE_REF_READING,
 					    &oid, &flag))
-			ret = fn(refname.buf, &oid, flag, cb_data);
+			ret = fn(refname.buf, NULL, &oid, flag, cb_data);
 		if (ret)
 			break;
 	}
@@ -626,7 +626,7 @@ static int is_main_worktree_path(const char *path)
 
 	strbuf_add_real_path(&target, path);
 	strbuf_strip_suffix(&target, "/.git");
-	strbuf_add_real_path(&maindir, get_git_common_dir());
+	strbuf_add_real_path(&maindir, repo_get_common_dir(the_repository));
 	strbuf_strip_suffix(&maindir, "/.git");
 	cmp = fspathcmp(maindir.buf, target.buf);
 
diff --git a/wrapper.h b/wrapper.h
index 1b2b047..a6b3e1f 100644
--- a/wrapper.h
+++ b/wrapper.h
@@ -140,4 +140,22 @@ int csprng_bytes(void *buf, size_t len);
  */
 uint32_t git_rand(void);
 
+/* Provide log2 of the given `size_t`. */
+static inline unsigned log2u(uintmax_t sz)
+{
+	unsigned l = 0;
+
+	/*
+	 * Technically this isn't required, but it helps the compiler optimize
+	 * this to a `bsr` instruction.
+	 */
+	if (!sz)
+		return 0;
+
+	for (; sz; sz >>= 1)
+		l++;
+
+	return l - 1;
+}
+
 #endif /* WRAPPER_H */
diff --git a/wt-status.c b/wt-status.c
index b778eef..6a6397c 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -16,6 +16,7 @@
 #include "revision.h"
 #include "diffcore.h"
 #include "quote.h"
+#include "repository.h"
 #include "run-command.h"
 #include "strvec.h"
 #include "remote.h"
@@ -152,7 +153,7 @@ void wt_status_prepare(struct repository *r, struct wt_status *s)
 					"HEAD", 0, NULL, NULL);
 	s->reference = "HEAD";
 	s->fp = stdout;
-	s->index_file = get_index_file();
+	s->index_file = repo_get_index_file(the_repository);
 	s->change.strdup_strings = 1;
 	s->untracked.strdup_strings = 1;
 	s->ignored.strdup_strings = 1;
@@ -1618,7 +1619,7 @@ static char *get_branch(const struct worktree *wt, const char *path)
 	struct object_id oid;
 	const char *branch_name;
 
-	if (strbuf_read_file(&sb, worktree_git_path(wt, "%s", path), 0) <= 0)
+	if (strbuf_read_file(&sb, worktree_git_path(the_repository, wt, "%s", path), 0) <= 0)
 		goto got_nothing;
 
 	while (sb.len && sb.buf[sb.len - 1] == '\n')
@@ -1716,18 +1717,18 @@ int wt_status_check_rebase(const struct worktree *wt,
 {
 	struct stat st;
 
-	if (!stat(worktree_git_path(wt, "rebase-apply"), &st)) {
-		if (!stat(worktree_git_path(wt, "rebase-apply/applying"), &st)) {
+	if (!stat(worktree_git_path(the_repository, wt, "rebase-apply"), &st)) {
+		if (!stat(worktree_git_path(the_repository, wt, "rebase-apply/applying"), &st)) {
 			state->am_in_progress = 1;
-			if (!stat(worktree_git_path(wt, "rebase-apply/patch"), &st) && !st.st_size)
+			if (!stat(worktree_git_path(the_repository, wt, "rebase-apply/patch"), &st) && !st.st_size)
 				state->am_empty_patch = 1;
 		} else {
 			state->rebase_in_progress = 1;
 			state->branch = get_branch(wt, "rebase-apply/head-name");
 			state->onto = get_branch(wt, "rebase-apply/onto");
 		}
-	} else if (!stat(worktree_git_path(wt, "rebase-merge"), &st)) {
-		if (!stat(worktree_git_path(wt, "rebase-merge/interactive"), &st))
+	} else if (!stat(worktree_git_path(the_repository, wt, "rebase-merge"), &st)) {
+		if (!stat(worktree_git_path(the_repository, wt, "rebase-merge/interactive"), &st))
 			state->rebase_interactive_in_progress = 1;
 		else
 			state->rebase_in_progress = 1;
@@ -1743,7 +1744,7 @@ int wt_status_check_bisect(const struct worktree *wt,
 {
 	struct stat st;
 
-	if (!stat(worktree_git_path(wt, "BISECT_LOG"), &st)) {
+	if (!stat(worktree_git_path(the_repository, wt, "BISECT_LOG"), &st)) {
 		state->bisect_in_progress = 1;
 		state->bisecting_from = get_branch(wt, "BISECT_START");
 		return 1;
@@ -2595,7 +2596,7 @@ int has_unstaged_changes(struct repository *r, int ignore_submodules)
 	rev_info.diffopt.flags.quick = 1;
 	diff_setup_done(&rev_info.diffopt);
 	run_diff_files(&rev_info, 0);
-	result = diff_result_code(&rev_info.diffopt);
+	result = diff_result_code(&rev_info);
 	release_revisions(&rev_info);
 	return result;
 }
@@ -2629,7 +2630,7 @@ int has_uncommitted_changes(struct repository *r,
 
 	diff_setup_done(&rev_info.diffopt);
 	run_diff_index(&rev_info, DIFF_INDEX_CACHED);
-	result = diff_result_code(&rev_info.diffopt);
+	result = diff_result_code(&rev_info);
 	release_revisions(&rev_info);
 	return result;
 }