2014-07-17 3 views
3

git 저장소에 path/to/file1.txt와 path/to/file2.txt라는 두 개의 파일이 있다고 가정 해 보겠습니다. file1.txt가 먼저 커밋되고 file2.txt가 커밋되었으므로 서로 다른 SHA1을 사용하여 커밋됩니다. jGit을 사용하여 각 파일에 해당하는 SHA1을 검색하고 싶습니다. 지금까지 가지고있는 코드는 다음과 같습니다.왜 jGit의 RevWalk.reset() 메소드가 잘못 되었습니까?

String localPath = "/path/to/repo"; 
Repository localRepo = new FileRepository(localPath + "/.git"); 

Ref headRef = localRepo.getRef("refs/heads/master"); 
RevWalk revWalk = new RevWalk(localRepo); 
RevCommit headCommit = revWalk.parseCommit(headRef.getObjectId()); 
TreeWalk tw = new TreeWalk(localRepo); 
tw.addTree(headCommit.getTree()); 
tw.setRecursive(true); 

HashMap<String, String> fileShas = new HashMap<String, String>(); 
RevWalk commitFinder = new RevWalk(localRepo); 

while (tw.next()) { 
    ArrayList<PathFilter> filters = new ArrayList<PathFilter>(); 
    filters.add(PathFilter.create(tw.getPathString())); 

    commitFinder.reset(); 
    RevCommit iterHead = commitFinder.lookupCommit(headRef.getObjectId()); 
    commitFinder.markStart(iterHead); 
    commitFinder.setTreeFilter(AndTreeFilter.create(PathFilterGroup.create(filters), TreeFilter.ANY_DIFF)); 
    commitFinder.setRevFilter(MaxCountRevFilter.create(1)); 

    RevCommit commit = commitFinder.next(); 
    fileShas.put(tw.getPathString(), commit.getId().getName()); 
} 

불행히도 이것은 작동하지 않습니다. 첫 번째 파일에 대해 올바른 SHA1을 얻지 만 두 번째 파일에는 올바른 SHA1을 얻지 못합니다. commitFinder.reset();이 그 일을하지 않는 것 같습니다. 각 반복마다 RevWalk을 새로 작성하면 작동하지만 매우 느립니다. reset()가 작동하지 않는 이유는 무엇입니까?

답변

0

이 질문에 대한 대답은 없지만 필자는 더 나은 가독성을 위해 여기에 내 결과를 기록했습니다. 아래 표시된 테스트의 getLatestModification 메서드는 주어진 파일이 마지막으로 수정 된 커밋의 ID를 반환합니다.

코드가 원래 스 니펫보다 짧지 만 문제는 reset이 작동하지 않는 것으로 나타납니다. discourseCommit의 커밋 이드 beerCommit 같기 때문에

public class RevWalkResetLearningTest { 

    @Rule 
    public final TemporaryFolder tempFolder = new TemporaryFolder(); 

    private Repository repository; 

    @Test 
    public void testReset() throws Exception { 
    RevWalk revWalk = new RevWalk(repository); 
    RevCommit beerCommit = getLastModification(revWalk, "plugins/emoji/public/images/beer.png"); 
// RevCommit discourseCommit = getLastModification(new RevWalk(repository), "images/discourse.png"); 
    RevCommit discourseCommit = getLastModification(revWalk, "images/discourse.png"); 

    assertEquals("8278fdb9ddbc61eea9f6e6045b705106678ce532", beerCommit.name()); 
    assertEquals("50cd44df2dec27c0834be4a2975fe175c3fac64f", discourseCommit.name()); 
    } 

    private RevCommit getLastModification(RevWalk revWalk, String path) throws IOException { 
    revWalk.reset(); 
    revWalk.markStart(revWalk.parseCommit(repository.resolve("refs/heads/master"))); 
    revWalk.setTreeFilter(AndTreeFilter.create(PathFilter.create(path), TreeFilter.ANY_DIFF)); 
    return revWalk.next(); 
    } 

    @Before 
    public void setUp() throws Exception { 
// Git git = Git.cloneRepository().setURI("https://github.com/discourse/discourse.git").setDirectory(tempFolder.getRoot()).call(); 
// repository = git.getRepository(); 
    repository = new FileRepositoryBuilder().setMustExist(true).setGitDir(new File("/path/to/discourse/.git")).build(); 
    } 

    @After 
    public void tearDown() { 
    repository.close(); 
    } 
} 

시험은 실패한다. getLastModification에 대한 각 호출이 RevWalk (주석 처리 된 행 참조)의 새 인스턴스를 가져 오도록 코드를 변경하면 테스트가 성공합니다.

나는 bug report을 열거 나 JGit mailing list에게 도움을 요청합니다.

+0

위대한 예입니다. 감사합니다. 그러나 테스트의 커밋 내역이 문제를 표면화하기에 너무 단순 할 수도 있습니다. 각 파일이 마지막으로 수정 된 커밋을 얻으려고합니다 ** **. 나는 이것을 [담화 프로젝트] (https://github.com/discourse/discourse)의 소스 코드로 대부분 시도했다. 담화의 예가 있습니다. 이 질문에 설명 된 기술은'plugins/emoji/public/images/beer.png'가'189b1c72'에서 마지막으로 수정되었지만'git log plugins/emoji/public/images/beer.png'에서는 '8278fdb9'. – Cameron

+0

또한'git show --name-only 189b1c72'는 커밋에서 변경된 것으로'plugins/emoji/public/images/beer.png'을 ** 나열하지 않습니다 **. 커밋 메시지 ("FEATURE : 주제 상태에 대한 쿼리 매개 변수")는 그림 이모티콘과 관련이없는 것으로 보입니다. – Cameron

+0

jgit 3.4.1.201406201815-r을 사용하고 있습니다. – Cameron