diff --git a/.bazelversion b/.bazelversion index 3eefcb9dd..7ec1d6db4 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -1.0.0 +2.1.0 diff --git a/WORKSPACE b/WORKSPACE index 5fd2ed90b..547c439bd 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -20,7 +20,7 @@ check_bazel_version() load("//tools:bazlets.bzl", "load_bazlets") -load_bazlets(commit = "09a035e98077dce549d5f6a7472d06c4b8f792d2") +load_bazlets(commit = "f30a992da9fc855dce819875afb59f9dd6f860cd") load( "@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java index cee898ab8..3d0dacab3 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java @@ -408,6 +408,7 @@ public class CloneCommandTest extends RepositoryTestCase { Git git2 = command.call(); addRepoToClose(git2.getRepository()); assertNotNull(git2); + assertTrue(git2.getRepository().isBare()); assertNotNull(git2.getRepository().resolve("tag-for-blob")); assertNotNull(git2.getRepository().resolve("tag-initial")); assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master"); @@ -448,6 +449,60 @@ public class CloneCommandTest extends RepositoryTestCase { specs.get(0)); } + @Test + public void testCloneRepositoryAllBranchesTakesPreference() + throws Exception { + File directory = createTempDirectory( + "testCloneRepositoryAllBranchesTakesPreference"); + CloneCommand command = Git.cloneRepository(); + command.setCloneAllBranches(true); + command.setBranchesToClone( + Collections.singletonList("refs/heads/test")); + command.setDirectory(directory); + command.setURI(fileUri()); + Git git2 = command.call(); + addRepoToClose(git2.getRepository()); + assertNotNull(git2); + assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test"); + // Expect both remote branches to exist; setCloneAllBranches(true) + // should override any setBranchesToClone(). + assertNotNull( + git2.getRepository().resolve("refs/remotes/origin/master")); + assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test")); + RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(), + Constants.DEFAULT_REMOTE_NAME); + List specs = cfg.getFetchRefSpecs(); + assertEquals(1, specs.size()); + assertEquals(new RefSpec("+refs/heads/*:refs/remotes/origin/*"), + specs.get(0)); + } + + @Test + public void testCloneRepositoryAllBranchesIndependent() throws Exception { + File directory = createTempDirectory( + "testCloneRepositoryAllBranchesIndependent"); + CloneCommand command = Git.cloneRepository(); + command.setCloneAllBranches(true); + command.setBranchesToClone( + Collections.singletonList("refs/heads/test")); + command.setCloneAllBranches(false); + command.setDirectory(directory); + command.setURI(fileUri()); + Git git2 = command.call(); + addRepoToClose(git2.getRepository()); + assertNotNull(git2); + assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test"); + // Expect only the test branch; allBranches was re-set to false + assertNull(git2.getRepository().resolve("refs/remotes/origin/master")); + assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test")); + RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(), + Constants.DEFAULT_REMOTE_NAME); + List specs = cfg.getFetchRefSpecs(); + assertEquals(1, specs.size()); + assertEquals(new RefSpec("+refs/heads/test:refs/remotes/origin/test"), + specs.get(0)); + } + public static String allRefNames(List refs) { StringBuilder sb = new StringBuilder(); for (Ref f : refs) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java index 9da35075d..b13cdb9fe 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java @@ -26,6 +26,7 @@ import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; @@ -509,6 +510,43 @@ public class FileReftableTest extends SampleDataRepositoryTestCase { assertEquals(RefUpdate.Result.LOCK_FAILURE, rename.rename()); } + @Test + public void compactFully() throws Exception { + FileReftableDatabase refDb = (FileReftableDatabase) db.getRefDatabase(); + PersonIdent person = new PersonIdent("jane", "jane@invalid"); + + ObjectId aId = db.exactRef("refs/heads/a").getObjectId(); + ObjectId bId = db.exactRef("refs/heads/b").getObjectId(); + + SecureRandom random = new SecureRandom(); + List strs = new ArrayList<>(); + for (int i = 0; i < 1024; i++) { + strs.add(String.format("%02x", + Integer.valueOf(random.nextInt(256)))); + } + + String randomStr = String.join("", strs); + String refName = "branch"; + for (long i = 0; i < 2; i++) { + RefUpdate ru = refDb.newUpdate(refName, false); + ru.setNewObjectId(i % 2 == 0 ? aId : bId); + ru.setForceUpdate(true); + // Only write a large string in the first table, so it becomes much larger + // than the second, and the result is not autocompacted. + ru.setRefLogMessage(i == 0 ? randomStr : "short", false); + ru.setRefLogIdent(person); + + RefUpdate.Result res = ru.update(); + assertTrue(res == Result.NEW || res == FORCED); + } + + assertEquals(refDb.exactRef(refName).getObjectId(), bId); + assertTrue(randomStr.equals(refDb.getReflogReader(refName).getReverseEntry(1).getComment())); + refDb.compactFully(); + assertEquals(refDb.exactRef(refName).getObjectId(), bId); + assertTrue(randomStr.equals(refDb.getReflogReader(refName).getReverseEntry(1).getComment())); + } + @Test public void reftableRefsStorageClass() throws IOException { Ref b = db.exactRef("refs/heads/b"); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java index 5232223c4..2525cbb58 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java @@ -71,7 +71,9 @@ public class CloneCommand extends TransportCommand { private ProgressMonitor monitor = NullProgressMonitor.INSTANCE; - private FETCH_TYPE fetchType = FETCH_TYPE.ALL_BRANCHES; + private boolean cloneAllBranches; + + private boolean mirror; private boolean cloneSubmodules; @@ -85,6 +87,8 @@ public class CloneCommand extends TransportCommand { private boolean gitDirExistsInitially; + private FETCH_TYPE fetchType; + private enum FETCH_TYPE { MULTIPLE_BRANCHES, ALL_BRANCHES, MIRROR } @@ -162,6 +166,7 @@ public class CloneCommand extends TransportCommand { throw new InvalidRemoteException( MessageFormat.format(JGitText.get().invalidURL, uri)); } + setFetchType(); @SuppressWarnings("resource") // Closed by caller Repository repository = init(); FetchResult fetchResult = null; @@ -205,6 +210,20 @@ public class CloneCommand extends TransportCommand { return new Git(repository, true); } + private void setFetchType() { + if (mirror) { + fetchType = FETCH_TYPE.MIRROR; + setBare(true); + } else if (cloneAllBranches) { + fetchType = FETCH_TYPE.ALL_BRANCHES; + } else if (branchesToClone != null && !branchesToClone.isEmpty()) { + fetchType = FETCH_TYPE.MULTIPLE_BRANCHES; + } else { + // Default: neither mirror nor all nor specific refs given + fetchType = FETCH_TYPE.ALL_BRANCHES; + } + } + private static boolean isNonEmptyDirectory(File dir) { if (dir != null && dir.exists()) { File[] files = dir.listFiles(); @@ -586,8 +605,7 @@ public class CloneCommand extends TransportCommand { * @return {@code this} */ public CloneCommand setCloneAllBranches(boolean cloneAllBranches) { - this.fetchType = cloneAllBranches ? FETCH_TYPE.ALL_BRANCHES - : this.fetchType; + this.cloneAllBranches = cloneAllBranches; return this; } @@ -607,10 +625,7 @@ public class CloneCommand extends TransportCommand { * @since 5.6 */ public CloneCommand setMirror(boolean mirror) { - if (mirror) { - this.fetchType = FETCH_TYPE.MIRROR; - setBare(true); - } + this.mirror = mirror; return this; } @@ -631,8 +646,9 @@ public class CloneCommand extends TransportCommand { * Set the branches or tags to clone. *

* This is ignored if {@link #setCloneAllBranches(boolean) - * setCloneAllBranches(true)} is used. If {@code branchesToClone} is - * {@code null} or empty, it's also ignored and all branches will be cloned. + * setCloneAllBranches(true)} or {@link #setMirror(boolean) setMirror(true)} + * is used. If {@code branchesToClone} is {@code null} or empty, it's also + * ignored. *

* * @param branchesToClone @@ -642,13 +658,7 @@ public class CloneCommand extends TransportCommand { * @return {@code this} */ public CloneCommand setBranchesToClone(Collection branchesToClone) { - if (branchesToClone == null || branchesToClone.isEmpty()) { - // fallback to default - fetchType = FETCH_TYPE.ALL_BRANCHES; - } else { - this.fetchType = FETCH_TYPE.MULTIPLE_BRANCHES; - this.branchesToClone = branchesToClone; - } + this.branchesToClone = branchesToClone; return this; } 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 dc9c28c1b..aea14de75 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 @@ -106,6 +106,7 @@ public class FileReftableDatabase extends RefDatabase { reftableDatabase.getLock().lock(); try { reftableStack.compactFully(); + reftableDatabase.clearCache(); } finally { reftableDatabase.getLock().unlock(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java index 5b540bd7e..4cb0bd3e8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java @@ -237,8 +237,13 @@ public class FileReftableStack implements AutoCloseable { long max = 1000; long delay = 0; boolean success = false; - while (System.currentTimeMillis() < deadline) { + + // Don't check deadline for the first 3 retries, so we can step with a + // debugger without worrying about deadlines. + int tries = 0; + while (tries < 3 || System.currentTimeMillis() < deadline) { List names = readTableNames(); + tries++; try { reloadOnce(names); success = true; @@ -260,9 +265,6 @@ public class FileReftableStack implements AutoCloseable { } if (!success) { - // TODO: should reexamine the 'refs' file to see if it was the same - // if it didn't change, then we must have corruption. If it did, - // retry. throw new LockFailedException(stackPath); } @@ -374,7 +376,7 @@ public class FileReftableStack implements AutoCloseable { * * @param w * writer to write data to a reftable under construction - * @return true if the transaction. + * @return true if the transaction was successful. * @throws IOException * on I/O problems */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java index 9d410aef9..f78975af3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java @@ -12,6 +12,7 @@ package org.eclipse.jgit.internal.storage.reftable; import java.io.IOException; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.lib.ReflogEntry; /** @@ -45,8 +46,9 @@ public abstract class LogCursor implements AutoCloseable { /** * Get current log entry. * - * @return current log entry. + * @return current log entry. Maybe null if we are producing deletions. */ + @Nullable public abstract ReflogEntry getReflogEntry(); /** {@inheritDoc} */