Skip to content

Instantly share code, notes, and snippets.

@GrantBirki
Last active September 8, 2022 19:18
Show Gist options
  • Save GrantBirki/046ca2a7675a313fc28afd11d4302209 to your computer and use it in GitHub Desktop.
Save GrantBirki/046ca2a7675a313fc28afd11d4302209 to your computer and use it in GitHub Desktop.
GitDiff Python
import git
from unidiff import PatchSet
import os
from io import StringIO
class GitDiff:
"""
Class to get the diff between two branches
"""
def __init__(
self,
repo_path=os.getcwd(),
base_branch=os.environ.get("BASE_BRANCH", "main"),
current_branch=os.environ.get("CURRENT_BRANCH", "HEAD"),
):
"""
Init function
:param repo_path: path to the git repo, default is current working directory
:param base_branch: base branch to compare with, default is main
:param current_branch: current branch to compare, default is HEAD
"""
self.base_branch = base_branch
self.current_branch = current_branch
self.repository = git.Repo(repo_path)
def json(self):
"""
Returns a git diff between two branches in json format
:return: Array of dicts
"""
uni_diff_text = self.repository.git.diff(
self.base_branch,
self.current_branch,
ignore_blank_lines=True,
ignore_space_at_eol=True,
)
patch_set = PatchSet(StringIO(uni_diff_text))
change_list = []
for patched_file in patch_set:
file_path = patched_file.path
added_lines = []
for hunk in patched_file:
for line in hunk:
if line.is_added and line.value.strip() != "":
added_lines.append(
{"line_number": line.target_line_no, "line": line.value}
)
deleted_lines = []
for hunk in patched_file:
for line in hunk:
if line.is_removed and line.value.strip() != "":
deleted_lines.append(
{"line_number": line.source_line_no, "line": line.value}
)
# get modifed lines by comparing added and deleted lines
added_to_remove = []
del_to_remove = []
modified_lines = []
for added_line in added_lines:
for deleted_line in deleted_lines:
if added_line["line_number"] == deleted_line["line_number"]:
modified_lines.append(
{
"line_number": added_line["line_number"],
"line": added_line["line"],
}
)
added_to_remove.append(added_line)
del_to_remove.append(deleted_line)
# remove modified lines from added and deleted lines
for line in added_to_remove:
added_lines.remove(line)
for line in del_to_remove:
deleted_lines.remove(line)
change_list.append(
{
"file_path": file_path,
"added": added_lines,
"deleted": deleted_lines,
"modified": modified_lines,
}
)
return change_list
@GrantBirki
Copy link
Author

Usage 🔨

Set your env vars:

export BASE_BRANCH=main
export CURRENT_BRANCH=my-cool-feature

Use the class:

import json
git_diff = GitDiff().json()

print(json.dumps(git_diff, indent=4))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment