aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/PackRefsTest.java81
-rw-r--r--org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin1
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties2
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/PackRefs.java34
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java31
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java10
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/PackRefsCommand.java87
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java19
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java51
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java29
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java19
14 files changed, 317 insertions, 54 deletions
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/PackRefsTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/PackRefsTest.java
new file mode 100644
index 0000000000..b4d4ea9e56
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/PackRefsTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * 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.pgm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.lib.CLIRepositoryTestCase;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Ref;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PackRefsTest extends CLIRepositoryTestCase {
+ private Git git;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ git = new Git(db);
+ git.commit().setMessage("initial commit").call();
+ }
+
+ @Test
+ public void tagPacked() throws Exception {
+ git.tag().setName("test").call();
+ git.packRefs().call();
+ assertEquals(Ref.Storage.PACKED,
+ git.getRepository().exactRef("refs/tags/test").getStorage());
+ }
+
+ @Test
+ public void nonTagRefNotPackedWithoutAll() throws Exception {
+ git.branchCreate().setName("test").call();
+ git.packRefs().call();
+ assertEquals(Ref.Storage.LOOSE,
+ git.getRepository().exactRef("refs/heads/test").getStorage());
+ }
+
+ @Test
+ public void nonTagRefPackedWithAll() throws Exception {
+ git.branchCreate().setName("test").call();
+ git.packRefs().setAll(true).call();
+ assertEquals(Ref.Storage.PACKED,
+ git.getRepository().exactRef("refs/heads/test").getStorage());
+ }
+
+ @Test
+ public void refTableCompacted() throws Exception {
+ ((FileRepository) git.getRepository()).convertRefStorage(
+ ConfigConstants.CONFIG_REF_STORAGE_REFTABLE, false, false);
+
+ git.commit().setMessage("test commit").call();
+ File tableDir = new File(db.getDirectory(), Constants.REFTABLE);
+ File[] reftables = tableDir.listFiles();
+ assertNotNull(reftables);
+ assertTrue(reftables.length > 2);
+
+ git.packRefs().call();
+
+ reftables = tableDir.listFiles();
+ assertNotNull(reftables);
+ assertEquals(2, reftables.length);
+ }
+}
diff --git a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
index 08d37278de..41b0091b77 100644
--- a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
+++ b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
@@ -26,6 +26,7 @@ org.eclipse.jgit.pgm.LsTree
org.eclipse.jgit.pgm.Merge
org.eclipse.jgit.pgm.MergeBase
org.eclipse.jgit.pgm.MergeTool
+org.eclipse.jgit.pgm.PackRefs
org.eclipse.jgit.pgm.Push
org.eclipse.jgit.pgm.ReceivePack
org.eclipse.jgit.pgm.Reflog
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 50ee809b98..d24b639a31 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
@@ -257,6 +257,7 @@ updating=Updating {0}..{1}
usage_Abbrev=Instead of using the default number of hexadecimal digits (which will vary according to the number of objects in the repository with a default of 7) of the abbreviated object name, use <n> digits, or as many digits as needed to form a unique object name. An <n> of 0 will suppress long format, only showing the closest tag.
usage_addRenormalize=Apply the "clean" process freshly to tracked files to forcibly add them again to the index. This implies -u.
usage_Aggressive=This option will cause gc to more aggressively optimize the repository at the expense of taking much more time
+usage_All=Pack all refs, except hidden refs, broken refs, and symbolic refs.
usage_AlwaysFallback=Show uniquely abbreviated commit object as fallback
usage_bareClone=Make a bare Git repository. That is, instead of creating [DIRECTORY] and placing the administrative files in [DIRECTORY]/.git, make the [DIRECTORY] itself the $GIT_DIR.
usage_extraArgument=Pass an extra argument to a merge driver. Currently supported are "-X ours" and "-X theirs".
@@ -300,6 +301,7 @@ usage_Match=Only consider tags matching the given glob(7) pattern or patterns, e
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_PackRefs=Pack heads and tags for efficient repository access
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/PackRefs.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/PackRefs.java
new file mode 100644
index 0000000000..ee05f5ca0b
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/PackRefs.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * 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.pgm;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.kohsuke.args4j.Option;
+
+@Command(common = true, usage = "usage_PackRefs")
+class PackRefs extends TextBuiltin {
+ @Option(name = "--all", usage = "usage_All")
+ private boolean all;
+
+ @Override
+ protected void run() {
+ Git git = Git.wrap(db);
+ try {
+ git.packRefs().setProgressMonitor(new TextProgressMonitor(errw))
+ .setAll(all).call();
+ } catch (GitAPIException e) {
+ throw die(e.getMessage(), e);
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
index c57295518d..f84be21e82 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
@@ -19,7 +19,6 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import java.io.File;
-import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.BrokenBarrierException;
@@ -31,6 +30,8 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.PackRefsCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
@@ -49,7 +50,7 @@ public class GcPackRefsTest extends GcTestCase {
RevBlob a = tr.blob("a");
tr.lightweightTag("t", a);
- gc.packRefs();
+ packRefs(false);
assertSame(repo.exactRef("refs/tags/t").getStorage(), Storage.PACKED);
}
@@ -60,7 +61,7 @@ public class GcPackRefsTest extends GcTestCase {
String name = repo.findRef(ref).getName();
Path dir = repo.getCommonDirectory().toPath().resolve(name).getParent();
assertNotNull(dir);
- gc.packRefs();
+ packRefs(true);
assertFalse(Files.exists(dir));
}
@@ -75,9 +76,9 @@ public class GcPackRefsTest extends GcTestCase {
Callable<Integer> packRefs = () -> {
syncPoint.await();
try {
- gc.packRefs();
+ packRefs(false);
return 0;
- } catch (IOException e) {
+ } catch (GitAPIException e) {
return 1;
}
};
@@ -102,7 +103,7 @@ public class GcPackRefsTest extends GcTestCase {
"refs/tags/t1"));
try {
refLock.lock();
- gc.packRefs();
+ packRefs(false);
} finally {
refLock.unlock();
}
@@ -145,7 +146,7 @@ public class GcPackRefsTest extends GcTestCase {
Future<Result> result2 = pool.submit(() -> {
refUpdateLockedRef.await();
- gc.packRefs();
+ packRefs(false);
packRefsDone.await();
return null;
});
@@ -173,19 +174,20 @@ public class GcPackRefsTest extends GcTestCase {
assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master");
assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
- gc.packRefs();
+ PackRefsCommand packRefsCommand = git.packRefs().setAll(true);
+ packRefsCommand.call();
assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master");
assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
git.checkout().setName("refs/heads/side").call();
- gc.packRefs();
+ packRefsCommand.call();
assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
// check for detached HEAD
git.checkout().setName(first.getName()).call();
- gc.packRefs();
+ packRefsCommand.call();
assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
}
@@ -208,7 +210,7 @@ public class GcPackRefsTest extends GcTestCase {
assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master");
assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
- gc.packRefs();
+ packRefs(true);
assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master");
@@ -216,9 +218,14 @@ public class GcPackRefsTest extends GcTestCase {
// check for non-detached HEAD
repo.updateRef(Constants.HEAD).link("refs/heads/side");
- gc.packRefs();
+ packRefs(true);
assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
assertEquals(repo.exactRef("HEAD").getTarget().getObjectId(),
second.getId());
}
+
+ private void packRefs(boolean all) throws GitAPIException {
+ new PackRefsCommand(repo).setAll(all).call();
+ }
+
}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 024ca77f21..acfe812a20 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -597,6 +597,8 @@ packInaccessible=Failed to access pack file {0}, caught {1} consecutive errors w
packingCancelledDuringObjectsWriting=Packing cancelled during objects writing
packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2}
packRefs=Pack refs
+packRefsFailed=Packing refs failed
+packRefsSuccessful=Packed refs successfully
packSizeNotSetYet=Pack size not yet set since it has not yet been received
packTooLargeForIndexVersion1=Pack too large for index version 1
packWasDeleted=Pack file {0} was deleted, removing it from pack list
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
index 3dc53ec248..5bc035a46a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
@@ -714,6 +714,16 @@ public class Git implements AutoCloseable {
}
/**
+ * Return a command object to execute a {@code PackRefs} command
+ *
+ * @return a {@link org.eclipse.jgit.api.PackRefsCommand}
+ * @since 7.1
+ */
+ public PackRefsCommand packRefs() {
+ return new PackRefsCommand(repo);
+ }
+
+ /**
* Return a command object to find human-readable names of revisions.
*
* @return a {@link org.eclipse.jgit.api.NameRevCommand}.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PackRefsCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PackRefsCommand.java
new file mode 100644
index 0000000000..29a69c5ac4
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PackRefsCommand.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * 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.api;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * Optimize storage of references.
+ *
+ * @since 7.1
+ */
+public class PackRefsCommand extends GitCommand<String> {
+ private ProgressMonitor monitor;
+
+ private boolean all;
+
+ /**
+ * Creates a new {@link PackRefsCommand} instance with default values.
+ *
+ * @param repo
+ * the repository this command will be used on
+ */
+ public PackRefsCommand(Repository repo) {
+ super(repo);
+ this.monitor = NullProgressMonitor.INSTANCE;
+ }
+
+ /**
+ * Set progress monitor
+ *
+ * @param monitor
+ * a progress monitor
+ * @return this instance
+ */
+ public PackRefsCommand setProgressMonitor(ProgressMonitor monitor) {
+ this.monitor = monitor;
+ return this;
+ }
+
+ /**
+ * Specify whether to pack all the references.
+ *
+ * @param all
+ * if <code>true</code> all the loose refs will be packed
+ * @return this instance
+ */
+ public PackRefsCommand setAll(boolean all) {
+ this.all = all;
+ return this;
+ }
+
+ /**
+ * Whether to pack all the references
+ *
+ * @return whether to pack all the references
+ */
+ public boolean isAll() {
+ return all;
+ }
+
+ @Override
+ public String call() throws GitAPIException {
+ checkCallable();
+ try {
+ repo.getRefDatabase().packRefs(monitor, this);
+ return JGitText.get().packRefsSuccessful;
+ } catch (IOException e) {
+ throw new JGitInternalException(JGitText.get().packRefsFailed, e);
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 0980219e25..2d9d2c527c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -627,6 +627,8 @@ public class JGitText extends TranslationBundle {
/***/ public String packingCancelledDuringObjectsWriting;
/***/ public String packObjectCountMismatch;
/***/ public String packRefs;
+ /***/ public String packRefsFailed;
+ /***/ public String packRefsSuccessful;
/***/ public String packSizeNotSetYet;
/***/ public String packTooLargeForIndexVersion1;
/***/ public String packWasDeleted;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
index 80240e5062..25b7583b95 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
@@ -28,8 +28,10 @@ import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.api.PackRefsCommand;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.events.RefsChangedEvent;
+import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.reftable.MergedReftable;
import org.eclipse.jgit.internal.storage.reftable.ReftableBatchRefUpdate;
import org.eclipse.jgit.internal.storage.reftable.ReftableDatabase;
@@ -39,6 +41,7 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.RefRename;
@@ -108,6 +111,22 @@ public class FileReftableDatabase extends RefDatabase {
}
/**
+ * {@inheritDoc}
+ *
+ * For Reftable, all the data is compacted into a single table.
+ */
+ @Override
+ public void packRefs(ProgressMonitor pm, PackRefsCommand packRefs)
+ throws IOException {
+ pm.beginTask(JGitText.get().packRefs, 1);
+ try {
+ compactFully();
+ } finally {
+ pm.endTask();
+ }
+ }
+
+ /**
* Runs a full compaction for GC purposes.
* @throws IOException on I/O errors
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
index 230dc6f45a..84c85659ff 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
@@ -33,6 +33,7 @@ import java.util.Set;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.attributes.AttributesNode;
import org.eclipse.jgit.attributes.AttributesNodeProvider;
@@ -599,7 +600,7 @@ public class FileRepository extends Repository {
gc.setBackground(shouldAutoDetach());
try {
gc.gc();
- } catch (ParseException | IOException e) {
+ } catch (ParseException | IOException | GitAPIException e) {
throw new JGitInternalException(JGitText.get().gcFailed, e);
}
}
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 c9da4d8d67..7f3369364b 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
@@ -63,6 +63,8 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.api.PackRefsCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.CancelledException;
import org.eclipse.jgit.errors.CorruptObjectException;
@@ -233,9 +235,11 @@ public class GC {
* @throws java.text.ParseException
* If the configuration parameter "gc.pruneexpire" couldn't be
* parsed
+ * @throws GitAPIException
+ * If packing refs failed
*/
public CompletableFuture<Collection<Pack>> gc()
- throws IOException, ParseException {
+ throws IOException, ParseException, GitAPIException {
if (!background) {
return CompletableFuture.completedFuture(doGc());
}
@@ -254,7 +258,7 @@ public class GC {
gcLog.commit();
}
return newPacks;
- } catch (IOException | ParseException e) {
+ } catch (IOException | ParseException | GitAPIException e) {
try {
gcLog.write(e.getMessage());
StringWriter sw = new StringWriter();
@@ -277,7 +281,8 @@ public class GC {
return (executor != null) ? executor : WorkQueue.getExecutor();
}
- private Collection<Pack> doGc() throws IOException, ParseException {
+ private Collection<Pack> doGc()
+ throws IOException, ParseException, GitAPIException {
if (automatic && !needGc()) {
return Collections.emptyList();
}
@@ -286,7 +291,8 @@ public class GC {
return Collections.emptyList();
}
pm.start(6 /* tasks */);
- packRefs();
+ new PackRefsCommand(repo).setProgressMonitor(pm).setAll(true)
+ .call();
// TODO: implement reflog_expire(pm, repo);
Collection<Pack> newPacks = repack();
prune(Collections.emptySet());
@@ -780,43 +786,6 @@ public class GC {
}
/**
- * Pack ref storage. For a RefDirectory database, this packs all
- * non-symbolic, loose refs into packed-refs. For Reftable, all of the data
- * is compacted into a single table.
- *
- * @throws java.io.IOException
- * if an IO error occurred
- */
- public void packRefs() throws IOException {
- RefDatabase refDb = repo.getRefDatabase();
- if (refDb instanceof FileReftableDatabase) {
- // TODO: abstract this more cleanly.
- pm.beginTask(JGitText.get().packRefs, 1);
- try {
- ((FileReftableDatabase) refDb).compactFully();
- } finally {
- pm.endTask();
- }
- return;
- }
-
- Collection<Ref> refs = refDb.getRefsByPrefix(Constants.R_REFS);
- List<String> refsToBePacked = new ArrayList<>(refs.size());
- pm.beginTask(JGitText.get().packRefs, refs.size());
- try {
- for (Ref ref : refs) {
- checkCancelled();
- if (!ref.isSymbolic() && ref.getStorage().isLoose())
- refsToBePacked.add(ref.getName());
- pm.update(1);
- }
- ((RefDirectory) repo.getRefDatabase()).pack(refsToBePacked);
- } finally {
- pm.endTask();
- }
- }
-
- /**
* Packs all objects which reachable from any of the heads into one pack
* file. Additionally all objects which are not reachable from any head but
* which are reachable from any of the other refs (e.g. tags), special refs
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index 604868133e..6aa1157e37 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -57,6 +57,7 @@ import java.util.stream.Stream;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.PackRefsCommand;
import org.eclipse.jgit.errors.InvalidObjectIdException;
import org.eclipse.jgit.errors.LockFailedException;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -69,6 +70,7 @@ import org.eclipse.jgit.lib.CoreConfig.TrustLooseRefStat;
import org.eclipse.jgit.lib.CoreConfig.TrustPackedRefsStat;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefComparator;
import org.eclipse.jgit.lib.RefDatabase;
@@ -287,6 +289,33 @@ public class RefDirectory extends RefDatabase {
clearReferences();
}
+ /**
+ * {@inheritDoc}
+ *
+ * For a RefDirectory database, by default this packs non-symbolic, loose
+ * tag refs into packed-refs. If {@code all} flag is set, this packs all the
+ * non-symbolic, loose refs.
+ */
+ @Override
+ public void packRefs(ProgressMonitor pm, PackRefsCommand packRefs)
+ throws IOException {
+ String prefix = packRefs.isAll() ? R_REFS : R_TAGS;
+ Collection<Ref> refs = getRefsByPrefix(prefix);
+ List<String> refsToBePacked = new ArrayList<>(refs.size());
+ pm.beginTask(JGitText.get().packRefs, refs.size());
+ try {
+ for (Ref ref : refs) {
+ if (!ref.isSymbolic() && ref.getStorage().isLoose()) {
+ refsToBePacked.add(ref.getName());
+ }
+ pm.update(1);
+ }
+ pack(refsToBePacked);
+ } finally {
+ pm.endTask();
+ }
+ }
+
@Override
public boolean isNameConflicting(String name) throws IOException {
// Cannot be nested within an existing reference.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
index 114246beb2..09cb5a83dd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
@@ -26,6 +26,7 @@ import java.util.stream.Stream;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.PackRefsCommand;
/**
* Abstraction of name to {@link org.eclipse.jgit.lib.ObjectId} mapping.
@@ -593,4 +594,22 @@ public abstract class RefDatabase {
}
return null;
}
+
+ /**
+ * Optimize pack ref storage.
+ *
+ * @param pm
+ * a progress monitor
+ *
+ * @param packRefs
+ * {@link PackRefsCommand} to control ref packing behavior
+ *
+ * @throws java.io.IOException
+ * if an IO error occurred
+ * @since 7.1
+ */
+ public void packRefs(ProgressMonitor pm, PackRefsCommand packRefs)
+ throws IOException {
+ // nothing
+ }
}