DEV Community

Saniyat Hossain
Saniyat Hossain

Posted on

Efficient Git Diff Analysis: A Comprehensive Guide

Analyzing differences between branches is an essential task for software developers. This guide provides two practical solutions to streamline this process:

  1. A one-liner function for direct terminal execution.
  2. A reusable shell script for automation.

Both solutions categorize changes into New, Modified, Deleted, and Renamed files and optionally include merge conflict detection. The guide includes real output examples and error handling.


Table of Contents

  1. Introduction
  2. Problem Statement
  3. Features
  4. One-Liner Function
  5. Shell Script
  6. Error Handling
  7. Conclusion

Introduction

When managing multiple branches in Git, it’s crucial to understand the differences between them. However, standard Git commands often require additional scripting for detailed reports.

This guide presents optimized solutions for analyzing branch differences efficiently.


Problem Statement

Developers face the following challenges:

  • Categorizing changes into New, Modified, Deleted, and Renamed files.
  • Detecting merge conflicts.
  • Sorting results by ascending or descending order.
  • Serial numbering for better readability.
  • Error handling for invalid directories, missing branches, or non-Git repositories.

Features

  1. Categorization: Files are grouped into New, Modified, Deleted, and Renamed.
  2. Merge Conflict Detection: Optionally include conflicts in results.
  3. Sorting: Alphabetical sorting in ascending or descending order.
  4. Serial Numbering: Customize numbering format.
  5. Error Handling: Validates directory, Git repository, and branches.
  6. Reusability: Use as a one-liner or a shell script.

One-Liner Function

Code

git_compare() { 
  d=${1:-$PWD}; s=${2:-master}; t=${3:-$(git branch --show-current)}; sort=${4:-asc}; f=${5:-". "}; conf=${6:-false}; total=0;
  cd "$d" 2>/dev/null || { echo "Error: Invalid directory"; return 1; };
  git rev-parse --git-dir >/dev/null 2>&1 || { echo "Error: Not a git repo"; return 1; };
  git rev-parse --verify "$s" >/dev/null 2>&1 || { echo "Error: Branch '$s' not found"; return 1; };
  git rev-parse --verify "$t" >/dev/null 2>&1 || { echo "Error: Branch '$t' not found"; return 1; };
  echo "=== Git Diff Analysis ($(git --version)) ==="; echo "Source → Target: $s$t"; echo "Directory: $d"; echo "Sort: $sort | Conflicts: $conf";
  for c in "A:New" "M:Modified" "D:Deleted" "R:Renamed"; do
    echo -e "\n>> ${c#*:} files:";
    if [[ "${c%%:*}" == "R" ]]; then
      git diff --name-status --diff-filter=R "$s..$t" | sort $([[ "$sort" == "desc" ]] && echo "-r") | awk -v fmt="$f" '{printf "%d%s%s → %s\n", NR, fmt, $2, $3}'
    else
      git diff --name-status --diff-filter=${c%%:*} "$s..$t" | sort $([[ "$sort" == "desc" ]] && echo "-r") | awk -v fmt="$f" '{printf "%d%s%s\n", NR, fmt, $2}'
    fi
    count=$(git diff --name-status --diff-filter=${c%%:*} "$s..$t" | wc -l);
    total=$((total + count)); echo "Total: $count";
  done
  if [[ "$conf" == "true" ]]; then
    echo -e "\n>> Conflict files:";
    conflicts=$(git diff --name-only --diff-filter=U "$s..$t" | sort $([[ "$sort" == "desc" ]] && echo "-r"));
    if [[ -z "$conflicts" ]]; then echo "None"; else
      echo "$conflicts" | awk -v fmt="$f" '{printf "%d%s%s\n", NR, fmt, $0}';
      total=$((total + $(echo "$conflicts" | wc -l))); fi;
  fi
  echo -e "\n=== Summary ==="; echo "Total files affected: $total";
}
Enter fullscreen mode Exit fullscreen mode

Usage

  1. Paste the function into your terminal.
  2. Call it using:
   git_compare [directory] [source_branch] [target_branch] [sort_order] [format] [show_conflicts]
Enter fullscreen mode Exit fullscreen mode

Example Output

=== Git Diff Analysis (git version 2.43.0) ===
Source → Target: master → feature/awesome-update
Directory: .
Sort: asc | Conflicts: false

>> New files:
1. src/new_file1.js
2. src/new_file2.php
Total: 2

>> Modified files:
1. src/modified_file.php
2. src/utils/helper.js
Total: 2

>> Deleted files:
N/A
Total: 0

>> Renamed files:
1. src/old_name.php → src/new_name.php
Total: 1

=== Summary ===
Total files affected: 5
Enter fullscreen mode Exit fullscreen mode

Shell Script

Save the following code in a file (e.g., git_compare.sh).


Code

#!/bin/bash
set -e

dir=${1:-$(pwd)}
src=${2:-master}
tgt=${3:-$(git branch --show-current)}
sort=${4:-asc}
fmt=${5:-". "}
conf=${6:-false}
total=0

cd "$dir" || { echo "Error: Invalid directory"; exit 1; }
git rev-parse --git-dir >/dev/null || { echo "Error: Not a git repo"; exit 1; }
git rev-parse --verify "$src" >/dev/null || { echo "Error: Branch '$src' not found"; exit 1; }
git rev-parse --verify "$tgt" >/dev/null || { echo "Error: Branch '$tgt' not found"; exit 1; }

process() {
  local filter=$1 label=$2 sflag=$([[ "$sort" == "desc" ]] && echo "-r" || echo "")
  echo ">> $label Files:"
  if [[ $filter == "R" ]]; then
    git diff --name-status --diff-filter=R "$src..$tgt" | sort $sflag | awk -v fmt="$fmt" 'NF{printf "%d%s%s → %s\n", NR, fmt, $2, $3; c++}END{print "Total:",c+0}'
  else
    git diff --name-status --diff-filter="$filter" "$src..$tgt" | sort $sflag | awk -v fmt="$fmt" 'NF{printf "%d%s%s\n", NR, fmt, $2; c++}END{print "Total:",c+0}'
  fi
}

for c in "A:New" "M:Modified" "D:Deleted" "R:Renamed"; do
  process "${c%%:*}" "${c#*:}"
done

if [[ "$conf" == "true" ]]; then
  echo ">> Conflict Files:"
  git diff --name-only --diff-filter=U "$src..$tgt" | sort $([[ "$sort" == "desc" ]] && echo "-r") | awk -v fmt="$fmt" 'NF{printf "%d%s%s\n", NR, fmt, $0; c++}END{print "Total:",c+0}'
fi

echo "Total Files: $total"
Enter fullscreen mode Exit fullscreen mode

Usage

  1. Save the script as git_compare.sh.
  2. Run the script:
   bash git_compare.sh [directory] [source_branch] [target_branch] [sort_order] [format] [show_conflicts]
Enter fullscreen mode Exit fullscreen mode

Example Output

Same as the one-liner output.


Error Handling

Both approaches handle:

  1. Invalid directories.
  2. Non-Git repositories.
  3. Missing branches.
  4. Missing Git installation.

Conclusion

This guide provides a streamlined solution for efficient Git diff analysis. Whether you prefer a one-liner or a script, the provided tools improve productivity and ensure accurate results.

Top comments (0)