git-commit-message 0.7.0__tar.gz → 0.8.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/PKG-INFO +109 -45
  2. git_commit_message-0.8.1/README.md +212 -0
  3. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/pyproject.toml +2 -1
  4. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message/_cli.py +87 -20
  5. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message/_gemini.py +6 -1
  6. git_commit_message-0.8.1/src/git_commit_message/_git.py +269 -0
  7. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message/_gpt.py +7 -1
  8. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message/_llm.py +23 -5
  9. git_commit_message-0.8.1/src/git_commit_message/_ollama.py +122 -0
  10. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message.egg-info/PKG-INFO +109 -45
  11. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message.egg-info/SOURCES.txt +1 -0
  12. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message.egg-info/requires.txt +1 -0
  13. git_commit_message-0.7.0/README.md +0 -149
  14. git_commit_message-0.7.0/src/git_commit_message/_git.py +0 -114
  15. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/UNLICENSE +0 -0
  16. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/setup.cfg +0 -0
  17. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message/__init__.py +0 -0
  18. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message/__main__.py +0 -0
  19. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message.egg-info/dependency_links.txt +0 -0
  20. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message.egg-info/entry_points.txt +0 -0
  21. {git_commit_message-0.7.0 → git_commit_message-0.8.1}/src/git_commit_message.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-commit-message
3
- Version: 0.7.0
3
+ Version: 0.8.1
4
4
  Summary: Generate Git commit messages from staged changes using LLM
5
5
  Maintainer-email: Mina Her <minacle@live.com>
6
6
  License: This is free and unencumbered software released into the public domain.
@@ -45,16 +45,22 @@ Requires-Python: >=3.13
45
45
  Description-Content-Type: text/markdown
46
46
  Requires-Dist: babel>=2.17.0
47
47
  Requires-Dist: google-genai>=1.56.0
48
+ Requires-Dist: ollama>=0.4.0
48
49
  Requires-Dist: openai>=2.6.1
49
50
  Requires-Dist: tiktoken>=0.12.0
50
51
 
51
52
  # git-commit-message
52
53
 
53
- Staged changes -> GPT commit message generator.
54
+ Generate a commit message from your staged changes using OpenAI, Google Gemini, or Ollama.
54
55
 
