3

I'm trying to create a simple application that executes a "git push --mirror" operation from the Java domain.

The JGit library, specifically the PushCommand class, doesn't seem to support the "--mirror" option even though it supports "--all" and "--tags".

Am I missing something? How do we use JGit to do "git push --mirror ..."?

robinst
  • 30,027
  • 10
  • 102
  • 108

2 Answers2

4

Try it manually by using the following ref spec:

git.push().setRefSpecs(new RefSpec("+refs/*:refs/*")).call();
robinst
  • 30,027
  • 10
  • 102
  • 108
2

There is no exact equivalent to --mirror in JGit yet, but you should be able to emulate this behaviour. To force-push all local refs you can configure the PushCommand with

PushCommand pushCommand = git.push();
pushCommand.setForce(true);
pushCommand.add("refs/*:refs/*");

That would leave the refs that have been deleted locally. Therefore you can obtain a list of remote-refs to determine what has been deleted locally and publish those deletions to the remote:

Collection<Ref> remoteRefs = git.lsRemote().setRemote("origin").setHeads(true).setTags(true).call();
Collection<String> deletedRefs = new ArrayList<String>();
for (Ref remoteRef : remoteRefs) {
  if (git.getRepository().getRef(remoteRef.getName()) == null) {
    deletedRefs.add(remoteRef.getName());
  }
}
for (String deletedRef : deletedRefs) {
  pushCommand.add(":" + deletedRef);
}

The git variable references the repository that you want to push from, i.e. the one from the first block. The LsRemoteCommand returns all heads and tags from the remote repository that is configured as origin in the local repository's configuration. In the usual case, the one you cloned from.

Please note that there is a small gap to the approach how deleted local refs are propagated. The LsRemoteCommand only returns refs under heads and tags (e.g. no custom refs like pulls), hence you would not detect a local deletion of e.g. refs/foo/bar.

Does that work for you?

Rüdiger Herrmann
  • 20,512
  • 11
  • 62
  • 79
  • The first part works fine (thanks for that). But this deleted references detection seems more difficult. It looks like I would first need to clone a copy of the repo and then do the LsRemoteCommand in the clone (otherwise there is no remote). So is the "git" object in the second block of code supposed to be the git on the far end of the push connection or an extra clone of the repo I have to make before pushing it to the mirror? (Note: I expect to run this application from inside the master storage folder for the git - not a clone.) – DavidCastagna Aug 18 '14 at 19:12
  • I'm supposed to do this right?: Git gRemote = new Git(new FileRepository("<>")) ; Collection remoteRefs = >>gRemote<<.lsRemote().setHeads(true).setTags(true).call() ; Then the rest of what you gave... – DavidCastagna Aug 18 '14 at 19:15
  • I am afraid I don't understand what 'master storage folder for the git' means. My understanding of your initial question is that you have a cloned repository from which you want to issue the `push --mirror`. I've annotatde the second code block in the hope to clarify things. – Rüdiger Herrmann Aug 19 '14 at 11:37
  • No I haven't cloned... and I don't want to. We have a master server with Gits on it and mirror servers with copies (produced by doing "git push --mirror"). If I want to compile a deleted items list as in your code example, how can I calculate the list of items in the mirror server's copy of the Git without cloning it first? Basically it comes down to this: Calling ".lsRemote()" only works on a clone. Is there a way to get a list of all head and tag references without cloning the git first? – DavidCastagna Aug 19 '14 at 13:52
  • There is a satic `Git.lsRemoteRepository()` method, it will return an LsRemoteCommand that works without a (local) repository. It should be possible to replace `git.lsRemote()` from the second code block with `Git.lsRemoteRepository()` and use `setRemote` to specify the URL of the remote repository. But be aware, the statically created `LsRemoteCommand` [has its limitations](http://stackoverflow.com/questions/22631261/list-branches-of-a-git-remote-repo-without-cloning-it/22632027#22632027) – Rüdiger Herrmann Aug 20 '14 at 14:27
  • @RüdigerHerrmann, I know I'm late to the party. It's been more than 3 years someone asked this question. I would like to do ``` git clone --depth 1 git-url ``` is it possible now to do the shallow copy? – supritshah1289 Jun 12 '18 at 00:57
  • As of now, shallow clones are still not supported by JGit, see the comments on https://stackoverflow.com/questions/11475263/shallow-clone-with-jgit – Rüdiger Herrmann Jun 12 '18 at 05:42