Get the default branch of a remote repository with JGit - java

I am working on a Git client, and right now I am trying to implement the checkout of a specific branch. I have a combo box that I populate with branch names, and I would like to find out which branch is the default, so that I can set it as the preselected item in the combo box when connecting to a valid Git repository.
I am listing all the remote branches as you can see below, but I cannot figure out which is the default one.
Map<String, Ref> callAsMap = Git.lsRemoteRepository()
.setRemote("https://github.com/example")
.setCredentialsProvider(credentialsProvider)
.callAsMap();
So, is there a way (standard or "hacky") to detect which Ref object represents the default branch? And how can I get its name?

Repository::getFullBranch returns the current branch of the local repository.
To get the default branch of a remote repository, you need to ask for its HEAD ref. The map that is returned by the snippet that you posted should contain an entry with key HEAD and (if I'm not mistaken) a value that denotes the name of the default branch.
If HEAD refers to an object id, you could obtain a list of all remote refs with repository.getRefDatabase().getRefs(Constants.R_REMOTES) to look up the HEAD id. This approach may be inaccurate as multiple refs could point to the same object id.
Note that it is not required for a remote repository to advertise a default branch.
See also these posts for how C-Git finds the default branch: git - how to get default branch? and What determines default branch after "git clone"?)

After the chain with .get("HEAD"), if it is a symbolic link, you can chain it with .getTarget().getName() to "extract" its name e.g.
Map<String, Ref> callAsMap = Git.lsRemoteRepository()
.setRemote("https://github.com/example")
.setCredentialsProvider(credentialsProvider)
.callAsMap().get("HEAD").getTarget().getName()
Source: https://www.eclipse.org/lists/jgit-dev/msg03320.html

Related

JGit: Can I find out whether or not a particular tag exists in a Git repository without checking it out?

I need to write a piece of code in Java which tests whether or not a particular tag exists in a Git repository.
Most obvious way to do it it this:
git = Git.cloneRepository()
.setURI(gitUri)
.setDirectory(dir)
.call();
git.checkout().setName(String.format("refs/tags/%s", version)).call();
If tag version does not exist, an exception will be thrown.
But this way requires me to have a directory (dir) into which the repository will be checked out.
Is it possible to find out whether or not a tag exists in a remote repository without checking it out on disk? If yes, how can I do it?
The LsRemoteCommand is able to list the refs that a remote repository has.
The command can be configured to include tags like this:
LsRemoteCommand ls = Git.lsRemoteRepository();
Collection<Ref> remoteRefs = ls
.setRemote("url-to-remote-repo")
.setHeads(true) // true by default, set to false if not interested in refs/heads/*
.setTags(true) // include tags in result
.call();
If you prefer to get a map of ref-names to Ref objects, you can execute the command with callAsMap().

How to Copy AEM node one place to another location?

