I have a bare repo located at main.git and am trying to fetch a branch (foo, let's say) in another repo, test, which has only just been git init'd:
fetchtest/
|- main.git/
|- test/
|- .git/
Using regular git commands, I can do a git fetch ../main.git foo:foo and this will make a new branch foo in test/ and fetch the objects required for the branch. I then want to do the same thing but programmatically using JGit, ie not using the git CLI but using only Java code. There is no way I can use the git CLI:
Git git = Git.init().setDirectory(new File("fetchtest/test/")).call();
git.fetch().setRemote(new File("../main.git"))
.setRefSpecs(new RefSpec("foo:foo"))
.call();
but it just errors with:
org.eclipse.jgit.api.errors.TransportException: Remote does not have foo available for fetch.
at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:137)
// ......
Caused by: org.eclipse.jgit.errors.TransportException: Remote does not have foo available for fetch.
at org.eclipse.jgit.transport.FetchProcess.expandSingle(FetchProcess.java:349)
at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:139)
at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:113)
at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1069)
at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:128)
How do I get this to work?
解决方案
What should work:
Git git = Git.init().setDirectory(new File("fetchtest/test/")).call();
git.fetch().setRemote(new File("../main.git"))
.setRefSpecs(new RefSpec("refs/heads/foo:refs/heads/foo"))
.call();
Note the RefSpec definition.
At least, try in your example:
new RefSpec("refs/heads/foo:refs/heads/foo")
/**
* Parse a ref specification for use during transport operations.
*
* Specifications are typically one of the following forms:
*
*
refs/head/master
*
refs/head/master:refs/remotes/origin/master
*
refs/head/*:refs/remotes/origin/*
*
+refs/head/master
*
+refs/head/master:refs/remotes/origin/master
*
+refs/head/*:refs/remotes/origin/*
*
:refs/head/master
*
*
* @param spec
* string describing the specification.
* @throws IllegalArgumentException
* the specification is invalid.
*/
So "refs/head/" seems mandatory.
Original answer:
And looking at the FetchCommandTest URI definition, I prefer making the remote more visible:
I would rather define a named remote (here below: "test") for your second repo (referring your first repo), and then fetch.
// setup the first repository to fetch from the second repository
final StoredConfig config = db.getConfig();
RemoteConfig remoteConfig = new RemoteConfig(config, "test");
URIish uri = new URIish(db2.getDirectory().toURI().toURL());
remoteConfig.addURI(uri);
remoteConfig.update(config);
config.save();
// create some refs via commits and tag
RevCommit commit = git2.commit().setMessage("initial commit").call();
Ref tagRef = git2.tag().setName("tag").call();
Git git1 = new Git(db);
RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x");
git1.fetch().setRemote("test").setRefSpecs(spec)
.call();