git/Documentation/git-repack.txt
Taylor Blau 37dc6d8104 builtin/repack.c: implement support for --max-cruft-size
Cruft packs are an alternative mechanism for storing a collection of
unreachable objects whose mtimes are recent enough to avoid being
pruned out of the repository.

When cruft packs were first introduced back in b757353676
(builtin/pack-objects.c: --cruft without expiration, 2022-05-20) and
a7d493833f (builtin/pack-objects.c: --cruft with expiration,
2022-05-20), the recommended workflow consisted of:

  - Repacking periodically, either by packing anything loose in the
    repository (via `git repack -d`) or producing a geometric sequence
    of packs (via `git repack --geometric=<d> -d`).

  - Every so often, splitting the repository into two packs, one cruft
    to store the unreachable objects, and another non-cruft pack to
    store the reachable objects.

Repositories may (out of band with the above) choose periodically to
prune out some unreachable objects which have aged out of the grace
period by generating a pack with `--cruft-expiration=<approxidate>`.

This allowed repositories to maintain relatively few packs on average,
and quarantine unreachable objects together in a cruft pack, avoiding
the pitfalls of holding unreachable objects as loose while they age out
(for more, see some of the details in 3d89a8c118
(Documentation/technical: add cruft-packs.txt, 2022-05-20)).

This all works, but can be costly from an I/O-perspective when
frequently repacking a repository that has many unreachable objects.
This problem is exacerbated when those unreachable objects are rarely
(if every) pruned.

Since there is at most one cruft pack in the above scheme, each time we
update the cruft pack it must be rewritten from scratch. Because much of
the pack is reused, this is a relatively inexpensive operation from a
CPU-perspective, but is very costly in terms of I/O since we end up
rewriting basically the same pack (plus any new unreachable objects that
have entered the repository since the last time a cruft pack was
generated).

At the time, we decided against implementing more robust support for
multiple cruft packs. This patch implements that support which we were
lacking.

Introduce a new option `--max-cruft-size` which allows repositories to
accumulate cruft packs up to a given size, after which point a new
generation of cruft packs can accumulate until it reaches the maximum
size, and so on. To generate a new cruft pack, the process works like
so:

  - Sort a list of any existing cruft packs in ascending order of pack
    size.

  - Starting from the beginning of the list, group cruft packs together
    while the accumulated size is smaller than the maximum specified
    pack size.

  - Combine the objects in these cruft packs together into a new cruft
    pack, along with any other unreachable objects which have since
    entered the repository.

Once a cruft pack grows beyond the size specified via `--max-cruft-size`
the pack is effectively frozen. This limits the I/O churn up to a
quadratic function of the value specified by the `--max-cruft-size`
option, instead of behaving quadratically in the number of total
unreachable objects.

When pruning unreachable objects, we bypass the new code paths which
combine small cruft packs together, and instead start from scratch,
passing in the appropriate `--max-pack-size` down to `pack-objects`,
putting it in charge of keeping the resulting set of cruft packs sized
correctly.

This may seem like further I/O churn, but in practice it isn't so bad.
We could prune old cruft packs for whom all or most objects are removed,
and then generate a new cruft pack with just the remaining set of
objects. But this additional complexity buys us relatively little,
because most objects end up being pruned anyway, so the I/O churn is
well contained.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-10-05 13:26:11 -07:00

260 lines
9.8 KiB
Plaintext

