2013-08-29 4 views
3

저는 푸시에 포함 된 커밋에 대한 정보를 수집하는 Python과 Git-Python을 사용하여 git post-receive 후크를 작성한 다음 버그 추적기와 IM에 요약 정보를 업데이트합니다. 푸시가 지점을 만드는 경우 (즉, 수신 후 fromrev 매개 변수가 모두 0 임) 문제가 발생하며 해당 분기에 대한 여러 커밋에 걸쳐 있습니다. 나는 부모 목록을 torev 커밋에서 뒤로 걷고 있는데, 어떤 커밋이 브랜치의 첫 번째인지, 즉 언제 멈출지를 어떻게 알 수 있는지 파악할 수 없습니다.GitPython을 사용하여 지점에서 첫 번째 커밋 찾기.

명령 행에서

나는 나에게 정확히 this-branch에서 커밋의 목록없이 다른 사람을 줄 것이다

git rev-list this-branch ^not-that-branch ^master 

을 할 수 있습니다. 나는 Commit.iter_parents 메쏘드를 사용하여 이것을 복제하려고 시도했다.이 메쏘드는 git-rev-list와 같은 매개 변수를 취하는 것으로 문서화되어 있지만, 나는 볼 수있는 한 위치 매개 변수를 좋아하지 않는다. 그리고 키워드 집합을 찾을 수 없다. params는 작동합니다.

덜 리치 (Dulwich)의 문서를 읽었지만 Git-Python과 다른 점이 있는지 여부는 분명하지 않았습니다.

내 (단순화 된) 코드는 다음과 같습니다. 푸시 다음은 현재 첫 번째 커밋에 보이는 새로운 지점을 시작하면 중지 :

난 그냥 dulwich와 함께 놀았
import git 
repo = git.Repo('.') 
for line in input: 
    (fromrev, torev, refname) = line.rstrip().split(' ') 
    commit = repo.commit(torev) 
    maxdepth = 25 # just so we don't go too far back in the tree 
    if fromrev == ('0' * 40): 
     maxdepth = 1 
    depth = 0 
    while depth < maxdepth: 
     if commit.hexsha == fromrev: 
      # Reached the start of the push 
      break 
     print '{sha} by {name}: {msg}'.format(
      sha = commit.hexsha[:7], user = commit.author.name, commit.summary) 
     commit = commit.parents[0] 
     depth += 1 

답변

2

은, 어쩌면이 작업을 수행하는 더 나은 방법이 (A 내장 워커와 함께?). 하나의 새로운 지점 (또는 공통점이 아무것도 여러 새로운 지점) 거기 가정 :

#!/usr/bin/env python 
import sys 
from dulwich.repo import Repo 
from dulwich.objects import ZERO_SHA 


def walk(repo, sha, shas, callback=None, depth=100): 
    if not sha in shas and depth > 0: 
     shas.add(sha) 

     if callback: 
      callback(sha) 

     for parent in repo.commit(sha).parents: 
      walk(repo, parent, shas, callback, depth - 1) 


def reachable_from_other_branches(repo, this_branch): 
    shas = set() 

    for branch in repo.refs.keys(): 
     if branch.startswith("refs/heads") and branch != this_branch: 
      walk(repo, repo.refs[branch], shas) 

    return shas 


def branch_commits(repo, fromrev, torev, branchname): 
    if fromrev == ZERO_SHA: 
     ends = reachable_from_other_branches(repo, branchname) 
    else: 
     ends = set([fromrev]) 

    def print_callback(sha): 
     commit = repo.commit(sha) 
     msg = commit.message.split("\n")[0] 
     print('{sha} by {author}: {msg}' 
       .format(sha=sha[:7], author=commit.author, msg=msg)) 

    print(branchname) 
    walk(repo, torev, ends, print_callback) 


repo = Repo(".") 
for line in sys.stdin: 
    fromrev, torev, refname = line.rstrip().split(' ') 
    branch_commits(repo, fromrev, torev, refname) 
+1

감사합니다 (이 큰 저장소에 대한 O (n)의 메모리를 사용하는 해결하기 위해 반복자를 사용합니다) - 덜 리치 (Dulwich)에서 워커 객체를 보지 못했고 그 중 하나를 사용하여 멋지게 할 수있는 것 같습니다. 곧 일부 코드를 게시합니다. – julianz

3

순수 힘내 - 파이썬을 사용하여, 그것은 또한 수행 할 수 있습니다. 나는 어느 쪽이든 그것을 할 kwargs의 세트를 확인하는 방법을 찾아 내지 않았다.

from git import * 

repo_path = '.' 
repo = Repo(repo_path) 
parent_branch = repo.branches.master 
examine_branch = repo.branches.test_feature_branch 

other_shas = set() 
for parent_commit in repo.iter_commits(rev=parent_branch): 
    other_shas.add(parent_commit.hexsha) 
for commit in repo.iter_commits(rev=examine_branch): 
    if commit.hexsha not in other_shas: 
     first_commit = commit 

print '%s by %s: %s' % (first_commit.hexsha[:7], 
     first_commit.author.name, first_commit.summary) 

그리고 만약 :하지만 하나는 단순히 마스터 지점의 SHA 세트를 구성 할 수 있습니다, 다음 상위에 표시되지 않는 첫 번째 하나를 찾기 위해에 - - 검사 지점에 iter_commits를 사용

other_shas = set() 
for branch in repo.branches: 
    if branch != examine_branch: 
     for commit in repo.iter_commits(rev=branch): 
      other_shas.add(commit.hexsha) 
  • 주의 할 1 : 2 방식이를 보여줍니다 당신이 정말로 다른 모든 지점에있는 모든 커밋을 제외해야 할, 당신은 첫째을 위해 루프의 또 다른 repo.branches 이상 - 루프 것을 포장 할 수 있습니다 첫 번째 커밋은 다른 분기에는 나타나지 않지만이 분기의 첫 번째 커밋 일 필요는 없습니다. feat_b가 master에서 오는 feat_a에서 분기 된 경우 feat_a가 분기 된 후에 feat_a에 대한 첫 번째 커밋이 표시됩니다. 나머지 feat_a 커밋은 이미 feat_b에 있습니다.
  • 주의 사항 2 : git rev-list 및 두 가지 해결책은 분기가 마스터로 병합되지 않은 경우에만 작동합니다. 말 그대로이 지사에있는 모든 커밋을 나열하고 다른 지에는 커밋하지 말 것을 요구하고 있습니다.
  • 비고 : 두 번째 접근법은 잔인하며 완료하는 데 약간 더 시간이 걸립니다. 더 나은 접근법은 다른 분기를 알려진 병합 분기 목록으로 제한하는 것입니다.이 같은
1

뭔가가 먼저 커밋 발견 할 것이다 :

x = Repo('.') 
print list(x.get_walker(include=[x.head()]))[-1].commit 

관련 문제