Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git fetch failing using jgit: Remote does not have <branchname> available for fetch

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?

like image 472
Callum Rogers Avatar asked Jul 03 '12 03:07

Callum Rogers


People also ask

Does git fetch fetch all branches?

Git fetch commands and optionsFetch all of the branches from the repository. This also downloads all of the required commits and files from the other repository. Same as the above command, but only fetch the specified branch. The --dry-run option will perform a demo run of the command.

What is the opposite of git fetch?

git fetch is the command that tells your local git to retrieve the latest meta-data info from the original (yet doesn't do any file transferring. It's more like just checking to see if there are any changes available). git pull on the other hand does that AND brings (copy) those changes from the remote repository.

What is the benefit of git fetch?

git fetch allows you to retrieve updated changes from the remote repository and review them, without affecting your local working copy. This is useful if you just wish to take a look at what your team is working on, but keep your own code exactly as it is.

Is git fetch always safe?

git fetch updates your remote-tracking branches under refs/remotes/<remote>/ . This operation is safe to run at any time since it never changes any of your local branches under refs/heads .


1 Answers

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")

The RefSpec class mentions:

/**
 * Parse a ref specification for use during transport operations.
 * <p>
 * Specifications are typically one of the following forms:
 * <ul>
 * <li><code>refs/head/master</code></li>
 * <li><code>refs/head/master:refs/remotes/origin/master</code></li>
 * <li><code>refs/head/*:refs/remotes/origin/*</code></li>
 * <li><code>+refs/head/master</code></li>
 * <li><code>+refs/head/master:refs/remotes/origin/master</code></li>
 * <li><code>+refs/head/*:refs/remotes/origin/*</code></li>
 * <li><code>:refs/head/master</code></li>
 * </ul>
 *
 * @param spec
 * string describing the specification.
 * @throws IllegalArgumentException
 * the specification is invalid.
*/

So "refs/head/" seems mandatory.


Original answer:

The setRemote() function on api.FetchCommand takes a name or an URI.

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();
like image 90
VonC Avatar answered Sep 23 '22 16:09

VonC