2009-11-06 11 views
23

Hace un tiempo que estaba buscando un embeddable distributed version control system in Java, y creo que lo he encontrado en JGit, que es una implementación pura de Java de git. Sin embargo, no hay muchos ejemplos de código o tutoriales.¿Cómo "cat" un archivo en JGit?

¿Cómo puedo usar JGit para recuperar la versión HEAD de un determinado archivo (como lo haría svn cat o hg cat)?

Supongo que esto implica algo de rev-tree-walking y estoy buscando una muestra de código.

+1

Los desarrolladores son bastante rápidos para responder en la lista de correo: https://dev.eclipse.org/mailman/listinfo/egit-dev. Sugiero que lo pruebes. –

Respuesta

18

Desafortunadamente la respuesta de Thilo no funciona con la última API JGit. Esta es la solución que encontré:

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) 

Ojalá fuera más simple.

+28

¿Quién en el mundo diseñó esta API? – Jochen

+1

¿Sabes cuál es el enésimo valor de treeWalk.getObjectId (nth)? (es decir, ¿cuáles son los casos en que pasamos un valor a treeWalk.getObjectId mayor que 0?) –

+0

@DinisCruz 'TreeWalk' puede recorrer más de un árbol (al invocar' addTree' varias veces). En ese caso, puede usar 'getObjectId (N)' para obtener la ID del objeto del árbol N (que podría ser igual o diferente, según los árboles). – robinst

3

Hay alguna información en JGit Tutorial (pero tampoco es realmente útil ni completa y probablemente obsoleta ya que cambiaron a eclipse donde aún no hay documentación disponible).

5

Entendí por mi cuenta. La API es bastante bajo nivel, pero no es tan malo:

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(); 
+2

Esto parece ser un ejemplo desactualizado con la versión actual de JGit. La API ha cambiado un poco, ten cuidado. –

+1

@Jonathan Dumaine: Actualice la publicación si es necesario (y ya sabe cómo) – Thilo

4

He comenzado a escribir una biblioteca llamada gitective que contiene muchos ayudantes para trabajar con blobs, commits y árboles usando JGit y está licenciada por MIT y disponible en GitHub.

obtener el contenido del archivo en la cabeza de cometer

Repository repo = new FileRepository("/repos/project/.git"); 
String content = BlobUtils.getHeadContent(repo, "src/Buffer.java"); 

obtener el contenido de un archivo en una rama

Repository repo = new FileRepository("/repos/project/.git"); 
String content = BlobUtils.getContent(repo, "master", "src/Buffer.java"); 

de diferencia de dos archivos

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

Más ejemplos de utilidades proporcionadas se detallan en el README.

+0

Se ve bien. Si no hubiera escrito mi proyecto jGit definitivamente lo hubiera usado. –

11

Seguí @ Thilo de @ y la respuesta de morisil para conseguir esto, compatible con 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(); 

no he probado la versión Java pero debería funcionar. Se traduce de

(.getBytes (.open repo (.getObjectId (TreeWalk/forPath repo "b/test.txt" tree) 0))) 

en clojure (siguiendo la misma configuración que la sección superior), que funciona.

+0

¡Funciona muy bien! Fui directamente al archivo: 'FileOutputStream fileOS = new FileOutputStream (ruta); if (treewalk! = Null) {repo.open (treewalk.getObjectId (0)). CopyTo (fileOS);} 'then' fileOS.close; ' –

+0

Se deben responder más preguntas de Java en Clojure. – user12341234

15

Aquí es una versión más simple de la respuesta de @ morisil, el uso de algunos de los conceptos de la risa de @directed y probado con 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 es un objeto de repositorio como creado en las otras respuestas.

+1

Se ve bien, excepto para devolver getBytes() mientras que el tipo de devolución es Cadena. Tenga en cuenta que también debe llamar a 'release' en' walk' y 'treeWalk' para liberar recursos. Para hacer eso solo una vez, llame a 'ObjectReader reader = repo.newObjectReader()' y páselo a Revwalk y Treewalk en lugar de al repositorio. Luego llama a 'reader.release()' en un bloque finally. – robinst

+0

@robinst: Muchas gracias por señalarlo, lo corrigieron. – creinig

+0

También se necesita liberar RevWalk, mover la llamada a 'newObjectReader' y utilizar' nueva RevWalk (lector) 'en su lugar. – robinst