Merge branch 'stable-6.3' into stable-6.4

* stable-6.3:
  Introduce core.trustPackedRefsStat config
  Fix documentation for core.trustFolderStat

Change-Id: I18d9fc89c9ac1ef069dcefa7d7f992a28539ccf3
diff --git a/Documentation/config-options.md b/Documentation/config-options.md
index 19bcc33..9cb3c62 100644
--- a/Documentation/config-options.md
+++ b/Documentation/config-options.md
@@ -45,7 +45,8 @@
 | `core.streamFileThreshold` | `50 MiB` | ⃞ | The size threshold beyond which objects must be streamed. |
 | `core.supportsAtomicFileCreation` | `true` | ⃞ | Whether the filesystem supports atomic file creation. |
 | `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 modification time. If `false` JGit will always scan the `.git/objects/pack` folder to check for new pack files. This can help to workaround caching issues on NFS, but reduces performance. If set to `true` it uses the `lastmodified` attribute of the folder and assumes that no new pack files can be in this folder if its modification time has not changed. |
+| `core.trustFolderStat` | `true` | ⃞ | Whether to trust the pack folder's and packed-refs file'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. 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.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. |
 
 ## __gc__ 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 7d3792e..94a377f 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
@@ -28,7 +28,9 @@
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.InterruptedIOException;
 import java.nio.file.DirectoryNotEmptyException;
@@ -59,6 +61,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.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdRef;
 import org.eclipse.jgit.lib.Ref;
@@ -891,10 +894,37 @@ PackedRefList getPackedRefs() throws IOException {
 		boolean trustFolderStat = getRepository().getConfig().getBoolean(
 				ConfigConstants.CONFIG_CORE_SECTION,
 				ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
+		TrustPackedRefsStat trustPackedRefsStat =
+				getRepository().getConfig().getEnum(
+						ConfigConstants.CONFIG_CORE_SECTION,
+						null,
+						ConfigConstants.CONFIG_KEY_TRUST_PACKED_REFS_STAT,
+						TrustPackedRefsStat.UNSET);
 
 		final PackedRefList curList = packedRefs.get();
-		if (trustFolderStat && !curList.snapshot.isModified(packedRefsFile)) {
-			return curList;
+
+		switch (trustPackedRefsStat) {
+		case NEVER:
+			break;
+		case AFTER_OPEN:
+			try (InputStream stream = Files
+					.newInputStream(packedRefsFile.toPath())) {
+				// open the file to refresh attributes (on some NFS clients)
+			} catch (FileNotFoundException e) {
+				// Ignore as packed-refs may not exist
+			}
+			//$FALL-THROUGH$
+		case ALWAYS:
+			if (!curList.snapshot.isModified(packedRefsFile)) {
+				return curList;
+			}
+			break;
+		case UNSET:
+			if (trustFolderStat
+					&& !curList.snapshot.isModified(packedRefsFile)) {
+				return curList;
+			}
+			break;
 		}
 
 		final PackedRefList newList = readPackedRefs();
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 47a572b..4b1a72e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -886,4 +886,10 @@ public final class ConfigConstants {
 	 */
 	public static final String CONFIG_KEY_ABBREV = "abbrev";
 
+	/**
+	 * The "trustPackedRefsStat" key
+	 *
+	 * @since 6.1.1
+	 */
+	public static final String CONFIG_KEY_TRUST_PACKED_REFS_STAT = "trustPackedRefsStat";
 }
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 f23c6e0..fc82a5f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
@@ -116,6 +116,27 @@ public enum LogRefUpdates {
 		ALWAYS
 	}
 
+	/**
+	 * Permissible values for {@code core.trustPackedRefsStat}.
+	 *
+	 * @since 6.1.1
+	 */
+	public enum TrustPackedRefsStat {
+		/** Do not trust file attributes of the packed-refs file. */
+		NEVER,
+
+		/** Trust file attributes of the packed-refs file. */
+		ALWAYS,
+
+		/** Open and close the packed-refs file to refresh its file attributes
+		 * and then trust it. */
+		AFTER_OPEN,
+
+		/** {@code core.trustPackedRefsStat} defaults to this when it is
+		 * not set */
+		UNSET
+	}
+
 	private final int compression;
 
 	private final int packIndexVersion;