git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2] builtin/repack: Honor --keep-pack and .keep when repacking promisor objects

From
Han Young <hanyang.tony@bytedance.com>
Date
May 8, 2025, 10:44 UTC
Message-ID
<20250508104437.51513-1-hanyang.tony@bytedance.com>
From: Tomáš Trnka <trnka@scm.com>

git-repack currently does not pass --keep-pack or --honor-pack-keep to the git-pack-objects handling promisor packs. This means that settings like gc.bigPackThreshold are completely ignored for promisor packs.

The simple fix is to just skip keep packs when iterating promisor packs.
Signed-off-by: Han Young <hanyang.tony@bytedance.com>
Original-patch-by: Tomáš Trnka <trnka@scm.com>
---
The original patch passes the --keep-pack arguments to pack-objects. While
this approach avoids repacking the keep packs, the objects in the keep
packs are still enumerated. These objects are iterated in repack and sent
to be packed, only to be skipped in pack-objects.

Filtering out the keep packs in repack_promisor_objects is more efficient, the objects in keep packs are not enumerated and sent to pack-objects.

In a test repo with a 2.7G promisor pack. The original patch took longer to repack the repo, most of the time was spent on enumerating objects.

The original patch:

$ time git repack -ad --keep-pack=pack-a26479ad4f9dff58448df6fca4953844009b3920.pack Enumerating objects: 19091575, done. Counting objects: 100% (5934/5934), done. Delta compression using up to 12 threads Compressing objects: 100% (4517/4517), done. Writing objects: 100% (5934/5934), done. Total 5934 (delta 2885), reused 2986 (delta 1192), pack-reused 0 (from 0) git repack -ad --keep-pack=pack-a26479ad4f9dff58448df6fca4953844009b3920.pack 43.94s user 46.83s system 134% cpu 1:07.60 total

This patch:

$ time git repack -ad --keep-pack=pack-a26479ad4f9dff58448df6fca4953844009b3920.pack Enumerating objects: 20952, done. Counting objects: 100% (18323/18323), done. Delta compression using up to 12 threads Compressing objects: 100% (9022/9022), done. Writing objects: 100% (18323/18323), done. Total 18323 (delta 11340), reused 15753 (delta 8771), pack-reused 0 (from 0) git repack -ad --keep-pack=pack-a26479ad4f9dff58448df6fca4953844009b3920.pack 8.65s user 3.14s system 62% cpu 18.838 total

I also noticed that this patch produced a smaller packfile.
1.6M compared to 4.5M generated by the original patch.
I suspect this is because some objects exist in multiple packs,
so pack-objects still repacks them even if they are actually present
in keep-packs.
---
 builtin/repack.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/builtin/repack.c b/builtin/repack.c
index 59214dbdfd..fb09df53c0 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -252,8 +252,9 @@ static void existing_packs_release(struct existing_packs *existing)
 /*
  * Adds all packs hex strings (pack-$HASH) to either packs->non_kept
  * or packs->kept based on whether each pack has a corresponding
- * .keep file or not.  Packs without a .keep file are not to be kept
- * if we are going to pack everything into one file.
+ * .keep file or not.  Packs without a .keep file or specified by
+ * --keep-pack are not to be kept if we are going to pack everything
+ * into one file.
  */
 static void collect_pack_filenames(struct existing_packs *existing,
 				   const struct string_list *extra_keep)
@@ -278,8 +279,15 @@ static void collect_pack_filenames(struct existing_packs *existing,
 		strbuf_addstr(&buf, base);
 		strbuf_strip_suffix(&buf, ".pack");
 
-		if ((extra_keep->nr > 0 && i < extra_keep->nr) || p->pack_keep)
+		if ((extra_keep->nr > 0 && i < extra_keep->nr) || p->pack_keep) {
 			string_list_append(&existing->kept_packs, buf.buf);
+			/*
+			 * mark packs specified by --keep-pack as keep in core, keep packs
+			 * are ignored by repack_promisor_objects. This avoids passthrough
+			 * --keep-pack args to pack-objects
+			 */
+			p->pack_keep_in_core = 1;
+		}
 		else if (p->is_cruft)
 			string_list_append(&existing->cruft_packs, buf.buf);
 		else
@@ -412,7 +420,9 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
 	 * of a {type -> size} ordering, which may produce better deltas.
 	 */
 	for_each_packed_object(the_repository, write_oid, &cmd,
-			       FOR_EACH_OBJECT_PROMISOR_ONLY);
+			       FOR_EACH_OBJECT_PROMISOR_ONLY |
+				   FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
+				   FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS);
 
 	if (cmd.in == -1) {
 		/* No packed objects; cmd was never started */
-- 
2.48.1
Next: Junio C Hamano
Message 1 of 3 in “builtin/repack: Honor --keep-pack and .keep when repacking promisor objects”
  1. builtin/repack: Honor --keep-pack and .keep when repacking promisor objectsHan Young, May 8, 2025
  2. Junio C HamanoMay 8, 2025
  3. Han YoungMay 21, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.