summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/config-options.md1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java37
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java15
4 files changed, 60 insertions, 0 deletions
diff --git a/Documentation/config-options.md b/Documentation/config-options.md
index ca94ab84d1..78930e6267 100644
--- a/Documentation/config-options.md
+++ b/Documentation/config-options.md
@@ -56,6 +56,7 @@ For details on native git options see also the official [git config documentatio
| `core.symlinks` | Auto detect if filesystem supports symlinks| ✅ | If false, symbolic links are checked out as small plain files that contain the link text. |
| `core.trustFolderStat` | `true` | ⃞ | Whether to trust the pack folder's, packed-refs file's and loose-objects folder's file attributes (Java equivalent of stat command on *nix). When looking for pack files, if `false` JGit will always scan the `.git/objects/pack` folder and if set to `true` it assumes that pack files are unchanged if the file attributes of the pack folder are unchanged. When getting the list of packed refs, if `false` JGit will always read the packed-refs file and if set to `true` it uses the file attributes of the packed-refs file and will only read it if a file attribute has changed. When looking for loose objects, if `false` and if a loose object is not found, JGit will open and close a stream to `.git/objects` folder (which can refresh its directory listing, at least on some NFS clients) and retry looking for that loose object. Setting this option to `false` can help to workaround caching issues on NFS, but reduces performance. |
| `core.trustPackedRefsStat` | `unset` | ⃞ | Whether to trust the file attributes (Java equivalent of stat command on *nix) of the packed-refs file. If `never` JGit will ignore the file attributes of the packed-refs file and always read it. If `always` JGit will trust the file attributes of the packed-refs file and will only read it if a file attribute has changed. `after_open` behaves the same as `always`, except that the packed-refs file is opened and closed before its file attributes are considered. An open/close of the packed-refs file is known to refresh its file attributes, at least on some NFS clients. If `unset`, JGit will use the behavior described in `trustFolderStat`. |
+| `core.trustLooseRefStat` | `always` | ⃞ | Whether to trust the file attributes (Java equivalent of stat command on *nix) of the loose ref. If `always` JGit will trust the file attributes of the loose ref and its parent directories. `after_open` behaves similar to `always`, except that all parent directories of the loose ref up to the repository root are opened and closed before its file attributes are considered. An open/close of these parent directories is known to refresh the file attributes, at least on some NFS clients. |
| `core.worktree` | Root directory of the working tree if it is not the parent directory of the `.git` directory | ✅ | The path to the root of the working tree. |
## __fetch__ options
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 e27029798d..169dce1cc0 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
@@ -37,6 +37,7 @@ import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.text.MessageFormat;
@@ -64,6 +65,7 @@ import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig.TrustPackedRefsStat;
+import org.eclipse.jgit.lib.CoreConfig.TrustLooseRefStat;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Ref;
@@ -181,6 +183,8 @@ public class RefDirectory extends RefDatabase {
private final TrustPackedRefsStat trustPackedRefsStat;
+ private final TrustLooseRefStat trustLooseRefStat;
+
RefDirectory(RefDirectory refDb) {
parent = refDb.parent;
gitDir = refDb.gitDir;
@@ -192,6 +196,7 @@ public class RefDirectory extends RefDatabase {
packedRefs.set(refDb.packedRefs.get());
trustFolderStat = refDb.trustFolderStat;
trustPackedRefsStat = refDb.trustPackedRefsStat;
+ trustLooseRefStat = refDb.trustLooseRefStat;
inProcessPackedRefsLock = refDb.inProcessPackedRefsLock;
}
@@ -213,6 +218,10 @@ public class RefDirectory extends RefDatabase {
.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_TRUST_PACKED_REFS_STAT,
TrustPackedRefsStat.UNSET);
+ trustLooseRefStat = db.getConfig()
+ .getEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_TRUST_LOOSE_REF_STAT,
+ TrustLooseRefStat.ALWAYS);
inProcessPackedRefsLock = new ReentrantLock(true);
}
@@ -1136,6 +1145,11 @@ public class RefDirectory extends RefDatabase {
LooseRef scanRef(LooseRef ref, String name) throws IOException {
final File path = fileFor(name);
+
+ if (trustLooseRefStat.equals(TrustLooseRefStat.AFTER_OPEN)) {
+ refreshPathToLooseRef(Paths.get(name));
+ }
+
FileSnapshot currentSnapshot = null;
if (ref != null) {
@@ -1221,6 +1235,29 @@ public class RefDirectory extends RefDatabase {
return new LooseUnpeeled(loose.snapshot, name, id);
}
+ /**
+ * Workaround for issues caused by NFS caching. Refresh directories starting
+ * from the repository root to a loose ref by opening an input stream. This
+ * refreshes file attributes of the loose ref (at least on some NFS
+ * clients).
+ *
+ * @param refPath
+ * path of a loose ref relative to the repository root
+ */
+ void refreshPathToLooseRef(Path refPath) {
+ for (int i = 1; i < refPath.getNameCount(); i++) {
+ File dir = fileFor(refPath.subpath(0, i).toString());
+ // Use Files.newInputStream(Path) as it is consistent with other
+ // code where a refresh is being done (see getPackedRefs()) and also
+ // it performs slightly better than Files.newDirectoryStream(Path)
+ try (InputStream stream = Files.newInputStream(dir.toPath())) {
+ // open the dir to refresh attributes (on some NFS clients)
+ } catch (IOException e) {
+ break; // loose ref may not exist
+ }
+ }
+ }
+
private static boolean isSymRef(byte[] buf, int n) {
if (n < 6)
return false;
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 76b4d7195e..0edf3c5ad0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -972,6 +972,13 @@ public final class ConfigConstants {
public static final String CONFIG_KEY_TRUST_PACKED_REFS_STAT = "trustPackedRefsStat";
/**
+ * The "trustLooseRefStat" key
+ *
+ * @since 6.9
+ */
+ public static final String CONFIG_KEY_TRUST_LOOSE_REF_STAT = "trustLooseRefStat";
+
+ /**
* The "pack.preserveOldPacks" key
*
* @since 5.13.2
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
index 4de1801d04..9fa5d75a3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
@@ -144,6 +144,21 @@ public class CoreConfig {
UNSET
}
+ /**
+ * Permissible values for {@code core.trustLooseRefStat}.
+ *
+ * @since 6.9
+ */
+ public enum TrustLooseRefStat {
+
+ /** Trust file attributes of the loose ref. */
+ ALWAYS,
+
+ /** Open and close parent directories of the loose ref file until the
+ * repository root to refresh its file attributes and then trust it. */
+ AFTER_OPEN,
+ }
+
private final int compression;
private final int packIndexVersion;