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

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.

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.

How to delete a file locked by the Java Platform?

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.

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.

svnkit: how to get working copy revision number?

I am using SVNKit 1.3.2 and trying to obtain working copy revision number.
Working copy is checkouted also with SVNKit, but when I'm trying to call
clientManager.getLookClient().doGetYoungestRevision(destination);
I got FileNotFoundException telling me that 'format' file is not found under destination path, ex /path/to/working/copy/format
I can see 2 troubles:
- It tries to access 'format' file right in working directory root, while this file supposed to be in .svn folder
There is not file in this .svn folder.
Any clues? Thank you!
Seems to be it should be done through SVNStatusClient:
clientManager.getStatusClient().doStatus(destination, false).getRevision().getNumber();
Though still don't understand what's the problem with doGetYoungestRevision(destination)...
It is not working because doGetYoungestRevision is for a repository, not for a working copy.
I was hoping to achieve the same things as you, and found out that when destination is pointing to a repository, it returns the last revision number of the repository.
The class in itself is for working with repository, you can look at the documentation here.

Categories

Resources