How to delete a file locked by the Java Platform? - java

I am currently developing an app which clones Git repositories thanks to JGit (http://wiki.eclipse.org/JGit/User_Guide) every time a user logs on. When the user wants to quit the app, I want to delete the clone.
Here's the problem : when cloning a repository, a folder .git is created, in which can be found a file .pack (.git/objects/pack/sutpideFile.pack) and which cannot be deleted, because the Java Platform is locking it (when trying to delete it by hand, get the error 'The action can't be completed because file is open in Java(TM) Platform SE binary').
THIS IS A KNOWN PROBLEM with Jgit : .pack file from git repo can't be deleted using File delete() method.
Thus I have used the solution proposed here : https://github.com/ajoberstar/grgit/issues/33 which is to add those three lines before my deleting method :
WindowCacheConfig config = new WindowCacheConfig();
config.setPackedGitMMAP(true);
WindowCache.install(config);
BUT what really bothers me because I do not understand is that this solution works only once: I launch the server (TomCat), connect, and then disconnect. Here, the whole folder is deleted. However, when I re-connect and disconnect (without re-launching the sever), there rebels the files and am I not able anymore to delete it until I shut down the server.
Has anybody the slighest idea why it works, but only once ?
Thanks for your help,
EDIT :
Well, so I just needed to add git.getRepository().close(); when I finish to use the Git object. Then the deletion is possible !

This is a know bug in JGit, see the discussion at How do I release file system locks after cloning repo via JGit
Basically you currently need to add the call to "Git.getRepository().close()" in order to free all file system locks until a new version of JGit is released.
result = Git.cloneRepository()
.setURI( 'https://github.com/github/testrepo.git' )
.setDirectory( localPath )
.call();
// this is currently necessary to free all file locks
result.getRepository().close();
result.close();
JGit 4.1 is scheduled to have a fix for this included.

Related

How to checkout a certain folder with JGit

FetchResult fr = git.fetch().setCredentialsProvider(credentials).setCheckFetchedObjects(true).Call();
git.checkout().setCreateBranch(true).setName("origin/" + branchName).setStartPoint("origin/" + branchName + "path/to/folder").call()
This is the code I'm using to check out a single folder from a remote repository.
Equivalent git commands are:
git fetch origin
git checkout origin/branch -- path/to/folder
But, the Java code doesn't work for me, I was only able to initialise the local repository and configure remote repository. The checkout didn't work and I couldn't find out what mistake I'm making.
Try making changes in the checkout part like this
"origin/"
and give it a try.
Otherwise you want to do is a sparse checkout
How do I implement sparse checkout in JGit?
In order to check out a particular folder with JGit (a sparse checkout), you need to tell the CheckoutCommand which folder to check out.
For example:
git.checkout().setName( "branch-to-check-out" ).addPath( "path/to/folder" ).call();
addPath() can be called multiple times to check out each of the given paths. The path is interpreted relative to the work directory.

JGit Removing a git repository

