Analyzing differences between branches is an essential task for software developers. This guide provides two practical solutions to streamline this process:
- A one-liner function for direct terminal execution.
- 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
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
- Categorization: Files are grouped into New, Modified, Deleted, and Renamed.
- Merge Conflict Detection: Optionally include conflicts in results.
- Sorting: Alphabetical sorting in ascending or descending order.
- Serial Numbering: Customize numbering format.
- Error Handling: Validates directory, Git repository, and branches.
- 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";
}
Usage
- Paste the function into your terminal.
- Call it using:
git_compare [directory] [source_branch] [target_branch] [sort_order] [format] [show_conflicts]
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
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"
Usage
- Save the script as
git_compare.sh
. - Run the script:
bash git_compare.sh [directory] [source_branch] [target_branch] [sort_order] [format] [show_conflicts]
Example Output
Same as the one-liner output.
Error Handling
Both approaches handle:
- Invalid directories.
- Non-Git repositories.
- Missing branches.
- 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)