Merge changes I70d0e59d,I10ed8daf,Icdf7a34f

* changes:
  Add missing LF at the end of GarbageCollectCommandTest
  Add GarbageCollectCommand#setGcConfig
  GC: add flag to control whether gc should pack all refs
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java
index 6090d5e..2954570 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java
@@ -9,12 +9,16 @@
  */
 package org.eclipse.jgit.api;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import java.io.IOException;
 import java.time.Instant;
 import java.util.Properties;
 
 import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.GcConfig;
+import org.eclipse.jgit.lib.GcConfig.PackRefsMode;
 import org.eclipse.jgit.util.GitTimeParser;
 import org.junit.Before;
 import org.junit.Test;
@@ -34,6 +38,22 @@ public void setUp() throws Exception {
 	}
 
 	@Test
+	public void testPackRefs() throws Exception {
+		assertTrue(hasLooseRef(git));
+
+		// by default, refs should be packed
+		git.gc().call();
+		assertFalse(hasLooseRef(git));
+
+		// now create a loose ref again
+		git.branchCreate().setName("foo").call();
+		assertTrue(hasLooseRef(git));
+
+		git.gc().setGcConfig(new GcConfig(PackRefsMode.FALSE)).call();
+		assertTrue(hasLooseRef(git));
+	}
+
+	@Test
 	public void testGConeCommit() throws Exception {
 		Instant expireNow = GitTimeParser.parseInstant("now");
 		Properties res = git.gc().setExpire(expireNow).call();
@@ -54,4 +74,10 @@ public void testGCmoreCommits() throws Exception {
 		Properties res = git.gc().setExpire(expireNow).call();
 		assertTrue(res.size() == 8);
 	}
+
+	private static boolean hasLooseRef(Git git) throws IOException {
+		return git.getRepository().getRefDatabase().getRefs().stream()
+				.filter(r -> !r.isSymbolic())
+				.anyMatch(r -> r.getStorage().isLoose());
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
index 434f7e4..101feec 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
@@ -21,8 +21,11 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
 import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.GcConfig;
+import org.eclipse.jgit.lib.GcConfig.PackRefsMode;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.revwalk.RevCommit;
@@ -376,4 +379,106 @@ private PackConfig configureGc(GC myGc, boolean aggressive) {
 		myGc.setPackConfig(pconfig);
 		return pconfig;
 	}
+
+	@Test
+	public void testPackRefs() throws Exception {
+		tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B")
+				.create();
+		assertHasLooseRef(repo);
+
+		// by default, refs should be packed
+		gc.gc().get();
+		assertHasNoLooseRef(repo);
+
+		// now create a loose ref again
+		tr.branch("refs/heads/foo").commit().add("C", "C").create();
+		assertHasLooseRef(repo);
+		// and disable packing of refs
+		gc.setGcConfig(new GcConfig(PackRefsMode.FALSE));
+		gc.gc().get();
+		assertHasLooseRef(repo);
+	}
+
+	@Test
+	public void testPackRefsWithConfig() throws Exception {
+		tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B")
+				.create();
+		assertHasLooseRef(repo);
+
+		// disable packing of refs via config
+		FileBasedConfig config = repo.getConfig();
+		config.setEnum(ConfigConstants.CONFIG_GC_SECTION, null,
+				ConfigConstants.CONFIG_KEY_PACK_REFS, PackRefsMode.FALSE);
+		config.save();
+		reloadGcFromRepoConfig();
+
+		gc.gc().get();
+		assertHasLooseRef(repo);
+
+		// now enable packing of refs via API
+		gc.setGcConfig(new GcConfig(PackRefsMode.TRUE));
+		gc.gc().get();
+		assertHasNoLooseRef(repo);
+	}
+
+	@Test
+	public void testPackRefsWithNotBareConfig() throws Exception {
+		// non-bare repo
+		tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B")
+				.create();
+		assertHasLooseRef(repo);
+
+		// configure packing of refs only for non-bare repositories
+		FileBasedConfig config = repo.getConfig();
+		config.setEnum(ConfigConstants.CONFIG_GC_SECTION, null,
+				ConfigConstants.CONFIG_KEY_PACK_REFS, PackRefsMode.NOTBARE);
+		config.save();
+		reloadGcFromRepoConfig();
+
+		gc.gc().get();
+		assertHasNoLooseRef(repo);
+
+		// bare repo
+		String repoUri = repo.getDirectory().toURI().toString();
+		File dir = createUniqueTestGitDir(true);
+		try (FileRepository bareRepo = (FileRepository) Git.cloneRepository()
+				.setBare(true).setURI(repoUri).setDirectory(dir).call()
+				.getRepository(); Git git = new Git(bareRepo)) {
+			git.branchCreate().setName("refs/heads/branch-in-bare-repo")
+					.setStartPoint("refs/heads/master").call();
+			assertHasLooseRef(bareRepo);
+
+			// configure packing of refs only for non-bare repositories
+			FileBasedConfig bareConfig = bareRepo.getConfig();
+			bareConfig.setEnum(ConfigConstants.CONFIG_GC_SECTION, null,
+					ConfigConstants.CONFIG_KEY_PACK_REFS, PackRefsMode.NOTBARE);
+			bareConfig.save();
+			// create a new GC instance to reread the config
+			gc = new GC(bareRepo);
+
+			gc.gc().get();
+			assertHasLooseRef(bareRepo);
+		}
+	}
+
+	private static boolean hasLooseRef(FileRepository repository)
+			throws IOException {
+		return repository.getRefDatabase().getRefs().stream()
+				.filter(r -> !r.isSymbolic())
+				.anyMatch(r -> r.getStorage().isLoose());
+	}
+
+	private void reloadGcFromRepoConfig() {
+		gc = new GC(repo);
+	}
+
+	private static void assertHasLooseRef(FileRepository repository)
+			throws IOException {
+		assertTrue("should have loose ref", hasLooseRef(repository));
+	}
+
+	private static void assertHasNoLooseRef(FileRepository repository)
+			throws IOException {
+		assertFalse("should have no loose ref", hasLooseRef(repository));
+	}
 }
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 f6935e1..a16be79 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
@@ -26,6 +26,7 @@
 import org.eclipse.jgit.internal.storage.file.GC;
 import org.eclipse.jgit.internal.storage.file.GC.RepoStatistics;
 import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.GcConfig;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
@@ -66,6 +67,8 @@ public class GarbageCollectCommand extends GitCommand<Properties> {
 
 	private Boolean packKeptObjects;
 
+	private GcConfig gcConfig;
+
 	/**
 	 * Constructor for GarbageCollectCommand.
 	 *
@@ -75,6 +78,7 @@ public class GarbageCollectCommand extends GitCommand<Properties> {
 	protected GarbageCollectCommand(Repository repo) {
 		super(repo);
 		pconfig = new PackConfig(repo);
+		gcConfig = repo.getConfig().get(GcConfig.KEY);
 	}
 
 	/**
@@ -200,6 +204,19 @@ public GarbageCollectCommand setPrunePreserved(boolean prunePreserved) {
 		return this;
 	}
 
+	/**
+	 * Set the gc configuration
+	 *
+	 * @param gcConfig
+	 *            the gc configuration
+	 * @return {@code this}
+	 * @since 7.6
+	 */
+	public GarbageCollectCommand setGcConfig(GcConfig gcConfig) {
+		this.gcConfig = gcConfig;
+		return this;
+	}
+
 	@Override
 	public Properties call() throws GitAPIException {
 		checkCallable();
@@ -214,6 +231,7 @@ public Properties call() throws GitAPIException {
 				if (this.packKeptObjects != null) {
 					gc.setPackKeptObjects(packKeptObjects.booleanValue());
 				}
+				gc.setGcConfig(gcConfig);
 				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 7c6a304..6a78271 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
@@ -82,6 +82,8 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.CoreConfig;
 import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.GcConfig;
+import org.eclipse.jgit.lib.GcConfig.PackRefsMode;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdSet;
@@ -171,6 +173,8 @@ public static void setExecutor(ExecutorService e) {
 
 	private PackConfig pconfig;
 
+	private GcConfig gcConfig;
+
 	/**
 	 * the refs which existed during the last call to {@link #repack()}. This is
 	 * needed during {@link #prune(Set)} where we can optimize by looking at the
@@ -207,6 +211,7 @@ public GC(FileRepository repo) {
 		this.repo = repo;
 		this.pconfig = new PackConfig(repo);
 		this.pm = NullProgressMonitor.INSTANCE;
+		this.gcConfig = repo.getConfig().get(GcConfig.KEY);
 	}
 
 	/**
@@ -282,6 +287,18 @@ private ExecutorService executor() {
 		return (executor != null) ? executor : WorkQueue.getExecutor();
 	}
 
+	/**
+	 * Set the gc configuration.
+	 *
+	 * @param gcConfig
+	 *            the gc configuration
+	 * @return this instance
+	 */
+	public GC setGcConfig(GcConfig gcConfig) {
+		this.gcConfig = gcConfig;
+		return this;
+	}
+
 	private Collection<Pack> doGc()
 			throws IOException, ParseException, GitAPIException {
 		if (automatic && !needGc()) {
@@ -292,8 +309,13 @@ private Collection<Pack> doGc()
 				return Collections.emptyList();
 			}
 			pm.start(6 /* tasks */);
-			new PackRefsCommand(repo).setProgressMonitor(pm).setAll(true)
-					.call();
+			boolean packRefs = gcConfig.getPackRefs() == PackRefsMode.TRUE
+					|| (gcConfig.getPackRefs() == PackRefsMode.NOTBARE
+							&& !repo.isBare());
+			if (packRefs) {
+				new PackRefsCommand(repo).setProgressMonitor(pm).setAll(true)
+						.call();
+			}
 			// TODO: implement reflog_expire(pm, repo);
 			Collection<Pack> newPacks = repack();
 			prune(Collections.emptySet());
@@ -747,6 +769,15 @@ private long getPackExpireDate() throws ParseException {
 	}
 
 	/**
+	 * Get the gc configuration.
+	 *
+	 * @return the gc configuration.
+	 */
+	public GcConfig getGcConfig() {
+		return gcConfig;
+	}
+
+	/**
 	 * Remove all entries from a map which key is the id of an object referenced
 	 * by the given ObjectWalk
 	 *
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 56b801e..73c7006 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -1122,4 +1122,11 @@ public final class ConfigConstants {
 	 * @since 7.5
 	 */
 	public static final String CONFIG_KEY_MULTIPACKINDEX = "multiPackIndex";
+
+	/**
+	 * The "packRefs" key
+	 *
+	 * @since 7.6
+	 */
+	public static final String CONFIG_KEY_PACK_REFS = "packRefs";
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GcConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GcConfig.java
new file mode 100644
index 0000000..7239bd7
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GcConfig.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2026, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lib;
+
+import org.eclipse.jgit.lib.Config.SectionParser;
+
+/**
+ * GC configuration settings.
+ *
+ * @since 7.6
+ */
+public class GcConfig {
+	/** Key for {@link Config#get(SectionParser)}. */
+	public static final Config.SectionParser<GcConfig> KEY = GcConfig::new;
+
+	/**
+	 * Whether to pack refs during gc.
+	 */
+	public enum PackRefsMode {
+		/**
+		 * Pack no refs.
+		 */
+		FALSE,
+		/**
+		 * Pack all refs except symbolic refs.
+		 */
+		TRUE,
+		/**
+		 * Pack all refs except symbolic refs within all non-bare repositories.
+		 */
+		NOTBARE
+	}
+
+	private final PackRefsMode packRefs;
+
+	/**
+	 * Create a new gc configuration from the passed configuration.
+	 *
+	 * @param rc
+	 *            git configuration
+	 */
+	public GcConfig(Config rc) {
+		this.packRefs = rc.getEnum(ConfigConstants.CONFIG_GC_SECTION, null,
+				ConfigConstants.CONFIG_KEY_PACK_REFS, PackRefsMode.TRUE);
+	}
+
+	/**
+	 * Create a new gc configuration with the given settings.
+	 *
+	 * @param packRefs
+	 *            whether to pack refs during gc
+	 */
+	public GcConfig(PackRefsMode packRefs) {
+		this.packRefs = packRefs;
+	}
+
+	/**
+	 * Get the pack refs mode configuring which refs to pack during gc.
+	 *
+	 * @return the pack refs mode configuring which refs to pack during gc.
+	 */
+	public PackRefsMode getPackRefs() {
+		return packRefs;
+	}
+
+}