git-repack(1)
=============
NAME
----
git-repack - Pack unpacked objects in a repository
SYNOPSIS
--------
[verse]
'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m] [--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>] [--write-midx]
DESCRIPTION
-----------
This command is used to combine all objects that do not currently
reside in a "pack", into a pack. It can also be used to re-organize
existing packs into a single, more efficient pack.
A pack is a collection of objects, individually compressed, with
delta compression applied, stored in a single file, with an
associated index file.
Packs are used to reduce the load on mirror systems, backup
engines, disk storage, etc.
OPTIONS
-------
-a::
Instead of incrementally packing the unpacked objects,
pack everything referenced into a single pack.
Especially useful when packing a repository that is used
for private development. Use
with `-d`. This will clean up the objects that `git prune`
leaves behind, but `git fsck --full --dangling` shows as
dangling.
+
Note that users fetching over dumb protocols will have to fetch the
whole new pack in order to get any contained object, no matter how many
other objects in that pack they already have locally.
+
Promisor packfiles are repacked separately: if there are packfiles that
have an associated ".promisor" file, these packfiles will be repacked
into another separate pack, and an empty ".promisor" file corresponding
to the new separate pack will be written.
-A::
Same as `-a`, unless `-d` is used. Then any unreachable
objects in a previous pack become loose, unpacked objects,
instead of being left in the old pack. Unreachable objects
are never intentionally added to a pack, even when repacking.
This option prevents unreachable objects from being immediately
deleted by way of being left in the old pack and then
removed. Instead, the loose unreachable objects
will be pruned according to normal expiry rules
with the next 'git gc' invocation. See linkgit:git-gc[1].
-d::
After packing, if the newly created packs make some
existing packs redundant, remove the redundant packs.
Also run 'git prune-packed' to remove redundant
loose object files.
--cruft::
Same as `-a`, unless `-d` is used. Then any unreachable objects
are packed into a separate cruft pack. Unreachable objects can
be pruned using the normal expiry rules with the next `git gc`
invocation (see linkgit:git-gc[1]). Incompatible with `-k`.
--cruft-expiration=<approxidate>::
Expire unreachable objects older than `<approxidate>`
immediately instead of waiting for the next `git gc` invocation.
Only useful with `--cruft -d`.
--max-cruft-size=<n>::
Repack cruft objects into packs as large as `<n>` bytes before
creating new packs. As long as there are enough cruft packs
smaller than `<n>`, repacking will cause a new cruft pack to
be created containing objects from any combined cruft packs,
along with any new unreachable objects. Cruft packs larger than
`<n>` will not be modified. When the new cruft pack is larger
than `<n>` bytes, it will be split into multiple packs, all of
which are guaranteed to be at most `<n>` bytes in size. Only
useful with `--cruft -d`.
--expire-to=<dir>::
Write a cruft pack containing pruned objects (if any) to the
directory `<dir>`. This option is useful for keeping a copy of
any pruned objects in a separate directory as a backup. Only
useful with `--cruft -d`.
-l::
Pass the `--local` option to 'git pack-objects'. See
linkgit:git-pack-objects[1].
-f::
Pass the `--no-reuse-delta` option to `git-pack-objects`, see
linkgit:git-pack-objects[1].
-F::
Pass the `--no-reuse-object` option to `git-pack-objects`, see
linkgit:git-pack-objects[1].
-q::
--quiet::
Show no progress over the standard error stream and pass the `-q`
option to 'git pack-objects'. See linkgit:git-pack-objects[1].
-n::
Do not update the server information with
'git update-server-info'. This option skips
updating local catalog files needed to publish
this repository (or a direct copy of it)
over HTTP or FTP. See linkgit:git-update-server-info[1].
--window=<n>::
--depth=<n>::
These two options affect how the objects contained in the pack are
stored using delta compression. The objects are first internally
sorted by type, size and optionally names and compared against the
other objects within `--window` to see if using delta compression saves
space. `--depth` limits the maximum delta depth; making it too deep
affects the performance on the unpacker side, because delta data needs
to be applied that many times to get to the necessary object.
+
The default value for --window is 10 and --depth is 50. The maximum
depth is 4095.
--threads=<n>::
This option is passed through to `git pack-objects`.
--window-memory=<n>::
This option provides an additional limit on top of `--window`;
the window size will dynamically scale down so as to not take
up more than '<n>' bytes in memory. This is useful in
repositories with a mix of large and small objects to not run
out of memory with a large window, but still be able to take
advantage of the large window for the smaller objects. The
size can be suffixed with "k", "m", or "g".
`--window-memory=0` makes memory usage unlimited. The default
is taken from the `pack.windowMemory` configuration variable.
Note that the actual memory usage will be the limit multiplied
by the number of threads used by linkgit:git-pack-objects[1].
--max-pack-size=<n>::
Maximum size of each output pack file. The size can be suffixed with
"k", "m", or "g". The minimum size allowed is limited to 1 MiB.
If specified, multiple packfiles may be created, which also
prevents the creation of a bitmap index.
The default is unlimited, unless the config variable
`pack.packSizeLimit` is set. Note that this option may result in
a larger and slower repository; see the discussion in
`pack.packSizeLimit`.
-b::
--write-bitmap-index::
Write a reachability bitmap index as part of the repack. This
only makes sense when used with `-a`, `-A` or `-m`, as the bitmaps
must be able to refer to all reachable objects. This option
overrides the setting of `repack.writeBitmaps`. This option
has no effect if multiple packfiles are created, unless writing a
MIDX (in which case a multi-pack bitmap is created).
--pack-kept-objects::
Include objects in `.keep` files when repacking. Note that we
still do not delete `.keep` packs after `pack-objects` finishes.
This means that we may duplicate objects, but this makes the
option safe to use when there are concurrent pushes or fetches.
This option is generally only useful if you are writing bitmaps
with `-b` or `repack.writeBitmaps`, as it ensures that the
bitmapped packfile has the necessary objects.
--keep-pack=<pack-name>::
Exclude the given pack from repacking. This is the equivalent
of having `.keep` file on the pack. `<pack-name>` is the
pack file name without leading directory (e.g. `pack-123.pack`).
The option could be specified multiple times to keep multiple
packs.
--unpack-unreachable=<when>::
When loosening unreachable objects, do not bother loosening any
objects older than `<when>`. This can be used to optimize out
the write of any objects that would be immediately pruned by
a follow-up `git prune`.
-k::
--keep-unreachable::
When used with `-ad`, any unreachable objects from existing
packs will be appended to the end of the packfile instead of
being removed. In addition, any unreachable loose objects will
be packed (and their loose counterparts removed).
-i::
--delta-islands::
Pass the `--delta-islands` option to `git-pack-objects`, see
linkgit:git-pack-objects[1].
-g=<factor>::
--geometric=<factor>::
Arrange resulting pack structure so that each successive pack
contains at least `<factor>` times the number of objects as the
next-largest pack.
+
`git repack` ensures this by determining a "cut" of packfiles that need
to be repacked into one in order to ensure a geometric progression. It
picks the smallest set of packfiles such that as many of the larger
packfiles (by count of objects contained in that pack) may be left
intact.
+
Unlike other repack modes, the set of objects to pack is determined
uniquely by the set of packs being "rolled-up"; in other words, the
packs determined to need to be combined in order to restore a geometric
progression.
+
When `--unpacked` is specified, loose objects are implicitly included in
this "roll-up", without respect to their reachability. This is subject
to change in the future. This option (implying a drastically different
repack mode) is not guaranteed to work with all other combinations of
option to `git repack`.
+
When writing a multi-pack bitmap, `git repack` selects the largest resulting
pack as the preferred pack for object selection by the MIDX (see
linkgit:git-multi-pack-index[1]).
-m::
--write-midx::
Write a multi-pack index (see linkgit:git-multi-pack-index[1])
containing the non-redundant packs.
CONFIGURATION
-------------
Various configuration variables affect packing, see
linkgit:git-config[1] (search for "pack" and "delta").
By default, the command passes `--delta-base-offset` option to
'git pack-objects'; this typically results in slightly smaller packs,
but the generated packs are incompatible with versions of Git older than
version 1.4.4. If you need to share your repository with such ancient Git
versions, either directly or via the dumb http protocol, then you
need to set the configuration variable `repack.UseDeltaBaseOffset` to
"false" and repack. Access from old Git versions over the native protocol
is unaffected by this option as the conversion is performed on the fly
as needed in that case.
Delta compression is not used on objects larger than the
`core.bigFileThreshold` configuration variable and on files with the
attribute `delta` set to false.
SEE ALSO
--------
linkgit:git-pack-objects[1]
linkgit:git-prune-packed[1]
GIT
---
Part of the linkgit:git[1] suite