2009-11-06 9 views
23

Qualche tempo fa cercavo un embeddable distributed version control system in Java, e penso di averlo trovato in JGit, che è una pura implementazione Java di git. Tuttavia, non c'è molto in termini di codice di esempio o tutorial.Come "cat" un file in JGit?

Come è possibile utilizzare JGit per recuperare la versione HEAD di un determinato file (analogamente allo svn cat o hg cat)?

Suppongo che questo comporti alcuni giri dell'albero e sto cercando un esempio di codice.

+1

Gli sviluppatori sono piuttosto pronti a rispondere sulla mailing list: https://dev.eclipse.org/mailman/listinfo/egit-dev. Ti suggerisco di fare un tentativo. –

risposta

18

Purtroppo la risposta di Thilo non funziona con l'ultima API JGit. Ecco la soluzione che ho trovato:

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) 

Vorrei che fosse più semplice.

+28

Chi ha progettato questa API nel mondo? – Jochen

+1

Sai qual è l'ennesimo valore di treeWalk.getObjectId (nth)? (cioè, in quali casi passiamo un valore a treeWalk.getObjectId maggiore di 0?) –

+0

@DinisCruz 'TreeWalk' può camminare su più di un albero (chiamando' addTree' più volte). In tal caso, è possibile utilizzare 'getObjectId (N)' per ottenere l'ID oggetto dall'albero N (che potrebbe essere uguale o diverso, a seconda degli alberi). – robinst

3

Ci sono alcune informazioni allo JGit Tutorial (ma anche questo non è né molto utile né completo e probabilmente obsoleto da quando sono passati a eclipse dove non è ancora disponibile alcuna documentazione).

5

Capito da solo. L'API è piuttosto basso livello, ma non è troppo male:

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

Questo sembra essere un esempio obsoleto con l'attuale versione di JGit. L'API è leggermente cambiata, fai attenzione. –

+1

@Jonathan Dumaine: aggiorna il post se necessario (e sai come) – Thilo

4

Ho iniziato a scrivere una libreria denominata gitective che contiene molti helper per lavorare con BLOB, commit e alberi utilizzando JGit ed è dotata di licenza MIT e disponibile su GitHub.

contenuti, scarica di file in HEAD commettere

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

ottenere contenuti di un file su un ramo

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

Diff due file

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

Altri esempi di utilità fornite sono dettagliate nello README.

+0

Sembra carino. Se non avessi già scritto il mio progetto jGit, lo avrei sicuramente usato. –

11

ho seguito @ Thilo di e @ risposta di morisil per ottenere questo, compatibile 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(); 

non ho la prova della versione di Java, ma dovrebbe funzionare. Si traduce da

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

in clojure (seguendo la stessa impostazione della sezione superiore), che funziona.

+0

Funziona alla grande! Sono andato direttamente al file: 'FileOutputStream fileOS = new FileOutputStream (path); if (treewalk! = Null) {repo.open (treewalk.getObjectId (0)). CopyTo (fileOS);} 'then' fileOS.close; ' –

+0

Altre domande Java devono essere risolte in Clojure. – user12341234

15

Ecco una versione più semplice di risposta di @ morisil, utilizzando alcuni dei concetti da laugh @directed di e testato 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 è un oggetto repository come creata nelle altre risposte.

+1

Sembra buono, tranne che per restituire getBytes() mentre il tipo restituito è String. Nota che devi anche chiamare 'release' su' walk' e 'treeWalk' per liberare risorse. Per farlo una sola volta, chiamate 'ObjectReader reader = repo.newObjectReader()' e passatelo a Revwalk e Treewalk al posto del repository. Quindi chiama 'reader.release()' in un blocco finale. – robinst

+0

@robinst: Mille grazie per averlo indicato - risolto. – creinig

+0

RevWalk deve anche essere rilasciato, spostare la chiamata a 'newObjectReader' su e utilizzare' new RevWalk (reader) '. – robinst