I am using JGit to clone a remote git repo using the below code.
localRepo = new FileRepository(path+"/.git");
git = new Git(localRepo);
clone = Git.cloneRepository().setURI(url).setBranch(branch)
.setDirectory(new File(path)).call();
clone.getRepository().close();
clone.close();
git.getRepository().close();
After cloning for the next repo, since I need to delete the directory, I use the below code.
File tempGitDirectory;
try {
tempGitDirectory = new File(dirPath);
if(tempGitDirectory.exists()){
FileUtils.deleteDirectory(tempGitDirectory);
}
} catch (IOException e) {
}
On my mac, everything works fine. But while trying on the redhat linux box, I am not able to delete the repo completely. Failing with the below error.
rm: cannot remove `git//TestGit/.nfs000000000011f6d40000032a': Device or resource busy
Any clue?
Make sure your pwd is not in the path you are trying to remove.
From this thread:
This occurs when a deleted file is still open by some process. It's an artifact of how NFS works behind the scenes.
An NFS server cannot actually remove a file if something still has it open.
The Linux kernel can easily do it with local disk files -- the inode still remains even after its unlinked from all directories, and the inode gets freed when the last process that has the file open terminates.
However this does not work with NFS, so the NFS server keeps this fake directory entry that represents an open file, and it will be automatically removed when whatever process has this file open terminates.
Check lsof in order to see what process is using the folder.
The OP Upen confirms in the comments:
I had opened a pom.xml reader for the cloned repo.
The FileReader was not closed. Works fine now.

Sticky tag for file is not a branch - CVS

I'm trying to commit my changes to the repository server (using CVS) in Eclipse Kepler, but when I do I get the following error which I've never seen before:
The server reported an error while performing the "cvs commit"
command. ProsperityMobile: cvsntsrv server: sticky tag 1.6' for file
src/com/prosperity/mobile/controller/UserController.java' is not a
branch ProsperityMobile: cvsntsrv server: sticky tag 1.14' for file
src/com/prosperity/mobile/service/UserService.java' is not a branch
ProsperityMobile: cvsntsrv [server aborted]: correct above errors
first!
And honestly I don't even know where to start trouble shooting this or what it even means. Any point in the right direction would really be appreciated!
I just came upon this too. This may happen, when you checkout a specific version of a file or at some specific date, see Sticky tags for more.
In my case, the files had a sticky tag, but were also at the HEAD. So I could just remove the sticky tag with
cvs update -A file.h file.cpp
and then proceed with cvs commit
And again when you're on a branch, it works more or less the same. Just update to the relevant branch with option -r
cvs update -r <branch-name> file.h file.cpp
In order to remove sticky tag from a file in CVS, easily use:
cvs update -A filename
A Tag applies to a specific revision of a file or tree of files. Trying to Commit changes to that wouldn't make sense, and in fact isn't supported by the server. This is why you check things out from a Branch, make changes and then check them back into the branch. A branch is expected to change over time while tags are expected to always point you back to the specific revision.
http://commons.oreilly.com/wiki/index.php/Essential_CVS/Using_CVS/Tagging_and_Branching
I had this same problem in Eclipse, and updating would not work.
What worked was:
Right click on file
Replace with > Another Branch or Version
Confirm (this will override local changes, therefore you should backup them)
Select HEAD (or the branch you need)

Is it possible to ignore a file once it is already tracked in Git?

Is it possible to add a dummy configuration file once (so that other developers can see how the configuration file should look) and then ignore it using the .gitignore file. Then replace the dummy config details with working ones so I can continue to develop the project and keep committing changes? But the original dummy config file will remain intact on Github?
This is the approach I attempted:
create repository on Github
intitialise local repo
pull remote repo
push local repo to github with Configuration.java (containing dummy details)
add Configuration.java to the .gitignore file
push local repo to github
add correct details to Configuration.java
push local repo to github
But the change to configuration.java is tracked, so this doesn't work.
If you are just worried about ignoring changes in your local dev repo, you can use git update-index --assume-unchanged <file> to ignore any changes to the file. See http://blog.pagebakers.nl/2009/01/29/git-ignoring-changes-in-tracked-files/ for more details.
You mention :
push local repo to github with Configuration.java (containing dummy
details)
add Configuration.java to the .gitignore file
The problem with this is, gitignore only works on files that aren't already being tracked, and since you've committed it it's too late for the gitignore to work. To quote the gitignore docs:
A gitignore file specifies intentionally untracked files that Git
should ignore. Files already tracked by Git are not affected;
If you want to commit your own work to a publicly visible repo, but want to hide sensitive info such as connection strings / passwords etc, then commit a dummy file first. For example, commit something like this:
public class Configuration {
public static final String USERNAME = "someUsername";
public static final String PASSWORD = "passwordHere";
}
Then, tell git to stop tracking changes on that file, so you can amend the values locally but not be prompted to commit those changes.
git update-index --assume-unchanged path/to/file.txt
A couple of things to point out:
Always check in a dummy config file, don't leave it out entirely. If
you do, when people checkout your project and the file is missing,
they won't be able to compile the project! Help them by giving some
sample data.
As git is no longer tracking that file, if you make any modifications
that you DO want to commit, you'll have to manually cater to that
(either do it via github.com or turn tracking back on, fix it, then
disable tracking again). For this purpose, keep that file relatively light, just variables, don't put logic in there that you may need to keep updating.

jgit - Delete .git directory (or get files without it)

I need to clone a git repo in java. I am using jGit.
The line of code I am using is :
Git clone = Git.cloneRepository().setURI(URIofRepo).setDirectory(localPath).call();
Where URIofRepo is : the github link to my repo
and
Where localPath is : the directory I want the clone to happen.
This works perfectly. However, since the use of the project I am doing doesn't require a clone for continued work, I simply want the clone to have the contents of the github repo WITHOUT the .git directory.
I tried also using the following :
File dirToDelete = new File (path + "/.git");
FileUtils.deleteDirectory(dirToDelete);
However I got an IO exception saying I am unable to delete the file as follows :
Exception in thread "main" java.io.IOException: Unable to delete file:
C:\testing\testRepo1.git\objects\pack\pack-7ca7f11688adda065d62f3394d0e055346beff22.pack
It is possible that the current eclipse process keep an handle on the pack file, preventing its deletion.
As RĂ¼diger Herrmann suggests in the comments:
If the open file handle is what prevents the file from being deleted, make sure to close the repository that is returned by init:
clone.getRepository().close()
Another approach would be to download an archive of the GitHub repo through its archive link.
Or using JGit to create an archive from your current local repo (see ArchiveTest.java), and unzip that archive for you to use.
This issue of unable to delete local repository still persisted even after trying following:
clone.getRepository().close()
I could fix the issue and successfully delete local repository after setting "options" value to RECURSIVE delete while calling delete() as follows:
FileUtils.deleteDirectory(dirToDelete, 1);
This is what delete() document says:
public static void delete(File f, int options) throws IOException
Delete file or folder
Parameters: f - File to be deleted
options - deletion options, RECURSIVE for recursive deletion of a subtree, RETRY to retry when deletion failed. Retrying may help if the underlying file system doesn't allow deletion of files being read by another thread.
Whether or not your .close() will have an effect depends on how the repository was created. So even though you are calling close on a Git instance, it may or may not release the resources. I wasted so much of my time before I realized this.
From Jgit documentation :
If the repository was opened by a static factory method in this class, then this method calls Repository.close() on the underlying repository instance. (Whether this actually releases underlying resources, such as file handles, may vary; see Repository for more details.)
If the repository was created by a caller and passed into Git(Repository) or a static factory method in this class, then this method does not call close on the underlying repository.

Categories

Resources