Merge branch 'stable-6.1' into stable-6.2

* stable-6.1:
  PackConfig: fix @since tags
  Remove unused API problem filters
  Add support for git config repack.packKeptObjects
  Do not exclude objects in locked packs from bitmap processing

Change-Id: Ib4e4fe407dce334c7537bf278baa39db93aa2f09
diff --git a/Documentation/config-options.md b/Documentation/config-options.md
index e95462a..815677c 100644
--- a/Documentation/config-options.md
+++ b/Documentation/config-options.md
@@ -111,3 +111,9 @@
 | `pack.waitPreventRacyPack` | `false` | ⃞ | Whether we wait before opening a newly written pack to prevent its lastModified timestamp could be racy. |
 | `pack.window` | `10` | ✅ | Number of objects to try when looking for a delta base per thread searching for deltas. |
 | `pack.windowMemory` | `0` (unlimited) | ✅ | Maximum number of bytes to put into the delta search window. |
+
+## __repack__ options
+
+|  option | default | git option | description |
+|---------|---------|------------|-------------|
+| `repack.packKeptObjects` | `true` when `pack.buildBitmaps` is set, `false` otherwise | ✅ | Include objects in packs locked by a `.keep` file when repacking. |
\ No newline at end of file
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index b14531a..74ea867 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -293,6 +293,7 @@
 usage_Match=Only consider tags matching the given glob(7) pattern or patterns, excluding the "refs/tags/" prefix.
 usage_MergeBase=Find as good common ancestors as possible for a merge
 usage_MergesTwoDevelopmentHistories=Merges two development histories
