diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index 54d715ead1..cbe08e7415 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -135,6 +135,17 @@ depth is 4095.
leading directory (e.g. `pack-123.pack`). The option could be
specified multiple times to keep multiple packs.
+--assume-kept-packs-closed::
+ This flag causes `git rev-list` to halt the object traversal
+ when it encounters an object found in a kept pack. This is
+ dissimilar to `--honor-pack-keep`, which only prunes unwanted
+ results after the full traversal is completed.
++
+Without any `--keep-pack=<pack-name>` arguments, only packs with an
+on-disk `*.keep` files are used when considering when to halt the
+traversal. If other packs are artificially marked as "kept" with
+`--keep-pack`, then those are considered as well.
+
--incremental::
This flag causes an object already in a pack to be ignored
even if it would have otherwise been packed.
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 2a00358f34..a5dcd66f52 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -78,6 +78,7 @@ static int have_non_local_packs;
static int incremental;
static int ignore_packed_keep_on_disk;
static int ignore_packed_keep_in_core;
+static int assume_kept_packs_closed;
static int allow_ofs_delta;
static struct pack_idx_option pack_idx_opts;
static const char *base_name;
@@ -3542,6 +3543,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
N_("create packs suitable for shallow fetches")),
OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep_on_disk,
N_("ignore packs that have companion .keep file")),
+ OPT_BOOL(0, "assume-kept-packs-closed", &assume_kept_packs_closed,
+ N_("assume the union of kept packs is closed under reachability")),
OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
N_("ignore this pack")),
OPT_INTEGER(0, "compression", &pack_compression_level,@@ -3631,6 +3634,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
use_internal_rev_list = 1;
strvec_push(&rp, "--unpacked");
}
+ if (assume_kept_packs_closed)
+ use_internal_rev_list = 1;
if (exclude_promisor_objects) {
use_internal_rev_list = 1;@@ -3711,6 +3716,14 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!p) /* no keep-able packs found */
ignore_packed_keep_on_disk = 0;
}
+ if (assume_kept_packs_closed) {
+ if (ignore_packed_keep_on_disk && ignore_packed_keep_in_core)
+ strvec_push(&rp, "--no-kept-objects");
+ else if (ignore_packed_keep_on_disk)
+ strvec_push(&rp, "--no-kept-objects=on-disk");
+ else if (ignore_packed_keep_in_core)
+ strvec_push(&rp, "--no-kept-objects=in-core");
+ }
if (local) {
/*
* unlike ignore_packed_keep_on_disk above, we do notdiff --git a/t/t6114-keep-packs.sh b/t/t6114-keep-packs.sh
index 9239d8aa46..0861305a04 100755
--- a/t/t6114-keep-packs.sh
+++ b/t/t6114-keep-packs.sh
@@ -66,4 +66,63 @@ test_expect_success '--no-kept-objects excludes kept non-MIDX object' '
test_cmp expect actual
'
+test_expect_success '--no-kept-objects can respect only in-core keep packs' '
+ test_when_finished "rm -fr actual-*.idx actual-*.pack" &&
+ (
+ git rev-list --objects --no-object-names packed..kept &&
+ git rev-list --objects --no-object-names loose
+ ) | sort >expect &&
+
+ git pack-objects \
+ --assume-kept-packs-closed \
+ --keep-pack=pack-$MISC_PACK.pack \
+ --all actual </dev/null &&
+ idx_objects actual-*.idx >actual &&
+
+ test_cmp expect actual
+'
+
+test_expect_success 'setup additional --no-kept-objects tests' '
+ test_commit additional &&
+
+ ADDITIONAL_PACK=$(git pack-objects --revs .git/objects/pack/pack <<-EOF
+ refs/tags/additional
+ ^refs/tags/kept
+ EOF
+ )
+'
+
+test_expect_success '--no-kept-objects can respect only on-disk keep packs' '
+ test_when_finished "rm -fr actual-*.idx actual-*.pack" &&
+ (
+ git rev-list --objects --no-object-names kept..additional &&
+ git rev-list --objects --no-object-names packed
+ ) | sort >expect &&
+
+ git pack-objects \
+ --assume-kept-packs-closed \
+ --honor-pack-keep \
+ --all actual </dev/null &&
+ idx_objects actual-*.idx >actual &&
+
+ test_cmp expect actual
+'
+
+test_expect_success '--no-kept-objects can respect mixed kept packs' '
+ test_when_finished "rm -fr actual-*.idx actual-*.pack" &&
+ (
+ git rev-list --objects --no-object-names kept..additional &&
+ git rev-list --objects --no-object-names loose
+ ) | sort >expect &&
+
+ git pack-objects \
+ --assume-kept-packs-closed \
+ --honor-pack-keep \
+ --keep-pack=pack-$MISC_PACK.pack \
+ --all actual </dev/null &&
+ idx_objects actual-*.idx >actual &&
+
+ test_cmp expect actual
+'
+
test_done
--
2.30.0.138.g6d7191ea01