summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.bazelversion2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java42
-rw-r--r--org.eclipse.jgit/.settings/.api_filters28
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java25
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java116
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java13
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java13
8 files changed, 184 insertions, 61 deletions
diff --git a/.bazelversion b/.bazelversion
index 7ec1d6db40..ccbccc3dc6 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-2.1.0
+2.2.0
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 b13cdb9fec..33bacbe3e2 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
@@ -92,11 +92,6 @@ public class FileReftableTest extends SampleDataRepositoryTestCase {
}
@Test
- public void additionalRefsAreRemoved() {
- assertFalse(new File(db.getDirectory(), Constants.HEAD).exists());
- }
-
- @Test
public void testCompactFully() throws Exception {
ObjectId c1 = db.resolve("master^^");
ObjectId c2 = db.resolve("master^");
@@ -108,9 +103,16 @@ public class FileReftableTest extends SampleDataRepositoryTestCase {
}
File tableDir = new File(db.getDirectory(), Constants.REFTABLE);
- assertTrue(tableDir.listFiles().length > 1);
+ assertTrue(tableDir.listFiles().length > 2);
((FileReftableDatabase)db.getRefDatabase()).compactFully();
- assertEquals(tableDir.listFiles().length,1);
+ assertEquals(tableDir.listFiles().length,2);
+ }
+
+ @Test
+ public void testOpenConvert() throws Exception {
+ try (FileRepository repo = new FileRepository(db.getDirectory())) {
+ assertTrue(repo.getRefDatabase() instanceof FileReftableDatabase);
+ }
}
@Test
@@ -129,7 +131,7 @@ public class FileReftableTest extends SampleDataRepositoryTestCase {
@Test
public void testConvertToRefdir() throws Exception {
- db.convertToPackedRefs(false);
+ db.convertToPackedRefs(false, false);
assertTrue(db.getRefDatabase() instanceof RefDirectory);
Ref h = db.exactRef("HEAD");
assertTrue(h.isSymbolic());
@@ -144,6 +146,30 @@ public class FileReftableTest extends SampleDataRepositoryTestCase {
}
@Test
+ public void testConvertToRefdirReflog() throws Exception {
+ Ref a = db.exactRef("refs/heads/a");
+ String aCommit = a.getObjectId().getName();
+ RefUpdate u = db.updateRef("refs/heads/master");
+ u.setForceUpdate(true);
+ u.setNewObjectId(ObjectId.fromString(aCommit));
+ u.setForceRefLog(true);
+ u.setRefLogMessage("apple", false);
+ u.update();
+
+ RefUpdate v = db.updateRef("refs/heads/master");
+ v.setForceUpdate(true);
+ v.setNewObjectId(ObjectId.fromString(bCommit));
+ v.setForceRefLog(true);
+ v.setRefLogMessage("banana", false);
+ v.update();
+
+ db.convertToPackedRefs(true, false);
+ List<ReflogEntry> logs = db.getReflogReader("refs/heads/master").getReverseEntries(2);
+ assertEquals(logs.get(0).getComment(), "banana");
+ assertEquals(logs.get(1).getComment(), "apple");
+ }
+
+ @Test
public void testBatchrefUpdate() throws Exception {
ObjectId cur = db.resolve("master");
ObjectId prev = db.resolve("master^");
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 92b736337e..9df953becb 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -37,6 +37,26 @@
<message_argument value="CONFIG_KEY_PACKED_GIT_WINDOWSIZE"/>
</message_arguments>
</filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.6.2"/>
+ <message_argument value="CONFIG_EXTENSIONS_SECTION"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.6.2"/>
+ <message_argument value="CONFIG_KEY_REF_STORAGE"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/lib/Constants.java" type="org.eclipse.jgit.lib.Constants">
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.6.2"/>
+ <message_argument value="TABLES_LIST"/>
+ </message_arguments>
+ </filter>
</resource>
<resource path="src/org/eclipse/jgit/storage/file/WindowCacheConfig.java" type="org.eclipse.jgit.storage.file.WindowCacheConfig">
<filter id="1142947843">
@@ -69,6 +89,14 @@
</message_arguments>
</filter>
</resource>
+ <resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS$FileStoreAttributes">
+ <filter id="1226833923">
+ <message_arguments>
+ <message_argument value="5.6.2"/>
+ <message_argument value="setBackground(boolean)"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/jgit/util/Monitoring.java" type="org.eclipse.jgit.util.Monitoring">
<filter id="1109393411">
<message_arguments>
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 aea14de756..e613a58062 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
@@ -64,6 +64,11 @@ public class FileReftableDatabase extends RefDatabase {
private final FileReftableStack reftableStack;
+ FileReftableDatabase(FileRepository repo) throws IOException {
+ this(repo, new File(new File(repo.getDirectory(), Constants.REFTABLE),
+ Constants.TABLES_LIST));
+ }
+
FileReftableDatabase(FileRepository repo, File refstackName) throws IOException {
this.fileRepository = repo;
this.reftableStack = new FileReftableStack(refstackName,
@@ -88,8 +93,7 @@ public class FileReftableDatabase extends RefDatabase {
* @return whether the given repo uses reftable for refdb storage.
*/
public static boolean isReftable(File repoDir) {
- return new File(repoDir, "refs").isFile() //$NON-NLS-1$
- && new File(repoDir, Constants.REFTABLE).isDirectory();
+ return new File(repoDir, Constants.REFTABLE).isDirectory();
}
/** {@inheritDoc} */
@@ -593,8 +597,6 @@ public class FileReftableDatabase extends RefDatabase {
/**
* @param repo
* the repository
- * @param refstackName
- * the filename for the stack
* @param writeLogs
* whether to write reflogs
* @return a reftable based RefDB from an existing repository.
@@ -602,22 +604,25 @@ public class FileReftableDatabase extends RefDatabase {
* on IO error
*/
public static FileReftableDatabase convertFrom(FileRepository repo,
- File refstackName, boolean writeLogs) throws IOException {
+ boolean writeLogs) throws IOException {
FileReftableDatabase newDb = null;
+ File reftableList = null;
try {
- File reftableDir = new File(repo.getDirectory(), Constants.REFTABLE);
+ File reftableDir = new File(repo.getDirectory(),
+ Constants.REFTABLE);
+ reftableList = new File(reftableDir, Constants.TABLES_LIST);
if (!reftableDir.isDirectory()) {
reftableDir.mkdir();
}
- try (FileReftableStack stack = new FileReftableStack(refstackName,
+ try (FileReftableStack stack = new FileReftableStack(reftableList,
reftableDir, null, () -> repo.getConfig())) {
stack.addReftable(rw -> writeConvertTable(repo, rw, writeLogs));
}
- refstackName = null;
+ reftableList = null;
} finally {
- if (refstackName != null) {
- refstackName.delete();
+ if (reftableList != null) {
+ reftableList.delete();
}
}
return newDb;
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 fb84a090d3..fd052cec28 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
@@ -18,10 +18,13 @@ import static java.util.stream.Collectors.toList;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -50,6 +53,7 @@ import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.ReflogEntry;
import org.eclipse.jgit.lib.ReflogReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
@@ -173,20 +177,17 @@ public class FileRepository extends Repository {
String reftype = repoConfig.getString(
ConfigConstants.CONFIG_EXTENSIONS_SECTION, null,
- ConfigConstants.CONFIG_KEY_REFSTORAGE);
+ ConfigConstants.CONFIG_KEY_REF_STORAGE);
if (repositoryFormatVersion >= 1 && reftype != null) {
if (StringUtils.equalsIgnoreCase(reftype,
- ConfigConstants.CONFIG_REFSTORAGE_REFTABLE)) {
- refs = new FileReftableDatabase(this,
- new File(getDirectory(), "refs")); //$NON-NLS-1$
+ ConfigConstants.CONFIG_REF_STORAGE_REFTABLE)) {
+ refs = new FileReftableDatabase(this);
} else if (StringUtils.equalsIgnoreCase(reftype,
ConfigConstants.CONFIG_REFSTORAGE_REFTREE)) {
refs = new RefTreeDatabase(this, new RefDirectory(this));
} else {
throw new IOException(JGitText.get().unknownRepositoryFormat);
}
- } else if (FileReftableDatabase.isReftable(getDirectory())) {
- refs = new FileReftableDatabase(this, new File(getDirectory(), "refs")); //$NON-NLS-1$
} else {
refs = new RefDirectory(this);
}
@@ -610,15 +611,18 @@ public class FileRepository extends Repository {
* Converts the RefDatabase from reftable to RefDirectory. This operation is
* not atomic.
*
+ * @param writeLogs
+ * whether to write reflogs
* @param backup
* whether to rename or delete the old storage files. If set to
- * true, the reftable list is left in "refs.old", and the
- * reftable/ dir is left alone. If set to false, the reftable/
- * dir is removed, and "refs" file is removed.
+ * {@code true}, the reftable list is left in {@code refs.old},
+ * and the {@code reftable/} dir is left alone. If set to
+ * {@code false}, the {@code reftable/} dir is removed, and
+ * {@code refs} file is removed.
* @throws IOException
* on IO problem
*/
- void convertToPackedRefs(boolean backup) throws IOException {
+ void convertToPackedRefs(boolean writeLogs, boolean backup) throws IOException {
List<Ref> all = refs.getRefs();
File packedRefs = new File(getDirectory(), Constants.PACKED_REFS);
if (packedRefs.exists()) {
@@ -627,26 +631,26 @@ public class FileRepository extends Repository {
}
File refsFile = new File(getDirectory(), "refs"); //$NON-NLS-1$
-
- refs.close();
-
- if (backup) {
- File refsOld = new File(getDirectory(), "refs.old"); //$NON-NLS-1$
- if (refsOld.exists()) {
- throw new IOException(MessageFormat.format(
- JGitText.get().fileAlreadyExists,
- "refs.old")); //$NON-NLS-1$
- }
- FileUtils.rename(refsFile, refsOld);
- } else {
- refsFile.delete();
- }
+ File refsHeadsFile = new File(refsFile, "heads");//$NON-NLS-1$
+ File headFile = new File(getDirectory(), Constants.HEAD);
+ FileReftableDatabase oldDb = (FileReftableDatabase) refs;
+
+ // Remove the dummy files that ensure compatibility with older git
+ // versions (see convertToReftable). First make room for refs/heads/
+ refsHeadsFile.delete();
+ // RefDirectory wants to create the refs/ directory from scratch, so
+ // remove that too.
+ refsFile.delete();
+ // remove HEAD so its previous invalid value doesn't cause issues.
+ headFile.delete();
// This is not atomic, but there is no way to instantiate a RefDirectory
// that is disconnected from the current repo.
- refs = new RefDirectory(this);
+ RefDirectory refDir = new RefDirectory(this);
+ refs = refDir;
refs.create();
+ ReflogWriter logWriter = refDir.newLogWriter(true);
List<Ref> symrefs = new ArrayList<>();
BatchRefUpdate bru = refs.newBatchUpdate();
for (Ref r : all) {
@@ -656,6 +660,15 @@ public class FileRepository extends Repository {
bru.addCommand(new ReceiveCommand(ObjectId.zeroId(),
r.getObjectId(), r.getName()));
}
+
+ if (writeLogs) {
+ List<ReflogEntry> logs = oldDb.getReflogReader(r.getName())
+ .getReverseEntries();
+ Collections.reverse(logs);
+ for (ReflogEntry e : logs) {
+ logWriter.log(r.getName(), e);
+ }
+ }
}
try (RevWalk rw = new RevWalk(this)) {
@@ -691,24 +704,39 @@ public class FileRepository extends Repository {
FileUtils.delete(reftableDir,
FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS);
}
-
repoConfig.unset(ConfigConstants.CONFIG_EXTENSIONS_SECTION, null,
- ConfigConstants.CONFIG_KEY_REFSTORAGE);
+ ConfigConstants.CONFIG_KEY_REF_STORAGE);
repoConfig.save();
}
+ /**
+ * Converts the RefDatabase from RefDirectory to reftable. This operation is
+ * not atomic.
+ *
+ * @param writeLogs
+ * whether to write reflogs
+ * @param backup
+ * whether to rename or delete the old storage files. If set to
+ * {@code true}, the loose refs are left in {@code refs.old}, the
+ * packed-refs in {@code packed-refs.old} and reflogs in
+ * {@code refs.old/}. HEAD is left in {@code HEAD.old} and also
+ * {@code .log} is appended to additional refs. If set to
+ * {@code false}, the {@code refs/} and {@code logs/} directories
+ * and {@code HEAD} and additional symbolic refs are removed.
+ * @throws IOException
+ * on IO problem
+ */
@SuppressWarnings("nls")
void convertToReftable(boolean writeLogs, boolean backup)
throws IOException {
- File newRefs = new File(getDirectory(), "refs.new");
File reftableDir = new File(getDirectory(), Constants.REFTABLE);
-
+ File headFile = new File(getDirectory(), Constants.HEAD);
if (reftableDir.exists() && reftableDir.listFiles().length > 0) {
throw new IOException(JGitText.get().reftableDirExists);
}
// Ignore return value, as it is tied to temporary newRefs file.
- FileReftableDatabase.convertFrom(this, newRefs, writeLogs);
+ FileReftableDatabase.convertFrom(this, writeLogs);
File refsFile = new File(getDirectory(), "refs");
@@ -716,7 +744,6 @@ public class FileRepository extends Repository {
File packedRefs = new File(getDirectory(), Constants.PACKED_REFS);
File logsDir = new File(getDirectory(), Constants.LOGS);
-
List<String> additional = getRefDatabase().getAdditionalRefs().stream()
.map(Ref::getName).collect(toList());
additional.add(Constants.HEAD);
@@ -735,7 +762,8 @@ public class FileRepository extends Repository {
new File(getDirectory(), r + ".old"));
}
} else {
- packedRefs.delete(); // ignore return value.
+ FileUtils.delete(packedRefs, FileUtils.SKIP_MISSING);
+ FileUtils.delete(headFile);
FileUtils.delete(logsDir, FileUtils.RECURSIVE);
FileUtils.delete(refsFile, FileUtils.RECURSIVE);
for (String r : additional) {
@@ -743,16 +771,26 @@ public class FileRepository extends Repository {
}
}
- // Put new data.
- FileUtils.rename(newRefs, refsFile);
+ FileUtils.mkdir(refsFile, true);
- refs.close();
- refs = new FileReftableDatabase(this, refsFile);
+ // By putting in a dummy HEAD, old versions of Git still detect a repo
+ // (that they can't read)
+ try (OutputStream os = new FileOutputStream(headFile)) {
+ os.write(Constants.encodeASCII("ref: refs/heads/.invalid"));
+ }
+
+ // Some tools might write directly into .git/refs/heads/BRANCH. By
+ // putting a file here, this fails spectacularly.
+ FileUtils.createNewFile(new File(refsFile, "heads"));
repoConfig.setString(ConfigConstants.CONFIG_EXTENSIONS_SECTION, null,
- ConfigConstants.CONFIG_KEY_REFSTORAGE,
- ConfigConstants.CONFIG_REFSTORAGE_REFTABLE);
+ ConfigConstants.CONFIG_KEY_REF_STORAGE,
+ ConfigConstants.CONFIG_REF_STORAGE_REFTABLE);
+ repoConfig.setLong(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 1);
repoConfig.save();
+ refs.close();
+ refs = new FileReftableDatabase(this);
}
/**
@@ -775,7 +813,7 @@ public class FileRepository extends Repository {
}
} else if (format.equals("refdir")) {//$NON-NLS-1$
if (refs instanceof FileReftableDatabase) {
- convertToPackedRefs(backup);
+ convertToPackedRefs(writeLogs, backup);
}
} else {
throw new IOException(MessageFormat
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 5b7afe3b37..e607edc2ea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -504,9 +504,18 @@ public final class ConfigConstants {
*/
public static final String CONFIG_KEY_MIN_RACY_THRESHOLD = "minRacyThreshold";
+
+ /**
+ * The "refStorage" key
+ *
+ * @since 5.6.2
+ */
+ public static final String CONFIG_KEY_REF_STORAGE = "refStorage";
+
/**
* The "extensions" section
- * @since 5.7
+ *
+ * @since 5.6.2
*/
public static final String CONFIG_EXTENSIONS_SECTION = "extensions";
@@ -520,7 +529,7 @@ public final class ConfigConstants {
* The "reftable" refStorage format
* @since 5.7
*/
- public static final String CONFIG_REFSTORAGE_REFTABLE = "reftable";
+ public static final String CONFIG_REF_STORAGE_REFTABLE = "reftable";
/**
* The "reftree" refStorage format
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
index ffc742d473..459ca2f7ff 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -254,6 +254,12 @@ public final class Constants {
*/
public static final String REFTABLE = "reftable";
+ /**
+ * Reftable table list name.
+ * @since 5.6.2
+ */
+ public static final String TABLES_LIST = "tables.list";
+
/** Info refs folder */
public static final String INFO_REFS = "info/refs";
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index cae3c394c2..216bf2c336 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -245,7 +245,16 @@ public abstract class FS {
return t;
});
- private static void setBackground(boolean async) {
+ /**
+ * Whether FileStore attributes should be determined asynchronously
+ *
+ * @param async
+ * whether FileStore attributes should be determined
+ * asynchronously. If false access to cached attributes may block
+ * for some seconds for the first call per FileStore
+ * @since 5.6.2
+ */
+ public static void setBackground(boolean async) {
background.set(async);
}
@@ -709,7 +718,9 @@ public abstract class FS {
* asynchronously. If false access to cached attributes may block
* for some seconds for the first call per FileStore
* @since 5.1.9
+ * @deprecated Use {@link FileStoreAttributes#setBackground} instead
*/
+ @Deprecated
public static void setAsyncFileStoreAttributes(boolean asynch) {
FileStoreAttributes.setBackground(asynch);
}