aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src
diff options
context:
space:
mode:
authorThomas Wolf <thomas.wolf@paranor.ch>2017-12-14 13:24:00 +0100
committerMatthias Sohn <matthias.sohn@sap.com>2017-12-15 14:14:03 +0100
commitc86327979f1362cf742e1401a95fdec259636d37 (patch)
tree0c3641b2502786a7db77f7e834759e00cfde7e16 /org.eclipse.jgit/src
parentec7f88eec8f52a2254b82bcb73aa489028ea3b39 (diff)
downloadjgit-c86327979f1362cf742e1401a95fdec259636d37.tar.gz
jgit-c86327979f1362cf742e1401a95fdec259636d37.zip
Write packed-refs directly when cloning
When we are cloning we have no refs at all yet, and there cannot (or at least should not) be any other thread doing something with refs yet. Locking loose refs is thus not needed, since there are no loose refs yet and nothing should be trying to create them concurrently. Let's skip the whole loose ref locking when we are cloning a repository. As a result, JGit will write the refs directly to the packed-refs file, and will not create the refs/remotes/ directories nor the lock files underneath when cloning and packed refs are used. Since no lock files are created, any problems on case-insensitive file systems with tag or branch names that differ only in case are avoided during cloning. Detect if we are cloning based on the following heuristics: * HEAD is a dangling symref * There is no loose ref * There is no packed-refs file Note, however, that there may still be problems with such tag or branch names later on. This is primarily a five-minutes-past-twelve stop-gap measure to resolve the referenced bug, which affects the Oxygen.2 release. Bug: 528497 Change-Id: I57860c29c210568165276a123b855e462b6a107a Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit/src')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java16
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java26
2 files changed, 37 insertions, 5 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java
index b328eb83e0..c1f5476496 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java
@@ -179,11 +179,19 @@ class PackedBatchRefUpdate extends BatchRefUpdate {
Map<String, LockFile> locks = null;
refdb.inProcessPackedRefsLock.lock();
try {
- locks = lockLooseRefs(pending);
- if (locks == null) {
- return;
+ PackedRefList oldPackedList;
+ if (!refdb.isInClone()) {
+ locks = lockLooseRefs(pending);
+ if (locks == null) {
+ return;
+ }
+ oldPackedList = refdb.pack(locks);
+ } else {
+ // During clone locking isn't needed since no refs exist yet.
+ // This also helps to avoid problems with refs only differing in
+ // case on a case insensitive filesystem (bug 528497)
+ oldPackedList = refdb.getPackedRefs();
}
- PackedRefList oldPackedList = refdb.pack(locks);
RefList<Ref> newRefs = applyUpdates(walk, oldPackedList, pending);
if (newRefs == null) {
return;
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 a44acacd12..bd39e65657 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
@@ -65,6 +65,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
+import java.nio.file.Files;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.text.MessageFormat;
@@ -901,7 +902,7 @@ public class RefDirectory extends RefDatabase {
return ref;
}
- private PackedRefList getPackedRefs() throws IOException {
+ PackedRefList getPackedRefs() throws IOException {
boolean trustFolderStat = getRepository().getConfig().getBoolean(
ConfigConstants.CONFIG_CORE_SECTION,
ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
@@ -1188,6 +1189,29 @@ public class RefDirectory extends RefDatabase {
&& buf[4] == ' ';
}
+ /**
+ * Detect if we are in a clone command execution
+ *
+ * @return {@code true} if we are currently cloning a repository
+ * @throws IOException
+ */
+ boolean isInClone() throws IOException {
+ return hasDanglingHead() && !packedRefsFile.exists() && !hasLooseRef();
+ }
+
+ private boolean hasDanglingHead() throws IOException {
+ Ref head = exactRef(Constants.HEAD);
+ if (head != null) {
+ ObjectId id = head.getObjectId();
+ return id == null || id.equals(ObjectId.zeroId());
+ }
+ return false;
+ }
+
+ private boolean hasLooseRef() throws IOException {
+ return Files.walk(refsDir.toPath()).anyMatch(Files::isRegularFile);
+ }
+
/** If the parent should fire listeners, fires them. */
void fireRefsChanged() {
final int last = lastNotifiedModCnt.get();