我正在编写一个Python脚本来获取即将由git pull
操作应用的提交列表。优秀的GitPython library是一个很好的基础,但是git的微妙内部运作正在扼杀我。现在,这是我目前所拥有的(简化和注释版本):
repo = git.Repo(path) # get the local repo
local_commit = repo.commit() # latest local commit
remote = git.remote.Remote(repo, 'origin') # remote repo
info = remote.fetch()[0] # fetch changes
remote_commit = info.commit # latest remote commit
if local_commit.hexsha == remote_commit.hexsha: # local is updated; end
return
# for every remote commit
while remote_commit.hexsha != local_commit.hexsha:
authors.append(remote_commit.author.email) # note the author
remote_commit = remote_commit.parents[0] # navigate up to the parent
基本上,它会让所有提交的作者在下一个git pull
中应用。这很好用,但它有以下问题:
我可以处理在本地后面的远程存储库:只是同时查看另一个方向(本地到远程),代码变得混乱,但它可以工作。但是最后一个问题是杀了我:现在我需要navegate一个(可能是无限的)树来找到本地提交的匹配。这不仅仅是理论上的:我的最新变化是一个repo merge,它提出了这个问题,所以我的脚本无效。
获取远程存储库中的有序提交列表,例如repo.iter_commits()
对本地Repo的提交,将是一个很好的帮助。但我没有在documentation中找到如何做到这一点。我可以为远程存储库获取Repo对象吗?
是否有其他方法可以让我在那里,而且我用锤子钉钉子?
答案 0 :(得分:0)
我意识到提交树总是这样:一个提交有两个父母,父母都有同一个父母。这意味着第一次提交有两个父母,但只有一个祖父母。
因此编写一个自定义迭代器来覆盖提交(包括分叉树)并不是很难。它看起来像这样:
def repo_changes(commit):
"Iterator over repository changes starting with the given commit."
number = 0
next_parent = None
yield commit # return the first commit itself
while len(commit.parents) > 0: # iterate
same_parent(commit.parents) # check only one grandparent
for parent in commit.parents: # go over all parents
yield parent # return each parent
next_parent = parent # for the next iteration
commit = next_parent # start again
当有两个父母和一个以上的祖父母时,函数same_parent()
会发出警告。现在迭代未合并的提交是一件简单的事情:
for commit in repo_changes(remote_commit):
if commit.hexsha == local_commit.hexsha:
return
authors.append(remote_commit.author.email)
为了清楚起见,我留下了一些细节。我永远不会返回超过预定数量的提交(在我的情况下为20),以避免到达回购的最后。我还事先检查了本地仓库是否在远程仓库之前。除此之外,它工作得很好!现在我可以提醒所有提交作者他们的更改正在合并。
答案 1 :(得分:0)
我知道这是年龄岁,但是我只需要为一个项目做这件事……
head = repo.head.ref
tracking = head.tracking_branch()
return tracking.commit.iter_items(repo, f'{head.path}..{tracking.path}')
(相反,要知道有多少本地提交有待推送,只需将其反转:head.commit.iter_items(repo, f'{tracking.path}..{head.path}')
)