Como “gato” um arquivo em JGit?
Pergunta
Um tempo atrás eu estava procurando uma href="https://stackoverflow.com/questions/177469/embeddable-distributed-version-control-system-in-java"> embutido sistema de controle de versão distribuído , e eu acho que eu tê-lo encontrado no JGit , que é uma implementação Java pura de git. No entanto, não há muito na forma de código de exemplo ou tutoriais.
Como posso usar JGit para recuperar a versão HEAD de um determinado arquivo (como svn cat
ou hg cat
whould fazer)?
Suponho que isso envolve alguma rev-árvore-pé e estou procurando um exemplo de código.
Solução
Infelizmente a resposta de Thilo não funciona com a mais recente API JGit. Aqui está a solução que eu encontrei:
File repoDir = new File("test-git");
// open the repository
Repository repository = new Repository(repoDir);
// find the HEAD
ObjectId lastCommitId = repository.resolve(Constants.HEAD);
// now we have to get the commit
RevWalk revWalk = new RevWalk(repository);
RevCommit commit = revWalk.parseCommit(lastCommitId);
// and using commit's tree find the path
RevTree tree = commit.getTree();
TreeWalk treeWalk = new TreeWalk(repository);
treeWalk.addTree(tree);
treeWalk.setRecursive(true);
treeWalk.setFilter(PathFilter.create(path));
if (!treeWalk.next()) {
return null;
}
ObjectId objectId = treeWalk.getObjectId(0);
ObjectLoader loader = repository.open(objectId);
// and then one can use either
InputStream in = loader.openStream()
// or
loader.copyTo(out)
Eu gostaria que fosse mais simples.
Outras dicas
Aqui está uma versão mais simples da resposta de @ morisil, usando alguns dos conceitos de @directed risada de e testado com JGit 2.2.0:
private String fetchBlob(String revSpec, String path) throws MissingObjectException, IncorrectObjectTypeException,
IOException {
// Resolve the revision specification
final ObjectId id = this.repo.resolve(revSpec);
// Makes it simpler to release the allocated resources in one go
ObjectReader reader = this.repo.newObjectReader();
try {
// Get the commit object for that revision
RevWalk walk = new RevWalk(reader);
RevCommit commit = walk.parseCommit(id);
// Get the revision's file tree
RevTree tree = commit.getTree();
// .. and narrow it down to the single file's path
TreeWalk treewalk = TreeWalk.forPath(reader, path, tree);
if (treewalk != null) {
// use the blob id to read the file's data
byte[] data = reader.open(treewalk.getObjectId(0)).getBytes();
return new String(data, "utf-8");
} else {
return "";
}
} finally {
reader.release();
}
}
repo
é um objeto Repository como criado em outras respostas.
Segui @ Thilo de e @ da morisil resposta para conseguir isso, compatível com JGit 1.2.0:
File repoDir = new File("test-git/.git");
// open the repository
Repository repo = new Repository(repoDir);
// find the HEAD
Commit head = repo.mapCommit(Constants.HEAD);
// retrieve the tree in HEAD
Tree tree = head.getTree();
// 1.2.0 api version here
// find a file (as a TreeEntry, which contains the blob object id)
TreeWalk treewalk = TreeWalk.forPath(repo, "b/test.txt", tree);
// use the blob id to read the file's data
byte[] data = repo.open(treewalk.getObjectId(0)).getBytes();
Eu não testei a versão Java, mas ele deve funcionar. Ele traduz a partir
(.getBytes (.open repo (.getObjectId (TreeWalk/forPath repo "b/test.txt" tree) 0)))
em Clojure (seguindo a mesma configuração como a seção superior), que faz o trabalho.
Descobri-lo por mim. A API é bastante baixo nível, mas não é muito ruim:
File repoDir = new File("test-git/.git");
// open the repository
Repository repo = new Repository(repoDir);
// find the HEAD
Commit head = repo.mapCommit(Constants.HEAD);
// retrieve the tree in HEAD
Tree tree = head.getTree();
// find a file (as a TreeEntry, which contains the blob object id)
TreeEntry entry = tree.findBlobMember("b/test.txt");
// use the blob id to read the file's data
byte[] data = repo.openBlob(entry.getId()).getBytes();
Eu comecei a escrever uma biblioteca chamada gitective que contém muitos ajudantes para trabalhar com gotas, commits, e árvores usando JGit e é MIT-licenciado e disponível no GitHub.
Obter conteúdo de arquivo em CABEÇA cometer
Repository repo = new FileRepository("/repos/project/.git");
String content = BlobUtils.getHeadContent(repo, "src/Buffer.java");
Obter conteúdo de um arquivo em um ramo
Repository repo = new FileRepository("/repos/project/.git");
String content = BlobUtils.getContent(repo, "master", "src/Buffer.java");
Diff dois arquivos
Repository repo = new FileRepository("/repos/project/.git");
ObjectId current = BlobUtils.getId(repo, "master", "Main.java");
ObjectId previous = BlobUtils.getId(repo, "master~1", "Main.java");
Collection<Edit> edit = BlobUtils.diff(repo, previous, current);
Mais exemplos de utilitários fornecidos estão detalhados na README .
Há algumas informações em JGit Tutorial (mas que também não é nem realmente útil nem completa e provavelmente desatualizado desde que mudou para eclipse onde nenhuma documentação está disponível ainda).
Você pode ler o conteúdo de um determinado caminho de arquivo da seguinte forma. Por favor, esteja ciente de que o TreeWalk pode ser nulo se nenhum caminho foi encontrado na árvore dada. Por isso requer algum tratamento específico.
public String readFile(RevCommit commit, String filepath) throws IOException {
try (TreeWalk walk = TreeWalk.forPath(repo, filepath, commit.getTree())) {
if (walk != null) {
byte[] bytes = repo.open(walk.getObjectId(0)).getBytes();
return new String(bytes, StandardCharsets.UTF_8);
} else {
throw new IllegalArgumentException("No path found.");
}
}
}
Por exemplo:
ObjectId head = repo.resolve(Constants.HEAD);
RevCommit last = repo.parseCommit(head);
readFile(last, "docs/README.md")
Esta resposta é escrito com JGit 4.8.0.