2015-08-05 6 views
2

Я использую JGit для одного из моих проектов, который предполагает интуитивное использование git.JGit: начальная точка отмены RevWalk

Моя цель - использовать RevWalk, чтобы иметь возможность выполнять итерацию по записям в репозитории в хронологическом порядке, начиная с commit. Я сумел добиться их обоих separetely:

  • Последовательность путем применения RevSort.REVERSE
  • Начальная точка по телефону RevWalk.markStart(RevCommit c)

Моя проблема заключается в том, что, когда я пытаюсь объединить два, это похоже, что RevSort переопределяет markStart, и RevWalk всегда заканчивается, начиная с начала фиксации фиксации, которую я указал.

Этот пример показывает, что у меня есть:

import org.eclipse.jgit.lib.Repository; 
import org.eclipse.jgit.internal.storage.file.FileRepository; 
import org.eclipse.jgit.revwalk.RevWalk; 
import org.eclipse.jgit.revwalk.RevCommit; 
import org.eclipse.jgit.revwalk.RevSort; 

import java.io.IOException; 
import org.eclipse.jgit.errors.AmbiguousObjectException; 
import org.eclipse.jgit.errors.MissingObjectException; 

public class Main { 

    public static void main(String[] args) throws IOException, AmbiguousObjectException, MissingObjectException { 
     final String repositoryPath = args[0]; 
     final String commitID = args[1]; 
     final Repository repository = new FileRepository(repositoryPath + "/.git"); 
     final RevWalk walk = new RevWalk(repository); 
     walk.sort(RevSort.REVERSE); 
     walk.markStart(walk.parseCommit(repository.resolve(commitID))); 
     for (final RevCommit revCommit : walk) { 
      System.err.println(revCommit.getId()); 
     } 
    } 

} 

Это должно напечатает идентификатор хранилища в обратном порядке, начиная с коммит указан, но он просто игнорировать второй параметр и начинается от начальной фиксации ,

UPDATE:

Я исследовал больше проблемы и получается, что при применении этих двух вариантов вместе (в любом порядке), то markStart становится markStop. Я думаю, что это вызвано тем, что markStart всегда выполняется первым и ограничивает диапазон коммитов (с фильтром), а затем сменяя их на RevSort. В принципе, RevWalk выполняет итерацию по комплементарному набору коммитов, который меня интересует.

Должен ли я предположить, что то, что я пытаюсь сделать, невозможно получить таким образом? Я не мог придумать другой способ получить его, не пройдя весь репозиторий до начальной точки, но это звучит крайне неэффективно.

ОБНОВЛЕНИЕ 2: Чтобы привести пример, вот что я ожидал достичь. Предположим, что у нас есть хранилище, содержащее 4 фиксации: A, B, C и D. Меня интересуют только комментарии от B до текущей версии, за исключением A, в хронологическом порядке. Я надеялся, чтобы иметь возможность использовать markStart и sort для достижения этой цели следующим образом:

@Test 
public void testReverse2() throws Exception { 
    final RevCommit commitA = this.git.commit().setMessage("Commit A").call(); 
    final RevCommit commitB = this.git.commit().setMessage("Commit B").call(); 
    final RevCommit commitC = this.git.commit().setMessage("Commit C").call(); 
    final RevCommit commitD = this.git.commit().setMessage("Commit D").call(); 

    final RevWalk revWalk = new RevWalk(this.git.getRepository()); 
    revWalk.markStart(revWalk.parseCommit(commitB)); 
    revWalk.sort(RevSort.REVERSE); 

    assertEquals(commitB, revWalk.next()); 
    assertEquals(commitC, revWalk.next()); 
    assertEquals(commitD, revWalk.next()); 
    assertNull(revWalk.next()); 
    revWalk.close(); 
} 

Теперь от того, что я видел, это не работает, потому что markStart всегда выполняется перед sort, так фактическое поведение удовлетворяет следующему тесту:

assertEquals(commitA, revWalk.next()); 
assertEquals(commitB, revWalk.next()); 
assertNull(revWalk.next()); 

Это противоположность тому, что я пытаюсь получить. Является ли это задуманным поведением, и если да, то каким другим способом я могу подойти к проблеме?

ответ

0

В Git совершает есть только ссылки на их родителей (s) , commitB не знает о своих преемниках commitC и commitD.

Следовательно, история может быть пройдена только назад, от данной фиксации к ее родительской, грандиозной паре и т. Д. Нет информации для перемещения в противоположном направлении.

В вашем примере RevWalk будет проходить от commitB до commitÀ. Тип REVERSE повлияет только на то, как итератор будет вести себя, но не может ходить вперед.

Если вы действительно хотите найти коммиты между commitB и HEAD, вам нужно будет начать с HEAD. Или, что более общее, вам нужно будет начать со всех известных советов ветви, чтобы найти возможные пути, которые приводят к commitB.

+0

Предполагая, что меня интересует только одна ветвь, как лучше всего перейти от 'commitB' к' HEAD' (поддерживая хронологический порядок)? Мой нынешний подход оказался тем, что использовал «сортировку» и просто делал целую прогулку с самого начала, вручную определяя, где я пришел к точке, которую я хотел установить как «start». Но это кажется довольно неэффективным, есть ли другой подход? – vivianig

+0

Пересмотреть, как общаются друг с другом в Git. Другого подхода нет: начинайте с головы (т. Е. Вы можете узнать, с какой стороны вы знаете 'commitB') и пройдите до тех пор, пока не найдете требуемую фиксацию. Я не понимаю, почему это неэффективно. –

0

API JGit не дает противопоказаний к объединению сортировки и markStart. Исходный код JGit также не показывает никаких проблем с поверхностью. На мой взгляд, для исправления этого непосредственно требуется отладка на уровне исходного кода. Вам понадобится источник JGit и нужно запустить ваш пример в отладчике.

В качестве альтернативы вы можете течь RevWalk с Spliterator без сортировки на отсортирован по сравнению с RevCommit: getCommitTime() следующим образом:

StreamSupport.stream(walk.spliterator()) 
    .sorted(RevCommit::getCommitTime()) 
    .toList(); 
+0

Да, я провел более глубокое расследование по источнику и обновил исходное сообщение. – vivianig

+0

@vivianig благодарим вас за обновление. Я думаю, вам, возможно, придется принять дорогостоящий подход. Будет ли мой обход посещать больше хранилища Git, чем сортировка? Это может оказаться эквивалентным. Сколько времени занимает каждый метод (без markStart)? Мое решение выше должно использовать прогулку после вызова markStart, чтобы отразить ваше намерение напрямую. –

+0

Вероятно, это будет эквивалентно, поскольку ему все равно придется проходить через весь репозиторий, чтобы добраться до данной точки. Моя проблема заключается в том, как работает 'markStart', и я не думаю, что изменение способа итерации по фильтруемому набору коммитов помогло бы. Я еще раз просмотрю его позже. – vivianig