JGit documentation and API reference with code examples
92
Pending
Does it follow best practices?
Impact
92%
1.09xAverage score across 10 eval scenarios
Pending
The risk profile of this skill
This section covers common patterns, best practices, and real-world usage scenarios for JGit.
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import java.io.File;
import java.io.IOException;
public class RepositoryLifecycle {
/**
* Safe repository access pattern using try-with-resources
*/
public static void withRepository(String repoPath, RepositoryOperation operation)
throws IOException {
FileRepositoryBuilder builder = new FileRepositoryBuilder();
try (Repository repository = builder
.setGitDir(new File(repoPath, ".git"))
.readEnvironment()
.findGitDir()
.setMustExist(true)
.build()) {
operation.execute(repository);
}
}
/**
* Repository operation interface
*/
@FunctionalInterface
public interface RepositoryOperation {
void execute(Repository repository) throws Exception;
}
/**
* Example usage
*/
public static void main(String[] args) {
try {
withRepository("/path/to/repo", repo -> {
System.out.println("Repository: " + repo.getDirectory());
System.out.println("Work tree: " + repo.getWorkTree());
System.out.println("Is bare: " + repo.isBare());
// Perform repository operations
// ...
});
} catch (IOException e) {
System.err.println("Failed to access repository: " + e.getMessage());
}
}
}import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import java.io.File;
import java.io.IOException;
import java.util.function.Supplier;
public class RepositoryFactory {
private final String basePath;
public RepositoryFactory(String basePath) {
this.basePath = basePath;
}
/**
* Create repository supplier for lazy initialization
*/
public Supplier<Repository> createRepositorySupplier(String repoName) {
return () -> {
try {
return new FileRepositoryBuilder()
.setGitDir(new File(basePath, repoName + "/.git"))
.setMustExist(true)
.build();
} catch (IOException e) {
throw new RuntimeException("Failed to open repository: " + repoName, e);
}
};
}
/**
* Create repository with retry logic
*/
public Repository createRepositoryWithRetry(String repoName, int maxRetries)
throws IOException {
IOException lastException = null;
for (int i = 0; i < maxRetries; i++) {
try {
return new FileRepositoryBuilder()
.setGitDir(new File(basePath, repoName + "/.git"))
.build();
} catch (IOException e) {
lastException = e;
if (i < maxRetries - 1) {
try {
Thread.sleep(100 * (i + 1)); // Exponential backoff
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted during retry", ie);
}
}
}
}
throw lastException;
}
}import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import java.io.File;
import java.io.IOException;
public class GitErrorHandling {
public enum GitOperation {
CLONE, PUSH, PULL, FETCH, COMMIT, MERGE
}
/**
* Execute Git operation with comprehensive error handling
*/
public static <T> T executeGitOperation(
GitOperation operation,
GitOperationExecutor<T> executor,
ErrorHandler errorHandler) {
try {
return executor.execute();
} catch (RepositoryNotFoundException e) {
return errorHandler.handleRepositoryNotFound(operation, e);
} catch (GitAPIException e) {
return errorHandler.handleGitApiError(operation, e);
} catch (IOException e) {
return errorHandler.handleIoError(operation, e);
} catch (Exception e) {
return errorHandler.handleUnexpectedError(operation, e);
}
}
@FunctionalInterface
public interface GitOperationExecutor<T> {
T execute() throws Exception;
}
public interface ErrorHandler<T> {
T handleRepositoryNotFound(GitOperation operation, RepositoryNotFoundException e);
T handleGitApiError(GitOperation operation, GitAPIException e);
T handleIoError(GitOperation operation, IOException e);
T handleUnexpectedError(GitOperation operation, Exception e);
}
/**
* Example error handler implementation
*/
public static class LoggingErrorHandler<T> implements ErrorHandler<T> {
private final T defaultValue;
public LoggingErrorHandler(T defaultValue) {
this.defaultValue = defaultValue;
}
@Override
public T handleRepositoryNotFound(GitOperation operation,
RepositoryNotFoundException e) {
System.err.println("Repository not found for " + operation + ": " + e.getMessage());
return defaultValue;
}
@Override
public T handleGitApiError(GitOperation operation, GitAPIException e) {
System.err.println("Git API error during " + operation + ": " + e.getMessage());
return defaultValue;
}
@Override
public T handleIoError(GitOperation operation, IOException e) {
System.err.println("IO error during " + operation + ": " + e.getMessage());
return defaultValue;
}
@Override
public T handleUnexpectedError(GitOperation operation, Exception e) {
System.err.println("Unexpected error during " + operation + ": " + e.getMessage());
e.printStackTrace();
return defaultValue;
}
}
}import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
public class RetryPattern {
/**
* Execute operation with exponential backoff retry
*/
public static <T> T executeWithRetry(
Callable<T> operation,
int maxRetries,
long initialDelayMs,
Class<? extends Exception>... retryableExceptions) throws Exception {
Exception lastException = null;
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
return operation.call();
} catch (Exception e) {
lastException = e;
// Check if exception is retryable
boolean shouldRetry = false;
for (Class<? extends Exception> retryable : retryableExceptions) {
if (retryable.isInstance(e)) {
shouldRetry = true;
break;
}
}
if (!shouldRetry || attempt == maxRetries) {
break;
}
// Exponential backoff
long delay = initialDelayMs * (1L << (attempt - 1));
System.out.println("Attempt " + attempt + " failed, retrying in " +
delay + "ms: " + e.getMessage());
try {
TimeUnit.MILLISECONDS.sleep(delay);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted during retry", ie);
}
}
}
throw lastException;
}
/**
* Example: Fetch with retry for network issues
*/
public static void fetchWithRetry(Repository repository) throws Exception {
executeWithRetry(() -> {
try (Git git = new Git(repository)) {
git.fetch().call();
return null;
}
}, 3, 1000, TransportException.class);
}
}import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class BatchOperations {
/**
* Batch commit multiple files
*/
public static void commitMultipleFiles(
Repository repository,
List<String> filePaths,
String commitMessage) throws IOException, GitAPIException {
try (Git git = new Git(repository)) {
// Add all files
for (String filePath : filePaths) {
git.add()
.addFilepattern(filePath)
.call();
}
// Single commit
git.commit()
.setMessage(commitMessage)
.call();
}
}
/**
* Process commits in batches
*/
public static void processCommitsInBatches(
Repository repository,
int batchSize,
CommitProcessor processor) throws IOException {
try (Git git = new Git(repository)) {
var commits = git.log().all().call();
List<Object> batch = new ArrayList<>();
for (var commit : commits) {
batch.add(commit);
if (batch.size() >= batchSize) {
processor.process(batch);
batch.clear();
}
}
// Process remaining commits
if (!batch.isEmpty()) {
processor.process(batch);
}
}
}
@FunctionalInterface
public interface CommitProcessor {
void process(List<Object> commits) throws IOException;
}
}import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
import java.util.concurrent.*;
public class GitCache {
private final Repository repository;
private final Cache<ObjectId, byte[]> blobCache;
private final Cache<String, ObjectId> refCache;
public GitCache(Repository repository, int maxSize) {
this.repository = repository;
this.blobCache = new ConcurrentCache<>(maxSize);
this.refCache = new ConcurrentCache<>(maxSize);
}
/**
* Get blob content with caching
*/
public byte[] getBlobContent(ObjectId blobId) throws IOException {
byte[] content = blobCache.get(blobId);
if (content == null) {
content = repository.open(blobId).getBytes();
blobCache.put(blobId, content);
}
return content;
}
/**
* Resolve reference with caching
*/
public ObjectId resolveRef(String refName) throws IOException {
ObjectId objectId = refCache.get(refName);
if (objectId == null) {
objectId = repository.resolve(refName);
if (objectId != null) {
refCache.put(refName, objectId);
}
}
return objectId;
}
/**
* Clear cache
*/
public void clear() {
blobCache.clear();
refCache.clear();
}
/**
* Simple cache interface
*/
private interface Cache<K, V> {
V get(K key);
void put(K key, V value);
void clear();
}
/**
* Concurrent cache implementation using LinkedHashMap
*/
private static class ConcurrentCache<K, V> implements Cache<K, V> {
private final ConcurrentHashMap<K, V> cache;
private final int maxSize;
public ConcurrentCache(int maxSize) {
this.maxSize = maxSize;
this.cache = new ConcurrentHashMap<>();
}
@Override
public V get(K key) {
return cache.get(key);
}
@Override
public void put(K key, V value) {
if (cache.size() >= maxSize) {
// Simple eviction: remove first entry (FIFO)
if (!cache.isEmpty()) {
cache.remove(cache.keys().nextElement());
}
}
cache.put(key, value);
}
@Override
public void clear() {
cache.clear();
}
}
}import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ThreadSafeRepository {
private final Repository repository;
private final ReadWriteLock lock;
public ThreadSafeRepository(Repository repository) {
this.repository = repository;
this.lock = new ReentrantReadWriteLock();
}
/**
* Execute read operation with shared lock
*/
public <T> T read(RepositoryReadOperation<T> operation) throws IOException {
lock.readLock().lock();
try {
return operation.execute(repository);
} finally {
lock.readLock().unlock();
}
}
/**
* Execute write operation with exclusive lock
*/
public <T> T write(RepositoryWriteOperation<T> operation) throws IOException {
lock.writeLock().lock();
try {
return operation.execute(repository);
} finally {
lock.writeLock().unlock();
}
}
@FunctionalInterface
public interface RepositoryReadOperation<T> {
T execute(Repository repository) throws IOException;
}
@FunctionalInterface
public interface RepositoryWriteOperation<T> {
T execute(Repository repository) throws IOException;
}
/**
* Close repository safely
*/
public void close() {
lock.writeLock().lock();
try {
repository.close();
} finally {
lock.writeLock().unlock();
}
}
}import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
import java.util.concurrent.*;
public class ConcurrentGitOperations {
private final ExecutorService executor;
private final Repository repository;
public ConcurrentGitOperations(Repository repository, int threadPoolSize) {
this.repository = repository;
this.executor = Executors.newFixedThreadPool(threadPoolSize);
}
/**
* Execute multiple Git operations concurrently
*/
public List<Future<?>> executeConcurrently(List<Runnable> operations) {
List<Future<?>> futures = new ArrayList<>();
for (Runnable operation : operations) {
futures.add(executor.submit(() -> {
try (Git git = new Git(repository)) {
operation.run();
} catch (Exception e) {
System.err.println("Error in concurrent operation: " + e.getMessage());
throw new RuntimeException(e);
}
}));
}
return futures;
}
/**
* Wait for all operations to complete
*/
public void awaitCompletion(List<Future<?>> futures, long timeout, TimeUnit unit)
throws InterruptedException, TimeoutException, ExecutionException {
for (Future<?> future : futures) {
future.get(timeout, unit);
}
}
/**
* Shutdown executor
*/
public void shutdown() {
executor.shutdown();
try {
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ResourceCleanup {
/**
* AutoCloseable wrapper for multiple resources
*/
public static class GitResources implements AutoCloseable {
private final List<AutoCloseable> resources;
public GitResources() {
this.resources = new ArrayList<>();
}
public <T extends AutoCloseable> T register(T resource) {
resources.add(resource);
return resource;
}
@Override
public void close() {
// Close in reverse order (LIFO)
for (int i = resources.size() - 1; i >= 0; i--) {
try {
resources.get(i).close();
} catch (Exception e) {
System.err.println("Error closing resource: " + e.getMessage());
}
}
resources.clear();
}
}
/**
* Safe resource usage example
*/
public static void processRepositorySafely(Repository repository) throws IOException {
try (GitResources resources = new GitResources()) {
// Register all resources
Git git = resources.register(new Git(repository));
RevWalk walk = resources.register(new RevWalk(repository));
TreeWalk treeWalk = resources.register(new TreeWalk(repository));
// Use resources
ObjectId headId = repository.resolve("HEAD");
RevCommit head = walk.parseCommit(headId);
treeWalk.addTree(head.getTree());
while (treeWalk.next()) {
// Process tree entries
System.out.println(treeWalk.getPathString());
}
// Resources will be auto-closed in reverse order
}
}
}import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import java.io.IOException;
import java.util.Iterator;
public class LargeRepositoryHandler {
/**
* Process large commit history in chunks
*/
public static void processLargeCommitHistory(
Repository repository,
int chunkSize,
CommitChunkProcessor processor) throws IOException, GitAPIException {
try (Git git = new Git(repository)) {
Iterator<RevCommit> commits = git.log().all().call().iterator();
while (commits.hasNext()) {
List<RevCommit> chunk = new ArrayList<>();
// Collect chunk
for (int i = 0; i < chunkSize && commits.hasNext(); i++) {
chunk.add(commits.next());
}
// Process chunk
processor.process(chunk);
// Hint to GC
if (chunk.size() == chunkSize) {
System.gc();
}
}
}
}
@FunctionalInterface
public interface CommitChunkProcessor {
void process(List<RevCommit> chunk) throws IOException;
}
/**
* Memory-efficient file processing
*/
public static void processFilesEfficiently(
Repository repository,
FileProcessor processor) throws IOException {
// Use streaming where possible
// Process files one at a time to avoid loading everything into memory
try (Git git = new Git(repository)) {
var commits = git.log().setMaxCount(1).call();
var commit = commits.iterator().next();
try (var treeWalk = new TreeWalk(repository)) {
treeWalk.addTree(commit.getTree());
treeWalk.setRecursive(true);
while (treeWalk.next()) {
// Load file content only when needed
byte[] content = repository.open(treeWalk.getObjectId(0)).getBytes();
processor.process(treeWalk.getPathString(), content);
// Clear reference to allow GC
content = null;
// Periodically hint GC for large repositories
if (treeWalk.getTreeCount() % 1000 == 0) {
System.gc();
}
}
}
}
}
@FunctionalInterface
public interface FileProcessor {
void process(String path, byte[] content) throws IOException;
}
}import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import java.io.File;
import java.io.IOException;
public class BuildSystemIntegration {
/**
* Git information for build metadata
*/
public static class BuildMetadata {
private final String commitId;
private final String branch;
private final String tag;
private final boolean dirty;
private final String commitMessage;
public BuildMetadata(String commitId, String branch, String tag,
boolean dirty, String commitMessage) {
this.commitId = commitId;
this.branch = branch;
this.tag = tag;
this.dirty = dirty;
this.commitMessage = commitMessage;
}
// Getters and utility methods
public String getVersionString() {
return tag != null ? tag : commitId.substring(0, 8) + (dirty ? "-dirty" : "");
}
}
/**
* Extract build metadata from Git
*/
public static BuildMetadata extractBuildMetadata(Repository repository)
throws IOException, GitAPIException {
try (Git git = new Git(repository)) {
// Get current commit
String commitId = repository.resolve("HEAD").getName();
// Get branch
String branch = repository.getBranch();
// Check if working tree is dirty
boolean dirty = !git.status().call().isClean();
// Get commit message
String commitMessage = git.log().setMaxCount(1).call()
.iterator().next().getFullMessage();
// Try to find tag
String tag = findTagForCommit(repository, commitId);
return new BuildMetadata(commitId, branch, tag, dirty, commitMessage);
}
}
private static String findTagForCommit(Repository repository, String commitId)
throws GitAPIException {
try (Git git = new Git(repository)) {
for (var ref : git.tagList().call()) {
if (ref.getObjectId().getName().startsWith(commitId)) {
return ref.getName().replace("refs/tags/", "");
}
}
}
return null;
}
}import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
public class CiCdIntegration {
/**
* Generate build properties from Git
*/
public static Properties generateBuildProperties(Repository repository)
throws IOException, GitAPIException {
Properties props = new Properties();
try (Git git = new Git(repository)) {
// Basic Git info
props.setProperty("git.commit.id", repository.resolve("HEAD").getName());
props.setProperty("git.branch", repository.getBranch());
// Commit info
var commit = git.log().setMaxCount(1).call().iterator().next();
props.setProperty("git.commit.message", commit.getShortMessage());
props.setProperty("git.commit.user.name", commit.getAuthorIdent().getName());
props.setProperty("git.commit.user.email", commit.getAuthorIdent().getEmailAddress());
props.setProperty("git.commit.time", commit.getAuthorIdent().getWhen().toString());
// Repository state
boolean isClean = git.status().call().isClean();
props.setProperty("git.dirty", String.valueOf(!isClean));
// Remote URL if available
var config = repository.getConfig();
String remoteUrl = config.getString("remote", "origin", "url");
if (remoteUrl != null) {
props.setProperty("git.remote.origin.url", remoteUrl);
}
}
return props;
}
/**
* Create Git tag for release
*/
public static void tagRelease(
Repository repository,
String version,
String message,
boolean annotated) throws GitAPIException {
try (Git git = new Git(repository)) {
if (annotated) {
git.tag()
.setName(version)
.setMessage(message)
.call();
} else {
git.tag()
.setName(version)
.call();
}
// Push tag to remote
git.push()
.setPushTags()
.call();
}
}
}import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class GitTestUtils {
/**
* Create temporary test repository
*/
public static TestRepository createTestRepository() throws IOException, GitAPIException {
Path tempDir = Files.createTempDirectory("jgit-test-");
File repoDir = tempDir.toFile();
try (Git git = Git.init().setDirectory(repoDir).call()) {
// Create initial commit
File readme = new File(repoDir, "README.md");
Files.writeString(readme.toPath(), "# Test Repository\n");
git.add().addFilepattern("README.md").call();
git.commit().setMessage("Initial commit").call();
return new TestRepository(git.getRepository(), tempDir);
}
}
public static class TestRepository implements AutoCloseable {
private final Repository repository;
private final Path tempDir;
public TestRepository(Repository repository, Path tempDir) {
this.repository = repository;
this.tempDir = tempDir;
}
public Repository getRepository() {
return repository;
}
public Path getTempDir() {
return tempDir;
}
@Override
public void close() throws Exception {
repository.close();
// Delete temporary directory
deleteRecursively(tempDir.toFile());
}
private void deleteRecursively(File file) {
if (file.isDirectory()) {
for (File child : file.listFiles()) {
deleteRecursively(child);
}
}
file.delete();
}
}
/**
* Create test repository with specific content
*/
public static Repository createRepositoryWithContent(
File repoDir,
String... fileContents) throws IOException, GitAPIException {
try (Git git = Git.init().setDirectory(repoDir).call()) {
for (int i = 0; i < fileContents.length; i++) {
File file = new File(repoDir, "file" + i + ".txt");
Files.writeString(file.toPath(), fileContents[i]);
git.add().addFilepattern("file" + i + ".txt").call();
git.commit().setMessage("Add file " + i).call();
}
return git.getRepository();
}
}
}import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
public class MockRepositoryExample {
/**
* Repository interface for testing
*/
public interface TestableRepository {
String getBranch() throws IOException;
boolean isBare();
// Add other methods needed for testing
}
/**
* Real repository wrapper
*/
public static class RealRepositoryWrapper implements TestableRepository {
private final Repository repository;
public RealRepositoryWrapper(Repository repository) {
this.repository = repository;
}
@Override
public String getBranch() throws IOException {
return repository.getBranch();
}
@Override
public boolean isBare() {
return repository.isBare();
}
}
/**
* Mock repository for unit tests
*/
public static class MockRepository implements TestableRepository {
private final String branch;
private final boolean bare;
public MockRepository(String branch, boolean bare) {
this.branch = branch;
this.bare = bare;
}
@Override
public String getBranch() {
return branch;
}
@Override
public boolean isBare() {
return bare;
}
}
}The RevWalk class is designed to be lightweight, but can still consume significant memory when walking large commit graphs. This section provides techniques to reduce memory usage when working with revision walks.
Only walk the portion of the graph you actually need. Use markStart() for the starting point and markUninteresting() for commits you don't need to traverse.
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.lib.ObjectId;
import java.io.IOException;
public class RestrictedRevWalkExample {
public static void walkRestrictedGraph(Repository repository) throws IOException {
RevWalk walk = new RevWalk(repository);
// Only walk commits in master not yet in origin/master
ObjectId from = repository.resolve("refs/heads/master");
ObjectId to = repository.resolve("refs/remotes/origin/master");
walk.markStart(walk.parseCommit(from));
walk.markUninteresting(walk.parseCommit(to));
for (RevCommit commit : walk) {
// Process commits between from and to
System.out.println(commit.getShortMessage());
}
walk.dispose();
}
}If you don't need author, committer, or message information, disable retaining commit bodies.
public class RevWalkWithoutBodies {
public static void walkWithoutCommitBodies(Repository repository) throws IOException {
RevWalk walk = new RevWalk(repository);
walk.setRetainBody(false); // Discard commit bodies
walk.markStart(walk.parseCommit(repository.resolve("HEAD")));
for (RevCommit commit : walk) {
// Can access commit ID but not message/author info
System.out.println("Commit: " + commit.getId().getName());
// commit.getFullMessage() would throw exception
}
walk.dispose();
}
}Extract only the data you need from commits, then call dispose() to release memory.
import java.util.HashSet;
import java.util.Set;
public class ExtractAndDisposeExample {
public static Set<String> collectAuthorEmails(Repository repository) throws IOException {
RevWalk walk = new RevWalk(repository);
Set<String> authorEmails = new HashSet<>();
walk.markStart(walk.parseCommit(repository.resolve("HEAD")));
for (RevCommit commit : walk) {
// Extract needed data
authorEmails.add(commit.getAuthorIdent().getEmailAddress());
commit.dispose(); // Release memory for this commit
}
walk.dispose();
return authorEmails;
}
}When you need to attach additional data to commits, subclass both RevWalk and RevCommit instead of using external maps.
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.lib.AnyObjectId;
import java.util.Date;
public class CustomRevWalkExample {
public static class ReviewedRevision extends RevCommit {
private final Date reviewDate;
public ReviewedRevision(AnyObjectId id, Date reviewDate) {
super(id);
this.reviewDate = reviewDate;
}
public Date getReviewDate() {
return reviewDate;
}
}
public static class ReviewedWalk extends RevWalk {
public ReviewedWalk(Repository repo) {
super(repo);
}
@Override
protected RevCommit createCommit(AnyObjectId id) {
// Create custom commit with review date
return new ReviewedRevision(id, getReviewDate(id));
}
private Date getReviewDate(AnyObjectId id) {
// Implementation to get review date from external source
return new Date();
}
}
}A RevWalk cannot shrink its internal object map. For large traversals, dispose of the walk and create a new one for subsequent operations.
public class RevWalkCleanup {
public static void processWithCleanup(Repository repository) throws IOException {
// First walk - loads everything into memory
RevWalk walk1 = new RevWalk(repository);
// ... perform walk ...
walk1.dispose(); // Allows GC to reclaim memory
// Second walk - fresh start, no accumulated objects
RevWalk walk2 = new RevWalk(repository);
// ... perform walk ...
walk2.dispose();
}
}RevWalk is faster but retains memory. Creating new walks reclaims memory but rebuilds object maps.setRetainBody(false) when you only need commit topology, not metadata.dispose() on individual commits when you've extracted needed data.markUninteresting() to avoid parsing unnecessary commits.RevWalk instances between batches.evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5