Git development
 help / color / mirror / Atom feed
* [PATCH v11 06/10] environment: migrate apply_default_whitespace and apply_default_ignorewhitespace
From: Tian Yuchen @ 2026-07-13  3:57 UTC (permalink / raw)
  To: git
  Cc: pabloosabaterr, cirnovskyv, szeder.dev, Tian Yuchen,
	Christian Couder, Ayush Chandekar, Olamide Caleb Bello
In-Reply-To: <20260713035738.1606138-1-cat@malon.dev>

The global variables 'apply_default_whitespace' and
'apply_default_ignorewhitespace' are used to store the default
whitespace configuration for 'git apply'. Move these variables
into 'struct repo_config_values' to continue the libification
effort.

Dynamically allocated strings fetched via 'repo_config_get_string()'
are now tracked per-repository and safely freed in
'repo_config_values_clear()'.

As part of this transition, update 'git_apply_config()' to accept a
'struct repository *' argument rather than relying on the
'the_repository' global.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>
Mentored-by: Olamide Caleb Bello <belkid98@gmail.com>
Signed-off-by: Tian Yuchen <cat@malon.dev>
---
 apply.c       | 28 ++++++++++++++++++++--------
 environment.c |  6 ++++--
 environment.h |  4 ++--
 3 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/apply.c b/apply.c
index 249248d4f2..f0cfd76190 100644
--- a/apply.c
+++ b/apply.c
@@ -47,11 +47,17 @@ struct gitdiff_data {
 	int p_value;
 };
 
-static void git_apply_config(void)
+static void git_apply_config(struct repository *repo)
 {
-	repo_config_get_string(the_repository, "apply.whitespace", &apply_default_whitespace);
-	repo_config_get_string(the_repository, "apply.ignorewhitespace", &apply_default_ignorewhitespace);
-	repo_config(the_repository, git_xmerge_config, NULL);
+	struct repo_config_values *cfg = repo_config_values(repo);
+
+	FREE_AND_NULL(cfg->apply_default_whitespace);
+	repo_config_get_string(repo, "apply.whitespace",
+			       &cfg->apply_default_whitespace);
+	FREE_AND_NULL(cfg->apply_default_ignorewhitespace);
+	repo_config_get_string(repo, "apply.ignorewhitespace",
+			       &cfg->apply_default_ignorewhitespace);
+	repo_config(repo, git_xmerge_config, NULL);
 }
 
 static int parse_whitespace_option(struct apply_state *state, const char *option)
@@ -126,10 +132,15 @@ int init_apply_state(struct apply_state *state,
 	strset_init(&state->kept_symlinks);
 	strbuf_init(&state->root, 0);
 
-	git_apply_config();
-	if (apply_default_whitespace && parse_whitespace_option(state, apply_default_whitespace))
+	git_apply_config(repo);
+
+	struct repo_config_values *cfg = repo_config_values(repo);
+
+	if (cfg->apply_default_whitespace &&
+	    parse_whitespace_option(state, cfg->apply_default_whitespace))
 		return -1;
-	if (apply_default_ignorewhitespace && parse_ignorewhitespace_option(state, apply_default_ignorewhitespace))
+	if (cfg->apply_default_ignorewhitespace &&
+	    parse_ignorewhitespace_option(state, cfg->apply_default_ignorewhitespace))
 		return -1;
 	return 0;
 }
@@ -192,7 +203,8 @@ int check_apply_state(struct apply_state *state, int force_apply)
 
 static void set_default_whitespace_mode(struct apply_state *state)
 {
-	if (!state->whitespace_option && !apply_default_whitespace)
+	if (!state->whitespace_option &&
+	    !repo_config_values(state->repo)->apply_default_whitespace)
 		state->ws_error_action = (state->apply ? warn_on_ws_error : nowarn_ws_error);
 }
 
diff --git a/environment.c b/environment.c
index 3857818da3..20500658a2 100644
--- a/environment.c
+++ b/environment.c
@@ -49,8 +49,6 @@ int assume_unchanged;
 int is_bare_repository_cfg = -1; /* unspecified */
 char *git_commit_encoding;
 char *git_log_output_encoding;
-char *apply_default_whitespace;
-char *apply_default_ignorewhitespace;
 int fsync_object_files = -1;
 int use_fsync = -1;
 enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;
@@ -726,6 +724,8 @@ void repo_config_values_init(struct repo_config_values *cfg)
 	cfg->editor_program = NULL;
 	cfg->pager_program = NULL;
 	cfg->askpass_program = NULL;
+	cfg->apply_default_whitespace = NULL;
+	cfg->apply_default_ignorewhitespace = NULL;
 	cfg->apply_sparse_checkout = 0;
 	cfg->branch_track = BRANCH_TRACK_REMOTE;
 	cfg->trust_ctime = 1;
@@ -745,4 +745,6 @@ void repo_config_values_clear(struct repo_config_values *cfg)
 	FREE_AND_NULL(cfg->editor_program);
 	FREE_AND_NULL(cfg->pager_program);
 	FREE_AND_NULL(cfg->askpass_program);
+	FREE_AND_NULL(cfg->apply_default_whitespace);
+	FREE_AND_NULL(cfg->apply_default_ignorewhitespace);
 }
diff --git a/environment.h b/environment.h
index 856dc70cc4..f450242ac0 100644
--- a/environment.h
+++ b/environment.h
@@ -94,6 +94,8 @@ struct repo_config_values {
 	char *editor_program;
 	char *pager_program;
 	char *askpass_program;
+	char *apply_default_whitespace;
+	char *apply_default_ignorewhitespace;
 	int apply_sparse_checkout;
 	int trust_ctime;
 	int check_stat;
@@ -182,8 +184,6 @@ extern int has_symlinks;
 extern int minimum_abbrev, default_abbrev;
 extern int ignore_case;
 extern int assume_unchanged;
-extern char *apply_default_whitespace;
-extern char *apply_default_ignorewhitespace;
 extern unsigned long pack_size_limit_cfg;
 
 extern int protect_hfs;
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH 6/6] SubmittingPatches: clarify the writing style of whats-cooking
From: Junio C Hamano @ 2026-07-13  4:20 UTC (permalink / raw)
  To: Michael Montalbo; +Cc: git
In-Reply-To: <CAC2Qwm+30zeMQKHc3onqhXG90wgrdvba28TadF=N3-dD1Ah8zw@mail.gmail.com>

Michael Montalbo <mmontalbo@gmail.com> writes:

> On Sat, Jul 11, 2026 at 12:27 PM Junio C Hamano <gitster@pobox.com> wrote:
>> +TIP: When proposing a topic summary in your cover letter, write it in...
>
> super nit: It seems like the precedent in this file is to use "NOTE" instead
> of "TIP".

Yeah, and not just locally in this file; "TIP:" is actually
not used anywhere in the Documentation/ directory, whereas
"NOTE:" is frequently used.  I will switch to "NOTE:" as
there is no point in having variety in something like this.

Thanks.

^ permalink raw reply

* Re: [PATCH v3 2/2] reftable: fix quadratic behavior in the presence of tombstones
From: Patrick Steinhardt @ 2026-07-13  5:14 UTC (permalink / raw)
  To: Kristofer Karlsson; +Cc: Kristofer Karlsson via GitGitGadget, git
In-Reply-To: <CAL71e4POhVpQ9FvLmjUc4ex_=T-DuCd7cas1D4uzqzg3RyDw+Q@mail.gmail.com>

On Fri, Jul 10, 2026 at 05:03:28PM +0200, Kristofer Karlsson wrote:
> On Fri, 10 Jul 2026 at 16:32, Patrick Steinhardt <ps@pks.im> wrote:
> >
> > > This also requires adding deletion checks to the log iteration paths,
> > > since suppress_deletions applied to both ref and log iterators.
> >
> > Nit: s/applied/applies/
> 
> Language and using correct tense is always the tricky part --
> will fix if a reroll is needed for other reasons.
> 
> > > +     int suppress_deletions;
> >
> > A comment would've been nice, but I don't think this warrants a reroll.
> 
> Agreed, the field name felt self-documenting to me, but I will
> add a short comment if there is a reroll.
> Something like this?
> "boolean: filters out tombstoned/deleted refs early if true"

I'd drop the "boolean: " prefix, but other than that this looks sensible
to me.

> > > -     new_merged->suppress_deletions = 1;
> > > +     new_merged->suppress_deletions = st->opts.suppress_deletions;
> >
> > Yup, this looks good to me.
> 
> Thanks for the quick review.
> 
> Another thing I have been thinking about: should we consider
> suppress_deletions a temporary stopgap, with the goal of
> eventually removing it?

Maybe? I'll update libgit2 as soon as both ps/reftable-hardening and
kk/reftable-tombstone-quadratic-fix have been merged to "master". Once
done, feel free to create a pull request against libgit2 to deactivate
`suppress_deletions` there, and once that's happened we can also drop
the code in Git itself.

Thanks!

Patrick

^ permalink raw reply

* Re: [PATCH v4 00/11] receive-pack: use ODB transactions to stage object writes
From: Patrick Steinhardt @ 2026-07-13  5:18 UTC (permalink / raw)
  To: Justin Tobler; +Cc: git, gitster
In-Reply-To: <20260710163722.2962278-1-jltobler@gmail.com>

On Fri, Jul 10, 2026 at 11:37:11AM -0500, Justin Tobler wrote:
> Changes since V3:
>   - Removed ugly line break in commit message to prevent eye strain.
>   - `odb_transaction_begin()` now only sets the repository transaction
>     on success.
>   - `odb_transaction_env()` now bubbles up error when failing to create
>     the temporary directory.

Thanks, all the changes here look good to me and I'm happy with the
state of this patch series.

Patrick

^ permalink raw reply

* Re: [PATCH] Makefile: fix up lib directory move
From: Patrick Steinhardt @ 2026-07-13  5:22 UTC (permalink / raw)
  To: Ramsay Jones; +Cc: GIT Mailing-list, Junio C Hamano
In-Reply-To: <0c94331b-7eb1-4116-afa5-811082ad5854@ramsayjones.plus.com>

On Fri, Jul 10, 2026 at 07:38:44PM +0100, Ramsay Jones wrote:
> If you need to re-roll your 'ps/libgit-in-subdir' branch, could you please squash
> this into the relevant patch. (This patch was created directly on top of the 'seen'
> branch, rather than on top of your branch).

Thanks, let me squash this in and send another version.

Patrick

^ permalink raw reply

* What's cooking in git.git (Jul 2026, #05)
From: Junio C Hamano @ 2026-07-13  5:40 UTC (permalink / raw)
  To: git

Here are the topics that have been cooking in my tree.  Commits
prefixed with '+' are in 'next' (being in 'next' is a sign that a
topic is stable enough to be used and is a candidate to be in a
future release).  Commits prefixed with '-' are only in 'seen', and
aren't considered "accepted" at all. They may be annotated with a URL
to a message that raises issues but they are by no means exhaustive.
A topic without enough support may be discarded after a long period
of no activity (of course, it can be resubmitted when new interest
arises).

The first batch of topics have now graduated to the 'master' branch.

Copies of the source code to Git live in many repositories, and the
following is a list of the ones I push into or their mirrors.  Some
repositories have only a subset of branches.

With maint, master, next, seen, todo:

	git://git.kernel.org/pub/scm/git/git.git/
	git://repo.or.cz/alt-git.git/
	https://kernel.googlesource.com/pub/scm/git/git/
	https://github.com/git/git/
	https://gitlab.com/git-scm/git/

With all the integration branches and topics broken out:

	https://github.com/gitster/git/

Even though the preformatted documentation in HTML and man format
are not sources, they are published in these repositories for
convenience (replace "htmldocs" with "manpages" for the manual
pages):

	git://git.kernel.org/pub/scm/git/git-htmldocs.git/
	https://github.com/gitster/git-htmldocs.git/

Release tarballs are available at:

	https://www.kernel.org/pub/software/scm/git/

--------------------------------------------------
[New Topics]

* js/pack-objects-delta-size-t (2026-07-09) 12 commits
 - git-zlib: widen `git_deflate_bound()` to `size_t`
 - t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to `size_t`
 - http-push: widen `start_put()`'s size local from `ssize_t` to `size_t`
 - diff: widen `deflate_it()`'s bound local from int to `size_t`
 - archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t`
 - packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`
 - delta: widen `create_delta()` and `diff_delta()` to `size_t`
 - pack-objects: widen `mem_usage` and `try_delta()`'s out-param to `size_t`
 - pack-objects: widen `free_unpacked()` return to `size_t`
 - pack-objects: widen delta-cache accounting to `size_t`
 - delta: widen `create_delta_index()` parameter to `size_t`
 - diff-delta: widen `struct delta_index`' size fields to `size_t`

 The pack-objects and delta-encoding code paths have been updated to
 use 'size_t' instead of 'unsigned long' for object sizes and offset
 limits, avoiding potential truncation issues on 64-bit Windows.

 Needs review.
 source: <pull.2175.git.1783615780.gitgitgadget@gmail.com>


* cl/b4-cover-change-id (2026-07-10) 1 commit
 - b4: include change-id in cover template

 The in-tree 'b4' cover letter template has been updated to include the
 'change-id' trailer, ensuring that sent tags generated by 'b4' contain
 the required tracking information for subsequent runs.

 Will merge to 'next'.
 source: <20260710-add-change-id-to-b4-template-v1-1-1bd37a25064e@black-desk.cn>


* ps/odb-stream-double-close-fix (2026-07-10) 1 commit
 - object-file: fix closing object stream twice

 The stream-based object signature verification path has been
 corrected to avoid double-closing the stream on read errors.

 Will merge to 'next'.
 source: <20260710-pks-odb-stream-double-close-v1-1-d5fa233a37c7@pks.im>


* pz/fetch-submodule-errors-config (2026-07-11) 3 commits
 - fixup! fetch: add fetch.submoduleErrors to make submodule fetch errors non-fatal
 - fetch: add fetch.submoduleErrors to make submodule fetch errors non-fatal
 - submodule: fix premature failure in recursive submodule fetch

 The 'git fetch' command has been updated to allow configuring how
 submodule fetch errors are handled.  A new configuration variable
 'fetch.submoduleErrors' and a corresponding '--submodule-errors'
 command-line option have been introduced, allowing users to make
 submodule fetch errors non-fatal (warn instead of fail). Additionally,
 a premature failure during recursive submodule fetches has been fixed
 by deferring the error until the OID-based retry phase also fails.

 Needs review.
 source: <20260710122655.3066377-1-paulius.zaleckas@gmail.com>


* gr/add-e-use-apply-api (2026-07-10) 1 commit
 - builtin/add.c: replace run_command() with direct apply_all_patches() call

 The application of the edited patch in 'git add -e' has been
 refactored to use the internal apply API directly, avoiding the need
 to spawn a 'git apply' subprocess.

 Needs review.
 source: <20260711061246.58079-1-gatlavishweshwarreddy26@gmail.com>


* fz/rebase-autosquash-empty (2026-07-11) 1 commit
 . sequencer: honor --empty when a fixup!/squash! empties its target

 A commit that is emptied by melding a 'fixup!' or 'squash!' commit
 during 'git rebase --autosquash' is now handled according to the
 '--empty' option, allowing it to be dropped, kept, or to halt the
 rebase.

 Waiting for response(s) to review comment(s).
 cf. <xmqqh5m494yh.fsf@gitster.g>
 source: <20260711-fz-autosquash-empty-v3-1-d227b63eb511@gmail.com>

--------------------------------------------------
[Stalled]

* kh/doc-trailers (2026-06-10) 10 commits
 - doc: interpret-trailers: document comment line treatment
 - doc: interpret-trailers: commit to “trailer block” term
 - doc: interpret-trailers: join new-trailers again
 - doc: interpret-trailers: add key format example
 - doc: interpret-trailers: explain key format
 - doc: interpret-trailers: explain the format after the intro
 - doc: interpret-trailers: not just for commit messages
 - doc: interpret-trailers: use “metadata” in Name as well
 - doc: interpret-trailers: replace “lines” with “metadata”
 - doc: interpret-trailers: stop fixating on RFC 822

 Documentation for 'git interpret-trailers' has been updated to explain
 the format of trailer keys (alphanumeric characters and hyphens),
 replace outdated terminology, define key terms upfront, and document
 how comment lines in the input are treated.

 Expecting a reroll for too long, stalled.
 cf. <729baf6b-53ea-4e8d-95ab-5935667e66c2@app.fastmail.com>
 source: <V3_CV_doc_int-tr_key_format.8a3@msgid.xyz>


* sn/rebase-update-refs-symrefs (2026-06-03) 1 commit
 - rebase: skip branch symref aliases

 'git rebase --update-refs' has been taught to resolve local branch
 symrefs to their referents before queuing updates, ensuring aliases of
 the current branch are skipped and duplicate updates are avoided to
 prevent failures when branch aliases are present.

 Waiting for response(s) to review comment(s) for too long, stalled.
 cf. <f982c386-e329-4ab0-b695-e540bcb9de3d@gmail.com>
 source: <pull.2126.v2.git.1780482436865.gitgitgadget@gmail.com>


* ap/http-redirect-wwwauth-fix (2026-06-02) 1 commit
 - http: preserve wwwauth_headers across redirects

 When 'cURL' follows a redirect, the 'WWW-Authenticate' headers from
 the redirect target were lost because 'credential_from_url()' cleared
 the credential state.  This has been fixed by preserving the collected
 headers across the redirect update.

 Will discard.
 cf. <xmqqmrw2zavx.fsf@gitster.g>
 source: <20260602161150.1527493-1-aplattner@nvidia.com>


* jt/config-lock-timeout (2026-05-17) 1 commit
 - config: retry acquiring config.lock, configurable via core.configLockTimeout

 Configuration file locking has been updated to retry for a short
 period, avoiding failures when multiple processes attempt to update
 the configuration simultaneously.

 Waiting for response(s) to review comment(s) for too long, stalled.
 cf. <agrIrGwSMFlKTx9x@pks.im>
 source: <20260517132111.1014901-1-joerg@thalheim.io>

--------------------------------------------------
[Cooking]

* dm/submodule-update-i-shorthand (2026-07-07) 1 commit
 - submodule--helper: accept '-i' shorthand for update --init

 The '-i' shorthand for the '--init' option, which was accepted by the
 'git submodule update' command until it was broken in a modernization
 of the option-parsing code, has been restored.

 Needs review.
 source: <20260708-submodule-init-v1-1-719456077262@atmark-techno.com>


* hf/unpack-trees-quadratic-scan (2026-07-08) 1 commit
  (merged to 'next' on 2026-07-12 at 744f1aede4)
 + unpack-trees: avoid quadratic index scan in next_cache_entry()

 The cache-scanning loop in 'next_cache_entry()' has been optimized
 to avoid rescanning already-unpacked index entries, preventing a
 quadratic performance slow-down when diffing the working tree
 against a commit with a pathspec matching early index entries.

 Will merge to 'master'.
 cf. <xmqqpl0xqh3n.fsf@gitster.g>
 source: <pull.2353.v2.git.git.1783546933992.gitgitgadget@gmail.com>


* jc/relnotes-2.55-rust-fix (2026-07-07) 1 commit
  (merged to 'next' on 2026-07-10 at 444d202a75)
 + Rust: fix description in Release Notes to 2.55

 A description in the release notes for Git 2.55.0 has been
 retroactively updated to clarify that Rust support is enabled by
 default, but still optional, and will become mandatory in Git 3.0.

 Will merge to 'master'.
 source: <xmqqpl0y4rpg.fsf@gitster.g>


* jc/submitting-patches-abandoning (2026-07-08) 1 commit
  (merged to 'next' on 2026-07-10 at 41b9b65b23)
 + SubmittingPatches: document how to retract a topic

 The 'SubmittingPatches' document has been updated to explicitly
 describe the expectation for contributors to retract or abandon their
 patch series when they are no longer pursuing it.

 Will merge to 'master'.
 cf. <ak6U07K1dQPlXxIp@nixos>
 source: <xmqqpl0xv25e.fsf@gitster.g>


* jk/git-hash-cleanups (2026-07-07) 8 commits
  (merged to 'next' on 2026-07-09 at 12a4856545)
 + hash: check ctx->active flag in all wrapper functions
 + http: use idempotent git_hash_discard()
 + csum-file: use idempotent git_hash_discard()
 + hash: make git_hash_discard() idempotent
 + hash: document function pointers and wrappers
 + hash: convert remaining direct function calls
 + hash: use git_hash_init() consistently
 + Merge branch 'jk/hash-algo-leak-fixes' into jk/git-hash-cleanups
 (this branch uses jk/hash-algo-leak-fixes.)

 The 'git_hash_*()' wrappers have been updated to be used consistently
 across the codebase instead of direct calls to members of 'struct
 git_hash_algo', and 'git_hash_discard()' has been made idempotent to
 simplify cleanups.

 Will merge to 'master'.
 cf. <ak4E4-jmgYFSI75O@pks.im>
 source: <20260708035235.GA41491@coredump.intra.peff.net>


* mm/lib-httpd-cgi-safe (2026-07-10) 3 commits
 - t/README: document writing concurrency-safe helpers
 - t/lib-httpd: make http-429 first-request check atomic
 - t/lib-httpd: fix apply-one-time-script race under concurrent requests

 CGI helper scripts used by HTTP-related test scripts have been updated
 to use atomic filesystem operations, preventing race conditions when
 Apache handles concurrent requests.

 Needs review.
 source: <pull.2171.v2.git.1783704657.gitgitgadget@gmail.com>


* mm/sideband-ansi-sgr-colon-fix (2026-05-13) 1 commit
  (merged to 'next' on 2026-07-09 at fd2b979b73)
 + sideband: allow ANSI SGR with colon-separated subfields

 The sideband demultiplexer has been updated to recognize ANSI SGR
 escape sequences that use colon-separated subfields (e.g., for
 256-color or true-color codes).

 Will merge to 'master'.
 cf. <8addf7c0-ae39-f1c0-20ab-52114702aaf6@gmx.de>
 source: <20260513070803.163546-1-grawity@nullroute.lt>


* ps/odb-pluggable-housekeeping (2026-07-07) 11 commits
 - odb: make optimizations pluggable
 - builtin/gc: fix signedness issues in ODB-related functionality
 - builtin/gc: refactor ODB optimizations to operate on "files" source
 - builtin/gc: introduce `odb_optimize_required()`
 - builtin/gc: move geometric repacking into `odb_optimize()`
 - builtin/gc: introduce object database optimization options
 - builtin/gc: inline config values specific to the "files" backend
 - builtin/gc: make repack arguments self-contained
 - builtin/gc: extract object database optimizations into separate function
 - builtin/gc: move worktree and rerere tasks before object optimizations
 - odb: run "pre-auto-gc" hook for all maintenance tasks

 Object database housekeeping in 'git gc' and 'git maintenance' has
 been refactored to be pluggable. The files-backend specific logic,
 including incremental and geometric repacking as well as object
 pruning, has been moved out of the command implementation and into the
 files object database source, enabling future alternative object
 database backends to implement their own housekeeping services.

 Expecting a reroll.
 cf. <ak4CHGpIhVIT9sd2@pks.im>
 source: <20260707-b4-pks-odb-optimize-v1-0-aae607667be4@pks.im>


* tc/bundle-uri-empty-fix (2026-07-08) 2 commits
  (merged to 'next' on 2026-07-12 at 9da32fdaf7)
 + bundle-uri: stop sending invalid bundle configuration
 + bundle-uri: drain remaining response on invalid bundle-uri lines

 The client-side parser of server-advertised bundle-URI list has been
 updated to drain the remaining response in order to avoid protocol
 desynchronization when the server sends a misconfigured list. Also,
 the server-side has been taught to omit empty configuration values
 instead of sending invalid key-value lines.

 Will merge to 'master'.
 cf. <xmqqtsq9qj5k.fsf@gitster.g>
 source: <20260708-toon-bundle-uri-no-uri-v2-0-09a03d8db556@iotcl.com>


* gr/t1410-reflog-exit-code (2026-07-08) 1 commit
  (merged to 'next' on 2026-07-10 at d0cf55ea54)
 + t1410-reflog.sh: avoid suppressing git's exit code in pipelines

 The pipelines in 't1410-reflog.sh' have been replaced with the
 'test_stdout_line_count' helper to avoid suppressing the exit code of
 'git' commands, ensuring failures are not hidden from the test suite.

 Will merge to 'master'.
 cf. <xmqqtsq8p18x.fsf@gitster.g>
 source: <20260709051229.40363-1-gatlavishweshwarreddy26@gmail.com>


* js/coverity-fixes-null-safety (2026-07-10) 12 commits
  (merged to 'next' on 2026-07-12 at 8d093f411d)
 + shallow: give write_one_shallow() its own hex buffer
 + shallow: fix NULL dereference
 + bisect: ensure non-NULL `head` before using it
 + pack-bitmap: handle missing bitmap for base MIDX
 + revision: avoid dereferencing NULL in `add_parents_only()`
 + replay: die when --onto does not peel to a commit
 + bisect: handle NULL commit in `bisect_successful()`
 + mailsplit: move NULL check before first use of file handle
 + reftable/stack: guard against NULL list_file in stack_destroy
 + remote: guard `remote_tracking()` against NULL remote
 + diff: handle NULL return from repo_get_commit_tree()
 + diffcore-break: guard against NULLed queue entries in merge loop

 Various code paths have been hardened against potential NULL-pointer
 dereferences and invalid file descriptor accesses flagged by
 Coverity.

 Will merge to 'master'.
 cf. <xmqqa4ryg84e.fsf@gitster.g>
 source: <pull.2174.v2.git.1783683577.gitgitgadget@gmail.com>


* ps/odb-for-each-object-filter (2026-07-10) 9 commits
 - builtin/cat-file: filter objects via object database
 - odb: introduce object filters to `odb_for_each_object()`
 - pack-bitmap: introduce function to open bitmap for a single source
 - pack-bitmap: drop `_1` suffix from functions that open bitmaps
 - pack-bitmap: iterate object sources when opening bitmaps
 - pack-bitmap: allow aborting iteration of bitmapped objects
 - pack-bitmap: mark object filter as `const`
 - odb/source-packed: improve lookup when enumerating objects
 - Merge branch 'ps/odb-drop-whence' into ps/odb-for-each-object-filter
 (this branch uses ps/odb-drop-whence.)

 The object database enumeration interface 'odb_for_each_object()' has
 been taught to accept object filters, allowing the underlying backends
 to optimize the traversal by using reachability bitmaps when
 available.  'git cat-file --batch-all-objects' has been updated to
 use this generic interface, simplifying its code and avoiding direct
 access to ODB backend internals.

 Needs review.
 source: <20260710-pks-odb-for-each-object-filter-v2-0-3710a9cc165a@pks.im>


* ps/refs-wo-the-repository (2026-07-09) 8 commits
 - refs: remove remaining uses of `the_repository`
 - worktree: pass repository to public functions
 - worktree: pass repository to file-local functions
 - worktree: refactor code to use available repositories
 - refs/files: drop `USE_THE_REPOSITORY_VARIABLE`
 - refs/packed: drop `USE_THE_REPOSITORY_VARIABLE`
 - refs/packed: de-globalize handling of "core.packedRefsTimeout"
 - Merge branch 'ps/refs-writing-subcommands' into ps/refs-wo-the-repository
 (this branch uses ps/refs-writing-subcommands.)

 The ref subsystem and the worktree API have been refactored to pass a
 repository pointer down the call chain, allowing them to drop
 references to the global 'the_repository' variable. As part of this,
 the handling of the 'core.packedRefsTimeout' configuration has been
 moved into the per-repository ref store structure.

 Expecting a reroll.
 cf. <alCJpxAQwpTQ4g93@pks.im>
 source: <20260709-pks-refs-wo-the-repository-v1-0-1ad6f27529c9@pks.im>


* kk/commit-graph-topo-levels-fix (2026-07-09) 2 commits
  (merged to 'next' on 2026-07-12 at 295a5f9b34)
 + commit-graph: propagate topo_levels slab to all chain layers
 + commit-graph: add trace2 instrumentation for generation DFS

 The 'topo_levels' slab was propagated only to the topmost layer of a
 split commit-graph chain, causing topological levels for commits in
 base layers to be recomputed during incremental writes. This has been
 corrected.

 Will merge to 'master'.
 cf. <alFu8gZURKhYr1VE@com-79390>
 source: <pull.2170.v2.git.1783609382.gitgitgadget@gmail.com>


* ds/sparse-index-ita-crash (2026-07-06) 1 commit
 - sparse-index: avoid crash on intent-to-add entry outside the cone

 A crash in the sparse-index collapse code when encountering an
 invalidated cache-tree node (due to an intent-to-add path) has been
 fixed by avoiding collapsing such subtrees.

 Needs review.
 source: <pull.2167.git.1783345853272.gitgitgadget@gmail.com>


* ij/subtree-reject-v2-config (2026-07-06) 2 commits
 - git-subtree: Bail out if we find output from Rust rewrite (test)
 - git-subtree: Bail out if we find output from Rust rewrite

 The shell script implementation of 'git subtree' has been updated to
 check for the presence of the configuration file of the new Rust
 implementation, preventing users from accidentally running the old
 script on repositories already managed by the new tool.

 Expecting a reroll.
 cf. <27219.20156.438730.881821@chiark.greenend.org.uk>
 source: <20260706115816.20267-1-ijackson@chiark.greenend.org.uk>


* kk/reftable-tombstone-quadratic-fix (2026-07-10) 2 commits
  (merged to 'next' on 2026-07-12 at 4e60bb0027)
 + reftable: fix quadratic behavior in the presence of tombstones
 + t/perf: add perf test for ref tombstone scenarios

 The performance of ref updates and reads using the 'reftable' backend
 in the presence of many deletion tombstone records has been optimized
 by removing the tombstone suppression flag from the merged iterator
 and instead skipping tombstones at higher-level call sites where
 iteration bounds are known.

 Will merge to 'master'.
 cf. <alECc90WZ9RPqMaA@pks.im>
 source: <pull.2166.v3.git.1783679767.gitgitgadget@gmail.com>


* rs/blame-abbrev-marks (2026-07-06) 1 commit
  (merged to 'next' on 2026-07-08 at e4962bd3d5)
 + blame: reserve mark column only if necessary

 The alignment of commit object name abbreviations in 'git blame'
 output has been optimized to reserve a column for marks (caret,
 question mark, or asterisk) only when such marks are actually shown.

 Will merge to 'master'.
 cf. <xmqqzf0397u1.fsf@gitster.g>
 source: <92991b5e-0667-4315-89d5-1514a5499297@web.de>


* jm/t0213-skip-emulated-ancestry-tests (2026-07-06) 1 commit
 - t0213: skip ancestry tests under user-mode emulation

 The 'TRACE2_ANCESTRY' prerequisite in the 't0213' test script has been
 refined to avoid failures under user-mode emulation, by verifying that
 the ancestry collector reports the expected process names rather than
 the emulator binary name.

 Needs review.
 source: <pull.2168.git.1783359242130.gitgitgadget@gmail.com>


* bc/parse-options-exit-0-on-help (2026-07-07) 4 commits
  (merged to 'next' on 2026-07-10 at 775654e447)
 + parse-options: exit 0 on -h
 + rev-parse: have --parseopt callers exit 0 on --help
 + parse-options: add a separate case for help output on error
 + t1517: skip svn tests if svn is not installed

 Option parsing with 'git rev-parse --parseopt' and in most 'git'
 subcommands has been updated to exit with 0 (instead of 129) when the
 help option ('-h' or '--help') is requested directly by the user,
 aligning with standard Unix convention.

 Will merge to 'master'.
 cf. <20260708035930.GB41684@coredump.intra.peff.net>
 source: <20260708001557.3581080-1-sandals@crustytoothpaste.net>


* mg/meson-hook-list-buildfix (2026-07-01) 1 commit
  (merged to 'next' on 2026-07-08 at 10763a0ebc)
 + meson: restore hook-list.h to builtin_sources

 A racy build failure under Meson has been corrected by ensuring that
 the generated header file 'hook-list.h' is built before compiling
 files in 'builtin_sources' that depend on it.

 Will merge to 'master'.
 cf. <akZGJP1kVtjBFN_e@pks.im>
 source: <20260701193928.358825-1-floppym@gentoo.org>


* zy/apply-abandoned-header-fix (2026-07-01) 1 commit
 - apply: avoid leaking abandoned git-header state

 A candidate 'git diff' header parsed by 'git apply' has been isolated
 in a temporary structure, preventing any partially parsed state from
 polluting the main patch structure and causing assertions to trip if
 the header is ultimately rejected.

 Needs review.
 source: <20260702041759.51572-1-zhihao.yao@njit.edu>


* jk/hash-algo-leak-fixes (2026-07-02) 9 commits
  (merged to 'next' on 2026-07-09 at 7db7b74972)
 + hash: add platform-specific discard functions
 + hash: fix memory leak copying sha256 gcrypt handles
 + http: discard hash in dumb-http http_object_request
 + check_stream_oid(): discard hash on read error
 + patch-id: discard hash when done
 + csum-file: provide a function to release checkpoints
 + csum-file: always finalize or discard hash
 + hash: add discard primitive
 + csum-file: drop discard_hashfile()
 (this branch is used by jk/git-hash-cleanups.)

 Various code paths that initialize a cryptographic hash context but
 bail out or finish without calling 'git_hash_final()' have been taught
 to call 'git_hash_discard()' to release allocated resources, fixing
 memory leaks when Git is built with non-default backends like
 'OpenSSL' or 'libgcrypt'.

 Will merge to 'master'.
 cf. <aktIIKuReMxJmDsi@pks.im>
 source: <20260702075234.GA1548258@coredump.intra.peff.net>


* ml/t9811-replace-test-f (2026-07-11) 2 commits
 - t9811: replace 'test -f' and '! test -f' with 'test_path_*'
 - t9811: break long && chains into multiple lines

 The test script 't/t9811-git-p4-label-import.sh' has been
 modernized to use 'test_path_is_file' and 'test_path_is_missing'
 instead of raw 'test -f' and '! test -f' calls.

 Needs review.
 source: <20260711160447.99708-1-marcelomlage@usp.br>


* ps/t-fixes-for-git-test-long (2026-07-05) 9 commits
  (merged to 'next' on 2026-07-09 at c5b13248c8)
 + gitlab-ci: enable "GIT_TEST_LONG"
 + gitlab-ci: disable RAM disk on macOS jobs
 + t: use `test_bool_env` to parse GIT_TEST_LONG
 + t7900: clean up large EXPENSIVE repository
 + t7508: skip EXPENSIVE test that is broken without SIZE_T_IS_64BIT
 + t5608: reduce maximum disk usage
 + t4141: fix inefficient use of dd(1)
 + t0021: skip EXPENSIVE test that is broken without SIZE_T_IS_64BIT
 + README: add GitLab CI badge to make it more discoverable

 Various test scripts have been updated to clean up large temporary
 files and repositories, reducing peak disk usage during testing.
 Also, expensive tests have been disabled on platforms that lack
 sufficient resources (like 32-bit platforms and Windows CI
 runners), and the long test suite has been enabled in GitLab CI.

 Will merge to 'master'.
 cf. <20260707043026.GB677056@coredump.intra.peff.net>
 source: <20260706-b4-pks-t-fixes-for-GIT-TEST-LONG-v3-0-4f6c5a37fd1f@pks.im>


* ih/precompose-flex-array (2026-07-04) 1 commit
  (merged to 'next' on 2026-07-09 at 737a87f65e)
 + precompose_utf8: use a flex array for d_name

 The UTF-8 precomposition wrapper on macOS has been updated to use a
 flexible array member to represent the name of a directory entry,
 preventing fortified libc checks from failing when the name is
 reallocated to be larger than 'NAME_MAX' bytes.

 Will merge to 'master'.
 cf. <20260703050800.GA29216@tb-raspi4>
 source: <20260704233724.16928-1-ihar.hrachyshka@gmail.com>


* sn/osxkeychain-rust-universal (2026-07-07) 3 commits
  (merged to 'next' on 2026-07-10 at fe82b5d188)
 + contrib: wire up osxkeychain in contrib/Makefile on macOS
 + Makefile: support universal macOS builds via RUST_TARGETS
 + Makefile: add $(RUST_LIB) prerequisite to osxkeychain

 The build system has been updated to support building universal macOS
 binaries when 'Rust' is enabled, by compiling separate static archives
 for each target triple listed in 'RUST_TARGETS' and combining them
 using the macOS 'lipo' tool. The 'git-credential-osxkeychain' helper
 has been updated to link against '$(RUST_LIB)' when 'Rust' is enabled.

 Will merge to 'master'.
 cf. <xmqq4ii9teym.fsf@gitster.g>
 source: <pull.2288.v8.git.git.1783480879.gitgitgadget@gmail.com>


* cl/conditional-config-on-worktree-path (2026-07-09) 2 commits
 - config: add "worktree" and "worktree/i" includeIf conditions
 - config: refactor include_by_gitdir() into include_by_path()

 The '[includeIf "condition"]' conditional inclusion facility for
 configuration files has been taught to use the location of the
 worktree in its condition.

 Needs review.
 source: <20260710-includeif-worktree-v8-0-04686d8a616c@black-desk.cn>


* kk/commit-reach-find-all-fix (2026-06-29) 2 commits
  (merged to 'next' on 2026-07-10 at 0444c74d81)
 + commit-reach: guard !FIND_ALL early exit with generation ordering check
 + t6600: add test for merge-base early exit with clock skew
 (this branch is used by kk/merge-base-exhaustion.)

 The early-exit optimization in 'paint_down_to_common()' has been
 gated on the queue being generation-ordered, fixing a bug where
 'git merge-base' (without '--all') could return incorrect results
 on repositories with v1 commit graphs and clock skew.

 Will merge to 'master'.
 cf. <xmqqjyr5v1gu.fsf@gitster.g>
 source: <pull.2162.git.1782739162.gitgitgadget@gmail.com>


* bl/t7412-use-test-path-helpers (2026-06-29) 1 commit
 - submodule absorbgitdirs tests: use test_* helper functions

 The test script 't7412' that tests 'git submodule absorbgitdirs' has
 been modernized to use 'test_path_is_file', 'test_path_is_dir', and
 'test_path_is_missing' helper functions instead of raw 'test -[fde]'
 commands.

 Waiting for response(s) to review comment(s).
 cf. <akTKHfKPsP3-Rn31@pks.im>
 source: <20260630020220.1559190-1-bblima@usp.br>


* jk/format-patch-leakfix (2026-06-29) 2 commits
  (merged to 'next' on 2026-07-06 at 35aff0d609)
 + format-patch: fix leak of rev_info in prepare_bases()
 + t: move LSan errors from stdout to stderr

 A memory leak in the '--base' handling of 'git format-patch' has been
 plugged, and the leak-reporting of the test suite when running under a
 TAP harness has been improved.

 Will merge to 'master'.
 cf. <akOZy-BygZS8fqPM@pks.im>
 source: <20260630063944.GA3733670@coredump.intra.peff.net>


* ps/setup-split-discovery-and-setup (2026-07-07) 16 commits
  (merged to 'next' on 2026-07-10 at 1691a942ab)
 + setup: mark `set_git_work_tree()` as file-local
 + setup: pass worktree to `init_db()`
 + setup: drop redundant configuration of `startup_info->have_repository`
 + setup: make repository discovery self-contained
 + setup: propagate prefix via repository discovery
 + setup: drop static `cwd` variable
 + setup: move prefix into repository
 + setup: embed repository format in discovery
 + setup: introduce explicit repository discovery
 + setup: split up concerns of `setup_git_env_internal()`
 + setup: unify setup of shallow file
 + setup: mark bogus worktree in `apply_repository_format()`
 + setup: rename `check_repository_format_gently()`
 + Merge branch 'jk/repo-info-path-keys' into ps/setup-split-discovery-and-setup
 + Merge branch 'ps/setup-drop-global-state' into ps/setup-split-discovery-and-setup
 + Merge branch 'ps/refs-onbranch-fixes' into ps/setup-split-discovery-and-setup

 The repository discovery and repository configuration phases, which
 were previously intertwined in 'setup.c', have been split. Repository
 discovery has been updated to populate a 'struct repo_discovery'
 without modifying the repository state, which is then taken by
 repository configuration to initialize the repository, paving the way
 for clean unification of repository configuration.

 Will merge to 'master'.
 cf. <87h5m9om0j.fsf@emacs.iotcl.com>
 source: <20260707-pks-setup-split-discovery-and-setup-v2-0-aab372cd227c@pks.im>


* pw/rebase-drop-notes-with-commit (2026-06-30) 15 commits
 - amend! sequencer: simplify pick_one_commit()
 - amend! sequencer: remove unnecessary "or" in pick_one_commit()
 - fixup! sequencer: never reschedule on failed commit
 - fixup! sequencer: be more careful with external merge
 - sequencer: do not record dropped commits as rewritten
 - sequencer: use an enum to represent result of picking a commit
 - sequencer: return early from pick_one_commit() on success
 - sequencer: simplify pick_one_commit()
 - sequencer: remove unnecessary condition in pick_one_commit()
 - sequencer: simplify handing of fixup with conflicts
 - sequencer: remove unnecessary "or" in pick_one_commit()
 - sequencer: never reschedule on failed commit
 - sequencer: be more careful with external merge
 - sequencer: move definition of is_final_fixup()
 - t3400: restore coverage for note copying with apply backend

 The rebase post-rewrite notes-copying logic has been corrected. When a
 commit is dropped during rebase (e.g., because its changes are already
 upstream), it is no longer recorded as rewritten, preventing its notes
 from being copied to an unrelated commit.

 Expecting a reroll.
 cf. <dce74d17-eefd-40bb-82f3-f6b3179cc2b6@gmail.com>
 source: <cover.1782833268.git.phillip.wood@dunelm.org.uk>


* jk/bloom-leak-fixes (2026-06-30) 3 commits
  (merged to 'next' on 2026-07-08 at 3b9a1cda3f)
 + line-log: drop extra copy of range with bloom filters
 + revision: avoid leaking bloom keyvecs with multiple traversals
 + bloom: make bloom-filter slab initialization idempotent

 Various memory leaks in the Bloom-filter code paths that are exposed
 when running tests with the 'GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=1'
 environment variable have been plugged.

 Will merge to 'master'.
 cf. <b641aed4-ad52-477b-b1d8-9d8e470be46f@gmail.com>
 cf. <xmqqo6gqobrt.fsf@gitster.g>
 source: <20260701063538.GA2579765@coredump.intra.peff.net>


* js/ci-dockerized-pid-limit (2026-07-04) 1 commit
  (merged to 'next' on 2026-07-09 at cd80e673a5)
 + ci(dockerized): raise the PID limit for private repositories

 Dockerized CI jobs running in private GitHub repositories have been
 adjusted to use explicit process and file limits, preventing resource
 exhaustion errors on private runners.

 Will merge to 'master'.
 cf. <xmqqh5medmzh.fsf@gitster.g>
 source: <pull.2164.v2.git.1783155124926.gitgitgadget@gmail.com>


* js/coverity-fixes (2026-07-05) 12 commits
  (merged to 'next' on 2026-07-09 at 1823fe297c)
 + mingw: make `exit_process()` own the process handle on all paths
 + fsmonitor: plug token-data leak on early daemon-startup failures
 + reftable/table: release filter on error path
 + imap-send: avoid leaking the IMAP upload buffer
 + worktree: fix resource leaks when branch creation fails
 + submodule: fix cwd leak in `get_superproject_working_tree()`
 + dir: free allocations on parse-error paths in `read_one_dir()`
 + line-log: avoid redundant copy that leaks in process_ranges
 + run-command: avoid `close(-1)` in `start_command()` error paths
 + download_https_uri_to_file(): do not leak fd upon failure
 + loose: avoid closing invalid fd on error path
 + load_one_loose_object_map(): fix resource leak

 Various resource leaks, invalid file descriptor closures, and process
 handle ownership issues flagged by Coverity have been fixed.

 Will merge to 'master'.
 cf. <xmqqa4s238lg.fsf@gitster.g>
 source: <pull.2163.v2.git.1783239870.gitgitgadget@gmail.com>


* tb/repack-geometric-cruft (2026-06-28) 11 commits
 - SQUASH??? bare grep !???
 - repack: support combining '--geometric' with '--cruft'
 - pack-objects: support '--refs-snapshot' with 'follow-reachable'
 - pack-objects: introduce '--stdin-packs=follow-reachable'
 - pack-objects: extract `stdin_packs_add_all_pack_entries()`
 - repack-geometry: drop unused redundant-pack removal
 - repack: delete geometric packs via existing_packs
 - repack: teach MIDX retention about geometric rollups
 - repack: mark geometric progression of packs as retained
 - repack: extract `locate_existing_pack()` helper
 - repack: unconditionally exclude non-kept packs

 'git repack' has been taught to accept '--geometric' and '--cruft'
 together. When both are given, non-cruft packs are rolled up by the
 geometric repack as usual, while a separate cruft pack is written to
 collect unreachable objects.

 Waiting for response(s) to review comment(s).
 cf. <aj8cOhH6hGVZIFft@nand.local>
 source: <cover.1782500507.git.me@ttaylorr.com>


* jk/reftable-leakfix (2026-06-28) 1 commit
  (merged to 'next' on 2026-07-06 at 55ce81f2d5)
 + reftable: fix unlikely leak on API error

 A memory leak in the 'reftable_writer_new()' initialization function
 has been fixed by delaying the allocation of 'struct reftable_writer'
 until after input options are validated.

 Will merge to 'master'.
 cf. <akIPBJLtPqDjQt-A@pks.im>
 source: <20260628090314.GA661068@coredump.intra.peff.net>


* ad/gpg-strip-cr-before-lf (2026-06-24) 1 commit
  (merged to 'next' on 2026-07-06 at b099249efd)
 + gpg-interface: fix strip_cr_before_lf to only remove CR before LF

 The GPG and SSH signature parsing code has been corrected to strip
 carriage return characters only when they immediately precede line
 feeds, instead of unconditionally stripping all carriage returns.

 Will merge to 'master'.
 source: <20260624093618.17456-1-antonio.destefani08@gmail.com>


* jt/receive-pack-use-odb-transactions (2026-07-10) 11 commits
 - builtin/receive-pack: stage incoming objects via ODB transactions
 - builtin/receive-pack: drop redundant tmpdir env
 - odb/transaction: introduce ODB transaction flags
 - odb/transaction: add transaction env interface
 - odb/transaction: propagate commit errors
 - odb/transaction: propagate begin errors
 - object-file: propagate files transaction errors
 - object-file: drop check for inflight transactions
 - object-file: embed transaction flush logic in commit function
 - object-file: rename files transaction fsync function
 - object-file: rename files transaction prepare function

 'git receive-pack' has been refactored to use ODB transaction
 interfaces instead of directly managing 'tmp_objdir' for staging
 incoming objects, bringing it closer to being ODB backend agnostic.

 Needs review.
 source: <20260710163722.2962278-1-jltobler@gmail.com>


* ps/odb-drop-whence (2026-07-02) 7 commits
  (merged to 'next' on 2026-07-08 at f43ee51cc3)
 + odb: document object info fields
 + odb: drop `whence` field from object info
 + treewide: convert users of `whence` to the new source field
 + odb: add `source` field to struct object_info_source
 + odb: make backend-specific fields optional
 + packfile: thread odb_source_packed through packed_object_info()
 + Merge branch 'ps/odb-source-packed' into ps/odb-drop-whence
 (this branch is used by ps/odb-for-each-object-filter.)

 The 'whence' field in 'struct object_info' has been removed. The
 backend-specific object information retrieval has been refactored into
 an opt-in 'struct object_info_source' structure.

 Will merge to 'master'.
 cf. <xmqqv7b0rmt6.fsf@gitster.g>
 source: <20260702-b4-pks-odb-drop-whence-v2-0-b0af7468ad95@pks.im>


* ps/reftable-hardening (2026-07-03) 12 commits
  (merged to 'next' on 2026-07-10 at b8f4dd0ab9)
 + reftable/table: fix OOB read on truncated table
 + reftable/table: fix NULL pointer access when seeking to bogus offsets
 + reftable/block: fix OOB read with bogus restart offset
 + reftable/block: fix use of uninitialized memory when binsearch fails
 + reftable/block: fix OOB read with bogus restart count
 + reftable/block: fix OOB read with bogus block size
 + reftable/block: fix OOB write with bogus inflated log size
 + t/unit-tests: introduce test helper to write reftable blocks
 + reftable/record: don't abort when decoding invalid ref value type
 + reftable/basics: fix OOB read on binary search of empty range
 + oss-fuzz: add fuzzer for parsing reftables
 + meson: support building fuzzers with libFuzzer

 The reftable code has been hardened against corrupted tables by
 fixing out-of-bounds writes, out-of-bounds reads, and abort calls
 during parsing.

 Will merge to 'master'.
 cf. <877bn5obz9.fsf@emacs.iotcl.com>
 source: <20260703-pks-reftable-hardening-v3-0-b87c555b9920@pks.im>


* hn/branch-push-slip-advice (2026-06-27) 2 commits
  (merged to 'next' on 2026-07-06 at acdff65ac5)
 + push: suggest <remote> <branch> for a slash slip
 + branch: suggest <remote>/<branch> on upstream slip

 When 'git push origin/main' or 'git branch origin main' is run, the
 command is now recognized as a potential typo, and advice has been
 added to offer a typo fix.

 Will merge to 'master'.
 cf. <xmqqfr272lq7.fsf@gitster.g>
 source: <pull.2331.v3.git.git.1782583345.gitgitgadget@gmail.com>


* jc/history-message-prep-fix (2026-06-29) 1 commit
  (merged to 'next' on 2026-07-06 at 00534a21ce)
 + history: streamline message preparation and plug file stream leak

 A write file stream resource leak has been fixed as part of a code
 cleanup.

 Will merge to 'master'.
 cf. <akO1mhi2u2PntLbt@pks.im>
 source: <xmqqmrwdxrat.fsf@gitster.g>


* ty/migrate-excludes-file (2026-07-12) 9 commits
 - environment: move object_creation_mode into repo_config_values
 - environment: move autorebase into repo_config_values
 - environment: move push_default into repo_config_values
 - environment: migrate apply_default_whitespace and apply_default_ignorewhitespace
 - environment: move askpass_program into repo_config_values
 - environment: move pager_program into repo_config_values
 - environment: move editor_program into repo_config_values
 - environment: move excludes_file into repo_config_values
 - repository: introduce repo_config_values_clear()

 The 'excludes_file' and various other global configuration variables
 (including 'editor_program', 'pager_program', 'askpass_program', and
 'push_default') have been migrated into the per-repository structure.

 Expecting a reroll.
 cf. <2a39cee9-1082-48aa-b42e-e12c34fa0e29@malon.dev>
 source: <20260712111734.1073514-1-cat@malon.dev>


* dk/meson-enable-use-nsec-build (2026-06-20) 1 commit
 - meson: wire up USE_NSEC build knob

 The 'USE_NSEC' build knob, which enables support for sub-second file
 timestamp resolution, has been wired up to the Meson build system.

 Will discard.
 cf. <xmqqa4rx9mb5.fsf@gitster.g>
 source: <c4c5ade901ff95b0f95939ea818870e4f3d59da1.1781971201.git.ben.knoble+github@gmail.com>


* ps/libgit-in-subdir (2026-07-10) 4 commits
 - fixup! Move libgit.a sources into separate "lib/" directory
 - Move libgit.a sources into separate "lib/" directory
 - t/helper: prepare "test-example-tap.c" for introduction of "lib/"
 - Merge branch 'ps/odb-source-packed' into ps/libgit-in-subdir

 The source files for 'libgit.a' have been moved into a new 'lib/'
 directory to clean up the top-level directory and clearly separate
 library code.

 Waiting for response(s) to review comment(s).
 cf. <0c94331b-7eb1-4116-afa5-811082ad5854@ramsayjones.plus.com>
 source: <20260701-pks-libgit-in-subdir-v3-0-5e4860056094@pks.im>


* ps/odb-generalize-prepare (2026-06-22) 3 commits
  (merged to 'next' on 2026-07-06 at 6132517517)
 + odb: introduce `odb_prepare()`
 + odb/source: generalize `reprepare()` callback
 + Merge branch 'ps/odb-source-packed' into ps/odb-generalize-prepare

 The 'reprepare()' callback for object database sources has been
 generalized into a 'prepare()' callback with an optional flush cache
 flag, and a new 'odb_prepare()' wrapper has been introduced to allow
 pre-opening object database sources.

 Will merge to 'master'.
 cf. <87ik704f1j.fsf@emacs.iotcl.com>
 source: <20260622-b4-pks-odb-generalize-prepare-v1-0-d2a5c5d13144@pks.im>


* ty/migrate-ignorecase (2026-06-19) 2 commits
  (merged to 'next' on 2026-07-12 at 39e9fdb93f)
 + config: use repo_ignore_case() to access core.ignorecase
 + environment: move ignore_case into repo_config_values

 The global configuration variable 'ignore_case' (representing the
 'core.ignorecase' configuration) has been migrated into 'struct
 repo_config_values' to tie it to a specific repository instance.

 Will merge to 'master'.
 cf. <xmqqechaga7p.fsf@gitster.g>
 source: <20260619155152.642760-1-cat@malon.dev>


* mm/line-log-limited-ops (2026-06-27) 7 commits
 - diffcore-pickaxe: scope -G to the -L tracked range
 - diff: support --check with -L line ranges
 - line-log: support diff stat formats with -L
 - diff: extract a line-range diff helper for reuse
 - diff: emit -L hunk headers via xdiff's formatter
 - diff: simplify the line-range filter by classifying removals immediately
 - diff: rename and group the line-range filter for clarity

 The 'git log -L<range>:<path>' command has been taught to limit
 various 'diff' operations, such as '--stat', '--check', and '-G', to
 the specified range and path.

 Needs review.
 source: <pull.2152.v2.git.1782581342.gitgitgadget@gmail.com>


* hn/history-squash (2026-07-10) 5 commits
 - history: re-edit a squash with every message
 - sequencer: share the squash message marker helpers and flags
 - history: add squash subcommand to fold a range
 - history: give commit_tree_ext a message template
 - history: extract helper for a commit's parent tree

 The experimental 'git history' command has been taught a new 'squash'
 subcommand to fold a range of commits into a single commit, with any
 descendants replayed on top.

 Needs review.
 source: <pull.2337.v8.git.git.1783674396.gitgitgadget@gmail.com>


* ps/refs-writing-subcommands (2026-07-06) 5 commits
  (merged to 'next' on 2026-07-08 at f001147283)
 + builtin/refs: add "rename" subcommand
 + builtin/refs: add "create" subcommand
 + builtin/refs: add "update" subcommand
 + builtin/refs: add "delete" subcommand
 + builtin/refs: drop `the_repository`
 (this branch is used by ps/refs-wo-the-repository.)

 The 'git refs' toolbox has been extended with new 'create', 'delete',
 'update', and 'rename' subcommands to create, delete, update, and
 rename references, respectively.

 Will merge to 'master'.
 source: <20260706-pks-refs-writing-subcommands-v4-0-d51f6ce7f830@pks.im>


* wy/doc-myfirstcontribution-trim-quotes (2026-06-11) 1 commit
  (merged to 'next' on 2026-07-12 at adeaa999b6)
 + MyFirstContribution: mention trimming quoted text in replies

 The contributor guide has been updated to advise new contributors to
 trim irrelevant quoted text when replying to review comments, matching
 the existing advice given to reviewers.

 Will merge to 'master'.
 cf. <xmqqcxxwljue.fsf@gitster.g>
 source: <080402ff0ac8127b654dccea59a1bf643df62a5c.1781186476.git.wy@wyuan.org>


* tb/midx-incremental-custom-base (2026-06-12) 3 commits
 - midx-write: include packs above custom incremental base
 - midx: pass custom '--base' through incremental writes
 - t5334: expose shared `nth_line()` helper

 The 'git multi-pack-index write --incremental' command has been
 corrected to properly honor the '--base' option. Previously, the
 custom base was ignored by the normal write path; packs from layers
 above the selected base were incorrectly skipped by the pack exclusion
 logic, and reachability closure for bitmaps was broken.

 Needs review.
 source: <cover.1781294771.git.me@ttaylorr.com>


* mm/test-grep-lint (2026-07-05) 6 commits
  (merged to 'next' on 2026-07-10 at 1916c07bf5)
 + t: add greplint to detect bare grep assertions
 + t: convert grep assertions to test_grep
 + t: fix Lexer line count for $() inside double-quoted strings
 + t: extract chainlint's parser into shared module
 + t: fix grep assertions missing file arguments
 + t/README: document test_grep helper

 The test suite has been updated to use the 'test_grep' helper instead
 of bare 'grep' for test assertions, allowing file contents to be
 printed on failure for easier debugging. A new 'greplint' linter has
 been introduced to detect and prevent new bare 'grep' assertions from
 being added to the test suite.

 Will merge to 'master'.
 cf. <xmqqtsqedxmt.fsf@gitster.g>
 source: <pull.2135.v4.git.1783314119.gitgitgadget@gmail.com>


* kk/prio-queue-get-put-fusion (2026-06-08) 2 commits
  (merged to 'next' on 2026-07-06 at aa748c4564)
 + prio-queue: fold lazy_queue into prio_queue for automatic get+put fusion
 + prio-queue: rename .nr to .nr_ and add accessor helpers
 (this branch is used by kk/prio-queue-cascade-sift.)

 The lazy priority queue optimization pattern (deferring actual removal
 in 'prio_queue_get()' to allow get+put fusion) has been folded
 directly into 'prio_queue' itself, speeding up commit traversal
 workflows and simplifying callers.

 Will merge to 'master'.
 cf. <xmqqh5mjrbgq.fsf@gitster.g>
 source: <pull.2140.v4.git.1780945851.gitgitgadget@gmail.com>


* td/ref-filter-memoize-contains (2026-06-12) 3 commits
 - commit-reach: die on contains walk errors
 - ref-filter: memoize --contains with generations
 - commit-reach: reject cycles in contains walk

 'git branch --contains' and 'git for-each-ref --contains' have been
 optimized to use the memoized commit traversal previously used only by
 'git tag --contains', significantly speeding up connectivity checks
 across many candidate refs with shared history.

 Needs review.
 cf. <xmqqqzlpulkp.fsf@gitster.g>
 source: <20260612-ref-filter-memoized-contains-v4-0-5ed39fd001dd@gmail.com>


* tc/replay-linearize (2026-07-07) 3 commits
  (merged to 'next' on 2026-07-09 at 371c2e9c3b)
 + replay: offer an option to linearize the commit topology
 + replay: resolve the replay base outside pick_regular_commit()
 + replay: add helper to put entry into replayed_commits

 The 'git replay' command has been taught the '--linearize' option to
 drop merge commits and linearize the replayed history, mimicking 'git
 rebase --no-rebase-merges'.

 Will merge to 'master'.
 cf. <xmqq5x2qz42z.fsf@gitster.g>
 source: <20260707-toon-git-replay-drop-merges-v7-0-808ab9b4afa6@iotcl.com>


* ps/cat-file-remote-object-info (2026-07-10) 13 commits
 - cat-file: make remote-object-info allow-list dynamic
 - cat-file: validate remote atoms with an allow-list
 - cat-file: add remote-object-info to batch-command
 - transport: add client support for object-info
 - serve: advertise object-info feature
 - fetch-pack: move fetch initialization
 - connect: make write_fetch_command_and_capabilities() more generic
 - fetch-pack: move write_fetch_command_and_capabilities() to connect.c
 - fetch-pack: drop static advertise_sid variable
 - fetch-pack: fix hash_algo variable type
 - t1006: split test utility functions into new 'lib-cat-file.sh'
 - cat-file: declare loop counter inside for()
 - transport-helper: fix memory leak of helper on disconnect

 The 'remote-object-info' command has been added to 'git cat-file
 --batch-command', allowing clients to request object metadata
 (currently size) from a remote server via protocol v2 without
 downloading the entire object. Format placeholders are dynamically
 filtered on the client based on server-advertised capabilities,
 returning empty strings for inapplicable or unsupported fields.

 Will merge to 'next'?
 cf. <CA+J6zkSo3ZqLe7HLEXRAs+hOq2FuOVokMQWbABcW95wihNtCgA@mail.gmail.com>
 source: <20260710-ps-eric-work-rebase-v16-0-66e07b58a8fe@gmail.com>


* mm/diff-process-hunks (2026-06-14) 6 commits
 - blame: consult diff process for no-hunk detection
 - diff: bypass diff process with --no-ext-diff and in format-patch
 - diff: add long-running diff process via diff.<driver>.process
 - sub-process: separate process lifecycle from hashmap management
 - userdiff: add diff.<driver>.process config
 - xdiff: support external hunks via xpparam_t

 A new 'diff.<driver>.process' configuration has been introduced to
 allow a long-running external process to act as a hunk provider,
 allowing external tools to control which lines Git considers changed
 while leaving all output formatting (word diff, color, blame, etc.) to
 Git's standard pipeline.

 Expecting a reroll for too long, stalled.
 cf. <CAC2Qwm+P=fZOtpfMPeMiSXf3Afk6OLYpTP8Br78_PRA8WNL1Wg@mail.gmail.com>
 source: <pull.2120.v4.git.1781463564.gitgitgadget@gmail.com>


* ty/migrate-trust-executable-bit (2026-06-19) 3 commits
 - environment: move trust_executable_bit into repo_config_values
 - read-cache: move 'ce_mode_from_stat()' to 'read-cache.c'
 - read-cache: remove redundant extern declarations

 The 'trust_executable_bit' (coming from 'core.filemode'
 configuration) has been migrated into 'repo_config_values' to tie it
 to a specific repository instance.

 Needs review.
 cf. <xmqqcxx9ukvw.fsf@gitster.g>
 source: <20260619162105.648495-1-cat@malon.dev>


* ps/history-drop (2026-07-01) 11 commits
  (merged to 'next' on 2026-07-08 at 6fb84708a4)
 + builtin/history: implement "drop" subcommand
 + builtin/history: split handling of ref updates into two phases
 + replay: expose `replay_result_queue_update()`
 + reset: stop assuming that the caller passes in a clean index
 + reset: allow the caller to specify the current HEAD object
 + reset: introduce ability to skip updating HEAD
 + reset: introduce dry-run mode
 + reset: modernize flags passed to `reset_working_tree()`
 + reset: rename `reset_head()`
 + reset: drop `USE_THE_REPOSITORY_VARIABLE`
 + read-cache: split out function to drop unmerged entries to stage 0

 The experimental 'git history' command has been taught a new 'drop'
 subcommand to remove a commit, with its descendants replayed onto its
 parent.

 Will merge to 'master'.
 cf. <xmqq1pdmprbk.fsf@gitster.g>
 cf. <CAP8UFD3OAktVQsLuqBNFH2uhEO31PH8ZF3ZT1ZW8k++XE8YLPw@mail.gmail.com>
 source: <20260701-b4-pks-history-drop-v8-0-19b5cdf1facd@pks.im>


* za/completion-hide-dotfiles (2026-06-20) 2 commits
 - completion: hide dotfiles by default for path completion
 - completion: hide dotfiles for selected path completion

 Path completion for commands like 'git rm' and 'git mv' has been
 updated to hide dotfiles by default unless the user explicitly starts
 the path with a dot, matching standard shell-completion behavior.

 Waiting for response(s) to review comment(s), stalled.
 cf. <xmqqik71t3nr.fsf@gitster.g>
 source: <pull.2311.v3.git.git.1781978156.gitgitgadget@gmail.com>


* ec/commit-fixup-options (2026-05-26) 2 commits
 - commit: allow -c/-C for all kinds of --fixup
 - commit: allow -m/-F for all kinds of --fixup

 Support for '-m', '-F', '-c', or '-C' options to supply a commit log
 message from outside the editor has been added for all 'git commit
 --fixup' variations.

 Needs review.
 source: <cover.1779792311.git.erik@cervined.in>


* kh/doc-replay-config (2026-06-05) 4 commits
 - doc: replay: move “default” to the right-hand side
 - doc: replay: use a nested description list
 - doc: replay: improve config description
 - doc: link to config for git-replay(1)

 Documentation for 'git replay' has been updated to refer to its
 configuration variables.

 Waiting for response(s) to review comment(s).
 cf. <87cxwxofgv.fsf@emacs.iotcl.com>
 source: <V3_CV_doc_replay_config.780@msgid.xyz>


* hn/branch-delete-merged (2026-06-24) 7 commits
 - branch: add --dry-run for --delete-merged
 - branch: add branch.<name>.deleteMerged opt-out
 - branch: add --delete-merged <branch>
 - branch: prepare delete_branches for a bulk caller
 - branch: let delete_branches skip unmerged branches on bulk refusal
 - branch: convert delete_branches() to a flags argument
 - branch: add --forked filter for --list mode

 The 'git branch' command has been taught the '--delete-merged' option
 to remove local branches that are already merged to their tracked
 remote-tracking branches.

 Expecting a reroll.
 cf. <CAHwyqnWspUTSnqmkMyXtWuAnENDSzrRLhhUR=Ljtt1xer3tphA@mail.gmail.com>
 source: <pull.2285.v18.git.git.1782338106.gitgitgadget@gmail.com>


* hn/checkout-track-fetch (2026-06-24) 2 commits
 - checkout: extend --track with a "fetch" mode to refresh start-point
 - branch: expose helpers for finding the remote owning a tracking ref

 The 'git checkout --track=...' command has been taught to optionally
 fetch the branch from the remote the new branch will work with.

 Waiting for response(s) to review comment(s).
 cf. <xmqq5x37h6fj.fsf@gitster.g>
 source: <pull.2281.v15.git.git.1782338098.gitgitgadget@gmail.com>


* ps/shift-root-in-graph (2026-07-11) 4 commits
 - graph: indent visual root in graph
 - graph: add a 2 commit buffer for lookahead
 - revision: add next_commit_to_show()
 - lib-log-graph: move check_graph function

 'git log --graph' has been modified to visually distinguish parentless
 'root' commits (and commits that become roots due to history
 simplification) by indenting them, preventing them from appearing
 falsely related to unrelated commits rendered immediately above them.

 Needs review.
 source: <20260711-ps-pre-commit-indent-v9-0-eab6676e82f7@gmail.com>


* kk/merge-base-exhaustion (2026-07-11) 11 commits
 - commit-reach: remove commit-date ordering fallback
 - commit-reach: move min_generation check into paint_queue_get()
 - commit-reach: terminate merge-base walk when one paint side is exhausted
 - commit-reach: introduce struct paint_state with per-side counters
 - t6600: add clock-skew topologies and step counts for edge cases
 - commit-reach: add trace2 instrumentation to paint_down_to_common()
 - t6099, t6600: add side-exhaustion regression tests
 - t6600: add test cases for side-exhaustion edge cases
 - test-lib-functions: improve diagnostic output for trace2 data assertions
 - Documentation/technical: add paint-down-to-common doc
 - Merge branch 'kk/commit-reach-find-all-fix' into kk/merge-base-exhaustion
 (this branch uses kk/commit-reach-find-all-fix.)

 The merge-base computation has been optimized by stopping the walk
 early when one side's exclusive commits in the queue are exhausted,
 yielding significant speedups for queries with one-sided histories.

 Needs review.
 source: <pull.2149.v6.git.1783776466.gitgitgadget@gmail.com>

--------------------------------------------------
[Discarded]

* kk/prio-queue-cascade-sift (2026-07-08) 3 commits
 . prio-queue: use cascade for unfused gets
 . prio-queue: extract sift_up() from prio_queue_put()
 . Merge branch 'kk/prio-queue-get-put-fusion' into kk/prio-queue-cascade-sift
 (this branch uses kk/prio-queue-get-put-fusion.)

 'prio_queue_get()' has been optimized by using a cascade-down approach
 (promoting the smaller child at each level and sifting up the last
 element from the leaf vacancy), whereby the number of comparisons per
 extract-min operation is halved in the common case.

 Retracted.
 cf. <CAL71e4PRVYfUWc-c+6XHTwtADqrbub9ykbo+rPyramDhJw=Rfg@mail.gmail.com>
 source: <pull.2132.v3.git.1783532989.gitgitgadget@gmail.com>

^ permalink raw reply

* [PATCH RFC v4 0/2] Move libgit.a sources into separate "lib/" directory
From: Patrick Steinhardt @ 2026-07-13  5:50 UTC (permalink / raw)
  To: git
  Cc: brian m. carlson, Junio C Hamano, Elijah Newren, Derrick Stolee,
	SZEDER Gábor, Johannes Schindelin, Ramsay Jones,
	Phillip Wood
In-Reply-To: <20260416-pks-libgit-in-subdir-v1-0-03afc731df55@pks.im>

Hi,

this small patch series follows up on a discussion we had two years ago
during the Git Contributor's Summit in Berlin.

I'm fully aware that this will likely result in some discussion, which
is why I have labelled this as RFC. I'd be fine with a result of "let's
not do it" if we cannot agree on this step, but I think that the current
layout hurts discoverability quite a bit. Not only for newcomers, but
I'm also struggling with it quite frequently.

I also intentionally decided to send this close to the upcoming release
so that the series can be merged early in the next release cycle if we
were to agree on it.

I've tested this patch series with both GitLab [1] and GitHub [2].

Changes in v4:
  - Squash in Ramsay's patch posted in
    https://patch.msgid.link/94e744f1-12b1-4ba4-8f9b-266c1642b5ff@ramsayjones.plus.com.
  - Link to v3: https://patch.msgid.link/20260701-pks-libgit-in-subdir-v3-0-5e4860056094@pks.im

Changes in v3:
  - Explicitly point out the downsides of doing this mass-rename. Please
    let me know in case any arguments are missing there.
  - Apply Dscho's fixup patch.
  - Link to v2: https://patch.msgid.link/20260622-pks-libgit-in-subdir-v2-0-cb946c51ee7b@pks.im

Changes in v2:
  - Feedback on v1 was generally positive, and we're close to the next
    release again. So I've decided to rebase the patch series and send
    v2 out before the quiet pre-release phase kicks off. The series is
    thus built on top of 8d96f09e92 (Merge branch
    'js/objects-larger-than-4gb-on-windows', 2026-06-19) with
    ps/odb-source-packed at 1bba3c035d (odb/source-packed: drop pointer
    to "files" parent source, 2026-06-17) merged into it.
  - Fix a couple of instances I missed to update in Meson.
  - Link to v1: https://patch.msgid.link/20260416-pks-libgit-in-subdir-v1-0-03afc731df55@pks.im

Thanks!

Patrick

[1]: https://gitlab.com/gitlab-org/git/-/merge_requests/544
[2]: https://github.com/git/git/pull/2271

---
Patrick Steinhardt (2):
      t/helper: prepare "test-example-tap.c" for introduction of "lib/"
      Move libgit.a sources into separate "lib/" directory

 .github/workflows/main.yml                         |   9 +-
 .gitmodules                                        |   2 +-
 Documentation/Makefile                             |   4 +-
 Makefile                                           | 766 ++++++++++-----------
 config.mak.uname                                   |  52 +-
 contrib/buildsystems/CMakeLists.txt                |  95 +--
 git.rc.in                                          |   2 +-
 abspath.c => lib/abspath.c                         |   0
 abspath.h => lib/abspath.h                         |   0
 add-interactive.c => lib/add-interactive.c         |   0
 add-interactive.h => lib/add-interactive.h         |   0
 add-patch.c => lib/add-patch.c                     |   0
 add-patch.h => lib/add-patch.h                     |   0
 advice.c => lib/advice.c                           |   0
 advice.h => lib/advice.h                           |   0
 alias.c => lib/alias.c                             |   0
 alias.h => lib/alias.h                             |   0
 alloc.c => lib/alloc.c                             |   0
 alloc.h => lib/alloc.h                             |   0
 apply.c => lib/apply.c                             |   0
 apply.h => lib/apply.h                             |   0
 archive-tar.c => lib/archive-tar.c                 |   0
 archive-zip.c => lib/archive-zip.c                 |   0
 archive.c => lib/archive.c                         |   0
 archive.h => lib/archive.h                         |   0
 attr.c => lib/attr.c                               |   0
 attr.h => lib/attr.h                               |   0
 banned.h => lib/banned.h                           |   0
 base85.c => lib/base85.c                           |   0
 base85.h => lib/base85.h                           |   0
 bisect.c => lib/bisect.c                           |   0
 bisect.h => lib/bisect.h                           |   0
 blame.c => lib/blame.c                             |   0
 blame.h => lib/blame.h                             |   0
 blob.c => lib/blob.c                               |   0
 blob.h => lib/blob.h                               |   0
 {block-sha1 => lib/block-sha1}/sha1.c              |   0
 {block-sha1 => lib/block-sha1}/sha1.h              |   0
 bloom.c => lib/bloom.c                             |   0
 bloom.h => lib/bloom.h                             |   0
 branch.c => lib/branch.c                           |   0
 branch.h => lib/branch.h                           |   0
 builtin.h => lib/builtin.h                         |   0
 bundle-uri.c => lib/bundle-uri.c                   |   0
 bundle-uri.h => lib/bundle-uri.h                   |   0
 bundle.c => lib/bundle.c                           |   0
 bundle.h => lib/bundle.h                           |   0
 cache-tree.c => lib/cache-tree.c                   |   0
 cache-tree.h => lib/cache-tree.h                   |   0
 cbtree.c => lib/cbtree.c                           |   0
 cbtree.h => lib/cbtree.h                           |   0
 chdir-notify.c => lib/chdir-notify.c               |   0
 chdir-notify.h => lib/chdir-notify.h               |   0
 checkout.c => lib/checkout.c                       |   0
 checkout.h => lib/checkout.h                       |   0
 chunk-format.c => lib/chunk-format.c               |   0
 chunk-format.h => lib/chunk-format.h               |   0
 color.c => lib/color.c                             |   0
 color.h => lib/color.h                             |   0
 column.c => lib/column.c                           |   0
 column.h => lib/column.h                           |   0
 combine-diff.c => lib/combine-diff.c               |   0
 commit-graph.c => lib/commit-graph.c               |   0
 commit-graph.h => lib/commit-graph.h               |   0
 commit-reach.c => lib/commit-reach.c               |   0
 commit-reach.h => lib/commit-reach.h               |   0
 commit-slab-decl.h => lib/commit-slab-decl.h       |   0
 commit-slab-impl.h => lib/commit-slab-impl.h       |   0
 commit-slab.h => lib/commit-slab.h                 |   0
 commit.c => lib/commit.c                           |   0
 commit.h => lib/commit.h                           |   0
 common-exit.c => lib/common-exit.c                 |   0
 common-init.c => lib/common-init.c                 |   0
 common-init.h => lib/common-init.h                 |   0
 {compat => lib/compat}/.gitattributes              |   0
 {compat => lib/compat}/access.c                    |   0
 {compat => lib/compat}/apple-common-crypto.h       |   0
 {compat => lib/compat}/basename.c                  |   0
 {compat => lib/compat}/bswap.h                     |   0
 {compat => lib/compat}/compiler.h                  |   0
 {compat => lib/compat}/darwin/procinfo.c           |   0
 {compat => lib/compat}/disk.h                      |   0
 {compat => lib/compat}/fileno.c                    |   0
 {compat => lib/compat}/fopen.c                     |   0
 {compat => lib/compat}/fsmonitor/fsm-darwin-gcc.h  |   0
 .../compat}/fsmonitor/fsm-health-darwin.c          |   0
 .../compat}/fsmonitor/fsm-health-linux.c           |   0
 .../compat}/fsmonitor/fsm-health-win32.c           |   0
 {compat => lib/compat}/fsmonitor/fsm-health.h      |   0
 {compat => lib/compat}/fsmonitor/fsm-ipc-unix.c    |   0
 {compat => lib/compat}/fsmonitor/fsm-ipc-win32.c   |   0
 .../compat}/fsmonitor/fsm-listen-darwin.c          |   0
 .../compat}/fsmonitor/fsm-listen-linux.c           |   0
 .../compat}/fsmonitor/fsm-listen-win32.c           |   0
 {compat => lib/compat}/fsmonitor/fsm-listen.h      |   0
 .../compat}/fsmonitor/fsm-path-utils-darwin.c      |   0
 .../compat}/fsmonitor/fsm-path-utils-linux.c       |   0
 .../compat}/fsmonitor/fsm-path-utils-win32.c       |   0
 .../compat}/fsmonitor/fsm-settings-unix.c          |   0
 .../compat}/fsmonitor/fsm-settings-win32.c         |   0
 {compat => lib/compat}/hstrerror.c                 |   0
 {compat => lib/compat}/inet_ntop.c                 |   0
 {compat => lib/compat}/inet_pton.c                 |   0
 {compat => lib/compat}/linux/procinfo.c            |   0
 {compat => lib/compat}/memmem.c                    |   0
 {compat => lib/compat}/mingw-posix.h               |   0
 {compat => lib/compat}/mingw.c                     |   0
 {compat => lib/compat}/mingw.h                     |   0
 {compat => lib/compat}/mkdir.c                     |   0
 {compat => lib/compat}/mmap.c                      |   0
 {compat => lib/compat}/msvc-posix.h                |   0
 {compat => lib/compat}/msvc.c                      |   0
 {compat => lib/compat}/msvc.h                      |   0
 {compat => lib/compat}/nonblock.c                  |   0
 {compat => lib/compat}/nonblock.h                  |   0
 {compat => lib/compat}/obstack.c                   |   0
 {compat => lib/compat}/obstack.h                   |   0
 {compat => lib/compat}/open.c                      |   0
 {compat => lib/compat}/poll/poll.c                 |   0
 {compat => lib/compat}/poll/poll.h                 |   0
 {compat => lib/compat}/posix.h                     |   0
 {compat => lib/compat}/pread.c                     |   0
 {compat => lib/compat}/precompose_utf8.c           |   0
 {compat => lib/compat}/precompose_utf8.h           |   0
 {compat => lib/compat}/qsort_s.c                   |   0
 {compat => lib/compat}/regcomp_enhanced.c          |   0
 {compat => lib/compat}/regex/regcomp.c             |   0
 {compat => lib/compat}/regex/regex.c               |   0
 {compat => lib/compat}/regex/regex.h               |   0
 {compat => lib/compat}/regex/regex_internal.c      |   0
 {compat => lib/compat}/regex/regex_internal.h      |   0
 {compat => lib/compat}/regex/regexec.c             |   0
 {compat => lib/compat}/setenv.c                    |   0
 {compat => lib/compat}/sha1-chunked.c              |   0
 {compat => lib/compat}/sha1-chunked.h              |   0
 {compat => lib/compat}/simple-ipc/ipc-shared.c     |   0
 .../compat}/simple-ipc/ipc-unix-socket.c           |   0
 {compat => lib/compat}/simple-ipc/ipc-win32.c      |   0
 {compat => lib/compat}/snprintf.c                  |   0
 {compat => lib/compat}/stat.c                      |   0
 {compat => lib/compat}/strcasestr.c                |   0
 {compat => lib/compat}/strdup.c                    |   0
 {compat => lib/compat}/strlcpy.c                   |   0
 {compat => lib/compat}/strtoimax.c                 |   0
 {compat => lib/compat}/strtoumax.c                 |   0
 {compat => lib/compat}/stub/procinfo.c             |   0
 {compat => lib/compat}/terminal.c                  |   0
 {compat => lib/compat}/terminal.h                  |   0
 {compat => lib/compat}/unsetenv.c                  |   0
 {compat => lib/compat}/vcbuild/.gitignore          |   0
 {compat => lib/compat}/vcbuild/README              |  10 +-
 {compat => lib/compat}/vcbuild/find_vs_env.bat     |   2 +-
 {compat => lib/compat}/vcbuild/include/sys/param.h |   0
 {compat => lib/compat}/vcbuild/include/sys/time.h  |   0
 {compat => lib/compat}/vcbuild/include/sys/utime.h |   0
 {compat => lib/compat}/vcbuild/include/unistd.h    |   0
 {compat => lib/compat}/vcbuild/include/utime.h     |   0
 {compat => lib/compat}/vcbuild/scripts/clink.pl    |   0
 {compat => lib/compat}/vcbuild/scripts/lib.pl      |   0
 {compat => lib/compat}/vcbuild/vcpkg_copy_dlls.bat |   0
 {compat => lib/compat}/vcbuild/vcpkg_install.bat   |   4 +-
 {compat => lib/compat}/win32.h                     |   0
 {compat => lib/compat}/win32/alloca.h              |   0
 {compat => lib/compat}/win32/dirent.c              |   0
 {compat => lib/compat}/win32/dirent.h              |   0
 {compat => lib/compat}/win32/exit-process.h        |   0
 {compat => lib/compat}/win32/flush.c               |   0
 {compat => lib/compat}/win32/git.manifest          |   0
 {compat => lib/compat}/win32/headless.c            |   0
 {compat => lib/compat}/win32/lazyload.h            |   0
 {compat => lib/compat}/win32/path-utils.c          |   0
 {compat => lib/compat}/win32/path-utils.h          |   0
 {compat => lib/compat}/win32/pthread.c             |   0
 {compat => lib/compat}/win32/pthread.h             |   0
 {compat => lib/compat}/win32/syslog.c              |   0
 {compat => lib/compat}/win32/syslog.h              |   0
 .../compat}/win32/trace2_win32_process_info.c      |   0
 {compat => lib/compat}/win32mmap.c                 |   0
 {compat => lib/compat}/winansi.c                   |   0
 {compat => lib/compat}/zlib-compat.h               |   0
 .../compiler-tricks}/not-constant.c                |   0
 config.c => lib/config.c                           |   0
 config.h => lib/config.h                           |   0
 connect.c => lib/connect.c                         |   0
 connect.h => lib/connect.h                         |   0
 connected.c => lib/connected.c                     |   0
 connected.h => lib/connected.h                     |   0
 convert.c => lib/convert.c                         |   0
 convert.h => lib/convert.h                         |   0
 copy.c => lib/copy.c                               |   0
 copy.h => lib/copy.h                               |   0
 credential.c => lib/credential.c                   |   0
 credential.h => lib/credential.h                   |   0
 csum-file.c => lib/csum-file.c                     |   0
 csum-file.h => lib/csum-file.h                     |   0
 ctype.c => lib/ctype.c                             |   0
 date.c => lib/date.c                               |   0
 date.h => lib/date.h                               |   0
 decorate.c => lib/decorate.c                       |   0
 decorate.h => lib/decorate.h                       |   0
 delta-islands.c => lib/delta-islands.c             |   0
 delta-islands.h => lib/delta-islands.h             |   0
 delta.h => lib/delta.h                             |   0
 diagnose.c => lib/diagnose.c                       |   0
 diagnose.h => lib/diagnose.h                       |   0
 diff-delta.c => lib/diff-delta.c                   |   0
 diff-lib.c => lib/diff-lib.c                       |   0
 diff-merges.c => lib/diff-merges.c                 |   0
 diff-merges.h => lib/diff-merges.h                 |   0
 diff-no-index.c => lib/diff-no-index.c             |   0
 diff.c => lib/diff.c                               |   0
 diff.h => lib/diff.h                               |   0
 diffcore-break.c => lib/diffcore-break.c           |   0
 diffcore-delta.c => lib/diffcore-delta.c           |   0
 diffcore-order.c => lib/diffcore-order.c           |   0
 diffcore-pickaxe.c => lib/diffcore-pickaxe.c       |   0
 diffcore-rename.c => lib/diffcore-rename.c         |   0
 diffcore-rotate.c => lib/diffcore-rotate.c         |   0
 diffcore.h => lib/diffcore.h                       |   0
 dir-iterator.c => lib/dir-iterator.c               |   0
 dir-iterator.h => lib/dir-iterator.h               |   0
 dir.c => lib/dir.c                                 |   0
 dir.h => lib/dir.h                                 |   0
 editor.c => lib/editor.c                           |   0
 editor.h => lib/editor.h                           |   0
 entry.c => lib/entry.c                             |   0
 entry.h => lib/entry.h                             |   0
 environment.c => lib/environment.c                 |   0
 environment.h => lib/environment.h                 |   0
 {ewah => lib/ewah}/bitmap.c                        |   0
 {ewah => lib/ewah}/ewah_bitmap.c                   |   0
 {ewah => lib/ewah}/ewah_io.c                       |   0
 {ewah => lib/ewah}/ewah_rlw.c                      |   0
 {ewah => lib/ewah}/ewok.h                          |   0
 {ewah => lib/ewah}/ewok_rlw.h                      |   0
 exec-cmd.c => lib/exec-cmd.c                       |   0
 exec-cmd.h => lib/exec-cmd.h                       |   0
 fetch-negotiator.c => lib/fetch-negotiator.c       |   0
 fetch-negotiator.h => lib/fetch-negotiator.h       |   0
 fetch-pack.c => lib/fetch-pack.c                   |   0
 fetch-pack.h => lib/fetch-pack.h                   |   0
 fmt-merge-msg.c => lib/fmt-merge-msg.c             |   0
 fmt-merge-msg.h => lib/fmt-merge-msg.h             |   0
 for-each-ref.h => lib/for-each-ref.h               |   0
 fsck.c => lib/fsck.c                               |   0
 fsck.h => lib/fsck.h                               |   0
 fsmonitor--daemon.h => lib/fsmonitor--daemon.h     |   0
 fsmonitor-ipc.c => lib/fsmonitor-ipc.c             |   0
 fsmonitor-ipc.h => lib/fsmonitor-ipc.h             |   0
 fsmonitor-ll.h => lib/fsmonitor-ll.h               |   0
 .../fsmonitor-path-utils.h                         |   0
 fsmonitor-settings.c => lib/fsmonitor-settings.c   |   0
 fsmonitor-settings.h => lib/fsmonitor-settings.h   |   0
 fsmonitor.c => lib/fsmonitor.c                     |   0
 fsmonitor.h => lib/fsmonitor.h                     |   0
 gettext.c => lib/gettext.c                         |   0
 gettext.h => lib/gettext.h                         |   0
 git-compat-util.h => lib/git-compat-util.h         |   0
 git-curl-compat.h => lib/git-curl-compat.h         |   0
 git-zlib.c => lib/git-zlib.c                       |   0
 git-zlib.h => lib/git-zlib.h                       |   0
 gpg-interface.c => lib/gpg-interface.c             |   0
 gpg-interface.h => lib/gpg-interface.h             |   0
 graph.c => lib/graph.c                             |   0
 graph.h => lib/graph.h                             |   0
 grep.c => lib/grep.c                               |   0
 grep.h => lib/grep.h                               |   0
 hash-lookup.c => lib/hash-lookup.c                 |   0
 hash-lookup.h => lib/hash-lookup.h                 |   0
 hash.c => lib/hash.c                               |   0
 hash.h => lib/hash.h                               |   0
 hashmap.c => lib/hashmap.c                         |   0
 hashmap.h => lib/hashmap.h                         |   0
 help.c => lib/help.c                               |   0
 help.h => lib/help.h                               |   0
 hex-ll.c => lib/hex-ll.c                           |   0
 hex-ll.h => lib/hex-ll.h                           |   0
 hex.c => lib/hex.c                                 |   0
 hex.h => lib/hex.h                                 |   0
 hook.c => lib/hook.c                               |   0
 hook.h => lib/hook.h                               |   0
 http-walker.c => lib/http-walker.c                 |   0
 http.c => lib/http.c                               |   0
 http.h => lib/http.h                               |   0
 ident.c => lib/ident.c                             |   0
 ident.h => lib/ident.h                             |   0
 iterator.h => lib/iterator.h                       |   0
 json-writer.c => lib/json-writer.c                 |   0
 json-writer.h => lib/json-writer.h                 |   0
 khash.h => lib/khash.h                             |   0
 kwset.c => lib/kwset.c                             |   0
 kwset.h => lib/kwset.h                             |   0
 levenshtein.c => lib/levenshtein.c                 |   0
 levenshtein.h => lib/levenshtein.h                 |   0
 line-log.c => lib/line-log.c                       |   0
 line-log.h => lib/line-log.h                       |   0
 line-range.c => lib/line-range.c                   |   0
 line-range.h => lib/line-range.h                   |   0
 linear-assignment.c => lib/linear-assignment.c     |   0
 linear-assignment.h => lib/linear-assignment.h     |   0
 .../list-objects-filter-options.c                  |   0
 .../list-objects-filter-options.h                  |   0
 list-objects-filter.c => lib/list-objects-filter.c |   0
 list-objects-filter.h => lib/list-objects-filter.h |   0
 list-objects.c => lib/list-objects.c               |   0
 list-objects.h => lib/list-objects.h               |   0
 list.h => lib/list.h                               |   0
 lockfile.c => lib/lockfile.c                       |   0
 lockfile.h => lib/lockfile.h                       |   0
 log-tree.c => lib/log-tree.c                       |   0
 log-tree.h => lib/log-tree.h                       |   0
 loose.c => lib/loose.c                             |   0
 loose.h => lib/loose.h                             |   0
 ls-refs.c => lib/ls-refs.c                         |   0
 ls-refs.h => lib/ls-refs.h                         |   0
 mailinfo.c => lib/mailinfo.c                       |   0
 mailinfo.h => lib/mailinfo.h                       |   0
 mailmap.c => lib/mailmap.c                         |   0
 mailmap.h => lib/mailmap.h                         |   0
 match-trees.c => lib/match-trees.c                 |   0
 match-trees.h => lib/match-trees.h                 |   0
 mem-pool.c => lib/mem-pool.c                       |   0
 mem-pool.h => lib/mem-pool.h                       |   0
 merge-blobs.c => lib/merge-blobs.c                 |   0
 merge-blobs.h => lib/merge-blobs.h                 |   0
 merge-ll.c => lib/merge-ll.c                       |   0
 merge-ll.h => lib/merge-ll.h                       |   0
 merge-ort-wrappers.c => lib/merge-ort-wrappers.c   |   0
 merge-ort-wrappers.h => lib/merge-ort-wrappers.h   |   0
 merge-ort.c => lib/merge-ort.c                     |   0
 merge-ort.h => lib/merge-ort.h                     |   0
 merge.c => lib/merge.c                             |   0
 merge.h => lib/merge.h                             |   0
 mergesort.h => lib/mergesort.h                     |   0
 midx-write.c => lib/midx-write.c                   |   0
 midx.c => lib/midx.c                               |   0
 midx.h => lib/midx.h                               |   0
 name-hash.c => lib/name-hash.c                     |   0
 name-hash.h => lib/name-hash.h                     |   0
 {negotiator => lib/negotiator}/default.c           |   0
 {negotiator => lib/negotiator}/default.h           |   0
 {negotiator => lib/negotiator}/noop.c              |   0
 {negotiator => lib/negotiator}/noop.h              |   0
 {negotiator => lib/negotiator}/skipping.c          |   0
 {negotiator => lib/negotiator}/skipping.h          |   0
 notes-cache.c => lib/notes-cache.c                 |   0
 notes-cache.h => lib/notes-cache.h                 |   0
 notes-merge.c => lib/notes-merge.c                 |   0
 notes-merge.h => lib/notes-merge.h                 |   0
 notes-utils.c => lib/notes-utils.c                 |   0
 notes-utils.h => lib/notes-utils.h                 |   0
 notes.c => lib/notes.c                             |   0
 notes.h => lib/notes.h                             |   0
 object-file-convert.c => lib/object-file-convert.c |   0
 object-file-convert.h => lib/object-file-convert.h |   0
 object-file.c => lib/object-file.c                 |   0
 object-file.h => lib/object-file.h                 |   0
 object-name.c => lib/object-name.c                 |   0
 object-name.h => lib/object-name.h                 |   0
 object.c => lib/object.c                           |   0
 object.h => lib/object.h                           |   0
 odb.c => lib/odb.c                                 |   0
 odb.h => lib/odb.h                                 |   0
 {odb => lib/odb}/source-files.c                    |   0
 {odb => lib/odb}/source-files.h                    |   0
 {odb => lib/odb}/source-inmemory.c                 |   0
 {odb => lib/odb}/source-inmemory.h                 |   0
 {odb => lib/odb}/source-loose.c                    |   0
 {odb => lib/odb}/source-loose.h                    |   0
 {odb => lib/odb}/source-packed.c                   |   0
 {odb => lib/odb}/source-packed.h                   |   0
 {odb => lib/odb}/source.c                          |   0
 {odb => lib/odb}/source.h                          |   0
 {odb => lib/odb}/streaming.c                       |   0
 {odb => lib/odb}/streaming.h                       |   0
 {odb => lib/odb}/transaction.c                     |   0
 {odb => lib/odb}/transaction.h                     |   0
 oid-array.c => lib/oid-array.c                     |   0
 oid-array.h => lib/oid-array.h                     |   0
 oidmap.c => lib/oidmap.c                           |   0
 oidmap.h => lib/oidmap.h                           |   0
 oidset.c => lib/oidset.c                           |   0
 oidset.h => lib/oidset.h                           |   0
 oidtree.c => lib/oidtree.c                         |   0
 oidtree.h => lib/oidtree.h                         |   0
 pack-bitmap-write.c => lib/pack-bitmap-write.c     |   0
 pack-bitmap.c => lib/pack-bitmap.c                 |   0
 pack-bitmap.h => lib/pack-bitmap.h                 |   0
 pack-check.c => lib/pack-check.c                   |   0
 pack-mtimes.c => lib/pack-mtimes.c                 |   0
 pack-mtimes.h => lib/pack-mtimes.h                 |   0
 pack-objects.c => lib/pack-objects.c               |   0
 pack-objects.h => lib/pack-objects.h               |   0
 pack-refs.c => lib/pack-refs.c                     |   0
 pack-refs.h => lib/pack-refs.h                     |   0
 pack-revindex.c => lib/pack-revindex.c             |   0
 pack-revindex.h => lib/pack-revindex.h             |   0
 pack-write.c => lib/pack-write.c                   |   0
 pack.h => lib/pack.h                               |   0
 packfile-list.c => lib/packfile-list.c             |   0
 packfile-list.h => lib/packfile-list.h             |   0
 packfile.c => lib/packfile.c                       |   0
 packfile.h => lib/packfile.h                       |   0
 pager.c => lib/pager.c                             |   0
 pager.h => lib/pager.h                             |   0
 parallel-checkout.c => lib/parallel-checkout.c     |   0
 parallel-checkout.h => lib/parallel-checkout.h     |   0
 parse-options-cb.c => lib/parse-options-cb.c       |   0
 parse-options.c => lib/parse-options.c             |   0
 parse-options.h => lib/parse-options.h             |   0
 parse.c => lib/parse.c                             |   0
 parse.h => lib/parse.h                             |   0
 patch-delta.c => lib/patch-delta.c                 |   0
 patch-ids.c => lib/patch-ids.c                     |   0
 patch-ids.h => lib/patch-ids.h                     |   0
 path-walk.c => lib/path-walk.c                     |   0
 path-walk.h => lib/path-walk.h                     |   0
 path.c => lib/path.c                               |   0
 path.h => lib/path.h                               |   0
 pathspec.c => lib/pathspec.c                       |   0
 pathspec.h => lib/pathspec.h                       |   0
 pkt-line.c => lib/pkt-line.c                       |   0
 pkt-line.h => lib/pkt-line.h                       |   0
 preload-index.c => lib/preload-index.c             |   0
 preload-index.h => lib/preload-index.h             |   0
 pretty.c => lib/pretty.c                           |   0
 pretty.h => lib/pretty.h                           |   0
 prio-queue.c => lib/prio-queue.c                   |   0
 prio-queue.h => lib/prio-queue.h                   |   0
 progress.c => lib/progress.c                       |   0
 progress.h => lib/progress.h                       |   0
 promisor-remote.c => lib/promisor-remote.c         |   0
 promisor-remote.h => lib/promisor-remote.h         |   0
 prompt.c => lib/prompt.c                           |   0
 prompt.h => lib/prompt.h                           |   0
 protocol-caps.c => lib/protocol-caps.c             |   0
 protocol-caps.h => lib/protocol-caps.h             |   0
 protocol.c => lib/protocol.c                       |   0
 protocol.h => lib/protocol.h                       |   0
 prune-packed.c => lib/prune-packed.c               |   0
 prune-packed.h => lib/prune-packed.h               |   0
 pseudo-merge.c => lib/pseudo-merge.c               |   0
 pseudo-merge.h => lib/pseudo-merge.h               |   0
 quote.c => lib/quote.c                             |   0
 quote.h => lib/quote.h                             |   0
 range-diff.c => lib/range-diff.c                   |   0
 range-diff.h => lib/range-diff.h                   |   0
 reachable.c => lib/reachable.c                     |   0
 reachable.h => lib/reachable.h                     |   0
 read-cache-ll.h => lib/read-cache-ll.h             |   0
 read-cache.c => lib/read-cache.c                   |   0
 read-cache.h => lib/read-cache.h                   |   0
 rebase-interactive.c => lib/rebase-interactive.c   |   0
 rebase-interactive.h => lib/rebase-interactive.h   |   0
 rebase.c => lib/rebase.c                           |   0
 rebase.h => lib/rebase.h                           |   0
 ref-filter.c => lib/ref-filter.c                   |   0
 ref-filter.h => lib/ref-filter.h                   |   0
 reflog-walk.c => lib/reflog-walk.c                 |   0
 reflog-walk.h => lib/reflog-walk.h                 |   0
 reflog.c => lib/reflog.c                           |   0
 reflog.h => lib/reflog.h                           |   0
 refs.c => lib/refs.c                               |   0
 refs.h => lib/refs.h                               |   0
 {refs => lib/refs}/debug.c                         |   0
 {refs => lib/refs}/files-backend.c                 |   0
 {refs => lib/refs}/iterator.c                      |   0
 {refs => lib/refs}/packed-backend.c                |   0
 {refs => lib/refs}/packed-backend.h                |   0
 {refs => lib/refs}/ref-cache.c                     |   0
 {refs => lib/refs}/ref-cache.h                     |   0
 {refs => lib/refs}/refs-internal.h                 |   0
 {refs => lib/refs}/reftable-backend.c              |   0
 refspec.c => lib/refspec.c                         |   0
 refspec.h => lib/refspec.h                         |   0
 {reftable => lib/reftable}/LICENSE                 |   0
 {reftable => lib/reftable}/basics.c                |   0
 {reftable => lib/reftable}/basics.h                |   0
 {reftable => lib/reftable}/block.c                 |   0
 {reftable => lib/reftable}/block.h                 |   0
 {reftable => lib/reftable}/blocksource.c           |   0
 {reftable => lib/reftable}/blocksource.h           |   0
 {reftable => lib/reftable}/constants.h             |   0
 {reftable => lib/reftable}/error.c                 |   0
 {reftable => lib/reftable}/fsck.c                  |   0
 {reftable => lib/reftable}/iter.c                  |   0
 {reftable => lib/reftable}/iter.h                  |   0
 {reftable => lib/reftable}/merged.c                |   0
 {reftable => lib/reftable}/merged.h                |   0
 {reftable => lib/reftable}/pq.c                    |   0
 {reftable => lib/reftable}/pq.h                    |   0
 {reftable => lib/reftable}/record.c                |   0
 {reftable => lib/reftable}/record.h                |   0
 {reftable => lib/reftable}/reftable-basics.h       |   0
 {reftable => lib/reftable}/reftable-block.h        |   0
 {reftable => lib/reftable}/reftable-blocksource.h  |   0
 {reftable => lib/reftable}/reftable-constants.h    |   0
 {reftable => lib/reftable}/reftable-error.h        |   0
 {reftable => lib/reftable}/reftable-fsck.h         |   0
 {reftable => lib/reftable}/reftable-iterator.h     |   0
 {reftable => lib/reftable}/reftable-merged.h       |   0
 {reftable => lib/reftable}/reftable-record.h       |   0
 {reftable => lib/reftable}/reftable-stack.h        |   0
 {reftable => lib/reftable}/reftable-system.h       |   0
 {reftable => lib/reftable}/reftable-table.h        |   0
 {reftable => lib/reftable}/reftable-writer.h       |   0
 {reftable => lib/reftable}/stack.c                 |   0
 {reftable => lib/reftable}/stack.h                 |   0
 {reftable => lib/reftable}/system.c                |   0
 {reftable => lib/reftable}/system.h                |   0
 {reftable => lib/reftable}/table.c                 |   0
 {reftable => lib/reftable}/table.h                 |   0
 {reftable => lib/reftable}/tree.c                  |   0
 {reftable => lib/reftable}/tree.h                  |   0
 {reftable => lib/reftable}/writer.c                |   0
 {reftable => lib/reftable}/writer.h                |   0
 remote.c => lib/remote.c                           |   0
 remote.h => lib/remote.h                           |   0
 repack-cruft.c => lib/repack-cruft.c               |   0
 repack-filtered.c => lib/repack-filtered.c         |   0
 repack-geometry.c => lib/repack-geometry.c         |   0
 repack-midx.c => lib/repack-midx.c                 |   0
 repack-promisor.c => lib/repack-promisor.c         |   0
 repack.c => lib/repack.c                           |   0
 repack.h => lib/repack.h                           |   0
 replace-object.c => lib/replace-object.c           |   0
 replace-object.h => lib/replace-object.h           |   0
 replay.c => lib/replay.c                           |   0
 replay.h => lib/replay.h                           |   0
 repo-settings.c => lib/repo-settings.c             |   0
 repo-settings.h => lib/repo-settings.h             |   0
 repository.c => lib/repository.c                   |   0
 repository.h => lib/repository.h                   |   0
 rerere.c => lib/rerere.c                           |   0
 rerere.h => lib/rerere.h                           |   0
 reset.c => lib/reset.c                             |   0
 reset.h => lib/reset.h                             |   0
 resolve-undo.c => lib/resolve-undo.c               |   0
 resolve-undo.h => lib/resolve-undo.h               |   0
 revision.c => lib/revision.c                       |   0
 revision.h => lib/revision.h                       |   0
 run-command.c => lib/run-command.c                 |   0
 run-command.h => lib/run-command.h                 |   0
 sane-ctype.h => lib/sane-ctype.h                   |   0
 send-pack.c => lib/send-pack.c                     |   0
 send-pack.h => lib/send-pack.h                     |   0
 sequencer.c => lib/sequencer.c                     |   0
 sequencer.h => lib/sequencer.h                     |   0
 serve.c => lib/serve.c                             |   0
 serve.h => lib/serve.h                             |   0
 server-info.c => lib/server-info.c                 |   0
 server-info.h => lib/server-info.h                 |   0
 setup.c => lib/setup.c                             |   0
 setup.h => lib/setup.h                             |   0
 {sha1 => lib/sha1}/openssl.h                       |   0
 .../sha1collisiondetection                         |   0
 {sha1dc => lib/sha1dc}/.gitattributes              |   0
 {sha1dc => lib/sha1dc}/LICENSE.txt                 |   0
 {sha1dc => lib/sha1dc}/sha1.c                      |   0
 {sha1dc => lib/sha1dc}/sha1.h                      |   0
 {sha1dc => lib/sha1dc}/ubc_check.c                 |   0
 {sha1dc => lib/sha1dc}/ubc_check.h                 |   0
 sha1dc_git.c => lib/sha1dc_git.c                   |   0
 sha1dc_git.h => lib/sha1dc_git.h                   |   0
 {sha256 => lib/sha256}/block/sha256.c              |   0
 {sha256 => lib/sha256}/block/sha256.h              |   0
 {sha256 => lib/sha256}/gcrypt.h                    |   0
 {sha256 => lib/sha256}/nettle.h                    |   0
 {sha256 => lib/sha256}/openssl.h                   |   0
 shallow.c => lib/shallow.c                         |   0
 shallow.h => lib/shallow.h                         |   0
 shortlog.h => lib/shortlog.h                       |   0
 sideband.c => lib/sideband.c                       |   0
 sideband.h => lib/sideband.h                       |   0
 sigchain.c => lib/sigchain.c                       |   0
 sigchain.h => lib/sigchain.h                       |   0
 simple-ipc.h => lib/simple-ipc.h                   |   0
 sparse-index.c => lib/sparse-index.c               |   0
 sparse-index.h => lib/sparse-index.h               |   0
 split-index.c => lib/split-index.c                 |   0
 split-index.h => lib/split-index.h                 |   0
 stable-qsort.c => lib/stable-qsort.c               |   0
 statinfo.c => lib/statinfo.c                       |   0
 statinfo.h => lib/statinfo.h                       |   0
 strbuf.c => lib/strbuf.c                           |   0
 strbuf.h => lib/strbuf.h                           |   0
 string-list.c => lib/string-list.c                 |   0
 string-list.h => lib/string-list.h                 |   0
 strmap.c => lib/strmap.c                           |   0
 strmap.h => lib/strmap.h                           |   0
 strvec.c => lib/strvec.c                           |   0
 strvec.h => lib/strvec.h                           |   0
 sub-process.c => lib/sub-process.c                 |   0
 sub-process.h => lib/sub-process.h                 |   0
 submodule-config.c => lib/submodule-config.c       |   0
 submodule-config.h => lib/submodule-config.h       |   0
 submodule.c => lib/submodule.c                     |   0
 submodule.h => lib/submodule.h                     |   0
 symlinks.c => lib/symlinks.c                       |   0
 symlinks.h => lib/symlinks.h                       |   0
 tag.c => lib/tag.c                                 |   0
 tag.h => lib/tag.h                                 |   0
 tar.h => lib/tar.h                                 |   0
 tempfile.c => lib/tempfile.c                       |   0
 tempfile.h => lib/tempfile.h                       |   0
 thread-utils.c => lib/thread-utils.c               |   0
 thread-utils.h => lib/thread-utils.h               |   0
 tmp-objdir.c => lib/tmp-objdir.c                   |   0
 tmp-objdir.h => lib/tmp-objdir.h                   |   0
 trace.c => lib/trace.c                             |   0
 trace.h => lib/trace.h                             |   0
 trace2.c => lib/trace2.c                           |   0
 trace2.h => lib/trace2.h                           |   0
 {trace2 => lib/trace2}/tr2_cfg.c                   |   0
 {trace2 => lib/trace2}/tr2_cfg.h                   |   0
 {trace2 => lib/trace2}/tr2_cmd_name.c              |   0
 {trace2 => lib/trace2}/tr2_cmd_name.h              |   0
 {trace2 => lib/trace2}/tr2_ctr.c                   |   0
 {trace2 => lib/trace2}/tr2_ctr.h                   |   0
 {trace2 => lib/trace2}/tr2_dst.c                   |   0
 {trace2 => lib/trace2}/tr2_dst.h                   |   0
 {trace2 => lib/trace2}/tr2_sid.c                   |   0
 {trace2 => lib/trace2}/tr2_sid.h                   |   0
 {trace2 => lib/trace2}/tr2_sysenv.c                |   0
 {trace2 => lib/trace2}/tr2_sysenv.h                |   0
 {trace2 => lib/trace2}/tr2_tbuf.c                  |   0
 {trace2 => lib/trace2}/tr2_tbuf.h                  |   0
 {trace2 => lib/trace2}/tr2_tgt.h                   |   0
 {trace2 => lib/trace2}/tr2_tgt_event.c             |   0
 {trace2 => lib/trace2}/tr2_tgt_normal.c            |   0
 {trace2 => lib/trace2}/tr2_tgt_perf.c              |   0
 {trace2 => lib/trace2}/tr2_tls.c                   |   0
 {trace2 => lib/trace2}/tr2_tls.h                   |   0
 {trace2 => lib/trace2}/tr2_tmr.c                   |   0
 {trace2 => lib/trace2}/tr2_tmr.h                   |   0
 trailer.c => lib/trailer.c                         |   0
 trailer.h => lib/trailer.h                         |   0
 transport-helper.c => lib/transport-helper.c       |   0
 transport-internal.h => lib/transport-internal.h   |   0
 transport.c => lib/transport.c                     |   0
 transport.h => lib/transport.h                     |   0
 tree-diff.c => lib/tree-diff.c                     |   0
 tree-walk.c => lib/tree-walk.c                     |   0
 tree-walk.h => lib/tree-walk.h                     |   0
 tree.c => lib/tree.c                               |   0
 tree.h => lib/tree.h                               |   0
 unicode-width.h => lib/unicode-width.h             |   0
 unix-socket.c => lib/unix-socket.c                 |   0
 unix-socket.h => lib/unix-socket.h                 |   0
 unix-stream-server.c => lib/unix-stream-server.c   |   0
 unix-stream-server.h => lib/unix-stream-server.h   |   0
 unpack-trees.c => lib/unpack-trees.c               |   0
 unpack-trees.h => lib/unpack-trees.h               |   0
 upload-pack.c => lib/upload-pack.c                 |   0
 upload-pack.h => lib/upload-pack.h                 |   0
 url.c => lib/url.c                                 |   0
 url.h => lib/url.h                                 |   0
 urlmatch.c => lib/urlmatch.c                       |   0
 urlmatch.h => lib/urlmatch.h                       |   0
 usage.c => lib/usage.c                             |   0
 userdiff.c => lib/userdiff.c                       |   0
 userdiff.h => lib/userdiff.h                       |   0
 utf8.c => lib/utf8.c                               |   0
 utf8.h => lib/utf8.h                               |   0
 varint.c => lib/varint.c                           |   0
 varint.h => lib/varint.h                           |   0
 version-def.h.in => lib/version-def.h.in           |   0
 version.c => lib/version.c                         |   0
 version.h => lib/version.h                         |   0
 versioncmp.c => lib/versioncmp.c                   |   0
 versioncmp.h => lib/versioncmp.h                   |   0
 walker.c => lib/walker.c                           |   0
 walker.h => lib/walker.h                           |   0
 wildmatch.c => lib/wildmatch.c                     |   0
 wildmatch.h => lib/wildmatch.h                     |   0
 worktree.c => lib/worktree.c                       |   0
 worktree.h => lib/worktree.h                       |   0
 wrapper.c => lib/wrapper.c                         |   0
 wrapper.h => lib/wrapper.h                         |   0
 write-or-die.c => lib/write-or-die.c               |   0
 write-or-die.h => lib/write-or-die.h               |   0
 ws.c => lib/ws.c                                   |   0
 ws.h => lib/ws.h                                   |   0
 wt-status.c => lib/wt-status.c                     |   0
 wt-status.h => lib/wt-status.h                     |   0
 xdiff-interface.c => lib/xdiff-interface.c         |   0
 xdiff-interface.h => lib/xdiff-interface.h         |   0
 {xdiff => lib/xdiff}/xdiff.h                       |   0
 {xdiff => lib/xdiff}/xdiffi.c                      |   0
 {xdiff => lib/xdiff}/xdiffi.h                      |   0
 {xdiff => lib/xdiff}/xemit.c                       |   0
 {xdiff => lib/xdiff}/xemit.h                       |   0
 {xdiff => lib/xdiff}/xhistogram.c                  |   0
 {xdiff => lib/xdiff}/xinclude.h                    |   0
 {xdiff => lib/xdiff}/xmacros.h                     |   0
 {xdiff => lib/xdiff}/xmerge.c                      |   0
 {xdiff => lib/xdiff}/xpatience.c                   |   0
 {xdiff => lib/xdiff}/xprepare.c                    |   0
 {xdiff => lib/xdiff}/xprepare.h                    |   0
 {xdiff => lib/xdiff}/xtypes.h                      |   0
 {xdiff => lib/xdiff}/xutils.c                      |   0
 {xdiff => lib/xdiff}/xutils.h                      |   0
 meson.build                                        | 700 +++++++++----------
 t/helper/test-example-tap.c                        |   2 +-
 704 files changed, 825 insertions(+), 823 deletions(-)

Range-diff versus v3:

1:  069f2aebcf = 1:  4218cf6705 t/helper: prepare "test-example-tap.c" for introduction of "lib/"
2:  ee935f0622 ! 2:  cdfc78c1ab Move libgit.a sources into separate "lib/" directory
    @@ Makefile: compile_commands.json:
     +http-push.sp lib/http.sp lib/http-walker.sp remote-curl.sp imap-send.sp: SP_EXTRA_FLAGS += \
      	-DCURL_DISABLE_TYPECHECK
      
    - pack-revindex.sp: SP_EXTRA_FLAGS += -Wno-memcpy-max-count
    +-pack-revindex.sp: SP_EXTRA_FLAGS += -Wno-memcpy-max-count
    ++lib/pack-revindex.sp: SP_EXTRA_FLAGS += -Wno-memcpy-max-count
      
      ifdef NO_EXPAT
     -http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT

---
base-commit: 0309c6da48e2f94a72c9cee6e95ac6a1d0d2c965
change-id: 20260415-pks-libgit-in-subdir-d8eec849cd48


^ permalink raw reply

* [PATCH RFC v4 1/2] t/helper: prepare "test-example-tap.c" for introduction of "lib/"
From: Patrick Steinhardt @ 2026-07-13  5:50 UTC (permalink / raw)
  To: git
  Cc: brian m. carlson, Junio C Hamano, Elijah Newren, Derrick Stolee,
	SZEDER Gábor, Johannes Schindelin, Ramsay Jones,
	Phillip Wood
In-Reply-To: <20260713-pks-libgit-in-subdir-v4-0-696240876eb1@pks.im>

In the next commit we're about to introduce a new "lib/" directory and
move all of our files into it. With this split the compiler won't be
able to find one of the includes in "test-example-tap.c" anymore. Adjust
it to a relative include to prepare for this change.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/helper/test-example-tap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/helper/test-example-tap.c b/t/helper/test-example-tap.c
index 998a1f0b42..50d46669d1 100644
--- a/t/helper/test-example-tap.c
+++ b/t/helper/test-example-tap.c
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "t/unit-tests/test-lib.h"
+#include "../unit-tests/test-lib.h"
 
 /*
  * The purpose of this "unit test" is to verify a few invariants of the unit

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH RFC v4 2/2] Move libgit.a sources into separate "lib/" directory
From: Patrick Steinhardt @ 2026-07-13  5:50 UTC (permalink / raw)
  To: git
  Cc: brian m. carlson, Junio C Hamano, Elijah Newren, Derrick Stolee,
	SZEDER Gábor, Johannes Schindelin, Ramsay Jones,
	Phillip Wood
In-Reply-To: <20260713-pks-libgit-in-subdir-v4-0-696240876eb1@pks.im>

The Git project is not exactly the easiest project to get started in:
it's written in C and POSIX shell, with bits of Perl, Rust and other
languages sprinkled into it. On top of that, the project has grown
somewhat organically over time, making the codebase hard to navigate.

These are problems that we're aware of, and there have been and still
are efforts to clean up some of the technical debt that is natural to
exist in a project that is more than 20 years old. Furthermore, we
provide resources to newcomers that help them out like our coding
guidelines, code of conduct or "MyFirstContribution.adoc".

But there is a rather practical problem: finding your way around in our
project's tree is not easy. Doing a directory listing in the top-level
directory will present you with more than 550 files, which makes it
extremely hard for a newcomer to figure out what files they are even
supposed to look at. This makes the onboarding experience somewhat
harder than it really needs to be. This isn't only a problem for
newcomers though, as I myself struggle to find the files I am looking
for because of the sheer number of files.

Besides the problem of discoverability it also creates a problem of
structure. It is not obvious at all which files are part of "libgit.a"
and which files are only linked into our final executables. So while we
have this split in our build systems, that split is not evident at all
in our tree.

Introduce a new "lib/" directory and move all of our sources for
"libgit.a" into it to fix these issues. It makes the split we have
evident and reduces the number of files in our top-level tree from 550
files to ~80 files.

This is still a lot of files, but it's significantly easier to navigate
already. Furthermore, we can further iterate after this step and think
about introducing a better structure for remaining files, as well.

This move does not come for free though:

  - The mass rename introduces a cutoff point in the history of every
    moved file, as tools like git-log(1) do not follow renames by
    default.

  - Any in-flight or not-yet-submitted topic that touches the moved
    files will have to be rebased, and backporting fixes across the
    boundary becomes more cumbersome as a patch can no longer apply
    cleanly to both the old and the new layout.

My own (obviously subjective and biased) take is that the tradeoff is
worth it, as these issues are a one-time cost while the benefits to
discoverability will be permanent.

Furthermore, especially the first downside is a limitation in Git
itself. We're not the first or last project to do such a mass rename. So
if our provided tools are insufficient, then we should improve them to
make the experience better for other projects, as well. Subjecting
ourselves to the same pain may even give us more incentive to eventually
improve rename following for everyone.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 .github/workflows/main.yml                         |   9 +-
 .gitmodules                                        |   2 +-
 Documentation/Makefile                             |   4 +-
 Makefile                                           | 766 ++++++++++-----------
 config.mak.uname                                   |  52 +-
 contrib/buildsystems/CMakeLists.txt                |  95 +--
 git.rc.in                                          |   2 +-
 abspath.c => lib/abspath.c                         |   0
 abspath.h => lib/abspath.h                         |   0
 add-interactive.c => lib/add-interactive.c         |   0
 add-interactive.h => lib/add-interactive.h         |   0
 add-patch.c => lib/add-patch.c                     |   0
 add-patch.h => lib/add-patch.h                     |   0
 advice.c => lib/advice.c                           |   0
 advice.h => lib/advice.h                           |   0
 alias.c => lib/alias.c                             |   0
 alias.h => lib/alias.h                             |   0
 alloc.c => lib/alloc.c                             |   0
 alloc.h => lib/alloc.h                             |   0
 apply.c => lib/apply.c                             |   0
 apply.h => lib/apply.h                             |   0
 archive-tar.c => lib/archive-tar.c                 |   0
 archive-zip.c => lib/archive-zip.c                 |   0
 archive.c => lib/archive.c                         |   0
 archive.h => lib/archive.h                         |   0
 attr.c => lib/attr.c                               |   0
 attr.h => lib/attr.h                               |   0
 banned.h => lib/banned.h                           |   0
 base85.c => lib/base85.c                           |   0
 base85.h => lib/base85.h                           |   0
 bisect.c => lib/bisect.c                           |   0
 bisect.h => lib/bisect.h                           |   0
 blame.c => lib/blame.c                             |   0
 blame.h => lib/blame.h                             |   0
 blob.c => lib/blob.c                               |   0
 blob.h => lib/blob.h                               |   0
 {block-sha1 => lib/block-sha1}/sha1.c              |   0
 {block-sha1 => lib/block-sha1}/sha1.h              |   0
 bloom.c => lib/bloom.c                             |   0
 bloom.h => lib/bloom.h                             |   0
 branch.c => lib/branch.c                           |   0
 branch.h => lib/branch.h                           |   0
 builtin.h => lib/builtin.h                         |   0
 bundle-uri.c => lib/bundle-uri.c                   |   0
 bundle-uri.h => lib/bundle-uri.h                   |   0
 bundle.c => lib/bundle.c                           |   0
 bundle.h => lib/bundle.h                           |   0
 cache-tree.c => lib/cache-tree.c                   |   0
 cache-tree.h => lib/cache-tree.h                   |   0
 cbtree.c => lib/cbtree.c                           |   0
 cbtree.h => lib/cbtree.h                           |   0
 chdir-notify.c => lib/chdir-notify.c               |   0
 chdir-notify.h => lib/chdir-notify.h               |   0
 checkout.c => lib/checkout.c                       |   0
 checkout.h => lib/checkout.h                       |   0
 chunk-format.c => lib/chunk-format.c               |   0
 chunk-format.h => lib/chunk-format.h               |   0
 color.c => lib/color.c                             |   0
 color.h => lib/color.h                             |   0
 column.c => lib/column.c                           |   0
 column.h => lib/column.h                           |   0
 combine-diff.c => lib/combine-diff.c               |   0
 commit-graph.c => lib/commit-graph.c               |   0
 commit-graph.h => lib/commit-graph.h               |   0
 commit-reach.c => lib/commit-reach.c               |   0
 commit-reach.h => lib/commit-reach.h               |   0
 commit-slab-decl.h => lib/commit-slab-decl.h       |   0
 commit-slab-impl.h => lib/commit-slab-impl.h       |   0
 commit-slab.h => lib/commit-slab.h                 |   0
 commit.c => lib/commit.c                           |   0
 commit.h => lib/commit.h                           |   0
 common-exit.c => lib/common-exit.c                 |   0
 common-init.c => lib/common-init.c                 |   0
 common-init.h => lib/common-init.h                 |   0
 {compat => lib/compat}/.gitattributes              |   0
 {compat => lib/compat}/access.c                    |   0
 {compat => lib/compat}/apple-common-crypto.h       |   0
 {compat => lib/compat}/basename.c                  |   0
 {compat => lib/compat}/bswap.h                     |   0
 {compat => lib/compat}/compiler.h                  |   0
 {compat => lib/compat}/darwin/procinfo.c           |   0
 {compat => lib/compat}/disk.h                      |   0
 {compat => lib/compat}/fileno.c                    |   0
 {compat => lib/compat}/fopen.c                     |   0
 {compat => lib/compat}/fsmonitor/fsm-darwin-gcc.h  |   0
 .../compat}/fsmonitor/fsm-health-darwin.c          |   0
 .../compat}/fsmonitor/fsm-health-linux.c           |   0
 .../compat}/fsmonitor/fsm-health-win32.c           |   0
 {compat => lib/compat}/fsmonitor/fsm-health.h      |   0
 {compat => lib/compat}/fsmonitor/fsm-ipc-unix.c    |   0
 {compat => lib/compat}/fsmonitor/fsm-ipc-win32.c   |   0
 .../compat}/fsmonitor/fsm-listen-darwin.c          |   0
 .../compat}/fsmonitor/fsm-listen-linux.c           |   0
 .../compat}/fsmonitor/fsm-listen-win32.c           |   0
 {compat => lib/compat}/fsmonitor/fsm-listen.h      |   0
 .../compat}/fsmonitor/fsm-path-utils-darwin.c      |   0
 .../compat}/fsmonitor/fsm-path-utils-linux.c       |   0
 .../compat}/fsmonitor/fsm-path-utils-win32.c       |   0
 .../compat}/fsmonitor/fsm-settings-unix.c          |   0
 .../compat}/fsmonitor/fsm-settings-win32.c         |   0
 {compat => lib/compat}/hstrerror.c                 |   0
 {compat => lib/compat}/inet_ntop.c                 |   0
 {compat => lib/compat}/inet_pton.c                 |   0
 {compat => lib/compat}/linux/procinfo.c            |   0
 {compat => lib/compat}/memmem.c                    |   0
 {compat => lib/compat}/mingw-posix.h               |   0
 {compat => lib/compat}/mingw.c                     |   0
 {compat => lib/compat}/mingw.h                     |   0
 {compat => lib/compat}/mkdir.c                     |   0
 {compat => lib/compat}/mmap.c                      |   0
 {compat => lib/compat}/msvc-posix.h                |   0
 {compat => lib/compat}/msvc.c                      |   0
 {compat => lib/compat}/msvc.h                      |   0
 {compat => lib/compat}/nonblock.c                  |   0
 {compat => lib/compat}/nonblock.h                  |   0
 {compat => lib/compat}/obstack.c                   |   0
 {compat => lib/compat}/obstack.h                   |   0
 {compat => lib/compat}/open.c                      |   0
 {compat => lib/compat}/poll/poll.c                 |   0
 {compat => lib/compat}/poll/poll.h                 |   0
 {compat => lib/compat}/posix.h                     |   0
 {compat => lib/compat}/pread.c                     |   0
 {compat => lib/compat}/precompose_utf8.c           |   0
 {compat => lib/compat}/precompose_utf8.h           |   0
 {compat => lib/compat}/qsort_s.c                   |   0
 {compat => lib/compat}/regcomp_enhanced.c          |   0
 {compat => lib/compat}/regex/regcomp.c             |   0
 {compat => lib/compat}/regex/regex.c               |   0
 {compat => lib/compat}/regex/regex.h               |   0
 {compat => lib/compat}/regex/regex_internal.c      |   0
 {compat => lib/compat}/regex/regex_internal.h      |   0
 {compat => lib/compat}/regex/regexec.c             |   0
 {compat => lib/compat}/setenv.c                    |   0
 {compat => lib/compat}/sha1-chunked.c              |   0
 {compat => lib/compat}/sha1-chunked.h              |   0
 {compat => lib/compat}/simple-ipc/ipc-shared.c     |   0
 .../compat}/simple-ipc/ipc-unix-socket.c           |   0
 {compat => lib/compat}/simple-ipc/ipc-win32.c      |   0
 {compat => lib/compat}/snprintf.c                  |   0
 {compat => lib/compat}/stat.c                      |   0
 {compat => lib/compat}/strcasestr.c                |   0
 {compat => lib/compat}/strdup.c                    |   0
 {compat => lib/compat}/strlcpy.c                   |   0
 {compat => lib/compat}/strtoimax.c                 |   0
 {compat => lib/compat}/strtoumax.c                 |   0
 {compat => lib/compat}/stub/procinfo.c             |   0
 {compat => lib/compat}/terminal.c                  |   0
 {compat => lib/compat}/terminal.h                  |   0
 {compat => lib/compat}/unsetenv.c                  |   0
 {compat => lib/compat}/vcbuild/.gitignore          |   0
 {compat => lib/compat}/vcbuild/README              |  10 +-
 {compat => lib/compat}/vcbuild/find_vs_env.bat     |   2 +-
 {compat => lib/compat}/vcbuild/include/sys/param.h |   0
 {compat => lib/compat}/vcbuild/include/sys/time.h  |   0
 {compat => lib/compat}/vcbuild/include/sys/utime.h |   0
 {compat => lib/compat}/vcbuild/include/unistd.h    |   0
 {compat => lib/compat}/vcbuild/include/utime.h     |   0
 {compat => lib/compat}/vcbuild/scripts/clink.pl    |   0
 {compat => lib/compat}/vcbuild/scripts/lib.pl      |   0
 {compat => lib/compat}/vcbuild/vcpkg_copy_dlls.bat |   0
 {compat => lib/compat}/vcbuild/vcpkg_install.bat   |   4 +-
 {compat => lib/compat}/win32.h                     |   0
 {compat => lib/compat}/win32/alloca.h              |   0
 {compat => lib/compat}/win32/dirent.c              |   0
 {compat => lib/compat}/win32/dirent.h              |   0
 {compat => lib/compat}/win32/exit-process.h        |   0
 {compat => lib/compat}/win32/flush.c               |   0
 {compat => lib/compat}/win32/git.manifest          |   0
 {compat => lib/compat}/win32/headless.c            |   0
 {compat => lib/compat}/win32/lazyload.h            |   0
 {compat => lib/compat}/win32/path-utils.c          |   0
 {compat => lib/compat}/win32/path-utils.h          |   0
 {compat => lib/compat}/win32/pthread.c             |   0
 {compat => lib/compat}/win32/pthread.h             |   0
 {compat => lib/compat}/win32/syslog.c              |   0
 {compat => lib/compat}/win32/syslog.h              |   0
 .../compat}/win32/trace2_win32_process_info.c      |   0
 {compat => lib/compat}/win32mmap.c                 |   0
 {compat => lib/compat}/winansi.c                   |   0
 {compat => lib/compat}/zlib-compat.h               |   0
 .../compiler-tricks}/not-constant.c                |   0
 config.c => lib/config.c                           |   0
 config.h => lib/config.h                           |   0
 connect.c => lib/connect.c                         |   0
 connect.h => lib/connect.h                         |   0
 connected.c => lib/connected.c                     |   0
 connected.h => lib/connected.h                     |   0
 convert.c => lib/convert.c                         |   0
 convert.h => lib/convert.h                         |   0
 copy.c => lib/copy.c                               |   0
 copy.h => lib/copy.h                               |   0
 credential.c => lib/credential.c                   |   0
 credential.h => lib/credential.h                   |   0
 csum-file.c => lib/csum-file.c                     |   0
 csum-file.h => lib/csum-file.h                     |   0
 ctype.c => lib/ctype.c                             |   0
 date.c => lib/date.c                               |   0
 date.h => lib/date.h                               |   0
 decorate.c => lib/decorate.c                       |   0
 decorate.h => lib/decorate.h                       |   0
 delta-islands.c => lib/delta-islands.c             |   0
 delta-islands.h => lib/delta-islands.h             |   0
 delta.h => lib/delta.h                             |   0
 diagnose.c => lib/diagnose.c                       |   0
 diagnose.h => lib/diagnose.h                       |   0
 diff-delta.c => lib/diff-delta.c                   |   0
 diff-lib.c => lib/diff-lib.c                       |   0
 diff-merges.c => lib/diff-merges.c                 |   0
 diff-merges.h => lib/diff-merges.h                 |   0
 diff-no-index.c => lib/diff-no-index.c             |   0
 diff.c => lib/diff.c                               |   0
 diff.h => lib/diff.h                               |   0
 diffcore-break.c => lib/diffcore-break.c           |   0
 diffcore-delta.c => lib/diffcore-delta.c           |   0
 diffcore-order.c => lib/diffcore-order.c           |   0
 diffcore-pickaxe.c => lib/diffcore-pickaxe.c       |   0
 diffcore-rename.c => lib/diffcore-rename.c         |   0
 diffcore-rotate.c => lib/diffcore-rotate.c         |   0
 diffcore.h => lib/diffcore.h                       |   0
 dir-iterator.c => lib/dir-iterator.c               |   0
 dir-iterator.h => lib/dir-iterator.h               |   0
 dir.c => lib/dir.c                                 |   0
 dir.h => lib/dir.h                                 |   0
 editor.c => lib/editor.c                           |   0
 editor.h => lib/editor.h                           |   0
 entry.c => lib/entry.c                             |   0
 entry.h => lib/entry.h                             |   0
 environment.c => lib/environment.c                 |   0
 environment.h => lib/environment.h                 |   0
 {ewah => lib/ewah}/bitmap.c                        |   0
 {ewah => lib/ewah}/ewah_bitmap.c                   |   0
 {ewah => lib/ewah}/ewah_io.c                       |   0
 {ewah => lib/ewah}/ewah_rlw.c                      |   0
 {ewah => lib/ewah}/ewok.h                          |   0
 {ewah => lib/ewah}/ewok_rlw.h                      |   0
 exec-cmd.c => lib/exec-cmd.c                       |   0
 exec-cmd.h => lib/exec-cmd.h                       |   0
 fetch-negotiator.c => lib/fetch-negotiator.c       |   0
 fetch-negotiator.h => lib/fetch-negotiator.h       |   0
 fetch-pack.c => lib/fetch-pack.c                   |   0
 fetch-pack.h => lib/fetch-pack.h                   |   0
 fmt-merge-msg.c => lib/fmt-merge-msg.c             |   0
 fmt-merge-msg.h => lib/fmt-merge-msg.h             |   0
 for-each-ref.h => lib/for-each-ref.h               |   0
 fsck.c => lib/fsck.c                               |   0
 fsck.h => lib/fsck.h                               |   0
 fsmonitor--daemon.h => lib/fsmonitor--daemon.h     |   0
 fsmonitor-ipc.c => lib/fsmonitor-ipc.c             |   0
 fsmonitor-ipc.h => lib/fsmonitor-ipc.h             |   0
 fsmonitor-ll.h => lib/fsmonitor-ll.h               |   0
 .../fsmonitor-path-utils.h                         |   0
 fsmonitor-settings.c => lib/fsmonitor-settings.c   |   0
 fsmonitor-settings.h => lib/fsmonitor-settings.h   |   0
 fsmonitor.c => lib/fsmonitor.c                     |   0
 fsmonitor.h => lib/fsmonitor.h                     |   0
 gettext.c => lib/gettext.c                         |   0
 gettext.h => lib/gettext.h                         |   0
 git-compat-util.h => lib/git-compat-util.h         |   0
 git-curl-compat.h => lib/git-curl-compat.h         |   0
 git-zlib.c => lib/git-zlib.c                       |   0
 git-zlib.h => lib/git-zlib.h                       |   0
 gpg-interface.c => lib/gpg-interface.c             |   0
 gpg-interface.h => lib/gpg-interface.h             |   0
 graph.c => lib/graph.c                             |   0
 graph.h => lib/graph.h                             |   0
 grep.c => lib/grep.c                               |   0
 grep.h => lib/grep.h                               |   0
 hash-lookup.c => lib/hash-lookup.c                 |   0
 hash-lookup.h => lib/hash-lookup.h                 |   0
 hash.c => lib/hash.c                               |   0
 hash.h => lib/hash.h                               |   0
 hashmap.c => lib/hashmap.c                         |   0
 hashmap.h => lib/hashmap.h                         |   0
 help.c => lib/help.c                               |   0
 help.h => lib/help.h                               |   0
 hex-ll.c => lib/hex-ll.c                           |   0
 hex-ll.h => lib/hex-ll.h                           |   0
 hex.c => lib/hex.c                                 |   0
 hex.h => lib/hex.h                                 |   0
 hook.c => lib/hook.c                               |   0
 hook.h => lib/hook.h                               |   0
 http-walker.c => lib/http-walker.c                 |   0
 http.c => lib/http.c                               |   0
 http.h => lib/http.h                               |   0
 ident.c => lib/ident.c                             |   0
 ident.h => lib/ident.h                             |   0
 iterator.h => lib/iterator.h                       |   0
 json-writer.c => lib/json-writer.c                 |   0
 json-writer.h => lib/json-writer.h                 |   0
 khash.h => lib/khash.h                             |   0
 kwset.c => lib/kwset.c                             |   0
 kwset.h => lib/kwset.h                             |   0
 levenshtein.c => lib/levenshtein.c                 |   0
 levenshtein.h => lib/levenshtein.h                 |   0
 line-log.c => lib/line-log.c                       |   0
 line-log.h => lib/line-log.h                       |   0
 line-range.c => lib/line-range.c                   |   0
 line-range.h => lib/line-range.h                   |   0
 linear-assignment.c => lib/linear-assignment.c     |   0
 linear-assignment.h => lib/linear-assignment.h     |   0
 .../list-objects-filter-options.c                  |   0
 .../list-objects-filter-options.h                  |   0
 list-objects-filter.c => lib/list-objects-filter.c |   0
 list-objects-filter.h => lib/list-objects-filter.h |   0
 list-objects.c => lib/list-objects.c               |   0
 list-objects.h => lib/list-objects.h               |   0
 list.h => lib/list.h                               |   0
 lockfile.c => lib/lockfile.c                       |   0
 lockfile.h => lib/lockfile.h                       |   0
 log-tree.c => lib/log-tree.c                       |   0
 log-tree.h => lib/log-tree.h                       |   0
 loose.c => lib/loose.c                             |   0
 loose.h => lib/loose.h                             |   0
 ls-refs.c => lib/ls-refs.c                         |   0
 ls-refs.h => lib/ls-refs.h                         |   0
 mailinfo.c => lib/mailinfo.c                       |   0
 mailinfo.h => lib/mailinfo.h                       |   0
 mailmap.c => lib/mailmap.c                         |   0
 mailmap.h => lib/mailmap.h                         |   0
 match-trees.c => lib/match-trees.c                 |   0
 match-trees.h => lib/match-trees.h                 |   0
 mem-pool.c => lib/mem-pool.c                       |   0
 mem-pool.h => lib/mem-pool.h                       |   0
 merge-blobs.c => lib/merge-blobs.c                 |   0
 merge-blobs.h => lib/merge-blobs.h                 |   0
 merge-ll.c => lib/merge-ll.c                       |   0
 merge-ll.h => lib/merge-ll.h                       |   0
 merge-ort-wrappers.c => lib/merge-ort-wrappers.c   |   0
 merge-ort-wrappers.h => lib/merge-ort-wrappers.h   |   0
 merge-ort.c => lib/merge-ort.c                     |   0
 merge-ort.h => lib/merge-ort.h                     |   0
 merge.c => lib/merge.c                             |   0
 merge.h => lib/merge.h                             |   0
 mergesort.h => lib/mergesort.h                     |   0
 midx-write.c => lib/midx-write.c                   |   0
 midx.c => lib/midx.c                               |   0
 midx.h => lib/midx.h                               |   0
 name-hash.c => lib/name-hash.c                     |   0
 name-hash.h => lib/name-hash.h                     |   0
 {negotiator => lib/negotiator}/default.c           |   0
 {negotiator => lib/negotiator}/default.h           |   0
 {negotiator => lib/negotiator}/noop.c              |   0
 {negotiator => lib/negotiator}/noop.h              |   0
 {negotiator => lib/negotiator}/skipping.c          |   0
 {negotiator => lib/negotiator}/skipping.h          |   0
 notes-cache.c => lib/notes-cache.c                 |   0
 notes-cache.h => lib/notes-cache.h                 |   0
 notes-merge.c => lib/notes-merge.c                 |   0
 notes-merge.h => lib/notes-merge.h                 |   0
 notes-utils.c => lib/notes-utils.c                 |   0
 notes-utils.h => lib/notes-utils.h                 |   0
 notes.c => lib/notes.c                             |   0
 notes.h => lib/notes.h                             |   0
 object-file-convert.c => lib/object-file-convert.c |   0
 object-file-convert.h => lib/object-file-convert.h |   0
 object-file.c => lib/object-file.c                 |   0
 object-file.h => lib/object-file.h                 |   0
 object-name.c => lib/object-name.c                 |   0
 object-name.h => lib/object-name.h                 |   0
 object.c => lib/object.c                           |   0
 object.h => lib/object.h                           |   0
 odb.c => lib/odb.c                                 |   0
 odb.h => lib/odb.h                                 |   0
 {odb => lib/odb}/source-files.c                    |   0
 {odb => lib/odb}/source-files.h                    |   0
 {odb => lib/odb}/source-inmemory.c                 |   0
 {odb => lib/odb}/source-inmemory.h                 |   0
 {odb => lib/odb}/source-loose.c                    |   0
 {odb => lib/odb}/source-loose.h                    |   0
 {odb => lib/odb}/source-packed.c                   |   0
 {odb => lib/odb}/source-packed.h                   |   0
 {odb => lib/odb}/source.c                          |   0
 {odb => lib/odb}/source.h                          |   0
 {odb => lib/odb}/streaming.c                       |   0
 {odb => lib/odb}/streaming.h                       |   0
 {odb => lib/odb}/transaction.c                     |   0
 {odb => lib/odb}/transaction.h                     |   0
 oid-array.c => lib/oid-array.c                     |   0
 oid-array.h => lib/oid-array.h                     |   0
 oidmap.c => lib/oidmap.c                           |   0
 oidmap.h => lib/oidmap.h                           |   0
 oidset.c => lib/oidset.c                           |   0
 oidset.h => lib/oidset.h                           |   0
 oidtree.c => lib/oidtree.c                         |   0
 oidtree.h => lib/oidtree.h                         |   0
 pack-bitmap-write.c => lib/pack-bitmap-write.c     |   0
 pack-bitmap.c => lib/pack-bitmap.c                 |   0
 pack-bitmap.h => lib/pack-bitmap.h                 |   0
 pack-check.c => lib/pack-check.c                   |   0
 pack-mtimes.c => lib/pack-mtimes.c                 |   0
 pack-mtimes.h => lib/pack-mtimes.h                 |   0
 pack-objects.c => lib/pack-objects.c               |   0
 pack-objects.h => lib/pack-objects.h               |   0
 pack-refs.c => lib/pack-refs.c                     |   0
 pack-refs.h => lib/pack-refs.h                     |   0
 pack-revindex.c => lib/pack-revindex.c             |   0
 pack-revindex.h => lib/pack-revindex.h             |   0
 pack-write.c => lib/pack-write.c                   |   0
 pack.h => lib/pack.h                               |   0
 packfile-list.c => lib/packfile-list.c             |   0
 packfile-list.h => lib/packfile-list.h             |   0
 packfile.c => lib/packfile.c                       |   0
 packfile.h => lib/packfile.h                       |   0
 pager.c => lib/pager.c                             |   0
 pager.h => lib/pager.h                             |   0
 parallel-checkout.c => lib/parallel-checkout.c     |   0
 parallel-checkout.h => lib/parallel-checkout.h     |   0
 parse-options-cb.c => lib/parse-options-cb.c       |   0
 parse-options.c => lib/parse-options.c             |   0
 parse-options.h => lib/parse-options.h             |   0
 parse.c => lib/parse.c                             |   0
 parse.h => lib/parse.h                             |   0
 patch-delta.c => lib/patch-delta.c                 |   0
 patch-ids.c => lib/patch-ids.c                     |   0
 patch-ids.h => lib/patch-ids.h                     |   0
 path-walk.c => lib/path-walk.c                     |   0
 path-walk.h => lib/path-walk.h                     |   0
 path.c => lib/path.c                               |   0
 path.h => lib/path.h                               |   0
 pathspec.c => lib/pathspec.c                       |   0
 pathspec.h => lib/pathspec.h                       |   0
 pkt-line.c => lib/pkt-line.c                       |   0
 pkt-line.h => lib/pkt-line.h                       |   0
 preload-index.c => lib/preload-index.c             |   0
 preload-index.h => lib/preload-index.h             |   0
 pretty.c => lib/pretty.c                           |   0
 pretty.h => lib/pretty.h                           |   0
 prio-queue.c => lib/prio-queue.c                   |   0
 prio-queue.h => lib/prio-queue.h                   |   0
 progress.c => lib/progress.c                       |   0
 progress.h => lib/progress.h                       |   0
 promisor-remote.c => lib/promisor-remote.c         |   0
 promisor-remote.h => lib/promisor-remote.h         |   0
 prompt.c => lib/prompt.c                           |   0
 prompt.h => lib/prompt.h                           |   0
 protocol-caps.c => lib/protocol-caps.c             |   0
 protocol-caps.h => lib/protocol-caps.h             |   0
 protocol.c => lib/protocol.c                       |   0
 protocol.h => lib/protocol.h                       |   0
 prune-packed.c => lib/prune-packed.c               |   0
 prune-packed.h => lib/prune-packed.h               |   0
 pseudo-merge.c => lib/pseudo-merge.c               |   0
 pseudo-merge.h => lib/pseudo-merge.h               |   0
 quote.c => lib/quote.c                             |   0
 quote.h => lib/quote.h                             |   0
 range-diff.c => lib/range-diff.c                   |   0
 range-diff.h => lib/range-diff.h                   |   0
 reachable.c => lib/reachable.c                     |   0
 reachable.h => lib/reachable.h                     |   0
 read-cache-ll.h => lib/read-cache-ll.h             |   0
 read-cache.c => lib/read-cache.c                   |   0
 read-cache.h => lib/read-cache.h                   |   0
 rebase-interactive.c => lib/rebase-interactive.c   |   0
 rebase-interactive.h => lib/rebase-interactive.h   |   0
 rebase.c => lib/rebase.c                           |   0
 rebase.h => lib/rebase.h                           |   0
 ref-filter.c => lib/ref-filter.c                   |   0
 ref-filter.h => lib/ref-filter.h                   |   0
 reflog-walk.c => lib/reflog-walk.c                 |   0
 reflog-walk.h => lib/reflog-walk.h                 |   0
 reflog.c => lib/reflog.c                           |   0
 reflog.h => lib/reflog.h                           |   0
 refs.c => lib/refs.c                               |   0
 refs.h => lib/refs.h                               |   0
 {refs => lib/refs}/debug.c                         |   0
 {refs => lib/refs}/files-backend.c                 |   0
 {refs => lib/refs}/iterator.c                      |   0
 {refs => lib/refs}/packed-backend.c                |   0
 {refs => lib/refs}/packed-backend.h                |   0
 {refs => lib/refs}/ref-cache.c                     |   0
 {refs => lib/refs}/ref-cache.h                     |   0
 {refs => lib/refs}/refs-internal.h                 |   0
 {refs => lib/refs}/reftable-backend.c              |   0
 refspec.c => lib/refspec.c                         |   0
 refspec.h => lib/refspec.h                         |   0
 {reftable => lib/reftable}/LICENSE                 |   0
 {reftable => lib/reftable}/basics.c                |   0
 {reftable => lib/reftable}/basics.h                |   0
 {reftable => lib/reftable}/block.c                 |   0
 {reftable => lib/reftable}/block.h                 |   0
 {reftable => lib/reftable}/blocksource.c           |   0
 {reftable => lib/reftable}/blocksource.h           |   0
 {reftable => lib/reftable}/constants.h             |   0
 {reftable => lib/reftable}/error.c                 |   0
 {reftable => lib/reftable}/fsck.c                  |   0
 {reftable => lib/reftable}/iter.c                  |   0
 {reftable => lib/reftable}/iter.h                  |   0
 {reftable => lib/reftable}/merged.c                |   0
 {reftable => lib/reftable}/merged.h                |   0
 {reftable => lib/reftable}/pq.c                    |   0
 {reftable => lib/reftable}/pq.h                    |   0
 {reftable => lib/reftable}/record.c                |   0
 {reftable => lib/reftable}/record.h                |   0
 {reftable => lib/reftable}/reftable-basics.h       |   0
 {reftable => lib/reftable}/reftable-block.h        |   0
 {reftable => lib/reftable}/reftable-blocksource.h  |   0
 {reftable => lib/reftable}/reftable-constants.h    |   0
 {reftable => lib/reftable}/reftable-error.h        |   0
 {reftable => lib/reftable}/reftable-fsck.h         |   0
 {reftable => lib/reftable}/reftable-iterator.h     |   0
 {reftable => lib/reftable}/reftable-merged.h       |   0
 {reftable => lib/reftable}/reftable-record.h       |   0
 {reftable => lib/reftable}/reftable-stack.h        |   0
 {reftable => lib/reftable}/reftable-system.h       |   0
 {reftable => lib/reftable}/reftable-table.h        |   0
 {reftable => lib/reftable}/reftable-writer.h       |   0
 {reftable => lib/reftable}/stack.c                 |   0
 {reftable => lib/reftable}/stack.h                 |   0
 {reftable => lib/reftable}/system.c                |   0
 {reftable => lib/reftable}/system.h                |   0
 {reftable => lib/reftable}/table.c                 |   0
 {reftable => lib/reftable}/table.h                 |   0
 {reftable => lib/reftable}/tree.c                  |   0
 {reftable => lib/reftable}/tree.h                  |   0
 {reftable => lib/reftable}/writer.c                |   0
 {reftable => lib/reftable}/writer.h                |   0
 remote.c => lib/remote.c                           |   0
 remote.h => lib/remote.h                           |   0
 repack-cruft.c => lib/repack-cruft.c               |   0
 repack-filtered.c => lib/repack-filtered.c         |   0
 repack-geometry.c => lib/repack-geometry.c         |   0
 repack-midx.c => lib/repack-midx.c                 |   0
 repack-promisor.c => lib/repack-promisor.c         |   0
 repack.c => lib/repack.c                           |   0
 repack.h => lib/repack.h                           |   0
 replace-object.c => lib/replace-object.c           |   0
 replace-object.h => lib/replace-object.h           |   0
 replay.c => lib/replay.c                           |   0
 replay.h => lib/replay.h                           |   0
 repo-settings.c => lib/repo-settings.c             |   0
 repo-settings.h => lib/repo-settings.h             |   0
 repository.c => lib/repository.c                   |   0
 repository.h => lib/repository.h                   |   0
 rerere.c => lib/rerere.c                           |   0
 rerere.h => lib/rerere.h                           |   0
 reset.c => lib/reset.c                             |   0
 reset.h => lib/reset.h                             |   0
 resolve-undo.c => lib/resolve-undo.c               |   0
 resolve-undo.h => lib/resolve-undo.h               |   0
 revision.c => lib/revision.c                       |   0
 revision.h => lib/revision.h                       |   0
 run-command.c => lib/run-command.c                 |   0
 run-command.h => lib/run-command.h                 |   0
 sane-ctype.h => lib/sane-ctype.h                   |   0
 send-pack.c => lib/send-pack.c                     |   0
 send-pack.h => lib/send-pack.h                     |   0
 sequencer.c => lib/sequencer.c                     |   0
 sequencer.h => lib/sequencer.h                     |   0
 serve.c => lib/serve.c                             |   0
 serve.h => lib/serve.h                             |   0
 server-info.c => lib/server-info.c                 |   0
 server-info.h => lib/server-info.h                 |   0
 setup.c => lib/setup.c                             |   0
 setup.h => lib/setup.h                             |   0
 {sha1 => lib/sha1}/openssl.h                       |   0
 .../sha1collisiondetection                         |   0
 {sha1dc => lib/sha1dc}/.gitattributes              |   0
 {sha1dc => lib/sha1dc}/LICENSE.txt                 |   0
 {sha1dc => lib/sha1dc}/sha1.c                      |   0
 {sha1dc => lib/sha1dc}/sha1.h                      |   0
 {sha1dc => lib/sha1dc}/ubc_check.c                 |   0
 {sha1dc => lib/sha1dc}/ubc_check.h                 |   0
 sha1dc_git.c => lib/sha1dc_git.c                   |   0
 sha1dc_git.h => lib/sha1dc_git.h                   |   0
 {sha256 => lib/sha256}/block/sha256.c              |   0
 {sha256 => lib/sha256}/block/sha256.h              |   0
 {sha256 => lib/sha256}/gcrypt.h                    |   0
 {sha256 => lib/sha256}/nettle.h                    |   0
 {sha256 => lib/sha256}/openssl.h                   |   0
 shallow.c => lib/shallow.c                         |   0
 shallow.h => lib/shallow.h                         |   0
 shortlog.h => lib/shortlog.h                       |   0
 sideband.c => lib/sideband.c                       |   0
 sideband.h => lib/sideband.h                       |   0
 sigchain.c => lib/sigchain.c                       |   0
 sigchain.h => lib/sigchain.h                       |   0
 simple-ipc.h => lib/simple-ipc.h                   |   0
 sparse-index.c => lib/sparse-index.c               |   0
 sparse-index.h => lib/sparse-index.h               |   0
 split-index.c => lib/split-index.c                 |   0
 split-index.h => lib/split-index.h                 |   0
 stable-qsort.c => lib/stable-qsort.c               |   0
 statinfo.c => lib/statinfo.c                       |   0
 statinfo.h => lib/statinfo.h                       |   0
 strbuf.c => lib/strbuf.c                           |   0
 strbuf.h => lib/strbuf.h                           |   0
 string-list.c => lib/string-list.c                 |   0
 string-list.h => lib/string-list.h                 |   0
 strmap.c => lib/strmap.c                           |   0
 strmap.h => lib/strmap.h                           |   0
 strvec.c => lib/strvec.c                           |   0
 strvec.h => lib/strvec.h                           |   0
 sub-process.c => lib/sub-process.c                 |   0
 sub-process.h => lib/sub-process.h                 |   0
 submodule-config.c => lib/submodule-config.c       |   0
 submodule-config.h => lib/submodule-config.h       |   0
 submodule.c => lib/submodule.c                     |   0
 submodule.h => lib/submodule.h                     |   0
 symlinks.c => lib/symlinks.c                       |   0
 symlinks.h => lib/symlinks.h                       |   0
 tag.c => lib/tag.c                                 |   0
 tag.h => lib/tag.h                                 |   0
 tar.h => lib/tar.h                                 |   0
 tempfile.c => lib/tempfile.c                       |   0
 tempfile.h => lib/tempfile.h                       |   0
 thread-utils.c => lib/thread-utils.c               |   0
 thread-utils.h => lib/thread-utils.h               |   0
 tmp-objdir.c => lib/tmp-objdir.c                   |   0
 tmp-objdir.h => lib/tmp-objdir.h                   |   0
 trace.c => lib/trace.c                             |   0
 trace.h => lib/trace.h                             |   0
 trace2.c => lib/trace2.c                           |   0
 trace2.h => lib/trace2.h                           |   0
 {trace2 => lib/trace2}/tr2_cfg.c                   |   0
 {trace2 => lib/trace2}/tr2_cfg.h                   |   0
 {trace2 => lib/trace2}/tr2_cmd_name.c              |   0
 {trace2 => lib/trace2}/tr2_cmd_name.h              |   0
 {trace2 => lib/trace2}/tr2_ctr.c                   |   0
 {trace2 => lib/trace2}/tr2_ctr.h                   |   0
 {trace2 => lib/trace2}/tr2_dst.c                   |   0
 {trace2 => lib/trace2}/tr2_dst.h                   |   0
 {trace2 => lib/trace2}/tr2_sid.c                   |   0
 {trace2 => lib/trace2}/tr2_sid.h                   |   0
 {trace2 => lib/trace2}/tr2_sysenv.c                |   0
 {trace2 => lib/trace2}/tr2_sysenv.h                |   0
 {trace2 => lib/trace2}/tr2_tbuf.c                  |   0
 {trace2 => lib/trace2}/tr2_tbuf.h                  |   0
 {trace2 => lib/trace2}/tr2_tgt.h                   |   0
 {trace2 => lib/trace2}/tr2_tgt_event.c             |   0
 {trace2 => lib/trace2}/tr2_tgt_normal.c            |   0
 {trace2 => lib/trace2}/tr2_tgt_perf.c              |   0
 {trace2 => lib/trace2}/tr2_tls.c                   |   0
 {trace2 => lib/trace2}/tr2_tls.h                   |   0
 {trace2 => lib/trace2}/tr2_tmr.c                   |   0
 {trace2 => lib/trace2}/tr2_tmr.h                   |   0
 trailer.c => lib/trailer.c                         |   0
 trailer.h => lib/trailer.h                         |   0
 transport-helper.c => lib/transport-helper.c       |   0
 transport-internal.h => lib/transport-internal.h   |   0
 transport.c => lib/transport.c                     |   0
 transport.h => lib/transport.h                     |   0
 tree-diff.c => lib/tree-diff.c                     |   0
 tree-walk.c => lib/tree-walk.c                     |   0
 tree-walk.h => lib/tree-walk.h                     |   0
 tree.c => lib/tree.c                               |   0
 tree.h => lib/tree.h                               |   0
 unicode-width.h => lib/unicode-width.h             |   0
 unix-socket.c => lib/unix-socket.c                 |   0
 unix-socket.h => lib/unix-socket.h                 |   0
 unix-stream-server.c => lib/unix-stream-server.c   |   0
 unix-stream-server.h => lib/unix-stream-server.h   |   0
 unpack-trees.c => lib/unpack-trees.c               |   0
 unpack-trees.h => lib/unpack-trees.h               |   0
 upload-pack.c => lib/upload-pack.c                 |   0
 upload-pack.h => lib/upload-pack.h                 |   0
 url.c => lib/url.c                                 |   0
 url.h => lib/url.h                                 |   0
 urlmatch.c => lib/urlmatch.c                       |   0
 urlmatch.h => lib/urlmatch.h                       |   0
 usage.c => lib/usage.c                             |   0
 userdiff.c => lib/userdiff.c                       |   0
 userdiff.h => lib/userdiff.h                       |   0
 utf8.c => lib/utf8.c                               |   0
 utf8.h => lib/utf8.h                               |   0
 varint.c => lib/varint.c                           |   0
 varint.h => lib/varint.h                           |   0
 version-def.h.in => lib/version-def.h.in           |   0
 version.c => lib/version.c                         |   0
 version.h => lib/version.h                         |   0
 versioncmp.c => lib/versioncmp.c                   |   0
 versioncmp.h => lib/versioncmp.h                   |   0
 walker.c => lib/walker.c                           |   0
 walker.h => lib/walker.h                           |   0
 wildmatch.c => lib/wildmatch.c                     |   0
 wildmatch.h => lib/wildmatch.h                     |   0
 worktree.c => lib/worktree.c                       |   0
 worktree.h => lib/worktree.h                       |   0
 wrapper.c => lib/wrapper.c                         |   0
 wrapper.h => lib/wrapper.h                         |   0
 write-or-die.c => lib/write-or-die.c               |   0
 write-or-die.h => lib/write-or-die.h               |   0
 ws.c => lib/ws.c                                   |   0
 ws.h => lib/ws.h                                   |   0
 wt-status.c => lib/wt-status.c                     |   0
 wt-status.h => lib/wt-status.h                     |   0
 xdiff-interface.c => lib/xdiff-interface.c         |   0
 xdiff-interface.h => lib/xdiff-interface.h         |   0
 {xdiff => lib/xdiff}/xdiff.h                       |   0
 {xdiff => lib/xdiff}/xdiffi.c                      |   0
 {xdiff => lib/xdiff}/xdiffi.h                      |   0
 {xdiff => lib/xdiff}/xemit.c                       |   0
 {xdiff => lib/xdiff}/xemit.h                       |   0
 {xdiff => lib/xdiff}/xhistogram.c                  |   0
 {xdiff => lib/xdiff}/xinclude.h                    |   0
 {xdiff => lib/xdiff}/xmacros.h                     |   0
 {xdiff => lib/xdiff}/xmerge.c                      |   0
 {xdiff => lib/xdiff}/xpatience.c                   |   0
 {xdiff => lib/xdiff}/xprepare.c                    |   0
 {xdiff => lib/xdiff}/xprepare.h                    |   0
 {xdiff => lib/xdiff}/xtypes.h                      |   0
 {xdiff => lib/xdiff}/xutils.c                      |   0
 {xdiff => lib/xdiff}/xutils.h                      |   0
 meson.build                                        | 700 +++++++++----------
 703 files changed, 824 insertions(+), 822 deletions(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index cf341d74db..accf456945 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -179,21 +179,22 @@ jobs:
       uses: actions/checkout@v6
       with:
         repository: 'microsoft/vcpkg'
-        path: 'compat/vcbuild/vcpkg'
+        path: 'lib/compat/vcbuild/vcpkg'
     - name: download vcpkg artifacts
       uses: git-for-windows/get-azure-pipelines-artifact@v0
       with:
         repository: git/git
         definitionId: 9
+        path: lib/compat
     - name: add msbuild to PATH
       uses: microsoft/setup-msbuild@v3
     - name: copy dlls to root
       shell: cmd
-      run: compat\vcbuild\vcpkg_copy_dlls.bat release
+      run: lib\compat\vcbuild\vcpkg_copy_dlls.bat release
     - name: generate Visual Studio solution
       shell: bash
       run: |
-        cmake `pwd`/contrib/buildsystems/ -DCMAKE_PREFIX_PATH=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows \
+        cmake `pwd`/contrib/buildsystems/ -DCMAKE_PREFIX_PATH=`pwd`/lib/compat/vcbuild/vcpkg/installed/x64-windows \
         -DNO_GETTEXT=YesPlease -DPERL_TESTS=OFF -DPYTHON_TESTS=OFF -DCURL_NO_CURL_CMAKE=ON
     - name: MSBuild
       run: msbuild git.sln -property:Configuration=Release -property:Platform=x64 -maxCpuCount:4 -property:PlatformToolset=v142
@@ -201,7 +202,7 @@ jobs:
       shell: bash
       env:
         MSVC: 1
-        VCPKG_ROOT: ${{github.workspace}}\compat\vcbuild\vcpkg
+        VCPKG_ROOT: ${{github.workspace}}\lib\compat\vcbuild\vcpkg
       run: |
         mkdir -p artifacts &&
         eval "$(make -n artifacts-tar INCLUDE_DLLS_IN_ARTIFACTS=YesPlease ARTIFACTS_DIRECTORY=artifacts NO_GETTEXT=YesPlease 2>&1 | grep ^tar)"
diff --git a/.gitmodules b/.gitmodules
index cbeebdab7a..8bafb8bb49 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,4 @@
 [submodule "sha1collisiondetection"]
-	path = sha1collisiondetection
+	path = lib/sha1collisiondetection
 	url = https://github.com/cr-marcstevens/sha1collisiondetection.git
 	branch = master
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 2699f0b24a..c4fd5a5c87 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -505,10 +505,10 @@ lint-docs-man-section-order: $(LINT_DOCS_MAN_SECTION_ORDER)
 .PHONY: lint-docs-fsck-msgids
 LINT_DOCS_FSCK_MSGIDS = .build/lint-docs/fsck-msgids.ok
 $(LINT_DOCS_FSCK_MSGIDS): lint-fsck-msgids.perl
-$(LINT_DOCS_FSCK_MSGIDS): ../fsck.h fsck-msgids.adoc
+$(LINT_DOCS_FSCK_MSGIDS): ../lib/fsck.h fsck-msgids.adoc
 	$(call mkdir_p_parent_template)
 	$(QUIET_GEN)$(PERL_PATH) lint-fsck-msgids.perl \
-		../fsck.h fsck-msgids.adoc $@
+		../lib/fsck.h fsck-msgids.adoc $@
 lint-docs-fsck-msgids: $(LINT_DOCS_FSCK_MSGIDS)
 
 ## Lint: delimited sections
diff --git a/Makefile b/Makefile
index 1f3f099f5c..706252558f 100644
--- a/Makefile
+++ b/Makefile
@@ -967,7 +967,7 @@ endif
 CFLAGS = -g -O2 -Wall
 LDFLAGS =
 CC_LD_DYNPATH = -Wl,-rpath,
-BASIC_CFLAGS = -I.
+BASIC_CFLAGS = -I. -Ilib
 BASIC_LDFLAGS =
 
 # library flags
@@ -992,7 +992,7 @@ SANITIZE_LEAK =
 SANITIZE_ADDRESS =
 
 # For the 'coccicheck' target
-SPATCH_INCLUDE_FLAGS = --all-includes $(addprefix -I ,compat ewah refs sha256 trace2 win32 xdiff)
+SPATCH_INCLUDE_FLAGS = --all-includes $(addprefix -I lib/,compat ewah refs sha256 trace2 win32 xdiff)
 SPATCH_FLAGS =
 SPATCH_TEST_FLAGS =
 
@@ -1083,297 +1083,297 @@ FOUND_SOURCE_FILES := $(filter-out $(GENERATED_H),$(shell $(SOURCES_CMD)))
 FOUND_C_SOURCES = $(filter %.c,$(FOUND_SOURCE_FILES))
 FOUND_H_SOURCES = $(filter %.h,$(FOUND_SOURCE_FILES))
 
-COCCI_SOURCES = $(filter-out $(THIRD_PARTY_SOURCES) reftable/%,$(FOUND_C_SOURCES))
+COCCI_SOURCES = $(filter-out $(THIRD_PARTY_SOURCES) lib/reftable/%,$(FOUND_C_SOURCES))
 
 LIB_H = $(FOUND_H_SOURCES)
 
-LIB_OBJS += abspath.o
-LIB_OBJS += add-interactive.o
-LIB_OBJS += add-patch.o
-LIB_OBJS += advice.o
-LIB_OBJS += alias.o
-LIB_OBJS += alloc.o
-LIB_OBJS += apply.o
-LIB_OBJS += archive-tar.o
-LIB_OBJS += archive-zip.o
-LIB_OBJS += archive.o
-LIB_OBJS += attr.o
-LIB_OBJS += base85.o
-LIB_OBJS += bisect.o
-LIB_OBJS += blame.o
-LIB_OBJS += blob.o
-LIB_OBJS += bloom.o
-LIB_OBJS += branch.o
-LIB_OBJS += bundle-uri.o
-LIB_OBJS += bundle.o
-LIB_OBJS += cache-tree.o
-LIB_OBJS += cbtree.o
-LIB_OBJS += chdir-notify.o
-LIB_OBJS += checkout.o
-LIB_OBJS += chunk-format.o
-LIB_OBJS += color.o
-LIB_OBJS += column.o
-LIB_OBJS += combine-diff.o
-LIB_OBJS += commit-graph.o
-LIB_OBJS += commit-reach.o
-LIB_OBJS += commit.o
-LIB_OBJS += common-exit.o
-LIB_OBJS += common-init.o
-LIB_OBJS += compat/nonblock.o
-LIB_OBJS += compat/obstack.o
-LIB_OBJS += compat/open.o
-LIB_OBJS += compat/terminal.o
-LIB_OBJS += compiler-tricks/not-constant.o
-LIB_OBJS += config.o
-LIB_OBJS += connect.o
-LIB_OBJS += connected.o
-LIB_OBJS += convert.o
-LIB_OBJS += copy.o
-LIB_OBJS += credential.o
-LIB_OBJS += csum-file.o
-LIB_OBJS += ctype.o
-LIB_OBJS += date.o
-LIB_OBJS += decorate.o
-LIB_OBJS += delta-islands.o
-LIB_OBJS += diagnose.o
-LIB_OBJS += diff-delta.o
-LIB_OBJS += diff-merges.o
-LIB_OBJS += diff-lib.o
-LIB_OBJS += diff-no-index.o
-LIB_OBJS += diff.o
-LIB_OBJS += diffcore-break.o
-LIB_OBJS += diffcore-delta.o
-LIB_OBJS += diffcore-order.o
-LIB_OBJS += diffcore-pickaxe.o
-LIB_OBJS += diffcore-rename.o
-LIB_OBJS += diffcore-rotate.o
-LIB_OBJS += dir-iterator.o
-LIB_OBJS += dir.o
-LIB_OBJS += editor.o
-LIB_OBJS += entry.o
-LIB_OBJS += environment.o
-LIB_OBJS += ewah/bitmap.o
-LIB_OBJS += ewah/ewah_bitmap.o
-LIB_OBJS += ewah/ewah_io.o
-LIB_OBJS += ewah/ewah_rlw.o
-LIB_OBJS += exec-cmd.o
-LIB_OBJS += fetch-negotiator.o
-LIB_OBJS += fetch-pack.o
-LIB_OBJS += fmt-merge-msg.o
-LIB_OBJS += fsck.o
-LIB_OBJS += fsmonitor.o
-LIB_OBJS += fsmonitor-ipc.o
-LIB_OBJS += fsmonitor-settings.o
-LIB_OBJS += gettext.o
-LIB_OBJS += git-zlib.o
-LIB_OBJS += gpg-interface.o
-LIB_OBJS += graph.o
-LIB_OBJS += grep.o
-LIB_OBJS += hash-lookup.o
-LIB_OBJS += hash.o
-LIB_OBJS += hashmap.o
-LIB_OBJS += help.o
-LIB_OBJS += hex.o
-LIB_OBJS += hex-ll.o
-LIB_OBJS += hook.o
-LIB_OBJS += ident.o
-LIB_OBJS += json-writer.o
-LIB_OBJS += kwset.o
-LIB_OBJS += levenshtein.o
-LIB_OBJS += line-log.o
-LIB_OBJS += line-range.o
-LIB_OBJS += linear-assignment.o
-LIB_OBJS += list-objects-filter-options.o
-LIB_OBJS += list-objects-filter.o
-LIB_OBJS += list-objects.o
-LIB_OBJS += lockfile.o
-LIB_OBJS += log-tree.o
-LIB_OBJS += loose.o
-LIB_OBJS += ls-refs.o
-LIB_OBJS += mailinfo.o
-LIB_OBJS += mailmap.o
-LIB_OBJS += match-trees.o
-LIB_OBJS += mem-pool.o
-LIB_OBJS += merge-blobs.o
-LIB_OBJS += merge-ll.o
-LIB_OBJS += merge-ort.o
-LIB_OBJS += merge-ort-wrappers.o
-LIB_OBJS += merge.o
-LIB_OBJS += midx.o
-LIB_OBJS += midx-write.o
-LIB_OBJS += name-hash.o
-LIB_OBJS += negotiator/default.o
-LIB_OBJS += negotiator/noop.o
-LIB_OBJS += negotiator/skipping.o
-LIB_OBJS += notes-cache.o
-LIB_OBJS += notes-merge.o
-LIB_OBJS += notes-utils.o
-LIB_OBJS += notes.o
-LIB_OBJS += object-file-convert.o
-LIB_OBJS += object-file.o
-LIB_OBJS += object-name.o
-LIB_OBJS += object.o
-LIB_OBJS += odb.o
-LIB_OBJS += odb/source.o
-LIB_OBJS += odb/source-files.o
-LIB_OBJS += odb/source-inmemory.o
-LIB_OBJS += odb/source-loose.o
-LIB_OBJS += odb/source-packed.o
-LIB_OBJS += odb/streaming.o
-LIB_OBJS += odb/transaction.o
-LIB_OBJS += oid-array.o
-LIB_OBJS += oidmap.o
-LIB_OBJS += oidset.o
-LIB_OBJS += oidtree.o
-LIB_OBJS += pack-bitmap-write.o
-LIB_OBJS += pack-bitmap.o
-LIB_OBJS += pack-check.o
-LIB_OBJS += pack-mtimes.o
-LIB_OBJS += pack-objects.o
-LIB_OBJS += pack-refs.o
-LIB_OBJS += pack-revindex.o
-LIB_OBJS += pack-write.o
-LIB_OBJS += packfile.o
-LIB_OBJS += packfile-list.o
-LIB_OBJS += pager.o
-LIB_OBJS += parallel-checkout.o
-LIB_OBJS += parse.o
-LIB_OBJS += parse-options-cb.o
-LIB_OBJS += parse-options.o
-LIB_OBJS += patch-delta.o
-LIB_OBJS += patch-ids.o
-LIB_OBJS += path.o
-LIB_OBJS += path-walk.o
-LIB_OBJS += pathspec.o
-LIB_OBJS += pkt-line.o
-LIB_OBJS += preload-index.o
-LIB_OBJS += pretty.o
-LIB_OBJS += prio-queue.o
-LIB_OBJS += progress.o
-LIB_OBJS += promisor-remote.o
-LIB_OBJS += prompt.o
-LIB_OBJS += protocol.o
-LIB_OBJS += protocol-caps.o
-LIB_OBJS += prune-packed.o
-LIB_OBJS += pseudo-merge.o
-LIB_OBJS += quote.o
-LIB_OBJS += range-diff.o
-LIB_OBJS += reachable.o
-LIB_OBJS += read-cache.o
-LIB_OBJS += rebase-interactive.o
-LIB_OBJS += rebase.o
-LIB_OBJS += ref-filter.o
-LIB_OBJS += reflog-walk.o
-LIB_OBJS += reflog.o
-LIB_OBJS += refs.o
-LIB_OBJS += refs/debug.o
-LIB_OBJS += refs/files-backend.o
-LIB_OBJS += refs/reftable-backend.o
-LIB_OBJS += refs/iterator.o
-LIB_OBJS += refs/packed-backend.o
-LIB_OBJS += refs/ref-cache.o
-LIB_OBJS += refspec.o
-LIB_OBJS += reftable/basics.o
-LIB_OBJS += reftable/block.o
-LIB_OBJS += reftable/blocksource.o
-LIB_OBJS += reftable/error.o
-LIB_OBJS += reftable/fsck.o
-LIB_OBJS += reftable/iter.o
-LIB_OBJS += reftable/merged.o
-LIB_OBJS += reftable/pq.o
-LIB_OBJS += reftable/record.o
-LIB_OBJS += reftable/stack.o
-LIB_OBJS += reftable/system.o
-LIB_OBJS += reftable/table.o
-LIB_OBJS += reftable/tree.o
-LIB_OBJS += reftable/writer.o
-LIB_OBJS += remote.o
-LIB_OBJS += repack.o
-LIB_OBJS += repack-cruft.o
-LIB_OBJS += repack-filtered.o
-LIB_OBJS += repack-geometry.o
-LIB_OBJS += repack-midx.o
-LIB_OBJS += repack-promisor.o
-LIB_OBJS += replace-object.o
-LIB_OBJS += replay.o
-LIB_OBJS += repo-settings.o
-LIB_OBJS += repository.o
-LIB_OBJS += rerere.o
-LIB_OBJS += reset.o
-LIB_OBJS += resolve-undo.o
-LIB_OBJS += revision.o
-LIB_OBJS += run-command.o
-LIB_OBJS += send-pack.o
-LIB_OBJS += sequencer.o
-LIB_OBJS += serve.o
-LIB_OBJS += server-info.o
-LIB_OBJS += setup.o
-LIB_OBJS += shallow.o
-LIB_OBJS += sideband.o
-LIB_OBJS += sigchain.o
-LIB_OBJS += sparse-index.o
-LIB_OBJS += split-index.o
-LIB_OBJS += stable-qsort.o
-LIB_OBJS += statinfo.o
-LIB_OBJS += strbuf.o
-LIB_OBJS += string-list.o
-LIB_OBJS += strmap.o
-LIB_OBJS += strvec.o
-LIB_OBJS += sub-process.o
-LIB_OBJS += submodule-config.o
-LIB_OBJS += submodule.o
-LIB_OBJS += symlinks.o
-LIB_OBJS += tag.o
-LIB_OBJS += tempfile.o
-LIB_OBJS += thread-utils.o
-LIB_OBJS += tmp-objdir.o
-LIB_OBJS += trace.o
-LIB_OBJS += trace2.o
-LIB_OBJS += trace2/tr2_cfg.o
-LIB_OBJS += trace2/tr2_cmd_name.o
-LIB_OBJS += trace2/tr2_ctr.o
-LIB_OBJS += trace2/tr2_dst.o
-LIB_OBJS += trace2/tr2_sid.o
-LIB_OBJS += trace2/tr2_sysenv.o
-LIB_OBJS += trace2/tr2_tbuf.o
-LIB_OBJS += trace2/tr2_tgt_event.o
-LIB_OBJS += trace2/tr2_tgt_normal.o
-LIB_OBJS += trace2/tr2_tgt_perf.o
-LIB_OBJS += trace2/tr2_tls.o
-LIB_OBJS += trace2/tr2_tmr.o
-LIB_OBJS += trailer.o
-LIB_OBJS += transport-helper.o
-LIB_OBJS += transport.o
-LIB_OBJS += tree-diff.o
-LIB_OBJS += tree-walk.o
-LIB_OBJS += tree.o
-LIB_OBJS += unpack-trees.o
-LIB_OBJS += upload-pack.o
-LIB_OBJS += url.o
-LIB_OBJS += urlmatch.o
-LIB_OBJS += usage.o
-LIB_OBJS += userdiff.o
-LIB_OBJS += utf8.o
+LIB_OBJS += lib/abspath.o
+LIB_OBJS += lib/add-interactive.o
+LIB_OBJS += lib/add-patch.o
+LIB_OBJS += lib/advice.o
+LIB_OBJS += lib/alias.o
+LIB_OBJS += lib/alloc.o
+LIB_OBJS += lib/apply.o
+LIB_OBJS += lib/archive-tar.o
+LIB_OBJS += lib/archive-zip.o
+LIB_OBJS += lib/archive.o
+LIB_OBJS += lib/attr.o
+LIB_OBJS += lib/base85.o
+LIB_OBJS += lib/bisect.o
+LIB_OBJS += lib/blame.o
+LIB_OBJS += lib/blob.o
+LIB_OBJS += lib/bloom.o
+LIB_OBJS += lib/branch.o
+LIB_OBJS += lib/bundle-uri.o
+LIB_OBJS += lib/bundle.o
+LIB_OBJS += lib/cache-tree.o
+LIB_OBJS += lib/cbtree.o
+LIB_OBJS += lib/chdir-notify.o
+LIB_OBJS += lib/checkout.o
+LIB_OBJS += lib/chunk-format.o
+LIB_OBJS += lib/color.o
+LIB_OBJS += lib/column.o
+LIB_OBJS += lib/combine-diff.o
+LIB_OBJS += lib/commit-graph.o
+LIB_OBJS += lib/commit-reach.o
+LIB_OBJS += lib/commit.o
+LIB_OBJS += lib/common-exit.o
+LIB_OBJS += lib/common-init.o
+LIB_OBJS += lib/compat/nonblock.o
+LIB_OBJS += lib/compat/obstack.o
+LIB_OBJS += lib/compat/open.o
+LIB_OBJS += lib/compat/terminal.o
+LIB_OBJS += lib/compiler-tricks/not-constant.o
+LIB_OBJS += lib/config.o
+LIB_OBJS += lib/connect.o
+LIB_OBJS += lib/connected.o
+LIB_OBJS += lib/convert.o
+LIB_OBJS += lib/copy.o
+LIB_OBJS += lib/credential.o
+LIB_OBJS += lib/csum-file.o
+LIB_OBJS += lib/ctype.o
+LIB_OBJS += lib/date.o
+LIB_OBJS += lib/decorate.o
+LIB_OBJS += lib/delta-islands.o
+LIB_OBJS += lib/diagnose.o
+LIB_OBJS += lib/diff-delta.o
+LIB_OBJS += lib/diff-merges.o
+LIB_OBJS += lib/diff-lib.o
+LIB_OBJS += lib/diff-no-index.o
+LIB_OBJS += lib/diff.o
+LIB_OBJS += lib/diffcore-break.o
+LIB_OBJS += lib/diffcore-delta.o
+LIB_OBJS += lib/diffcore-order.o
+LIB_OBJS += lib/diffcore-pickaxe.o
+LIB_OBJS += lib/diffcore-rename.o
+LIB_OBJS += lib/diffcore-rotate.o
+LIB_OBJS += lib/dir-iterator.o
+LIB_OBJS += lib/dir.o
+LIB_OBJS += lib/editor.o
+LIB_OBJS += lib/entry.o
+LIB_OBJS += lib/environment.o
+LIB_OBJS += lib/ewah/bitmap.o
+LIB_OBJS += lib/ewah/ewah_bitmap.o
+LIB_OBJS += lib/ewah/ewah_io.o
+LIB_OBJS += lib/ewah/ewah_rlw.o
+LIB_OBJS += lib/exec-cmd.o
+LIB_OBJS += lib/fetch-negotiator.o
+LIB_OBJS += lib/fetch-pack.o
+LIB_OBJS += lib/fmt-merge-msg.o
+LIB_OBJS += lib/fsck.o
+LIB_OBJS += lib/fsmonitor.o
+LIB_OBJS += lib/fsmonitor-ipc.o
+LIB_OBJS += lib/fsmonitor-settings.o
+LIB_OBJS += lib/gettext.o
+LIB_OBJS += lib/git-zlib.o
+LIB_OBJS += lib/gpg-interface.o
+LIB_OBJS += lib/graph.o
+LIB_OBJS += lib/grep.o
+LIB_OBJS += lib/hash-lookup.o
+LIB_OBJS += lib/hash.o
+LIB_OBJS += lib/hashmap.o
+LIB_OBJS += lib/help.o
+LIB_OBJS += lib/hex.o
+LIB_OBJS += lib/hex-ll.o
+LIB_OBJS += lib/hook.o
+LIB_OBJS += lib/ident.o
+LIB_OBJS += lib/json-writer.o
+LIB_OBJS += lib/kwset.o
+LIB_OBJS += lib/levenshtein.o
+LIB_OBJS += lib/line-log.o
+LIB_OBJS += lib/line-range.o
+LIB_OBJS += lib/linear-assignment.o
+LIB_OBJS += lib/list-objects-filter-options.o
+LIB_OBJS += lib/list-objects-filter.o
+LIB_OBJS += lib/list-objects.o
+LIB_OBJS += lib/lockfile.o
+LIB_OBJS += lib/log-tree.o
+LIB_OBJS += lib/loose.o
+LIB_OBJS += lib/ls-refs.o
+LIB_OBJS += lib/mailinfo.o
+LIB_OBJS += lib/mailmap.o
+LIB_OBJS += lib/match-trees.o
+LIB_OBJS += lib/mem-pool.o
+LIB_OBJS += lib/merge-blobs.o
+LIB_OBJS += lib/merge-ll.o
+LIB_OBJS += lib/merge-ort.o
+LIB_OBJS += lib/merge-ort-wrappers.o
+LIB_OBJS += lib/merge.o
+LIB_OBJS += lib/midx.o
+LIB_OBJS += lib/midx-write.o
+LIB_OBJS += lib/name-hash.o
+LIB_OBJS += lib/negotiator/default.o
+LIB_OBJS += lib/negotiator/noop.o
+LIB_OBJS += lib/negotiator/skipping.o
+LIB_OBJS += lib/notes-cache.o
+LIB_OBJS += lib/notes-merge.o
+LIB_OBJS += lib/notes-utils.o
+LIB_OBJS += lib/notes.o
+LIB_OBJS += lib/object-file-convert.o
+LIB_OBJS += lib/object-file.o
+LIB_OBJS += lib/object-name.o
+LIB_OBJS += lib/object.o
+LIB_OBJS += lib/odb.o
+LIB_OBJS += lib/odb/source.o
+LIB_OBJS += lib/odb/source-files.o
+LIB_OBJS += lib/odb/source-inmemory.o
+LIB_OBJS += lib/odb/source-loose.o
+LIB_OBJS += lib/odb/source-packed.o
+LIB_OBJS += lib/odb/streaming.o
+LIB_OBJS += lib/odb/transaction.o
+LIB_OBJS += lib/oid-array.o
+LIB_OBJS += lib/oidmap.o
+LIB_OBJS += lib/oidset.o
+LIB_OBJS += lib/oidtree.o
+LIB_OBJS += lib/pack-bitmap-write.o
+LIB_OBJS += lib/pack-bitmap.o
+LIB_OBJS += lib/pack-check.o
+LIB_OBJS += lib/pack-mtimes.o
+LIB_OBJS += lib/pack-objects.o
+LIB_OBJS += lib/pack-refs.o
+LIB_OBJS += lib/pack-revindex.o
+LIB_OBJS += lib/pack-write.o
+LIB_OBJS += lib/packfile.o
+LIB_OBJS += lib/packfile-list.o
+LIB_OBJS += lib/pager.o
+LIB_OBJS += lib/parallel-checkout.o
+LIB_OBJS += lib/parse.o
+LIB_OBJS += lib/parse-options-cb.o
+LIB_OBJS += lib/parse-options.o
+LIB_OBJS += lib/patch-delta.o
+LIB_OBJS += lib/patch-ids.o
+LIB_OBJS += lib/path.o
+LIB_OBJS += lib/path-walk.o
+LIB_OBJS += lib/pathspec.o
+LIB_OBJS += lib/pkt-line.o
+LIB_OBJS += lib/preload-index.o
+LIB_OBJS += lib/pretty.o
+LIB_OBJS += lib/prio-queue.o
+LIB_OBJS += lib/progress.o
+LIB_OBJS += lib/promisor-remote.o
+LIB_OBJS += lib/prompt.o
+LIB_OBJS += lib/protocol.o
+LIB_OBJS += lib/protocol-caps.o
+LIB_OBJS += lib/prune-packed.o
+LIB_OBJS += lib/pseudo-merge.o
+LIB_OBJS += lib/quote.o
+LIB_OBJS += lib/range-diff.o
+LIB_OBJS += lib/reachable.o
+LIB_OBJS += lib/read-cache.o
+LIB_OBJS += lib/rebase-interactive.o
+LIB_OBJS += lib/rebase.o
+LIB_OBJS += lib/ref-filter.o
+LIB_OBJS += lib/reflog-walk.o
+LIB_OBJS += lib/reflog.o
+LIB_OBJS += lib/refs.o
+LIB_OBJS += lib/refs/debug.o
+LIB_OBJS += lib/refs/files-backend.o
+LIB_OBJS += lib/refs/reftable-backend.o
+LIB_OBJS += lib/refs/iterator.o
+LIB_OBJS += lib/refs/packed-backend.o
+LIB_OBJS += lib/refs/ref-cache.o
+LIB_OBJS += lib/refspec.o
+LIB_OBJS += lib/reftable/basics.o
+LIB_OBJS += lib/reftable/block.o
+LIB_OBJS += lib/reftable/blocksource.o
+LIB_OBJS += lib/reftable/error.o
+LIB_OBJS += lib/reftable/fsck.o
+LIB_OBJS += lib/reftable/iter.o
+LIB_OBJS += lib/reftable/merged.o
+LIB_OBJS += lib/reftable/pq.o
+LIB_OBJS += lib/reftable/record.o
+LIB_OBJS += lib/reftable/stack.o
+LIB_OBJS += lib/reftable/system.o
+LIB_OBJS += lib/reftable/table.o
+LIB_OBJS += lib/reftable/tree.o
+LIB_OBJS += lib/reftable/writer.o
+LIB_OBJS += lib/remote.o
+LIB_OBJS += lib/repack.o
+LIB_OBJS += lib/repack-cruft.o
+LIB_OBJS += lib/repack-filtered.o
+LIB_OBJS += lib/repack-geometry.o
+LIB_OBJS += lib/repack-midx.o
+LIB_OBJS += lib/repack-promisor.o
+LIB_OBJS += lib/replace-object.o
+LIB_OBJS += lib/replay.o
+LIB_OBJS += lib/repo-settings.o
+LIB_OBJS += lib/repository.o
+LIB_OBJS += lib/rerere.o
+LIB_OBJS += lib/reset.o
+LIB_OBJS += lib/resolve-undo.o
+LIB_OBJS += lib/revision.o
+LIB_OBJS += lib/run-command.o
+LIB_OBJS += lib/send-pack.o
+LIB_OBJS += lib/sequencer.o
+LIB_OBJS += lib/serve.o
+LIB_OBJS += lib/server-info.o
+LIB_OBJS += lib/setup.o
+LIB_OBJS += lib/shallow.o
+LIB_OBJS += lib/sideband.o
+LIB_OBJS += lib/sigchain.o
+LIB_OBJS += lib/sparse-index.o
+LIB_OBJS += lib/split-index.o
+LIB_OBJS += lib/stable-qsort.o
+LIB_OBJS += lib/statinfo.o
+LIB_OBJS += lib/strbuf.o
+LIB_OBJS += lib/string-list.o
+LIB_OBJS += lib/strmap.o
+LIB_OBJS += lib/strvec.o
+LIB_OBJS += lib/sub-process.o
+LIB_OBJS += lib/submodule-config.o
+LIB_OBJS += lib/submodule.o
+LIB_OBJS += lib/symlinks.o
+LIB_OBJS += lib/tag.o
+LIB_OBJS += lib/tempfile.o
+LIB_OBJS += lib/thread-utils.o
+LIB_OBJS += lib/tmp-objdir.o
+LIB_OBJS += lib/trace.o
+LIB_OBJS += lib/trace2.o
+LIB_OBJS += lib/trace2/tr2_cfg.o
+LIB_OBJS += lib/trace2/tr2_cmd_name.o
+LIB_OBJS += lib/trace2/tr2_ctr.o
+LIB_OBJS += lib/trace2/tr2_dst.o
+LIB_OBJS += lib/trace2/tr2_sid.o
+LIB_OBJS += lib/trace2/tr2_sysenv.o
+LIB_OBJS += lib/trace2/tr2_tbuf.o
+LIB_OBJS += lib/trace2/tr2_tgt_event.o
+LIB_OBJS += lib/trace2/tr2_tgt_normal.o
+LIB_OBJS += lib/trace2/tr2_tgt_perf.o
+LIB_OBJS += lib/trace2/tr2_tls.o
+LIB_OBJS += lib/trace2/tr2_tmr.o
+LIB_OBJS += lib/trailer.o
+LIB_OBJS += lib/transport-helper.o
+LIB_OBJS += lib/transport.o
+LIB_OBJS += lib/tree-diff.o
+LIB_OBJS += lib/tree-walk.o
+LIB_OBJS += lib/tree.o
+LIB_OBJS += lib/unpack-trees.o
+LIB_OBJS += lib/upload-pack.o
+LIB_OBJS += lib/url.o
+LIB_OBJS += lib/urlmatch.o
+LIB_OBJS += lib/usage.o
+LIB_OBJS += lib/userdiff.o
+LIB_OBJS += lib/utf8.o
 ifdef NO_RUST
-LIB_OBJS += varint.o
-endif
-LIB_OBJS += version.o
-LIB_OBJS += versioncmp.o
-LIB_OBJS += walker.o
-LIB_OBJS += wildmatch.o
-LIB_OBJS += worktree.o
-LIB_OBJS += wrapper.o
-LIB_OBJS += write-or-die.o
-LIB_OBJS += ws.o
-LIB_OBJS += wt-status.o
-LIB_OBJS += xdiff-interface.o
-LIB_OBJS += xdiff/xdiffi.o
-LIB_OBJS += xdiff/xemit.o
-LIB_OBJS += xdiff/xhistogram.o
-LIB_OBJS += xdiff/xmerge.o
-LIB_OBJS += xdiff/xpatience.o
-LIB_OBJS += xdiff/xprepare.o
-LIB_OBJS += xdiff/xutils.o
+LIB_OBJS += lib/varint.o
+endif
+LIB_OBJS += lib/version.o
+LIB_OBJS += lib/versioncmp.o
+LIB_OBJS += lib/walker.o
+LIB_OBJS += lib/wildmatch.o
+LIB_OBJS += lib/worktree.o
+LIB_OBJS += lib/wrapper.o
+LIB_OBJS += lib/write-or-die.o
+LIB_OBJS += lib/ws.o
+LIB_OBJS += lib/wt-status.o
+LIB_OBJS += lib/xdiff-interface.o
+LIB_OBJS += lib/xdiff/xdiffi.o
+LIB_OBJS += lib/xdiff/xemit.o
+LIB_OBJS += lib/xdiff/xhistogram.o
+LIB_OBJS += lib/xdiff/xmerge.o
+LIB_OBJS += lib/xdiff/xpatience.o
+LIB_OBJS += lib/xdiff/xprepare.o
+LIB_OBJS += lib/xdiff/xutils.o
 
 BUILTIN_OBJS += builtin/add.o
 BUILTIN_OBJS += builtin/am.o
@@ -1513,13 +1513,13 @@ BUILTIN_OBJS += builtin/write-tree.o
 # files which are taken from some third-party source where we want to be
 # less strict about issues such as coding style so we don't diverge from
 # upstream unnecessarily (making merging in future changes easier).
-THIRD_PARTY_SOURCES += compat/inet_ntop.c
-THIRD_PARTY_SOURCES += compat/inet_pton.c
-THIRD_PARTY_SOURCES += compat/obstack.%
-THIRD_PARTY_SOURCES += compat/poll/%
-THIRD_PARTY_SOURCES += compat/regex/%
-THIRD_PARTY_SOURCES += sha1collisiondetection/%
-THIRD_PARTY_SOURCES += sha1dc/%
+THIRD_PARTY_SOURCES += lib/compat/inet_ntop.c
+THIRD_PARTY_SOURCES += lib/compat/inet_pton.c
+THIRD_PARTY_SOURCES += lib/compat/obstack.%
+THIRD_PARTY_SOURCES += lib/compat/poll/%
+THIRD_PARTY_SOURCES += lib/compat/regex/%
+THIRD_PARTY_SOURCES += lib/sha1collisiondetection/%
+THIRD_PARTY_SOURCES += lib/sha1dc/%
 THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/%
 THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/%
 
@@ -1750,7 +1750,7 @@ endif
 
 ifdef NO_LIBGEN_H
 	COMPAT_CFLAGS += -DNO_LIBGEN_H
-	COMPAT_OBJS += compat/basename.o
+	COMPAT_OBJS += lib/compat/basename.o
 endif
 
 ifdef USE_LIBPCRE1
@@ -1816,7 +1816,7 @@ else
         endif
         ifdef USE_CURL_FOR_IMAP_SEND
 		BASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND
-		IMAP_SEND_BUILDDEPS = http.o
+		IMAP_SEND_BUILDDEPS = lib/http.o
 		IMAP_SEND_LDFLAGS += $(CURL_LIBCURL)
         endif
         ifndef NO_EXPAT
@@ -1937,11 +1937,11 @@ ifdef NO_NSEC
 endif
 ifdef SNPRINTF_RETURNS_BOGUS
 	COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
-	COMPAT_OBJS += compat/snprintf.o
+	COMPAT_OBJS += lib/compat/snprintf.o
 endif
 ifdef FREAD_READS_DIRECTORIES
 	COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
-	COMPAT_OBJS += compat/fopen.o
+	COMPAT_OBJS += lib/compat/fopen.o
 endif
 ifdef OPEN_RETURNS_EINTR
 	COMPAT_CFLAGS += -DOPEN_RETURNS_EINTR
@@ -1956,38 +1956,38 @@ endif
 ifdef NO_POLL
 	NO_POLL_H = YesPlease
 	NO_SYS_POLL_H = YesPlease
-	COMPAT_CFLAGS += -DNO_POLL -Icompat/poll
-	COMPAT_OBJS += compat/poll/poll.o
+	COMPAT_CFLAGS += -DNO_POLL -Ilib/compat/poll
+	COMPAT_OBJS += lib/compat/poll/poll.o
 endif
 ifdef NO_STRCASESTR
 	COMPAT_CFLAGS += -DNO_STRCASESTR
-	COMPAT_OBJS += compat/strcasestr.o
+	COMPAT_OBJS += lib/compat/strcasestr.o
 endif
 ifdef NO_STRLCPY
 	COMPAT_CFLAGS += -DNO_STRLCPY
-	COMPAT_OBJS += compat/strlcpy.o
+	COMPAT_OBJS += lib/compat/strlcpy.o
 endif
 ifdef NO_STRTOUMAX
 	COMPAT_CFLAGS += -DNO_STRTOUMAX
-	COMPAT_OBJS += compat/strtoumax.o compat/strtoimax.o
+	COMPAT_OBJS += lib/compat/strtoumax.o lib/compat/strtoimax.o
 endif
 ifdef NO_STRTOULL
 	COMPAT_CFLAGS += -DNO_STRTOULL
 endif
 ifdef NO_SETENV
 	COMPAT_CFLAGS += -DNO_SETENV
-	COMPAT_OBJS += compat/setenv.o
+	COMPAT_OBJS += lib/compat/setenv.o
 endif
 ifdef NO_MKDTEMP
 	COMPAT_CFLAGS += -DNO_MKDTEMP
 endif
 ifdef MKDIR_WO_TRAILING_SLASH
 	COMPAT_CFLAGS += -DMKDIR_WO_TRAILING_SLASH
-	COMPAT_OBJS += compat/mkdir.o
+	COMPAT_OBJS += lib/compat/mkdir.o
 endif
 ifdef NO_UNSETENV
 	COMPAT_CFLAGS += -DNO_UNSETENV
-	COMPAT_OBJS += compat/unsetenv.o
+	COMPAT_OBJS += lib/compat/unsetenv.o
 endif
 ifdef NO_SYS_SELECT_H
 	BASIC_CFLAGS += -DNO_SYS_SELECT_H
@@ -2009,11 +2009,11 @@ ifdef NO_INITGROUPS
 endif
 ifdef NO_MMAP
 	COMPAT_CFLAGS += -DNO_MMAP
-	COMPAT_OBJS += compat/mmap.o
+	COMPAT_OBJS += lib/compat/mmap.o
 else
         ifdef USE_WIN32_MMAP
 		COMPAT_CFLAGS += -DUSE_WIN32_MMAP
-		COMPAT_OBJS += compat/win32mmap.o
+		COMPAT_OBJS += lib/compat/win32mmap.o
         endif
 endif
 ifdef MMAP_PREVENTS_DELETE
@@ -2031,7 +2031,7 @@ ifdef NO_SETITIMER
 endif
 ifdef NO_PREAD
 	COMPAT_CFLAGS += -DNO_PREAD
-	COMPAT_OBJS += compat/pread.o
+	COMPAT_OBJS += lib/compat/pread.o
 endif
 ifdef NO_FAST_WORKING_DIRECTORY
 	BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
@@ -2041,7 +2041,7 @@ ifdef NO_TRUSTABLE_FILEMODE
 endif
 ifdef NEEDS_MODE_TRANSLATION
 	COMPAT_CFLAGS += -DNEEDS_MODE_TRANSLATION
-	COMPAT_OBJS += compat/stat.o
+	COMPAT_OBJS += lib/compat/stat.o
 endif
 ifdef NO_IPV6
 	BASIC_CFLAGS += -DNO_IPV6
@@ -2057,18 +2057,18 @@ else
 endif
 endif
 ifdef NO_INET_NTOP
-	LIB_OBJS += compat/inet_ntop.o
+	LIB_OBJS += lib/compat/inet_ntop.o
 	BASIC_CFLAGS += -DNO_INET_NTOP
 endif
 ifdef NO_INET_PTON
-	LIB_OBJS += compat/inet_pton.o
+	LIB_OBJS += lib/compat/inet_pton.o
 	BASIC_CFLAGS += -DNO_INET_PTON
 endif
 ifdef NO_UNIX_SOCKETS
 	BASIC_CFLAGS += -DNO_UNIX_SOCKETS
 else
-	LIB_OBJS += unix-socket.o
-	LIB_OBJS += unix-stream-server.o
+	LIB_OBJS += lib/unix-socket.o
+	LIB_OBJS += lib/unix-stream-server.o
 endif
 
 # Simple IPC requires threads and platform-specific IPC support.
@@ -2084,14 +2084,14 @@ endif
 #
 ifdef USE_WIN32_IPC
 	BASIC_CFLAGS += -DSUPPORTS_SIMPLE_IPC
-	LIB_OBJS += compat/simple-ipc/ipc-shared.o
-	LIB_OBJS += compat/simple-ipc/ipc-win32.o
+	LIB_OBJS += lib/compat/simple-ipc/ipc-shared.o
+	LIB_OBJS += lib/compat/simple-ipc/ipc-win32.o
 else
 ifndef NO_PTHREADS
 ifndef NO_UNIX_SOCKETS
 	BASIC_CFLAGS += -DSUPPORTS_SIMPLE_IPC
-	LIB_OBJS += compat/simple-ipc/ipc-shared.o
-	LIB_OBJS += compat/simple-ipc/ipc-unix-socket.o
+	LIB_OBJS += lib/compat/simple-ipc/ipc-shared.o
+	LIB_OBJS += lib/compat/simple-ipc/ipc-unix-socket.o
 endif
 endif
 endif
@@ -2126,7 +2126,7 @@ ifdef OPENSSL_SHA1
 	BASIC_CFLAGS += -DSHA1_OPENSSL
 else
 ifdef BLK_SHA1
-	LIB_OBJS += block-sha1/sha1.o
+	LIB_OBJS += lib/block-sha1/sha1.o
 	BASIC_CFLAGS += -DSHA1_BLK
 else
 ifdef APPLE_COMMON_CRYPTO_SHA1
@@ -2134,7 +2134,7 @@ ifdef APPLE_COMMON_CRYPTO_SHA1
 	BASIC_CFLAGS += -DSHA1_APPLE
 else
 	BASIC_CFLAGS += -DSHA1_DC
-	LIB_OBJS += sha1dc_git.o
+	LIB_OBJS += lib/sha1dc_git.o
 ifdef DC_SHA1_EXTERNAL
         ifdef DC_SHA1_SUBMODULE
                 ifneq ($(DC_SHA1_SUBMODULE),auto)
@@ -2145,12 +2145,12 @@ $(error Only set DC_SHA1_EXTERNAL or DC_SHA1_SUBMODULE, not both)
 	EXTLIBS += -lsha1detectcoll
 else
 ifdef DC_SHA1_SUBMODULE
-	LIB_OBJS += sha1collisiondetection/lib/sha1.o
-	LIB_OBJS += sha1collisiondetection/lib/ubc_check.o
+	LIB_OBJS += lib/sha1collisiondetection/lib/sha1.o
+	LIB_OBJS += lib/sha1collisiondetection/lib/ubc_check.o
 	BASIC_CFLAGS += -DDC_SHA1_SUBMODULE
 else
-	LIB_OBJS += sha1dc/sha1.o
-	LIB_OBJS += sha1dc/ubc_check.o
+	LIB_OBJS += lib/sha1dc/sha1.o
+	LIB_OBJS += lib/sha1dc/ubc_check.o
 endif
 	BASIC_CFLAGS += \
 		-DSHA1DC_NO_STANDARD_INCLUDES \
@@ -2170,7 +2170,7 @@ endif
 else
 ifdef BLK_SHA1_UNSAFE
 ifndef BLK_SHA1
-	LIB_OBJS += block-sha1/sha1.o
+	LIB_OBJS += lib/block-sha1/sha1.o
 	BASIC_CFLAGS += -DSHA1_BLK_UNSAFE
 endif
 else
@@ -2195,23 +2195,23 @@ ifdef GCRYPT_SHA256
 	BASIC_CFLAGS += -DSHA256_GCRYPT
 	EXTLIBS += -lgcrypt
 else
-	LIB_OBJS += sha256/block/sha256.o
+	LIB_OBJS += lib/sha256/block/sha256.o
 	BASIC_CFLAGS += -DSHA256_BLK
 endif
 endif
 endif
 
 ifdef SHA1_MAX_BLOCK_SIZE
-	LIB_OBJS += compat/sha1-chunked.o
+	LIB_OBJS += lib/compat/sha1-chunked.o
 	BASIC_CFLAGS += -DSHA1_MAX_BLOCK_SIZE="$(SHA1_MAX_BLOCK_SIZE)"
 endif
 ifdef NO_HSTRERROR
 	COMPAT_CFLAGS += -DNO_HSTRERROR
-	COMPAT_OBJS += compat/hstrerror.o
+	COMPAT_OBJS += lib/compat/hstrerror.o
 endif
 ifdef NO_MEMMEM
 	COMPAT_CFLAGS += -DNO_MEMMEM
-	COMPAT_OBJS += compat/memmem.o
+	COMPAT_OBJS += lib/compat/memmem.o
 endif
 ifdef NO_GETPAGESIZE
 	COMPAT_CFLAGS += -DNO_GETPAGESIZE
@@ -2222,7 +2222,7 @@ endif
 ifdef HAVE_ISO_QSORT_S
 	COMPAT_CFLAGS += -DHAVE_ISO_QSORT_S
 else
-	COMPAT_OBJS += compat/qsort_s.o
+	COMPAT_OBJS += lib/compat/qsort_s.o
 endif
 ifdef RUNTIME_PREFIX
 	COMPAT_CFLAGS += -DRUNTIME_PREFIX
@@ -2259,12 +2259,12 @@ ifdef UNRELIABLE_FSTAT
 	BASIC_CFLAGS += -DUNRELIABLE_FSTAT
 endif
 ifdef NO_REGEX
-	COMPAT_CFLAGS += -Icompat/regex
-	COMPAT_OBJS += compat/regex/regex.o
+	COMPAT_CFLAGS += -Ilib/compat/regex
+	COMPAT_OBJS += lib/compat/regex/regex.o
 else
 ifdef USE_ENHANCED_BASIC_REGULAR_EXPRESSIONS
 	COMPAT_CFLAGS += -DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS
-	COMPAT_OBJS += compat/regcomp_enhanced.o
+	COMPAT_OBJS += lib/compat/regcomp_enhanced.o
 endif
 endif
 ifdef NATIVE_CRLF
@@ -2273,7 +2273,7 @@ endif
 
 ifdef OVERRIDE_STRDUP
 	COMPAT_CFLAGS += -DOVERRIDE_STRDUP
-	COMPAT_OBJS += compat/strdup.o
+	COMPAT_OBJS += lib/compat/strdup.o
 endif
 
 ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
@@ -2335,7 +2335,7 @@ ifneq ($(findstring openssl,$(CSPRNG_METHOD)),)
 endif
 
 ifndef HAVE_PLATFORM_PROCINFO
-	COMPAT_OBJS += compat/stub/procinfo.o
+	COMPAT_OBJS += lib/compat/stub/procinfo.o
 endif
 
 ifdef RUNTIME_PREFIX
@@ -2365,25 +2365,25 @@ endif
 
 ifdef FILENO_IS_A_MACRO
 	COMPAT_CFLAGS += -DFILENO_IS_A_MACRO
-	COMPAT_OBJS += compat/fileno.o
+	COMPAT_OBJS += lib/compat/fileno.o
 endif
 
 ifdef NEED_ACCESS_ROOT_HANDLER
 	COMPAT_CFLAGS += -DNEED_ACCESS_ROOT_HANDLER
-	COMPAT_OBJS += compat/access.o
+	COMPAT_OBJS += lib/compat/access.o
 endif
 
 ifdef FSMONITOR_DAEMON_BACKEND
 	COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
-	COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
-	COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+	COMPAT_OBJS += lib/compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
+	COMPAT_OBJS += lib/compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
 endif
 
 ifdef FSMONITOR_OS_SETTINGS
 	COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
-	COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_OS_SETTINGS).o
-	COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
-	COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_DAEMON_BACKEND).o
+	COMPAT_OBJS += lib/compat/fsmonitor/fsm-ipc-$(FSMONITOR_OS_SETTINGS).o
+	COMPAT_OBJS += lib/compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+	COMPAT_OBJS += lib/compat/fsmonitor/fsm-path-utils-$(FSMONITOR_DAEMON_BACKEND).o
 endif
 
 ifdef WITH_BREAKING_CHANGES
@@ -2667,9 +2667,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
 		$(filter %.o,$^) $(LIBS)
 
-help.sp help.s help.o: command-list.h
+lib/help.sp lib/help.s lib/help.o: command-list.h
 builtin/bugreport.sp builtin/bugreport.s builtin/bugreport.o: hook-list.h
-hook.sp hook.s hook.o: hook-list.h
+lib/hook.sp lib/hook.s lib/hook.o: hook-list.h
 
 builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX
 builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
@@ -2680,13 +2680,13 @@ builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
 PAGER_ENV_SQ = $(subst ','\'',$(PAGER_ENV))
 PAGER_ENV_CQ = "$(subst ",\",$(subst \,\\,$(PAGER_ENV)))"
 PAGER_ENV_CQ_SQ = $(subst ','\'',$(PAGER_ENV_CQ))
-pager.sp pager.s pager.o: EXTRA_CPPFLAGS = \
+lib/pager.sp lib/pager.s lib/pager.o: EXTRA_CPPFLAGS = \
 	-DPAGER_ENV='$(PAGER_ENV_CQ_SQ)'
 
-version-def.h: version-def.h.in GIT-VERSION-GEN GIT-VERSION-FILE GIT-USER-AGENT
+version-def.h: lib/version-def.h.in GIT-VERSION-GEN GIT-VERSION-FILE GIT-USER-AGENT
 	$(QUIET_GEN)$(call version_gen,"$(shell pwd)",$<,$@)
 
-version.sp version.s version.o: version-def.h
+lib/version.sp lib/version.s lib/version.o: version-def.h
 
 $(BUILT_INS): git$X
 	$(QUIET_BUILT_IN)$(RM) $@ && \
@@ -2879,7 +2879,7 @@ ifdef INCLUDE_LIBGIT_RS
 endif
 
 ifndef NO_CURL
-	OBJECTS += http.o http-walker.o remote-curl.o
+	OBJECTS += lib/http.o lib/http-walker.o remote-curl.o
 endif
 
 .PHONY: objects
@@ -2944,44 +2944,44 @@ compile_commands.json:
 	@if test -s $@+; then mv $@+ $@; else $(RM) $@+; fi
 endif
 
-exec-cmd.sp exec-cmd.s exec-cmd.o: GIT-PREFIX
-exec-cmd.sp exec-cmd.s exec-cmd.o: EXTRA_CPPFLAGS = \
+lib/exec-cmd.sp lib/exec-cmd.s lib/exec-cmd.o: GIT-PREFIX
+lib/exec-cmd.sp lib/exec-cmd.s lib/exec-cmd.o: EXTRA_CPPFLAGS = \
 	'-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
 	'-DGIT_LOCALE_PATH="$(localedir_relative_SQ)"' \
 	'-DBINDIR="$(bindir_relative_SQ)"' \
 	'-DFALLBACK_RUNTIME_PREFIX="$(prefix_SQ)"'
 
-setup.sp setup.s setup.o: GIT-PREFIX
-setup.sp setup.s setup.o: EXTRA_CPPFLAGS = \
+lib/setup.sp lib/setup.s lib/setup.o: GIT-PREFIX
+lib/setup.sp lib/setup.s lib/setup.o: EXTRA_CPPFLAGS = \
 	-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
 
-config.sp config.s config.o: GIT-PREFIX
-config.sp config.s config.o: EXTRA_CPPFLAGS = \
+lib/config.sp lib/config.s lib/config.o: GIT-PREFIX
+lib/config.sp lib/config.s lib/config.o: EXTRA_CPPFLAGS = \
 	-DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
 
-attr.sp attr.s attr.o: GIT-PREFIX
-attr.sp attr.s attr.o: EXTRA_CPPFLAGS = \
+lib/attr.sp lib/attr.s lib/attr.o: GIT-PREFIX
+lib/attr.sp lib/attr.s lib/attr.o: EXTRA_CPPFLAGS = \
 	-DETC_GITATTRIBUTES='"$(ETC_GITATTRIBUTES_SQ)"'
 
-gettext.sp gettext.s gettext.o: GIT-PREFIX
-gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
+lib/gettext.sp lib/gettext.s lib/gettext.o: GIT-PREFIX
+lib/gettext.sp lib/gettext.s lib/gettext.o: EXTRA_CPPFLAGS = \
 	-DGIT_LOCALE_PATH='"$(localedir_relative_SQ)"'
 
-http-push.sp http.sp http-walker.sp remote-curl.sp imap-send.sp: SP_EXTRA_FLAGS += \
+http-push.sp lib/http.sp lib/http-walker.sp remote-curl.sp imap-send.sp: SP_EXTRA_FLAGS += \
 	-DCURL_DISABLE_TYPECHECK
 
-pack-revindex.sp: SP_EXTRA_FLAGS += -Wno-memcpy-max-count
+lib/pack-revindex.sp: SP_EXTRA_FLAGS += -Wno-memcpy-max-count
 
 ifdef NO_EXPAT
-http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
+lib/http-walker.sp lib/http-walker.s lib/http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
 endif
 
 ifdef NO_REGEX
-compat/regex/regex.sp compat/regex/regex.o: EXTRA_CPPFLAGS = \
+lib/compat/regex/regex.sp lib/compat/regex/regex.o: EXTRA_CPPFLAGS = \
 	-DGAWK -DNO_MBSUPPORT
 endif
 
-headless-git.o: compat/win32/headless.c GIT-CFLAGS
+headless-git.o: lib/compat/win32/headless.c GIT-CFLAGS
 	$(QUIET_CC)$(CC) $(ALL_CFLAGS) $(COMPAT_CFLAGS) \
 		-fno-stack-protector -o $@ -c -Wall -Wwrite-strings $<
 
@@ -2995,10 +2995,10 @@ git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(IMAP_SEND_LDFLAGS) $(LIBS)
 
-git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
+git-http-fetch$X: lib/http.o lib/http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(CURL_LIBCURL) $(LIBS)
-git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS)
+git-http-push$X: lib/http.o http-push.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
 
@@ -3008,7 +3008,7 @@ $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
 	ln -s $< $@ 2>/dev/null || \
 	cp $< $@
 
-$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS $(GITLIBS)
+$(REMOTE_CURL_PRIMARY): remote-curl.o lib/http.o lib/http-walker.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
 
@@ -3172,8 +3172,8 @@ LOCALIZED_C_CORE += builtin/clone.c
 LOCALIZED_C_CORE += builtin/index-pack.c
 LOCALIZED_C_CORE += builtin/push.c
 LOCALIZED_C_CORE += builtin/reset.c
-LOCALIZED_C_CORE += remote.c
-LOCALIZED_C_CORE += wt-status.c
+LOCALIZED_C_CORE += lib/remote.c
+LOCALIZED_C_CORE += lib/wt-status.c
 
 LOCALIZED_C_CORE_GEN_PO = $(LOCALIZED_C_CORE:%=.build/pot/po/%.po)
 
@@ -3412,18 +3412,18 @@ $(SP_OBJ): %.sp: %.c %.o $(GENERATED_H)
 .PHONY: sparse
 sparse: $(SP_OBJ)
 
-EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/% $(UNIT_TEST_DIR)/clar/% $(UNIT_TEST_DIR)/clar/clar/%
+EXCEPT_HDRS := $(GENERATED_H) lib/unicode-width.h lib/compat/% lib/xdiff/% $(UNIT_TEST_DIR)/clar/% $(UNIT_TEST_DIR)/clar/clar/%
 ifndef OPENSSL_SHA1
-	EXCEPT_HDRS += sha1/openssl.h
+	EXCEPT_HDRS += lib/sha1/openssl.h
 endif
 ifndef OPENSSL_SHA256
-	EXCEPT_HDRS += sha256/openssl.h
+	EXCEPT_HDRS += lib/sha256/openssl.h
 endif
 ifndef NETTLE_SHA256
-	EXCEPT_HDRS += sha256/nettle.h
+	EXCEPT_HDRS += lib/sha256/nettle.h
 endif
 ifndef GCRYPT_SHA256
-	EXCEPT_HDRS += sha256/gcrypt.h
+	EXCEPT_HDRS += lib/sha256/gcrypt.h
 endif
 CHK_HDRS = $(filter-out $(EXCEPT_HDRS),$(LIB_H))
 HCO = $(patsubst %.h,%.hco,$(CHK_HDRS))
@@ -3775,13 +3775,13 @@ GIT_ARCHIVE_EXTRA_FILES = \
 	--add-file=.dist-tmp-dir/git-gui/version
 ifdef DC_SHA1_SUBMODULE
 GIT_ARCHIVE_EXTRA_FILES += \
-	--prefix=$(GIT_TARNAME)/sha1collisiondetection/ \
-	--add-file=sha1collisiondetection/LICENSE.txt \
-	--prefix=$(GIT_TARNAME)/sha1collisiondetection/lib/ \
-	--add-file=sha1collisiondetection/lib/sha1.c \
-	--add-file=sha1collisiondetection/lib/sha1.h \
-	--add-file=sha1collisiondetection/lib/ubc_check.c \
-	--add-file=sha1collisiondetection/lib/ubc_check.h
+	--prefix=$(GIT_TARNAME)/lib/sha1collisiondetection/ \
+	--add-file=lib/sha1collisiondetection/LICENSE.txt \
+	--prefix=$(GIT_TARNAME)/lib/sha1collisiondetection/lib/ \
+	--add-file=lib/sha1collisiondetection/lib/sha1.c \
+	--add-file=lib/sha1collisiondetection/lib/sha1.h \
+	--add-file=lib/sha1collisiondetection/lib/ubc_check.c \
+	--add-file=lib/sha1collisiondetection/lib/ubc_check.h
 endif
 dist: git-archive$(X) configure
 	@$(RM) -r .dist-tmp-dir
@@ -3911,7 +3911,7 @@ ifdef MSVC
 	$(RM) $(patsubst %.exe,%.pdb,$(TEST_PROGRAMS))
 	$(RM) $(patsubst %.exe,%.iobj,$(TEST_PROGRAMS))
 	$(RM) $(patsubst %.exe,%.ipdb,$(TEST_PROGRAMS))
-	$(RM) compat/vcbuild/MSVC-DEFS-GEN
+	$(RM) lib/compat/vcbuild/MSVC-DEFS-GEN
 endif
 
 .PHONY: all install profile-clean cocciclean clean strip
diff --git a/config.mak.uname b/config.mak.uname
index 8719e09f66..7af406439e 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -21,17 +21,17 @@ ifdef MSVC
 
 	# Generate and include makefile variables that point to the
 	# currently installed set of MSVC command line tools.
-compat/vcbuild/MSVC-DEFS-GEN: compat/vcbuild/find_vs_env.bat
+lib/compat/vcbuild/MSVC-DEFS-GEN: lib/compat/vcbuild/find_vs_env.bat
 	@"$<" | tr '\\' / >"$@"
-include compat/vcbuild/MSVC-DEFS-GEN
+include lib/compat/vcbuild/MSVC-DEFS-GEN
 
 	# See if vcpkg and the vcpkg-build versions of the third-party
 	# libraries that we use are installed.  We include the result
 	# to get $(vcpkg_*) variables defined for the Makefile.
 ifeq (,$(SKIP_VCPKG))
-compat/vcbuild/VCPKG-DEFS: compat/vcbuild/vcpkg_install.bat
+lib/compat/vcbuild/VCPKG-DEFS: lib/compat/vcbuild/vcpkg_install.bat
 	@"$<"
-include compat/vcbuild/VCPKG-DEFS
+include lib/compat/vcbuild/VCPKG-DEFS
 endif
 endif
 
@@ -62,7 +62,7 @@ ifeq ($(uname_S),Linux)
 	HAVE_SYSINFO = YesPlease
 	PROCFS_EXECUTABLE_PATH = /proc/self/exe
 	HAVE_PLATFORM_PROCINFO = YesPlease
-	COMPAT_OBJS += compat/linux/procinfo.o
+	COMPAT_OBJS += lib/compat/linux/procinfo.o
 	EXTLIBS += -ldl
 	# centos7/rhel7 provides gcc 4.8.5 and zlib 1.2.7.
         ifneq ($(findstring .el7.,$(uname_R)),)
@@ -152,7 +152,7 @@ ifeq ($(uname_S),Darwin)
 	NO_MEMMEM = YesPlease
 	USE_ST_TIMESPEC = YesPlease
 	HAVE_DEV_TTY = YesPlease
-	COMPAT_OBJS += compat/precompose_utf8.o
+	COMPAT_OBJS += lib/compat/precompose_utf8.o
 	BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
 	BASIC_CFLAGS += -DPROTECT_HFS_DEFAULT=1
 	HAVE_BSD_SYSCTL = YesPlease
@@ -161,7 +161,7 @@ ifeq ($(uname_S),Darwin)
 	CSPRNG_METHOD = arc4random
 	USE_ENHANCED_BASIC_REGULAR_EXPRESSIONS = YesPlease
 	HAVE_PLATFORM_PROCINFO = YesPlease
-	COMPAT_OBJS += compat/darwin/procinfo.o
+	COMPAT_OBJS += lib/compat/darwin/procinfo.o
 
         ifeq ($(uname_M),arm64)
 		HOMEBREW_PREFIX = /opt/homebrew
@@ -292,7 +292,7 @@ ifeq ($(uname_O),Cygwin)
 	UNRELIABLE_FSTAT = UnfortunatelyYes
 	OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
 	MMAP_PREVENTS_DELETE = UnfortunatelyYes
-	COMPAT_OBJS += compat/win32/path-utils.o
+	COMPAT_OBJS += lib/compat/win32/path-utils.o
 	FREAD_READS_DIRECTORIES = UnfortunatelyYes
 endif
 ifeq ($(uname_S),FreeBSD)
@@ -523,17 +523,17 @@ ifeq (/mingw64,$(subst 32,64,$(subst clangarm,mingw,$(prefix))))
 	ETC_GITATTRIBUTES = ../etc/gitattributes
 endif
 
-	CC = compat/vcbuild/scripts/clink.pl
-	AR = compat/vcbuild/scripts/lib.pl
+	CC = lib/compat/vcbuild/scripts/clink.pl
+	AR = lib/compat/vcbuild/scripts/lib.pl
 	CFLAGS =
-	BASIC_CFLAGS = -nologo -I. -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
-	COMPAT_OBJS = compat/msvc.o compat/winansi.o \
-		compat/win32/flush.o \
-		compat/win32/path-utils.o \
-		compat/win32/pthread.o compat/win32/syslog.o \
-		compat/win32/trace2_win32_process_info.o \
-		compat/win32/dirent.o
-	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY -DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
+	BASIC_CFLAGS = -nologo -I. -Ilib/compat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
+	COMPAT_OBJS = lib/compat/msvc.o lib/compat/winansi.o \
+		lib/compat/win32/flush.o \
+		lib/compat/win32/path-utils.o \
+		lib/compat/win32/pthread.o lib/compat/win32/syslog.o \
+		lib/compat/win32/trace2_win32_process_info.o \
+		lib/compat/win32/dirent.o
+	COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY -DNOGDI -DHAVE_STRING_H -Ilib/compat -Ilib/compat/regex -Ilib/compat/win32 -DSTRIP_EXTENSION=\".exe\"
 	BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -ENTRY:wmainCRTStartup -SUBSYSTEM:CONSOLE
 	# invalidcontinue.obj allows Git's source code to close the same file
 	# handle twice, or to access the osfhandle of an already-closed stdout
@@ -573,7 +573,7 @@ endif
 
 	EXTRA_PROGRAMS += headless-git$X
 
-compat/msvc.o: compat/msvc.c compat/mingw.c GIT-CFLAGS
+lib/compat/msvc.o: lib/compat/msvc.c lib/compat/mingw.c GIT-CFLAGS
 endif
 ifeq ($(uname_S),Interix)
 	NO_INITGROUPS = YesPlease
@@ -724,14 +724,14 @@ ifeq ($(uname_S),MINGW)
 	HAVE_PLATFORM_PROCINFO = YesPlease
 	CSPRNG_METHOD = rtlgenrandom
 	BASIC_LDFLAGS += -municode
-	COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
+	COMPAT_CFLAGS += -DNOGDI -Ilib/compat -Ilib/compat/win32
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
-	COMPAT_OBJS += compat/mingw.o compat/winansi.o \
-		compat/win32/trace2_win32_process_info.o \
-		compat/win32/flush.o \
-		compat/win32/path-utils.o \
-		compat/win32/pthread.o compat/win32/syslog.o \
-		compat/win32/dirent.o
+	COMPAT_OBJS += lib/compat/mingw.o lib/compat/winansi.o \
+		lib/compat/win32/trace2_win32_process_info.o \
+		lib/compat/win32/flush.o \
+		lib/compat/win32/path-utils.o \
+		lib/compat/win32/pthread.o lib/compat/win32/syslog.o \
+		lib/compat/win32/dirent.o
 	BASIC_CFLAGS += -DWIN32
 	EXTLIBS += -lws2_32
 	GITLIBS += git.res
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index a57c4b464f..446a6c889f 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -62,10 +62,10 @@ if(NOT DEFINED CMAKE_EXPORT_COMPILE_COMMANDS)
 endif()
 
 if(USE_VCPKG)
-	set(VCPKG_DIR "${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg")
+	set(VCPKG_DIR "${CMAKE_SOURCE_DIR}/lib/compat/vcbuild/vcpkg")
 	if(NOT EXISTS ${VCPKG_DIR})
 		message("Initializing vcpkg and building the Git's dependencies (this will take a while...)")
-		execute_process(COMMAND ${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg_install.bat)
+		execute_process(COMMAND ${CMAKE_SOURCE_DIR}/lib/compat/vcbuild/vcpkg_install.bat)
 	endif()
 	list(APPEND CMAKE_PREFIX_PATH "${VCPKG_DIR}/installed/x64-windows")
 
@@ -194,7 +194,7 @@ else()
 	find_program(MSGFMT_EXE msgfmt)
 	if(NOT MSGFMT_EXE)
 		if(USE_VCPKG)
-			set(MSGFMT_EXE ${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg/downloads/tools/msys2/msys64/usr/bin/msgfmt.exe)
+			set(MSGFMT_EXE ${CMAKE_SOURCE_DIR}/lib/compat/vcbuild/vcpkg/downloads/tools/msys2/msys64/usr/bin/msgfmt.exe)
 		endif()
 		if(NOT EXISTS ${MSGFMT_EXE})
 			message(WARNING "Text Translations won't be built")
@@ -212,13 +212,14 @@ endif()
 
 #default behaviour
 include_directories(${CMAKE_SOURCE_DIR})
+include_directories(${CMAKE_SOURCE_DIR}/lib)
 add_compile_definitions(GIT_HOST_CPU="${CMAKE_SYSTEM_PROCESSOR}")
 add_compile_definitions(SHA256_BLK INTERNAL_QSORT RUNTIME_PREFIX)
 add_compile_definitions(NO_OPENSSL SHA1_DC SHA1DC_NO_STANDARD_INCLUDES
 			SHA1DC_INIT_SAFE_HASH_DEFAULT=0
 			SHA1DC_CUSTOM_INCLUDE_SHA1_C="git-compat-util.h"
 			SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="git-compat-util.h" )
-list(APPEND compat_SOURCES sha1dc_git.c sha1dc/sha1.c sha1dc/ubc_check.c block-sha1/sha1.c sha256/block/sha256.c compat/qsort_s.c)
+list(APPEND compat_SOURCES lib/sha1dc_git.c lib/sha1dc/sha1.c lib/sha1dc/ubc_check.c lib/block-sha1/sha1.c lib/sha256/block/sha256.c lib/compat/qsort_s.c)
 
 
 add_compile_definitions(PAGER_ENV="LESS=FRX LV=-c"
@@ -248,43 +249,43 @@ endif()
 #Platform Specific
 if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
 	if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
-		include_directories(${CMAKE_SOURCE_DIR}/compat/vcbuild/include)
+		include_directories(${CMAKE_SOURCE_DIR}/lib/compat/vcbuild/include)
 		add_compile_definitions(_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
 	endif()
-	include_directories(${CMAKE_SOURCE_DIR}/compat/win32)
+	include_directories(${CMAKE_SOURCE_DIR}/lib/compat/win32)
 	add_compile_definitions(HAVE_ALLOCA_H NO_POSIX_GOODIES NATIVE_CRLF NO_UNIX_SOCKETS WIN32
 				_CONSOLE DETECT_MSYS_TTY STRIP_EXTENSION=".exe"  NO_SYMLINK_HEAD UNRELIABLE_FSTAT
 				NOGDI OBJECT_CREATION_MODE=1 __USE_MINGW_ANSI_STDIO=0
 				OVERRIDE_STRDUP MMAP_PREVENTS_DELETE USE_WIN32_MMAP
 				HAVE_WPGMPTR ENSURE_MSYSTEM_IS_SET HAVE_RTLGENRANDOM)
 	list(APPEND compat_SOURCES
-		compat/mingw.c
-		compat/winansi.c
-		compat/win32/flush.c
-		compat/win32/path-utils.c
-		compat/win32/pthread.c
-		compat/win32mmap.c
-		compat/win32/syslog.c
-		compat/win32/trace2_win32_process_info.c
-		compat/win32/dirent.c
-		compat/strdup.c)
+		lib/compat/mingw.c
+		lib/compat/winansi.c
+		lib/compat/win32/flush.c
+		lib/compat/win32/path-utils.c
+		lib/compat/win32/pthread.c
+		lib/compat/win32mmap.c
+		lib/compat/win32/syslog.c
+		lib/compat/win32/trace2_win32_process_info.c
+		lib/compat/win32/dirent.c
+		lib/compat/strdup.c)
 	set(NO_UNIX_SOCKETS 1)
 
 elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
 	add_compile_definitions(PROCFS_EXECUTABLE_PATH="/proc/self/exe" HAVE_DEV_TTY )
-	list(APPEND compat_SOURCES unix-socket.c unix-stream-server.c compat/linux/procinfo.c)
+	list(APPEND compat_SOURCES lib/unix-socket.c lib/unix-stream-server.c lib/compat/linux/procinfo.c)
 elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
-	list(APPEND compat_SOURCES compat/darwin/procinfo.c)
+	list(APPEND compat_SOURCES lib/compat/darwin/procinfo.c)
 endif()
 
 if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
-	list(APPEND compat_SOURCES compat/simple-ipc/ipc-shared.c compat/simple-ipc/ipc-win32.c)
+	list(APPEND compat_SOURCES lib/compat/simple-ipc/ipc-shared.c lib/compat/simple-ipc/ipc-win32.c)
 	add_compile_definitions(SUPPORTS_SIMPLE_IPC)
 	set(SUPPORTS_SIMPLE_IPC 1)
 else()
 	# Simple IPC requires both Unix sockets and pthreads on Unix-based systems.
 	if(NOT NO_UNIX_SOCKETS AND NOT NO_PTHREADS)
-		list(APPEND compat_SOURCES compat/simple-ipc/ipc-shared.c compat/simple-ipc/ipc-unix-socket.c)
+		list(APPEND compat_SOURCES lib/compat/simple-ipc/ipc-shared.c lib/compat/simple-ipc/ipc-unix-socket.c)
 		add_compile_definitions(SUPPORTS_SIMPLE_IPC)
 		set(SUPPORTS_SIMPLE_IPC 1)
 	endif()
@@ -305,13 +306,13 @@ if(SUPPORTS_SIMPLE_IPC)
 
 	if(FSMONITOR_DAEMON_BACKEND)
 		add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
-		list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-${FSMONITOR_DAEMON_BACKEND}.c)
-		list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-${FSMONITOR_DAEMON_BACKEND}.c)
-		list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-${FSMONITOR_OS_SETTINGS}.c)
-		list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-${FSMONITOR_DAEMON_BACKEND}.c)
+		list(APPEND compat_SOURCES lib/compat/fsmonitor/fsm-listen-${FSMONITOR_DAEMON_BACKEND}.c)
+		list(APPEND compat_SOURCES lib/compat/fsmonitor/fsm-health-${FSMONITOR_DAEMON_BACKEND}.c)
+		list(APPEND compat_SOURCES lib/compat/fsmonitor/fsm-ipc-${FSMONITOR_OS_SETTINGS}.c)
+		list(APPEND compat_SOURCES lib/compat/fsmonitor/fsm-path-utils-${FSMONITOR_DAEMON_BACKEND}.c)
 
 		add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
-		list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-${FSMONITOR_OS_SETTINGS}.c)
+		list(APPEND compat_SOURCES lib/compat/fsmonitor/fsm-settings-${FSMONITOR_OS_SETTINGS}.c)
 	endif()
 endif()
 
@@ -321,7 +322,7 @@ set(EXE_EXTENSION ${CMAKE_EXECUTABLE_SUFFIX})
 check_include_file(libgen.h HAVE_LIBGEN_H)
 if(NOT HAVE_LIBGEN_H)
 	add_compile_definitions(NO_LIBGEN_H)
-	list(APPEND compat_SOURCES compat/basename.c)
+	list(APPEND compat_SOURCES lib/compat/basename.c)
 endif()
 
 check_include_file(sys/sysinfo.h HAVE_SYSINFO)
@@ -394,42 +395,42 @@ foreach(f ${function_checks})
 endforeach()
 
 if(NOT HAVE_POLL_H OR NOT HAVE_SYS_POLL_H OR NOT HAVE_POLL)
-	include_directories(${CMAKE_SOURCE_DIR}/compat/poll)
+	include_directories(${CMAKE_SOURCE_DIR}/lib/compat/poll)
 	add_compile_definitions(NO_POLL)
-	list(APPEND compat_SOURCES compat/poll/poll.c)
+	list(APPEND compat_SOURCES lib/compat/poll/poll.c)
 endif()
 
 if(NOT HAVE_STRCASESTR)
-	list(APPEND compat_SOURCES compat/strcasestr.c)
+	list(APPEND compat_SOURCES lib/compat/strcasestr.c)
 endif()
 
 if(NOT HAVE_STRLCPY)
-	list(APPEND compat_SOURCES compat/strlcpy.c)
+	list(APPEND compat_SOURCES lib/compat/strlcpy.c)
 endif()
 
 if(NOT HAVE_STRTOUMAX)
-	list(APPEND compat_SOURCES compat/strtoumax.c compat/strtoimax.c)
+	list(APPEND compat_SOURCES lib/compat/strtoumax.c lib/compat/strtoimax.c)
 endif()
 
 if(NOT HAVE_SETENV)
-	list(APPEND compat_SOURCES compat/setenv.c)
+	list(APPEND compat_SOURCES lib/compat/setenv.c)
 endif()
 
 if(NOT HAVE_PREAD)
-	list(APPEND compat_SOURCES compat/pread.c)
+	list(APPEND compat_SOURCES lib/compat/pread.c)
 endif()
 
 if(NOT HAVE_MEMMEM)
-	list(APPEND compat_SOURCES compat/memmem.c)
+	list(APPEND compat_SOURCES lib/compat/memmem.c)
 endif()
 
 if(NOT WIN32)
 	if(NOT HAVE_UNSETENV)
-		list(APPEND compat_SOURCES compat/unsetenv.c)
+		list(APPEND compat_SOURCES lib/compat/unsetenv.c)
 	endif()
 
 	if(NOT HAVE_HSTRERROR)
-		list(APPEND compat_SOURCES compat/hstrerror.c)
+		list(APPEND compat_SOURCES lib/compat/hstrerror.c)
 	endif()
 endif()
 
@@ -486,7 +487,7 @@ int main(void)
 SNPRINTF_OK)
 if(NOT SNPRINTF_OK)
 	add_compile_definitions(SNPRINTF_RETURNS_BOGUS)
-	list(APPEND compat_SOURCES compat/snprintf.c)
+	list(APPEND compat_SOURCES lib/compat/snprintf.c)
 endif()
 
 check_c_source_runs("
@@ -501,7 +502,7 @@ int main(void)
 FREAD_READS_DIRECTORIES_NO)
 if(NOT FREAD_READS_DIRECTORIES_NO)
 	add_compile_definitions(FREAD_READS_DIRECTORIES)
-	list(APPEND compat_SOURCES compat/fopen.c)
+	list(APPEND compat_SOURCES lib/compat/fopen.c)
 endif()
 
 check_c_source_compiles("
@@ -516,8 +517,8 @@ int main(void)
 }"
 HAVE_REGEX)
 if(NOT HAVE_REGEX)
-	include_directories(${CMAKE_SOURCE_DIR}/compat/regex)
-	list(APPEND compat_SOURCES compat/regex/regex.c )
+	include_directories(${CMAKE_SOURCE_DIR}/lib/compat/regex)
+	list(APPEND compat_SOURCES lib/compat/regex/regex.c )
 	add_compile_definitions(NO_REGEX NO_MBSUPPORT GAWK)
 endif()
 
@@ -670,10 +671,10 @@ list(TRANSFORM compat_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
 add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/version-def.h"
 	COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
 		"${CMAKE_SOURCE_DIR}"
-		"${CMAKE_SOURCE_DIR}/version-def.h.in"
+		"${CMAKE_SOURCE_DIR}/lib/version-def.h.in"
 		"${CMAKE_BINARY_DIR}/version-def.h"
 	DEPENDS "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN"
-		"${CMAKE_SOURCE_DIR}/version-def.h.in"
+		"${CMAKE_SOURCE_DIR}/lib/version-def.h.in"
 	VERBATIM)
 list(APPEND libgit_SOURCES "${CMAKE_BINARY_DIR}/version-def.h")
 
@@ -732,7 +733,7 @@ if(WIN32)
 		message(FATAL_ERROR "Unhandled compiler: ${CMAKE_C_COMPILER_ID}")
 	endif()
 
-	add_executable(headless-git ${CMAKE_SOURCE_DIR}/compat/win32/headless.c)
+	add_executable(headless-git ${CMAKE_SOURCE_DIR}/lib/compat/win32/headless.c)
 	if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
 		target_link_options(headless-git PUBLIC -municode -Wl,-subsystem,windows)
 	elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
@@ -767,15 +768,15 @@ add_executable(scalar ${CMAKE_SOURCE_DIR}/scalar.c)
 target_link_libraries(scalar common-main)
 
 if(CURL_FOUND)
-	add_library(http_obj OBJECT ${CMAKE_SOURCE_DIR}/http.c)
+	add_library(http_obj OBJECT ${CMAKE_SOURCE_DIR}/lib/http.c)
 
 	add_executable(git-imap-send ${CMAKE_SOURCE_DIR}/imap-send.c)
 	target_link_libraries(git-imap-send http_obj common-main ${CURL_LIBRARIES})
 
-	add_executable(git-http-fetch ${CMAKE_SOURCE_DIR}/http-walker.c ${CMAKE_SOURCE_DIR}/http-fetch.c)
+	add_executable(git-http-fetch ${CMAKE_SOURCE_DIR}/lib/http-walker.c ${CMAKE_SOURCE_DIR}/http-fetch.c)
 	target_link_libraries(git-http-fetch http_obj common-main ${CURL_LIBRARIES})
 
-	add_executable(git-remote-http ${CMAKE_SOURCE_DIR}/http-walker.c ${CMAKE_SOURCE_DIR}/remote-curl.c)
+	add_executable(git-remote-http ${CMAKE_SOURCE_DIR}/lib/http-walker.c ${CMAKE_SOURCE_DIR}/remote-curl.c)
 	target_link_libraries(git-remote-http http_obj common-main ${CURL_LIBRARIES} )
 
 	if(EXPAT_FOUND)
@@ -1201,7 +1202,7 @@ string(REPLACE "@USE_LIBPCRE2@" "" git_build_options "${git_build_options}")
 string(REPLACE "@WITH_BREAKING_CHANGES@" "" git_build_options "${git_build_options}")
 string(REPLACE "@X@" "${EXE_EXTENSION}" git_build_options "${git_build_options}")
 if(USE_VCPKG)
-	string(APPEND git_build_options "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n")
+	string(APPEND git_build_options "PATH=\"$PATH:$TEST_DIRECTORY/../lib/compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n")
 endif()
 file(WRITE ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS ${git_build_options})
 
diff --git a/git.rc.in b/git.rc.in
index e69444eef3..87cdefd50b 100644
--- a/git.rc.in
+++ b/git.rc.in
@@ -21,4 +21,4 @@ BEGIN
   END
 END
 
-1 RT_MANIFEST "compat/win32/git.manifest"
+1 RT_MANIFEST "lib/compat/win32/git.manifest"
diff --git a/abspath.c b/lib/abspath.c
similarity index 100%
rename from abspath.c
rename to lib/abspath.c
diff --git a/abspath.h b/lib/abspath.h
similarity index 100%
rename from abspath.h
rename to lib/abspath.h
diff --git a/add-interactive.c b/lib/add-interactive.c
similarity index 100%
rename from add-interactive.c
rename to lib/add-interactive.c
diff --git a/add-interactive.h b/lib/add-interactive.h
similarity index 100%
rename from add-interactive.h
rename to lib/add-interactive.h
diff --git a/add-patch.c b/lib/add-patch.c
similarity index 100%
rename from add-patch.c
rename to lib/add-patch.c
diff --git a/add-patch.h b/lib/add-patch.h
similarity index 100%
rename from add-patch.h
rename to lib/add-patch.h
diff --git a/advice.c b/lib/advice.c
similarity index 100%
rename from advice.c
rename to lib/advice.c
diff --git a/advice.h b/lib/advice.h
similarity index 100%
rename from advice.h
rename to lib/advice.h
diff --git a/alias.c b/lib/alias.c
similarity index 100%
rename from alias.c
rename to lib/alias.c
diff --git a/alias.h b/lib/alias.h
similarity index 100%
rename from alias.h
rename to lib/alias.h
diff --git a/alloc.c b/lib/alloc.c
similarity index 100%
rename from alloc.c
rename to lib/alloc.c
diff --git a/alloc.h b/lib/alloc.h
similarity index 100%
rename from alloc.h
rename to lib/alloc.h
diff --git a/apply.c b/lib/apply.c
similarity index 100%
rename from apply.c
rename to lib/apply.c
diff --git a/apply.h b/lib/apply.h
similarity index 100%
rename from apply.h
rename to lib/apply.h
diff --git a/archive-tar.c b/lib/archive-tar.c
similarity index 100%
rename from archive-tar.c
rename to lib/archive-tar.c
diff --git a/archive-zip.c b/lib/archive-zip.c
similarity index 100%
rename from archive-zip.c
rename to lib/archive-zip.c
diff --git a/archive.c b/lib/archive.c
similarity index 100%
rename from archive.c
rename to lib/archive.c
diff --git a/archive.h b/lib/archive.h
similarity index 100%
rename from archive.h
rename to lib/archive.h
diff --git a/attr.c b/lib/attr.c
similarity index 100%
rename from attr.c
rename to lib/attr.c
diff --git a/attr.h b/lib/attr.h
similarity index 100%
rename from attr.h
rename to lib/attr.h
diff --git a/banned.h b/lib/banned.h
similarity index 100%
rename from banned.h
rename to lib/banned.h
diff --git a/base85.c b/lib/base85.c
similarity index 100%
rename from base85.c
rename to lib/base85.c
diff --git a/base85.h b/lib/base85.h
similarity index 100%
rename from base85.h
rename to lib/base85.h
diff --git a/bisect.c b/lib/bisect.c
similarity index 100%
rename from bisect.c
rename to lib/bisect.c
diff --git a/bisect.h b/lib/bisect.h
similarity index 100%
rename from bisect.h
rename to lib/bisect.h
diff --git a/blame.c b/lib/blame.c
similarity index 100%
rename from blame.c
rename to lib/blame.c
diff --git a/blame.h b/lib/blame.h
similarity index 100%
rename from blame.h
rename to lib/blame.h
diff --git a/blob.c b/lib/blob.c
similarity index 100%
rename from blob.c
rename to lib/blob.c
diff --git a/blob.h b/lib/blob.h
similarity index 100%
rename from blob.h
rename to lib/blob.h
diff --git a/block-sha1/sha1.c b/lib/block-sha1/sha1.c
similarity index 100%
rename from block-sha1/sha1.c
rename to lib/block-sha1/sha1.c
diff --git a/block-sha1/sha1.h b/lib/block-sha1/sha1.h
similarity index 100%
rename from block-sha1/sha1.h
rename to lib/block-sha1/sha1.h
diff --git a/bloom.c b/lib/bloom.c
similarity index 100%
rename from bloom.c
rename to lib/bloom.c
diff --git a/bloom.h b/lib/bloom.h
similarity index 100%
rename from bloom.h
rename to lib/bloom.h
diff --git a/branch.c b/lib/branch.c
similarity index 100%
rename from branch.c
rename to lib/branch.c
diff --git a/branch.h b/lib/branch.h
similarity index 100%
rename from branch.h
rename to lib/branch.h
diff --git a/builtin.h b/lib/builtin.h
similarity index 100%
rename from builtin.h
rename to lib/builtin.h
diff --git a/bundle-uri.c b/lib/bundle-uri.c
similarity index 100%
rename from bundle-uri.c
rename to lib/bundle-uri.c
diff --git a/bundle-uri.h b/lib/bundle-uri.h
similarity index 100%
rename from bundle-uri.h
rename to lib/bundle-uri.h
diff --git a/bundle.c b/lib/bundle.c
similarity index 100%
rename from bundle.c
rename to lib/bundle.c
diff --git a/bundle.h b/lib/bundle.h
similarity index 100%
rename from bundle.h
rename to lib/bundle.h
diff --git a/cache-tree.c b/lib/cache-tree.c
similarity index 100%
rename from cache-tree.c
rename to lib/cache-tree.c
diff --git a/cache-tree.h b/lib/cache-tree.h
similarity index 100%
rename from cache-tree.h
rename to lib/cache-tree.h
diff --git a/cbtree.c b/lib/cbtree.c
similarity index 100%
rename from cbtree.c
rename to lib/cbtree.c
diff --git a/cbtree.h b/lib/cbtree.h
similarity index 100%
rename from cbtree.h
rename to lib/cbtree.h
diff --git a/chdir-notify.c b/lib/chdir-notify.c
similarity index 100%
rename from chdir-notify.c
rename to lib/chdir-notify.c
diff --git a/chdir-notify.h b/lib/chdir-notify.h
similarity index 100%
rename from chdir-notify.h
rename to lib/chdir-notify.h
diff --git a/checkout.c b/lib/checkout.c
similarity index 100%
rename from checkout.c
rename to lib/checkout.c
diff --git a/checkout.h b/lib/checkout.h
similarity index 100%
rename from checkout.h
rename to lib/checkout.h
diff --git a/chunk-format.c b/lib/chunk-format.c
similarity index 100%
rename from chunk-format.c
rename to lib/chunk-format.c
diff --git a/chunk-format.h b/lib/chunk-format.h
similarity index 100%
rename from chunk-format.h
rename to lib/chunk-format.h
diff --git a/color.c b/lib/color.c
similarity index 100%
rename from color.c
rename to lib/color.c
diff --git a/color.h b/lib/color.h
similarity index 100%
rename from color.h
rename to lib/color.h
diff --git a/column.c b/lib/column.c
similarity index 100%
rename from column.c
rename to lib/column.c
diff --git a/column.h b/lib/column.h
similarity index 100%
rename from column.h
rename to lib/column.h
diff --git a/combine-diff.c b/lib/combine-diff.c
similarity index 100%
rename from combine-diff.c
rename to lib/combine-diff.c
diff --git a/commit-graph.c b/lib/commit-graph.c
similarity index 100%
rename from commit-graph.c
rename to lib/commit-graph.c
diff --git a/commit-graph.h b/lib/commit-graph.h
similarity index 100%
rename from commit-graph.h
rename to lib/commit-graph.h
diff --git a/commit-reach.c b/lib/commit-reach.c
similarity index 100%
rename from commit-reach.c
rename to lib/commit-reach.c
diff --git a/commit-reach.h b/lib/commit-reach.h
similarity index 100%
rename from commit-reach.h
rename to lib/commit-reach.h
diff --git a/commit-slab-decl.h b/lib/commit-slab-decl.h
similarity index 100%
rename from commit-slab-decl.h
rename to lib/commit-slab-decl.h
diff --git a/commit-slab-impl.h b/lib/commit-slab-impl.h
similarity index 100%
rename from commit-slab-impl.h
rename to lib/commit-slab-impl.h
diff --git a/commit-slab.h b/lib/commit-slab.h
similarity index 100%
rename from commit-slab.h
rename to lib/commit-slab.h
diff --git a/commit.c b/lib/commit.c
similarity index 100%
rename from commit.c
rename to lib/commit.c
diff --git a/commit.h b/lib/commit.h
similarity index 100%
rename from commit.h
rename to lib/commit.h
diff --git a/common-exit.c b/lib/common-exit.c
similarity index 100%
rename from common-exit.c
rename to lib/common-exit.c
diff --git a/common-init.c b/lib/common-init.c
similarity index 100%
rename from common-init.c
rename to lib/common-init.c
diff --git a/common-init.h b/lib/common-init.h
similarity index 100%
rename from common-init.h
rename to lib/common-init.h
diff --git a/compat/.gitattributes b/lib/compat/.gitattributes
similarity index 100%
rename from compat/.gitattributes
rename to lib/compat/.gitattributes
diff --git a/compat/access.c b/lib/compat/access.c
similarity index 100%
rename from compat/access.c
rename to lib/compat/access.c
diff --git a/compat/apple-common-crypto.h b/lib/compat/apple-common-crypto.h
similarity index 100%
rename from compat/apple-common-crypto.h
rename to lib/compat/apple-common-crypto.h
diff --git a/compat/basename.c b/lib/compat/basename.c
similarity index 100%
rename from compat/basename.c
rename to lib/compat/basename.c
diff --git a/compat/bswap.h b/lib/compat/bswap.h
similarity index 100%
rename from compat/bswap.h
rename to lib/compat/bswap.h
diff --git a/compat/compiler.h b/lib/compat/compiler.h
similarity index 100%
rename from compat/compiler.h
rename to lib/compat/compiler.h
diff --git a/compat/darwin/procinfo.c b/lib/compat/darwin/procinfo.c
similarity index 100%
rename from compat/darwin/procinfo.c
rename to lib/compat/darwin/procinfo.c
diff --git a/compat/disk.h b/lib/compat/disk.h
similarity index 100%
rename from compat/disk.h
rename to lib/compat/disk.h
diff --git a/compat/fileno.c b/lib/compat/fileno.c
similarity index 100%
rename from compat/fileno.c
rename to lib/compat/fileno.c
diff --git a/compat/fopen.c b/lib/compat/fopen.c
similarity index 100%
rename from compat/fopen.c
rename to lib/compat/fopen.c
diff --git a/compat/fsmonitor/fsm-darwin-gcc.h b/lib/compat/fsmonitor/fsm-darwin-gcc.h
similarity index 100%
rename from compat/fsmonitor/fsm-darwin-gcc.h
rename to lib/compat/fsmonitor/fsm-darwin-gcc.h
diff --git a/compat/fsmonitor/fsm-health-darwin.c b/lib/compat/fsmonitor/fsm-health-darwin.c
similarity index 100%
rename from compat/fsmonitor/fsm-health-darwin.c
rename to lib/compat/fsmonitor/fsm-health-darwin.c
diff --git a/compat/fsmonitor/fsm-health-linux.c b/lib/compat/fsmonitor/fsm-health-linux.c
similarity index 100%
rename from compat/fsmonitor/fsm-health-linux.c
rename to lib/compat/fsmonitor/fsm-health-linux.c
diff --git a/compat/fsmonitor/fsm-health-win32.c b/lib/compat/fsmonitor/fsm-health-win32.c
similarity index 100%
rename from compat/fsmonitor/fsm-health-win32.c
rename to lib/compat/fsmonitor/fsm-health-win32.c
diff --git a/compat/fsmonitor/fsm-health.h b/lib/compat/fsmonitor/fsm-health.h
similarity index 100%
rename from compat/fsmonitor/fsm-health.h
rename to lib/compat/fsmonitor/fsm-health.h
diff --git a/compat/fsmonitor/fsm-ipc-unix.c b/lib/compat/fsmonitor/fsm-ipc-unix.c
similarity index 100%
rename from compat/fsmonitor/fsm-ipc-unix.c
rename to lib/compat/fsmonitor/fsm-ipc-unix.c
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/lib/compat/fsmonitor/fsm-ipc-win32.c
similarity index 100%
rename from compat/fsmonitor/fsm-ipc-win32.c
rename to lib/compat/fsmonitor/fsm-ipc-win32.c
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/lib/compat/fsmonitor/fsm-listen-darwin.c
similarity index 100%
rename from compat/fsmonitor/fsm-listen-darwin.c
rename to lib/compat/fsmonitor/fsm-listen-darwin.c
diff --git a/compat/fsmonitor/fsm-listen-linux.c b/lib/compat/fsmonitor/fsm-listen-linux.c
similarity index 100%
rename from compat/fsmonitor/fsm-listen-linux.c
rename to lib/compat/fsmonitor/fsm-listen-linux.c
diff --git a/compat/fsmonitor/fsm-listen-win32.c b/lib/compat/fsmonitor/fsm-listen-win32.c
similarity index 100%
rename from compat/fsmonitor/fsm-listen-win32.c
rename to lib/compat/fsmonitor/fsm-listen-win32.c
diff --git a/compat/fsmonitor/fsm-listen.h b/lib/compat/fsmonitor/fsm-listen.h
similarity index 100%
rename from compat/fsmonitor/fsm-listen.h
rename to lib/compat/fsmonitor/fsm-listen.h
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/lib/compat/fsmonitor/fsm-path-utils-darwin.c
similarity index 100%
rename from compat/fsmonitor/fsm-path-utils-darwin.c
rename to lib/compat/fsmonitor/fsm-path-utils-darwin.c
diff --git a/compat/fsmonitor/fsm-path-utils-linux.c b/lib/compat/fsmonitor/fsm-path-utils-linux.c
similarity index 100%
rename from compat/fsmonitor/fsm-path-utils-linux.c
rename to lib/compat/fsmonitor/fsm-path-utils-linux.c
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/lib/compat/fsmonitor/fsm-path-utils-win32.c
similarity index 100%
rename from compat/fsmonitor/fsm-path-utils-win32.c
rename to lib/compat/fsmonitor/fsm-path-utils-win32.c
diff --git a/compat/fsmonitor/fsm-settings-unix.c b/lib/compat/fsmonitor/fsm-settings-unix.c
similarity index 100%
rename from compat/fsmonitor/fsm-settings-unix.c
rename to lib/compat/fsmonitor/fsm-settings-unix.c
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/lib/compat/fsmonitor/fsm-settings-win32.c
similarity index 100%
rename from compat/fsmonitor/fsm-settings-win32.c
rename to lib/compat/fsmonitor/fsm-settings-win32.c
diff --git a/compat/hstrerror.c b/lib/compat/hstrerror.c
similarity index 100%
rename from compat/hstrerror.c
rename to lib/compat/hstrerror.c
diff --git a/compat/inet_ntop.c b/lib/compat/inet_ntop.c
similarity index 100%
rename from compat/inet_ntop.c
rename to lib/compat/inet_ntop.c
diff --git a/compat/inet_pton.c b/lib/compat/inet_pton.c
similarity index 100%
rename from compat/inet_pton.c
rename to lib/compat/inet_pton.c
diff --git a/compat/linux/procinfo.c b/lib/compat/linux/procinfo.c
similarity index 100%
rename from compat/linux/procinfo.c
rename to lib/compat/linux/procinfo.c
diff --git a/compat/memmem.c b/lib/compat/memmem.c
similarity index 100%
rename from compat/memmem.c
rename to lib/compat/memmem.c
diff --git a/compat/mingw-posix.h b/lib/compat/mingw-posix.h
similarity index 100%
rename from compat/mingw-posix.h
rename to lib/compat/mingw-posix.h
diff --git a/compat/mingw.c b/lib/compat/mingw.c
similarity index 100%
rename from compat/mingw.c
rename to lib/compat/mingw.c
diff --git a/compat/mingw.h b/lib/compat/mingw.h
similarity index 100%
rename from compat/mingw.h
rename to lib/compat/mingw.h
diff --git a/compat/mkdir.c b/lib/compat/mkdir.c
similarity index 100%
rename from compat/mkdir.c
rename to lib/compat/mkdir.c
diff --git a/compat/mmap.c b/lib/compat/mmap.c
similarity index 100%
rename from compat/mmap.c
rename to lib/compat/mmap.c
diff --git a/compat/msvc-posix.h b/lib/compat/msvc-posix.h
similarity index 100%
rename from compat/msvc-posix.h
rename to lib/compat/msvc-posix.h
diff --git a/compat/msvc.c b/lib/compat/msvc.c
similarity index 100%
rename from compat/msvc.c
rename to lib/compat/msvc.c
diff --git a/compat/msvc.h b/lib/compat/msvc.h
similarity index 100%
rename from compat/msvc.h
rename to lib/compat/msvc.h
diff --git a/compat/nonblock.c b/lib/compat/nonblock.c
similarity index 100%
rename from compat/nonblock.c
rename to lib/compat/nonblock.c
diff --git a/compat/nonblock.h b/lib/compat/nonblock.h
similarity index 100%
rename from compat/nonblock.h
rename to lib/compat/nonblock.h
diff --git a/compat/obstack.c b/lib/compat/obstack.c
similarity index 100%
rename from compat/obstack.c
rename to lib/compat/obstack.c
diff --git a/compat/obstack.h b/lib/compat/obstack.h
similarity index 100%
rename from compat/obstack.h
rename to lib/compat/obstack.h
diff --git a/compat/open.c b/lib/compat/open.c
similarity index 100%
rename from compat/open.c
rename to lib/compat/open.c
diff --git a/compat/poll/poll.c b/lib/compat/poll/poll.c
similarity index 100%
rename from compat/poll/poll.c
rename to lib/compat/poll/poll.c
diff --git a/compat/poll/poll.h b/lib/compat/poll/poll.h
similarity index 100%
rename from compat/poll/poll.h
rename to lib/compat/poll/poll.h
diff --git a/compat/posix.h b/lib/compat/posix.h
similarity index 100%
rename from compat/posix.h
rename to lib/compat/posix.h
diff --git a/compat/pread.c b/lib/compat/pread.c
similarity index 100%
rename from compat/pread.c
rename to lib/compat/pread.c
diff --git a/compat/precompose_utf8.c b/lib/compat/precompose_utf8.c
similarity index 100%
rename from compat/precompose_utf8.c
rename to lib/compat/precompose_utf8.c
diff --git a/compat/precompose_utf8.h b/lib/compat/precompose_utf8.h
similarity index 100%
rename from compat/precompose_utf8.h
rename to lib/compat/precompose_utf8.h
diff --git a/compat/qsort_s.c b/lib/compat/qsort_s.c
similarity index 100%
rename from compat/qsort_s.c
rename to lib/compat/qsort_s.c
diff --git a/compat/regcomp_enhanced.c b/lib/compat/regcomp_enhanced.c
similarity index 100%
rename from compat/regcomp_enhanced.c
rename to lib/compat/regcomp_enhanced.c
diff --git a/compat/regex/regcomp.c b/lib/compat/regex/regcomp.c
similarity index 100%
rename from compat/regex/regcomp.c
rename to lib/compat/regex/regcomp.c
diff --git a/compat/regex/regex.c b/lib/compat/regex/regex.c
similarity index 100%
rename from compat/regex/regex.c
rename to lib/compat/regex/regex.c
diff --git a/compat/regex/regex.h b/lib/compat/regex/regex.h
similarity index 100%
rename from compat/regex/regex.h
rename to lib/compat/regex/regex.h
diff --git a/compat/regex/regex_internal.c b/lib/compat/regex/regex_internal.c
similarity index 100%
rename from compat/regex/regex_internal.c
rename to lib/compat/regex/regex_internal.c
diff --git a/compat/regex/regex_internal.h b/lib/compat/regex/regex_internal.h
similarity index 100%
rename from compat/regex/regex_internal.h
rename to lib/compat/regex/regex_internal.h
diff --git a/compat/regex/regexec.c b/lib/compat/regex/regexec.c
similarity index 100%
rename from compat/regex/regexec.c
rename to lib/compat/regex/regexec.c
diff --git a/compat/setenv.c b/lib/compat/setenv.c
similarity index 100%
rename from compat/setenv.c
rename to lib/compat/setenv.c
diff --git a/compat/sha1-chunked.c b/lib/compat/sha1-chunked.c
similarity index 100%
rename from compat/sha1-chunked.c
rename to lib/compat/sha1-chunked.c
diff --git a/compat/sha1-chunked.h b/lib/compat/sha1-chunked.h
similarity index 100%
rename from compat/sha1-chunked.h
rename to lib/compat/sha1-chunked.h
diff --git a/compat/simple-ipc/ipc-shared.c b/lib/compat/simple-ipc/ipc-shared.c
similarity index 100%
rename from compat/simple-ipc/ipc-shared.c
rename to lib/compat/simple-ipc/ipc-shared.c
diff --git a/compat/simple-ipc/ipc-unix-socket.c b/lib/compat/simple-ipc/ipc-unix-socket.c
similarity index 100%
rename from compat/simple-ipc/ipc-unix-socket.c
rename to lib/compat/simple-ipc/ipc-unix-socket.c
diff --git a/compat/simple-ipc/ipc-win32.c b/lib/compat/simple-ipc/ipc-win32.c
similarity index 100%
rename from compat/simple-ipc/ipc-win32.c
rename to lib/compat/simple-ipc/ipc-win32.c
diff --git a/compat/snprintf.c b/lib/compat/snprintf.c
similarity index 100%
rename from compat/snprintf.c
rename to lib/compat/snprintf.c
diff --git a/compat/stat.c b/lib/compat/stat.c
similarity index 100%
rename from compat/stat.c
rename to lib/compat/stat.c
diff --git a/compat/strcasestr.c b/lib/compat/strcasestr.c
similarity index 100%
rename from compat/strcasestr.c
rename to lib/compat/strcasestr.c
diff --git a/compat/strdup.c b/lib/compat/strdup.c
similarity index 100%
rename from compat/strdup.c
rename to lib/compat/strdup.c
diff --git a/compat/strlcpy.c b/lib/compat/strlcpy.c
similarity index 100%
rename from compat/strlcpy.c
rename to lib/compat/strlcpy.c
diff --git a/compat/strtoimax.c b/lib/compat/strtoimax.c
similarity index 100%
rename from compat/strtoimax.c
rename to lib/compat/strtoimax.c
diff --git a/compat/strtoumax.c b/lib/compat/strtoumax.c
similarity index 100%
rename from compat/strtoumax.c
rename to lib/compat/strtoumax.c
diff --git a/compat/stub/procinfo.c b/lib/compat/stub/procinfo.c
similarity index 100%
rename from compat/stub/procinfo.c
rename to lib/compat/stub/procinfo.c
diff --git a/compat/terminal.c b/lib/compat/terminal.c
similarity index 100%
rename from compat/terminal.c
rename to lib/compat/terminal.c
diff --git a/compat/terminal.h b/lib/compat/terminal.h
similarity index 100%
rename from compat/terminal.h
rename to lib/compat/terminal.h
diff --git a/compat/unsetenv.c b/lib/compat/unsetenv.c
similarity index 100%
rename from compat/unsetenv.c
rename to lib/compat/unsetenv.c
diff --git a/compat/vcbuild/.gitignore b/lib/compat/vcbuild/.gitignore
similarity index 100%
rename from compat/vcbuild/.gitignore
rename to lib/compat/vcbuild/.gitignore
diff --git a/compat/vcbuild/README b/lib/compat/vcbuild/README
similarity index 94%
rename from compat/vcbuild/README
rename to lib/compat/vcbuild/README
index 29ec1d0f10..63ee00a4ef 100644
--- a/compat/vcbuild/README
+++ b/lib/compat/vcbuild/README
@@ -6,17 +6,17 @@ The Steps to Build Git with VS2015 or VS2017 from the command line.
    Prompt or from an SDK bash window:
 
    $ cd <repo_root>
-   $ ./compat/vcbuild/vcpkg_install.bat
+   $ ./lib/compat/vcbuild/vcpkg_install.bat
 
    The vcpkg tools and all of the third-party sources will be installed
    in this folder:
-      <repo_root>/compat/vcbuild/vcpkg/
+      <repo_root>/lib/compat/vcbuild/vcpkg/
 
    A file will be created with a set of Makefile macros pointing to a
    unified "include", "lib", and "bin" directory (release and debug) for
    all of the required packages.  This file will be included by the main
    Makefile:
-      <repo_root>/compat/vcbuild/MSVC-DEFS-GEN
+      <repo_root>/lib/compat/vcbuild/MSVC-DEFS-GEN
 
 2. OPTIONALLY copy the third-party *.dll and *.pdb files into the repo
    root to make it easier to run and debug git.exe without having to
@@ -26,8 +26,8 @@ The Steps to Build Git with VS2015 or VS2017 from the command line.
    Use ONE of the following forms which should match how you want to
    compile git.exe.
 
-   $ ./compat/vcbuild/vcpkg_copy_dlls.bat debug
-   $ ./compat/vcbuild/vcpkg_copy_dlls.bat release
+   $ ./lib/compat/vcbuild/vcpkg_copy_dlls.bat debug
+   $ ./lib/compat/vcbuild/vcpkg_copy_dlls.bat release
 
 3. Build git using MSVC from an SDK bash window using one of the
    following commands:
diff --git a/compat/vcbuild/find_vs_env.bat b/lib/compat/vcbuild/find_vs_env.bat
similarity index 98%
rename from compat/vcbuild/find_vs_env.bat
rename to lib/compat/vcbuild/find_vs_env.bat
index b35d264c0e..30e884b3d7 100644
--- a/compat/vcbuild/find_vs_env.bat
+++ b/lib/compat/vcbuild/find_vs_env.bat
@@ -25,7 +25,7 @@ REM
 REM The output of this script should be written to a make "include
 REM file" and referenced by the top-level Makefile.
 REM
-REM See "config.mak.uname" (look for compat/vcbuild/MSVC-DEFS-GEN).
+REM See "config.mak.uname" (look for lib/compat/vcbuild/MSVC-DEFS-GEN).
 REM ================================================================
 REM The provided command prompts are custom to each VS release and
 REM filled with lots of internal knowledge (such as Registry settings);
diff --git a/compat/vcbuild/include/sys/param.h b/lib/compat/vcbuild/include/sys/param.h
similarity index 100%
rename from compat/vcbuild/include/sys/param.h
rename to lib/compat/vcbuild/include/sys/param.h
diff --git a/compat/vcbuild/include/sys/time.h b/lib/compat/vcbuild/include/sys/time.h
similarity index 100%
rename from compat/vcbuild/include/sys/time.h
rename to lib/compat/vcbuild/include/sys/time.h
diff --git a/compat/vcbuild/include/sys/utime.h b/lib/compat/vcbuild/include/sys/utime.h
similarity index 100%
rename from compat/vcbuild/include/sys/utime.h
rename to lib/compat/vcbuild/include/sys/utime.h
diff --git a/compat/vcbuild/include/unistd.h b/lib/compat/vcbuild/include/unistd.h
similarity index 100%
rename from compat/vcbuild/include/unistd.h
rename to lib/compat/vcbuild/include/unistd.h
diff --git a/compat/vcbuild/include/utime.h b/lib/compat/vcbuild/include/utime.h
similarity index 100%
rename from compat/vcbuild/include/utime.h
rename to lib/compat/vcbuild/include/utime.h
diff --git a/compat/vcbuild/scripts/clink.pl b/lib/compat/vcbuild/scripts/clink.pl
similarity index 100%
rename from compat/vcbuild/scripts/clink.pl
rename to lib/compat/vcbuild/scripts/clink.pl
diff --git a/compat/vcbuild/scripts/lib.pl b/lib/compat/vcbuild/scripts/lib.pl
similarity index 100%
rename from compat/vcbuild/scripts/lib.pl
rename to lib/compat/vcbuild/scripts/lib.pl
diff --git a/compat/vcbuild/vcpkg_copy_dlls.bat b/lib/compat/vcbuild/vcpkg_copy_dlls.bat
similarity index 100%
rename from compat/vcbuild/vcpkg_copy_dlls.bat
rename to lib/compat/vcbuild/vcpkg_copy_dlls.bat
diff --git a/compat/vcbuild/vcpkg_install.bat b/lib/compat/vcbuild/vcpkg_install.bat
similarity index 95%
rename from compat/vcbuild/vcpkg_install.bat
rename to lib/compat/vcbuild/vcpkg_install.bat
index ebd0bad242..64c1b199e0 100644
--- a/compat/vcbuild/vcpkg_install.bat
+++ b/lib/compat/vcbuild/vcpkg_install.bat
@@ -5,10 +5,10 @@ REM it to build the third-party libraries that git requires when it
 REM is built using MSVC.
 REM
 REM [1] Install VCPKG.
-REM     [a] Create <root>/compat/vcbuild/vcpkg/
+REM     [a] Create <root>/lib/compat/vcbuild/vcpkg/
 REM     [b] Download "vcpkg".
 REM     [c] Compile using the currently installed version of VS.
-REM     [d] Create <root>/compat/vcbuild/vcpkg/vcpkg.exe
+REM     [d] Create <root>/lib/compat/vcbuild/vcpkg/vcpkg.exe
 REM
 REM [2] Install third-party libraries.
 REM     [a] Download each (which may also install CMAKE).
diff --git a/compat/win32.h b/lib/compat/win32.h
similarity index 100%
rename from compat/win32.h
rename to lib/compat/win32.h
diff --git a/compat/win32/alloca.h b/lib/compat/win32/alloca.h
similarity index 100%
rename from compat/win32/alloca.h
rename to lib/compat/win32/alloca.h
diff --git a/compat/win32/dirent.c b/lib/compat/win32/dirent.c
similarity index 100%
rename from compat/win32/dirent.c
rename to lib/compat/win32/dirent.c
diff --git a/compat/win32/dirent.h b/lib/compat/win32/dirent.h
similarity index 100%
rename from compat/win32/dirent.h
rename to lib/compat/win32/dirent.h
diff --git a/compat/win32/exit-process.h b/lib/compat/win32/exit-process.h
similarity index 100%
rename from compat/win32/exit-process.h
rename to lib/compat/win32/exit-process.h
diff --git a/compat/win32/flush.c b/lib/compat/win32/flush.c
similarity index 100%
rename from compat/win32/flush.c
rename to lib/compat/win32/flush.c
diff --git a/compat/win32/git.manifest b/lib/compat/win32/git.manifest
similarity index 100%
rename from compat/win32/git.manifest
rename to lib/compat/win32/git.manifest
diff --git a/compat/win32/headless.c b/lib/compat/win32/headless.c
similarity index 100%
rename from compat/win32/headless.c
rename to lib/compat/win32/headless.c
diff --git a/compat/win32/lazyload.h b/lib/compat/win32/lazyload.h
similarity index 100%
rename from compat/win32/lazyload.h
rename to lib/compat/win32/lazyload.h
diff --git a/compat/win32/path-utils.c b/lib/compat/win32/path-utils.c
similarity index 100%
rename from compat/win32/path-utils.c
rename to lib/compat/win32/path-utils.c
diff --git a/compat/win32/path-utils.h b/lib/compat/win32/path-utils.h
similarity index 100%
rename from compat/win32/path-utils.h
rename to lib/compat/win32/path-utils.h
diff --git a/compat/win32/pthread.c b/lib/compat/win32/pthread.c
similarity index 100%
rename from compat/win32/pthread.c
rename to lib/compat/win32/pthread.c
diff --git a/compat/win32/pthread.h b/lib/compat/win32/pthread.h
similarity index 100%
rename from compat/win32/pthread.h
rename to lib/compat/win32/pthread.h
diff --git a/compat/win32/syslog.c b/lib/compat/win32/syslog.c
similarity index 100%
rename from compat/win32/syslog.c
rename to lib/compat/win32/syslog.c
diff --git a/compat/win32/syslog.h b/lib/compat/win32/syslog.h
similarity index 100%
rename from compat/win32/syslog.h
rename to lib/compat/win32/syslog.h
diff --git a/compat/win32/trace2_win32_process_info.c b/lib/compat/win32/trace2_win32_process_info.c
similarity index 100%
rename from compat/win32/trace2_win32_process_info.c
rename to lib/compat/win32/trace2_win32_process_info.c
diff --git a/compat/win32mmap.c b/lib/compat/win32mmap.c
similarity index 100%
rename from compat/win32mmap.c
rename to lib/compat/win32mmap.c
diff --git a/compat/winansi.c b/lib/compat/winansi.c
similarity index 100%
rename from compat/winansi.c
rename to lib/compat/winansi.c
diff --git a/compat/zlib-compat.h b/lib/compat/zlib-compat.h
similarity index 100%
rename from compat/zlib-compat.h
rename to lib/compat/zlib-compat.h
diff --git a/compiler-tricks/not-constant.c b/lib/compiler-tricks/not-constant.c
similarity index 100%
rename from compiler-tricks/not-constant.c
rename to lib/compiler-tricks/not-constant.c
diff --git a/config.c b/lib/config.c
similarity index 100%
rename from config.c
rename to lib/config.c
diff --git a/config.h b/lib/config.h
similarity index 100%
rename from config.h
rename to lib/config.h
diff --git a/connect.c b/lib/connect.c
similarity index 100%
rename from connect.c
rename to lib/connect.c
diff --git a/connect.h b/lib/connect.h
similarity index 100%
rename from connect.h
rename to lib/connect.h
diff --git a/connected.c b/lib/connected.c
similarity index 100%
rename from connected.c
rename to lib/connected.c
diff --git a/connected.h b/lib/connected.h
similarity index 100%
rename from connected.h
rename to lib/connected.h
diff --git a/convert.c b/lib/convert.c
similarity index 100%
rename from convert.c
rename to lib/convert.c
diff --git a/convert.h b/lib/convert.h
similarity index 100%
rename from convert.h
rename to lib/convert.h
diff --git a/copy.c b/lib/copy.c
similarity index 100%
rename from copy.c
rename to lib/copy.c
diff --git a/copy.h b/lib/copy.h
similarity index 100%
rename from copy.h
rename to lib/copy.h
diff --git a/credential.c b/lib/credential.c
similarity index 100%
rename from credential.c
rename to lib/credential.c
diff --git a/credential.h b/lib/credential.h
similarity index 100%
rename from credential.h
rename to lib/credential.h
diff --git a/csum-file.c b/lib/csum-file.c
similarity index 100%
rename from csum-file.c
rename to lib/csum-file.c
diff --git a/csum-file.h b/lib/csum-file.h
similarity index 100%
rename from csum-file.h
rename to lib/csum-file.h
diff --git a/ctype.c b/lib/ctype.c
similarity index 100%
rename from ctype.c
rename to lib/ctype.c
diff --git a/date.c b/lib/date.c
similarity index 100%
rename from date.c
rename to lib/date.c
diff --git a/date.h b/lib/date.h
similarity index 100%
rename from date.h
rename to lib/date.h
diff --git a/decorate.c b/lib/decorate.c
similarity index 100%
rename from decorate.c
rename to lib/decorate.c
diff --git a/decorate.h b/lib/decorate.h
similarity index 100%
rename from decorate.h
rename to lib/decorate.h
diff --git a/delta-islands.c b/lib/delta-islands.c
similarity index 100%
rename from delta-islands.c
rename to lib/delta-islands.c
diff --git a/delta-islands.h b/lib/delta-islands.h
similarity index 100%
rename from delta-islands.h
rename to lib/delta-islands.h
diff --git a/delta.h b/lib/delta.h
similarity index 100%
rename from delta.h
rename to lib/delta.h
diff --git a/diagnose.c b/lib/diagnose.c
similarity index 100%
rename from diagnose.c
rename to lib/diagnose.c
diff --git a/diagnose.h b/lib/diagnose.h
similarity index 100%
rename from diagnose.h
rename to lib/diagnose.h
diff --git a/diff-delta.c b/lib/diff-delta.c
similarity index 100%
rename from diff-delta.c
rename to lib/diff-delta.c
diff --git a/diff-lib.c b/lib/diff-lib.c
similarity index 100%
rename from diff-lib.c
rename to lib/diff-lib.c
diff --git a/diff-merges.c b/lib/diff-merges.c
similarity index 100%
rename from diff-merges.c
rename to lib/diff-merges.c
diff --git a/diff-merges.h b/lib/diff-merges.h
similarity index 100%
rename from diff-merges.h
rename to lib/diff-merges.h
diff --git a/diff-no-index.c b/lib/diff-no-index.c
similarity index 100%
rename from diff-no-index.c
rename to lib/diff-no-index.c
diff --git a/diff.c b/lib/diff.c
similarity index 100%
rename from diff.c
rename to lib/diff.c
diff --git a/diff.h b/lib/diff.h
similarity index 100%
rename from diff.h
rename to lib/diff.h
diff --git a/diffcore-break.c b/lib/diffcore-break.c
similarity index 100%
rename from diffcore-break.c
rename to lib/diffcore-break.c
diff --git a/diffcore-delta.c b/lib/diffcore-delta.c
similarity index 100%
rename from diffcore-delta.c
rename to lib/diffcore-delta.c
diff --git a/diffcore-order.c b/lib/diffcore-order.c
similarity index 100%
rename from diffcore-order.c
rename to lib/diffcore-order.c
diff --git a/diffcore-pickaxe.c b/lib/diffcore-pickaxe.c
similarity index 100%
rename from diffcore-pickaxe.c
rename to lib/diffcore-pickaxe.c
diff --git a/diffcore-rename.c b/lib/diffcore-rename.c
similarity index 100%
rename from diffcore-rename.c
rename to lib/diffcore-rename.c
diff --git a/diffcore-rotate.c b/lib/diffcore-rotate.c
similarity index 100%
rename from diffcore-rotate.c
rename to lib/diffcore-rotate.c
diff --git a/diffcore.h b/lib/diffcore.h
similarity index 100%
rename from diffcore.h
rename to lib/diffcore.h
diff --git a/dir-iterator.c b/lib/dir-iterator.c
similarity index 100%
rename from dir-iterator.c
rename to lib/dir-iterator.c
diff --git a/dir-iterator.h b/lib/dir-iterator.h
similarity index 100%
rename from dir-iterator.h
rename to lib/dir-iterator.h
diff --git a/dir.c b/lib/dir.c
similarity index 100%
rename from dir.c
rename to lib/dir.c
diff --git a/dir.h b/lib/dir.h
similarity index 100%
rename from dir.h
rename to lib/dir.h
diff --git a/editor.c b/lib/editor.c
similarity index 100%
rename from editor.c
rename to lib/editor.c
diff --git a/editor.h b/lib/editor.h
similarity index 100%
rename from editor.h
rename to lib/editor.h
diff --git a/entry.c b/lib/entry.c
similarity index 100%
rename from entry.c
rename to lib/entry.c
diff --git a/entry.h b/lib/entry.h
similarity index 100%
rename from entry.h
rename to lib/entry.h
diff --git a/environment.c b/lib/environment.c
similarity index 100%
rename from environment.c
rename to lib/environment.c
diff --git a/environment.h b/lib/environment.h
similarity index 100%
rename from environment.h
rename to lib/environment.h
diff --git a/ewah/bitmap.c b/lib/ewah/bitmap.c
similarity index 100%
rename from ewah/bitmap.c
rename to lib/ewah/bitmap.c
diff --git a/ewah/ewah_bitmap.c b/lib/ewah/ewah_bitmap.c
similarity index 100%
rename from ewah/ewah_bitmap.c
rename to lib/ewah/ewah_bitmap.c
diff --git a/ewah/ewah_io.c b/lib/ewah/ewah_io.c
similarity index 100%
rename from ewah/ewah_io.c
rename to lib/ewah/ewah_io.c
diff --git a/ewah/ewah_rlw.c b/lib/ewah/ewah_rlw.c
similarity index 100%
rename from ewah/ewah_rlw.c
rename to lib/ewah/ewah_rlw.c
diff --git a/ewah/ewok.h b/lib/ewah/ewok.h
similarity index 100%
rename from ewah/ewok.h
rename to lib/ewah/ewok.h
diff --git a/ewah/ewok_rlw.h b/lib/ewah/ewok_rlw.h
similarity index 100%
rename from ewah/ewok_rlw.h
rename to lib/ewah/ewok_rlw.h
diff --git a/exec-cmd.c b/lib/exec-cmd.c
similarity index 100%
rename from exec-cmd.c
rename to lib/exec-cmd.c
diff --git a/exec-cmd.h b/lib/exec-cmd.h
similarity index 100%
rename from exec-cmd.h
rename to lib/exec-cmd.h
diff --git a/fetch-negotiator.c b/lib/fetch-negotiator.c
similarity index 100%
rename from fetch-negotiator.c
rename to lib/fetch-negotiator.c
diff --git a/fetch-negotiator.h b/lib/fetch-negotiator.h
similarity index 100%
rename from fetch-negotiator.h
rename to lib/fetch-negotiator.h
diff --git a/fetch-pack.c b/lib/fetch-pack.c
similarity index 100%
rename from fetch-pack.c
rename to lib/fetch-pack.c
diff --git a/fetch-pack.h b/lib/fetch-pack.h
similarity index 100%
rename from fetch-pack.h
rename to lib/fetch-pack.h
diff --git a/fmt-merge-msg.c b/lib/fmt-merge-msg.c
similarity index 100%
rename from fmt-merge-msg.c
rename to lib/fmt-merge-msg.c
diff --git a/fmt-merge-msg.h b/lib/fmt-merge-msg.h
similarity index 100%
rename from fmt-merge-msg.h
rename to lib/fmt-merge-msg.h
diff --git a/for-each-ref.h b/lib/for-each-ref.h
similarity index 100%
rename from for-each-ref.h
rename to lib/for-each-ref.h
diff --git a/fsck.c b/lib/fsck.c
similarity index 100%
rename from fsck.c
rename to lib/fsck.c
diff --git a/fsck.h b/lib/fsck.h
similarity index 100%
rename from fsck.h
rename to lib/fsck.h
diff --git a/fsmonitor--daemon.h b/lib/fsmonitor--daemon.h
similarity index 100%
rename from fsmonitor--daemon.h
rename to lib/fsmonitor--daemon.h
diff --git a/fsmonitor-ipc.c b/lib/fsmonitor-ipc.c
similarity index 100%
rename from fsmonitor-ipc.c
rename to lib/fsmonitor-ipc.c
diff --git a/fsmonitor-ipc.h b/lib/fsmonitor-ipc.h
similarity index 100%
rename from fsmonitor-ipc.h
rename to lib/fsmonitor-ipc.h
diff --git a/fsmonitor-ll.h b/lib/fsmonitor-ll.h
similarity index 100%
rename from fsmonitor-ll.h
rename to lib/fsmonitor-ll.h
diff --git a/fsmonitor-path-utils.h b/lib/fsmonitor-path-utils.h
similarity index 100%
rename from fsmonitor-path-utils.h
rename to lib/fsmonitor-path-utils.h
diff --git a/fsmonitor-settings.c b/lib/fsmonitor-settings.c
similarity index 100%
rename from fsmonitor-settings.c
rename to lib/fsmonitor-settings.c
diff --git a/fsmonitor-settings.h b/lib/fsmonitor-settings.h
similarity index 100%
rename from fsmonitor-settings.h
rename to lib/fsmonitor-settings.h
diff --git a/fsmonitor.c b/lib/fsmonitor.c
similarity index 100%
rename from fsmonitor.c
rename to lib/fsmonitor.c
diff --git a/fsmonitor.h b/lib/fsmonitor.h
similarity index 100%
rename from fsmonitor.h
rename to lib/fsmonitor.h
diff --git a/gettext.c b/lib/gettext.c
similarity index 100%
rename from gettext.c
rename to lib/gettext.c
diff --git a/gettext.h b/lib/gettext.h
similarity index 100%
rename from gettext.h
rename to lib/gettext.h
diff --git a/git-compat-util.h b/lib/git-compat-util.h
similarity index 100%
rename from git-compat-util.h
rename to lib/git-compat-util.h
diff --git a/git-curl-compat.h b/lib/git-curl-compat.h
similarity index 100%
rename from git-curl-compat.h
rename to lib/git-curl-compat.h
diff --git a/git-zlib.c b/lib/git-zlib.c
similarity index 100%
rename from git-zlib.c
rename to lib/git-zlib.c
diff --git a/git-zlib.h b/lib/git-zlib.h
similarity index 100%
rename from git-zlib.h
rename to lib/git-zlib.h
diff --git a/gpg-interface.c b/lib/gpg-interface.c
similarity index 100%
rename from gpg-interface.c
rename to lib/gpg-interface.c
diff --git a/gpg-interface.h b/lib/gpg-interface.h
similarity index 100%
rename from gpg-interface.h
rename to lib/gpg-interface.h
diff --git a/graph.c b/lib/graph.c
similarity index 100%
rename from graph.c
rename to lib/graph.c
diff --git a/graph.h b/lib/graph.h
similarity index 100%
rename from graph.h
rename to lib/graph.h
diff --git a/grep.c b/lib/grep.c
similarity index 100%
rename from grep.c
rename to lib/grep.c
diff --git a/grep.h b/lib/grep.h
similarity index 100%
rename from grep.h
rename to lib/grep.h
diff --git a/hash-lookup.c b/lib/hash-lookup.c
similarity index 100%
rename from hash-lookup.c
rename to lib/hash-lookup.c
diff --git a/hash-lookup.h b/lib/hash-lookup.h
similarity index 100%
rename from hash-lookup.h
rename to lib/hash-lookup.h
diff --git a/hash.c b/lib/hash.c
similarity index 100%
rename from hash.c
rename to lib/hash.c
diff --git a/hash.h b/lib/hash.h
similarity index 100%
rename from hash.h
rename to lib/hash.h
diff --git a/hashmap.c b/lib/hashmap.c
similarity index 100%
rename from hashmap.c
rename to lib/hashmap.c
diff --git a/hashmap.h b/lib/hashmap.h
similarity index 100%
rename from hashmap.h
rename to lib/hashmap.h
diff --git a/help.c b/lib/help.c
similarity index 100%
rename from help.c
rename to lib/help.c
diff --git a/help.h b/lib/help.h
similarity index 100%
rename from help.h
rename to lib/help.h
diff --git a/hex-ll.c b/lib/hex-ll.c
similarity index 100%
rename from hex-ll.c
rename to lib/hex-ll.c
diff --git a/hex-ll.h b/lib/hex-ll.h
similarity index 100%
rename from hex-ll.h
rename to lib/hex-ll.h
diff --git a/hex.c b/lib/hex.c
similarity index 100%
rename from hex.c
rename to lib/hex.c
diff --git a/hex.h b/lib/hex.h
similarity index 100%
rename from hex.h
rename to lib/hex.h
diff --git a/hook.c b/lib/hook.c
similarity index 100%
rename from hook.c
rename to lib/hook.c
diff --git a/hook.h b/lib/hook.h
similarity index 100%
rename from hook.h
rename to lib/hook.h
diff --git a/http-walker.c b/lib/http-walker.c
similarity index 100%
rename from http-walker.c
rename to lib/http-walker.c
diff --git a/http.c b/lib/http.c
similarity index 100%
rename from http.c
rename to lib/http.c
diff --git a/http.h b/lib/http.h
similarity index 100%
rename from http.h
rename to lib/http.h
diff --git a/ident.c b/lib/ident.c
similarity index 100%
rename from ident.c
rename to lib/ident.c
diff --git a/ident.h b/lib/ident.h
similarity index 100%
rename from ident.h
rename to lib/ident.h
diff --git a/iterator.h b/lib/iterator.h
similarity index 100%
rename from iterator.h
rename to lib/iterator.h
diff --git a/json-writer.c b/lib/json-writer.c
similarity index 100%
rename from json-writer.c
rename to lib/json-writer.c
diff --git a/json-writer.h b/lib/json-writer.h
similarity index 100%
rename from json-writer.h
rename to lib/json-writer.h
diff --git a/khash.h b/lib/khash.h
similarity index 100%
rename from khash.h
rename to lib/khash.h
diff --git a/kwset.c b/lib/kwset.c
similarity index 100%
rename from kwset.c
rename to lib/kwset.c
diff --git a/kwset.h b/lib/kwset.h
similarity index 100%
rename from kwset.h
rename to lib/kwset.h
diff --git a/levenshtein.c b/lib/levenshtein.c
similarity index 100%
rename from levenshtein.c
rename to lib/levenshtein.c
diff --git a/levenshtein.h b/lib/levenshtein.h
similarity index 100%
rename from levenshtein.h
rename to lib/levenshtein.h
diff --git a/line-log.c b/lib/line-log.c
similarity index 100%
rename from line-log.c
rename to lib/line-log.c
diff --git a/line-log.h b/lib/line-log.h
similarity index 100%
rename from line-log.h
rename to lib/line-log.h
diff --git a/line-range.c b/lib/line-range.c
similarity index 100%
rename from line-range.c
rename to lib/line-range.c
diff --git a/line-range.h b/lib/line-range.h
similarity index 100%
rename from line-range.h
rename to lib/line-range.h
diff --git a/linear-assignment.c b/lib/linear-assignment.c
similarity index 100%
rename from linear-assignment.c
rename to lib/linear-assignment.c
diff --git a/linear-assignment.h b/lib/linear-assignment.h
similarity index 100%
rename from linear-assignment.h
rename to lib/linear-assignment.h
diff --git a/list-objects-filter-options.c b/lib/list-objects-filter-options.c
similarity index 100%
rename from list-objects-filter-options.c
rename to lib/list-objects-filter-options.c
diff --git a/list-objects-filter-options.h b/lib/list-objects-filter-options.h
similarity index 100%
rename from list-objects-filter-options.h
rename to lib/list-objects-filter-options.h
diff --git a/list-objects-filter.c b/lib/list-objects-filter.c
similarity index 100%
rename from list-objects-filter.c
rename to lib/list-objects-filter.c
diff --git a/list-objects-filter.h b/lib/list-objects-filter.h
similarity index 100%
rename from list-objects-filter.h
rename to lib/list-objects-filter.h
diff --git a/list-objects.c b/lib/list-objects.c
similarity index 100%
rename from list-objects.c
rename to lib/list-objects.c
diff --git a/list-objects.h b/lib/list-objects.h
similarity index 100%
rename from list-objects.h
rename to lib/list-objects.h
diff --git a/list.h b/lib/list.h
similarity index 100%
rename from list.h
rename to lib/list.h
diff --git a/lockfile.c b/lib/lockfile.c
similarity index 100%
rename from lockfile.c
rename to lib/lockfile.c
diff --git a/lockfile.h b/lib/lockfile.h
similarity index 100%
rename from lockfile.h
rename to lib/lockfile.h
diff --git a/log-tree.c b/lib/log-tree.c
similarity index 100%
rename from log-tree.c
rename to lib/log-tree.c
diff --git a/log-tree.h b/lib/log-tree.h
similarity index 100%
rename from log-tree.h
rename to lib/log-tree.h
diff --git a/loose.c b/lib/loose.c
similarity index 100%
rename from loose.c
rename to lib/loose.c
diff --git a/loose.h b/lib/loose.h
similarity index 100%
rename from loose.h
rename to lib/loose.h
diff --git a/ls-refs.c b/lib/ls-refs.c
similarity index 100%
rename from ls-refs.c
rename to lib/ls-refs.c
diff --git a/ls-refs.h b/lib/ls-refs.h
similarity index 100%
rename from ls-refs.h
rename to lib/ls-refs.h
diff --git a/mailinfo.c b/lib/mailinfo.c
similarity index 100%
rename from mailinfo.c
rename to lib/mailinfo.c
diff --git a/mailinfo.h b/lib/mailinfo.h
similarity index 100%
rename from mailinfo.h
rename to lib/mailinfo.h
diff --git a/mailmap.c b/lib/mailmap.c
similarity index 100%
rename from mailmap.c
rename to lib/mailmap.c
diff --git a/mailmap.h b/lib/mailmap.h
similarity index 100%
rename from mailmap.h
rename to lib/mailmap.h
diff --git a/match-trees.c b/lib/match-trees.c
similarity index 100%
rename from match-trees.c
rename to lib/match-trees.c
diff --git a/match-trees.h b/lib/match-trees.h
similarity index 100%
rename from match-trees.h
rename to lib/match-trees.h
diff --git a/mem-pool.c b/lib/mem-pool.c
similarity index 100%
rename from mem-pool.c
rename to lib/mem-pool.c
diff --git a/mem-pool.h b/lib/mem-pool.h
similarity index 100%
rename from mem-pool.h
rename to lib/mem-pool.h
diff --git a/merge-blobs.c b/lib/merge-blobs.c
similarity index 100%
rename from merge-blobs.c
rename to lib/merge-blobs.c
diff --git a/merge-blobs.h b/lib/merge-blobs.h
similarity index 100%
rename from merge-blobs.h
rename to lib/merge-blobs.h
diff --git a/merge-ll.c b/lib/merge-ll.c
similarity index 100%
rename from merge-ll.c
rename to lib/merge-ll.c
diff --git a/merge-ll.h b/lib/merge-ll.h
similarity index 100%
rename from merge-ll.h
rename to lib/merge-ll.h
diff --git a/merge-ort-wrappers.c b/lib/merge-ort-wrappers.c
similarity index 100%
rename from merge-ort-wrappers.c
rename to lib/merge-ort-wrappers.c
diff --git a/merge-ort-wrappers.h b/lib/merge-ort-wrappers.h
similarity index 100%
rename from merge-ort-wrappers.h
rename to lib/merge-ort-wrappers.h
diff --git a/merge-ort.c b/lib/merge-ort.c
similarity index 100%
rename from merge-ort.c
rename to lib/merge-ort.c
diff --git a/merge-ort.h b/lib/merge-ort.h
similarity index 100%
rename from merge-ort.h
rename to lib/merge-ort.h
diff --git a/merge.c b/lib/merge.c
similarity index 100%
rename from merge.c
rename to lib/merge.c
diff --git a/merge.h b/lib/merge.h
similarity index 100%
rename from merge.h
rename to lib/merge.h
diff --git a/mergesort.h b/lib/mergesort.h
similarity index 100%
rename from mergesort.h
rename to lib/mergesort.h
diff --git a/midx-write.c b/lib/midx-write.c
similarity index 100%
rename from midx-write.c
rename to lib/midx-write.c
diff --git a/midx.c b/lib/midx.c
similarity index 100%
rename from midx.c
rename to lib/midx.c
diff --git a/midx.h b/lib/midx.h
similarity index 100%
rename from midx.h
rename to lib/midx.h
diff --git a/name-hash.c b/lib/name-hash.c
similarity index 100%
rename from name-hash.c
rename to lib/name-hash.c
diff --git a/name-hash.h b/lib/name-hash.h
similarity index 100%
rename from name-hash.h
rename to lib/name-hash.h
diff --git a/negotiator/default.c b/lib/negotiator/default.c
similarity index 100%
rename from negotiator/default.c
rename to lib/negotiator/default.c
diff --git a/negotiator/default.h b/lib/negotiator/default.h
similarity index 100%
rename from negotiator/default.h
rename to lib/negotiator/default.h
diff --git a/negotiator/noop.c b/lib/negotiator/noop.c
similarity index 100%
rename from negotiator/noop.c
rename to lib/negotiator/noop.c
diff --git a/negotiator/noop.h b/lib/negotiator/noop.h
similarity index 100%
rename from negotiator/noop.h
rename to lib/negotiator/noop.h
diff --git a/negotiator/skipping.c b/lib/negotiator/skipping.c
similarity index 100%
rename from negotiator/skipping.c
rename to lib/negotiator/skipping.c
diff --git a/negotiator/skipping.h b/lib/negotiator/skipping.h
similarity index 100%
rename from negotiator/skipping.h
rename to lib/negotiator/skipping.h
diff --git a/notes-cache.c b/lib/notes-cache.c
similarity index 100%
rename from notes-cache.c
rename to lib/notes-cache.c
diff --git a/notes-cache.h b/lib/notes-cache.h
similarity index 100%
rename from notes-cache.h
rename to lib/notes-cache.h
diff --git a/notes-merge.c b/lib/notes-merge.c
similarity index 100%
rename from notes-merge.c
rename to lib/notes-merge.c
diff --git a/notes-merge.h b/lib/notes-merge.h
similarity index 100%
rename from notes-merge.h
rename to lib/notes-merge.h
diff --git a/notes-utils.c b/lib/notes-utils.c
similarity index 100%
rename from notes-utils.c
rename to lib/notes-utils.c
diff --git a/notes-utils.h b/lib/notes-utils.h
similarity index 100%
rename from notes-utils.h
rename to lib/notes-utils.h
diff --git a/notes.c b/lib/notes.c
similarity index 100%
rename from notes.c
rename to lib/notes.c
diff --git a/notes.h b/lib/notes.h
similarity index 100%
rename from notes.h
rename to lib/notes.h
diff --git a/object-file-convert.c b/lib/object-file-convert.c
similarity index 100%
rename from object-file-convert.c
rename to lib/object-file-convert.c
diff --git a/object-file-convert.h b/lib/object-file-convert.h
similarity index 100%
rename from object-file-convert.h
rename to lib/object-file-convert.h
diff --git a/object-file.c b/lib/object-file.c
similarity index 100%
rename from object-file.c
rename to lib/object-file.c
diff --git a/object-file.h b/lib/object-file.h
similarity index 100%
rename from object-file.h
rename to lib/object-file.h
diff --git a/object-name.c b/lib/object-name.c
similarity index 100%
rename from object-name.c
rename to lib/object-name.c
diff --git a/object-name.h b/lib/object-name.h
similarity index 100%
rename from object-name.h
rename to lib/object-name.h
diff --git a/object.c b/lib/object.c
similarity index 100%
rename from object.c
rename to lib/object.c
diff --git a/object.h b/lib/object.h
similarity index 100%
rename from object.h
rename to lib/object.h
diff --git a/odb.c b/lib/odb.c
similarity index 100%
rename from odb.c
rename to lib/odb.c
diff --git a/odb.h b/lib/odb.h
similarity index 100%
rename from odb.h
rename to lib/odb.h
diff --git a/odb/source-files.c b/lib/odb/source-files.c
similarity index 100%
rename from odb/source-files.c
rename to lib/odb/source-files.c
diff --git a/odb/source-files.h b/lib/odb/source-files.h
similarity index 100%
rename from odb/source-files.h
rename to lib/odb/source-files.h
diff --git a/odb/source-inmemory.c b/lib/odb/source-inmemory.c
similarity index 100%
rename from odb/source-inmemory.c
rename to lib/odb/source-inmemory.c
diff --git a/odb/source-inmemory.h b/lib/odb/source-inmemory.h
similarity index 100%
rename from odb/source-inmemory.h
rename to lib/odb/source-inmemory.h
diff --git a/odb/source-loose.c b/lib/odb/source-loose.c
similarity index 100%
rename from odb/source-loose.c
rename to lib/odb/source-loose.c
diff --git a/odb/source-loose.h b/lib/odb/source-loose.h
similarity index 100%
rename from odb/source-loose.h
rename to lib/odb/source-loose.h
diff --git a/odb/source-packed.c b/lib/odb/source-packed.c
similarity index 100%
rename from odb/source-packed.c
rename to lib/odb/source-packed.c
diff --git a/odb/source-packed.h b/lib/odb/source-packed.h
similarity index 100%
rename from odb/source-packed.h
rename to lib/odb/source-packed.h
diff --git a/odb/source.c b/lib/odb/source.c
similarity index 100%
rename from odb/source.c
rename to lib/odb/source.c
diff --git a/odb/source.h b/lib/odb/source.h
similarity index 100%
rename from odb/source.h
rename to lib/odb/source.h
diff --git a/odb/streaming.c b/lib/odb/streaming.c
similarity index 100%
rename from odb/streaming.c
rename to lib/odb/streaming.c
diff --git a/odb/streaming.h b/lib/odb/streaming.h
similarity index 100%
rename from odb/streaming.h
rename to lib/odb/streaming.h
diff --git a/odb/transaction.c b/lib/odb/transaction.c
similarity index 100%
rename from odb/transaction.c
rename to lib/odb/transaction.c
diff --git a/odb/transaction.h b/lib/odb/transaction.h
similarity index 100%
rename from odb/transaction.h
rename to lib/odb/transaction.h
diff --git a/oid-array.c b/lib/oid-array.c
similarity index 100%
rename from oid-array.c
rename to lib/oid-array.c
diff --git a/oid-array.h b/lib/oid-array.h
similarity index 100%
rename from oid-array.h
rename to lib/oid-array.h
diff --git a/oidmap.c b/lib/oidmap.c
similarity index 100%
rename from oidmap.c
rename to lib/oidmap.c
diff --git a/oidmap.h b/lib/oidmap.h
similarity index 100%
rename from oidmap.h
rename to lib/oidmap.h
diff --git a/oidset.c b/lib/oidset.c
similarity index 100%
rename from oidset.c
rename to lib/oidset.c
diff --git a/oidset.h b/lib/oidset.h
similarity index 100%
rename from oidset.h
rename to lib/oidset.h
diff --git a/oidtree.c b/lib/oidtree.c
similarity index 100%
rename from oidtree.c
rename to lib/oidtree.c
diff --git a/oidtree.h b/lib/oidtree.h
similarity index 100%
rename from oidtree.h
rename to lib/oidtree.h
diff --git a/pack-bitmap-write.c b/lib/pack-bitmap-write.c
similarity index 100%
rename from pack-bitmap-write.c
rename to lib/pack-bitmap-write.c
diff --git a/pack-bitmap.c b/lib/pack-bitmap.c
similarity index 100%
rename from pack-bitmap.c
rename to lib/pack-bitmap.c
diff --git a/pack-bitmap.h b/lib/pack-bitmap.h
similarity index 100%
rename from pack-bitmap.h
rename to lib/pack-bitmap.h
diff --git a/pack-check.c b/lib/pack-check.c
similarity index 100%
rename from pack-check.c
rename to lib/pack-check.c
diff --git a/pack-mtimes.c b/lib/pack-mtimes.c
similarity index 100%
rename from pack-mtimes.c
rename to lib/pack-mtimes.c
diff --git a/pack-mtimes.h b/lib/pack-mtimes.h
similarity index 100%
rename from pack-mtimes.h
rename to lib/pack-mtimes.h
diff --git a/pack-objects.c b/lib/pack-objects.c
similarity index 100%
rename from pack-objects.c
rename to lib/pack-objects.c
diff --git a/pack-objects.h b/lib/pack-objects.h
similarity index 100%
rename from pack-objects.h
rename to lib/pack-objects.h
diff --git a/pack-refs.c b/lib/pack-refs.c
similarity index 100%
rename from pack-refs.c
rename to lib/pack-refs.c
diff --git a/pack-refs.h b/lib/pack-refs.h
similarity index 100%
rename from pack-refs.h
rename to lib/pack-refs.h
diff --git a/pack-revindex.c b/lib/pack-revindex.c
similarity index 100%
rename from pack-revindex.c
rename to lib/pack-revindex.c
diff --git a/pack-revindex.h b/lib/pack-revindex.h
similarity index 100%
rename from pack-revindex.h
rename to lib/pack-revindex.h
diff --git a/pack-write.c b/lib/pack-write.c
similarity index 100%
rename from pack-write.c
rename to lib/pack-write.c
diff --git a/pack.h b/lib/pack.h
similarity index 100%
rename from pack.h
rename to lib/pack.h
diff --git a/packfile-list.c b/lib/packfile-list.c
similarity index 100%
rename from packfile-list.c
rename to lib/packfile-list.c
diff --git a/packfile-list.h b/lib/packfile-list.h
similarity index 100%
rename from packfile-list.h
rename to lib/packfile-list.h
diff --git a/packfile.c b/lib/packfile.c
similarity index 100%
rename from packfile.c
rename to lib/packfile.c
diff --git a/packfile.h b/lib/packfile.h
similarity index 100%
rename from packfile.h
rename to lib/packfile.h
diff --git a/pager.c b/lib/pager.c
similarity index 100%
rename from pager.c
rename to lib/pager.c
diff --git a/pager.h b/lib/pager.h
similarity index 100%
rename from pager.h
rename to lib/pager.h
diff --git a/parallel-checkout.c b/lib/parallel-checkout.c
similarity index 100%
rename from parallel-checkout.c
rename to lib/parallel-checkout.c
diff --git a/parallel-checkout.h b/lib/parallel-checkout.h
similarity index 100%
rename from parallel-checkout.h
rename to lib/parallel-checkout.h
diff --git a/parse-options-cb.c b/lib/parse-options-cb.c
similarity index 100%
rename from parse-options-cb.c
rename to lib/parse-options-cb.c
diff --git a/parse-options.c b/lib/parse-options.c
similarity index 100%
rename from parse-options.c
rename to lib/parse-options.c
diff --git a/parse-options.h b/lib/parse-options.h
similarity index 100%
rename from parse-options.h
rename to lib/parse-options.h
diff --git a/parse.c b/lib/parse.c
similarity index 100%
rename from parse.c
rename to lib/parse.c
diff --git a/parse.h b/lib/parse.h
similarity index 100%
rename from parse.h
rename to lib/parse.h
diff --git a/patch-delta.c b/lib/patch-delta.c
similarity index 100%
rename from patch-delta.c
rename to lib/patch-delta.c
diff --git a/patch-ids.c b/lib/patch-ids.c
similarity index 100%
rename from patch-ids.c
rename to lib/patch-ids.c
diff --git a/patch-ids.h b/lib/patch-ids.h
similarity index 100%
rename from patch-ids.h
rename to lib/patch-ids.h
diff --git a/path-walk.c b/lib/path-walk.c
similarity index 100%
rename from path-walk.c
rename to lib/path-walk.c
diff --git a/path-walk.h b/lib/path-walk.h
similarity index 100%
rename from path-walk.h
rename to lib/path-walk.h
diff --git a/path.c b/lib/path.c
similarity index 100%
rename from path.c
rename to lib/path.c
diff --git a/path.h b/lib/path.h
similarity index 100%
rename from path.h
rename to lib/path.h
diff --git a/pathspec.c b/lib/pathspec.c
similarity index 100%
rename from pathspec.c
rename to lib/pathspec.c
diff --git a/pathspec.h b/lib/pathspec.h
similarity index 100%
rename from pathspec.h
rename to lib/pathspec.h
diff --git a/pkt-line.c b/lib/pkt-line.c
similarity index 100%
rename from pkt-line.c
rename to lib/pkt-line.c
diff --git a/pkt-line.h b/lib/pkt-line.h
similarity index 100%
rename from pkt-line.h
rename to lib/pkt-line.h
diff --git a/preload-index.c b/lib/preload-index.c
similarity index 100%
rename from preload-index.c
rename to lib/preload-index.c
diff --git a/preload-index.h b/lib/preload-index.h
similarity index 100%
rename from preload-index.h
rename to lib/preload-index.h
diff --git a/pretty.c b/lib/pretty.c
similarity index 100%
rename from pretty.c
rename to lib/pretty.c
diff --git a/pretty.h b/lib/pretty.h
similarity index 100%
rename from pretty.h
rename to lib/pretty.h
diff --git a/prio-queue.c b/lib/prio-queue.c
similarity index 100%
rename from prio-queue.c
rename to lib/prio-queue.c
diff --git a/prio-queue.h b/lib/prio-queue.h
similarity index 100%
rename from prio-queue.h
rename to lib/prio-queue.h
diff --git a/progress.c b/lib/progress.c
similarity index 100%
rename from progress.c
rename to lib/progress.c
diff --git a/progress.h b/lib/progress.h
similarity index 100%
rename from progress.h
rename to lib/progress.h
diff --git a/promisor-remote.c b/lib/promisor-remote.c
similarity index 100%
rename from promisor-remote.c
rename to lib/promisor-remote.c
diff --git a/promisor-remote.h b/lib/promisor-remote.h
similarity index 100%
rename from promisor-remote.h
rename to lib/promisor-remote.h
diff --git a/prompt.c b/lib/prompt.c
similarity index 100%
rename from prompt.c
rename to lib/prompt.c
diff --git a/prompt.h b/lib/prompt.h
similarity index 100%
rename from prompt.h
rename to lib/prompt.h
diff --git a/protocol-caps.c b/lib/protocol-caps.c
similarity index 100%
rename from protocol-caps.c
rename to lib/protocol-caps.c
diff --git a/protocol-caps.h b/lib/protocol-caps.h
similarity index 100%
rename from protocol-caps.h
rename to lib/protocol-caps.h
diff --git a/protocol.c b/lib/protocol.c
similarity index 100%
rename from protocol.c
rename to lib/protocol.c
diff --git a/protocol.h b/lib/protocol.h
similarity index 100%
rename from protocol.h
rename to lib/protocol.h
diff --git a/prune-packed.c b/lib/prune-packed.c
similarity index 100%
rename from prune-packed.c
rename to lib/prune-packed.c
diff --git a/prune-packed.h b/lib/prune-packed.h
similarity index 100%
rename from prune-packed.h
rename to lib/prune-packed.h
diff --git a/pseudo-merge.c b/lib/pseudo-merge.c
similarity index 100%
rename from pseudo-merge.c
rename to lib/pseudo-merge.c
diff --git a/pseudo-merge.h b/lib/pseudo-merge.h
similarity index 100%
rename from pseudo-merge.h
rename to lib/pseudo-merge.h
diff --git a/quote.c b/lib/quote.c
similarity index 100%
rename from quote.c
rename to lib/quote.c
diff --git a/quote.h b/lib/quote.h
similarity index 100%
rename from quote.h
rename to lib/quote.h
diff --git a/range-diff.c b/lib/range-diff.c
similarity index 100%
rename from range-diff.c
rename to lib/range-diff.c
diff --git a/range-diff.h b/lib/range-diff.h
similarity index 100%
rename from range-diff.h
rename to lib/range-diff.h
diff --git a/reachable.c b/lib/reachable.c
similarity index 100%
rename from reachable.c
rename to lib/reachable.c
diff --git a/reachable.h b/lib/reachable.h
similarity index 100%
rename from reachable.h
rename to lib/reachable.h
diff --git a/read-cache-ll.h b/lib/read-cache-ll.h
similarity index 100%
rename from read-cache-ll.h
rename to lib/read-cache-ll.h
diff --git a/read-cache.c b/lib/read-cache.c
similarity index 100%
rename from read-cache.c
rename to lib/read-cache.c
diff --git a/read-cache.h b/lib/read-cache.h
similarity index 100%
rename from read-cache.h
rename to lib/read-cache.h
diff --git a/rebase-interactive.c b/lib/rebase-interactive.c
similarity index 100%
rename from rebase-interactive.c
rename to lib/rebase-interactive.c
diff --git a/rebase-interactive.h b/lib/rebase-interactive.h
similarity index 100%
rename from rebase-interactive.h
rename to lib/rebase-interactive.h
diff --git a/rebase.c b/lib/rebase.c
similarity index 100%
rename from rebase.c
rename to lib/rebase.c
diff --git a/rebase.h b/lib/rebase.h
similarity index 100%
rename from rebase.h
rename to lib/rebase.h
diff --git a/ref-filter.c b/lib/ref-filter.c
similarity index 100%
rename from ref-filter.c
rename to lib/ref-filter.c
diff --git a/ref-filter.h b/lib/ref-filter.h
similarity index 100%
rename from ref-filter.h
rename to lib/ref-filter.h
diff --git a/reflog-walk.c b/lib/reflog-walk.c
similarity index 100%
rename from reflog-walk.c
rename to lib/reflog-walk.c
diff --git a/reflog-walk.h b/lib/reflog-walk.h
similarity index 100%
rename from reflog-walk.h
rename to lib/reflog-walk.h
diff --git a/reflog.c b/lib/reflog.c
similarity index 100%
rename from reflog.c
rename to lib/reflog.c
diff --git a/reflog.h b/lib/reflog.h
similarity index 100%
rename from reflog.h
rename to lib/reflog.h
diff --git a/refs.c b/lib/refs.c
similarity index 100%
rename from refs.c
rename to lib/refs.c
diff --git a/refs.h b/lib/refs.h
similarity index 100%
rename from refs.h
rename to lib/refs.h
diff --git a/refs/debug.c b/lib/refs/debug.c
similarity index 100%
rename from refs/debug.c
rename to lib/refs/debug.c
diff --git a/refs/files-backend.c b/lib/refs/files-backend.c
similarity index 100%
rename from refs/files-backend.c
rename to lib/refs/files-backend.c
diff --git a/refs/iterator.c b/lib/refs/iterator.c
similarity index 100%
rename from refs/iterator.c
rename to lib/refs/iterator.c
diff --git a/refs/packed-backend.c b/lib/refs/packed-backend.c
similarity index 100%
rename from refs/packed-backend.c
rename to lib/refs/packed-backend.c
diff --git a/refs/packed-backend.h b/lib/refs/packed-backend.h
similarity index 100%
rename from refs/packed-backend.h
rename to lib/refs/packed-backend.h
diff --git a/refs/ref-cache.c b/lib/refs/ref-cache.c
similarity index 100%
rename from refs/ref-cache.c
rename to lib/refs/ref-cache.c
diff --git a/refs/ref-cache.h b/lib/refs/ref-cache.h
similarity index 100%
rename from refs/ref-cache.h
rename to lib/refs/ref-cache.h
diff --git a/refs/refs-internal.h b/lib/refs/refs-internal.h
similarity index 100%
rename from refs/refs-internal.h
rename to lib/refs/refs-internal.h
diff --git a/refs/reftable-backend.c b/lib/refs/reftable-backend.c
similarity index 100%
rename from refs/reftable-backend.c
rename to lib/refs/reftable-backend.c
diff --git a/refspec.c b/lib/refspec.c
similarity index 100%
rename from refspec.c
rename to lib/refspec.c
diff --git a/refspec.h b/lib/refspec.h
similarity index 100%
rename from refspec.h
rename to lib/refspec.h
diff --git a/reftable/LICENSE b/lib/reftable/LICENSE
similarity index 100%
rename from reftable/LICENSE
rename to lib/reftable/LICENSE
diff --git a/reftable/basics.c b/lib/reftable/basics.c
similarity index 100%
rename from reftable/basics.c
rename to lib/reftable/basics.c
diff --git a/reftable/basics.h b/lib/reftable/basics.h
similarity index 100%
rename from reftable/basics.h
rename to lib/reftable/basics.h
diff --git a/reftable/block.c b/lib/reftable/block.c
similarity index 100%
rename from reftable/block.c
rename to lib/reftable/block.c
diff --git a/reftable/block.h b/lib/reftable/block.h
similarity index 100%
rename from reftable/block.h
rename to lib/reftable/block.h
diff --git a/reftable/blocksource.c b/lib/reftable/blocksource.c
similarity index 100%
rename from reftable/blocksource.c
rename to lib/reftable/blocksource.c
diff --git a/reftable/blocksource.h b/lib/reftable/blocksource.h
similarity index 100%
rename from reftable/blocksource.h
rename to lib/reftable/blocksource.h
diff --git a/reftable/constants.h b/lib/reftable/constants.h
similarity index 100%
rename from reftable/constants.h
rename to lib/reftable/constants.h
diff --git a/reftable/error.c b/lib/reftable/error.c
similarity index 100%
rename from reftable/error.c
rename to lib/reftable/error.c
diff --git a/reftable/fsck.c b/lib/reftable/fsck.c
similarity index 100%
rename from reftable/fsck.c
rename to lib/reftable/fsck.c
diff --git a/reftable/iter.c b/lib/reftable/iter.c
similarity index 100%
rename from reftable/iter.c
rename to lib/reftable/iter.c
diff --git a/reftable/iter.h b/lib/reftable/iter.h
similarity index 100%
rename from reftable/iter.h
rename to lib/reftable/iter.h
diff --git a/reftable/merged.c b/lib/reftable/merged.c
similarity index 100%
rename from reftable/merged.c
rename to lib/reftable/merged.c
diff --git a/reftable/merged.h b/lib/reftable/merged.h
similarity index 100%
rename from reftable/merged.h
rename to lib/reftable/merged.h
diff --git a/reftable/pq.c b/lib/reftable/pq.c
similarity index 100%
rename from reftable/pq.c
rename to lib/reftable/pq.c
diff --git a/reftable/pq.h b/lib/reftable/pq.h
similarity index 100%
rename from reftable/pq.h
rename to lib/reftable/pq.h
diff --git a/reftable/record.c b/lib/reftable/record.c
similarity index 100%
rename from reftable/record.c
rename to lib/reftable/record.c
diff --git a/reftable/record.h b/lib/reftable/record.h
similarity index 100%
rename from reftable/record.h
rename to lib/reftable/record.h
diff --git a/reftable/reftable-basics.h b/lib/reftable/reftable-basics.h
similarity index 100%
rename from reftable/reftable-basics.h
rename to lib/reftable/reftable-basics.h
diff --git a/reftable/reftable-block.h b/lib/reftable/reftable-block.h
similarity index 100%
rename from reftable/reftable-block.h
rename to lib/reftable/reftable-block.h
diff --git a/reftable/reftable-blocksource.h b/lib/reftable/reftable-blocksource.h
similarity index 100%
rename from reftable/reftable-blocksource.h
rename to lib/reftable/reftable-blocksource.h
diff --git a/reftable/reftable-constants.h b/lib/reftable/reftable-constants.h
similarity index 100%
rename from reftable/reftable-constants.h
rename to lib/reftable/reftable-constants.h
diff --git a/reftable/reftable-error.h b/lib/reftable/reftable-error.h
similarity index 100%
rename from reftable/reftable-error.h
rename to lib/reftable/reftable-error.h
diff --git a/reftable/reftable-fsck.h b/lib/reftable/reftable-fsck.h
similarity index 100%
rename from reftable/reftable-fsck.h
rename to lib/reftable/reftable-fsck.h
diff --git a/reftable/reftable-iterator.h b/lib/reftable/reftable-iterator.h
similarity index 100%
rename from reftable/reftable-iterator.h
rename to lib/reftable/reftable-iterator.h
diff --git a/reftable/reftable-merged.h b/lib/reftable/reftable-merged.h
similarity index 100%
rename from reftable/reftable-merged.h
rename to lib/reftable/reftable-merged.h
diff --git a/reftable/reftable-record.h b/lib/reftable/reftable-record.h
similarity index 100%
rename from reftable/reftable-record.h
rename to lib/reftable/reftable-record.h
diff --git a/reftable/reftable-stack.h b/lib/reftable/reftable-stack.h
similarity index 100%
rename from reftable/reftable-stack.h
rename to lib/reftable/reftable-stack.h
diff --git a/reftable/reftable-system.h b/lib/reftable/reftable-system.h
similarity index 100%
rename from reftable/reftable-system.h
rename to lib/reftable/reftable-system.h
diff --git a/reftable/reftable-table.h b/lib/reftable/reftable-table.h
similarity index 100%
rename from reftable/reftable-table.h
rename to lib/reftable/reftable-table.h
diff --git a/reftable/reftable-writer.h b/lib/reftable/reftable-writer.h
similarity index 100%
rename from reftable/reftable-writer.h
rename to lib/reftable/reftable-writer.h
diff --git a/reftable/stack.c b/lib/reftable/stack.c
similarity index 100%
rename from reftable/stack.c
rename to lib/reftable/stack.c
diff --git a/reftable/stack.h b/lib/reftable/stack.h
similarity index 100%
rename from reftable/stack.h
rename to lib/reftable/stack.h
diff --git a/reftable/system.c b/lib/reftable/system.c
similarity index 100%
rename from reftable/system.c
rename to lib/reftable/system.c
diff --git a/reftable/system.h b/lib/reftable/system.h
similarity index 100%
rename from reftable/system.h
rename to lib/reftable/system.h
diff --git a/reftable/table.c b/lib/reftable/table.c
similarity index 100%
rename from reftable/table.c
rename to lib/reftable/table.c
diff --git a/reftable/table.h b/lib/reftable/table.h
similarity index 100%
rename from reftable/table.h
rename to lib/reftable/table.h
diff --git a/reftable/tree.c b/lib/reftable/tree.c
similarity index 100%
rename from reftable/tree.c
rename to lib/reftable/tree.c
diff --git a/reftable/tree.h b/lib/reftable/tree.h
similarity index 100%
rename from reftable/tree.h
rename to lib/reftable/tree.h
diff --git a/reftable/writer.c b/lib/reftable/writer.c
similarity index 100%
rename from reftable/writer.c
rename to lib/reftable/writer.c
diff --git a/reftable/writer.h b/lib/reftable/writer.h
similarity index 100%
rename from reftable/writer.h
rename to lib/reftable/writer.h
diff --git a/remote.c b/lib/remote.c
similarity index 100%
rename from remote.c
rename to lib/remote.c
diff --git a/remote.h b/lib/remote.h
similarity index 100%
rename from remote.h
rename to lib/remote.h
diff --git a/repack-cruft.c b/lib/repack-cruft.c
similarity index 100%
rename from repack-cruft.c
rename to lib/repack-cruft.c
diff --git a/repack-filtered.c b/lib/repack-filtered.c
similarity index 100%
rename from repack-filtered.c
rename to lib/repack-filtered.c
diff --git a/repack-geometry.c b/lib/repack-geometry.c
similarity index 100%
rename from repack-geometry.c
rename to lib/repack-geometry.c
diff --git a/repack-midx.c b/lib/repack-midx.c
similarity index 100%
rename from repack-midx.c
rename to lib/repack-midx.c
diff --git a/repack-promisor.c b/lib/repack-promisor.c
similarity index 100%
rename from repack-promisor.c
rename to lib/repack-promisor.c
diff --git a/repack.c b/lib/repack.c
similarity index 100%
rename from repack.c
rename to lib/repack.c
diff --git a/repack.h b/lib/repack.h
similarity index 100%
rename from repack.h
rename to lib/repack.h
diff --git a/replace-object.c b/lib/replace-object.c
similarity index 100%
rename from replace-object.c
rename to lib/replace-object.c
diff --git a/replace-object.h b/lib/replace-object.h
similarity index 100%
rename from replace-object.h
rename to lib/replace-object.h
diff --git a/replay.c b/lib/replay.c
similarity index 100%
rename from replay.c
rename to lib/replay.c
diff --git a/replay.h b/lib/replay.h
similarity index 100%
rename from replay.h
rename to lib/replay.h
diff --git a/repo-settings.c b/lib/repo-settings.c
similarity index 100%
rename from repo-settings.c
rename to lib/repo-settings.c
diff --git a/repo-settings.h b/lib/repo-settings.h
similarity index 100%
rename from repo-settings.h
rename to lib/repo-settings.h
diff --git a/repository.c b/lib/repository.c
similarity index 100%
rename from repository.c
rename to lib/repository.c
diff --git a/repository.h b/lib/repository.h
similarity index 100%
rename from repository.h
rename to lib/repository.h
diff --git a/rerere.c b/lib/rerere.c
similarity index 100%
rename from rerere.c
rename to lib/rerere.c
diff --git a/rerere.h b/lib/rerere.h
similarity index 100%
rename from rerere.h
rename to lib/rerere.h
diff --git a/reset.c b/lib/reset.c
similarity index 100%
rename from reset.c
rename to lib/reset.c
diff --git a/reset.h b/lib/reset.h
similarity index 100%
rename from reset.h
rename to lib/reset.h
diff --git a/resolve-undo.c b/lib/resolve-undo.c
similarity index 100%
rename from resolve-undo.c
rename to lib/resolve-undo.c
diff --git a/resolve-undo.h b/lib/resolve-undo.h
similarity index 100%
rename from resolve-undo.h
rename to lib/resolve-undo.h
diff --git a/revision.c b/lib/revision.c
similarity index 100%
rename from revision.c
rename to lib/revision.c
diff --git a/revision.h b/lib/revision.h
similarity index 100%
rename from revision.h
rename to lib/revision.h
diff --git a/run-command.c b/lib/run-command.c
similarity index 100%
rename from run-command.c
rename to lib/run-command.c
diff --git a/run-command.h b/lib/run-command.h
similarity index 100%
rename from run-command.h
rename to lib/run-command.h
diff --git a/sane-ctype.h b/lib/sane-ctype.h
similarity index 100%
rename from sane-ctype.h
rename to lib/sane-ctype.h
diff --git a/send-pack.c b/lib/send-pack.c
similarity index 100%
rename from send-pack.c
rename to lib/send-pack.c
diff --git a/send-pack.h b/lib/send-pack.h
similarity index 100%
rename from send-pack.h
rename to lib/send-pack.h
diff --git a/sequencer.c b/lib/sequencer.c
similarity index 100%
rename from sequencer.c
rename to lib/sequencer.c
diff --git a/sequencer.h b/lib/sequencer.h
similarity index 100%
rename from sequencer.h
rename to lib/sequencer.h
diff --git a/serve.c b/lib/serve.c
similarity index 100%
rename from serve.c
rename to lib/serve.c
diff --git a/serve.h b/lib/serve.h
similarity index 100%
rename from serve.h
rename to lib/serve.h
diff --git a/server-info.c b/lib/server-info.c
similarity index 100%
rename from server-info.c
rename to lib/server-info.c
diff --git a/server-info.h b/lib/server-info.h
similarity index 100%
rename from server-info.h
rename to lib/server-info.h
diff --git a/setup.c b/lib/setup.c
similarity index 100%
rename from setup.c
rename to lib/setup.c
diff --git a/setup.h b/lib/setup.h
similarity index 100%
rename from setup.h
rename to lib/setup.h
diff --git a/sha1/openssl.h b/lib/sha1/openssl.h
similarity index 100%
rename from sha1/openssl.h
rename to lib/sha1/openssl.h
diff --git a/sha1collisiondetection b/lib/sha1collisiondetection
similarity index 100%
rename from sha1collisiondetection
rename to lib/sha1collisiondetection
diff --git a/sha1dc/.gitattributes b/lib/sha1dc/.gitattributes
similarity index 100%
rename from sha1dc/.gitattributes
rename to lib/sha1dc/.gitattributes
diff --git a/sha1dc/LICENSE.txt b/lib/sha1dc/LICENSE.txt
similarity index 100%
rename from sha1dc/LICENSE.txt
rename to lib/sha1dc/LICENSE.txt
diff --git a/sha1dc/sha1.c b/lib/sha1dc/sha1.c
similarity index 100%
rename from sha1dc/sha1.c
rename to lib/sha1dc/sha1.c
diff --git a/sha1dc/sha1.h b/lib/sha1dc/sha1.h
similarity index 100%
rename from sha1dc/sha1.h
rename to lib/sha1dc/sha1.h
diff --git a/sha1dc/ubc_check.c b/lib/sha1dc/ubc_check.c
similarity index 100%
rename from sha1dc/ubc_check.c
rename to lib/sha1dc/ubc_check.c
diff --git a/sha1dc/ubc_check.h b/lib/sha1dc/ubc_check.h
similarity index 100%
rename from sha1dc/ubc_check.h
rename to lib/sha1dc/ubc_check.h
diff --git a/sha1dc_git.c b/lib/sha1dc_git.c
similarity index 100%
rename from sha1dc_git.c
rename to lib/sha1dc_git.c
diff --git a/sha1dc_git.h b/lib/sha1dc_git.h
similarity index 100%
rename from sha1dc_git.h
rename to lib/sha1dc_git.h
diff --git a/sha256/block/sha256.c b/lib/sha256/block/sha256.c
similarity index 100%
rename from sha256/block/sha256.c
rename to lib/sha256/block/sha256.c
diff --git a/sha256/block/sha256.h b/lib/sha256/block/sha256.h
similarity index 100%
rename from sha256/block/sha256.h
rename to lib/sha256/block/sha256.h
diff --git a/sha256/gcrypt.h b/lib/sha256/gcrypt.h
similarity index 100%
rename from sha256/gcrypt.h
rename to lib/sha256/gcrypt.h
diff --git a/sha256/nettle.h b/lib/sha256/nettle.h
similarity index 100%
rename from sha256/nettle.h
rename to lib/sha256/nettle.h
diff --git a/sha256/openssl.h b/lib/sha256/openssl.h
similarity index 100%
rename from sha256/openssl.h
rename to lib/sha256/openssl.h
diff --git a/shallow.c b/lib/shallow.c
similarity index 100%
rename from shallow.c
rename to lib/shallow.c
diff --git a/shallow.h b/lib/shallow.h
similarity index 100%
rename from shallow.h
rename to lib/shallow.h
diff --git a/shortlog.h b/lib/shortlog.h
similarity index 100%
rename from shortlog.h
rename to lib/shortlog.h
diff --git a/sideband.c b/lib/sideband.c
similarity index 100%
rename from sideband.c
rename to lib/sideband.c
diff --git a/sideband.h b/lib/sideband.h
similarity index 100%
rename from sideband.h
rename to lib/sideband.h
diff --git a/sigchain.c b/lib/sigchain.c
similarity index 100%
rename from sigchain.c
rename to lib/sigchain.c
diff --git a/sigchain.h b/lib/sigchain.h
similarity index 100%
rename from sigchain.h
rename to lib/sigchain.h
diff --git a/simple-ipc.h b/lib/simple-ipc.h
similarity index 100%
rename from simple-ipc.h
rename to lib/simple-ipc.h
diff --git a/sparse-index.c b/lib/sparse-index.c
similarity index 100%
rename from sparse-index.c
rename to lib/sparse-index.c
diff --git a/sparse-index.h b/lib/sparse-index.h
similarity index 100%
rename from sparse-index.h
rename to lib/sparse-index.h
diff --git a/split-index.c b/lib/split-index.c
similarity index 100%
rename from split-index.c
rename to lib/split-index.c
diff --git a/split-index.h b/lib/split-index.h
similarity index 100%
rename from split-index.h
rename to lib/split-index.h
diff --git a/stable-qsort.c b/lib/stable-qsort.c
similarity index 100%
rename from stable-qsort.c
rename to lib/stable-qsort.c
diff --git a/statinfo.c b/lib/statinfo.c
similarity index 100%
rename from statinfo.c
rename to lib/statinfo.c
diff --git a/statinfo.h b/lib/statinfo.h
similarity index 100%
rename from statinfo.h
rename to lib/statinfo.h
diff --git a/strbuf.c b/lib/strbuf.c
similarity index 100%
rename from strbuf.c
rename to lib/strbuf.c
diff --git a/strbuf.h b/lib/strbuf.h
similarity index 100%
rename from strbuf.h
rename to lib/strbuf.h
diff --git a/string-list.c b/lib/string-list.c
similarity index 100%
rename from string-list.c
rename to lib/string-list.c
diff --git a/string-list.h b/lib/string-list.h
similarity index 100%
rename from string-list.h
rename to lib/string-list.h
diff --git a/strmap.c b/lib/strmap.c
similarity index 100%
rename from strmap.c
rename to lib/strmap.c
diff --git a/strmap.h b/lib/strmap.h
similarity index 100%
rename from strmap.h
rename to lib/strmap.h
diff --git a/strvec.c b/lib/strvec.c
similarity index 100%
rename from strvec.c
rename to lib/strvec.c
diff --git a/strvec.h b/lib/strvec.h
similarity index 100%
rename from strvec.h
rename to lib/strvec.h
diff --git a/sub-process.c b/lib/sub-process.c
similarity index 100%
rename from sub-process.c
rename to lib/sub-process.c
diff --git a/sub-process.h b/lib/sub-process.h
similarity index 100%
rename from sub-process.h
rename to lib/sub-process.h
diff --git a/submodule-config.c b/lib/submodule-config.c
similarity index 100%
rename from submodule-config.c
rename to lib/submodule-config.c
diff --git a/submodule-config.h b/lib/submodule-config.h
similarity index 100%
rename from submodule-config.h
rename to lib/submodule-config.h
diff --git a/submodule.c b/lib/submodule.c
similarity index 100%
rename from submodule.c
rename to lib/submodule.c
diff --git a/submodule.h b/lib/submodule.h
similarity index 100%
rename from submodule.h
rename to lib/submodule.h
diff --git a/symlinks.c b/lib/symlinks.c
similarity index 100%
rename from symlinks.c
rename to lib/symlinks.c
diff --git a/symlinks.h b/lib/symlinks.h
similarity index 100%
rename from symlinks.h
rename to lib/symlinks.h
diff --git a/tag.c b/lib/tag.c
similarity index 100%
rename from tag.c
rename to lib/tag.c
diff --git a/tag.h b/lib/tag.h
similarity index 100%
rename from tag.h
rename to lib/tag.h
diff --git a/tar.h b/lib/tar.h
similarity index 100%
rename from tar.h
rename to lib/tar.h
diff --git a/tempfile.c b/lib/tempfile.c
similarity index 100%
rename from tempfile.c
rename to lib/tempfile.c
diff --git a/tempfile.h b/lib/tempfile.h
similarity index 100%
rename from tempfile.h
rename to lib/tempfile.h
diff --git a/thread-utils.c b/lib/thread-utils.c
similarity index 100%
rename from thread-utils.c
rename to lib/thread-utils.c
diff --git a/thread-utils.h b/lib/thread-utils.h
similarity index 100%
rename from thread-utils.h
rename to lib/thread-utils.h
diff --git a/tmp-objdir.c b/lib/tmp-objdir.c
similarity index 100%
rename from tmp-objdir.c
rename to lib/tmp-objdir.c
diff --git a/tmp-objdir.h b/lib/tmp-objdir.h
similarity index 100%
rename from tmp-objdir.h
rename to lib/tmp-objdir.h
diff --git a/trace.c b/lib/trace.c
similarity index 100%
rename from trace.c
rename to lib/trace.c
diff --git a/trace.h b/lib/trace.h
similarity index 100%
rename from trace.h
rename to lib/trace.h
diff --git a/trace2.c b/lib/trace2.c
similarity index 100%
rename from trace2.c
rename to lib/trace2.c
diff --git a/trace2.h b/lib/trace2.h
similarity index 100%
rename from trace2.h
rename to lib/trace2.h
diff --git a/trace2/tr2_cfg.c b/lib/trace2/tr2_cfg.c
similarity index 100%
rename from trace2/tr2_cfg.c
rename to lib/trace2/tr2_cfg.c
diff --git a/trace2/tr2_cfg.h b/lib/trace2/tr2_cfg.h
similarity index 100%
rename from trace2/tr2_cfg.h
rename to lib/trace2/tr2_cfg.h
diff --git a/trace2/tr2_cmd_name.c b/lib/trace2/tr2_cmd_name.c
similarity index 100%
rename from trace2/tr2_cmd_name.c
rename to lib/trace2/tr2_cmd_name.c
diff --git a/trace2/tr2_cmd_name.h b/lib/trace2/tr2_cmd_name.h
similarity index 100%
rename from trace2/tr2_cmd_name.h
rename to lib/trace2/tr2_cmd_name.h
diff --git a/trace2/tr2_ctr.c b/lib/trace2/tr2_ctr.c
similarity index 100%
rename from trace2/tr2_ctr.c
rename to lib/trace2/tr2_ctr.c
diff --git a/trace2/tr2_ctr.h b/lib/trace2/tr2_ctr.h
similarity index 100%
rename from trace2/tr2_ctr.h
rename to lib/trace2/tr2_ctr.h
diff --git a/trace2/tr2_dst.c b/lib/trace2/tr2_dst.c
similarity index 100%
rename from trace2/tr2_dst.c
rename to lib/trace2/tr2_dst.c
diff --git a/trace2/tr2_dst.h b/lib/trace2/tr2_dst.h
similarity index 100%
rename from trace2/tr2_dst.h
rename to lib/trace2/tr2_dst.h
diff --git a/trace2/tr2_sid.c b/lib/trace2/tr2_sid.c
similarity index 100%
rename from trace2/tr2_sid.c
rename to lib/trace2/tr2_sid.c
diff --git a/trace2/tr2_sid.h b/lib/trace2/tr2_sid.h
similarity index 100%
rename from trace2/tr2_sid.h
rename to lib/trace2/tr2_sid.h
diff --git a/trace2/tr2_sysenv.c b/lib/trace2/tr2_sysenv.c
similarity index 100%
rename from trace2/tr2_sysenv.c
rename to lib/trace2/tr2_sysenv.c
diff --git a/trace2/tr2_sysenv.h b/lib/trace2/tr2_sysenv.h
similarity index 100%
rename from trace2/tr2_sysenv.h
rename to lib/trace2/tr2_sysenv.h
diff --git a/trace2/tr2_tbuf.c b/lib/trace2/tr2_tbuf.c
similarity index 100%
rename from trace2/tr2_tbuf.c
rename to lib/trace2/tr2_tbuf.c
diff --git a/trace2/tr2_tbuf.h b/lib/trace2/tr2_tbuf.h
similarity index 100%
rename from trace2/tr2_tbuf.h
rename to lib/trace2/tr2_tbuf.h
diff --git a/trace2/tr2_tgt.h b/lib/trace2/tr2_tgt.h
similarity index 100%
rename from trace2/tr2_tgt.h
rename to lib/trace2/tr2_tgt.h
diff --git a/trace2/tr2_tgt_event.c b/lib/trace2/tr2_tgt_event.c
similarity index 100%
rename from trace2/tr2_tgt_event.c
rename to lib/trace2/tr2_tgt_event.c
diff --git a/trace2/tr2_tgt_normal.c b/lib/trace2/tr2_tgt_normal.c
similarity index 100%
rename from trace2/tr2_tgt_normal.c
rename to lib/trace2/tr2_tgt_normal.c
diff --git a/trace2/tr2_tgt_perf.c b/lib/trace2/tr2_tgt_perf.c
similarity index 100%
rename from trace2/tr2_tgt_perf.c
rename to lib/trace2/tr2_tgt_perf.c
diff --git a/trace2/tr2_tls.c b/lib/trace2/tr2_tls.c
similarity index 100%
rename from trace2/tr2_tls.c
rename to lib/trace2/tr2_tls.c
diff --git a/trace2/tr2_tls.h b/lib/trace2/tr2_tls.h
similarity index 100%
rename from trace2/tr2_tls.h
rename to lib/trace2/tr2_tls.h
diff --git a/trace2/tr2_tmr.c b/lib/trace2/tr2_tmr.c
similarity index 100%
rename from trace2/tr2_tmr.c
rename to lib/trace2/tr2_tmr.c
diff --git a/trace2/tr2_tmr.h b/lib/trace2/tr2_tmr.h
similarity index 100%
rename from trace2/tr2_tmr.h
rename to lib/trace2/tr2_tmr.h
diff --git a/trailer.c b/lib/trailer.c
similarity index 100%
rename from trailer.c
rename to lib/trailer.c
diff --git a/trailer.h b/lib/trailer.h
similarity index 100%
rename from trailer.h
rename to lib/trailer.h
diff --git a/transport-helper.c b/lib/transport-helper.c
similarity index 100%
rename from transport-helper.c
rename to lib/transport-helper.c
diff --git a/transport-internal.h b/lib/transport-internal.h
similarity index 100%
rename from transport-internal.h
rename to lib/transport-internal.h
diff --git a/transport.c b/lib/transport.c
similarity index 100%
rename from transport.c
rename to lib/transport.c
diff --git a/transport.h b/lib/transport.h
similarity index 100%
rename from transport.h
rename to lib/transport.h
diff --git a/tree-diff.c b/lib/tree-diff.c
similarity index 100%
rename from tree-diff.c
rename to lib/tree-diff.c
diff --git a/tree-walk.c b/lib/tree-walk.c
similarity index 100%
rename from tree-walk.c
rename to lib/tree-walk.c
diff --git a/tree-walk.h b/lib/tree-walk.h
similarity index 100%
rename from tree-walk.h
rename to lib/tree-walk.h
diff --git a/tree.c b/lib/tree.c
similarity index 100%
rename from tree.c
rename to lib/tree.c
diff --git a/tree.h b/lib/tree.h
similarity index 100%
rename from tree.h
rename to lib/tree.h
diff --git a/unicode-width.h b/lib/unicode-width.h
similarity index 100%
rename from unicode-width.h
rename to lib/unicode-width.h
diff --git a/unix-socket.c b/lib/unix-socket.c
similarity index 100%
rename from unix-socket.c
rename to lib/unix-socket.c
diff --git a/unix-socket.h b/lib/unix-socket.h
similarity index 100%
rename from unix-socket.h
rename to lib/unix-socket.h
diff --git a/unix-stream-server.c b/lib/unix-stream-server.c
similarity index 100%
rename from unix-stream-server.c
rename to lib/unix-stream-server.c
diff --git a/unix-stream-server.h b/lib/unix-stream-server.h
similarity index 100%
rename from unix-stream-server.h
rename to lib/unix-stream-server.h
diff --git a/unpack-trees.c b/lib/unpack-trees.c
similarity index 100%
rename from unpack-trees.c
rename to lib/unpack-trees.c
diff --git a/unpack-trees.h b/lib/unpack-trees.h
similarity index 100%
rename from unpack-trees.h
rename to lib/unpack-trees.h
diff --git a/upload-pack.c b/lib/upload-pack.c
similarity index 100%
rename from upload-pack.c
rename to lib/upload-pack.c
diff --git a/upload-pack.h b/lib/upload-pack.h
similarity index 100%
rename from upload-pack.h
rename to lib/upload-pack.h
diff --git a/url.c b/lib/url.c
similarity index 100%
rename from url.c
rename to lib/url.c
diff --git a/url.h b/lib/url.h
similarity index 100%
rename from url.h
rename to lib/url.h
diff --git a/urlmatch.c b/lib/urlmatch.c
similarity index 100%
rename from urlmatch.c
rename to lib/urlmatch.c
diff --git a/urlmatch.h b/lib/urlmatch.h
similarity index 100%
rename from urlmatch.h
rename to lib/urlmatch.h
diff --git a/usage.c b/lib/usage.c
similarity index 100%
rename from usage.c
rename to lib/usage.c
diff --git a/userdiff.c b/lib/userdiff.c
similarity index 100%
rename from userdiff.c
rename to lib/userdiff.c
diff --git a/userdiff.h b/lib/userdiff.h
similarity index 100%
rename from userdiff.h
rename to lib/userdiff.h
diff --git a/utf8.c b/lib/utf8.c
similarity index 100%
rename from utf8.c
rename to lib/utf8.c
diff --git a/utf8.h b/lib/utf8.h
similarity index 100%
rename from utf8.h
rename to lib/utf8.h
diff --git a/varint.c b/lib/varint.c
similarity index 100%
rename from varint.c
rename to lib/varint.c
diff --git a/varint.h b/lib/varint.h
similarity index 100%
rename from varint.h
rename to lib/varint.h
diff --git a/version-def.h.in b/lib/version-def.h.in
similarity index 100%
rename from version-def.h.in
rename to lib/version-def.h.in
diff --git a/version.c b/lib/version.c
similarity index 100%
rename from version.c
rename to lib/version.c
diff --git a/version.h b/lib/version.h
similarity index 100%
rename from version.h
rename to lib/version.h
diff --git a/versioncmp.c b/lib/versioncmp.c
similarity index 100%
rename from versioncmp.c
rename to lib/versioncmp.c
diff --git a/versioncmp.h b/lib/versioncmp.h
similarity index 100%
rename from versioncmp.h
rename to lib/versioncmp.h
diff --git a/walker.c b/lib/walker.c
similarity index 100%
rename from walker.c
rename to lib/walker.c
diff --git a/walker.h b/lib/walker.h
similarity index 100%
rename from walker.h
rename to lib/walker.h
diff --git a/wildmatch.c b/lib/wildmatch.c
similarity index 100%
rename from wildmatch.c
rename to lib/wildmatch.c
diff --git a/wildmatch.h b/lib/wildmatch.h
similarity index 100%
rename from wildmatch.h
rename to lib/wildmatch.h
diff --git a/worktree.c b/lib/worktree.c
similarity index 100%
rename from worktree.c
rename to lib/worktree.c
diff --git a/worktree.h b/lib/worktree.h
similarity index 100%
rename from worktree.h
rename to lib/worktree.h
diff --git a/wrapper.c b/lib/wrapper.c
similarity index 100%
rename from wrapper.c
rename to lib/wrapper.c
diff --git a/wrapper.h b/lib/wrapper.h
similarity index 100%
rename from wrapper.h
rename to lib/wrapper.h
diff --git a/write-or-die.c b/lib/write-or-die.c
similarity index 100%
rename from write-or-die.c
rename to lib/write-or-die.c
diff --git a/write-or-die.h b/lib/write-or-die.h
similarity index 100%
rename from write-or-die.h
rename to lib/write-or-die.h
diff --git a/ws.c b/lib/ws.c
similarity index 100%
rename from ws.c
rename to lib/ws.c
diff --git a/ws.h b/lib/ws.h
similarity index 100%
rename from ws.h
rename to lib/ws.h
diff --git a/wt-status.c b/lib/wt-status.c
similarity index 100%
rename from wt-status.c
rename to lib/wt-status.c
diff --git a/wt-status.h b/lib/wt-status.h
similarity index 100%
rename from wt-status.h
rename to lib/wt-status.h
diff --git a/xdiff-interface.c b/lib/xdiff-interface.c
similarity index 100%
rename from xdiff-interface.c
rename to lib/xdiff-interface.c
diff --git a/xdiff-interface.h b/lib/xdiff-interface.h
similarity index 100%
rename from xdiff-interface.h
rename to lib/xdiff-interface.h
diff --git a/xdiff/xdiff.h b/lib/xdiff/xdiff.h
similarity index 100%
rename from xdiff/xdiff.h
rename to lib/xdiff/xdiff.h
diff --git a/xdiff/xdiffi.c b/lib/xdiff/xdiffi.c
similarity index 100%
rename from xdiff/xdiffi.c
rename to lib/xdiff/xdiffi.c
diff --git a/xdiff/xdiffi.h b/lib/xdiff/xdiffi.h
similarity index 100%
rename from xdiff/xdiffi.h
rename to lib/xdiff/xdiffi.h
diff --git a/xdiff/xemit.c b/lib/xdiff/xemit.c
similarity index 100%
rename from xdiff/xemit.c
rename to lib/xdiff/xemit.c
diff --git a/xdiff/xemit.h b/lib/xdiff/xemit.h
similarity index 100%
rename from xdiff/xemit.h
rename to lib/xdiff/xemit.h
diff --git a/xdiff/xhistogram.c b/lib/xdiff/xhistogram.c
similarity index 100%
rename from xdiff/xhistogram.c
rename to lib/xdiff/xhistogram.c
diff --git a/xdiff/xinclude.h b/lib/xdiff/xinclude.h
similarity index 100%
rename from xdiff/xinclude.h
rename to lib/xdiff/xinclude.h
diff --git a/xdiff/xmacros.h b/lib/xdiff/xmacros.h
similarity index 100%
rename from xdiff/xmacros.h
rename to lib/xdiff/xmacros.h
diff --git a/xdiff/xmerge.c b/lib/xdiff/xmerge.c
similarity index 100%
rename from xdiff/xmerge.c
rename to lib/xdiff/xmerge.c
diff --git a/xdiff/xpatience.c b/lib/xdiff/xpatience.c
similarity index 100%
rename from xdiff/xpatience.c
rename to lib/xdiff/xpatience.c
diff --git a/xdiff/xprepare.c b/lib/xdiff/xprepare.c
similarity index 100%
rename from xdiff/xprepare.c
rename to lib/xdiff/xprepare.c
diff --git a/xdiff/xprepare.h b/lib/xdiff/xprepare.h
similarity index 100%
rename from xdiff/xprepare.h
rename to lib/xdiff/xprepare.h
diff --git a/xdiff/xtypes.h b/lib/xdiff/xtypes.h
similarity index 100%
rename from xdiff/xtypes.h
rename to lib/xdiff/xtypes.h
diff --git a/xdiff/xutils.c b/lib/xdiff/xutils.c
similarity index 100%
rename from xdiff/xutils.c
rename to lib/xdiff/xutils.c
diff --git a/xdiff/xutils.h b/lib/xdiff/xutils.h
similarity index 100%
rename from xdiff/xutils.h
rename to lib/xdiff/xutils.h
diff --git a/meson.build b/meson.build
index ca235801cf..2f90bed441 100644
--- a/meson.build
+++ b/meson.build
@@ -272,293 +272,293 @@ version_gen_environment.set('GIT_VERSION', get_option('version'))
 compiler = meson.get_compiler('c')
 
 compat_sources = [
-  'compat/nonblock.c',
-  'compat/obstack.c',
-  'compat/open.c',
-  'compat/terminal.c',
+  'lib/compat/nonblock.c',
+  'lib/compat/obstack.c',
+  'lib/compat/open.c',
+  'lib/compat/terminal.c',
 ]
 
 libgit_sources = [
-  'abspath.c',
-  'add-interactive.c',
-  'add-patch.c',
-  'advice.c',
-  'alias.c',
-  'alloc.c',
-  'apply.c',
-  'archive-tar.c',
-  'archive-zip.c',
-  'archive.c',
-  'attr.c',
-  'base85.c',
-  'bisect.c',
-  'blame.c',
-  'blob.c',
-  'bloom.c',
-  'branch.c',
-  'bundle-uri.c',
-  'bundle.c',
-  'cache-tree.c',
-  'cbtree.c',
-  'chdir-notify.c',
-  'checkout.c',
-  'chunk-format.c',
-  'color.c',
-  'column.c',
-  'combine-diff.c',
-  'commit-graph.c',
-  'commit-reach.c',
-  'commit.c',
-  'common-exit.c',
-  'common-init.c',
-  'compiler-tricks/not-constant.c',
-  'config.c',
-  'connect.c',
-  'connected.c',
-  'convert.c',
-  'copy.c',
-  'credential.c',
-  'csum-file.c',
-  'ctype.c',
-  'date.c',
-  'decorate.c',
-  'delta-islands.c',
-  'diagnose.c',
-  'diff-delta.c',
-  'diff-merges.c',
-  'diff-lib.c',
-  'diff-no-index.c',
-  'diff.c',
-  'diffcore-break.c',
-  'diffcore-delta.c',
-  'diffcore-order.c',
-  'diffcore-pickaxe.c',
-  'diffcore-rename.c',
-  'diffcore-rotate.c',
-  'dir-iterator.c',
-  'dir.c',
-  'editor.c',
-  'entry.c',
-  'environment.c',
-  'ewah/bitmap.c',
-  'ewah/ewah_bitmap.c',
-  'ewah/ewah_io.c',
-  'ewah/ewah_rlw.c',
-  'exec-cmd.c',
-  'fetch-negotiator.c',
-  'fetch-pack.c',
-  'fmt-merge-msg.c',
-  'fsck.c',
-  'fsmonitor.c',
-  'fsmonitor-ipc.c',
-  'fsmonitor-settings.c',
-  'gettext.c',
-  'git-zlib.c',
-  'gpg-interface.c',
-  'graph.c',
-  'grep.c',
-  'hash-lookup.c',
-  'hash.c',
-  'hashmap.c',
-  'help.c',
-  'hex.c',
-  'hex-ll.c',
-  'hook.c',
-  'ident.c',
-  'json-writer.c',
-  'kwset.c',
-  'levenshtein.c',
-  'line-log.c',
-  'line-range.c',
-  'linear-assignment.c',
-  'list-objects-filter-options.c',
-  'list-objects-filter.c',
-  'list-objects.c',
-  'lockfile.c',
-  'log-tree.c',
-  'loose.c',
-  'ls-refs.c',
-  'mailinfo.c',
-  'mailmap.c',
-  'match-trees.c',
-  'mem-pool.c',
-  'merge-blobs.c',
-  'merge-ll.c',
-  'merge-ort.c',
-  'merge-ort-wrappers.c',
-  'merge.c',
-  'midx.c',
-  'midx-write.c',
-  'name-hash.c',
-  'negotiator/default.c',
-  'negotiator/noop.c',
-  'negotiator/skipping.c',
-  'notes-cache.c',
-  'notes-merge.c',
-  'notes-utils.c',
-  'notes.c',
-  'object-file-convert.c',
-  'object-file.c',
-  'object-name.c',
-  'object.c',
-  'odb.c',
-  'odb/source.c',
-  'odb/source-files.c',
-  'odb/source-inmemory.c',
-  'odb/source-loose.c',
-  'odb/source-packed.c',
-  'odb/streaming.c',
-  'odb/transaction.c',
-  'oid-array.c',
-  'oidmap.c',
-  'oidset.c',
-  'oidtree.c',
-  'pack-bitmap-write.c',
-  'pack-bitmap.c',
-  'pack-check.c',
-  'pack-mtimes.c',
-  'pack-objects.c',
-  'pack-refs.c',
-  'pack-revindex.c',
-  'pack-write.c',
-  'packfile.c',
-  'packfile-list.c',
-  'pager.c',
-  'parallel-checkout.c',
-  'parse.c',
-  'parse-options-cb.c',
-  'parse-options.c',
-  'patch-delta.c',
-  'patch-ids.c',
-  'path.c',
-  'path-walk.c',
-  'pathspec.c',
-  'pkt-line.c',
-  'preload-index.c',
-  'pretty.c',
-  'prio-queue.c',
-  'progress.c',
-  'promisor-remote.c',
-  'prompt.c',
-  'protocol.c',
-  'protocol-caps.c',
-  'prune-packed.c',
-  'pseudo-merge.c',
-  'quote.c',
-  'range-diff.c',
-  'reachable.c',
-  'read-cache.c',
-  'rebase-interactive.c',
-  'rebase.c',
-  'ref-filter.c',
-  'reflog-walk.c',
-  'reflog.c',
-  'refs.c',
-  'refs/debug.c',
-  'refs/files-backend.c',
-  'refs/reftable-backend.c',
-  'refs/iterator.c',
-  'refs/packed-backend.c',
-  'refs/ref-cache.c',
-  'refspec.c',
-  'reftable/basics.c',
-  'reftable/error.c',
-  'reftable/block.c',
-  'reftable/blocksource.c',
-  'reftable/fsck.c',
-  'reftable/iter.c',
-  'reftable/merged.c',
-  'reftable/pq.c',
-  'reftable/record.c',
-  'reftable/stack.c',
-  'reftable/system.c',
-  'reftable/table.c',
-  'reftable/tree.c',
-  'reftable/writer.c',
-  'remote.c',
-  'repack.c',
-  'repack-cruft.c',
-  'repack-filtered.c',
-  'repack-geometry.c',
-  'repack-midx.c',
-  'repack-promisor.c',
-  'replace-object.c',
-  'replay.c',
-  'repo-settings.c',
-  'repository.c',
-  'rerere.c',
-  'reset.c',
-  'resolve-undo.c',
-  'revision.c',
-  'run-command.c',
-  'send-pack.c',
-  'sequencer.c',
-  'serve.c',
-  'server-info.c',
-  'setup.c',
-  'shallow.c',
-  'sideband.c',
-  'sigchain.c',
-  'sparse-index.c',
-  'split-index.c',
-  'stable-qsort.c',
-  'statinfo.c',
-  'strbuf.c',
-  'string-list.c',
-  'strmap.c',
-  'strvec.c',
-  'sub-process.c',
-  'submodule-config.c',
-  'submodule.c',
-  'symlinks.c',
-  'tag.c',
-  'tempfile.c',
-  'thread-utils.c',
-  'tmp-objdir.c',
-  'trace.c',
-  'trace2.c',
-  'trace2/tr2_cfg.c',
-  'trace2/tr2_cmd_name.c',
-  'trace2/tr2_ctr.c',
-  'trace2/tr2_dst.c',
-  'trace2/tr2_sid.c',
-  'trace2/tr2_sysenv.c',
-  'trace2/tr2_tbuf.c',
-  'trace2/tr2_tgt_event.c',
-  'trace2/tr2_tgt_normal.c',
-  'trace2/tr2_tgt_perf.c',
-  'trace2/tr2_tls.c',
-  'trace2/tr2_tmr.c',
-  'trailer.c',
-  'transport-helper.c',
-  'transport.c',
-  'tree-diff.c',
-  'tree-walk.c',
-  'tree.c',
-  'unpack-trees.c',
-  'upload-pack.c',
-  'url.c',
-  'urlmatch.c',
-  'usage.c',
-  'userdiff.c',
-  'utf8.c',
-  'version.c',
-  'versioncmp.c',
-  'walker.c',
-  'wildmatch.c',
-  'worktree.c',
-  'wrapper.c',
-  'write-or-die.c',
-  'ws.c',
-  'wt-status.c',
-  'xdiff-interface.c',
-  'xdiff/xdiffi.c',
-  'xdiff/xemit.c',
-  'xdiff/xhistogram.c',
-  'xdiff/xmerge.c',
-  'xdiff/xpatience.c',
-  'xdiff/xprepare.c',
-  'xdiff/xutils.c',
+  'lib/abspath.c',
+  'lib/add-interactive.c',
+  'lib/add-patch.c',
+  'lib/advice.c',
+  'lib/alias.c',
+  'lib/alloc.c',
+  'lib/apply.c',
+  'lib/archive-tar.c',
+  'lib/archive-zip.c',
+  'lib/archive.c',
+  'lib/attr.c',
+  'lib/base85.c',
+  'lib/bisect.c',
+  'lib/blame.c',
+  'lib/blob.c',
+  'lib/bloom.c',
+  'lib/branch.c',
+  'lib/bundle-uri.c',
+  'lib/bundle.c',
+  'lib/cache-tree.c',
+  'lib/cbtree.c',
+  'lib/chdir-notify.c',
+  'lib/checkout.c',
+  'lib/chunk-format.c',
+  'lib/color.c',
+  'lib/column.c',
+  'lib/combine-diff.c',
+  'lib/commit-graph.c',
+  'lib/commit-reach.c',
+  'lib/commit.c',
+  'lib/common-exit.c',
+  'lib/common-init.c',
+  'lib/compiler-tricks/not-constant.c',
+  'lib/config.c',
+  'lib/connect.c',
+  'lib/connected.c',
+  'lib/convert.c',
+  'lib/copy.c',
+  'lib/credential.c',
+  'lib/csum-file.c',
+  'lib/ctype.c',
+  'lib/date.c',
+  'lib/decorate.c',
+  'lib/delta-islands.c',
+  'lib/diagnose.c',
+  'lib/diff-delta.c',
+  'lib/diff-merges.c',
+  'lib/diff-lib.c',
+  'lib/diff-no-index.c',
+  'lib/diff.c',
+  'lib/diffcore-break.c',
+  'lib/diffcore-delta.c',
+  'lib/diffcore-order.c',
+  'lib/diffcore-pickaxe.c',
+  'lib/diffcore-rename.c',
+  'lib/diffcore-rotate.c',
+  'lib/dir-iterator.c',
+  'lib/dir.c',
+  'lib/editor.c',
+  'lib/entry.c',
+  'lib/environment.c',
+  'lib/ewah/bitmap.c',
+  'lib/ewah/ewah_bitmap.c',
+  'lib/ewah/ewah_io.c',
+  'lib/ewah/ewah_rlw.c',
+  'lib/exec-cmd.c',
+  'lib/fetch-negotiator.c',
+  'lib/fetch-pack.c',
+  'lib/fmt-merge-msg.c',
+  'lib/fsck.c',
+  'lib/fsmonitor.c',
+  'lib/fsmonitor-ipc.c',
+  'lib/fsmonitor-settings.c',
+  'lib/gettext.c',
+  'lib/git-zlib.c',
+  'lib/gpg-interface.c',
+  'lib/graph.c',
+  'lib/grep.c',
+  'lib/hash-lookup.c',
+  'lib/hash.c',
+  'lib/hashmap.c',
+  'lib/help.c',
+  'lib/hex.c',
+  'lib/hex-ll.c',
+  'lib/hook.c',
+  'lib/ident.c',
+  'lib/json-writer.c',
+  'lib/kwset.c',
+  'lib/levenshtein.c',
+  'lib/line-log.c',
+  'lib/line-range.c',
+  'lib/linear-assignment.c',
+  'lib/list-objects-filter-options.c',
+  'lib/list-objects-filter.c',
+  'lib/list-objects.c',
+  'lib/lockfile.c',
+  'lib/log-tree.c',
+  'lib/loose.c',
+  'lib/ls-refs.c',
+  'lib/mailinfo.c',
+  'lib/mailmap.c',
+  'lib/match-trees.c',
+  'lib/mem-pool.c',
+  'lib/merge-blobs.c',
+  'lib/merge-ll.c',
+  'lib/merge-ort.c',
+  'lib/merge-ort-wrappers.c',
+  'lib/merge.c',
+  'lib/midx.c',
+  'lib/midx-write.c',
+  'lib/name-hash.c',
+  'lib/negotiator/default.c',
+  'lib/negotiator/noop.c',
+  'lib/negotiator/skipping.c',
+  'lib/notes-cache.c',
+  'lib/notes-merge.c',
+  'lib/notes-utils.c',
+  'lib/notes.c',
+  'lib/object-file-convert.c',
+  'lib/object-file.c',
+  'lib/object-name.c',
+  'lib/object.c',
+  'lib/odb.c',
+  'lib/odb/source.c',
+  'lib/odb/source-files.c',
+  'lib/odb/source-inmemory.c',
+  'lib/odb/source-loose.c',
+  'lib/odb/source-packed.c',
+  'lib/odb/streaming.c',
+  'lib/odb/transaction.c',
+  'lib/oid-array.c',
+  'lib/oidmap.c',
+  'lib/oidset.c',
+  'lib/oidtree.c',
+  'lib/pack-bitmap-write.c',
+  'lib/pack-bitmap.c',
+  'lib/pack-check.c',
+  'lib/pack-mtimes.c',
+  'lib/pack-objects.c',
+  'lib/pack-refs.c',
+  'lib/pack-revindex.c',
+  'lib/pack-write.c',
+  'lib/packfile.c',
+  'lib/packfile-list.c',
+  'lib/pager.c',
+  'lib/parallel-checkout.c',
+  'lib/parse.c',
+  'lib/parse-options-cb.c',
+  'lib/parse-options.c',
+  'lib/patch-delta.c',
+  'lib/patch-ids.c',
+  'lib/path.c',
+  'lib/path-walk.c',
+  'lib/pathspec.c',
+  'lib/pkt-line.c',
+  'lib/preload-index.c',
+  'lib/pretty.c',
+  'lib/prio-queue.c',
+  'lib/progress.c',
+  'lib/promisor-remote.c',
+  'lib/prompt.c',
+  'lib/protocol.c',
+  'lib/protocol-caps.c',
+  'lib/prune-packed.c',
+  'lib/pseudo-merge.c',
+  'lib/quote.c',
+  'lib/range-diff.c',
+  'lib/reachable.c',
+  'lib/read-cache.c',
+  'lib/rebase-interactive.c',
+  'lib/rebase.c',
+  'lib/ref-filter.c',
+  'lib/reflog-walk.c',
+  'lib/reflog.c',
+  'lib/refs.c',
+  'lib/refs/debug.c',
+  'lib/refs/files-backend.c',
+  'lib/refs/reftable-backend.c',
+  'lib/refs/iterator.c',
+  'lib/refs/packed-backend.c',
+  'lib/refs/ref-cache.c',
+  'lib/refspec.c',
+  'lib/reftable/basics.c',
+  'lib/reftable/error.c',
+  'lib/reftable/block.c',
+  'lib/reftable/blocksource.c',
+  'lib/reftable/fsck.c',
+  'lib/reftable/iter.c',
+  'lib/reftable/merged.c',
+  'lib/reftable/pq.c',
+  'lib/reftable/record.c',
+  'lib/reftable/stack.c',
+  'lib/reftable/system.c',
+  'lib/reftable/table.c',
+  'lib/reftable/tree.c',
+  'lib/reftable/writer.c',
+  'lib/remote.c',
+  'lib/repack.c',
+  'lib/repack-cruft.c',
+  'lib/repack-filtered.c',
+  'lib/repack-geometry.c',
+  'lib/repack-midx.c',
+  'lib/repack-promisor.c',
+  'lib/replace-object.c',
+  'lib/replay.c',
+  'lib/repo-settings.c',
+  'lib/repository.c',
+  'lib/rerere.c',
+  'lib/reset.c',
+  'lib/resolve-undo.c',
+  'lib/revision.c',
+  'lib/run-command.c',
+  'lib/send-pack.c',
+  'lib/sequencer.c',
+  'lib/serve.c',
+  'lib/server-info.c',
+  'lib/setup.c',
+  'lib/shallow.c',
+  'lib/sideband.c',
+  'lib/sigchain.c',
+  'lib/sparse-index.c',
+  'lib/split-index.c',
+  'lib/stable-qsort.c',
+  'lib/statinfo.c',
+  'lib/strbuf.c',
+  'lib/string-list.c',
+  'lib/strmap.c',
+  'lib/strvec.c',
+  'lib/sub-process.c',
+  'lib/submodule-config.c',
+  'lib/submodule.c',
+  'lib/symlinks.c',
+  'lib/tag.c',
+  'lib/tempfile.c',
+  'lib/thread-utils.c',
+  'lib/tmp-objdir.c',
+  'lib/trace.c',
+  'lib/trace2.c',
+  'lib/trace2/tr2_cfg.c',
+  'lib/trace2/tr2_cmd_name.c',
+  'lib/trace2/tr2_ctr.c',
+  'lib/trace2/tr2_dst.c',
+  'lib/trace2/tr2_sid.c',
+  'lib/trace2/tr2_sysenv.c',
+  'lib/trace2/tr2_tbuf.c',
+  'lib/trace2/tr2_tgt_event.c',
+  'lib/trace2/tr2_tgt_normal.c',
+  'lib/trace2/tr2_tgt_perf.c',
+  'lib/trace2/tr2_tls.c',
+  'lib/trace2/tr2_tmr.c',
+  'lib/trailer.c',
+  'lib/transport-helper.c',
+  'lib/transport.c',
+  'lib/tree-diff.c',
+  'lib/tree-walk.c',
+  'lib/tree.c',
+  'lib/unpack-trees.c',
+  'lib/upload-pack.c',
+  'lib/url.c',
+  'lib/urlmatch.c',
+  'lib/usage.c',
+  'lib/userdiff.c',
+  'lib/utf8.c',
+  'lib/version.c',
+  'lib/versioncmp.c',
+  'lib/walker.c',
+  'lib/wildmatch.c',
+  'lib/worktree.c',
+  'lib/wrapper.c',
+  'lib/write-or-die.c',
+  'lib/ws.c',
+  'lib/wt-status.c',
+  'lib/xdiff-interface.c',
+  'lib/xdiff/xdiffi.c',
+  'lib/xdiff/xemit.c',
+  'lib/xdiff/xhistogram.c',
+  'lib/xdiff/xmerge.c',
+  'lib/xdiff/xpatience.c',
+  'lib/xdiff/xprepare.c',
+  'lib/xdiff/xutils.c',
 ]
 
 libgit_sources += custom_target(
@@ -713,17 +713,16 @@ builtin_sources = [
 ]
 
 third_party_excludes = [
-  ':!contrib',
-  ':!compat/inet_ntop.c',
-  ':!compat/inet_pton.c',
-  ':!compat/obstack.*',
-  ':!compat/poll',
-  ':!compat/regex',
-  ':!sha1collisiondetection',
-  ':!sha1dc',
+  ':!lib/contrib',
+  ':!lib/compat/inet_ntop.c',
+  ':!lib/compat/inet_pton.c',
+  ':!lib/compat/obstack.*',
+  ':!lib/compat/poll',
+  ':!lib/compat/regex',
+  ':!lib/sha1collisiondetection',
+  ':!lib/sha1dc',
   ':!t/unit-tests/clar',
   ':!t/t[0-9][0-9][0-9][0-9]*',
-  ':!xdiff',
 ]
 
 headers_to_check = []
@@ -840,7 +839,7 @@ if help_format_opt != 'man'
     libgit_c_args += '-DDEFAULT_HELP_FORMAT="' + help_format_opt + '"'
 endif
 
-libgit_include_directories = [ '.' ]
+libgit_include_directories = [ 'lib' ]
 libgit_dependencies = [ ]
 
 # Treat any warning level above 1 the same as we treat DEVELOPER=1 in our
@@ -1189,8 +1188,8 @@ endif
 
 if not has_poll_h and not has_sys_poll_h
   libgit_c_args += '-DNO_POLL'
-  compat_sources += 'compat/poll/poll.c'
-  libgit_include_directories += 'compat/poll'
+  compat_sources += 'lib/compat/poll/poll.c'
+  libgit_include_directories += 'lib/compat/poll'
 endif
 
 if not compiler.has_header('inttypes.h')
@@ -1205,7 +1204,7 @@ endif
 # implementation to threat things like drive prefixes specially.
 if host_machine.system() == 'windows' or not compiler.has_header('libgen.h')
   libgit_c_args += '-DNO_LIBGEN_H'
-  compat_sources += 'compat/basename.c'
+  compat_sources += 'lib/compat/basename.c'
 endif
 
 if compiler.has_header('paths.h')
@@ -1235,7 +1234,7 @@ if host_machine.system() != 'windows'
   foreach symbol : ['inet_ntop', 'inet_pton', 'hstrerror']
     if not compiler.has_function(symbol, dependencies: networking_dependencies)
       libgit_c_args += '-DNO_' + symbol.to_upper()
-      compat_sources += 'compat/' + symbol + '.c'
+      compat_sources += 'lib/compat/' + symbol + '.c'
     endif
   endforeach
 endif
@@ -1267,8 +1266,8 @@ endif
 
 if compiler.has_function('socket', dependencies: networking_dependencies)
   libgit_sources += [
-    'unix-socket.c',
-    'unix-stream-server.c',
+    'lib/unix-socket.c',
+    'lib/unix-stream-server.c',
   ]
   build_options_config.set('NO_UNIX_SOCKETS', '')
 else
@@ -1277,7 +1276,7 @@ else
 endif
 
 if host_machine.system() == 'darwin'
-  compat_sources += 'compat/precompose_utf8.c'
+  compat_sources += 'lib/compat/precompose_utf8.c'
   libgit_c_args += '-DPRECOMPOSE_UNICODE'
   libgit_c_args += '-DPROTECT_HFS_DEFAULT'
 endif
@@ -1285,17 +1284,17 @@ endif
 # Configure general compatibility wrappers.
 if host_machine.system() == 'cygwin'
   compat_sources += [
-    'compat/win32/path-utils.c',
+    'lib/compat/win32/path-utils.c',
   ]
 elif host_machine.system() == 'windows'
   compat_sources += [
-    'compat/winansi.c',
-    'compat/win32/dirent.c',
-    'compat/win32/flush.c',
-    'compat/win32/path-utils.c',
-    'compat/win32/pthread.c',
-    'compat/win32/syslog.c',
-    'compat/win32mmap.c',
+    'lib/compat/winansi.c',
+    'lib/compat/win32/dirent.c',
+    'lib/compat/win32/flush.c',
+    'lib/compat/win32/path-utils.c',
+    'lib/compat/win32/pthread.c',
+    'lib/compat/win32/syslog.c',
+    'lib/compat/win32mmap.c',
   ]
 
   libgit_c_args += [
@@ -1311,23 +1310,23 @@ elif host_machine.system() == 'windows'
   ]
 
   libgit_dependencies += compiler.find_library('ntdll')
-  libgit_include_directories += 'compat/win32'
+  libgit_include_directories += 'lib/compat/win32'
   if compiler.get_id() == 'msvc'
-    libgit_include_directories += 'compat/vcbuild/include'
-    compat_sources += 'compat/msvc.c'
+    libgit_include_directories += 'lib/compat/vcbuild/include'
+    compat_sources += 'lib/compat/msvc.c'
   else
-    compat_sources += 'compat/mingw.c'
+    compat_sources += 'lib/compat/mingw.c'
   endif
 endif
 
 if host_machine.system() == 'linux'
-  compat_sources += 'compat/linux/procinfo.c'
+  compat_sources += 'lib/compat/linux/procinfo.c'
 elif host_machine.system() == 'windows'
-  compat_sources += 'compat/win32/trace2_win32_process_info.c'
+  compat_sources += 'lib/compat/win32/trace2_win32_process_info.c'
 elif host_machine.system() == 'darwin'
-  compat_sources += 'compat/darwin/procinfo.c'
+  compat_sources += 'lib/compat/darwin/procinfo.c'
 else
-  compat_sources += 'compat/stub/procinfo.c'
+  compat_sources += 'lib/compat/stub/procinfo.c'
 endif
 
 if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
@@ -1341,14 +1340,14 @@ endif
 # Configure the simple-ipc subsystem required fro the fsmonitor.
 if host_machine.system() == 'windows'
   compat_sources += [
-    'compat/simple-ipc/ipc-shared.c',
-    'compat/simple-ipc/ipc-win32.c',
+    'lib/compat/simple-ipc/ipc-shared.c',
+    'lib/compat/simple-ipc/ipc-win32.c',
   ]
   libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'
 else
   compat_sources += [
-    'compat/simple-ipc/ipc-shared.c',
-    'compat/simple-ipc/ipc-unix-socket.c',
+    'lib/compat/simple-ipc/ipc-shared.c',
+    'lib/compat/simple-ipc/ipc-unix-socket.c',
   ]
   libgit_c_args += '-DSUPPORTS_SIMPLE_IPC'
 endif
@@ -1372,11 +1371,11 @@ if fsmonitor_backend != ''
   libgit_c_args += '-DHAVE_FSMONITOR_OS_SETTINGS'
 
   compat_sources += [
-    'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',
-    'compat/fsmonitor/fsm-ipc-' + fsmonitor_os + '.c',
-    'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',
-    'compat/fsmonitor/fsm-path-utils-' + fsmonitor_backend + '.c',
-    'compat/fsmonitor/fsm-settings-' + fsmonitor_os + '.c',
+    'lib/compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c',
+    'lib/compat/fsmonitor/fsm-ipc-' + fsmonitor_os + '.c',
+    'lib/compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c',
+    'lib/compat/fsmonitor/fsm-path-utils-' + fsmonitor_backend + '.c',
+    'lib/compat/fsmonitor/fsm-settings-' + fsmonitor_os + '.c',
   ]
 endif
 build_options_config.set_quoted('FSMONITOR_DAEMON_BACKEND', fsmonitor_backend)
@@ -1387,7 +1386,7 @@ if not get_option('b_sanitize').contains('address') and get_option('regex').allo
 
   if compiler.get_define('REG_ENHANCED', prefix: '#include <regex.h>') != ''
     libgit_c_args += '-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS'
-    compat_sources += 'compat/regcomp_enhanced.c'
+    compat_sources += 'lib/compat/regcomp_enhanced.c'
   endif
 elif not get_option('regex').enabled()
   libgit_c_args += [
@@ -1396,13 +1395,13 @@ elif not get_option('regex').enabled()
     '-DNO_MBSUPPORT',
   ]
   build_options_config.set('NO_REGEX', '1')
-  compat_sources += 'compat/regex/regex.c'
-  libgit_include_directories += 'compat/regex'
+  compat_sources += 'lib/compat/regex/regex.c'
+  libgit_include_directories += 'lib/compat/regex'
 else
     error('Native regex support requested but not found')
 endif
 
-# setitimer and friends are provided by compat/mingw.c.
+# setitimer and friends are provided by lib/compat/mingw.c.
 if host_machine.system() != 'windows'
   if not compiler.compiles('''
     #include <sys/time.h>
@@ -1460,7 +1459,7 @@ else
 
   if get_option('b_sanitize').contains('address') or get_option('b_sanitize').contains('leak')
     libgit_c_args += '-DNO_MMAP'
-    compat_sources += 'compat/mmap.c'
+    compat_sources += 'lib/compat/mmap.c'
   else
     checkfuncs += { 'mmap': ['mmap.c'] }
   endif
@@ -1470,7 +1469,7 @@ foreach func, impls : checkfuncs
   if not compiler.has_function(func)
     libgit_c_args += '-DNO_' + func.to_upper()
     foreach impl : impls
-      compat_sources += 'compat/' + impl
+      compat_sources += 'lib/compat/' + impl
     endforeach
   endif
 endforeach
@@ -1481,13 +1480,13 @@ endif
 
 if not compiler.has_function('strdup')
   libgit_c_args += '-DOVERRIDE_STRDUP'
-  compat_sources += 'compat/strdup.c'
+  compat_sources += 'lib/compat/strdup.c'
 endif
 
 if not compiler.has_function('qsort')
   libgit_c_args += '-DINTERNAL_QSORT'
 endif
-compat_sources += 'compat/qsort_s.c'
+compat_sources += 'lib/compat/qsort_s.c'
 
 if compiler.has_function('getdelim')
   libgit_c_args += '-DHAVE_GETDELIM'
@@ -1543,7 +1542,7 @@ if meson.can_run_host_binaries() and compiler.run('''
   }
 ''', name: 'fread reads directories').returncode() == 0
   libgit_c_args += '-DFREAD_READS_DIRECTORIES'
-  compat_sources += 'compat/fopen.c'
+  compat_sources += 'lib/compat/fopen.c'
 endif
 
 if not meson.is_cross_build() and fs.exists('/dev/tty')
@@ -1596,9 +1595,9 @@ if sha1_backend == 'sha1dc'
   libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="git-compat-util.h"'
 
   libgit_sources += [
-    'sha1dc_git.c',
-    'sha1dc/sha1.c',
-    'sha1dc/ubc_check.c',
+    'lib/sha1dc_git.c',
+    'lib/sha1dc/sha1.c',
+    'lib/sha1dc/ubc_check.c',
   ]
 endif
 if sha1_backend == 'CommonCrypto' or sha1_unsafe_backend == 'CommonCrypto'
@@ -1631,7 +1630,7 @@ if sha1_backend == 'block' or sha1_unsafe_backend == 'block'
     libgit_c_args += '-DSHA1_BLK_UNSAFE'
   endif
 
-  libgit_sources += 'block-sha1/sha1.c'
+  libgit_sources += 'lib/block-sha1/sha1.c'
 endif
 
 if sha256_backend == 'openssl'
@@ -1647,7 +1646,7 @@ elif sha256_backend == 'gcrypt'
   libgit_c_args += '-DSHA256_GCRYPT'
 elif sha256_backend == 'block'
   libgit_c_args += '-DSHA256_BLK'
-  libgit_sources += 'sha256/block/sha256.c'
+  libgit_sources += 'lib/sha256/block/sha256.c'
 else
   error('Unhandled SHA256 backend ' + sha256_backend)
 endif
@@ -1752,7 +1751,7 @@ version_def_h = custom_target(
     '@INPUT@',
     '@OUTPUT@',
   ],
-  input: meson.current_source_dir() / 'version-def.h.in',
+  input: meson.current_source_dir() / 'lib/version-def.h.in',
   output: 'version-def.h',
   # Depend on GIT-VERSION-FILE so that we don't always try to rebuild this
   # target for the same commit.
@@ -1771,7 +1770,7 @@ if rust_option.allowed()
   endif
 else
   libgit_sources += [
-    'varint.c',
+    'lib/varint.c',
   ]
 endif
 
@@ -1894,8 +1893,8 @@ bin_wrappers += executable('scalar',
 if curl.found()
   libgit_curl = declare_dependency(
     sources: [
-      'http.c',
-      'http-walker.c',
+      'lib/http.c',
+      'lib/http-walker.c',
     ],
     dependencies: [libgit_commonmain, curl],
   )
@@ -2199,21 +2198,21 @@ if get_option('docs') != []
 endif
 
 exclude_from_check_headers = [
-  'compat/',
-  'unicode-width.h',
+  'lib/compat/',
+  'lib/unicode-width.h',
 ]
 
 if sha1_backend != 'openssl'
-  exclude_from_check_headers += 'sha1/openssl.h'
+  exclude_from_check_headers += 'lib/sha1/openssl.h'
 endif
 if sha256_backend != 'openssl'
-  exclude_from_check_headers += 'sha256/openssl.h'
+  exclude_from_check_headers += 'lib/sha256/openssl.h'
 endif
 if sha256_backend != 'nettle'
-  exclude_from_check_headers += 'sha256/nettle.h'
+  exclude_from_check_headers += 'lib/sha256/nettle.h'
 endif
 if sha256_backend != 'gcrypt'
-  exclude_from_check_headers += 'sha256/gcrypt.h'
+  exclude_from_check_headers += 'lib/sha256/gcrypt.h'
 endif
 
 if headers_to_check.length() != 0 and compiler.get_argument_syntax() == 'gcc'
@@ -2248,6 +2247,7 @@ if headers_to_check.length() != 0 and compiler.get_argument_syntax() == 'gcc'
         compiler.cmd_array(),
         libgit_c_args,
         '-I', meson.project_source_root(),
+        '-I', meson.project_source_root() / 'lib',
         '-I', meson.project_source_root() / 't/unit-tests',
         '-o', '/dev/null',
         '-c', '-xc',

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 00/12] odb: make optimizations pluggable
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260707-b4-pks-odb-optimize-v1-0-aae607667be4@pks.im>

Hi,

this patch series converts object housekeeping to become pluggable.
There isn't really anything else to say about this.

The series is built on top of f85a7e6620 (Start Git 2.56 cycle,
2026-07-06).

Changes in v2:
  - Make tests in t7900 a bit more robust by not checking for exact
    commands, but instead by checking for executed tasks.
  - Link to v1: https://patch.msgid.link/20260707-b4-pks-odb-optimize-v1-0-aae607667be4@pks.im

Thanks!

Patrick

---
Patrick Steinhardt (12):
      t7900: simplify how we check for maintenance tasks
      odb: run "pre-auto-gc" hook for all maintenance tasks
      builtin/gc: move worktree and rerere tasks before object optimizations
      builtin/gc: extract object database optimizations into separate function
      builtin/gc: make repack arguments self-contained
      builtin/gc: inline config values specific to the "files" backend
      builtin/gc: introduce object database optimization options
      builtin/gc: move geometric repacking into `odb_optimize()`
      builtin/gc: introduce `odb_optimize_required()`
      builtin/gc: refactor ODB optimizations to operate on "files" source
      builtin/gc: fix signedness issues in ODB-related functionality
      odb: make optimizations pluggable

 builtin/gc.c           | 534 ++++++++-----------------------------------------
 odb.c                  |  12 ++
 odb.h                  |  45 +++++
 odb/source-files.c     | 470 +++++++++++++++++++++++++++++++++++++++++++
 odb/source-files.h     |  15 ++
 odb/source.h           |  36 ++++
 t/t7900-maintenance.sh | 338 +++++++++++++++++++++----------
 7 files changed, 894 insertions(+), 556 deletions(-)

Range-diff versus v1:

 -:  ---------- >  1:  b05988c150 t7900: simplify how we check for maintenance tasks
 1:  df9ed71c10 !  2:  734d3c6d17 odb: run "pre-auto-gc" hook for all maintenance tasks
    @@ t/t7900-maintenance.sh: test_expect_success 'geometric repacking honors configur
     +			git maintenance run --auto 2>/dev/null &&
     +
     +		# The successful hook does not inhibit any of the tasks...
    -+		test_subcommand git reflog expire --all <trace2.txt &&
    -+		test_subcommand_flex git repack <trace2.txt &&
    -+		test_subcommand git rerere gc <trace2.txt &&
    ++		test_maintenance_tasks trace2.txt <<-\EOF &&
    ++		reflog-expire foreground
    ++		geometric-repack
    ++		rerere-gc
    ++		EOF
     +		# ... but it must only have been executed a single time.
     +		test_line_count = 1 hook.log
     +	)
    @@ t/t7900-maintenance.sh: test_expect_success 'geometric repacking honors configur
     +		# is expected to be the only child process being spawned, and
     +		# it must only run a single time.
     +		test_grep "child_start.*pre-auto-gc" trace2.txt &&
    -+		test_subcommand_flex ! git trace2 &&
    ++		test_maintenance_tasks trace2.txt <<-\EOF &&
    ++		EOF
     +		test_line_count = 1 hook.log
     +	)
     +'
    @@ t/t7900-maintenance.sh: test_expect_success 'geometric repacking honors configur
     +		# is expected to be the only child process being spawned, and
     +		# it must only run a single time.
     +		test_grep "child_start.*pre-auto-gc" trace2.txt &&
    ++		test_maintenance_tasks trace2.txt <<-\EOF &&
    ++		EOF
     +		test_subcommand_flex ! git trace2 &&
     +		test_line_count = 1 hook.log
     +	)
 2:  ba358cede1 =  3:  a61f01a1c1 builtin/gc: move worktree and rerere tasks before object optimizations
 3:  ffbaf71f46 =  4:  3d6ea9927b builtin/gc: extract object database optimizations into separate function
 4:  7b568dcd0c =  5:  de2c2c084d builtin/gc: make repack arguments self-contained
 5:  e18465b4b2 =  6:  0b4f6a553d builtin/gc: inline config values specific to the "files" backend
 6:  4ee5a61e44 =  7:  e231c437ba builtin/gc: introduce object database optimization options
 7:  2b428d4516 !  8:  b015c35c8a builtin/gc: move geometric repacking into `odb_optimize()`
    @@ t/t7900-maintenance.sh: test_expect_success 'geometric repacking honors configur
      	)
      '
      
    -@@ t/t7900-maintenance.sh: test_expect_success 'maintenance.strategy is respected' '
    - 		test_strategy geometric <<-\EOF &&
    - 		git pack-refs --all --prune
    - 		git reflog expire --all
    --		git repack -d -l --geometric=2 --quiet --write-midx
    -+		git repack -d -l -q --geometric=2 --write-midx
    - 		git commit-graph write --split --reachable --no-progress
    - 		git worktree prune --expire 3.months.ago
    - 		git rerere gc
    -@@ t/t7900-maintenance.sh: test_expect_success 'maintenance.strategy is respected' '
    - 		test_strategy geometric --schedule=weekly <<-\EOF
    - 		git pack-refs --all --prune
    - 		git reflog expire --all
    --		git repack -d -l --geometric=2 --quiet --write-midx
    -+		git repack -d -l -q --geometric=2 --write-midx
    - 		git commit-graph write --split --reachable --no-progress
    - 		git worktree prune --expire 3.months.ago
    - 		git rerere gc
 8:  79c3d77210 =  9:  426a06b349 builtin/gc: introduce `odb_optimize_required()`
 9:  15f65ab0bf = 10:  cfb6014c30 builtin/gc: refactor ODB optimizations to operate on "files" source
10:  9035d7d679 = 11:  a478e0e0b3 builtin/gc: fix signedness issues in ODB-related functionality
11:  8fa84c3aa0 = 12:  5383b9027c odb: make optimizations pluggable

---
base-commit: f85a7e662054a7b0d9070e432508831afa214b47
change-id: 20260612-b4-pks-odb-optimize-3426c57e5c30


^ permalink raw reply

* [PATCH v2 01/12] t7900: simplify how we check for maintenance tasks
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

We have several tests in t7900 that verify whether specific maintenance
tasks did or did not run. This is done rather ad-hoc by checking for
spawned Git commands, which is awfully fragile:

  - We have to adjust tests whenever arguments to the spawned Git
    commands change.

  - We don't have a way to verify that negative matches are still
    working as expected.

  - We rely on maintenance tasks spawning a Git command in the first
    place.

We can do much better though, as we already have trace2 regions for each
of the maintenance tasks. Introduce a helper function that extracts all
such regions so that we can get a direct list of all maintenance tasks
that a certain command ran.

Adapt tests that care about whether or not a specific task ran to use
this new helper. Note that many tests still use `test_subcommand`
though, as they really care about the exact command that was executed.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/t7900-maintenance.sh | 194 ++++++++++++++++++++++++++-----------------------
 1 file changed, 102 insertions(+), 92 deletions(-)

diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index d7f82e1bec..129829f1f4 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -23,6 +23,12 @@ test_xmllint () {
 	fi
 }
 
+test_maintenance_tasks () {
+	cat >expect &&
+	sed -ne "s/.*\"region_enter\".*\"category\":\"maintenance\([^\"]*\)\".*\"label\":\"\([^\"][^\"]*\)\".*/\2\1/p" "$1" >actual &&
+	test_cmp expect actual
+}
+
 test_lazy_prereq SYSTEMD_ANALYZE '
 	systemd-analyze verify /lib/systemd/system/basic.target
 '
@@ -180,8 +186,9 @@ test_expect_success 'maintenance.<task>.enabled' '
 	git config maintenance.gc.enabled false &&
 	git config maintenance.commit-graph.enabled true &&
 	GIT_TRACE2_EVENT="$(pwd)/run-config.txt" git maintenance run 2>err &&
-	test_subcommand ! git gc --quiet <run-config.txt &&
-	test_subcommand git commit-graph write --split --reachable --no-progress <run-config.txt
+	test_maintenance_tasks run-config.txt <<-\EOF
+	commit-graph
+	EOF
 '
 
 test_expect_success 'run --task=<task>' '
@@ -189,16 +196,20 @@ test_expect_success 'run --task=<task>' '
 		git maintenance run --task=commit-graph 2>/dev/null &&
 	GIT_TRACE2_EVENT="$(pwd)/run-gc.txt" \
 		git maintenance run --task=gc 2>/dev/null &&
-	GIT_TRACE2_EVENT="$(pwd)/run-commit-graph.txt" \
-		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 --no-detach --skip-foreground-tasks <run-commit-graph.txt &&
-	test_subcommand git gc --quiet --no-detach --skip-foreground-tasks <run-gc.txt &&
-	test_subcommand git gc --quiet --no-detach --skip-foreground-tasks <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
+	test_maintenance_tasks run-commit-graph.txt <<-\EOF &&
+	commit-graph
+	EOF
+	test_maintenance_tasks run-gc.txt <<-\EOF &&
+	gc foreground
+	gc
+	EOF
+	test_maintenance_tasks run-both.txt <<-\EOF
+	gc foreground
+	commit-graph
+	gc
+	EOF
 '
 
 test_expect_success 'core.commitGraph=false prevents write process' '
@@ -235,12 +246,19 @@ test_expect_success 'commit-graph auto condition' '
 	GIT_TRACE2_EVENT="$(pwd)/cg-two-satisfied.txt" \
 		git -c maintenance.commit-graph.auto=2 $COMMAND &&
 
-	COMMIT_GRAPH_WRITE="git commit-graph write --split --reachable --no-progress" &&
-	test_subcommand ! $COMMIT_GRAPH_WRITE <cg-no.txt &&
-	test_subcommand $COMMIT_GRAPH_WRITE <cg-negative-means-yes.txt &&
-	test_subcommand ! $COMMIT_GRAPH_WRITE <cg-zero-means-no.txt &&
-	test_subcommand $COMMIT_GRAPH_WRITE <cg-one-satisfied.txt &&
-	test_subcommand $COMMIT_GRAPH_WRITE <cg-two-satisfied.txt
+	test_maintenance_tasks cg-no.txt <<-\EOF &&
+	EOF
+	test_maintenance_tasks cg-negative-means-yes.txt <<-\EOF &&
+	commit-graph
+	EOF
+	test_maintenance_tasks cg-zero-means-no.txt <<-\EOF &&
+	EOF
+	test_maintenance_tasks cg-one-satisfied.txt <<-\EOF &&
+	commit-graph
+	EOF
+	test_maintenance_tasks cg-two-satisfied.txt <<-\EOF
+	commit-graph
+	EOF
 '
 
 test_expect_success 'commit-graph auto condition with merges' '
@@ -910,24 +928,28 @@ test_expect_success '--schedule inheritance weekly -> daily -> hourly' '
 
 	GIT_TRACE2_EVENT="$(pwd)/hourly.txt" \
 		git maintenance run --schedule=hourly 2>/dev/null &&
-	test_subcommand git prune-packed --quiet <hourly.txt &&
-	test_subcommand ! git commit-graph write --split --reachable \
-		--no-progress <hourly.txt &&
-	test_subcommand ! git multi-pack-index write --no-progress <hourly.txt &&
+	test_maintenance_tasks hourly.txt <<-\EOF &&
+	prefetch
+	loose-objects
+	EOF
 
 	GIT_TRACE2_EVENT="$(pwd)/daily.txt" \
 		git maintenance run --schedule=daily 2>/dev/null &&
-	test_subcommand git prune-packed --quiet <daily.txt &&
-	test_subcommand git commit-graph write --split --reachable \
-		--no-progress <daily.txt &&
-	test_subcommand ! git multi-pack-index write --no-progress <daily.txt &&
+	test_maintenance_tasks daily.txt <<-\EOF &&
+	prefetch
+	loose-objects
+	commit-graph
+	EOF
 
 	GIT_TRACE2_EVENT="$(pwd)/weekly.txt" \
 		git maintenance run --schedule=weekly 2>/dev/null &&
-	test_subcommand git prune-packed --quiet <weekly.txt &&
-	test_subcommand git commit-graph write --split --reachable \
-		--no-progress <weekly.txt &&
-	test_subcommand git multi-pack-index write --no-progress <weekly.txt
+	test_maintenance_tasks weekly.txt <<-\EOF
+	pack-refs foreground
+	prefetch
+	loose-objects
+	incremental-repack
+	commit-graph
+	EOF
 '
 
 test_expect_success 'maintenance.strategy inheritance' '
@@ -946,29 +968,25 @@ test_expect_success 'maintenance.strategy inheritance' '
 	GIT_TRACE2_EVENT="$(pwd)/incremental-weekly.txt" \
 		git maintenance run --schedule=weekly --quiet &&
 
-	test_subcommand git commit-graph write --split --reachable \
-		--no-progress <incremental-hourly.txt &&
-	test_subcommand ! git prune-packed --quiet <incremental-hourly.txt &&
-	test_subcommand ! git multi-pack-index write --no-progress \
-		<incremental-hourly.txt &&
-	test_subcommand ! git pack-refs --all --prune \
-		<incremental-hourly.txt &&
-
-	test_subcommand git commit-graph write --split --reachable \
-		--no-progress <incremental-daily.txt &&
-	test_subcommand git prune-packed --quiet <incremental-daily.txt &&
-	test_subcommand git multi-pack-index write --no-progress \
-		<incremental-daily.txt &&
-	test_subcommand ! git pack-refs --all --prune \
-		<incremental-daily.txt &&
-
-	test_subcommand git commit-graph write --split --reachable \
-		--no-progress <incremental-weekly.txt &&
-	test_subcommand git prune-packed --quiet <incremental-weekly.txt &&
-	test_subcommand git multi-pack-index write --no-progress \
-		<incremental-weekly.txt &&
-	test_subcommand git pack-refs --all --prune \
-		<incremental-weekly.txt &&
+	test_maintenance_tasks incremental-hourly.txt <<-\EOF &&
+	prefetch
+	commit-graph
+	EOF
+
+	test_maintenance_tasks incremental-daily.txt <<-\EOF &&
+	prefetch
+	loose-objects
+	incremental-repack
+	commit-graph
+	EOF
+
+	test_maintenance_tasks incremental-weekly.txt <<-\EOF &&
+	pack-refs foreground
+	prefetch
+	loose-objects
+	incremental-repack
+	commit-graph
+	EOF
 
 	# Modify defaults
 	git config maintenance.commit-graph.schedule daily &&
@@ -980,30 +998,26 @@ test_expect_success 'maintenance.strategy inheritance' '
 	GIT_TRACE2_EVENT="$(pwd)/modified-daily.txt" \
 		git maintenance run --schedule=daily --quiet &&
 
-	test_subcommand ! git commit-graph write --split --reachable \
-		--no-progress <modified-hourly.txt &&
-	test_subcommand git prune-packed --quiet <modified-hourly.txt &&
-	test_subcommand ! git multi-pack-index write --no-progress \
-		<modified-hourly.txt &&
+	test_maintenance_tasks modified-hourly.txt <<-\EOF &&
+	prefetch
+	loose-objects
+	EOF
 
-	test_subcommand git commit-graph write --split --reachable \
-		--no-progress <modified-daily.txt &&
-	test_subcommand git prune-packed --quiet <modified-daily.txt &&
-	test_subcommand ! git multi-pack-index write --no-progress \
-		<modified-daily.txt
+	test_maintenance_tasks modified-daily.txt <<-\EOF
+	prefetch
+	loose-objects
+	commit-graph
+	EOF
 '
 
 test_strategy () {
 	STRATEGY="$1"
 	shift
 
-	cat >expect &&
 	rm -f trace2.txt &&
 	GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
 		git -c maintenance.strategy=$STRATEGY maintenance run --quiet "$@" &&
-	sed -n 's/{"event":"child_start","sid":"[^/"]*",.*,"argv":\["\(.*\)\"]}/\1/p' <trace2.txt |
-		sed 's/","/ /g'  >actual
-	test_cmp expect actual
+	test_maintenance_tasks trace2.txt
 }
 
 test_expect_success 'maintenance.strategy is respected' '
@@ -1017,48 +1031,44 @@ test_expect_success 'maintenance.strategy is respected' '
 		test_grep "unknown maintenance strategy: .unknown." err &&
 
 		test_strategy incremental <<-\EOF &&
-		git pack-refs --all --prune
-		git reflog expire --all
-		git gc --quiet --no-detach --skip-foreground-tasks
+		gc foreground
+		gc
 		EOF
 
 		test_strategy incremental --schedule=weekly <<-\EOF &&
-		git pack-refs --all --prune
-		git prune-packed --quiet
-		git multi-pack-index write --no-progress
-		git multi-pack-index expire --no-progress
-		git multi-pack-index repack --no-progress --batch-size=1
-		git commit-graph write --split --reachable --no-progress
+		pack-refs foreground
+		prefetch
+		loose-objects
+		incremental-repack
+		commit-graph
 		EOF
 
 		test_strategy gc <<-\EOF &&
-		git pack-refs --all --prune
-		git reflog expire --all
-		git gc --quiet --no-detach --skip-foreground-tasks
+		gc foreground
+		gc
 		EOF
 
 		test_strategy gc --schedule=weekly <<-\EOF &&
-		git pack-refs --all --prune
-		git reflog expire --all
-		git gc --quiet --no-detach --skip-foreground-tasks
+		gc foreground
+		gc
 		EOF
 
 		test_strategy geometric <<-\EOF &&
-		git pack-refs --all --prune
-		git reflog expire --all
-		git repack -d -l --geometric=2 --quiet --write-midx
-		git commit-graph write --split --reachable --no-progress
-		git worktree prune --expire 3.months.ago
-		git rerere gc
+		pack-refs foreground
+		reflog-expire foreground
+		geometric-repack
+		commit-graph
+		worktree-prune
+		rerere-gc
 		EOF
 
 		test_strategy geometric --schedule=weekly <<-\EOF
-		git pack-refs --all --prune
-		git reflog expire --all
-		git repack -d -l --geometric=2 --quiet --write-midx
-		git commit-graph write --split --reachable --no-progress
-		git worktree prune --expire 3.months.ago
-		git rerere gc
+		pack-refs foreground
+		reflog-expire foreground
+		geometric-repack
+		commit-graph
+		worktree-prune
+		rerere-gc
 		EOF
 	)
 '

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 02/12] odb: run "pre-auto-gc" hook for all maintenance tasks
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

The "pre-auto-gc" hook is supposed to run before auto-maintenance
starts. The intent of this is to give users the ability to intercept
running maintenance in case there's for example an event that is not
supposed to run in parallel with repository maintenance.

This hook runs via `need_to_gc()`, which is invoked via two paths:

  - It is called directly by git-gc(1).

  - It is called indirectly by git-maintenance(1) via the "gc" task.

While the former makes sense, the latter is somewhat off. While the hook
is indeed strongly tied to gc'ing a repository, the original intent of
the hook is rather to inhibit any kind of automated garbage collection.
That noticeably also includes all the other maintenance tasks that our
new infrastructure may run, but those aren't getting intercepted at all.
The move towards our new maintenance strategy has thus somewhat neutered
the effectiveness of the hook.

Fix this issue by running the hook before the first auto-maintenance
task that would run as determined by the tasks's auto condition. Note
that this requires us to lift the call to `run_hooks()` out of
`needs_to_gc()`, as the hook would otherwise potentially run multiple
times.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c           |  35 ++++++++++----
 t/t7900-maintenance.sh | 126 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 152 insertions(+), 9 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index d32af422af..77d0a5c948 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -709,8 +709,6 @@ static int need_to_gc(struct gc_config *cfg, struct strvec *repack_args)
 	else
 		return 0;
 
-	if (run_hooks(the_repository, "pre-auto-gc"))
-		return 0;
 	return 1;
 }
 
@@ -933,7 +931,8 @@ int cmd_gc(int argc,
 		/*
 		 * Auto-gc should be least intrusive as possible.
 		 */
-		if (!need_to_gc(&cfg, &repack_args)) {
+		if (!need_to_gc(&cfg, &repack_args) ||
+		    run_hooks(the_repository, "pre-auto-gc")) {
 			ret = 0;
 			goto out;
 		}
@@ -1755,11 +1754,18 @@ enum task_phase {
 	TASK_PHASE_BACKGROUND,
 };
 
+enum auto_gc_hook_result {
+	AUTO_GC_HOOK_UNDECIDED = 0,
+	AUTO_GC_HOOK_RUN = 1,
+	AUTO_GC_HOOK_SKIP = 2,
+};
+
 static int maybe_run_task(const struct maintenance_task *task,
 			  struct repository *repo,
 			  struct maintenance_run_opts *opts,
 			  struct gc_config *cfg,
-			  enum task_phase phase)
+			  enum task_phase phase,
+			  enum auto_gc_hook_result *auto_gc_hook_result)
 {
 	int foreground = (phase == TASK_PHASE_FOREGROUND);
 	maintenance_task_fn fn = foreground ? task->foreground : task->background;
@@ -1768,9 +1774,19 @@ static int maybe_run_task(const struct maintenance_task *task,
 
 	if (!fn)
 		return 0;
-	if (opts->auto_flag &&
-	    (!task->auto_condition || !task->auto_condition(cfg)))
-		return 0;
+	if (opts->auto_flag) {
+		if (*auto_gc_hook_result == AUTO_GC_HOOK_SKIP)
+			return 0;
+
+		if (!task->auto_condition || !task->auto_condition(cfg))
+			return 0;
+
+		if (*auto_gc_hook_result == AUTO_GC_HOOK_UNDECIDED)
+			*auto_gc_hook_result = run_hooks(repo, "pre-auto-gc") ?
+				AUTO_GC_HOOK_SKIP : AUTO_GC_HOOK_RUN;
+		if (*auto_gc_hook_result == AUTO_GC_HOOK_SKIP)
+			return 0;
+	}
 
 	trace2_region_enter(region, task->name, repo);
 	if (fn(opts, cfg)) {
@@ -1789,6 +1805,7 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
 	struct lock_file lk;
 	struct repository *r = the_repository;
 	char *lock_path = xstrfmt("%s/maintenance", r->objects->sources->path);
+	enum auto_gc_hook_result auto_gc_hook_result = AUTO_GC_HOOK_UNDECIDED;
 
 	if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
 		/*
@@ -1808,7 +1825,7 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
 
 	for (size_t i = 0; i < opts->tasks_nr; i++)
 		if (maybe_run_task(&tasks[opts->tasks[i]], r, opts, cfg,
-				   TASK_PHASE_FOREGROUND))
+				   TASK_PHASE_FOREGROUND, &auto_gc_hook_result))
 			result = 1;
 
 	/* Failure to daemonize is ok, we'll continue in foreground. */
@@ -1820,7 +1837,7 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
 
 	for (size_t i = 0; i < opts->tasks_nr; i++)
 		if (maybe_run_task(&tasks[opts->tasks[i]], r, opts, cfg,
-				   TASK_PHASE_BACKGROUND))
+				   TASK_PHASE_BACKGROUND, &auto_gc_hook_result))
 			result = 1;
 
 	rollback_lock_file(&lk);
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index 129829f1f4..2d52e7918a 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -758,6 +758,132 @@ test_expect_success 'geometric repacking honors configured split factor' '
 	)
 '
 
+test_expect_success 'pre-auto-gc hook runs exactly once' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+		write_script .git/hooks/pre-auto-gc <<-\EOF &&
+		echo hook >>hook.log
+		EOF
+
+		# Satisfy the auto condition for multiple tasks, both in the
+		# foreground and in the background phase.
+		git config set maintenance.reflog-expire.auto -1 &&
+		git config set maintenance.geometric-repack.auto -1 &&
+		git config set maintenance.rerere-gc.auto -1 &&
+
+		GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+			git maintenance run --auto 2>/dev/null &&
+
+		# The successful hook does not inhibit any of the tasks...
+		test_maintenance_tasks trace2.txt <<-\EOF &&
+		reflog-expire foreground
+		geometric-repack
+		rerere-gc
+		EOF
+		# ... but it must only have been executed a single time.
+		test_line_count = 1 hook.log
+	)
+'
+
+test_expect_success 'pre-auto-gc hook can inhibit geometric strategy' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+		write_script .git/hooks/pre-auto-gc <<-\EOF &&
+		echo hook >>hook.log
+		exit 1
+		EOF
+
+		git config set maintenance.reflog-expire.auto -1 &&
+		git config set maintenance.geometric-repack.auto -1 &&
+		git config set maintenance.rerere-gc.auto -1 &&
+
+		# Maintenance would be required...
+		git maintenance is-needed --auto &&
+
+		GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+			git maintenance run --auto 2>/dev/null &&
+
+		# ... but the failing hook inhibits all tasks. The hook itself
+		# is expected to be the only child process being spawned, and
+		# it must only run a single time.
+		test_grep "child_start.*pre-auto-gc" trace2.txt &&
+		test_maintenance_tasks trace2.txt <<-\EOF &&
+		EOF
+		test_line_count = 1 hook.log
+	)
+'
+
+test_expect_success 'pre-auto-gc hook can inhibit gc strategy' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+		write_script .git/hooks/pre-auto-gc <<-\EOF &&
+		echo hook >>hook.log
+		exit 1
+		EOF
+
+		git config set maintenance.strategy gc &&
+		git config set maintenance.auto false &&
+		git config set gc.auto 3 &&
+
+		test_oid_init &&
+
+		# We need to create two objects whose hashes start with 17
+		# since this is what the gc task counts.
+		test_commit "$(test_oid blob17_1)" &&
+		test_commit "$(test_oid blob17_2)" &&
+
+		# Maintenance would be required...
+		git maintenance is-needed --auto &&
+
+		GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+			git maintenance run --auto 2>/dev/null &&
+
+		# ... but the failing hook inhibits all tasks. The hook itself
+		# is expected to be the only child process being spawned, and
+		# it must only run a single time.
+		test_grep "child_start.*pre-auto-gc" trace2.txt &&
+		test_maintenance_tasks trace2.txt <<-\EOF &&
+		EOF
+		test_subcommand_flex ! git trace2 &&
+		test_line_count = 1 hook.log
+	)
+'
+
+test_expect_success 'pre-auto-gc hook does not run when no maintenance is needed' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+		write_script .git/hooks/pre-auto-gc <<-\EOF &&
+		echo hook >>hook.log
+		EOF
+		test_must_fail git maintenance is-needed --auto &&
+		git maintenance run --auto 2>/dev/null &&
+		test_path_is_missing hook.log
+	)
+'
+
+test_expect_success 'pre-auto-gc hook does not run without --auto' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	test_hook -C repo pre-auto-gc <<-\EOF &&
+	echo hook >>hook.log
+	EOF
+	(
+		cd repo &&
+		GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+			git maintenance run 2>/dev/null &&
+		test_grep "\[\"git\",\"repack\"," trace2.txt &&
+		test_path_is_missing hook.log
+	)
+'
+
 test_expect_success 'pack-refs task' '
 	for n in $(test_seq 1 5)
 	do

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 03/12] builtin/gc: move worktree and rerere tasks before object optimizations
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

In subsequent patches we'll consolidate all tasks that relate to
maintenance of the object database and move it into the "files" backend.
The relevant code is somewhat scattered though, as several other tasks
are interspersed between.

Refactor the code so that all object database optimizations are grouped
together, which requires us to move worktree pruning and rerere garbage
collection around. In theory, rearranging this code can have an effect
on the object database optimizations:

  - Rerere entries really shouldn't impact garbage collection at all, as
    these entries are not stored in the object database.

  - The index and HEAD reference of pruned worktrees may reference
    objects that become unreachable.

That being said, the impact should be overall rather negligible. If the
user was asking us to prune objects with immediate expiration time then
we might now prune objects that were previously still kept alive by the
worktree. But besides being a very specific edge case, it's arguably not
even the wrong thing to also prune any potentially-unreachable objects
immediately.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 77d0a5c948..8f568003ee 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -1011,6 +1011,13 @@ int cmd_gc(int argc,
 	if (opts.detach <= 0 && !skip_foreground_tasks)
 		gc_foreground_tasks(&opts, &cfg);
 
+	if (cfg.prune_worktrees_expire &&
+	    maintenance_task_worktree_prune(&opts, &cfg))
+		die(FAILED_RUN, "worktree");
+
+	if (maintenance_task_rerere_gc(&opts, &cfg))
+		die(FAILED_RUN, "rerere");
+
 	if (!the_repository->repository_format_precious_objects) {
 		struct child_process repack_cmd = CHILD_PROCESS_INIT;
 
@@ -1038,13 +1045,6 @@ int cmd_gc(int argc,
 		}
 	}
 
-	if (cfg.prune_worktrees_expire &&
-	    maintenance_task_worktree_prune(&opts, &cfg))
-		die(FAILED_RUN, "worktree");
-
-	if (maintenance_task_rerere_gc(&opts, &cfg))
-		die(FAILED_RUN, "rerere");
-
 	report_garbage = report_pack_garbage;
 	odb_reprepare(the_repository->objects);
 	if (pack_garbage.nr > 0) {

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* Re: [PATCH RFC v3 2/2] Move libgit.a sources into separate "lib/" directory
From: SZEDER Gábor @ 2026-07-13  5:52 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: git, brian m. carlson, Junio C Hamano, Elijah Newren,
	Derrick Stolee, Johannes Schindelin, Phillip Wood
In-Reply-To: <20260701-pks-libgit-in-subdir-v3-2-5e4860056094@pks.im>

On Wed, Jul 01, 2026 at 08:59:27AM +0200, Patrick Steinhardt wrote:
> This move does not come for free though:
> 
>   - The mass rename introduces a cutoff point in the history of every
>     moved file, as tools like git-log(1) do not follow renames by
>     default.
> 
>   - Any in-flight or not-yet-submitted topic that touches the moved
>     files will have to be rebased, and backporting fixes across the
>     boundary becomes more cumbersome as a patch can no longer apply
>     cleanly to both the old and the new layout.
> 
> My own (obviously subjective and biased) take is that the tradeoff is
> worth it, as these issues are a one-time cost while the benefits to
> discoverability will be permanent.

It is not a one-time cost, but will be an ongoing burden.

> Furthermore, especially the first downside is a limitation in Git
> itself. We're not the first or last project to do such a mass rename. So
> if our provided tools are insufficient, then we should improve them to
> make the experience better for other projects, as well. Subjecting
> ourselves to the same pain may even give us more incentive to eventually
> improve rename following for everyone.

I'm uncertain how that should work, and rather sceptical that it would
work at all.

Some have expressed that it is a pain to deal with the fallout of this
patch.  Should we then come up with those envisioned improvements,
whatever they might be?  I'm fairly certain that I won't have the time
for that.  Or should you do those improvements, because, after all,
you thrust upon us this churn?  Then it would certainly be better to
come up with those improvements first...

Overall, I remain unconvinced, and maintain that this just trades one
annoyance for the other, and it's not worth it.


^ permalink raw reply

* [PATCH v2 04/12] builtin/gc: extract object database optimizations into separate function
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

Extract the object database optimization logic from `cmd_gc()` into a
new `maintenance_task_odb()` helper function. This is a pure refactoring
with no intended functional change.

Note that the message that notifies the user about too many loose
objects is moved into the new function, as well. It is inherently an
implementation detail of how the "files" source works, and as a
consequence we'll move it around in a later commit, as well. This
reordering means that the warning may now be printed at a different
point in time, but it's not expected that this will have any practical
implications.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c | 79 +++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 49 insertions(+), 30 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 8f568003ee..2ff98fa727 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -839,6 +839,53 @@ static int gc_foreground_tasks(struct maintenance_run_opts *opts,
 	return 0;
 }
 
+static int maintenance_task_odb(struct maintenance_run_opts *opts,
+				struct gc_config *cfg,
+				struct strvec *repack_args)
+{
+	struct child_process repack_cmd = CHILD_PROCESS_INIT;
+	int ret;
+
+	if (the_repository->repository_format_precious_objects)
+		return 0;
+
+	repack_cmd.git_cmd = 1;
+	repack_cmd.odb_to_close = the_repository->objects;
+	strvec_pushv(&repack_cmd.args, repack_args->v);
+	if (run_command(&repack_cmd)) {
+		ret = error(FAILED_RUN, repack_args->v[0]);
+		goto out;
+	}
+
+	if (cfg->prune_expire) {
+		struct child_process prune_cmd = CHILD_PROCESS_INIT;
+
+		strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL);
+		/* run `git prune` even if using cruft packs */
+		strvec_push(&prune_cmd.args, cfg->prune_expire);
+		if (opts->quiet)
+			strvec_push(&prune_cmd.args, "--no-progress");
+		if (repo_has_promisor_remote(the_repository))
+			strvec_push(&prune_cmd.args,
+				    "--exclude-promisor-objects");
+		prune_cmd.git_cmd = 1;
+
+		if (run_command(&prune_cmd)) {
+			ret = error(FAILED_RUN, prune_cmd.args.v[0]);
+			goto out;
+		}
+	}
+
+	if (opts->auto_flag && too_many_loose_objects(cfg->gc_auto_threshold))
+		warning(_("There are too many unreachable loose objects; "
+			"run 'git prune' to remove them."));
+
+	ret = 0;
+
+out:
+	return ret;
+}
+
 int cmd_gc(int argc,
 	   const char **argv,
 	   const char *prefix,
@@ -1018,32 +1065,8 @@ int cmd_gc(int argc,
 	if (maintenance_task_rerere_gc(&opts, &cfg))
 		die(FAILED_RUN, "rerere");
 
-	if (!the_repository->repository_format_precious_objects) {
-		struct child_process repack_cmd = CHILD_PROCESS_INIT;
-
-		repack_cmd.git_cmd = 1;
-		repack_cmd.odb_to_close = the_repository->objects;
-		strvec_pushv(&repack_cmd.args, repack_args.v);
-		if (run_command(&repack_cmd))
-			die(FAILED_RUN, repack_args.v[0]);
-
-		if (cfg.prune_expire) {
-			struct child_process prune_cmd = CHILD_PROCESS_INIT;
-
-			strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL);
-			/* run `git prune` even if using cruft packs */
-			strvec_push(&prune_cmd.args, cfg.prune_expire);
-			if (opts.quiet)
-				strvec_push(&prune_cmd.args, "--no-progress");
-			if (repo_has_promisor_remote(the_repository))
-				strvec_push(&prune_cmd.args,
-					    "--exclude-promisor-objects");
-			prune_cmd.git_cmd = 1;
-
-			if (run_command(&prune_cmd))
-				die(FAILED_RUN, prune_cmd.args.v[0]);
-		}
-	}
+	if (maintenance_task_odb(&opts, &cfg, &repack_args))
+		die(NULL);
 
 	report_garbage = report_pack_garbage;
 	odb_reprepare(the_repository->objects);
@@ -1057,10 +1080,6 @@ int cmd_gc(int argc,
 					     !opts.quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
 					     NULL);
 
-	if (opts.auto_flag && too_many_loose_objects(cfg.gc_auto_threshold))
-		warning(_("There are too many unreachable loose objects; "
-			"run 'git prune' to remove them."));
-
 	if (!daemonized) {
 		char *path = repo_git_path(the_repository, "gc.log");
 		unlink(path);

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 05/12] builtin/gc: make repack arguments self-contained
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

When optimizing the object database most of the heavy-lifting is done by
git-repack(1). The arguments we pass to this function are assembled in
global scope, which is hard to follow.

Refactor the logic by moving the vector into `maintenance_task_odb()`.
While that means we have to pass more arguments to this function, it has
the upside that the logic becomes self-contained without any kind of
global interdependencies.

This is a pure refactoring with no intended functional change.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c | 156 ++++++++++++++++++++++++++++-------------------------------
 1 file changed, 75 insertions(+), 81 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 2ff98fa727..25a59caea6 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -661,7 +661,7 @@ static void add_repack_incremental_option(struct strvec *args)
 	strvec_push(args, "--no-write-bitmap-index");
 }
 
-static int need_to_gc(struct gc_config *cfg, struct strvec *repack_args)
+static int need_to_gc(struct gc_config *cfg)
 {
 	/*
 	 * Setting gc.auto to 0 or negative can disable the
@@ -669,46 +669,8 @@ static int need_to_gc(struct gc_config *cfg, struct strvec *repack_args)
 	 */
 	if (cfg->gc_auto_threshold <= 0)
 		return 0;
-
-	/*
-	 * If there are too many loose objects, but not too many
-	 * packs, we run "repack -d -l".  If there are too many packs,
-	 * we run "repack -A -d -l".  Otherwise we tell the caller
-	 * there is no need.
-	 */
-	if (too_many_packs(cfg)) {
-		struct string_list keep_pack = STRING_LIST_INIT_NODUP;
-
-		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);
-			}
-		} else {
-			struct packed_git *p = find_base_packs(&keep_pack, 0);
-			uint64_t mem_have, mem_want;
-
-			mem_have = total_ram();
-			mem_want = estimate_repack_memory(cfg, p);
-
-			/*
-			 * Only allow 1/2 of memory for pack-objects, leave
-			 * the rest for the OS and other processes in the
-			 * system.
-			 */
-			if (!mem_have || mem_want < mem_have / 2)
-				string_list_clear(&keep_pack, 0);
-		}
-
-		add_repack_all_option(cfg, &keep_pack, repack_args);
-		string_list_clear(&keep_pack, 0);
-	} else if (too_many_loose_objects(cfg->gc_auto_threshold))
-		add_repack_incremental_option(repack_args);
-	else
+	if (!too_many_packs(cfg) && !too_many_loose_objects(cfg->gc_auto_threshold))
 		return 0;
-
 	return 1;
 }
 
@@ -841,7 +803,8 @@ static int gc_foreground_tasks(struct maintenance_run_opts *opts,
 
 static int maintenance_task_odb(struct maintenance_run_opts *opts,
 				struct gc_config *cfg,
-				struct strvec *repack_args)
+				int keep_largest_pack,
+				int aggressive)
 {
 	struct child_process repack_cmd = CHILD_PROCESS_INIT;
 	int ret;
@@ -851,9 +814,75 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 
 	repack_cmd.git_cmd = 1;
 	repack_cmd.odb_to_close = the_repository->objects;
-	strvec_pushv(&repack_cmd.args, repack_args->v);
+
+	strvec_pushl(&repack_cmd.args, "repack", "-d", "-l", NULL);
+	if (aggressive) {
+		strvec_push(&repack_cmd.args, "-f");
+		if (cfg->aggressive_depth > 0)
+			strvec_pushf(&repack_cmd.args, "--depth=%d", cfg->aggressive_depth);
+		if (cfg->aggressive_window > 0)
+			strvec_pushf(&repack_cmd.args, "--window=%d", cfg->aggressive_window);
+	}
+	if (opts->quiet)
+		strvec_push(&repack_cmd.args, "-q");
+
+	/*
+	 * There's three cases we need to consider:
+	 *
+	 *   - If we're invoked without `--auto` we'll need to perform a full
+	 *     repack.
+	 *
+	 *   - If we're invoked with `--auto` and there's too many packs, then
+	 *     we perform a full repack, as well.
+	 *
+	 *   - Otherwise we perform an incremental repack.
+	 */
+	if (!opts->auto_flag) {
+		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 (cfg->big_pack_threshold) {
+			find_base_packs(&keep_pack, cfg->big_pack_threshold);
+		}
+
+		add_repack_all_option(cfg, &keep_pack, &repack_cmd.args);
+		string_list_clear(&keep_pack, 0);
+	} else if (too_many_packs(cfg)) {
+		struct string_list keep_pack = STRING_LIST_INIT_NODUP;
+
+		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);
+			}
+		} else {
+			struct packed_git *p = find_base_packs(&keep_pack, 0);
+			uint64_t mem_have, mem_want;
+
+			mem_have = total_ram();
+			mem_want = estimate_repack_memory(cfg, p);
+
+			/*
+			 * Only allow 1/2 of memory for pack-objects, leave
+			 * the rest for the OS and other processes in the
+			 * system.
+			 */
+			if (!mem_have || mem_want < mem_have / 2)
+				string_list_clear(&keep_pack, 0);
+		}
+
+		add_repack_all_option(cfg, &keep_pack, &repack_cmd.args);
+		string_list_clear(&keep_pack, 0);
+	} else {
+		add_repack_incremental_option(&repack_cmd.args);
+	}
+
 	if (run_command(&repack_cmd)) {
-		ret = error(FAILED_RUN, repack_args->v[0]);
+		ret = error(FAILED_RUN, repack_cmd.args.v[0]);
 		goto out;
 	}
 
@@ -899,7 +928,6 @@ int cmd_gc(int argc,
 	int keep_largest_pack = -1;
 	int skip_foreground_tasks = 0;
 	timestamp_t dummy;
-	struct strvec repack_args = STRVEC_INIT;
 	struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
 	struct gc_config cfg = GC_CONFIG_INIT;
 	const char *prune_expire_sentinel = "sentinel";
@@ -939,8 +967,6 @@ int cmd_gc(int argc,
 	show_usage_with_options_if_asked(argc, argv,
 					 builtin_gc_usage, builtin_gc_options);
 
-	strvec_pushl(&repack_args, "repack", "-d", "-l", NULL);
-
 	gc_config(&cfg);
 
 	if (parse_expiry_date(cfg.gc_log_expire, &gc_log_expire_time))
@@ -961,16 +987,6 @@ int cmd_gc(int argc,
 	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_args, "-f");
-		if (cfg.aggressive_depth > 0)
-			strvec_pushf(&repack_args, "--depth=%d", cfg.aggressive_depth);
-		if (cfg.aggressive_window > 0)
-			strvec_pushf(&repack_args, "--window=%d", cfg.aggressive_window);
-	}
-	if (opts.quiet)
-		strvec_push(&repack_args, "-q");
-
 	if (opts.auto_flag) {
 		if (cfg.detach_auto && opts.detach < 0)
 			opts.detach = 1;
@@ -978,8 +994,7 @@ int cmd_gc(int argc,
 		/*
 		 * Auto-gc should be least intrusive as possible.
 		 */
-		if (!need_to_gc(&cfg, &repack_args) ||
-		    run_hooks(the_repository, "pre-auto-gc")) {
+		if (!need_to_gc(&cfg) || run_hooks(the_repository, "pre-auto-gc")) {
 			ret = 0;
 			goto out;
 		}
@@ -991,18 +1006,6 @@ int cmd_gc(int argc,
 				fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
 			fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n"));
 		}
-	} 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 (cfg.big_pack_threshold) {
-			find_base_packs(&keep_pack, cfg.big_pack_threshold);
-		}
-
-		add_repack_all_option(&cfg, &keep_pack, &repack_args);
-		string_list_clear(&keep_pack, 0);
 	}
 
 	if (opts.detach > 0) {
@@ -1065,7 +1068,7 @@ int cmd_gc(int argc,
 	if (maintenance_task_rerere_gc(&opts, &cfg))
 		die(FAILED_RUN, "rerere");
 
-	if (maintenance_task_odb(&opts, &cfg, &repack_args))
+	if (maintenance_task_odb(&opts, &cfg, keep_largest_pack, aggressive))
 		die(NULL);
 
 	report_garbage = report_pack_garbage;
@@ -1088,7 +1091,6 @@ int cmd_gc(int argc,
 
 out:
 	maintenance_run_opts_release(&opts);
-	strvec_clear(&repack_args);
 	gc_config_release(&cfg);
 	return 0;
 }
@@ -1291,15 +1293,7 @@ static int maintenance_task_gc_background(struct maintenance_run_opts *opts,
 
 static int gc_condition(struct gc_config *cfg)
 {
-	/*
-	 * Note that it's fine to drop the repack arguments here, as we execute
-	 * git-gc(1) as a separate child process anyway. So it knows to compute
-	 * these arguments again.
-	 */
-	struct strvec repack_args = STRVEC_INIT;
-	int ret = need_to_gc(cfg, &repack_args);
-	strvec_clear(&repack_args);
-	return ret;
+	return need_to_gc(cfg);
 }
 
 static int prune_packed(struct maintenance_run_opts *opts)

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 06/12] builtin/gc: inline config values specific to the "files" backend
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

The `struct gc_config` contains a set of values that we read via the Git
repository's configuration. Several of those values that are consumed by
the object database optimization logic are inherently specific to the
"files" config.

In a later commit we'll make the logic to optimize object databases
pluggable. So by carrying these "files"-backend specific values in the
generic config struct means that other backends would have to worry
about these values, too. This feels somewhat dirty, as implementation-
specific details should live with the backends themselves.

Inline these values directly at the call sites that need them instead.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c | 115 +++++++++++++++++++++++++++--------------------------------
 1 file changed, 53 insertions(+), 62 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 25a59caea6..5d445edaa0 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -130,22 +130,11 @@ struct gc_config {
 	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;
 	char *repack_expire_to;
-	unsigned long big_pack_threshold;
-	unsigned long max_delta_cache_size;
-	/*
-	 * Remove this member from gc_config once repo_settings is passed
-	 * through the callchain.
-	 */
-	size_t delta_base_cache_limit;
 };
 
 #define GC_CONFIG_INIT { \
@@ -154,14 +143,10 @@ struct gc_config {
 	.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, \
-	.delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT, \
 }
 
 static void gc_config_release(struct gc_config *cfg)
@@ -169,15 +154,12 @@ 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;
-	unsigned long ulongval;
 
 	if (!repo_config_get_value(the_repository, "gc.packrefs", &value)) {
 		if (value && !strcmp(value, "notbare"))
@@ -192,8 +174,6 @@ static void gc_config(struct gc_config *cfg)
 
 	repo_config_get_int(the_repository, "gc.aggressivewindow", &cfg->aggressive_window);
 	repo_config_get_int(the_repository, "gc.aggressivedepth", &cfg->aggressive_depth);
-	repo_config_get_int(the_repository, "gc.auto", &cfg->gc_auto_threshold);
-	repo_config_get_int(the_repository, "gc.autopacklimit", &cfg->gc_auto_pack_limit);
 	repo_config_get_bool(the_repository, "gc.autodetach", &cfg->detach_auto);
 	repo_config_get_bool(the_repository, "gc.cruftpacks", &cfg->cruft_packs);
 	repo_config_get_ulong(the_repository, "gc.maxcruftsize", &cfg->max_cruft_size);
@@ -213,22 +193,6 @@ static void gc_config(struct gc_config *cfg)
 		cfg->gc_log_expire = owned;
 	}
 
-	repo_config_get_ulong(the_repository, "gc.bigpackthreshold", &cfg->big_pack_threshold);
-	repo_config_get_ulong(the_repository, "pack.deltacachesize", &cfg->max_delta_cache_size);
-
-	if (!repo_config_get_ulong(the_repository, "core.deltabasecachelimit", &ulongval))
-		cfg->delta_base_cache_limit = ulongval;
-
-	if (!repo_config_get_string(the_repository, "gc.repackfilter", &owned)) {
-		free(cfg->repack_filter);
-		cfg->repack_filter = owned;
-	}
-
-	if (!repo_config_get_string(the_repository, "gc.repackfilterto", &owned)) {
-		free(cfg->repack_filter_to);
-		cfg->repack_filter_to = owned;
-	}
-
 	repo_config(the_repository, git_default_config, NULL);
 }
 
@@ -504,12 +468,12 @@ static struct packed_git *find_base_packs(struct string_list *packs,
 	return base;
 }
 
-static int too_many_packs(struct gc_config *cfg)
+static int too_many_packs(int gc_auto_pack_limit)
 {
 	struct packed_git *p;
 	int cnt = 0;
 
-	if (cfg->gc_auto_pack_limit <= 0)
+	if (gc_auto_pack_limit <= 0)
 		return 0;
 
 	repo_for_each_pack(the_repository, p) {
@@ -523,7 +487,7 @@ static int too_many_packs(struct gc_config *cfg)
 		 */
 		cnt++;
 	}
-	return cfg->gc_auto_pack_limit < cnt;
+	return gc_auto_pack_limit < cnt;
 }
 
 static uint64_t total_ram(void)
@@ -571,9 +535,10 @@ static uint64_t total_ram(void)
 	return 0;
 }
 
-static uint64_t estimate_repack_memory(struct gc_config *cfg,
-				       struct packed_git *pack)
+static uint64_t estimate_repack_memory(struct packed_git *pack)
 {
+	unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
+	unsigned long delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT;
 	unsigned long nr_objects;
 	size_t os_cache, heap;
 
@@ -584,6 +549,9 @@ static uint64_t estimate_repack_memory(struct gc_config *cfg,
 	if (!pack || !nr_objects)
 		return 0;
 
+	repo_config_get_ulong(the_repository, "pack.deltacachesize", &max_delta_cache_size);
+	repo_config_get_ulong(the_repository, "core.deltabasecachelimit", &delta_base_cache_limit);
+
 	/*
 	 * First we have to scan through at least one pack.
 	 * Assume enough room in OS file cache to keep the entire pack
@@ -611,9 +579,9 @@ static uint64_t estimate_repack_memory(struct gc_config *cfg,
 	 * read_sha1_file() (either at delta calculation phase, or
 	 * writing phase) also fills up the delta base cache
 	 */
-	heap += cfg->delta_base_cache_limit;
+	heap += delta_base_cache_limit;
 	/* and of course pack-objects has its own delta cache */
-	heap += cfg->max_delta_cache_size;
+	heap += max_delta_cache_size;
 
 	return os_cache + heap;
 }
@@ -629,6 +597,12 @@ static void add_repack_all_option(struct gc_config *cfg,
 				  struct string_list *keep_pack,
 				  struct strvec *args)
 {
+	char *repack_filter = NULL;
+	char *repack_filter_to = NULL;
+
+	repo_config_get_string(the_repository, "gc.repackfilter", &repack_filter);
+	repo_config_get_string(the_repository, "gc.repackfilterto", &repack_filter_to);
+
 	if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now")
 		&& !(cfg->cruft_packs && cfg->repack_expire_to))
 		strvec_push(args, "-a");
@@ -650,10 +624,13 @@ static void add_repack_all_option(struct gc_config *cfg,
 	if (keep_pack)
 		for_each_string_list(keep_pack, keep_one_pack, args);
 
-	if (cfg->repack_filter && *cfg->repack_filter)
-		strvec_pushf(args, "--filter=%s", cfg->repack_filter);
-	if (cfg->repack_filter_to && *cfg->repack_filter_to)
-		strvec_pushf(args, "--filter-to=%s", cfg->repack_filter_to);
+	if (repack_filter && *repack_filter)
+		strvec_pushf(args, "--filter=%s", repack_filter);
+	if (repack_filter_to && *repack_filter_to)
+		strvec_pushf(args, "--filter-to=%s", repack_filter_to);
+
+	free(repack_filter);
+	free(repack_filter_to);
 }
 
 static void add_repack_incremental_option(struct strvec *args)
@@ -661,16 +638,24 @@ static void add_repack_incremental_option(struct strvec *args)
 	strvec_push(args, "--no-write-bitmap-index");
 }
 
-static int need_to_gc(struct gc_config *cfg)
+static int need_to_gc(struct repository *repo)
 {
+	int gc_auto_threshold = 6700;
+	int gc_auto_pack_limit = 50;
+
+	repo_config_get_int(repo, "gc.auto", &gc_auto_threshold);
+	repo_config_get_int(repo, "gc.autopacklimit", &gc_auto_pack_limit);
+
 	/*
 	 * Setting gc.auto to 0 or negative can disable the
 	 * automatic gc.
 	 */
-	if (cfg->gc_auto_threshold <= 0)
+	if (gc_auto_threshold <= 0)
 		return 0;
-	if (!too_many_packs(cfg) && !too_many_loose_objects(cfg->gc_auto_threshold))
+	if (!too_many_packs(gc_auto_pack_limit) &&
+	    !too_many_loose_objects(gc_auto_threshold))
 		return 0;
+
 	return 1;
 }
 
@@ -807,8 +792,15 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 				int aggressive)
 {
 	struct child_process repack_cmd = CHILD_PROCESS_INIT;
+	unsigned long big_pack_threshold = 0;
+	int gc_auto_threshold = 6700;
+	int gc_auto_pack_limit = 50;
 	int ret;
 
+	repo_config_get_int(the_repository, "gc.auto", &gc_auto_threshold);
+	repo_config_get_int(the_repository, "gc.autopacklimit", &gc_auto_pack_limit);
+	repo_config_get_ulong(the_repository, "gc.bigpackthreshold", &big_pack_threshold);
+
 	if (the_repository->repository_format_precious_objects)
 		return 0;
 
@@ -843,19 +835,18 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 		if (keep_largest_pack != -1) {
 			if (keep_largest_pack)
 				find_base_packs(&keep_pack, 0);
-		} else if (cfg->big_pack_threshold) {
-			find_base_packs(&keep_pack, cfg->big_pack_threshold);
+		} else if (big_pack_threshold) {
+			find_base_packs(&keep_pack, big_pack_threshold);
 		}
 
 		add_repack_all_option(cfg, &keep_pack, &repack_cmd.args);
 		string_list_clear(&keep_pack, 0);
-	} else if (too_many_packs(cfg)) {
+	} else if (too_many_packs(gc_auto_pack_limit)) {
 		struct string_list keep_pack = STRING_LIST_INIT_NODUP;
 
-		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;
+		if (big_pack_threshold) {
+			find_base_packs(&keep_pack, big_pack_threshold);
+			if (keep_pack.nr >= gc_auto_pack_limit) {
 				string_list_clear(&keep_pack, 0);
 				find_base_packs(&keep_pack, 0);
 			}
@@ -864,7 +855,7 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 			uint64_t mem_have, mem_want;
 
 			mem_have = total_ram();
-			mem_want = estimate_repack_memory(cfg, p);
+			mem_want = estimate_repack_memory(p);
 
 			/*
 			 * Only allow 1/2 of memory for pack-objects, leave
@@ -905,7 +896,7 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 		}
 	}
 
-	if (opts->auto_flag && too_many_loose_objects(cfg->gc_auto_threshold))
+	if (opts->auto_flag && too_many_loose_objects(gc_auto_threshold))
 		warning(_("There are too many unreachable loose objects; "
 			"run 'git prune' to remove them."));
 
@@ -994,7 +985,7 @@ int cmd_gc(int argc,
 		/*
 		 * Auto-gc should be least intrusive as possible.
 		 */
-		if (!need_to_gc(&cfg) || run_hooks(the_repository, "pre-auto-gc")) {
+		if (!need_to_gc(the_repository) || run_hooks(the_repository, "pre-auto-gc")) {
 			ret = 0;
 			goto out;
 		}
@@ -1291,9 +1282,9 @@ static int maintenance_task_gc_background(struct maintenance_run_opts *opts,
 	return run_command(&child);
 }
 
-static int gc_condition(struct gc_config *cfg)
+static int gc_condition(struct gc_config *cfg UNUSED)
 {
-	return need_to_gc(cfg);
+	return need_to_gc(the_repository);
 }
 
 static int prune_packed(struct maintenance_run_opts *opts)

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 07/12] builtin/gc: introduce object database optimization options
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

Introduce `struct odb_optimize_options` to decouple the options that are
specific to optimizing the object database from `struct gc_config`. This
structure will be moved into the object database layer in a subsequent
commit.

Note that there are a small set of backend-specific options in this
structure. In an ideal world those of course wouldn't exist, but as
we're introducing the object database abstractions retroactively we are
somewhat forced to keep them.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c | 181 +++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 120 insertions(+), 61 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 5d445edaa0..17490106fc 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -593,7 +593,39 @@ static int keep_one_pack(struct string_list_item *item, void *data)
 	return 0;
 }
 
-static void add_repack_all_option(struct gc_config *cfg,
+enum odb_optimize_flags {
+	/* Enable verbose logging and progress reporting. */
+	ODB_OPTIMIZE_VERBOSE = (1 << 0),
+
+	/* Perform auto-maintenance, only optimizing objects as required. */
+	ODB_OPTIMIZE_AUTO = (1 << 1),
+
+	/* Recompute existing deltas. */
+	ODB_OPTIMIZE_NO_REUSE_DELTAS = (1 << 2),
+};
+
+struct odb_optimize_options {
+	enum odb_optimize_flags flags;
+	const char *prune_expire;
+	const char *expire_to;
+	int depth;
+	int window;
+
+	/* Backend-specific options. */
+	int keep_largest_pack;
+	int cruft_packs;
+	unsigned long max_cruft_size;
+};
+
+#define OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, aggressive) \
+	.prune_expire = (cfg)->prune_expire, \
+	.expire_to = (cfg)->repack_expire_to, \
+	.cruft_packs = (cfg)->cruft_packs, \
+	.max_cruft_size = (cfg)->max_cruft_size, \
+	.window = (aggressive) ? (cfg)->aggressive_window : 0, \
+	.depth = (aggressive) ? (cfg)->aggressive_depth : 0
+
+static void add_repack_all_option(const struct odb_optimize_options *opts,
 				  struct string_list *keep_pack,
 				  struct strvec *args)
 {
@@ -603,22 +635,22 @@ static void add_repack_all_option(struct gc_config *cfg,
 	repo_config_get_string(the_repository, "gc.repackfilter", &repack_filter);
 	repo_config_get_string(the_repository, "gc.repackfilterto", &repack_filter_to);
 
-	if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now")
-		&& !(cfg->cruft_packs && cfg->repack_expire_to))
+	if (opts->prune_expire && !strcmp(opts->prune_expire, "now") &&
+	    !(opts->cruft_packs && opts->expire_to))
 		strvec_push(args, "-a");
-	else if (cfg->cruft_packs) {
+	else if (opts->cruft_packs) {
 		strvec_push(args, "--cruft");
-		if (cfg->prune_expire)
-			strvec_pushf(args, "--cruft-expiration=%s", cfg->prune_expire);
-		if (cfg->max_cruft_size)
+		if (opts->prune_expire)
+			strvec_pushf(args, "--cruft-expiration=%s", opts->prune_expire);
+		if (opts->max_cruft_size)
 			strvec_pushf(args, "--max-cruft-size=%lu",
-				     cfg->max_cruft_size);
-		if (cfg->repack_expire_to)
-			strvec_pushf(args, "--expire-to=%s", cfg->repack_expire_to);
+				     opts->max_cruft_size);
+		if (opts->expire_to)
+			strvec_pushf(args, "--expire-to=%s", opts->expire_to);
 	} else {
 		strvec_push(args, "-A");
-		if (cfg->prune_expire)
-			strvec_pushf(args, "--unpack-unreachable=%s", cfg->prune_expire);
+		if (opts->prune_expire)
+			strvec_pushf(args, "--unpack-unreachable=%s", opts->prune_expire);
 	}
 
 	if (keep_pack)
@@ -786,10 +818,8 @@ static int gc_foreground_tasks(struct maintenance_run_opts *opts,
 	return 0;
 }
 
-static int maintenance_task_odb(struct maintenance_run_opts *opts,
-				struct gc_config *cfg,
-				int keep_largest_pack,
-				int aggressive)
+static int odb_optimize(struct object_database *odb,
+			const struct odb_optimize_options *opts)
 {
 	struct child_process repack_cmd = CHILD_PROCESS_INIT;
 	unsigned long big_pack_threshold = 0;
@@ -801,21 +831,20 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 	repo_config_get_int(the_repository, "gc.autopacklimit", &gc_auto_pack_limit);
 	repo_config_get_ulong(the_repository, "gc.bigpackthreshold", &big_pack_threshold);
 
-	if (the_repository->repository_format_precious_objects)
+	if (odb->repo->repository_format_precious_objects)
 		return 0;
 
 	repack_cmd.git_cmd = 1;
 	repack_cmd.odb_to_close = the_repository->objects;
 
 	strvec_pushl(&repack_cmd.args, "repack", "-d", "-l", NULL);
-	if (aggressive) {
+	if (opts->flags & ODB_OPTIMIZE_NO_REUSE_DELTAS)
 		strvec_push(&repack_cmd.args, "-f");
-		if (cfg->aggressive_depth > 0)
-			strvec_pushf(&repack_cmd.args, "--depth=%d", cfg->aggressive_depth);
-		if (cfg->aggressive_window > 0)
-			strvec_pushf(&repack_cmd.args, "--window=%d", cfg->aggressive_window);
-	}
-	if (opts->quiet)
+	if (opts->depth > 0)
+		strvec_pushf(&repack_cmd.args, "--depth=%d", opts->depth);
+	if (opts->window > 0)
+		strvec_pushf(&repack_cmd.args, "--window=%d", opts->window);
+	if (!(opts->flags & ODB_OPTIMIZE_VERBOSE))
 		strvec_push(&repack_cmd.args, "-q");
 
 	/*
@@ -829,47 +858,49 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 	 *
 	 *   - Otherwise we perform an incremental repack.
 	 */
-	if (!opts->auto_flag) {
+	if (!(opts->flags & ODB_OPTIMIZE_AUTO)) {
 		struct string_list keep_pack = STRING_LIST_INIT_NODUP;
 
-		if (keep_largest_pack != -1) {
-			if (keep_largest_pack)
+		if (opts->keep_largest_pack != -1) {
+			if (opts->keep_largest_pack)
 				find_base_packs(&keep_pack, 0);
 		} else if (big_pack_threshold) {
 			find_base_packs(&keep_pack, big_pack_threshold);
 		}
 
-		add_repack_all_option(cfg, &keep_pack, &repack_cmd.args);
+		add_repack_all_option(opts, &keep_pack, &repack_cmd.args);
 		string_list_clear(&keep_pack, 0);
-	} else if (too_many_packs(gc_auto_pack_limit)) {
-		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) {
-				string_list_clear(&keep_pack, 0);
-				find_base_packs(&keep_pack, 0);
+	} else {
+		if (too_many_packs(gc_auto_pack_limit)) {
+			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) {
+					string_list_clear(&keep_pack, 0);
+					find_base_packs(&keep_pack, 0);
+				}
+			} else {
+				struct packed_git *p = find_base_packs(&keep_pack, 0);
+				uint64_t mem_have, mem_want;
+
+				mem_have = total_ram();
+				mem_want = estimate_repack_memory(p);
+
+				/*
+				 * Only allow 1/2 of memory for pack-objects, leave
+				 * the rest for the OS and other processes in the
+				 * system.
+				 */
+				if (!mem_have || mem_want < mem_have / 2)
+					string_list_clear(&keep_pack, 0);
 			}
-		} else {
-			struct packed_git *p = find_base_packs(&keep_pack, 0);
-			uint64_t mem_have, mem_want;
-
-			mem_have = total_ram();
-			mem_want = estimate_repack_memory(p);
 
-			/*
-			 * Only allow 1/2 of memory for pack-objects, leave
-			 * the rest for the OS and other processes in the
-			 * system.
-			 */
-			if (!mem_have || mem_want < mem_have / 2)
-				string_list_clear(&keep_pack, 0);
+			add_repack_all_option(opts, &keep_pack, &repack_cmd.args);
+			string_list_clear(&keep_pack, 0);
+		} else {
+			add_repack_incremental_option(&repack_cmd.args);
 		}
-
-		add_repack_all_option(cfg, &keep_pack, &repack_cmd.args);
-		string_list_clear(&keep_pack, 0);
-	} else {
-		add_repack_incremental_option(&repack_cmd.args);
 	}
 
 	if (run_command(&repack_cmd)) {
@@ -877,13 +908,13 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 		goto out;
 	}
 
-	if (cfg->prune_expire) {
+	if (opts->prune_expire) {
 		struct child_process prune_cmd = CHILD_PROCESS_INIT;
 
 		strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL);
 		/* run `git prune` even if using cruft packs */
-		strvec_push(&prune_cmd.args, cfg->prune_expire);
-		if (opts->quiet)
+		strvec_push(&prune_cmd.args, opts->prune_expire);
+		if (!(opts->flags & ODB_OPTIMIZE_VERBOSE))
 			strvec_push(&prune_cmd.args, "--no-progress");
 		if (repo_has_promisor_remote(the_repository))
 			strvec_push(&prune_cmd.args,
@@ -896,7 +927,7 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 		}
 	}
 
-	if (opts->auto_flag && too_many_loose_objects(gc_auto_threshold))
+	if (opts->flags & ODB_OPTIMIZE_AUTO && too_many_loose_objects(gc_auto_threshold))
 		warning(_("There are too many unreachable loose objects; "
 			"run 'git prune' to remove them."));
 
@@ -906,6 +937,26 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 	return ret;
 }
 
+static int maintenance_task_odb(struct maintenance_run_opts *opts,
+				struct gc_config *cfg,
+				int keep_largest_pack,
+				int aggressive)
+{
+	struct odb_optimize_options odb_opts = {
+		.keep_largest_pack = keep_largest_pack,
+		OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, aggressive),
+	};
+
+	if (opts->auto_flag)
+		odb_opts.flags |= ODB_OPTIMIZE_AUTO;
+	if (!opts->quiet)
+		odb_opts.flags |= ODB_OPTIMIZE_VERBOSE;
+	if (aggressive)
+		odb_opts.flags |= ODB_OPTIMIZE_NO_REUSE_DELTAS;
+
+	return odb_optimize(the_repository->objects, &odb_opts);
+}
+
 int cmd_gc(int argc,
 	   const char **argv,
 	   const char *prefix,
@@ -1596,11 +1647,19 @@ static int maintenance_task_geometric_repack(struct maintenance_run_opts *opts,
 	child.odb_to_close = the_repository->objects;
 
 	strvec_pushl(&child.args, "repack", "-d", "-l", NULL);
-	if (geometry.split < geometry.pack_nr)
+	if (geometry.split < geometry.pack_nr) {
 		strvec_pushf(&child.args, "--geometric=%d",
 			     geometry.split_factor);
-	else
-		add_repack_all_option(cfg, NULL, &child.args);
+	} else {
+		struct odb_optimize_options odb_opts = {
+			OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, 0),
+		};
+
+		if (!opts->quiet)
+			odb_opts.flags |= ODB_OPTIMIZE_VERBOSE;
+
+		add_repack_all_option(&odb_opts, NULL, &child.args);
+	}
 	if (opts->quiet)
 		strvec_push(&child.args, "--quiet");
 	if (the_repository->settings.core_multi_pack_index)

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 08/12] builtin/gc: move geometric repacking into `odb_optimize()`
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

We have two major object database optimization strategies:

  - The legacy strategy used by git-gc(1), which absorbs loose objects
    into packfiles, and eventually merges all packfiles once we have too
    many of them.

  - The more recent "geometric" strategy used by git-maintenance(1),
    which merges packfiles using a geometric sequence.

These two strategies are still using completely separate code paths. In
a subsequent commit we'll want to make both strategies pluggable though.

Prepare for this change by merging the "geometric" strategy into
`odb_optimize()`. This also allows us to reuse some of the logic we have
in that function.

Note that this change requires us to adapt tests because we're now using
"-q" instead of "--quiet". Naturally though, these invocations are of
course equivalent to one another.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c           | 171 +++++++++++++++++++++++++------------------------
 t/t7900-maintenance.sh |  18 +++---
 2 files changed, 96 insertions(+), 93 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 17490106fc..c8504f4456 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -593,6 +593,11 @@ static int keep_one_pack(struct string_list_item *item, void *data)
 	return 0;
 }
 
+enum odb_optimize_strategy {
+	ODB_OPTIMIZE_INCREMENTAL,
+	ODB_OPTIMIZE_GEOMETRIC,
+};
+
 enum odb_optimize_flags {
 	/* Enable verbose logging and progress reporting. */
 	ODB_OPTIMIZE_VERBOSE = (1 << 0),
@@ -605,6 +610,7 @@ enum odb_optimize_flags {
 };
 
 struct odb_optimize_options {
+	enum odb_optimize_strategy strategy;
 	enum odb_optimize_flags flags;
 	const char *prune_expire;
 	const char *expire_to;
@@ -858,49 +864,87 @@ static int odb_optimize(struct object_database *odb,
 	 *
 	 *   - Otherwise we perform an incremental repack.
 	 */
-	if (!(opts->flags & ODB_OPTIMIZE_AUTO)) {
-		struct string_list keep_pack = STRING_LIST_INIT_NODUP;
-
-		if (opts->keep_largest_pack != -1) {
-			if (opts->keep_largest_pack)
-				find_base_packs(&keep_pack, 0);
-		} else if (big_pack_threshold) {
-			find_base_packs(&keep_pack, big_pack_threshold);
-		}
-
-		add_repack_all_option(opts, &keep_pack, &repack_cmd.args);
-		string_list_clear(&keep_pack, 0);
-	} else {
-		if (too_many_packs(gc_auto_pack_limit)) {
+	switch (opts->strategy) {
+	case ODB_OPTIMIZE_INCREMENTAL:
+		if (!(opts->flags & ODB_OPTIMIZE_AUTO)) {
 			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) {
-					string_list_clear(&keep_pack, 0);
+			if (opts->keep_largest_pack != -1) {
+				if (opts->keep_largest_pack)
 					find_base_packs(&keep_pack, 0);
-				}
-			} else {
-				struct packed_git *p = find_base_packs(&keep_pack, 0);
-				uint64_t mem_have, mem_want;
-
-				mem_have = total_ram();
-				mem_want = estimate_repack_memory(p);
-
-				/*
-				 * Only allow 1/2 of memory for pack-objects, leave
-				 * the rest for the OS and other processes in the
-				 * system.
-				 */
-				if (!mem_have || mem_want < mem_have / 2)
-					string_list_clear(&keep_pack, 0);
+			} else if (big_pack_threshold) {
+				find_base_packs(&keep_pack, big_pack_threshold);
 			}
 
 			add_repack_all_option(opts, &keep_pack, &repack_cmd.args);
 			string_list_clear(&keep_pack, 0);
 		} else {
-			add_repack_incremental_option(&repack_cmd.args);
+			if (too_many_packs(gc_auto_pack_limit)) {
+				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) {
+						string_list_clear(&keep_pack, 0);
+						find_base_packs(&keep_pack, 0);
+					}
+				} else {
+					struct packed_git *p = find_base_packs(&keep_pack, 0);
+					uint64_t mem_have, mem_want;
+
+					mem_have = total_ram();
+					mem_want = estimate_repack_memory(p);
+
+					/*
+					 * Only allow 1/2 of memory for pack-objects, leave
+					 * the rest for the OS and other processes in the
+					 * system.
+					 */
+					if (!mem_have || mem_want < mem_have / 2)
+						string_list_clear(&keep_pack, 0);
+				}
+
+				add_repack_all_option(opts, &keep_pack, &repack_cmd.args);
+				string_list_clear(&keep_pack, 0);
+			} else {
+				add_repack_incremental_option(&repack_cmd.args);
+			}
 		}
+
+		break;
+	case ODB_OPTIMIZE_GEOMETRIC: {
+		struct pack_geometry geometry = {
+			.split_factor = 2,
+		};
+		struct pack_objects_args po_args = {
+			.local = 1,
+		};
+		struct existing_packs existing_packs = EXISTING_PACKS_INIT;
+		struct string_list kept_packs = STRING_LIST_INIT_DUP;
+
+		repo_config_get_int(the_repository, "maintenance.geometric-repack.splitFactor",
+				    &geometry.split_factor);
+
+		existing_packs.repo = the_repository;
+		existing_packs_collect(&existing_packs, &kept_packs);
+		pack_geometry_init(&geometry, &existing_packs, &po_args);
+		pack_geometry_split(&geometry);
+
+		if (geometry.split < geometry.pack_nr) {
+			strvec_pushf(&repack_cmd.args, "--geometric=%d",
+				     geometry.split_factor);
+		} else {
+			add_repack_all_option(opts, NULL, &repack_cmd.args);
+		}
+		if (the_repository->settings.core_multi_pack_index)
+			strvec_push(&repack_cmd.args, "--write-midx");
+
+		existing_packs_release(&existing_packs);
+		pack_geometry_release(&geometry);
+		break;
+	}
+	default:
+		die("unknown maintenance strategy '%d'", opts->strategy);
 	}
 
 	if (run_command(&repack_cmd)) {
@@ -908,7 +952,8 @@ static int odb_optimize(struct object_database *odb,
 		goto out;
 	}
 
-	if (opts->prune_expire) {
+	/* Geometric repacking uses cruft packs, so we don't have to prune separately. */
+	if (opts->strategy != ODB_OPTIMIZE_GEOMETRIC && opts->prune_expire) {
 		struct child_process prune_cmd = CHILD_PROCESS_INIT;
 
 		strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL);
@@ -943,6 +988,7 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
 				int aggressive)
 {
 	struct odb_optimize_options odb_opts = {
+		.strategy = ODB_OPTIMIZE_INCREMENTAL,
 		.keep_largest_pack = keep_largest_pack,
 		OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, aggressive),
 	};
@@ -1624,58 +1670,15 @@ static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts
 static int maintenance_task_geometric_repack(struct maintenance_run_opts *opts,
 					     struct gc_config *cfg)
 {
-	struct pack_geometry geometry = {
-		.split_factor = 2,
-	};
-	struct pack_objects_args po_args = {
-		.local = 1,
+	struct odb_optimize_options odb_opts = {
+		.strategy = ODB_OPTIMIZE_GEOMETRIC,
+		OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, 0),
 	};
-	struct existing_packs existing_packs = EXISTING_PACKS_INIT;
-	struct string_list kept_packs = STRING_LIST_INIT_DUP;
-	struct child_process child = CHILD_PROCESS_INIT;
-	int ret;
-
-	repo_config_get_int(the_repository, "maintenance.geometric-repack.splitFactor",
-			    &geometry.split_factor);
-
-	existing_packs.repo = the_repository;
-	existing_packs_collect(&existing_packs, &kept_packs);
-	pack_geometry_init(&geometry, &existing_packs, &po_args);
-	pack_geometry_split(&geometry);
-
-	child.git_cmd = 1;
-	child.odb_to_close = the_repository->objects;
-
-	strvec_pushl(&child.args, "repack", "-d", "-l", NULL);
-	if (geometry.split < geometry.pack_nr) {
-		strvec_pushf(&child.args, "--geometric=%d",
-			     geometry.split_factor);
-	} else {
-		struct odb_optimize_options odb_opts = {
-			OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, 0),
-		};
 
-		if (!opts->quiet)
-			odb_opts.flags |= ODB_OPTIMIZE_VERBOSE;
-
-		add_repack_all_option(&odb_opts, NULL, &child.args);
-	}
-	if (opts->quiet)
-		strvec_push(&child.args, "--quiet");
-	if (the_repository->settings.core_multi_pack_index)
-		strvec_push(&child.args, "--write-midx");
-
-	if (run_command(&child)) {
-		ret = error(_("failed to perform geometric repack"));
-		goto out;
-	}
-
-	ret = 0;
+	if (!opts->quiet)
+		odb_opts.flags |= ODB_OPTIMIZE_VERBOSE;
 
-out:
-	existing_packs_release(&existing_packs);
-	pack_geometry_release(&geometry);
-	return ret;
+	return odb_optimize(the_repository->objects, &odb_opts);
 }
 
 static int geometric_repack_auto_condition(struct gc_config *cfg UNUSED)
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index 2d52e7918a..6d87da2ae4 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -574,8 +574,8 @@ run_and_verify_geometric_pack () {
 	rm -f "trace2.txt" &&
 	GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
 		git maintenance run --task=geometric-repack 2>/dev/null &&
-	test_subcommand git repack -d -l --geometric=2 \
-		--quiet --write-midx <trace2.txt &&
+	test_subcommand git repack -d -l -q --geometric=2 \
+		--write-midx <trace2.txt &&
 
 	# Verify that the number of packfiles matches our expectation.
 	ls -l .git/objects/pack/*.pack >packfiles &&
@@ -606,8 +606,8 @@ test_expect_success 'geometric repacking task' '
 		# The initial repack causes an all-into-one repack.
 		GIT_TRACE2_EVENT="$(pwd)/initial-repack.txt" \
 			git maintenance run --task=geometric-repack 2>/dev/null &&
-		test_subcommand git repack -d -l --cruft --cruft-expiration=2.weeks.ago \
-			--quiet --write-midx <initial-repack.txt &&
+		test_subcommand git repack -d -l -q --cruft --cruft-expiration=2.weeks.ago \
+			--write-midx <initial-repack.txt &&
 
 		# Repacking should now cause a no-op geometric repack because
 		# no packfiles need to be combined.
@@ -627,8 +627,8 @@ test_expect_success 'geometric repacking task' '
 		# an all-into-one-repack.
 		GIT_TRACE2_EVENT="$(pwd)/all-into-one-repack.txt" \
 			git maintenance run --task=geometric-repack 2>/dev/null &&
-		test_subcommand git repack -d -l --cruft --cruft-expiration=2.weeks.ago \
-			--quiet --write-midx <all-into-one-repack.txt &&
+		test_subcommand git repack -d -l -q --cruft --cruft-expiration=2.weeks.ago \
+			--write-midx <all-into-one-repack.txt &&
 
 		# The geometric repack soaks up unreachable objects.
 		echo blob-1 | git hash-object -w --stdin -t blob &&
@@ -662,8 +662,8 @@ test_expect_success 'geometric repacking task' '
 		run_and_verify_geometric_pack 3 &&
 		GIT_TRACE2_EVENT="$(pwd)/cruft-repack.txt" \
 			git maintenance run --task=geometric-repack 2>/dev/null &&
-		test_subcommand git repack -d -l --cruft --cruft-expiration=2.weeks.ago \
-			--quiet --write-midx <cruft-repack.txt &&
+		test_subcommand git repack -d -l -q --cruft --cruft-expiration=2.weeks.ago \
+			--write-midx <cruft-repack.txt &&
 		ls .git/objects/pack/*.pack >packs &&
 		test_line_count = 2 packs &&
 		ls .git/objects/pack/*.mtimes >cruft &&
@@ -754,7 +754,7 @@ test_expect_success 'geometric repacking honors configured split factor' '
 
 		test_geometric_repack_needed false splitFactor=2 &&
 		test_geometric_repack_needed true splitFactor=3 &&
-		test_subcommand git repack -d -l --geometric=3 --quiet --write-midx <trace2.txt
+		test_subcommand git repack -d -l -q --geometric=3 --write-midx <trace2.txt
 	)
 '
 

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 09/12] builtin/gc: introduce `odb_optimize_required()`
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

When invoking either git-gc(1) or git-maintenance(1) with the "--auto"
flag then we only perform those maintenance tasks that are actually
required. This logic is inherently an implementation detail of the
object database backend that's in use. But the logic is scattered around
multiple different functions, which makes it hard to make the logic
pluggable.

Introduce a new `odb_optimize_required()` function that allows us to
check these conditions in a generic way.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c | 160 ++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 92 insertions(+), 68 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index c8504f4456..e119930adc 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -676,25 +676,84 @@ static void add_repack_incremental_option(struct strvec *args)
 	strvec_push(args, "--no-write-bitmap-index");
 }
 
-static int need_to_gc(struct repository *repo)
+static bool odb_optimize_required(struct object_database *odb,
+				  const struct odb_optimize_options *opts)
 {
-	int gc_auto_threshold = 6700;
-	int gc_auto_pack_limit = 50;
+	switch (opts->strategy) {
+	case ODB_OPTIMIZE_INCREMENTAL: {
+		int gc_auto_threshold = 6700;
+		int gc_auto_pack_limit = 50;
 
-	repo_config_get_int(repo, "gc.auto", &gc_auto_threshold);
-	repo_config_get_int(repo, "gc.autopacklimit", &gc_auto_pack_limit);
+		repo_config_get_int(odb->repo, "gc.auto", &gc_auto_threshold);
+		repo_config_get_int(odb->repo, "gc.autopacklimit", &gc_auto_pack_limit);
 
-	/*
-	 * Setting gc.auto to 0 or negative can disable the
-	 * automatic gc.
-	 */
-	if (gc_auto_threshold <= 0)
-		return 0;
-	if (!too_many_packs(gc_auto_pack_limit) &&
-	    !too_many_loose_objects(gc_auto_threshold))
-		return 0;
+		/*
+		 * Setting gc.auto to 0 or negative can disable the
+		 * automatic gc.
+		 */
+		if (gc_auto_threshold <= 0)
+			return false;
+		if (!too_many_packs(gc_auto_pack_limit) &&
+		    !too_many_loose_objects(gc_auto_threshold))
+			return false;
 
-	return 1;
+		return true;
+	}
+	case ODB_OPTIMIZE_GEOMETRIC: {
+		struct pack_geometry geometry = {
+			.split_factor = 2,
+		};
+		struct pack_objects_args po_args = {
+			.local = 1,
+		};
+		struct existing_packs existing_packs = EXISTING_PACKS_INIT;
+		struct string_list kept_packs = STRING_LIST_INIT_DUP;
+		int auto_value = 100;
+		bool ret;
+
+		repo_config_get_int(odb->repo, "maintenance.geometric-repack.auto",
+				    &auto_value);
+		if (!auto_value)
+			return false;
+		if (auto_value < 0)
+			return true;
+
+		repo_config_get_int(odb->repo, "maintenance.geometric-repack.splitFactor",
+				    &geometry.split_factor);
+
+		existing_packs.repo = odb->repo;
+		existing_packs_collect(&existing_packs, &kept_packs);
+		pack_geometry_init(&geometry, &existing_packs, &po_args);
+		pack_geometry_split(&geometry);
+
+		/*
+		 * When we'd merge at least two packs with one another we always
+		 * perform the repack.
+		 */
+		if (geometry.split) {
+			ret = true;
+			goto out;
+		}
+
+		/*
+		 * Otherwise, we estimate the number of loose objects to determine
+		 * whether we want to create a new packfile or not.
+		 */
+		if (too_many_loose_objects(auto_value)) {
+			ret = true;
+			goto out;
+		}
+
+		ret = false;
+
+	out:
+		existing_packs_release(&existing_packs);
+		pack_geometry_release(&geometry);
+		return ret;
+	}
+	default:
+		BUG("unknown maintenance strategy '%d'", opts->strategy);
+	}
 }
 
 /* return NULL on success, else hostname running the gc */
@@ -1076,13 +1135,19 @@ int cmd_gc(int argc,
 		die(_("failed to parse prune expiry value %s"), cfg.prune_expire);
 
 	if (opts.auto_flag) {
+		struct odb_optimize_options optimize_opts = {
+			.strategy = ODB_OPTIMIZE_INCREMENTAL,
+			OPTIMIZE_FIELDS_FROM_GC_CONFIG(&cfg, 0),
+		};
+
 		if (cfg.detach_auto && opts.detach < 0)
 			opts.detach = 1;
 
 		/*
 		 * Auto-gc should be least intrusive as possible.
 		 */
-		if (!need_to_gc(the_repository) || run_hooks(the_repository, "pre-auto-gc")) {
+		if (!odb_optimize_required(the_repository->objects, &optimize_opts) ||
+		    run_hooks(the_repository, "pre-auto-gc")) {
 			ret = 0;
 			goto out;
 		}
@@ -1379,9 +1444,13 @@ static int maintenance_task_gc_background(struct maintenance_run_opts *opts,
 	return run_command(&child);
 }
 
-static int gc_condition(struct gc_config *cfg UNUSED)
+static int gc_condition(struct gc_config *cfg)
 {
-	return need_to_gc(the_repository);
+	struct odb_optimize_options opts = {
+		.strategy = ODB_OPTIMIZE_INCREMENTAL,
+		OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, 0),
+	};
+	return odb_optimize_required(the_repository->objects, &opts);
 }
 
 static int prune_packed(struct maintenance_run_opts *opts)
@@ -1681,58 +1750,13 @@ static int maintenance_task_geometric_repack(struct maintenance_run_opts *opts,
 	return odb_optimize(the_repository->objects, &odb_opts);
 }
 
-static int geometric_repack_auto_condition(struct gc_config *cfg UNUSED)
+static int geometric_repack_auto_condition(struct gc_config *cfg)
 {
-	struct pack_geometry geometry = {
-		.split_factor = 2,
-	};
-	struct pack_objects_args po_args = {
-		.local = 1,
+	struct odb_optimize_options opts = {
+		.strategy = ODB_OPTIMIZE_GEOMETRIC,
+		OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, 0),
 	};
-	struct existing_packs existing_packs = EXISTING_PACKS_INIT;
-	struct string_list kept_packs = STRING_LIST_INIT_DUP;
-	int auto_value = 100;
-	int ret;
-
-	repo_config_get_int(the_repository, "maintenance.geometric-repack.auto",
-			    &auto_value);
-	if (!auto_value)
-		return 0;
-	if (auto_value < 0)
-		return 1;
-
-	repo_config_get_int(the_repository, "maintenance.geometric-repack.splitFactor",
-			    &geometry.split_factor);
-
-	existing_packs.repo = the_repository;
-	existing_packs_collect(&existing_packs, &kept_packs);
-	pack_geometry_init(&geometry, &existing_packs, &po_args);
-	pack_geometry_split(&geometry);
-
-	/*
-	 * When we'd merge at least two packs with one another we always
-	 * perform the repack.
-	 */
-	if (geometry.split) {
-		ret = 1;
-		goto out;
-	}
-
-	/*
-	 * Otherwise, we estimate the number of loose objects to determine
-	 * whether we want to create a new packfile or not.
-	 */
-	if (too_many_loose_objects(auto_value)) {
-		ret = 1;
-		goto out;
-	}
-
-	ret = 0;
-
-out:
-	existing_packs_release(&existing_packs);
-	pack_geometry_release(&geometry);
-	return ret;
+	return odb_optimize_required(the_repository->objects, &opts);
 }
 
 typedef int (*maintenance_task_fn)(struct maintenance_run_opts *opts,

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 10/12] builtin/gc: refactor ODB optimizations to operate on "files" source
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

We have a couple of functions that are implementation details of how the
"files" object database source performs optimizations. These functions
often use global state like `the_repository` and implicitly derive the
source they are supposed to optimize.

Refactor these interfaces to accept a "files" source directly. This will
make it easier to move around the whole logic into "odb/source-files.c"
in a subsequent step.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c | 79 +++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 41 insertions(+), 38 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index e119930adc..3207182488 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -428,9 +428,8 @@ static int rerere_gc_condition(struct gc_config *cfg UNUSED)
 	return should_gc;
 }
 
-static int too_many_loose_objects(int limit)
+static int too_many_loose_objects(struct odb_source_files *files, int limit)
 {
-	struct odb_source_files *files = odb_source_files_downcast(the_repository->objects->sources);
 	/*
 	 * This is weird, but stems from legacy behaviour: the GC auto
 	 * threshold was always essentially interpreted as if it was rounded up
@@ -446,19 +445,21 @@ static int too_many_loose_objects(int limit)
 	return loose_count > auto_threshold;
 }
 
-static struct packed_git *find_base_packs(struct string_list *packs,
+static struct packed_git *find_base_packs(struct odb_source_files *files,
+					  struct string_list *packs,
 					  unsigned long limit)
 {
-	struct packed_git *p, *base = NULL;
+	struct packfile_list_entry *e;
+	struct packed_git *base = NULL;
 
-	repo_for_each_pack(the_repository, p) {
-		if (!p->pack_local || p->is_cruft)
+	for (e = packfile_store_get_packs(files->packed); e; e = e->next) {
+		if (e->pack->is_cruft)
 			continue;
 		if (limit) {
-			if (p->pack_size >= limit)
-				string_list_append(packs, p->pack_name);
-		} else if (!base || base->pack_size < p->pack_size) {
-			base = p;
+			if (e->pack->pack_size >= limit)
+				string_list_append(packs, e->pack->pack_name);
+		} else if (!base || base->pack_size < e->pack->pack_size) {
+			base = e->pack;
 		}
 	}
 
@@ -468,18 +469,16 @@ static struct packed_git *find_base_packs(struct string_list *packs,
 	return base;
 }
 
-static int too_many_packs(int gc_auto_pack_limit)
+static int too_many_packs(struct odb_source_files *files, int gc_auto_pack_limit)
 {
-	struct packed_git *p;
+	struct packfile_list_entry *e;
 	int cnt = 0;
 
 	if (gc_auto_pack_limit <= 0)
 		return 0;
 
-	repo_for_each_pack(the_repository, p) {
-		if (!p->pack_local)
-			continue;
-		if (p->pack_keep)
+	for (e = packfile_store_get_packs(files->packed); e; e = e->next) {
+		if (e->pack->pack_keep)
 			continue;
 		/*
 		 * Perhaps check the size of the pack and count only
@@ -535,15 +534,16 @@ 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 odb_source_files *files,
+				       struct packed_git *pack)
 {
 	unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
 	unsigned long delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT;
 	unsigned long nr_objects;
 	size_t os_cache, heap;
 
-	if (odb_count_objects(the_repository->objects,
-			      ODB_COUNT_OBJECTS_APPROXIMATE, &nr_objects) < 0)
+	if (odb_source_count_objects(&files->base, ODB_COUNT_OBJECTS_APPROXIMATE,
+				     &nr_objects) < 0)
 		return 0;
 
 	if (!pack || !nr_objects)
@@ -679,6 +679,8 @@ static void add_repack_incremental_option(struct strvec *args)
 static bool odb_optimize_required(struct object_database *odb,
 				  const struct odb_optimize_options *opts)
 {
+	struct odb_source_files *files = odb_source_files_downcast(odb->sources);
+
 	switch (opts->strategy) {
 	case ODB_OPTIMIZE_INCREMENTAL: {
 		int gc_auto_threshold = 6700;
@@ -693,8 +695,8 @@ static bool odb_optimize_required(struct object_database *odb,
 		 */
 		if (gc_auto_threshold <= 0)
 			return false;
-		if (!too_many_packs(gc_auto_pack_limit) &&
-		    !too_many_loose_objects(gc_auto_threshold))
+		if (!too_many_packs(files, gc_auto_pack_limit) &&
+		    !too_many_loose_objects(files, gc_auto_threshold))
 			return false;
 
 		return true;
@@ -739,7 +741,7 @@ static bool odb_optimize_required(struct object_database *odb,
 		 * Otherwise, we estimate the number of loose objects to determine
 		 * whether we want to create a new packfile or not.
 		 */
-		if (too_many_loose_objects(auto_value)) {
+		if (too_many_loose_objects(files, auto_value)) {
 			ret = true;
 			goto out;
 		}
@@ -886,21 +888,22 @@ static int gc_foreground_tasks(struct maintenance_run_opts *opts,
 static int odb_optimize(struct object_database *odb,
 			const struct odb_optimize_options *opts)
 {
+	struct odb_source_files *files = odb_source_files_downcast(odb->sources);
 	struct child_process repack_cmd = CHILD_PROCESS_INIT;
 	unsigned long big_pack_threshold = 0;
 	int gc_auto_threshold = 6700;
 	int gc_auto_pack_limit = 50;
 	int ret;
 
-	repo_config_get_int(the_repository, "gc.auto", &gc_auto_threshold);
-	repo_config_get_int(the_repository, "gc.autopacklimit", &gc_auto_pack_limit);
-	repo_config_get_ulong(the_repository, "gc.bigpackthreshold", &big_pack_threshold);
+	repo_config_get_int(odb->repo, "gc.auto", &gc_auto_threshold);
+	repo_config_get_int(odb->repo, "gc.autopacklimit", &gc_auto_pack_limit);
+	repo_config_get_ulong(odb->repo, "gc.bigpackthreshold", &big_pack_threshold);
 
 	if (odb->repo->repository_format_precious_objects)
 		return 0;
 
 	repack_cmd.git_cmd = 1;
-	repack_cmd.odb_to_close = the_repository->objects;
+	repack_cmd.odb_to_close = odb->repo->objects;
 
 	strvec_pushl(&repack_cmd.args, "repack", "-d", "-l", NULL);
 	if (opts->flags & ODB_OPTIMIZE_NO_REUSE_DELTAS)
@@ -930,29 +933,29 @@ static int odb_optimize(struct object_database *odb,
 
 			if (opts->keep_largest_pack != -1) {
 				if (opts->keep_largest_pack)
-					find_base_packs(&keep_pack, 0);
+					find_base_packs(files, &keep_pack, 0);
 			} else if (big_pack_threshold) {
-				find_base_packs(&keep_pack, big_pack_threshold);
+				find_base_packs(files, &keep_pack, big_pack_threshold);
 			}
 
 			add_repack_all_option(opts, &keep_pack, &repack_cmd.args);
 			string_list_clear(&keep_pack, 0);
 		} else {
-			if (too_many_packs(gc_auto_pack_limit)) {
+			if (too_many_packs(files, gc_auto_pack_limit)) {
 				struct string_list keep_pack = STRING_LIST_INIT_NODUP;
 
 				if (big_pack_threshold) {
-					find_base_packs(&keep_pack, big_pack_threshold);
+					find_base_packs(files, &keep_pack, big_pack_threshold);
 					if (keep_pack.nr >= gc_auto_pack_limit) {
 						string_list_clear(&keep_pack, 0);
-						find_base_packs(&keep_pack, 0);
+						find_base_packs(files, &keep_pack, 0);
 					}
 				} else {
-					struct packed_git *p = find_base_packs(&keep_pack, 0);
+					struct packed_git *p = find_base_packs(files, &keep_pack, 0);
 					uint64_t mem_have, mem_want;
 
 					mem_have = total_ram();
-					mem_want = estimate_repack_memory(p);
+					mem_want = estimate_repack_memory(files, p);
 
 					/*
 					 * Only allow 1/2 of memory for pack-objects, leave
@@ -981,10 +984,10 @@ static int odb_optimize(struct object_database *odb,
 		struct existing_packs existing_packs = EXISTING_PACKS_INIT;
 		struct string_list kept_packs = STRING_LIST_INIT_DUP;
 
-		repo_config_get_int(the_repository, "maintenance.geometric-repack.splitFactor",
+		repo_config_get_int(odb->repo, "maintenance.geometric-repack.splitFactor",
 				    &geometry.split_factor);
 
-		existing_packs.repo = the_repository;
+		existing_packs.repo = odb->repo;
 		existing_packs_collect(&existing_packs, &kept_packs);
 		pack_geometry_init(&geometry, &existing_packs, &po_args);
 		pack_geometry_split(&geometry);
@@ -995,7 +998,7 @@ static int odb_optimize(struct object_database *odb,
 		} else {
 			add_repack_all_option(opts, NULL, &repack_cmd.args);
 		}
-		if (the_repository->settings.core_multi_pack_index)
+		if (odb->repo->settings.core_multi_pack_index)
 			strvec_push(&repack_cmd.args, "--write-midx");
 
 		existing_packs_release(&existing_packs);
@@ -1020,7 +1023,7 @@ static int odb_optimize(struct object_database *odb,
 		strvec_push(&prune_cmd.args, opts->prune_expire);
 		if (!(opts->flags & ODB_OPTIMIZE_VERBOSE))
 			strvec_push(&prune_cmd.args, "--no-progress");
-		if (repo_has_promisor_remote(the_repository))
+		if (repo_has_promisor_remote(odb->repo))
 			strvec_push(&prune_cmd.args,
 				    "--exclude-promisor-objects");
 		prune_cmd.git_cmd = 1;
@@ -1031,7 +1034,7 @@ static int odb_optimize(struct object_database *odb,
 		}
 	}
 
-	if (opts->flags & ODB_OPTIMIZE_AUTO && too_many_loose_objects(gc_auto_threshold))
+	if (opts->flags & ODB_OPTIMIZE_AUTO && too_many_loose_objects(files, gc_auto_threshold))
 		warning(_("There are too many unreachable loose objects; "
 			"run 'git prune' to remove them."));
 

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 11/12] builtin/gc: fix signedness issues in ODB-related functionality
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

There are a couple of signedness issues in ODB-related functionality.
These are not a problem because we disable -Wsign-compare in this file,
but once we move these functions into "odb/source-files.c" they will
result in warnings.

Fix those issues:

  - In `too_many_loose_objects()` we receive a signed limit, but compare
    it with the unsigned actual number of loose objects. This is fixed
    by bailing out immediately when the limit is smaller than or equal
    to zero, which we also do similarly in other places. The warning is
    then squelched via a cast.

  - In `find_base_packs()` we compare the signed size of the pack
    against the unsigned limit. As the pack size is always going to be a
    positive file size it's safe to cast it to an unsigned value.

  - In `odb_optimize()` we compare the unsigned `keep_pack.nr` value
    against the signed `gc_auto_pack_limit`. We only reach this code
    when `too_many_packs()` returns true-ish, and that can only happen
    when `gc_auto_pack_limit > 0`. Consequently, we can fix the warning
    by casting the limit to an unsigned value.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 3207182488..8cf3781313 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -430,19 +430,21 @@ static int rerere_gc_condition(struct gc_config *cfg UNUSED)
 
 static int too_many_loose_objects(struct odb_source_files *files, int limit)
 {
-	/*
-	 * This is weird, but stems from legacy behaviour: the GC auto
-	 * threshold was always essentially interpreted as if it was rounded up
-	 * to the next multiple 256 of, so we retain this behaviour for now.
-	 */
-	int auto_threshold = DIV_ROUND_UP(limit, 256) * 256;
 	unsigned long loose_count;
 
+	if (limit <= 0)
+		return 0;
+
 	if (odb_source_count_objects(&files->loose->base, ODB_COUNT_OBJECTS_APPROXIMATE,
 				     &loose_count) < 0)
 		return 0;
 
-	return loose_count > auto_threshold;
+	/*
+	 * This is weird, but stems from legacy behaviour: the GC auto
+	 * threshold was always essentially interpreted as if it was rounded up
+	 * to the next multiple 256 of, so we retain this behaviour for now.
+	 */
+	return loose_count > (DIV_ROUND_UP(((unsigned long) limit), 256) * 256);
 }
 
 static struct packed_git *find_base_packs(struct odb_source_files *files,
@@ -456,7 +458,7 @@ static struct packed_git *find_base_packs(struct odb_source_files *files,
 		if (e->pack->is_cruft)
 			continue;
 		if (limit) {
-			if (e->pack->pack_size >= limit)
+			if ((uintmax_t) e->pack->pack_size >= limit)
 				string_list_append(packs, e->pack->pack_name);
 		} else if (!base || base->pack_size < e->pack->pack_size) {
 			base = e->pack;
@@ -946,7 +948,7 @@ static int odb_optimize(struct object_database *odb,
 
 				if (big_pack_threshold) {
 					find_base_packs(files, &keep_pack, big_pack_threshold);
-					if (keep_pack.nr >= gc_auto_pack_limit) {
+					if (keep_pack.nr >= (unsigned long) gc_auto_pack_limit) {
 						string_list_clear(&keep_pack, 0);
 						find_base_packs(files, &keep_pack, 0);
 					}

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* [PATCH v2 12/12] odb: make optimizations pluggable
From: Patrick Steinhardt @ 2026-07-13  5:52 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <20260713-b4-pks-odb-optimize-v2-0-9c2c3ee94b38@pks.im>

Move `odb_optimize()` and `odb_optimize_required()` from "builtin/gc.c"
into the "files" source and wire them up via newly introduced vtable
pointers for the object database sources. This makes the logic pluggable
and thus allows other backends to have their own, custom implementation.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/gc.c       | 490 +----------------------------------------------------
 odb.c              |  12 ++
 odb.h              |  45 +++++
 odb/source-files.c | 470 ++++++++++++++++++++++++++++++++++++++++++++++++++
 odb/source-files.h |  15 ++
 odb/source.h       |  36 ++++
 6 files changed, 579 insertions(+), 489 deletions(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 8cf3781313..ac1a21e912 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -30,16 +30,11 @@
 #include "commit-graph.h"
 #include "packfile.h"
 #include "object-file.h"
-#include "pack.h"
-#include "pack-objects.h"
+#include "odb.h"
 #include "path.h"
 #include "reflog.h"
-#include "repack.h"
 #include "rerere.h"
 #include "revision.h"
-#include "blob.h"
-#include "tree.h"
-#include "promisor-remote.h"
 #include "refs.h"
 #include "remote.h"
 #include "exec-cmd.h"
@@ -428,203 +423,6 @@ static int rerere_gc_condition(struct gc_config *cfg UNUSED)
 	return should_gc;
 }
 
-static int too_many_loose_objects(struct odb_source_files *files, int limit)
-{
-	unsigned long loose_count;
-
-	if (limit <= 0)
-		return 0;
-
-	if (odb_source_count_objects(&files->loose->base, ODB_COUNT_OBJECTS_APPROXIMATE,
-				     &loose_count) < 0)
-		return 0;
-
-	/*
-	 * This is weird, but stems from legacy behaviour: the GC auto
-	 * threshold was always essentially interpreted as if it was rounded up
-	 * to the next multiple 256 of, so we retain this behaviour for now.
-	 */
-	return loose_count > (DIV_ROUND_UP(((unsigned long) limit), 256) * 256);
-}
-
-static struct packed_git *find_base_packs(struct odb_source_files *files,
-					  struct string_list *packs,
-					  unsigned long limit)
-{
-	struct packfile_list_entry *e;
-	struct packed_git *base = NULL;
-
-	for (e = packfile_store_get_packs(files->packed); e; e = e->next) {
-		if (e->pack->is_cruft)
-			continue;
-		if (limit) {
-			if ((uintmax_t) e->pack->pack_size >= limit)
-				string_list_append(packs, e->pack->pack_name);
-		} else if (!base || base->pack_size < e->pack->pack_size) {
-			base = e->pack;
-		}
-	}
-
-	if (base)
-		string_list_append(packs, base->pack_name);
-
-	return base;
-}
-
-static int too_many_packs(struct odb_source_files *files, int gc_auto_pack_limit)
-{
-	struct packfile_list_entry *e;
-	int cnt = 0;
-
-	if (gc_auto_pack_limit <= 0)
-		return 0;
-
-	for (e = packfile_store_get_packs(files->packed); e; e = e->next) {
-		if (e->pack->pack_keep)
-			continue;
-		/*
-		 * Perhaps check the size of the pack and count only
-		 * very small ones here?
-		 */
-		cnt++;
-	}
-	return gc_auto_pack_limit < cnt;
-}
-
-static uint64_t total_ram(void)
-{
-#if defined(HAVE_SYSINFO)
-	struct sysinfo si;
-
-	if (!sysinfo(&si)) {
-		uint64_t total = si.totalram;
-
-		if (si.mem_unit > 1)
-			total *= (uint64_t)si.mem_unit;
-		return total;
-	}
-#elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM) || defined(HW_PHYSMEM64))
-	uint64_t physical_memory;
-	int mib[2];
-	size_t length;
-
-	mib[0] = CTL_HW;
-# if defined(HW_MEMSIZE)
-	mib[1] = HW_MEMSIZE;
-# elif defined(HW_PHYSMEM64)
-	mib[1] = HW_PHYSMEM64;
-# else
-	mib[1] = HW_PHYSMEM;
-# endif
-	length = sizeof(physical_memory);
-	if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0)) {
-		if (length == 4) {
-			uint32_t mem;
-
-			if (!sysctl(mib, 2, &mem, &length, NULL, 0))
-				physical_memory = mem;
-		}
-		return physical_memory;
-	}
-#elif defined(GIT_WINDOWS_NATIVE)
-	MEMORYSTATUSEX memInfo;
-
-	memInfo.dwLength = sizeof(MEMORYSTATUSEX);
-	if (GlobalMemoryStatusEx(&memInfo))
-		return memInfo.ullTotalPhys;
-#endif
-	return 0;
-}
-
-static uint64_t estimate_repack_memory(struct odb_source_files *files,
-				       struct packed_git *pack)
-{
-	unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
-	unsigned long delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT;
-	unsigned long nr_objects;
-	size_t os_cache, heap;
-
-	if (odb_source_count_objects(&files->base, ODB_COUNT_OBJECTS_APPROXIMATE,
-				     &nr_objects) < 0)
-		return 0;
-
-	if (!pack || !nr_objects)
-		return 0;
-
-	repo_config_get_ulong(the_repository, "pack.deltacachesize", &max_delta_cache_size);
-	repo_config_get_ulong(the_repository, "core.deltabasecachelimit", &delta_base_cache_limit);
-
-	/*
-	 * First we have to scan through at least one pack.
-	 * Assume enough room in OS file cache to keep the entire pack
-	 * or we may accidentally evict data of other processes from
-	 * the cache.
-	 */
-	os_cache = pack->pack_size + pack->index_size;
-	/* then pack-objects needs lots more for book keeping */
-	heap = sizeof(struct object_entry) * nr_objects;
-	/*
-	 * internal rev-list --all --objects takes up some memory too,
-	 * let's say half of it is for blobs
-	 */
-	heap += sizeof(struct blob) * nr_objects / 2;
-	/*
-	 * and the other half is for trees (commits and tags are
-	 * usually insignificant)
-	 */
-	heap += sizeof(struct tree) * nr_objects / 2;
-	/* and then obj_hash[], underestimated in fact */
-	heap += sizeof(struct object *) * nr_objects;
-	/* revindex is used also */
-	heap += (sizeof(off_t) + sizeof(uint32_t)) * nr_objects;
-	/*
-	 * read_sha1_file() (either at delta calculation phase, or
-	 * writing phase) also fills up the delta base cache
-	 */
-	heap += delta_base_cache_limit;
-	/* and of course pack-objects has its own delta cache */
-	heap += max_delta_cache_size;
-
-	return os_cache + heap;
-}
-
-static int keep_one_pack(struct string_list_item *item, void *data)
-{
-	struct strvec *args = data;
-	strvec_pushf(args, "--keep-pack=%s", basename(item->string));
-	return 0;
-}
-
-enum odb_optimize_strategy {
-	ODB_OPTIMIZE_INCREMENTAL,
-	ODB_OPTIMIZE_GEOMETRIC,
-};
-
-enum odb_optimize_flags {
-	/* Enable verbose logging and progress reporting. */
-	ODB_OPTIMIZE_VERBOSE = (1 << 0),
-
-	/* Perform auto-maintenance, only optimizing objects as required. */
-	ODB_OPTIMIZE_AUTO = (1 << 1),
-
-	/* Recompute existing deltas. */
-	ODB_OPTIMIZE_NO_REUSE_DELTAS = (1 << 2),
-};
-
-struct odb_optimize_options {
-	enum odb_optimize_strategy strategy;
-	enum odb_optimize_flags flags;
-	const char *prune_expire;
-	const char *expire_to;
-	int depth;
-	int window;
-
-	/* Backend-specific options. */
-	int keep_largest_pack;
-	int cruft_packs;
-	unsigned long max_cruft_size;
-};
-
 #define OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, aggressive) \
 	.prune_expire = (cfg)->prune_expire, \
 	.expire_to = (cfg)->repack_expire_to, \
@@ -633,133 +431,6 @@ struct odb_optimize_options {
 	.window = (aggressive) ? (cfg)->aggressive_window : 0, \
 	.depth = (aggressive) ? (cfg)->aggressive_depth : 0
 
-static void add_repack_all_option(const struct odb_optimize_options *opts,
-				  struct string_list *keep_pack,
-				  struct strvec *args)
-{
-	char *repack_filter = NULL;
-	char *repack_filter_to = NULL;
-
-	repo_config_get_string(the_repository, "gc.repackfilter", &repack_filter);
-	repo_config_get_string(the_repository, "gc.repackfilterto", &repack_filter_to);
-
-	if (opts->prune_expire && !strcmp(opts->prune_expire, "now") &&
-	    !(opts->cruft_packs && opts->expire_to))
-		strvec_push(args, "-a");
-	else if (opts->cruft_packs) {
-		strvec_push(args, "--cruft");
-		if (opts->prune_expire)
-			strvec_pushf(args, "--cruft-expiration=%s", opts->prune_expire);
-		if (opts->max_cruft_size)
-			strvec_pushf(args, "--max-cruft-size=%lu",
-				     opts->max_cruft_size);
-		if (opts->expire_to)
-			strvec_pushf(args, "--expire-to=%s", opts->expire_to);
-	} else {
-		strvec_push(args, "-A");
-		if (opts->prune_expire)
-			strvec_pushf(args, "--unpack-unreachable=%s", opts->prune_expire);
-	}
-
-	if (keep_pack)
-		for_each_string_list(keep_pack, keep_one_pack, args);
-
-	if (repack_filter && *repack_filter)
-		strvec_pushf(args, "--filter=%s", repack_filter);
-	if (repack_filter_to && *repack_filter_to)
-		strvec_pushf(args, "--filter-to=%s", repack_filter_to);
-
-	free(repack_filter);
-	free(repack_filter_to);
-}
-
-static void add_repack_incremental_option(struct strvec *args)
-{
-	strvec_push(args, "--no-write-bitmap-index");
-}
-
-static bool odb_optimize_required(struct object_database *odb,
-				  const struct odb_optimize_options *opts)
-{
-	struct odb_source_files *files = odb_source_files_downcast(odb->sources);
-
-	switch (opts->strategy) {
-	case ODB_OPTIMIZE_INCREMENTAL: {
-		int gc_auto_threshold = 6700;
-		int gc_auto_pack_limit = 50;
-
-		repo_config_get_int(odb->repo, "gc.auto", &gc_auto_threshold);
-		repo_config_get_int(odb->repo, "gc.autopacklimit", &gc_auto_pack_limit);
-
-		/*
-		 * Setting gc.auto to 0 or negative can disable the
-		 * automatic gc.
-		 */
-		if (gc_auto_threshold <= 0)
-			return false;
-		if (!too_many_packs(files, gc_auto_pack_limit) &&
-		    !too_many_loose_objects(files, gc_auto_threshold))
-			return false;
-
-		return true;
-	}
-	case ODB_OPTIMIZE_GEOMETRIC: {
-		struct pack_geometry geometry = {
-			.split_factor = 2,
-		};
-		struct pack_objects_args po_args = {
-			.local = 1,
-		};
-		struct existing_packs existing_packs = EXISTING_PACKS_INIT;
-		struct string_list kept_packs = STRING_LIST_INIT_DUP;
-		int auto_value = 100;
-		bool ret;
-
-		repo_config_get_int(odb->repo, "maintenance.geometric-repack.auto",
-				    &auto_value);
-		if (!auto_value)
-			return false;
-		if (auto_value < 0)
-			return true;
-
-		repo_config_get_int(odb->repo, "maintenance.geometric-repack.splitFactor",
-				    &geometry.split_factor);
-
-		existing_packs.repo = odb->repo;
-		existing_packs_collect(&existing_packs, &kept_packs);
-		pack_geometry_init(&geometry, &existing_packs, &po_args);
-		pack_geometry_split(&geometry);
-
-		/*
-		 * When we'd merge at least two packs with one another we always
-		 * perform the repack.
-		 */
-		if (geometry.split) {
-			ret = true;
-			goto out;
-		}
-
-		/*
-		 * Otherwise, we estimate the number of loose objects to determine
-		 * whether we want to create a new packfile or not.
-		 */
-		if (too_many_loose_objects(files, auto_value)) {
-			ret = true;
-			goto out;
-		}
-
-		ret = false;
-
-	out:
-		existing_packs_release(&existing_packs);
-		pack_geometry_release(&geometry);
-		return ret;
-	}
-	default:
-		BUG("unknown maintenance strategy '%d'", opts->strategy);
-	}
-}
-
 /* return NULL on success, else hostname running the gc */
 static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
 {
@@ -887,165 +558,6 @@ static int gc_foreground_tasks(struct maintenance_run_opts *opts,
 	return 0;
 }
 
-static int odb_optimize(struct object_database *odb,
-			const struct odb_optimize_options *opts)
-{
-	struct odb_source_files *files = odb_source_files_downcast(odb->sources);
-	struct child_process repack_cmd = CHILD_PROCESS_INIT;
-	unsigned long big_pack_threshold = 0;
-	int gc_auto_threshold = 6700;
-	int gc_auto_pack_limit = 50;
-	int ret;
-
-	repo_config_get_int(odb->repo, "gc.auto", &gc_auto_threshold);
-	repo_config_get_int(odb->repo, "gc.autopacklimit", &gc_auto_pack_limit);
-	repo_config_get_ulong(odb->repo, "gc.bigpackthreshold", &big_pack_threshold);
-
-	if (odb->repo->repository_format_precious_objects)
-		return 0;
-
-	repack_cmd.git_cmd = 1;
-	repack_cmd.odb_to_close = odb->repo->objects;
-
-	strvec_pushl(&repack_cmd.args, "repack", "-d", "-l", NULL);
-	if (opts->flags & ODB_OPTIMIZE_NO_REUSE_DELTAS)
-		strvec_push(&repack_cmd.args, "-f");
-	if (opts->depth > 0)
-		strvec_pushf(&repack_cmd.args, "--depth=%d", opts->depth);
-	if (opts->window > 0)
-		strvec_pushf(&repack_cmd.args, "--window=%d", opts->window);
-	if (!(opts->flags & ODB_OPTIMIZE_VERBOSE))
-		strvec_push(&repack_cmd.args, "-q");
-
-	/*
-	 * There's three cases we need to consider:
-	 *
-	 *   - If we're invoked without `--auto` we'll need to perform a full
-	 *     repack.
-	 *
-	 *   - If we're invoked with `--auto` and there's too many packs, then
-	 *     we perform a full repack, as well.
-	 *
-	 *   - Otherwise we perform an incremental repack.
-	 */
-	switch (opts->strategy) {
-	case ODB_OPTIMIZE_INCREMENTAL:
-		if (!(opts->flags & ODB_OPTIMIZE_AUTO)) {
-			struct string_list keep_pack = STRING_LIST_INIT_NODUP;
-
-			if (opts->keep_largest_pack != -1) {
-				if (opts->keep_largest_pack)
-					find_base_packs(files, &keep_pack, 0);
-			} else if (big_pack_threshold) {
-				find_base_packs(files, &keep_pack, big_pack_threshold);
-			}
-
-			add_repack_all_option(opts, &keep_pack, &repack_cmd.args);
-			string_list_clear(&keep_pack, 0);
-		} else {
-			if (too_many_packs(files, gc_auto_pack_limit)) {
-				struct string_list keep_pack = STRING_LIST_INIT_NODUP;
-
-				if (big_pack_threshold) {
-					find_base_packs(files, &keep_pack, big_pack_threshold);
-					if (keep_pack.nr >= (unsigned long) gc_auto_pack_limit) {
-						string_list_clear(&keep_pack, 0);
-						find_base_packs(files, &keep_pack, 0);
-					}
-				} else {
-					struct packed_git *p = find_base_packs(files, &keep_pack, 0);
-					uint64_t mem_have, mem_want;
-
-					mem_have = total_ram();
-					mem_want = estimate_repack_memory(files, p);
-
-					/*
-					 * Only allow 1/2 of memory for pack-objects, leave
-					 * the rest for the OS and other processes in the
-					 * system.
-					 */
-					if (!mem_have || mem_want < mem_have / 2)
-						string_list_clear(&keep_pack, 0);
-				}
-
-				add_repack_all_option(opts, &keep_pack, &repack_cmd.args);
-				string_list_clear(&keep_pack, 0);
-			} else {
-				add_repack_incremental_option(&repack_cmd.args);
-			}
-		}
-
-		break;
-	case ODB_OPTIMIZE_GEOMETRIC: {
-		struct pack_geometry geometry = {
-			.split_factor = 2,
-		};
-		struct pack_objects_args po_args = {
-			.local = 1,
-		};
-		struct existing_packs existing_packs = EXISTING_PACKS_INIT;
-		struct string_list kept_packs = STRING_LIST_INIT_DUP;
-
-		repo_config_get_int(odb->repo, "maintenance.geometric-repack.splitFactor",
-				    &geometry.split_factor);
-
-		existing_packs.repo = odb->repo;
-		existing_packs_collect(&existing_packs, &kept_packs);
-		pack_geometry_init(&geometry, &existing_packs, &po_args);
-		pack_geometry_split(&geometry);
-
-		if (geometry.split < geometry.pack_nr) {
-			strvec_pushf(&repack_cmd.args, "--geometric=%d",
-				     geometry.split_factor);
-		} else {
-			add_repack_all_option(opts, NULL, &repack_cmd.args);
-		}
-		if (odb->repo->settings.core_multi_pack_index)
-			strvec_push(&repack_cmd.args, "--write-midx");
-
-		existing_packs_release(&existing_packs);
-		pack_geometry_release(&geometry);
-		break;
-	}
-	default:
-		die("unknown maintenance strategy '%d'", opts->strategy);
-	}
-
-	if (run_command(&repack_cmd)) {
-		ret = error(FAILED_RUN, repack_cmd.args.v[0]);
-		goto out;
-	}
-
-	/* Geometric repacking uses cruft packs, so we don't have to prune separately. */
-	if (opts->strategy != ODB_OPTIMIZE_GEOMETRIC && opts->prune_expire) {
-		struct child_process prune_cmd = CHILD_PROCESS_INIT;
-
-		strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL);
-		/* run `git prune` even if using cruft packs */
-		strvec_push(&prune_cmd.args, opts->prune_expire);
-		if (!(opts->flags & ODB_OPTIMIZE_VERBOSE))
-			strvec_push(&prune_cmd.args, "--no-progress");
-		if (repo_has_promisor_remote(odb->repo))
-			strvec_push(&prune_cmd.args,
-				    "--exclude-promisor-objects");
-		prune_cmd.git_cmd = 1;
-
-		if (run_command(&prune_cmd)) {
-			ret = error(FAILED_RUN, prune_cmd.args.v[0]);
-			goto out;
-		}
-	}
-
-	if (opts->flags & ODB_OPTIMIZE_AUTO && too_many_loose_objects(files, gc_auto_threshold))
-		warning(_("There are too many unreachable loose objects; "
-			"run 'git prune' to remove them."));
-
-	ret = 0;
-
-out:
-	return ret;
-}
-
 static int maintenance_task_odb(struct maintenance_run_opts *opts,
 				struct gc_config *cfg,
 				int keep_largest_pack,
diff --git a/odb.c b/odb.c
index 7d555be09f..89660981fe 100644
--- a/odb.c
+++ b/odb.c
@@ -1003,6 +1003,18 @@ int odb_write_object_stream(struct object_database *odb,
 	return odb_source_write_object_stream(odb->sources, stream, len, oid);
 }
 
+int odb_optimize(struct object_database *odb,
+		 const struct odb_optimize_options *opts)
+{
+	return odb_source_optimize(odb->sources, opts);
+}
+
+bool odb_optimize_required(struct object_database *odb,
+			   const struct odb_optimize_options *opts)
+{
+	return odb_source_optimize_required(odb->sources, opts);
+}
+
 struct object_database *odb_new(struct repository *repo,
 				const char *primary_source,
 				const char *secondary_sources)
diff --git a/odb.h b/odb.h
index 3834a0dcbf..7e1c85c22e 100644
--- a/odb.h
+++ b/odb.h
@@ -117,6 +117,51 @@ struct object_database *odb_new(struct repository *repo,
 /* Free the object database and release all resources. */
 void odb_free(struct object_database *o);
 
+enum odb_optimize_strategy {
+	ODB_OPTIMIZE_INCREMENTAL,
+	ODB_OPTIMIZE_GEOMETRIC,
+};
+
+enum odb_optimize_flags {
+	/* Enable verbose logging and progress reporting. */
+	ODB_OPTIMIZE_VERBOSE = (1 << 0),
+
+	/* Perform auto-maintenance, only optimizing objects as required. */
+	ODB_OPTIMIZE_AUTO = (1 << 1),
+
+	/* Recompute existing deltas. */
+	ODB_OPTIMIZE_NO_REUSE_DELTAS = (1 << 2),
+};
+
+struct odb_optimize_options {
+	enum odb_optimize_strategy strategy;
+	enum odb_optimize_flags flags;
+	const char *prune_expire;
+	const char *expire_to;
+	int depth;
+	int window;
+
+	/* Backend-specific options. */
+	int keep_largest_pack;
+	int cruft_packs;
+	unsigned long max_cruft_size;
+};
+
+/*
+ * Optimize the object database. Returns 0 on success, a negative error code
+ * otherwise.
+ */
+int odb_optimize(struct object_database *odb,
+		 const struct odb_optimize_options *opts);
+
+/*
+ * Check whether optimization of the object database is required given the
+ * provided options. Returns true if optimization should be performed, false
+ * otherwise.
+ */
+bool odb_optimize_required(struct object_database *odb,
+			   const struct odb_optimize_options *opts);
+
 /*
  * Close the object database and all of its sources so that any held resources
  * will be released. The database can still be used after closing it, in which
diff --git a/odb/source-files.c b/odb/source-files.c
index bbd1784b33..82cf61da4a 100644
--- a/odb/source-files.c
+++ b/odb/source-files.c
@@ -1,6 +1,8 @@
 #include "git-compat-util.h"
 #include "abspath.h"
+#include "blob.h"
 #include "chdir-notify.h"
+#include "config.h"
 #include "gettext.h"
 #include "lockfile.h"
 #include "object-file.h"
@@ -8,8 +10,16 @@
 #include "odb/source.h"
 #include "odb/source-files.h"
 #include "odb/source-loose.h"
+#include "pack-objects.h"
 #include "packfile.h"
+#include "path.h"
+#include "promisor-remote.h"
+#include "repack.h"
+#include "run-command.h"
 #include "strbuf.h"
+#include "string-list.h"
+#include "strvec.h"
+#include "tree.h"
 #include "write-or-die.h"
 
 static void odb_source_files_reparent(const char *name UNUSED,
@@ -260,6 +270,464 @@ static int odb_source_files_write_alternate(struct odb_source *source,
 	return ret;
 }
 
+static int too_many_loose_objects(struct odb_source_files *files, int limit)
+{
+	unsigned long loose_count;
+
+	if (limit <= 0)
+		return 0;
+
+	if (odb_source_count_objects(&files->loose->base, ODB_COUNT_OBJECTS_APPROXIMATE,
+				     &loose_count) < 0)
+		return 0;
+
+	/*
+	 * This is weird, but stems from legacy behaviour: the GC auto
+	 * threshold was always essentially interpreted as if it was rounded up
+	 * to the next multiple 256 of, so we retain this behaviour for now.
+	 */
+	return loose_count > (DIV_ROUND_UP(((unsigned long) limit), 256) * 256);
+}
+
+static struct packed_git *find_base_packs(struct odb_source_files *files,
+					  struct string_list *packs,
+					  unsigned long limit)
+{
+	struct packfile_list_entry *e;
+	struct packed_git *base = NULL;
+
+	for (e = packfile_store_get_packs(files->packed); e; e = e->next) {
+		if (e->pack->is_cruft)
+			continue;
+		if (limit) {
+			if ((uintmax_t) e->pack->pack_size >= limit)
+				string_list_append(packs, e->pack->pack_name);
+		} else if (!base || base->pack_size < e->pack->pack_size) {
+			base = e->pack;
+		}
+	}
+
+	if (base)
+		string_list_append(packs, base->pack_name);
+
+	return base;
+}
+
+static int too_many_packs(struct odb_source_files *files, int gc_auto_pack_limit)
+{
+	struct packfile_list_entry *e;
+	int cnt = 0;
+
+	if (gc_auto_pack_limit <= 0)
+		return 0;
+
+	for (e = packfile_store_get_packs(files->packed); e; e = e->next) {
+		if (e->pack->pack_keep)
+			continue;
+		/*
+		 * Perhaps check the size of the pack and count only
+		 * very small ones here?
+		 */
+		cnt++;
+	}
+	return gc_auto_pack_limit < cnt;
+}
+
+static uint64_t total_ram(void)
+{
+#if defined(HAVE_SYSINFO)
+	struct sysinfo si;
+
+	if (!sysinfo(&si)) {
+		uint64_t total = si.totalram;
+
+		if (si.mem_unit > 1)
+			total *= (uint64_t)si.mem_unit;
+		return total;
+	}
+#elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM) || defined(HW_PHYSMEM64))
+	uint64_t physical_memory;
+	int mib[2];
+	size_t length;
+
+	mib[0] = CTL_HW;
+# if defined(HW_MEMSIZE)
+	mib[1] = HW_MEMSIZE;
+# elif defined(HW_PHYSMEM64)
+	mib[1] = HW_PHYSMEM64;
+# else
+	mib[1] = HW_PHYSMEM;
+# endif
+	length = sizeof(physical_memory);
+	if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0)) {
+		if (length == 4) {
+			uint32_t mem;
+
+			if (!sysctl(mib, 2, &mem, &length, NULL, 0))
+				physical_memory = mem;
+		}
+		return physical_memory;
+	}
+#elif defined(GIT_WINDOWS_NATIVE)
+	MEMORYSTATUSEX memInfo;
+
+	memInfo.dwLength = sizeof(MEMORYSTATUSEX);
+	if (GlobalMemoryStatusEx(&memInfo))
+		return memInfo.ullTotalPhys;
+#endif
+	return 0;
+}
+
+static uint64_t estimate_repack_memory(struct odb_source_files *files,
+				       struct packed_git *pack)
+{
+	unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
+	unsigned long delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT;
+	unsigned long nr_objects;
+	size_t os_cache, heap;
+
+	if (odb_source_count_objects(&files->base, ODB_COUNT_OBJECTS_APPROXIMATE,
+				     &nr_objects) < 0)
+		return 0;
+
+	if (!pack || !nr_objects)
+		return 0;
+
+	repo_config_get_ulong(files->base.odb->repo, "pack.deltacachesize",
+			      &max_delta_cache_size);
+	repo_config_get_ulong(files->base.odb->repo, "core.deltabasecachelimit",
+			      &delta_base_cache_limit);
+
+	/*
+	 * First we have to scan through at least one pack.
+	 * Assume enough room in OS file cache to keep the entire pack
+	 * or we may accidentally evict data of other processes from
+	 * the cache.
+	 */
+	os_cache = pack->pack_size + pack->index_size;
+	/* then pack-objects needs lots more for book keeping */
+	heap = sizeof(struct object_entry) * nr_objects;
+	/*
+	 * internal rev-list --all --objects takes up some memory too,
+	 * let's say half of it is for blobs
+	 */
+	heap += sizeof(struct blob) * nr_objects / 2;
+	/*
+	 * and the other half is for trees (commits and tags are
+	 * usually insignificant)
+	 */
+	heap += sizeof(struct tree) * nr_objects / 2;
+	/* and then obj_hash[], underestimated in fact */
+	heap += sizeof(struct object *) * nr_objects;
+	/* revindex is used also */
+	heap += (sizeof(off_t) + sizeof(uint32_t)) * nr_objects;
+	/*
+	 * read_sha1_file() (either at delta calculation phase, or
+	 * writing phase) also fills up the delta base cache
+	 */
+	heap += delta_base_cache_limit;
+	/* and of course pack-objects has its own delta cache */
+	heap += max_delta_cache_size;
+
+	return os_cache + heap;
+}
+
+static int keep_one_pack(struct string_list_item *item, void *data)
+{
+	struct strvec *args = data;
+	strvec_pushf(args, "--keep-pack=%s", basename(item->string));
+	return 0;
+}
+
+static void add_repack_all_option(struct repository *repo,
+				  const struct odb_optimize_options *opts,
+				  struct string_list *keep_pack,
+				  struct strvec *args)
+{
+	char *repack_filter = NULL;
+	char *repack_filter_to = NULL;
+
+	repo_config_get_string(repo, "gc.repackfilter", &repack_filter);
+	repo_config_get_string(repo, "gc.repackfilterto", &repack_filter_to);
+
+	if (opts->prune_expire && !strcmp(opts->prune_expire, "now") &&
+	    !(opts->cruft_packs && opts->expire_to))
+		strvec_push(args, "-a");
+	else if (opts->cruft_packs) {
+		strvec_push(args, "--cruft");
+		if (opts->prune_expire)
+			strvec_pushf(args, "--cruft-expiration=%s", opts->prune_expire);
+		if (opts->max_cruft_size)
+			strvec_pushf(args, "--max-cruft-size=%lu",
+				     opts->max_cruft_size);
+		if (opts->expire_to)
+			strvec_pushf(args, "--expire-to=%s", opts->expire_to);
+	} else {
+		strvec_push(args, "-A");
+		if (opts->prune_expire)
+			strvec_pushf(args, "--unpack-unreachable=%s", opts->prune_expire);
+	}
+
+	if (keep_pack)
+		for_each_string_list(keep_pack, keep_one_pack, args);
+
+	if (repack_filter && *repack_filter)
+		strvec_pushf(args, "--filter=%s", repack_filter);
+	if (repack_filter_to && *repack_filter_to)
+		strvec_pushf(args, "--filter-to=%s", repack_filter_to);
+
+	free(repack_filter);
+	free(repack_filter_to);
+}
+
+static void add_repack_incremental_option(struct strvec *args)
+{
+	strvec_push(args, "--no-write-bitmap-index");
+}
+
+bool odb_source_files_optimize_required(struct odb_source *source,
+					const struct odb_optimize_options *opts)
+{
+	struct odb_source_files *files = odb_source_files_downcast(source);
+	struct repository *repo = source->odb->repo;
+
+	switch (opts->strategy) {
+	case ODB_OPTIMIZE_INCREMENTAL: {
+		int gc_auto_threshold = 6700;
+		int gc_auto_pack_limit = 50;
+
+		repo_config_get_int(repo, "gc.auto", &gc_auto_threshold);
+		repo_config_get_int(repo, "gc.autopacklimit", &gc_auto_pack_limit);
+
+		/*
+		 * Setting gc.auto to 0 or negative can disable the
+		 * automatic gc.
+		 */
+		if (gc_auto_threshold <= 0)
+			return false;
+		if (!too_many_packs(files, gc_auto_pack_limit) &&
+		    !too_many_loose_objects(files, gc_auto_threshold))
+			return false;
+
+		return true;
+	}
+	case ODB_OPTIMIZE_GEOMETRIC: {
+		struct pack_geometry geometry = {
+			.split_factor = 2,
+		};
+		struct pack_objects_args po_args = {
+			.local = 1,
+		};
+		struct existing_packs existing_packs = EXISTING_PACKS_INIT;
+		struct string_list kept_packs = STRING_LIST_INIT_DUP;
+		int auto_value = 100;
+		bool ret;
+
+		repo_config_get_int(repo, "maintenance.geometric-repack.auto",
+				    &auto_value);
+		if (!auto_value)
+			return false;
+		if (auto_value < 0)
+			return true;
+
+		repo_config_get_int(repo, "maintenance.geometric-repack.splitFactor",
+				    &geometry.split_factor);
+
+		existing_packs.repo = repo;
+		existing_packs_collect(&existing_packs, &kept_packs);
+		pack_geometry_init(&geometry, &existing_packs, &po_args);
+		pack_geometry_split(&geometry);
+
+		/*
+		 * When we'd merge at least two packs with one another we always
+		 * perform the repack.
+		 */
+		if (geometry.split) {
+			ret = true;
+			goto out;
+		}
+
+		/*
+		 * Otherwise, we estimate the number of loose objects to determine
+		 * whether we want to create a new packfile or not.
+		 */
+		if (too_many_loose_objects(files, auto_value)) {
+			ret = true;
+			goto out;
+		}
+
+		ret = false;
+
+	out:
+		existing_packs_release(&existing_packs);
+		pack_geometry_release(&geometry);
+		return ret;
+	}
+	default:
+		BUG("unknown maintenance strategy '%d'", opts->strategy);
+	}
+}
+
+int odb_source_files_optimize(struct odb_source *source,
+			      const struct odb_optimize_options *opts)
+{
+	struct odb_source_files *files = odb_source_files_downcast(source);
+	struct repository *repo = source->odb->repo;
+	struct child_process repack_cmd = CHILD_PROCESS_INIT;
+	unsigned long big_pack_threshold = 0;
+	int gc_auto_threshold = 6700;
+	int gc_auto_pack_limit = 50;
+	int ret;
+
+	repo_config_get_int(repo, "gc.auto", &gc_auto_threshold);
+	repo_config_get_int(repo, "gc.autopacklimit", &gc_auto_pack_limit);
+	repo_config_get_ulong(repo, "gc.bigpackthreshold", &big_pack_threshold);
+
+	if (repo->repository_format_precious_objects)
+		return 0;
+
+	repack_cmd.git_cmd = 1;
+	repack_cmd.odb_to_close = repo->objects;
+
+	strvec_pushl(&repack_cmd.args, "repack", "-d", "-l", NULL);
+	if (opts->flags & ODB_OPTIMIZE_NO_REUSE_DELTAS)
+		strvec_push(&repack_cmd.args, "-f");
+	if (opts->depth > 0)
+		strvec_pushf(&repack_cmd.args, "--depth=%d", opts->depth);
+	if (opts->window > 0)
+		strvec_pushf(&repack_cmd.args, "--window=%d", opts->window);
+	if (!(opts->flags & ODB_OPTIMIZE_VERBOSE))
+		strvec_push(&repack_cmd.args, "-q");
+
+	/*
+	 * There's three cases we need to consider:
+	 *
+	 *   - If we're invoked without `--auto` we'll need to perform a full
+	 *     repack.
+	 *
+	 *   - If we're invoked with `--auto` and there's too many packs, then
+	 *     we perform a full repack, as well.
+	 *
+	 *   - Otherwise we perform an incremental repack.
+	 */
+	switch (opts->strategy) {
+	case ODB_OPTIMIZE_INCREMENTAL:
+		if (!(opts->flags & ODB_OPTIMIZE_AUTO)) {
+			struct string_list keep_pack = STRING_LIST_INIT_NODUP;
+
+			if (opts->keep_largest_pack != -1) {
+				if (opts->keep_largest_pack)
+					find_base_packs(files, &keep_pack, 0);
+			} else if (big_pack_threshold) {
+				find_base_packs(files, &keep_pack, big_pack_threshold);
+			}
+
+			add_repack_all_option(repo, opts, &keep_pack, &repack_cmd.args);
+			string_list_clear(&keep_pack, 0);
+		} else {
+			if (too_many_packs(files, gc_auto_pack_limit)) {
+				struct string_list keep_pack = STRING_LIST_INIT_NODUP;
+
+				if (big_pack_threshold) {
+					find_base_packs(files, &keep_pack, big_pack_threshold);
+					if (keep_pack.nr >= (unsigned long) gc_auto_pack_limit) {
+						string_list_clear(&keep_pack, 0);
+						find_base_packs(files, &keep_pack, 0);
+					}
+				} else {
+					struct packed_git *p = find_base_packs(files, &keep_pack, 0);
+					uint64_t mem_have, mem_want;
+
+					mem_have = total_ram();
+					mem_want = estimate_repack_memory(files, p);
+
+					/*
+					 * Only allow 1/2 of memory for pack-objects, leave
+					 * the rest for the OS and other processes in the
+					 * system.
+					 */
+					if (!mem_have || mem_want < mem_have / 2)
+						string_list_clear(&keep_pack, 0);
+				}
+
+				add_repack_all_option(repo, opts, &keep_pack, &repack_cmd.args);
+				string_list_clear(&keep_pack, 0);
+			} else {
+				add_repack_incremental_option(&repack_cmd.args);
+			}
+		}
+
+		break;
+	case ODB_OPTIMIZE_GEOMETRIC: {
+		struct pack_geometry geometry = {
+			.split_factor = 2,
+		};
+		struct pack_objects_args po_args = {
+			.local = 1,
+		};
+		struct existing_packs existing_packs = EXISTING_PACKS_INIT;
+		struct string_list kept_packs = STRING_LIST_INIT_DUP;
+
+		repo_config_get_int(repo, "maintenance.geometric-repack.splitFactor",
+				    &geometry.split_factor);
+
+		existing_packs.repo = repo;
+		existing_packs_collect(&existing_packs, &kept_packs);
+		pack_geometry_init(&geometry, &existing_packs, &po_args);
+		pack_geometry_split(&geometry);
+
+		if (geometry.split < geometry.pack_nr) {
+			strvec_pushf(&repack_cmd.args, "--geometric=%d",
+				     geometry.split_factor);
+		} else {
+			add_repack_all_option(repo, opts, NULL, &repack_cmd.args);
+		}
+		if (repo->settings.core_multi_pack_index)
+			strvec_push(&repack_cmd.args, "--write-midx");
+
+		existing_packs_release(&existing_packs);
+		pack_geometry_release(&geometry);
+		break;
+	}
+	default:
+		die("unknown maintenance strategy '%d'", opts->strategy);
+	}
+
+	if (run_command(&repack_cmd)) {
+		ret = error("failed to run %s", repack_cmd.args.v[0]);
+		goto out;
+	}
+
+	/* Geometric repacking uses cruft packs, so we don't have to prune separately. */
+	if (opts->strategy != ODB_OPTIMIZE_GEOMETRIC && opts->prune_expire) {
+		struct child_process prune_cmd = CHILD_PROCESS_INIT;
+
+		strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL);
+		/* run `git prune` even if using cruft packs */
+		strvec_push(&prune_cmd.args, opts->prune_expire);
+		if (!(opts->flags & ODB_OPTIMIZE_VERBOSE))
+			strvec_push(&prune_cmd.args, "--no-progress");
+		if (repo_has_promisor_remote(repo))
+			strvec_push(&prune_cmd.args,
+				    "--exclude-promisor-objects");
+		prune_cmd.git_cmd = 1;
+
+		if (run_command(&prune_cmd)) {
+			ret = error("failed to run %s", prune_cmd.args.v[0]);
+			goto out;
+		}
+	}
+
+	if (opts->flags & ODB_OPTIMIZE_AUTO && too_many_loose_objects(files, gc_auto_threshold))
+		warning(_("There are too many unreachable loose objects; "
+			"run 'git prune' to remove them."));
+
+	ret = 0;
+
+out:
+	return ret;
+}
+
 struct odb_source_files *odb_source_files_new(struct object_database *odb,
 					      const char *path,
 					      bool local)
@@ -285,6 +753,8 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
 	files->base.begin_transaction = odb_source_files_begin_transaction;
 	files->base.read_alternates = odb_source_files_read_alternates;
 	files->base.write_alternate = odb_source_files_write_alternate;
+	files->base.optimize = odb_source_files_optimize;
+	files->base.optimize_required = odb_source_files_optimize_required;
 
 	/*
 	 * Ideally, we would only ever store absolute paths in the source. This
diff --git a/odb/source-files.h b/odb/source-files.h
index d7ac3c1c81..044242bc36 100644
--- a/odb/source-files.h
+++ b/odb/source-files.h
@@ -21,6 +21,21 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
 					      const char *path,
 					      bool local);
 
+/*
+ * Optimize the files object database source by repacking loose objects and
+ * packfiles as needed. Returns 0 on success, a negative error code otherwise.
+ */
+int odb_source_files_optimize(struct odb_source *source,
+			      const struct odb_optimize_options *opts);
+
+/*
+ * Check whether optimization of the files object database source is required
+ * given the provided options. Returns true if optimization should be
+ * performed, false otherwise.
+ */
+bool odb_source_files_optimize_required(struct odb_source *source,
+					const struct odb_optimize_options *opts);
+
 /*
  * Cast the given object database source to the files backend. This will cause
  * a BUG in case the source doesn't use this backend.
diff --git a/odb/source.h b/odb/source.h
index 8767708c9c..88a48ba3c3 100644
--- a/odb/source.h
+++ b/odb/source.h
@@ -258,6 +258,21 @@ struct odb_source {
 	 */
 	int (*write_alternate)(struct odb_source *source,
 			       const char *alternate);
+
+	/*
+	 * This callback is expected to optimize the object database source.
+	 * Returns 0 on success, a negative error code otherwise.
+	 */
+	int (*optimize)(struct odb_source *source,
+			const struct odb_optimize_options *opts);
+
+	/*
+	 * This callback is expected to check whether optimization of the
+	 * object database source is required given the provided options.
+	 * Returns true if optimization should be performed, false otherwise.
+	 */
+	bool (*optimize_required)(struct odb_source *source,
+				  const struct odb_optimize_options *opts);
 };
 
 /*
@@ -475,4 +490,25 @@ static inline int odb_source_begin_transaction(struct odb_source *source,
 	return source->begin_transaction(source, out);
 }
 
+/*
+ * Optimize the object database source. Returns 0 on success, a negative error
+ * code otherwise.
+ */
+static inline int odb_source_optimize(struct odb_source *source,
+				      const struct odb_optimize_options *opts)
+{
+	return source->optimize(source, opts);
+}
+
+/*
+ * Check whether optimization of the object database source is required given
+ * the provided options. Returns true if optimization should be performed,
+ * false otherwise.
+ */
+static inline bool odb_source_optimize_required(struct odb_source *source,
+						const struct odb_optimize_options *opts)
+{
+	return source->optimize_required(source, opts);
+}
+
 #endif

-- 
2.55.0.313.g8d093f411d.dirty


^ permalink raw reply related

* Re: [PATCH 2/2] commit-graph: propagate topo_levels slab to all chain layers
From: Patrick Steinhardt @ 2026-07-13  6:16 UTC (permalink / raw)
  To: Taylor Blau
  Cc: Kristofer Karlsson, ', Taylor Blau,
	Kristofer Karlsson via GitGitGadget, git
In-Reply-To: <alFuxPQQcFxseAzh@com-79390>

On Fri, Jul 10, 2026 at 03:14:28PM -0700, Taylor Blau wrote:
> On Tue, Jul 07, 2026 at 04:57:13PM +0200, Kristofer Karlsson wrote:
> > (b) Move topo_levels to struct object_database. Since
> > fill_commit_graph_info() can already reach the odb via
> > g->odb_source->odb, no signature changes are needed.
> > The write side becomes a single assignment:
> >
> >     ctx.r->objects->topo_levels = &topo_levels;
> >
> > and cleanup becomes:
> >
> >     ctx.r->objects->topo_levels = NULL;
> >
> > No chain walk needed and the diff is fairly small.
> > I am not sure about the semantics of it though -- should the odb
> > have a reference to topo_levels?
> 
> This seems to be the most promising approach, though I'd be curious what
> Patrick's thoughts are. The commit-slab API is really a property of the
> object database, but we treat these as a global as I do not recall them
> yet being touched by the ODB refactoring effort.

I was investigating several times whether we can remove them from global
scope and move them into the object database indeed. The answer is that
it's somewhat complicated because we reuse the slab for multiple
different things, and detangling that has proven to be a bit of a mess.

The other question here is whether commit graphs really are a property
of the object database itself, or whether they are rather a property of
a given backend. Sure, we can only have a single commit graph at any
point in time, so they feel like they are at the object database level.
But is the current implementation of a commit graph really the best for
all potential backends out there?

If you take for example a distributed backend to store objects, then you
probably don't want to have a single local commit graph that is stored
in ".git/objects/info". Furthermore, the current format may not even be
the best one to store the cached information, either.

So ultimately, I can see one of two approaches:
 
  - Either we make the commit graph itself pluggable as a standalone
    mechanism, too.

  - Or we treat it as a property of the object backend.

I haven't fully made up my mind yet. But I guess detangling the current
mess that we have with the commit graphs would help regardless of which
direction we eventually go into.

Thanks!

Patrick

^ permalink raw reply

* Re: What's cooking in git.git (Jul 2026, #05)
From: Michael Montalbo @ 2026-07-13  6:27 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <xmqqik6j1m7u.fsf@gitster.g>

On Sun, Jul 12, 2026 at 10:40 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> * mm/diff-process-hunks (2026-06-14) 6 commits
>  - blame: consult diff process for no-hunk detection
>  - diff: bypass diff process with --no-ext-diff and in format-patch
>  - diff: add long-running diff process via diff.<driver>.process
>  - sub-process: separate process lifecycle from hashmap management
>  - userdiff: add diff.<driver>.process config
>  - xdiff: support external hunks via xpparam_t
>
>  A new 'diff.<driver>.process' configuration has been introduced to
>  allow a long-running external process to act as a hunk provider,
>  allowing external tools to control which lines Git considers changed
>  while leaving all output formatting (word diff, color, blame, etc.) to
>  Git's standard pipeline.
>
>  Expecting a reroll for too long, stalled.
>  cf. <CAC2Qwm+P=fZOtpfMPeMiSXf3Afk6OLYpTP8Br78_PRA8WNL1Wg@mail.gmail.com>
>  source: <pull.2120.v4.git.1781463564.gitgitgadget@gmail.com>
>

Apologies for the delayed update. I will have a reroll ready for this topic this
week.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox