DEV Community

Saniyat Hossain
Saniyat Hossain

Posted on

Efficient Git Diff Analysis: A Comprehensive Guide

Comprehensive Git Diff Analysis: A Developer’s Guide

Analyzing changes between Git branches can be cumbersome without the right tools. This guide presents two robust solutions:

  1. A one-liner function for quick terminal use.
  2. A reusable shell script for automation.

Both solutions provide detailed insights into branch differences, including new, modified, deleted, and renamed files, with features like sorting and conflict detection.


Table of Contents

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

Introduction

Tracking changes between Git branches is critical during code reviews, debugging, or merging processes. This guide simplifies Git diff analysis using a one-liner or shell script, empowering developers to efficiently inspect file changes and conflicts.


Problem Statement

Without proper tools, Git branch comparisons can be:

  • Time-consuming.
  • Difficult to categorize into New, Modified, Deleted, and Renamed files.
  • Lacking clarity with merge conflict detection.

Features

  1. Categorized Output: Changes are grouped into New, Modified, Deleted, and Renamed files.
  2. Merge Conflict Detection: Identify files causing conflicts during merges.
  3. Sorting: Files can be listed in ascending or descending alphabetical order.
  4. Serial Numbering: Each file is numbered for easy reference.
  5. Error Handling: The solution ensures proper validation of input parameters and environment setup.

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 with parameters:
   git_compare [directory] [source_branch] [target_branch] [sort_order] [format] [show_conflicts]
Enter fullscreen mode Exit fullscreen mode

Example Usage

  • Basic comparison:
  git_compare
Enter fullscreen mode Exit fullscreen mode

Compares the current branch with master in the current directory.

  • Specific directory and branches:
  git_compare /path/to/repo develop feature
Enter fullscreen mode Exit fullscreen mode
  • Descending order with conflict detection:
  git_compare /repos/main main feature desc ": " true
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

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

Example Usage

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

Use Cases

  1. Code Reviews: Analyze changes in pull requests.
  2. Merge Prep: Detect and resolve conflicts before merging.
  3. Audit: Track file modifications for debugging or compliance.

Error Handling

  1. Invalid Directory: Displays "Error: Invalid directory".
  2. Non-Git Repository: Displays "Error: Not a git repository".
  3. Branch Not Found: Displays "Error: Branch '' not found".

Conclusion

The provided one-liner function and shell script simplify Git diff analysis with a feature-rich and customizeable approach. Tailor the tools to suit your workflow and boost

productivity.

Top comments (0)