I'm cloning a git repo into a temp directory using jgit (version 4.8.0.201706111038-r
) and adding a shutdown hook to delete the temp directory after termination. However, the shutdown hook fails to delete some files from within the .git
subdirectory (despite closing the Git object, as required by jgit).
The funny thing though, is that the deletion fails only if I use the Path API (Files.delete(<PATH>)
), but not if I delete using the old file.delete()
.
Here's a minimal standalone example whose only dependency is jgit 4.8.0.201706111038-r:
public static void main(String... args) throws Exception {
String gitRepo = "https://github.com/netgloo/spring-boot-samples.git";
Path localDir = Files.createTempDirectory(null);
// Clone repo
Git git = Git.cloneRepository().setURI(gitRepo).setBranch("master").setDirectory(localDir.toFile()).call();
// Print some stuff to make sure that the git repo actually works
for (RevCommit c : git.log().call()) {
System.out.println(c);
}
git.getRepository().close(); // Close all the things!
git.close(); // Close all the things!
// Delete
Files.walkFileTree(localDir, new SimpleFileVisitor<Path>() {
void safeDelete(Path p) {
try {
Files.delete(p);
} catch (Exception e) {
try {
Files.delete(p);
} catch (Exception e2) {
System.err.println("Failed to delete " + p + " due to " + e.getClass().getSimpleName() + " using Files.detlete().\nTrying toFile().delete(): " + p.toFile().delete());
}
}
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
safeDelete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
safeDelete(dir);
return FileVisitResult.CONTINUE;
}
});
}
Output:
...
Failed to delete C:\Users\malt\AppData\Local\Temp\7908805853015958247\.git\objects\pack\pack-9cc3ec0769e34546bb7683f4e22ef67b3c800444.idx due to AccessDeniedException using Files.detlete().
Trying toFile().delete(): true
Failed to delete C:\Users\malt\AppData\Local\Temp\7908805853015958247\.git\objects\pack\pack-9cc3ec0769e34546bb7683f4e22ef67b3c800444.pack due to AccessDeniedException using Files.detlete().
Trying toFile().delete(): true
Can anyone explain why this happens? And is there a way to get JGIT to properly close these files so that Files.delete()
works?
When obtained from a CloneCommand
, Git::close
alone should be enough to release all file handles, held by JGit for a given repository. It simply delegates to Repository::close
in this case.
I think the difference between Files::delete()
and File::delete()
that you are seeing is explained here:
Difference between Files#delete(Path) and File#delete()
Probably unrelated, but I think nonetheless worth mentioning, is an issue with the recently introduced background thread for auto-gc. It may also prevent a repository from being deleted successfully. See this mailing list thread:
https://dev.eclipse.org/mhonarc/lists/jgit-dev/msg03370.html
To work around the latter issue, I disabled auto-gc in the configuration of the repository like this:
StoredConfig config = repository.getConfig();
config.setBoolean(CONFIG_GC_SECTION, null, CONFIG_KEY_AUTODETACH, false);
config.setInt(CONFIG_GC_SECTION, null, CONFIG_KEY_AUTOPACKLIMIT, -1);
config.setInt(CONFIG_GC_SECTION, null, CONFIG_KEY_AUTO, -1);
config.save();
The constants are imported static from ConfigConstants
.
Does that match your problem?
If somebody still faces the same issue, what worked for me is to force calling gc to release the files locking
gitReference.gc().call()
Here is the full close method of mine:
public void close() {
if (gitReference != null) {
try {
gitReference.close();
gitReference.gc().call();
} catch (GitAPIException e) {
throw new RuntimeException(e);
}
gitReference = null;
}
}
Good Luck
Jalal
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With