Merge "Fix GC for FileRepo in case packfile renames fail"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GCTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GCTest.java
index bc60f64..d5c8f12 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GCTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GCTest.java
@@ -435,6 +435,13 @@ public void testPackAllObjectsInOnePack() throws Exception {
 		assertEquals(0, stats.numberOfLooseObjects);
 		assertEquals(4, stats.numberOfPackedObjects);
 		assertEquals(1, stats.numberOfPackFiles);
+
+		// Do the gc again and check that it hasn't changed anything
+		gc.gc();
+		stats = gc.getStatistics();
+		assertEquals(0, stats.numberOfLooseObjects);
+		assertEquals(4, stats.numberOfPackedObjects);
+		assertEquals(1, stats.numberOfPackFiles);
 	}
 
 	@Test
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index 22fa827..bc14d88 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -735,11 +735,21 @@ public int compare(PackExt o1, PackExt o2) {
 
 			// rename the temporary files to real files
 			File realPack = nameFor(id, ".pack"); //$NON-NLS-1$
+
+			// if the packfile already exists (because we are rewriting a
+			// packfile for the same set of objects maybe with different
+			// PackConfig) then make sure we get rid of all handles on the file.
+			// Windows will not allow for rename otherwise.
+			if (realPack.exists())
+				for (PackFile p : repo.getObjectDatabase().getPacks())
+					if (realPack.getPath().equals(p.getPackFile().getPath())) {
+						p.close();
+						break;
+					}
 			tmpPack.setReadOnly();
 			boolean delete = true;
 			try {
-				if (!tmpPack.renameTo(realPack))
-					return null;
+				FileUtils.rename(tmpPack, realPack);
 				delete = false;
 				for (Map.Entry<PackExt, File> tmpEntry : tmpExts.entrySet()) {
 					File tmpExt = tmpEntry.getValue();
@@ -747,7 +757,9 @@ public int compare(PackExt o1, PackExt o2) {
 
 					File realExt = nameFor(
 							id, "." + tmpEntry.getKey().getExtension()); //$NON-NLS-1$
-					if (!tmpExt.renameTo(realExt)) {
+					try {
+						FileUtils.rename(tmpExt, realExt);
+					} catch (IOException e) {
 						File newExt = new File(realExt.getParentFile(),
 								realExt.getName() + ".new"); //$NON-NLS-1$
 						if (!tmpExt.renameTo(newExt))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
index 67f371b..acc1a2c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -168,6 +168,39 @@ public static void delete(final File f, int options) throws IOException {
 	}
 
 	/**
+	 * Rename a file or folder. If the rename fails and if we are running on a
+	 * filesystem where it makes sense to repeat a failing rename then repeat
+	 * the rename operation up to 9 times with 100ms sleep time between two
+	 * calls
+	 *
+	 * @see FS#retryFailedLockFileCommit()
+	 * @param src
+	 *            the old {@code File}
+	 * @param dst
+	 *            the new {@code File}
+	 * @throws IOException
+	 *             if the rename has failed
+	 */
+	public static void rename(final File src, final File dst)
+			throws IOException {
+		int attempts = FS.DETECTED.retryFailedLockFileCommit() ? 10 : 1;
+		while (--attempts >= 0) {
+			if (src.renameTo(dst))
+				return;
+			try {
+				Thread.sleep(100);
+			} catch (InterruptedException e) {
+				throw new IOException(MessageFormat.format(
+						JGitText.get().renameFileFailed, src.getAbsolutePath(),
+						dst.getAbsolutePath()));
+			}
+		}
+		throw new IOException(MessageFormat.format(
+				JGitText.get().renameFileFailed, src.getAbsolutePath(),
+				dst.getAbsolutePath()));
+	}
+
+	/**
 	 * Creates the directory named by this abstract pathname.
 	 *
 	 * @param d