+usage_PackKeptObjects=Include objects in packs locked by a ".keep" file when repacking
 usage_PreserveOldPacks=Preserve old pack files by moving them into the preserved subdirectory instead of deleting them after repacking
 usage_PrunePreserved=Remove the preserved subdirectory containing previously preserved old pack files before repacking, and before preserving more old pack files
 usage_ReadDirCache= Read the DirCache 100 times
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
index c87f0b6..35ac7a1 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java
@@ -27,6 +27,9 @@ class Gc extends TextBuiltin {
 	@Option(name = "--prune-preserved", usage = "usage_PrunePreserved")
 	private Boolean prunePreserved;
 
+	@Option(name = "--pack-kept-objects", usage = "usage_PackKeptObjects")
+	private Boolean packKeptObjects;
+
 	/** {@inheritDoc} */
 	@Override
 	protected void run() {
@@ -40,6 +43,9 @@ protected void run() {
 			if (prunePreserved != null) {
 				command.setPrunePreserved(prunePreserved.booleanValue());
 			}
+			if (packKeptObjects != null) {
+				command.setPackKeptObjects(packKeptObjects.booleanValue());
+			}
 			command.call();
 		} catch (GitAPIException e) {
 			throw die(e.getMessage(), e);
diff --git a/org.eclipse.jgit.ssh.apache.agent/bin/.project b/org.eclipse.jgit.ssh.apache.agent/bin/.project
new file mode 100644
index 0000000..73358f4
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.agent/bin/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.jgit.ssh.apache.agent</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcKeepFilesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcKeepFilesTest.java
index 571f261..9a2935f1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcKeepFilesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcKeepFilesTest.java
@@ -10,8 +10,13 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BUILD_BITMAPS;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PACK_KEPT_OBJECTS;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_PACK_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_REPACK_SECTION;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Iterator;
@@ -19,9 +24,14 @@
 import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
 import org.eclipse.jgit.internal.storage.pack.PackExt;
 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.storage.pack.PackConfig;
 import org.junit.Test;
 
 public class GcKeepFilesTest extends GcTestCase {
+	private static final int COMMIT_AND_TREE_OBJECTS = 2;
+
 	@Test
 	public void testKeepFiles() throws Exception {
 		BranchBuilder bb = tr.branch("refs/heads/master");
@@ -51,6 +61,7 @@ public void testKeepFiles() throws Exception {
 		PackFile bitmapFile = singlePack.getPackFile().create(PackExt.BITMAP_INDEX);
 		assertTrue(keepFile.exists());
 		assertTrue(bitmapFile.delete());
+		gc.setPackKeptObjects(false);
 		gc.gc().get();
 		stats = gc.getStatistics();
 		assertEquals(0, stats.numberOfLooseObjects);
@@ -72,4 +83,149 @@ public void testKeepFiles() throws Exception {
 								+ e.toObjectId(),
 						ind2.hasObject(e.toObjectId()));
 	}
+
+	@Test
+	public void testKeptObjectsAreIncludedByDefault() throws Exception {
+		testKeptObjectsAreIncluded();
+	}
+
+	@Test
+	public void testKeptObjectsAreIncludedByDefaultWhenBuildBitmapsIsTrue()
+			throws Exception {
+		PackConfig packConfig = new PackConfig();
+		Config repoConfig = repo.getObjectDatabase().getConfig();
+		repoConfig.setBoolean(CONFIG_PACK_SECTION, null,
+				CONFIG_KEY_BUILD_BITMAPS, true);
+		packConfig.fromConfig(repoConfig);
+		gc.setPackConfig(packConfig);
+
+		testKeptObjectsAreIncluded();
+	}
+
+	@Test
+	public void testKeptObjectsAreIncludedWhenPackKeptObjectsIsFalseButOverriddenViaCommandLine()
+			throws Exception {
+		PackConfig packConfig = new PackConfig();
+		packConfig.setPackKeptObjects(false);
+		gc.setPackConfig(packConfig);
+		gc.setPackKeptObjects(true);
+
+		testKeptObjectsAreIncluded();
+	}
+
+	@Test
+	public void testKeptObjectsAreNotIncludedByDefaultWhenBuildBitmapsIsFalse()
+			throws Exception {
+		PackConfig packConfig = new PackConfig();
+		packConfig.setBuildBitmaps(false);
+		gc.setPackConfig(packConfig);
+
+		testKeptObjectsAreNotIncluded();
+	}
+
+	@Test
+	public void testKeptObjectsAreIncludedWhenBuildBitmapsIsFalseButPackKeptObjectsIsTrue()
+			throws Exception {
+		PackConfig packConfig = new PackConfig();
+		Config repoConfig = repo.getObjectDatabase().getConfig();
+		repoConfig.setBoolean(CONFIG_PACK_SECTION, null,
+				CONFIG_KEY_BUILD_BITMAPS, false);
+		repoConfig.setBoolean(CONFIG_REPACK_SECTION, null,
+				CONFIG_KEY_PACK_KEPT_OBJECTS, true);
+		packConfig.fromConfig(repoConfig);
+		gc.setPackConfig(packConfig);
+
+		testKeptObjectsAreIncluded();
+	}
+
+	@Test
+	public void testKeptObjectsAreNotIncludedWhenPackKeptObjectsIsTrueButOverriddenViaCommandLine()
+			throws Exception {
+		PackConfig packConfig = new PackConfig();
+		packConfig.setPackKeptObjects(true);
+		gc.setPackConfig(packConfig);
+		gc.setPackKeptObjects(false);
+
+		testKeptObjectsAreNotIncluded();
+	}
+
+	@Test
+	public void testKeptObjectsAreNotIncludedWhenPackKeptObjectsConfigIsFalse()
+			throws Exception {
+		PackConfig packConfig = new PackConfig();
+		packConfig.setPackKeptObjects(false);
+		gc.setPackConfig(packConfig);
+
+		testKeptObjectsAreNotIncluded();
+	}
+
+	private void testKeptObjectsAreIncluded() throws Exception {
+		BranchBuilder bb = tr.branch("refs/heads/master");
+		ObjectId commitObjectInLockedPack = bb.commit().create().toObjectId();
+		gc.gc();
+		stats = gc.getStatistics();
+		assertEquals(COMMIT_AND_TREE_OBJECTS, stats.numberOfPackedObjects);
+		assertEquals(1, stats.numberOfPackFiles);
+		assertTrue(getSinglePack().getPackFile().create(PackExt.KEEP)
+				.createNewFile());
+
+		bb.commit().create();
+		gc.gc();
+		stats = gc.getStatistics();
+		assertEquals(2 * COMMIT_AND_TREE_OBJECTS + 1,
+				stats.numberOfPackedObjects);
+		assertEquals(2, stats.numberOfPackFiles);
+
+		PackIndex lockedPackIdx = null;
+		PackIndex newPackIdx = null;
+		for (Pack pack : repo.getObjectDatabase().getPacks()) {
+			if (pack.getObjectCount() == COMMIT_AND_TREE_OBJECTS) {
+				lockedPackIdx = pack.getIndex();
+			} else {
+				newPackIdx = pack.getIndex();
+			}
+		}
+		assertNotNull(lockedPackIdx);
+		assertTrue(lockedPackIdx.hasObject(commitObjectInLockedPack));
+		assertNotNull(newPackIdx);
+		assertTrue(newPackIdx.hasObject(commitObjectInLockedPack));
+	}
+
+	private void testKeptObjectsAreNotIncluded() throws Exception {
+		BranchBuilder bb = tr.branch("refs/heads/master");
+		ObjectId commitObjectInLockedPack = bb.commit().create().toObjectId();
+		gc.gc();
+		stats = gc.getStatistics();
+		assertEquals(COMMIT_AND_TREE_OBJECTS, stats.numberOfPackedObjects);
+		assertEquals(1, stats.numberOfPackFiles);
+		assertTrue(getSinglePack().getPackFile().create(PackExt.KEEP)
+				.createNewFile());
+
+		bb.commit().create();
+		gc.gc();
+		stats = gc.getStatistics();
+		assertEquals(COMMIT_AND_TREE_OBJECTS + 1, stats.numberOfPackedObjects);
+		assertEquals(2, stats.numberOfPackFiles);
+
+		PackIndex lockedPackIdx = null;
+		PackIndex newPackIdx = null;
+		for (Pack pack : repo.getObjectDatabase().getPacks()) {
+			if (pack.getObjectCount() == COMMIT_AND_TREE_OBJECTS) {
+				lockedPackIdx = pack.getIndex();
+			} else {
+				newPackIdx = pack.getIndex();
+			}
+		}
+		assertNotNull(lockedPackIdx);
+		assertTrue(lockedPackIdx.hasObject(commitObjectInLockedPack));
+		assertNotNull(newPackIdx);
+		assertFalse(newPackIdx.hasObject(commitObjectInLockedPack));
+	}
+
+	private Pack getSinglePack() {
+		Iterator<Pack> packIt = repo.getObjectDatabase().getPacks().iterator();
+		Pack singlePack = packIt.next();
+		assertFalse(packIt.hasNext());
+		return singlePack;
+	}
 }
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 0a9b2b0..8b122a3 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -1,5 +1,13 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <component id="org.eclipse.jgit" version="2">
+    <resource path="src/org/eclipse/jgit/api/GarbageCollectCommand.java" type="org.eclipse.jgit.api.GarbageCollectCommand">
+        <filter id="1142947843">
+            <message_arguments>
+                <message_argument value="5.13.3"/>
+                <message_argument value="setPackKeptObjects(boolean)"/>
+            </message_arguments>
+        </filter>
+    </resource>
     <resource path="src/org/eclipse/jgit/errors/PackMismatchException.java" type="org.eclipse.jgit.errors.PackMismatchException">
         <filter id="1142947843">
             <message_arguments>
@@ -47,6 +55,18 @@
         </filter>
         <filter id="1142947843">
             <message_arguments>
+                <message_argument value="5.13.3"/>
+                <message_argument value="CONFIG_KEY_PACK_KEPT_OBJECTS"/>
+            </message_arguments>
+        </filter>
+        <filter id="1142947843">
+            <message_arguments>
+                <message_argument value="5.13.3"/>
+                <message_argument value="CONFIG_REPACK_SECTION"/>
+            </message_arguments>
+        </filter>
+        <filter id="1142947843">
+            <message_arguments>
                 <message_argument value="6.1.1"/>
                 <message_argument value="CONFIG_KEY_TRUST_PACKED_REFS_STAT"/>
             </message_arguments>
@@ -75,6 +95,12 @@
                 <message_argument value="DEFAULT_BITMAP_EXCLUDED_REFS_PREFIXES"/>
             </message_arguments>
         </filter>
+        <filter id="336658481">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.storage.pack.PackConfig"/>
+                <message_argument value="DEFAULT_PACK_KEPT_OBJECTS"/>
+            </message_arguments>
+        </filter>
         <filter id="1142947843">
             <message_arguments>
                 <message_argument value="5.13.2"/>
@@ -93,6 +119,24 @@
                 <message_argument value="setBitmapExcludedRefsPrefixes(String[])"/>
             </message_arguments>
         </filter>
+        <filter id="1142947843">
+            <message_arguments>
+                <message_argument value="5.13.3"/>
+                <message_argument value="DEFAULT_PACK_KEPT_OBJECTS"/>
+            </message_arguments>
+        </filter>
+        <filter id="1142947843">
+            <message_arguments>
+                <message_argument value="5.13.3"/>
+                <message_argument value="isPackKeptObjects()"/>
+            </message_arguments>
+        </filter>
+        <filter id="1142947843">
+            <message_arguments>
+                <message_argument value="5.13.3"/>
+                <message_argument value="setPackKeptObjects(boolean)"/>
+            </message_arguments>
+        </filter>
     </resource>
     <resource path="src/org/eclipse/jgit/transport/AwsRequestSignerV4.java" type="org.eclipse.jgit.transport.AwsRequestSignerV4">
         <filter id="1109393411">
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
index 584d2bc..ab8cd18 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
@@ -63,6 +63,8 @@ public class GarbageCollectCommand extends GitCommand<Properties> {
 
 	private PackConfig pconfig;
 
+	private Boolean packKeptObjects;
+
 	/**
 	 * Constructor for GarbageCollectCommand.
 	 *
@@ -132,6 +134,19 @@ public GarbageCollectCommand setAggressive(boolean aggressive) {
 	}
 
 	/**
+	 * Whether to include objects in `.keep` packs when repacking.
+	 *
+	 * @param packKeptObjects
+	 *            whether to include objects in `.keep` files when repacking.
+	 * @return this instance
+	 * @since 5.13.3
+	 */
+	public GarbageCollectCommand setPackKeptObjects(boolean packKeptObjects) {
+		this.packKeptObjects = Boolean.valueOf(packKeptObjects);
+		return this;
+	}
+
+	/**
 	 * Whether to preserve old pack files instead of deleting them.
 	 *
 	 * @since 4.7
@@ -175,7 +190,9 @@ public Properties call() throws GitAPIException {
 				gc.setProgressMonitor(monitor);
 				if (this.expire != null)
 					gc.setExpire(expire);
-
+				if (this.packKeptObjects != null) {
+					gc.setPackKeptObjects(packKeptObjects.booleanValue());
+				}
 				try {
 					gc.gc().get();
 					return toProperties(gc.getStatistics());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index b261cb1..799d058 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -159,6 +159,8 @@ public static void setExecutor(ExecutorService e) {
 
 	private Date packExpire;
 
+	private Boolean packKeptObjects;
+
 	private PackConfig pconfig;
 
 	/**
@@ -837,8 +839,9 @@ public Collection<Pack> repack() throws IOException {
 		List<ObjectIdSet> excluded = new LinkedList<>();
 		for (Pack p : repo.getObjectDatabase().getPacks()) {
 			checkCancelled();
-			if (p.shouldBeKept())
+			if (!shouldPackKeptObjects() && p.shouldBeKept()) {
 				excluded.add(p.getIndex());
+			}
 		}
 
 		// Don't exclude tags that are also branch tips
@@ -1306,6 +1309,21 @@ private void checkCancelled() throws CancelledException {
 	}
 
 	/**
+	 * Define whether to include objects in `.keep` files when repacking.
+	 *
+	 * @param packKeptObjects Whether to include objects in `.keep` files when repacking.
+	 */
+	public void setPackKeptObjects(boolean packKeptObjects) {
+		this.packKeptObjects = Boolean.valueOf(packKeptObjects);
+	}
+
+	@SuppressWarnings("boxing")
+	private boolean shouldPackKeptObjects() {
+		return Optional.ofNullable(packKeptObjects)
+				.orElse(pconfig.isPackKeptObjects());
+	}
+
+	/**
 	 * A class holding statistical data for a FileRepository regarding how many
 	 * objects are stored as loose or packed objects
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 5c48c7a..2b49f95 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -103,6 +103,12 @@ public final class ConfigConstants {
 	/** The "gc" section */
 	public static final String CONFIG_GC_SECTION = "gc";
 
+	/**
+	 * The "repack" section
+	 * @since 5.13.3
+	 */
+	public static final String CONFIG_REPACK_SECTION = "repack";
+
 	/** The "pack" section */
 	public static final String CONFIG_PACK_SECTION = "pack";
 
@@ -829,6 +835,13 @@ public final class ConfigConstants {
 	public static final String CONFIG_KEY_WINDOW_MEMORY = "windowmemory";
 
 	/**
+	 * The "repack.packKeptObjects" key
+	 *
+	 * @since 5.13.3
+	 */
+	public static final String CONFIG_KEY_PACK_KEPT_OBJECTS = "packkeptobjects";
+
+	/**
 	 * The "feature" section
 	 *
 	 * @since 5.9
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
index 163e475..ff925db 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
@@ -37,8 +37,10 @@
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WINDOW;
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WINDOW_MEMORY;
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_PACK_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PACK_KEPT_OBJECTS;
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PRESERVE_OLD_PACKS;
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PRUNE_PRESERVED;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_REPACK_SECTION;
 
 import java.time.Duration;
 import java.util.concurrent.Executor;
@@ -168,6 +170,16 @@ public class PackConfig {
 	 */
 	public static final boolean DEFAULT_BUILD_BITMAPS = true;
 
+
+	/**
+	 * Default value for including objects in packs locked by .keep file when
+	 * repacking: {@value}
+	 *
+	 * @see #setPackKeptObjects(boolean)
+	 * @since 5.13.3
+	 */
+	public static final boolean DEFAULT_PACK_KEPT_OBJECTS = false;
+
 	/**
 	 * Default count of most recent commits to select for bitmaps. Only applies
 	 * when bitmaps are enabled: {@value}
@@ -284,6 +296,8 @@ public class PackConfig {
 
 	private boolean buildBitmaps = DEFAULT_BUILD_BITMAPS;
 
+	private boolean packKeptObjects = DEFAULT_PACK_KEPT_OBJECTS;
+
 	private int bitmapContiguousCommitCount = DEFAULT_BITMAP_CONTIGUOUS_COMMIT_COUNT;
 
 	private int bitmapRecentCommitCount = DEFAULT_BITMAP_RECENT_COMMIT_COUNT;
@@ -362,6 +376,7 @@ public PackConfig(PackConfig cfg) {
 		this.executor = cfg.executor;
 		this.indexVersion = cfg.indexVersion;
 		this.buildBitmaps = cfg.buildBitmaps;
+		this.packKeptObjects = cfg.packKeptObjects;
 		this.bitmapContiguousCommitCount = cfg.bitmapContiguousCommitCount;
 		this.bitmapRecentCommitCount = cfg.bitmapRecentCommitCount;
 		this.bitmapRecentCommitSpan = cfg.bitmapRecentCommitSpan;
@@ -990,6 +1005,34 @@ public void setBuildBitmaps(boolean buildBitmaps) {
 	}
 
 	/**
+	 * Set whether to include objects in `.keep` files when repacking.
+	 *
+	 * <p>
+	 * Default setting: {@value #DEFAULT_PACK_KEPT_OBJECTS}
+	 *
+	 * @param packKeptObjects
+	 *            boolean indicating whether to include objects in `.keep` files
+	 *            when repacking.
+	 * @since 5.13.3
+	 */
+	public void setPackKeptObjects(boolean packKeptObjects) {
+		this.packKeptObjects = packKeptObjects;
+	}
+
+	/**
+	 * True if objects in `.keep` files should be included when repacking.
+	 *
+	 * Default setting: {@value #DEFAULT_PACK_KEPT_OBJECTS}
+	 *
+	 * @return True if objects in `.keep` files should be included when
+	 *         repacking.
+	 * @since 5.13.3
+	 */
+	public boolean isPackKeptObjects() {
+		return packKeptObjects;
+	}
+
+	/**
 	 * Get the count of most recent commits for which to build bitmaps.
 	 *
 	 * Default setting: {@value #DEFAULT_BITMAP_CONTIGUOUS_COMMIT_COUNT}
@@ -1234,8 +1277,12 @@ public void fromConfig(Config rc) {
 		setSinglePack(rc.getBoolean(CONFIG_PACK_SECTION,
 				CONFIG_KEY_SINGLE_PACK,
 				getSinglePack()));
-		setBuildBitmaps(rc.getBoolean(CONFIG_PACK_SECTION,
-				CONFIG_KEY_BUILD_BITMAPS, isBuildBitmaps()));
+		boolean buildBitmapsFromConfig = rc.getBoolean(CONFIG_PACK_SECTION,
+				CONFIG_KEY_BUILD_BITMAPS, isBuildBitmaps());
+		setBuildBitmaps(buildBitmapsFromConfig);
+		setPackKeptObjects(rc.getBoolean(CONFIG_REPACK_SECTION,
+				CONFIG_KEY_PACK_KEPT_OBJECTS,
+				buildBitmapsFromConfig || isPackKeptObjects()));
 		setBitmapContiguousCommitCount(rc.getInt(CONFIG_PACK_SECTION,
 				CONFIG_KEY_BITMAP_CONTIGUOUS_COMMIT_COUNT,
 				getBitmapContiguousCommitCount()));