I need to copy an AEM JCR node source to destination. The following code is working but if that node already exists in the destination I'm getting an error:
String sourcePath="/content/dam/assets/content";
String destinationPath="/content/dam/Marketing/content";
Session session = resourceResolver.adaptTo(Session.class);
Workspace workspace = session.getWorkspace();
workspace.copy(sourcePath, destinationPath);
session.logout();
But the problem is that the content node already exists inside the folder "Marketing" so that it's only working on the first time. Once the content node is created I'm not able to copy/update the node but I need to replace each time without deleting the source node.
If you want to operate on a whole node you can always use workspace move/copy operations (workspace.copy(String srcAbsPath, String destAbsPath) to the destination path, where the destination node should not be present/exist in JCR, if it present/exist you will end up with
javax.jcr.ItemExistsException: /jcr/repository/path/nodepresent
and for the workspace clone (workspace.clone(String srcWorkspace, String srcAbsPath, String destAbsPath, boolean removeExisting) usage you need to operate with two different workspaces, if you use the clone operation with the same workspace you will end up with
javax.jcr.RepositoryException: crx.default: illegal workspace (same as
current)
As i can see your requirement is to verify the destination path and update operation, you need to handle it with custom code which can verify destpath and have the NodeIterations and perform update operation.
Also have a look at copy-aem-node-tree-in-jcr which might help for your use case.
Use clone instead of copy.because clone has a removexisting boolean argument. Refer https://docs.adobe.com/docs/en/spec/jsr170/javadocs/jcr-1.0/javax/jcr/Workspace.html#clone

how to find the remote branch of local branch

I created local branch 12345 from origin/master that relevant to gerrit
How I can find the remote name refs/for/master for the local branch 12345
The input is the branch name refs/heads/12345 or part of the string
I calculated it branch Name in :
public String getCurrentBranch() throws GitException {
try {
Ref headRef;
headRef = repository.getRef(Constants.HEAD);
return Repository.shortenRefName(headRef.getLeaf().getName());
} catch (IOException e) {
throw new GitException(e.getMessage(), e);
}
}
How I Can find the result of the remote refs/for/master to res/heads/12345 ?
Do I need to do it from the config ?
You've cross-tagged this as both git and jgit (and then also java, which seems completely inappropriate here, but I'll leave that to others) and I can only give a pure-git answer, which may be unhelpful.
In Git, a branch—by which I mean the branch name, not the structure—can have at most one upstream set. When a branch has an upstream set, the branch is said to track the upstream. This upstream is normally a remote-tracking branch name, e.g., master may track origin/master. The name origin/master is a remote-tracking branch, so we say that "branch master tracks remote-tracking branch origin/master": this has far too many occurrences of the words "branch" and "tracks", each with a different meaning, but we're kind of stuck with it.
A branch that tracks another branch need not track (i.e., have as an upstream) a remote-tracking branch at all. For instance, local branch feature/zorg might track local branch develop. The only things that having an upstream does for you are to automate more of fetch, merge, and rebase (and hence pull which is just fetch followed by one of the other two), and give you more information when running git branch -v (or -vv, etc) and git status. Of course, these are fairly significant, and hence are a reason to set an upstream.
The upstream—the name of the other branch that the given branch is tracking—is set in two parts: a remote, which is the name of a remote if the upstream is a remote-tracking branch, and a branch (name). If the remote is set to ., the branch is tracking another local branch.
These two parts may be obtained individually with git config or git config --get (both do the same thing):
$ git config --get branch.master.remote
origin
$ git config --get branch.master.merge
refs/heads/master
Note that the second part has not undergone the mapping(s) specified by the fetch rule for the given remote:
$ git config --get-all remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
Since this mapping says that refs/heads/* becomes refs/remotes/origin/*, we can determine that our name for the remote-tracking branch that corresponds to refs/heads/master on remote origin is in fact refs/remotes/origin/master. (Of course, this mapping is pretty standard and some software might just assume it, but it's better practice to actually do the mapping using the setting(s) for remotes.origin.fetch. There may be more than one, hence the --get-all here.)
Again, if the remote part is set to ., the upstream is actually a local branch, and no mapping should be applied to the merge part.
In shell script, then, you could do something like:
branch="${1:-master}"
has_upstream=true
remote="$(git config --get branch.$branch.remote)" || has_upstream=false
merge="$(git config --get branch.$branch.merge)" || has_upstream=false
if ! $has_upstream; then
echo "branch $branch has no upstream"
else
case "$remote" in
.) echo "branch $branch tracks local branch $merge";;
*) echo "branch $branch tracks $merge on $remote";;
esac
fi
This does not help with the mapping, if you'd like to check the remote-tracking branch (you may of course need to run git fetch to update it), but you can get that using git rev-parse:
$ git rev-parse --symbolic-full-name master#{u}
refs/remotes/origin/master
Note that you need to strip refs/remotes/ from the result when it is a remote-tracking branch, if you want to use the short form. Of course if the upstream is a local branch, the full name will begin with refs/heads/ rather than refs/remotes/. If you want the current branch's upstream, a simple #{u} suffices; the name#{u} syntax allows you to find other branches' upstream names.
The #{u} suffix makes rev-parse fail if there is no configured upstream:
$ git rev-parse --symbolic-full-name target#{u}
fatal: no upstream configured for branch 'target'
which offers another way to tell if an upstream is configured.
Sorry to be late, but here you go:
private static Ref findCurrentBranch(Git git) throws IOException, GitAPIException {
String currentBranch = git.getRepository().getFullBranch();
return git.branchList()
.setListMode(ListBranchCommand.ListMode.ALL)
.call()
.stream()
.filter(e -> e.getName().equals(currentBranch))
.findFirst()
.get();
}
private static Optional<Ref> findRemoteBranch(Git git, Ref branch) throws GitAPIException {
Optional<Ref> remoteBranch = git.branchList()
.setListMode(ListBranchCommand.ListMode.REMOTE)
.call()
.stream()
.filter(e -> e.getObjectId().getName().equals(branch.getObjectId().getName()))
.findFirst();
return remoteBranch;
}

Need help related with cluster setup

I am trying to make a cluster of ejabberd.For the same purpose i have configured the single node of ejabberd(i am using version 15.04 which is the latest one available)and now to add another node i am trying modify the configuration file.I opened the "/sbin/ejabberdctl" script file for changing the host name and modified the
ERLANG_NODE=ejabberd#localhost to ERLANG_NODE=ejabberd#ejabbered1
and modified the "/etc/ejabberd/ejabberd.yml" ERLANG_NODE=ejabberd#ejabbered1
Now when I try to run the ejabberd using "ejabberdctl start" i could see
Failed RPC connection to the node ejabberd#ejabberd1: nodedown
After going to the "ejabberd.log" i could see
"2015-05-20 06:10:21.462 [critical] <0.38.0>#ejabberd_app:db_init:120 Node name mismatch: I'm [ejabberd#ejabberd1], the database is owned by [ejabberd#localhost]"
Now i want to know how can i change the node name in change node name in Mnesia.
thanks in advance.
You can change the node name associated with a Mnesia database. You either have to restart fresh or export the Mnesia database with old node name and reimport it. See: https://www.ejabberd.im/migrate-host
Note that setting up cluster should not involve changing node name, so I am not sure what you did to get to that state.

How To Use JGit To Do Equivalent Of "git push --mirror ..."?

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 ..."?
Try it manually by using the following ref spec:
git.push().setRefSpecs(new RefSpec("+refs/*:refs/*")).call();
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?

Categories