55
56
  [![asciicast](https://asciinema.org/a/jk0phFqNnc5vaCiIZEYBwZOyN.svg)](https://asciinema.org/a/jk0phFqNnc5vaCiIZEYBwZOyN)
56
57
 
57
- ## Install (PyPI)
58
+ ## Requirements
59
+
60
+ - Python 3.13+
61
+ - A Git repo with staged changes (`git add ...`) (or use `--amend` even if nothing is staged)
62
+
63
+ ## Install
58
64
 
59
65
  Install the latest released version from PyPI:
60
66
 
@@ -78,19 +84,43 @@ Quick check:
78
84
  git-commit-message --help
79
85
  ```
80
86
 
81
- Set your API key (POSIX sh):
87
+ ## Setup
88
+
89
+ ### OpenAI
82
90
 
83
91
  ```sh
84
92
  export OPENAI_API_KEY="sk-..."
85
93
  ```
86
94
 
87
- Or for the Google provider:
95
+ ### Google Gemini
88
96
 
89
97
  ```sh
90
98
  export GOOGLE_API_KEY="..."
91
99
  ```
92
100
 
93
- Note (fish): In fish, set it as follows.
101
+ ### Ollama (local models)
102
+
103
+ 1. Install Ollama: https://ollama.ai
104
+ 2. Start the server:
105
+
106
+ ```sh
107
+ ollama serve
108
+ ```
109
+
110
+ 3. Pull a model:
111
+
112
+ ```sh
113
+ ollama pull mistral
114
+ ```
115
+
116
+ Optional: set defaults:
117
+
118
+ ```sh
119
+ export GIT_COMMIT_MESSAGE_PROVIDER=ollama
120
+ export OLLAMA_MODEL=mistral
121
+ ```
122
+
123
+ Note (fish):
94
124
 
95
125
  ```fish
96
126
  set -x OPENAI_API_KEY "sk-..."
@@ -104,96 +134,130 @@ python -m pip install -e .
104
134
 
105
135
  ## Usage
106
136
 
107
- - Print commit message only:
137
+ Generate and print a commit message:
108
138
 
109
139
  ```sh
110
140
  git add -A
111
141
  git-commit-message "optional extra context about the change"
112
142
  ```
113
143
 
114
- - Force single-line subject only:
144
+ Generate a single-line subject only:
115
145
 
116
146
  ```sh
117
147
  git-commit-message --one-line "optional context"
118
148
  ```
119
149
 
120
- - Select provider (default: openai):
150
+ Select provider:
121
151
 
122
152
  ```sh
123
- git-commit-message --provider openai "optional context"
153
+ # OpenAI (default)
154
+ git-commit-message --provider openai
155
+
156
+ # Google Gemini (via google-genai)
157
+ git-commit-message --provider google
158
+
159
+ # Ollama
160
+ git-commit-message --provider ollama
161
+ ```
162
+
163
+ Commit immediately (optionally open editor):
164
+
165
+ ```sh
166
+ git-commit-message --commit "refactor parser for speed"
167
+ git-commit-message --commit --edit "refactor parser for speed"
124
168
  ```
125
169
 
126
- - Select provider (Google Gemini via google-genai):
170
+ Amend the previous commit:
127
171
 
128
172
  ```sh
129
- git-commit-message --provider google "optional context"
173
+ # print only (useful for pasting into a GUI editor)
174
+ git-commit-message --amend "optional context"
175
+
176
+ # amend immediately
177
+ git-commit-message --commit --amend "optional context"
178
+
179
+ # amend immediately, but open editor for final tweaks
180
+ git-commit-message --commit --amend --edit "optional context"
130
181
  ```
131
182
 
132
- - Limit subject length (default 72):
183
+ Limit subject length:
133
184
 
134
185
  ```sh
135
- git-commit-message --one-line --max-length 50 "optional context"
186
+ git-commit-message --one-line --max-length 50
136
187
  ```
137
188
 
138
- - Chunk long diffs by token budget (0 = single chunk + summary, -1 = disable chunking):
189
+ Chunk/summarise long diffs by token budget:
139
190
 
140
191
  ```sh
141
192
  # force a single summary pass over the whole diff (default)
142
- git-commit-message --chunk-tokens 0 "optional context"
193
+ git-commit-message --chunk-tokens 0
143
194
 
144
195
  # chunk the diff into ~4000-token pieces before summarising
145
- git-commit-message --chunk-tokens 4000 "optional context"
196
+ git-commit-message --chunk-tokens 4000
146
197
 
147
198
  # disable summarisation and use the legacy one-shot prompt
148
- git-commit-message --chunk-tokens -1 "optional context"
199
+ git-commit-message --chunk-tokens -1
149
200
  ```
150
201
 
151
- - Commit immediately with editor:
202
+ Select output language/locale (IETF language tag):
152
203
 
153
204
  ```sh
154
- git-commit-message --commit --edit "refactor parser for speed"
205
+ git-commit-message --language en-US
206
+ git-commit-message --language ko-KR
207
+ git-commit-message --language ja-JP
155
208
  ```
156
209
 
157
- - Print debug info (prompt/response + token usage):
210
+ Print debug info:
158
211
 
159
212
  ```sh
160
- git-commit-message --debug "optional context"
213
+ git-commit-message --debug
161
214
  ```
162
215
 
163
- - Select output language/locale (default: en-GB):
216
+ Configure Ollama host (if running on a different machine):
164
217
 
165
218
  ```sh
166
- # American English
167
- git-commit-message --language en-US "optional context"
219
+ git-commit-message --provider ollama --host http://192.168.1.100:11434
220
+ ```
168
221
 
169
- # Korean
170
- git-commit-message --language ko-KR
222
+ ## Options
171
223
 
172
- # Japanese
173
- git-commit-message --language ja-JP
174
- ```
224
+ - `--provider {openai,google,ollama}`: provider to use (default: `openai`)
225
+ - `--model MODEL`: model override (provider-specific)
226
+ - `--language TAG`: output language/locale (default: `en-GB`)
227
+ - `--one-line`: output subject only
228
+ - `--max-length N`: max subject length (default: 72)
229
+ - `--chunk-tokens N`: token budget per diff chunk (`0` = single summary pass, `-1` disables summarisation)
230
+ - `--debug`: print request/response details
231
+ - `--commit`: run `git commit -m <message>`
232
+ - `--amend`: generate a message suitable for amending the previous commit (diff is from the amended commit's parent to the staged index; if nothing is staged, this effectively becomes the diff introduced by `HEAD`)
233
+ - `--edit`: with `--commit`, open editor for final message
234
+ - `--host URL`: host URL for providers like Ollama (default: `http://localhost:11434`)
235
+
236
+ ## Environment variables
175
237
 
176
- Notes:
238
+ Required:
177
239
 
178
- - The model is instructed to write using the selected language/locale.
179
- - In multi-line mode, the only allowed label ("Rationale:") is also translated into the target language.
240
+ - `OPENAI_API_KEY`: when provider is `openai`
241
+ - `GOOGLE_API_KEY`: when provider is `google`
180
242
 
181
- Environment:
243
+ Optional:
182
244
 
183
- - `OPENAI_API_KEY`: required when provider is `openai`
184
- - `GOOGLE_API_KEY`: required when provider is `google`
185
- - `GIT_COMMIT_MESSAGE_PROVIDER`: optional (default: `openai`). `--provider` overrides this value.
186
- - `GIT_COMMIT_MESSAGE_MODEL`: optional model override (defaults: `openai` -> `gpt-5-mini`, `google` -> `gemini-2.5-flash`)
187
- - `OPENAI_MODEL`: optional OpenAI-only model override
188
- - `GIT_COMMIT_MESSAGE_LANGUAGE`: optional (default: `en-GB`)
189
- - `GIT_COMMIT_MESSAGE_CHUNK_TOKENS`: optional token budget per diff chunk (default: 0 = single chunk + summary; -1 disables summarisation)
245
+ - `GIT_COMMIT_MESSAGE_PROVIDER`: default provider (`openai` by default). `--provider` overrides this.
246
+ - `GIT_COMMIT_MESSAGE_MODEL`: model override for any provider. `--model` overrides this.
247
+ - `OPENAI_MODEL`: OpenAI-only model override (used if `--model`/`GIT_COMMIT_MESSAGE_MODEL` are not set)
248
+ - `OLLAMA_MODEL`: Ollama-only model override (used if `--model`/`GIT_COMMIT_MESSAGE_MODEL` are not set)
249
+ - `OLLAMA_HOST`: Ollama server URL (default: `http://localhost:11434`)
250
+ - `GIT_COMMIT_MESSAGE_LANGUAGE`: default language/locale (default: `en-GB`)
251
+ - `GIT_COMMIT_MESSAGE_CHUNK_TOKENS`: default chunk token budget (default: `0`)
190
252
 
191
- Notes:
253
+ Default models (if not overridden):
192
254
 
193
- - If token counting fails for your provider while chunking, try `--chunk-tokens 0` (default) or `--chunk-tokens -1`.
255
+ - OpenAI: `gpt-5-mini`
256
+ - Google: `gemini-2.5-flash`
257
+ - Ollama: `gpt-oss:20b`
194
258
 
195
- ## AIgenerated code notice
259
+ ## AI-generated code notice
196
260
 
197
261
  Parts of this project were created with assistance from AI tools (e.g. large language models).
198
- All AIassisted contributions were reviewed and adapted by maintainers before inclusion.
262
+ All AI-assisted contributions were reviewed and adapted by maintainers before inclusion.
199
263
  If you need provenance for specific changes, please refer to the Git history and commit messages.
@@ -0,0 +1,212 @@
1
+ # git-commit-message
2
+
3
+ Generate a commit message from your staged changes using OpenAI, Google Gemini, or Ollama.
4
+
5
+ [![asciicast](https://asciinema.org/a/jk0phFqNnc5vaCiIZEYBwZOyN.svg)](https://asciinema.org/a/jk0phFqNnc5vaCiIZEYBwZOyN)
6
+
7
+ ## Requirements
8
+
9
+ - Python 3.13+
10
+ - A Git repo with staged changes (`git add ...`) (or use `--amend` even if nothing is staged)
11
+
12
+ ## Install
13
+
14
+ Install the latest released version from PyPI:
15
+
16
+ ```sh
17
+ # User environment (recommended)
18
+ python -m pip install --user git-commit-message
19
+
20
+ # Or system/virtualenv as appropriate
21
+ python -m pip install git-commit-message
22
+
23
+ # Or with pipx for isolated CLI installs
24
+ pipx install git-commit-message
25
+
26
+ # Upgrade to the newest version
27
+ python -m pip install --upgrade git-commit-message
28
+ ```
29
+
30
+ Quick check:
31
+
32
+ ```sh
33
+ git-commit-message --help
34
+ ```
35
+
36
+ ## Setup
37
+
38
+ ### OpenAI
39
+
40
+ ```sh
41
+ export OPENAI_API_KEY="sk-..."
42
+ ```
43
+
44
+ ### Google Gemini
45
+
46
+ ```sh
47
+ export GOOGLE_API_KEY="..."
48
+ ```
49
+
50
+ ### Ollama (local models)
51
+
52
+ 1. Install Ollama: https://ollama.ai
53
+ 2. Start the server:
54
+
55
+ ```sh
56
+ ollama serve
57
+ ```
58
+
59
+ 3. Pull a model:
60
+
61
+ ```sh
62
+ ollama pull mistral
63
+ ```
64
+
65
+ Optional: set defaults:
66
+
67
+ ```sh
68
+ export GIT_COMMIT_MESSAGE_PROVIDER=ollama
69
+ export OLLAMA_MODEL=mistral
70
+ ```
71
+
72
+ Note (fish):
73
+
74
+ ```fish
75
+ set -x OPENAI_API_KEY "sk-..."
76
+ ```
77
+
78
+ ## Install (editable)
79
+
80
+ ```sh
81
+ python -m pip install -e .
82
+ ```
83
+
84
+ ## Usage
85
+
86
+ Generate and print a commit message:
87
+
88
+ ```sh
89
+ git add -A
90
+ git-commit-message "optional extra context about the change"
91
+ ```
92
+
93
+ Generate a single-line subject only:
94
+
95
+ ```sh
96
+ git-commit-message --one-line "optional context"
97
+ ```
98
+
99
+ Select provider:
100
+
101
+ ```sh
102
+ # OpenAI (default)
103
+ git-commit-message --provider openai
104
+
105
+ # Google Gemini (via google-genai)
106
+ git-commit-message --provider google
107
+
108
+ # Ollama
109
+ git-commit-message --provider ollama
110
+ ```
111
+
112
+ Commit immediately (optionally open editor):
113
+
114
+ ```sh
115
+ git-commit-message --commit "refactor parser for speed"
116
+ git-commit-message --commit --edit "refactor parser for speed"
117
+ ```
118
+
119
+ Amend the previous commit:
120
+
121
+ ```sh
122
+ # print only (useful for pasting into a GUI editor)
123
+ git-commit-message --amend "optional context"
124
+
125
+ # amend immediately
126
+ git-commit-message --commit --amend "optional context"
127
+
128
+ # amend immediately, but open editor for final tweaks
129
+ git-commit-message --commit --amend --edit "optional context"
130
+ ```
131
+
132
+ Limit subject length:
133
+
134
+ ```sh
135
+ git-commit-message --one-line --max-length 50
136
+ ```
137
+
138
+ Chunk/summarise long diffs by token budget:
139
+
140
+ ```sh
141
+ # force a single summary pass over the whole diff (default)
142
+ git-commit-message --chunk-tokens 0
143
+
144
+ # chunk the diff into ~4000-token pieces before summarising
145
+ git-commit-message --chunk-tokens 4000
146
+
147
+ # disable summarisation and use the legacy one-shot prompt
148
+ git-commit-message --chunk-tokens -1
149
+ ```
150
+
151
+ Select output language/locale (IETF language tag):
152
+
153
+ ```sh
154
+ git-commit-message --language en-US
155
+ git-commit-message --language ko-KR
156
+ git-commit-message --language ja-JP
157
+ ```
158
+
159
+ Print debug info:
160
+
161
+ ```sh
162
+ git-commit-message --debug
163
+ ```
164
+
165
+ Configure Ollama host (if running on a different machine):
166
+
167
+ ```sh
168
+ git-commit-message --provider ollama --host http://192.168.1.100:11434
169
+ ```
170
+
171
+ ## Options
172
+
173
+ - `--provider {openai,google,ollama}`: provider to use (default: `openai`)
174
+ - `--model MODEL`: model override (provider-specific)
175
+ - `--language TAG`: output language/locale (default: `en-GB`)
176
+ - `--one-line`: output subject only
177
+ - `--max-length N`: max subject length (default: 72)
178
+ - `--chunk-tokens N`: token budget per diff chunk (`0` = single summary pass, `-1` disables summarisation)
179
+ - `--debug`: print request/response details
180
+ - `--commit`: run `git commit -m <message>`
181
+ - `--amend`: generate a message suitable for amending the previous commit (diff is from the amended commit's parent to the staged index; if nothing is staged, this effectively becomes the diff introduced by `HEAD`)
182
+ - `--edit`: with `--commit`, open editor for final message
183
+ - `--host URL`: host URL for providers like Ollama (default: `http://localhost:11434`)
184
+
185
+ ## Environment variables
186
+
187
+ Required:
188
+
189
+ - `OPENAI_API_KEY`: when provider is `openai`
190
+ - `GOOGLE_API_KEY`: when provider is `google`
191
+
192
+ Optional:
193
+
194
+ - `GIT_COMMIT_MESSAGE_PROVIDER`: default provider (`openai` by default). `--provider` overrides this.
195
+ - `GIT_COMMIT_MESSAGE_MODEL`: model override for any provider. `--model` overrides this.
196
+ - `OPENAI_MODEL`: OpenAI-only model override (used if `--model`/`GIT_COMMIT_MESSAGE_MODEL` are not set)
197
+ - `OLLAMA_MODEL`: Ollama-only model override (used if `--model`/`GIT_COMMIT_MESSAGE_MODEL` are not set)
198
+ - `OLLAMA_HOST`: Ollama server URL (default: `http://localhost:11434`)
199
+ - `GIT_COMMIT_MESSAGE_LANGUAGE`: default language/locale (default: `en-GB`)
200
+ - `GIT_COMMIT_MESSAGE_CHUNK_TOKENS`: default chunk token budget (default: `0`)
201
+
202
+ Default models (if not overridden):
203
+
204
+ - OpenAI: `gpt-5-mini`
205
+ - Google: `gemini-2.5-flash`
206
+ - Ollama: `gpt-oss:20b`
207
+
208
+ ## AI-generated code notice
209
+
210
+ Parts of this project were created with assistance from AI tools (e.g. large language models).
211
+ All AI-assisted contributions were reviewed and adapted by maintainers before inclusion.
212
+ If you need provenance for specific changes, please refer to the Git history and commit messages.
@@ -1,12 +1,13 @@
1
1
  [project]
2
2
  name = "git-commit-message"
3
- version = "0.7.0"
3
+ version = "0.8.1"
4
4
  description = "Generate Git commit messages from staged changes using LLM"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
7
7
  dependencies = [
8
8
  "babel>=2.17.0",
9
9
  "google-genai>=1.56.0",
10
+ "ollama>=0.4.0",
10
11
  "openai>=2.6.1",
11
12
  "tiktoken>=0.12.0",
12
13
  ]
@@ -17,7 +17,9 @@ from ._git import (
17
17
  commit_with_message,
18
18
  get_repo_root,
19
19
  get_staged_diff,
20
+ has_head_commit,
20
21
  has_staged_changes,
22
+ resolve_amend_base_ref,
21
23
  )
22
24
  from ._llm import (
23
25
  CommitMessageResult,
@@ -27,6 +29,40 @@ from ._llm import (
27
29
  )
28
30
 
29
31
 
32
+ class CliArgs(Namespace):
33
+ __slots__ = (
34
+ "description",
35
+ "commit",
36
+ "amend",
37
+ "edit",
38
+ "provider",
39
+ "model",
40
+ "language",
41
+ "debug",
42
+ "one_line",
43
+ "max_length",
44
+ "chunk_tokens",
45
+ "host",
46
+ )
47
+
48
+ def __init__(
49
+ self,
50
+ /,
51
+ ) -> None:
52
+ self.description: str | None = None
53
+ self.commit: bool = False
54
+ self.amend: bool = False
55
+ self.edit: bool = False
56
+ self.provider: str | None = None
57
+ self.model: str | None = None
58
+ self.language: str | None = None
59
+ self.debug: bool = False
60
+ self.one_line: bool = False
61
+ self.max_length: int | None = None
62
+ self.chunk_tokens: int | None = None
63
+ self.host: str | None = None
64
+
65
+
30
66
  def _env_chunk_tokens_default() -> int | None:
31
67
  """Return chunk token default from env if valid, else None."""
32
68
 
@@ -67,6 +103,16 @@ def _build_parser() -> ArgumentParser:
67
103
  help="Commit immediately with the generated message.",
68
104
  )
69
105
 
106
+ parser.add_argument(
107
+ "--amend",
108
+ action="store_true",
109
+ help=(
110
+ "Generate a message suitable for amending the previous commit. "
111
+ "When set, the diff is computed from the amended commit's parent to the staged index. "
112
+ "Use with '--commit' to run the amend, or omit '--commit' to print the message only."
113
+ ),
114
+ )
115
+
70
116
  parser.add_argument(
71
117
  "--edit",
72
118
  action="store_true",
@@ -87,7 +133,7 @@ def _build_parser() -> ArgumentParser:
87
133
  "--model",
88
134
  default=None,
89
135
  help=(
90
- "Model name to use. If unspecified, uses GIT_COMMIT_MESSAGE_MODEL or a provider-specific default (openai: gpt-5-mini; google: gemini-2.5-flash)."
136
+ "Model name to use. If unspecified, uses GIT_COMMIT_MESSAGE_MODEL or a provider-specific default (openai: gpt-5-mini; google: gemini-2.5-flash; ollama: gpt-oss:20b)."
91
137
  ),
92
138
  )
93
139
 
@@ -134,11 +180,21 @@ def _build_parser() -> ArgumentParser:
134
180
  ),
135
181
  )
136
182
 
183
+ parser.add_argument(
184
+ "--host",
185
+ dest="host",
186
+ default=None,
187
+ help=(
188
+ "Host URL for API providers like Ollama (default: http://localhost:11434). "
189
+ "You may also set OLLAMA_HOST for Ollama."
190
+ ),
191
+ )
192
+
137
193
  return parser
138
194
 
139
195
 
140
196
  def _run(
141
- args: Namespace,
197
+ args: CliArgs,
142
198
  /,
143
199
  ) -> int:
144
200
  """Main execution logic.
@@ -156,11 +212,19 @@ def _run(
156
212
 
157
213
  repo_root: Path = get_repo_root()
158
214
 
159
- if not has_staged_changes(repo_root):
160
- print("No staged changes. Run 'git add' and try again.", file=stderr)
161
- return 2
215
+ if args.amend:
216
+ if not has_head_commit(repo_root):
217
+ print("Cannot amend: the repository has no commits yet.", file=stderr)
218
+ return 2
219
+
220
+ base_ref = resolve_amend_base_ref(repo_root)
221
+ diff_text: str = get_staged_diff(repo_root, base_ref=base_ref)
222
+ else:
223
+ if not has_staged_changes(repo_root):
224
+ print("No staged changes. Run 'git add' and try again.", file=stderr)
225
+ return 2
162
226
 
163
- diff_text: str = get_staged_diff(repo_root)
227
+ diff_text = get_staged_diff(repo_root)
164
228
 
165
229
  hint: str | None = args.description if isinstance(args.description, str) else None
166
230
 
@@ -177,11 +241,12 @@ def _run(
177
241
  diff_text,
178
242
  hint,
179
243
  args.model,
180
- getattr(args, "one_line", False),
181
- getattr(args, "max_length", None),
182
- getattr(args, "language", None),
244
+ args.one_line,
245
+ args.max_length,
246
+ args.language,
183
247
  chunk_tokens,
184
- getattr(args, "provider", None),
248
+ args.provider,
249
+ args.host,
185
250
  )
186
251
  message = result.message
187
252
  else:
@@ -189,11 +254,12 @@ def _run(
189
254
  diff_text,
190
255
  hint,
191
256
  args.model,
192
- getattr(args, "one_line", False),
193
- getattr(args, "max_length", None),
194
- getattr(args, "language", None),
257
+ args.one_line,
258
+ args.max_length,
259
+ args.language,
195
260
  chunk_tokens,
196
- getattr(args, "provider", None),
261
+ args.provider,
262
+ args.host,
197
263
  )
198
264
  except UnsupportedProviderError as exc:
199
265
  print(str(exc), file=stderr)
@@ -203,7 +269,7 @@ def _run(
203
269
  return 3
204
270
 
205
271
  # Option: force single-line message
206
- if getattr(args, "one_line", False):
272
+ if args.one_line:
207
273
  # Use the first non-empty line only
208
274
  for line in (ln.strip() for ln in message.splitlines()):
209
275
  if line:
@@ -218,7 +284,7 @@ def _run(
218
284
  print(f"==== {result.provider} Usage ====")
219
285
  print(f"provider: {result.provider}")
220
286
  print(f"model: {result.model}")
221
- print(f"response_id: {getattr(result, 'response_id', '(n/a)')}")
287
+ print(f"response_id: {result.response_id or '(n/a)'}")
222
288
  if result.total_tokens is not None:
223
289
  print(
224
290
  f"tokens: prompt={result.prompt_tokens} completion={result.completion_tokens} total={result.total_tokens}"
@@ -240,7 +306,7 @@ def _run(
240
306
  print(f"==== {result.provider} Usage ====")
241
307
  print(f"provider: {result.provider}")
242
308
  print(f"model: {result.model}")
243
- print(f"response_id: {getattr(result, 'response_id', '(n/a)')}")
309
+ print(f"response_id: {result.response_id or '(n/a)'}")
244
310
  if result.total_tokens is not None:
245
311
  print(
246
312
  f"tokens: prompt={result.prompt_tokens} completion={result.completion_tokens} total={result.total_tokens}"
@@ -255,9 +321,9 @@ def _run(
255
321
  print(message)
256
322
 
257
323
  if args.edit:
258
- rc: int = commit_with_message(message, True, repo_root)
324
+ rc: int = commit_with_message(message, True, repo_root, amend=args.amend)
259
325
  else:
260
- rc = commit_with_message(message, False, repo_root)
326
+ rc = commit_with_message(message, False, repo_root, amend=args.amend)
261
327
 
262
328
  return rc
263
329
 
@@ -269,7 +335,8 @@ def main() -> None:
269
335
  """
270
336
 
271
337
  parser: Final[ArgumentParser] = _build_parser()
272
- args: Namespace = parser.parse_args()
338
+ args = CliArgs()
339
+ parser.parse_args(namespace=args)
273
340
 
274
341
  if args.edit and not args.commit:
275
342
  print("'--edit' must be used together with '--commit'.", file=stderr)