Вопрос

Некоторое время назад я искал встраиваемая распределенная система контроля версий на Java, и я думаю, что нашел это в JGit, который представляет собой чистую Java-реализацию git.Однако здесь не так уж много примеров кода или учебных пособий.

Как я могу использовать JGit для получения HEAD-версии определенного файла (точно так же, как svn cat или hg cat кто бы сделал)?

Я предполагаю, что это требует некоторого обхода дерева версий, и я ищу образец кода.

Это было полезно?

Решение

К сожалению, ответ Тило не работает с последней версией API JGit.Вот решение, которое я нашел:

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)

Я бы хотел, чтобы это было проще.

Другие советы

Вот более простая версия ответа @morisil, использующая некоторые концепции из @directed смеха и протестированная с помощью 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 — это объект репозитория, созданный в других ответах.

Я последовал за ответом @Thilo и @morisil, чтобы получить это, совместимое с 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();

Я не проверял версию Java, но она должна работать.Это переводится с

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

в Clojure (следуя той же настройке, что и верхний раздел), который работает.

Разобрался сам.API довольно низкоуровневый, но это не так уж и плохо:

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

Я начал писать библиотеку под названием гитивный который содержит множество помощников для работы с большими двоичными объектами, коммитами и деревьями с использованием JGit, имеет лицензию MIT и доступен на GitHub.

Получить содержимое файла в фиксации HEAD

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

Получить содержимое файла в ветке

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

Разница двух файлов

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

Дополнительные примеры предоставляемых утилит подробно описаны в ПРОЧТИ МЕНЯ.

Есть некоторая информация на Учебное пособие по JGit (но это также не является ни полезным, ни полным и, вероятно, устарело, поскольку они перешли на затмение где еще нет документации).

Вы можете прочитать содержимое заданного пути к файлу следующим образом.Имейте в виду, что TreeWalk может быть нулевой если в данном дереве путь не найден.Поэтому он требует определенного обращения.

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.");
        }
    }
}

Например:

ObjectId head = repo.resolve(Constants.HEAD);
RevCommit last = repo.parseCommit(head);
readFile(last, "docs/README.md")

Этот ответ написан с помощью JGit 4.8.0.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top