Skip to content

Commit

Permalink
repack: add repack.packKeptObjects config var
Browse files Browse the repository at this point in the history
The git-repack command always passes `--honor-pack-keep`
to pack-objects. This has traditionally been a good thing,
as we do not want to duplicate those objects in a new pack,
and we are not going to delete the old pack.

However, when bitmaps are in use, it is important for a full
repack to include all reachable objects, even if they may be
duplicated in a .keep pack. Otherwise, we cannot generate
the bitmaps, as the on-disk format requires the set of
objects in the pack to be fully closed.

Even if the repository does not generally have .keep files,
a simultaneous push could cause a race condition in which a
.keep file exists at the moment of a repack. The repack may
try to include those objects in one of two situations:

  1. The pushed .keep pack contains objects that were
     already in the repository (e.g., blobs due to a revert of
     an old commit).

  2. Receive-pack updates the refs, making the objects
     reachable, but before it removes the .keep file, the
     repack runs.

In either case, we may prefer to duplicate some objects in
the new, full pack, and let the next repack (after the .keep
file is cleaned up) take care of removing them.

This patch introduces both a command-line and config option
to disable the `--honor-pack-keep` option.  By default, it
is triggered when pack.writeBitmaps (or `--write-bitmap-index`
is turned on), but specifying it explicitly can override the
behavior (e.g., in cases where you prefer .keep files to
bitmaps, but only when they are present).

Note that this option just disables the pack-objects
behavior. We still leave packs with a .keep in place, as we
do not necessarily know that we have duplicated all of their
objects.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Jeff King authored and Junio C Hamano committed Mar 3, 2014
1 parent 6b5b3a2 commit ee34a2b
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 2 deletions.
7 changes: 7 additions & 0 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2128,6 +2128,13 @@ repack.usedeltabaseoffset::
"false" and repack. Access from old Git versions over the
native protocol are unaffected by this option.

repack.packKeptObjects::
If set to true, makes `git repack` act as if
`--pack-kept-objects` was passed. See linkgit:git-repack[1] for
details. Defaults to `false` normally, but `true` if a bitmap
index is being written (either via `--write-bitmap-index` or
`pack.writeBitmaps`).

rerere.autoupdate::
When set to true, `git-rerere` updates the index with the
resulting contents after it cleanly resolves conflicts using
Expand Down
8 changes: 8 additions & 0 deletions Documentation/git-repack.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ other objects in that pack they already have locally.
must be able to refer to all reachable objects. This option
overrides the setting of `pack.writebitmaps`.

--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 `pack.writebitmaps`, as it ensures that the
bitmapped packfile has the necessary objects.

Configuration
-------------
Expand Down
13 changes: 12 additions & 1 deletion builtin/repack.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "argv-array.h"

static int delta_base_offset = 1;
static int pack_kept_objects = -1;
static char *packdir, *packtmp;

static const char *const git_repack_usage[] = {
Expand All @@ -22,6 +23,10 @@ static int repack_config(const char *var, const char *value, void *cb)
delta_base_offset = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "repack.packkeptobjects")) {
pack_kept_objects = git_config_bool(var, value);
return 0;
}
return git_default_config(var, value, cb);
}

Expand Down Expand Up @@ -175,6 +180,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("limits the maximum delta depth")),
OPT_INTEGER(0, "max-pack-size", &max_pack_size,
N_("maximum size of each packfile")),
OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
N_("repack objects in packs marked with .keep")),
OPT_END()
};

Expand All @@ -183,14 +190,18 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, builtin_repack_options,
git_repack_usage, 0);

if (pack_kept_objects < 0)
pack_kept_objects = write_bitmap;

packdir = mkpathdup("%s/pack", get_object_directory());
packtmp = mkpathdup("%s/.tmp-%d-pack", packdir, (int)getpid());

sigchain_push_common(remove_pack_on_signal);

argv_array_push(&cmd_args, "pack-objects");
argv_array_push(&cmd_args, "--keep-true-parents");
argv_array_push(&cmd_args, "--honor-pack-keep");
if (!pack_kept_objects)
argv_array_push(&cmd_args, "--honor-pack-keep");
argv_array_push(&cmd_args, "--non-empty");
argv_array_push(&cmd_args, "--all");
argv_array_push(&cmd_args, "--reflog");
Expand Down
18 changes: 17 additions & 1 deletion t/t7700-repack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ test_expect_success 'objects in packs marked .keep are not repacked' '
objsha1=$(git verify-pack -v pack-$packsha1.idx | head -n 1 |
sed -e "s/^\([0-9a-f]\{40\}\).*/\1/") &&
mv pack-* .git/objects/pack/ &&
git repack -A -d -l &&
git repack --no-pack-kept-objects -A -d -l &&
git prune-packed &&
for p in .git/objects/pack/*.idx; do
idx=$(basename $p)
Expand All @@ -35,6 +35,22 @@ test_expect_success 'objects in packs marked .keep are not repacked' '
test -z "$found_duplicate_object"
'

test_expect_success 'writing bitmaps can duplicate .keep objects' '
# build on $objsha1, $packsha1, and .keep state from previous
git repack -Adl &&
test_when_finished "found_duplicate_object=" &&
for p in .git/objects/pack/*.idx; do
idx=$(basename $p)
test "pack-$packsha1.idx" = "$idx" && continue
if git verify-pack -v $p | egrep "^$objsha1"; then
found_duplicate_object=1
echo "DUPLICATE OBJECT FOUND"
break
fi
done &&
test "$found_duplicate_object" = 1
'

test_expect_success 'loose objects in alternate ODB are not repacked' '
mkdir alt_objects &&
echo `pwd`/alt_objects > .git/objects/info/alternates &&
Expand Down

0 comments on commit ee34a2b

Please sign in to comment.