-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgit-ai-commit
More file actions
executable file
·160 lines (138 loc) · 4.75 KB
/
git-ai-commit
File metadata and controls
executable file
·160 lines (138 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/bin/bash
set -euo pipefail
# Source shared library
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/git-ai-lib.sh"
# Check for llm installation
if ! command -v llm >/dev/null 2>&1; then
echo "Error: llm command not found. Install from https://llm.datasette.io/en/stable/setup.html" >&2
exit 1
fi
usage() {
cat << EOF
Usage: $(basename "$0") [options]
Generate and commit changes using AI messages.
Commits both staged and unstaged changes to tracked files (like git commit -a).
By default, also stages and commits untracked files (skip with --no-verify).
Options:
-m, --model MODEL Specify the LLM model to use (default: deepseek-coder or o1-mini)
Examples: gpt-4, claude-3-opus, mistral-7b, ...
-d, --dry-run Show changes without committing
-n, --no-verify Skip pre-commit hooks, skip adding untracked files, and pass --no-verify to git commit
--author=<author> Set commit author
-s, --signoff, --no-signoff
Add or remove signoff
--cleanup=<mode> Set commit cleanup mode
-e, --edit, --no-edit
Edit or skip editing commit message
-l, --list List available models
-h, --help Show this help
EOF
exit 1
}
# Default values
model=$(select_default_model)
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Capture original arguments before parsing
original_args=("$@")
dry_run=false
no_verify=false
extra_commit_args=()
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-m|--model)
model="$2"
shift 2
;;
-d|--dry-run)
dry_run=true
shift
;;
-n|--no-verify)
no_verify=true
extra_commit_args+=("--no-verify")
shift
;;
-l|--list)
echo "Available models:"
llm models
exit 0
;;
-h|--help)
usage
;;
--author=*|--cleanup=*|-e|--edit|--no-edit|-s|--signoff|--no-signoff)
extra_commit_args+=("$1")
shift
;;
*)
echo "Error: Unknown option: $1" >&2
usage
;;
esac
done
# Check if we're in a git repository
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "Error: Not in a git repository" >&2
exit 1
fi
# Run pre-commit hook unless --no-verify was specified
if [ "$no_verify" = false ]; then
git_dir=$(git rev-parse --git-dir)
pre_commit_hook="$git_dir/hooks/pre-commit"
if [ -x "$pre_commit_hook" ]; then
echo "Running pre-commit hook..."
"$pre_commit_hook"
fi
fi
# Check for any changes (staged, unstaged, or untracked)
if [ -z "$(git status --porcelain)" ]; then
echo "Error: No changes to commit" >&2
exit 1
fi
if [ "$dry_run" = true ]; then
echo "=== Changes to be committed ==="
git status --short
fi
# Load additional instructions from config files
repo_root=$(git rev-parse --show-toplevel)
additional_instructions=$(load_additional_instructions "$repo_root")
# Combine additional instructions with custom prompt (git-ai-commit doesn't have custom_prompt variable, so just use additional_instructions)
combined_prompt="$additional_instructions"
# Generate commit message with progress indicator
model_display=$(resolve_model_display "$model")
echo -e "\n== Commit Message (via ${model_display}) =="
echo -n "Generating commit message... " >&2
# Generate the diff and pipe through the message generator
if [ "$no_verify" = false ]; then
# Include untracked files
commit_msg=$({ git diff HEAD; git ls-files --others --exclude-standard | xargs -I{} echo "A {}"; } | generate_commit_message "$model" "$combined_prompt" "")
else
# Only tracked files
commit_msg=$(git diff HEAD | generate_commit_message "$model" "$combined_prompt" "")
fi
printf "\r\033[K" >&2 # Clear progress message
# Display the message
echo "$commit_msg"
if [ "$dry_run" = true ]; then
# Build suggestion command safely
suggestion="$(basename "$0")"
filtered_args=()
for arg in "${original_args[@]}"; do
[[ "$arg" != "-d" && "$arg" != "--dry-run" ]] && filtered_args+=("$arg")
done
if [ ${#filtered_args[@]} -gt 0 ]; then
suggestion+=" ${filtered_args[*]}"
fi
echo -e "\n== Next Steps ==\nTo use a message like this, run:\n $suggestion"
else
# Stage and commit changes
echo -e "\n== Committing changes... ==" >&2
if [ "$no_verify" = false ]; then
git add -A # Add all changes including untracked files
else
git add -u # Only add changes to tracked files
fi
git commit -m "$commit_msg" ${extra_commit_args[@]:-} >/dev/null && echo "Changes committed successfully!"
fi