From 541b68ec1c5e2883838cab75a4424b71644b73e0 Mon Sep 17 00:00:00 2001 From: Luka Hietala Date: Wed, 19 Nov 2025 17:10:46 +0200 Subject: [PATCH] add diff deltas and their line stats --- git/diff.py | 47 ++++++++++++++++++++++++++++++++++++++++++--- templates/diff.html | 10 +++++++++- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/git/diff.py b/git/diff.py index 27b97c6..5e5b75c 100644 --- a/git/diff.py +++ b/git/diff.py @@ -1,13 +1,54 @@ import pygit2 as git -# compares two refs and return diff -# TODO: per file, now just full hunk, per file stats, and no changes to compare. +# compares two refs and return diff stats per file and full patch def get_diff(path, id1="HEAD", id2="HEAD"): repo = git.Repository(path) ref_one = repo.revparse_single(id1) ref_two = repo.revparse_single(id2) diff = repo.diff(ref_one, ref_two) - return diff.patch + # TODO: context_lines, interhunk_lines, etc as options + + # detect renames and copies, if not they are just deletions and additions + # rename and copy thresholds are 50% by default in libgit2 + # https://libgit2.org/docs/reference/main/diff/git_diff_find_options.html + # debating whether to keep or remove this, but for now it's useful. or atleast alter the default thresholds + diff.find_similar() + + # map libgit2 delta status to human readable, most not used, but good to have them all here + status_map = { + git.GIT_DELTA_ADDED: 'added', + git.GIT_DELTA_DELETED: 'deleted', + git.GIT_DELTA_MODIFIED: 'modified', + git.GIT_DELTA_RENAMED: 'renamed', + git.GIT_DELTA_COPIED: 'copied', + git.GIT_DELTA_IGNORED: 'ignored', + git.GIT_DELTA_UNTRACKED: 'untracked', + git.GIT_DELTA_TYPECHANGE: 'typechange', + git.GIT_DELTA_UNREADABLE: 'unreadable', + git.GIT_DELTA_CONFLICTED: 'conflicted' + } + + patches = list(diff) + deltas = diff.deltas + changed_files = [] + + for i, delta in enumerate(deltas): + patch = patches[i] + file_path = delta.new_file.path if delta.new_file.path else delta.old_file.path + # insertions and deletions in diff stats and additions and deletions in delta line stats. little confusing + _, additions, deletions = patch.line_stats # (context, additions, deletions) + status_str = status_map.get(delta.status, 'unknown') + changed_files.append({ + 'file': file_path, + 'additions': additions, + 'deletions': deletions, + 'status': status_str + }) + + return { + 'patch': diff.patch, + 'files': changed_files + } diff --git a/templates/diff.html b/templates/diff.html index c70022f..a1da9de 100644 --- a/templates/diff.html +++ b/templates/diff.html @@ -1,5 +1,13 @@ {% block content %} +

Changed Files

+ + +

Full Patch

-    {{ diff }}
+    {{ diff.patch }}
 
{% endblock %} \ No newline at end of file -- 2.47.3