Initial commit
This commit is contained in:
70
commands/commit-error-handling/.scripts/changes-detector.sh
Executable file
70
commands/commit-error-handling/.scripts/changes-detector.sh
Executable file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
# ================================================================
|
||||
# Script: changes-detector.sh
|
||||
# Purpose: Check for changes to commit (staged, unstaged, untracked)
|
||||
# Version: 1.0.0
|
||||
# Usage: ./changes-detector.sh
|
||||
# Returns: JSON with change counts
|
||||
# Exit Codes:
|
||||
# 0 = Success (with or without changes)
|
||||
# 1 = Not a git repository
|
||||
# 2 = Script error
|
||||
# ================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Function to output JSON
|
||||
output_json() {
|
||||
local has_changes=$1
|
||||
local staged=$2
|
||||
local unstaged=$3
|
||||
local untracked=$4
|
||||
local total=$5
|
||||
|
||||
cat <<EOF
|
||||
{
|
||||
"has_changes": $has_changes,
|
||||
"staged_count": $staged,
|
||||
"unstaged_count": $unstaged,
|
||||
"untracked_count": $untracked,
|
||||
"total_changes": $total,
|
||||
"checked_at": "$(date -Iseconds)"
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
# Main logic
|
||||
main() {
|
||||
# Verify we're in a git repository
|
||||
if ! git rev-parse --git-dir &>/dev/null; then
|
||||
output_json false 0 0 0 0
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Count staged changes (added to index)
|
||||
STAGED_COUNT=$(git diff --cached --numstat | wc -l)
|
||||
|
||||
# Count unstaged changes (modified but not staged)
|
||||
UNSTAGED_COUNT=$(git diff --numstat | wc -l)
|
||||
|
||||
# Count untracked files
|
||||
UNTRACKED_COUNT=$(git ls-files --others --exclude-standard | wc -l)
|
||||
|
||||
# Total changes
|
||||
TOTAL=$((STAGED_COUNT + UNSTAGED_COUNT + UNTRACKED_COUNT))
|
||||
|
||||
# Determine if there are any changes
|
||||
if [ "$TOTAL" -gt 0 ]; then
|
||||
HAS_CHANGES=true
|
||||
else
|
||||
HAS_CHANGES=false
|
||||
fi
|
||||
|
||||
# Output JSON
|
||||
output_json "$HAS_CHANGES" "$STAGED_COUNT" "$UNSTAGED_COUNT" "$UNTRACKED_COUNT" "$TOTAL"
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
173
commands/commit-error-handling/.scripts/conflict-detector.py
Executable file
173
commands/commit-error-handling/.scripts/conflict-detector.py
Executable file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
================================================================
|
||||
Script: conflict-detector.py
|
||||
Purpose: Detect and report merge conflicts
|
||||
Version: 1.0.0
|
||||
Usage: ./conflict-detector.py
|
||||
Returns: JSON with conflict information
|
||||
Exit Codes:
|
||||
0 = Success (conflicts may or may not exist)
|
||||
1 = Not a git repository
|
||||
2 = Script error
|
||||
================================================================
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run_git_command(command):
|
||||
"""Run a git command and return output."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
command,
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False
|
||||
)
|
||||
return result.returncode, result.stdout.strip(), result.stderr.strip()
|
||||
except Exception as e:
|
||||
return -1, "", str(e)
|
||||
|
||||
|
||||
def check_repo_validity():
|
||||
"""Check if current directory is a git repository."""
|
||||
returncode, _, _ = run_git_command("git rev-parse --git-dir")
|
||||
return returncode == 0
|
||||
|
||||
|
||||
def get_conflicted_files():
|
||||
"""Get list of files with merge conflicts."""
|
||||
# Files with conflicts show up with 'U' status (unmerged)
|
||||
returncode, stdout, _ = run_git_command("git ls-files -u")
|
||||
|
||||
if returncode != 0 or not stdout:
|
||||
return []
|
||||
|
||||
# Extract unique filenames (git ls-files -u shows each stage)
|
||||
conflicted_files = set()
|
||||
for line in stdout.split('\n'):
|
||||
if line.strip():
|
||||
# Format: <mode> <object> <stage> <filename>
|
||||
parts = line.split('\t')
|
||||
if len(parts) > 1:
|
||||
filename = parts[1]
|
||||
conflicted_files.add(filename)
|
||||
|
||||
return sorted(conflicted_files)
|
||||
|
||||
|
||||
def check_merge_in_progress():
|
||||
"""Check if a merge operation is in progress."""
|
||||
git_dir_code, git_dir, _ = run_git_command("git rev-parse --git-dir")
|
||||
|
||||
if git_dir_code != 0:
|
||||
return False, None
|
||||
|
||||
git_dir_path = Path(git_dir)
|
||||
|
||||
# Check for various merge/rebase states
|
||||
if (git_dir_path / "MERGE_HEAD").exists():
|
||||
return True, "merge"
|
||||
elif (git_dir_path / "REBASE_HEAD").exists():
|
||||
return True, "rebase"
|
||||
elif (git_dir_path / "CHERRY_PICK_HEAD").exists():
|
||||
return True, "cherry-pick"
|
||||
elif (git_dir_path / "REVERT_HEAD").exists():
|
||||
return True, "revert"
|
||||
|
||||
return False, None
|
||||
|
||||
|
||||
def get_conflict_details(files):
|
||||
"""Get detailed information about conflicts in each file."""
|
||||
details = []
|
||||
|
||||
for filepath in files:
|
||||
try:
|
||||
# Count conflict markers in file
|
||||
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
content = f.read()
|
||||
conflict_count = content.count('<<<<<<<')
|
||||
|
||||
details.append({
|
||||
"file": filepath,
|
||||
"conflict_regions": conflict_count
|
||||
})
|
||||
except Exception:
|
||||
# If can't read file, just include filename
|
||||
details.append({
|
||||
"file": filepath,
|
||||
"conflict_regions": 0
|
||||
})
|
||||
|
||||
return details
|
||||
|
||||
|
||||
def main():
|
||||
"""Main execution function."""
|
||||
# Check if in git repository
|
||||
if not check_repo_validity():
|
||||
result = {
|
||||
"has_conflicts": False,
|
||||
"conflict_count": 0,
|
||||
"conflicted_files": [],
|
||||
"merge_in_progress": False,
|
||||
"operation_type": None,
|
||||
"error": "not a git repository",
|
||||
"checked_at": datetime.now().isoformat()
|
||||
}
|
||||
print(json.dumps(result, indent=2))
|
||||
sys.exit(1)
|
||||
|
||||
# Get conflicted files
|
||||
conflicted_files = get_conflicted_files()
|
||||
conflict_count = len(conflicted_files)
|
||||
has_conflicts = conflict_count > 0
|
||||
|
||||
# Check merge status
|
||||
merge_in_progress, operation_type = check_merge_in_progress()
|
||||
|
||||
# Get detailed conflict information
|
||||
conflict_details = []
|
||||
if has_conflicts:
|
||||
conflict_details = get_conflict_details(conflicted_files)
|
||||
|
||||
# Build result
|
||||
result = {
|
||||
"has_conflicts": has_conflicts,
|
||||
"conflict_count": conflict_count,
|
||||
"conflicted_files": conflicted_files,
|
||||
"conflict_details": conflict_details,
|
||||
"merge_in_progress": merge_in_progress,
|
||||
"operation_type": operation_type,
|
||||
"error": "",
|
||||
"checked_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
# Output JSON
|
||||
print(json.dumps(result, indent=2))
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except Exception as e:
|
||||
# Handle unexpected errors
|
||||
result = {
|
||||
"has_conflicts": False,
|
||||
"conflict_count": 0,
|
||||
"conflicted_files": [],
|
||||
"merge_in_progress": False,
|
||||
"operation_type": None,
|
||||
"error": f"script error: {str(e)}",
|
||||
"checked_at": datetime.now().isoformat()
|
||||
}
|
||||
print(json.dumps(result, indent=2))
|
||||
sys.exit(2)
|
||||
54
commands/commit-error-handling/.scripts/repo-checker.sh
Executable file
54
commands/commit-error-handling/.scripts/repo-checker.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
# ================================================================
|
||||
# Script: repo-checker.sh
|
||||
# Purpose: Verify git repository validity
|
||||
# Version: 1.0.0
|
||||
# Usage: ./repo-checker.sh
|
||||
# Returns: JSON with repository status
|
||||
# Exit Codes:
|
||||
# 0 = Valid repository
|
||||
# 1 = Not a repository
|
||||
# 2 = Script error
|
||||
# ================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Function to output JSON
|
||||
output_json() {
|
||||
local is_repo=$1
|
||||
local git_dir=$2
|
||||
local error=$3
|
||||
|
||||
cat <<EOF
|
||||
{
|
||||
"is_repo": $is_repo,
|
||||
"git_dir": $git_dir,
|
||||
"error": "$error",
|
||||
"checked_at": "$(date -Iseconds)"
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
# Main logic
|
||||
main() {
|
||||
# Check if git is installed
|
||||
if ! command -v git &>/dev/null; then
|
||||
output_json false "null" "git not installed"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Try to get git directory
|
||||
if GIT_DIR=$(git rev-parse --git-dir 2>/dev/null); then
|
||||
# Valid repository
|
||||
ABSOLUTE_GIT_DIR=$(cd "$GIT_DIR" && pwd)
|
||||
output_json true "\"$ABSOLUTE_GIT_DIR\"" ""
|
||||
exit 0
|
||||
else
|
||||
# Not a repository
|
||||
output_json false "null" "not a git repository"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
183
commands/commit-error-handling/.scripts/state-analyzer.sh
Executable file
183
commands/commit-error-handling/.scripts/state-analyzer.sh
Executable file
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env bash
|
||||
# ================================================================
|
||||
# Script: state-analyzer.sh
|
||||
# Purpose: Analyze repository state (HEAD, branch, remote status)
|
||||
# Version: 1.0.0
|
||||
# Usage: ./state-analyzer.sh
|
||||
# Returns: JSON with repository state information
|
||||
# Exit Codes:
|
||||
# 0 = Success
|
||||
# 1 = Not a git repository
|
||||
# 2 = Script error
|
||||
# ================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Function to check HEAD state
|
||||
check_head_state() {
|
||||
if git symbolic-ref HEAD &>/dev/null; then
|
||||
echo "attached"
|
||||
else
|
||||
echo "detached"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get current branch
|
||||
get_current_branch() {
|
||||
local branch
|
||||
branch=$(git branch --show-current 2>/dev/null)
|
||||
|
||||
if [ -z "$branch" ]; then
|
||||
echo "null"
|
||||
else
|
||||
echo "\"$branch\""
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get current commit SHA
|
||||
get_current_commit() {
|
||||
git rev-parse --short HEAD 2>/dev/null || echo "unknown"
|
||||
}
|
||||
|
||||
# Function to check remote status
|
||||
check_remote_status() {
|
||||
# Check if remote exists
|
||||
if ! git remote &>/dev/null || [ -z "$(git remote)" ]; then
|
||||
echo "no_remote"
|
||||
return
|
||||
fi
|
||||
|
||||
# Check if branch tracks remote
|
||||
if ! git rev-parse --abbrev-ref @{upstream} &>/dev/null; then
|
||||
echo "no_upstream"
|
||||
return
|
||||
fi
|
||||
|
||||
# Compare with upstream
|
||||
local local_commit remote_commit
|
||||
local_commit=$(git rev-parse HEAD 2>/dev/null)
|
||||
remote_commit=$(git rev-parse @{upstream} 2>/dev/null)
|
||||
|
||||
if [ "$local_commit" = "$remote_commit" ]; then
|
||||
echo "up_to_date"
|
||||
else
|
||||
# Check ahead/behind
|
||||
local ahead behind
|
||||
ahead=$(git rev-list --count @{upstream}..HEAD 2>/dev/null || echo "0")
|
||||
behind=$(git rev-list --count HEAD..@{upstream} 2>/dev/null || echo "0")
|
||||
|
||||
if [ "$ahead" -gt 0 ] && [ "$behind" -gt 0 ]; then
|
||||
echo "diverged"
|
||||
elif [ "$ahead" -gt 0 ]; then
|
||||
echo "ahead"
|
||||
elif [ "$behind" -gt 0 ]; then
|
||||
echo "behind"
|
||||
else
|
||||
echo "up_to_date"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get ahead/behind counts
|
||||
get_ahead_behind_counts() {
|
||||
if ! git rev-parse --abbrev-ref @{upstream} &>/dev/null; then
|
||||
echo "0" "0"
|
||||
return
|
||||
fi
|
||||
|
||||
local ahead behind
|
||||
ahead=$(git rev-list --count @{upstream}..HEAD 2>/dev/null || echo "0")
|
||||
behind=$(git rev-list --count HEAD..@{upstream} 2>/dev/null || echo "0")
|
||||
|
||||
echo "$ahead" "$behind"
|
||||
}
|
||||
|
||||
# Function to get remote name
|
||||
get_remote_name() {
|
||||
local remote
|
||||
remote=$(git remote 2>/dev/null | head -1)
|
||||
|
||||
if [ -z "$remote" ]; then
|
||||
echo "null"
|
||||
else
|
||||
echo "\"$remote\""
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get remote URL
|
||||
get_remote_url() {
|
||||
local remote_name
|
||||
remote_name=$(git remote 2>/dev/null | head -1)
|
||||
|
||||
if [ -z "$remote_name" ]; then
|
||||
echo "null"
|
||||
return
|
||||
fi
|
||||
|
||||
local url
|
||||
url=$(git remote get-url "$remote_name" 2>/dev/null)
|
||||
|
||||
if [ -z "$url" ]; then
|
||||
echo "null"
|
||||
else
|
||||
echo "\"$url\""
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if working tree is clean
|
||||
check_working_tree() {
|
||||
if git diff-index --quiet HEAD -- 2>/dev/null; then
|
||||
echo "clean"
|
||||
else
|
||||
echo "dirty"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
# Verify we're in a git repository
|
||||
if ! git rev-parse --git-dir &>/dev/null; then
|
||||
cat <<EOF
|
||||
{
|
||||
"error": "not a git repository",
|
||||
"is_repo": false
|
||||
}
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Collect all state information
|
||||
local head_state current_branch current_commit remote_status
|
||||
local ahead behind remote_name remote_url working_tree
|
||||
|
||||
head_state=$(check_head_state)
|
||||
current_branch=$(get_current_branch)
|
||||
current_commit=$(get_current_commit)
|
||||
remote_status=$(check_remote_status)
|
||||
read -r ahead behind < <(get_ahead_behind_counts)
|
||||
remote_name=$(get_remote_name)
|
||||
remote_url=$(get_remote_url)
|
||||
working_tree=$(check_working_tree)
|
||||
|
||||
# Output JSON
|
||||
cat <<EOF
|
||||
{
|
||||
"is_repo": true,
|
||||
"head_state": "$head_state",
|
||||
"current_branch": $current_branch,
|
||||
"current_commit": "$current_commit",
|
||||
"remote_status": "$remote_status",
|
||||
"ahead_by": $ahead,
|
||||
"behind_by": $behind,
|
||||
"remote_name": $remote_name,
|
||||
"remote_url": $remote_url,
|
||||
"working_tree": "$working_tree",
|
||||
"checked_at": "$(date -Iseconds)"
|
||||
}
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user