GitPython和Git Diff

29
我想仅获取git存储库中更改的文件的差异。目前,我正在使用gitpython来获取提交对象和git更改的文件,但我只想对更改部分进行依赖关系分析。是否有办法从git python获取git diff?还是必须逐行读取每个文件进行比较?
9个回答

24

如果您想访问差异内容,请尝试以下方法:

repo = git.Repo(repo_root.as_posix())
commit_dev = repo.commit("dev")
commit_origin_dev = repo.commit("origin/dev")
diff_index = commit_origin_dev.diff(commit_dev)

for diff_item in diff_index.iter_change_type('M'):
    print("A blob:\n{}".format(diff_item.a_blob.data_stream.read().decode('utf-8')))
    print("B blob:\n{}".format(diff_item.b_blob.data_stream.read().decode('utf-8'))) 

这将打印每个文件的内容。


4
好的,使用GitPython API 进行操作是正确的方式,与直接使用Git CLI 委派不同。这正是Cairo's answer 所做的。 - Michael
使用这段代码时,如何在不同的分支上使用?我不想固定在一个分支上(在您的情况下是dev)。差异获取。 - rRr
你太棒了!我已经寻找这个解决方案一个月了!!为了让它更易读,我将其缩小为“diff = repo.commit(head1).diff(head2)” - Reflection

19
您可以使用GitPython与git命令“diff”一起使用,只需使用每个提交的“tree”对象或要查看差异的分支即可,例如:
repo = Repo('/git/repository')
t = repo.head.commit.tree
repo.git.diff(t)

这将打印出该提交中包含的所有文件的“全部”差异,因此如果您想要每个文件的差异,必须对它们进行迭代。
使用实际分支时,是这样的:
repo.git.diff('HEAD~1')

希望这能帮到您,祝好。

我怎样才能找出treehead~1之间的diff差异呢?它们有相似之处,但后者有更多的差异条目。看起来后者包含了与最后一次提交的差异。 - Timo

6
Git不存储差异,正如你所注意到的那样。给定两个 blob(变化前和变化后),你可以使用Python的difflib模块来比较数据。

我正在工作的repo只有一个主分支。如果我想获取两个blob,我应该如何获取第二个以便于比较变更前的状态? - user1816561
抱歉,还有一个问题。除了尝试获取a blob和b blob并理解它们的含义之外,这些blob是否会给我文件更改的内容? - user1816561
如果你指的是工作树与最近提交之间的差异中的两个 blob,那么你应该使用 repo.head.commit.diff(None) - Addison Klinke
这是 linkpython3 版本。 - Timo

3

我建议您使用PyDriller,它内部使用GitPython。使用起来非常简单:

for commit in Repository("path_to_repo").traverse_commits():
    for modified_file in commit.modified_files: # here you have the list of modified files
        print(modified_file.diff)
        # etc...

您也可以通过以下方式分析单个提交:

for commit in RepositoryMining("path_to_repo", single="123213")

3

如果你想要重现类似于标准 git diff 的内容,可以尝试以下方法:

# cloned_repo = git.Repo.clone_from(
#     url=ssh_url,
#     to_path=repo_dir,
#     env={"GIT_SSH_COMMAND": "ssh -i " + SSH_KEY},
# ) 
for diff_item in cloned_repo.index.diff(None, create_patch=True):
    repo_diff += (
        f"--- a/{diff_item.a_blob.name}\n+++ b/{diff_item.b_blob.name}\n"
        f"{diff_item.diff.decode('utf-8')}\n\n"
        )

1
如果您想在两个提交之间对文件进行 git diff,可以按照以下步骤操作:
import git
   
repo = git.Repo()
path_to_a_file = "diff_this_file_across_commits.txt"
   
commits_touching_path = list(repo.iter_commits(paths=path))
   
print repo.git.diff(commits_touching_path[0], commits_touching_path[1], path_to_a_file)

这将向您展示对您指定的文件进行的两个最新提交之间的差异。

0

PyDriller +1

pip install pydriller

但是使用新的API:

Breaking API: ```
from pydriller import Repository

for commit in Repository('https://github.com/ishepard/pydriller').traverse_commits():
    print(commit.hash)
    print(commit.msg)
    print(commit.author.name)

    for file in commit.modified_files:
        print(file.filename, ' has changed')

0
repo.git.diff("main", "head~5")

1
欢迎来到Stack Overflow!请阅读[提问]和[编辑]您的问题,以包含解释为什么这段代码实际上可以解决手头的问题。请记住,您不仅要解决问题,还要教育提问者和任何未来阅读此帖子的读者。 - Adriaan
结果: @@ -97,6 +97,25 @@
  • org.codehaus.mojo
  • findbugs-maven-plugin
  • 3.0.5
  • 中等
- 土豆先生
如果你想更新 [edit],请勿评论。 - General Grievance

-2

这是如何做到的

import git
repo = git.Repo("path/of/repo/")

# the below gives us all commits
repo.commits()

# take the first and last commit

a_commit = repo.commits()[0]
b_commit = repo.commits()[1]

# now get the diff
repo.diff(a_commit,b_commit)

7
此代码无法运行。出现了两个错误:AttributeError: 'Repo' object has no attribute 'diff'AttributeError: 'Repo' object has no attribute 'commits' - firelynx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接