git-commit-message 0.7.0__py3-none-any.whl → 0.8.0__py3-none-any.whl
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.
- git_commit_message/_cli.py +59 -14
- git_commit_message/_gemini.py +6 -1
- git_commit_message/_gpt.py +7 -1
- git_commit_message/_llm.py +23 -5
- git_commit_message/_ollama.py +122 -0
- {git_commit_message-0.7.0.dist-info → git_commit_message-0.8.0.dist-info}/METADATA +95 -45
- git_commit_message-0.8.0.dist-info/RECORD +13 -0
- git_commit_message-0.7.0.dist-info/RECORD +0 -12
- {git_commit_message-0.7.0.dist-info → git_commit_message-0.8.0.dist-info}/WHEEL +0 -0
- {git_commit_message-0.7.0.dist-info → git_commit_message-0.8.0.dist-info}/entry_points.txt +0 -0
- {git_commit_message-0.7.0.dist-info → git_commit_message-0.8.0.dist-info}/top_level.txt +0 -0
git_commit_message/_cli.py
CHANGED
|
@@ -27,6 +27,38 @@ from ._llm import (
|
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
class CliArgs(Namespace):
|
|
31
|
+
__slots__ = (
|
|
32
|
+
"description",
|
|
33
|
+
"commit",
|
|
34
|
+
"edit",
|
|
35
|
+
"provider",
|
|
36
|
+
"model",
|
|
37
|
+
"language",
|
|
38
|
+
"debug",
|
|
39
|
+
"one_line",
|
|
40
|
+
"max_length",
|
|
41
|
+
"chunk_tokens",
|
|
42
|
+
"host",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
/,
|
|
48
|
+
) -> None:
|
|
49
|
+
self.description: str | None = None
|
|
50
|
+
self.commit: bool = False
|
|
51
|
+
self.edit: bool = False
|
|
52
|
+
self.provider: str | None = None
|
|
53
|
+
self.model: str | None = None
|
|
54
|
+
self.language: str | None = None
|
|
55
|
+
self.debug: bool = False
|
|
56
|
+
self.one_line: bool = False
|
|
57
|
+
self.max_length: int | None = None
|
|
58
|
+
self.chunk_tokens: int | None = None
|
|
59
|
+
self.host: str | None = None
|
|
60
|
+
|
|
61
|
+
|
|
30
62
|
def _env_chunk_tokens_default() -> int | None:
|
|
31
63
|
"""Return chunk token default from env if valid, else None."""
|
|
32
64
|
|
|
@@ -87,7 +119,7 @@ def _build_parser() -> ArgumentParser:
|
|
|
87
119
|
"--model",
|
|
88
120
|
default=None,
|
|
89
121
|
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)."
|
|
122
|
+
"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
123
|
),
|
|
92
124
|
)
|
|
93
125
|
|
|
@@ -134,11 +166,21 @@ def _build_parser() -> ArgumentParser:
|
|
|
134
166
|
),
|
|
135
167
|
)
|
|
136
168
|
|
|
169
|
+
parser.add_argument(
|
|
170
|
+
"--host",
|
|
171
|
+
dest="host",
|
|
172
|
+
default=None,
|
|
173
|
+
help=(
|
|
174
|
+
"Host URL for API providers like Ollama (default: http://localhost:11434). "
|
|
175
|
+
"You may also set OLLAMA_HOST for Ollama."
|
|
176
|
+
),
|
|
177
|
+
)
|
|
178
|
+
|
|
137
179
|
return parser
|
|
138
180
|
|
|
139
181
|
|
|
140
182
|
def _run(
|
|
141
|
-
args:
|
|
183
|
+
args: CliArgs,
|
|
142
184
|
/,
|
|
143
185
|
) -> int:
|
|
144
186
|
"""Main execution logic.
|
|
@@ -177,11 +219,12 @@ def _run(
|
|
|
177
219
|
diff_text,
|
|
178
220
|
hint,
|
|
179
221
|
args.model,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
222
|
+
args.one_line,
|
|
223
|
+
args.max_length,
|
|
224
|
+
args.language,
|
|
183
225
|
chunk_tokens,
|
|
184
|
-
|
|
226
|
+
args.provider,
|
|
227
|
+
args.host,
|
|
185
228
|
)
|
|
186
229
|
message = result.message
|
|
187
230
|
else:
|
|
@@ -189,11 +232,12 @@ def _run(
|
|
|
189
232
|
diff_text,
|
|
190
233
|
hint,
|
|
191
234
|
args.model,
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
235
|
+
args.one_line,
|
|
236
|
+
args.max_length,
|
|
237
|
+
args.language,
|
|
195
238
|
chunk_tokens,
|
|
196
|
-
|
|
239
|
+
args.provider,
|
|
240
|
+
args.host,
|
|
197
241
|
)
|
|
198
242
|
except UnsupportedProviderError as exc:
|
|
199
243
|
print(str(exc), file=stderr)
|
|
@@ -203,7 +247,7 @@ def _run(
|
|
|
203
247
|
return 3
|
|
204
248
|
|
|
205
249
|
# Option: force single-line message
|
|
206
|
-
if
|
|
250
|
+
if args.one_line:
|
|
207
251
|
# Use the first non-empty line only
|
|
208
252
|
for line in (ln.strip() for ln in message.splitlines()):
|
|
209
253
|
if line:
|
|
@@ -218,7 +262,7 @@ def _run(
|
|
|
218
262
|
print(f"==== {result.provider} Usage ====")
|
|
219
263
|
print(f"provider: {result.provider}")
|
|
220
264
|
print(f"model: {result.model}")
|
|
221
|
-
print(f"response_id: {
|
|
265
|
+
print(f"response_id: {result.response_id or '(n/a)'}")
|
|
222
266
|
if result.total_tokens is not None:
|
|
223
267
|
print(
|
|
224
268
|
f"tokens: prompt={result.prompt_tokens} completion={result.completion_tokens} total={result.total_tokens}"
|
|
@@ -240,7 +284,7 @@ def _run(
|
|
|
240
284
|
print(f"==== {result.provider} Usage ====")
|
|
241
285
|
print(f"provider: {result.provider}")
|
|
242
286
|
print(f"model: {result.model}")
|
|
243
|
-
print(f"response_id: {
|
|
287
|
+
print(f"response_id: {result.response_id or '(n/a)'}")
|
|
244
288
|
if result.total_tokens is not None:
|
|
245
289
|
print(
|
|
246
290
|
f"tokens: prompt={result.prompt_tokens} completion={result.completion_tokens} total={result.total_tokens}"
|
|
@@ -269,7 +313,8 @@ def main() -> None:
|
|
|
269
313
|
"""
|
|
270
314
|
|
|
271
315
|
parser: Final[ArgumentParser] = _build_parser()
|
|
272
|
-
args
|
|
316
|
+
args = CliArgs()
|
|
317
|
+
parser.parse_args(namespace=args)
|
|
273
318
|
|
|
274
319
|
if args.edit and not args.commit:
|
|
275
320
|
print("'--edit' must be used together with '--commit'.", file=stderr)
|
git_commit_message/_gemini.py
CHANGED
|
@@ -7,6 +7,7 @@ Provider-agnostic orchestration/prompt logic lives in `_llm.py`.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
from os import environ
|
|
10
|
+
from typing import ClassVar
|
|
10
11
|
|
|
11
12
|
from google import genai
|
|
12
13
|
from google.genai import types
|
|
@@ -15,7 +16,11 @@ from ._llm import LLMTextResult, LLMUsage
|
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class GoogleGenAIProvider:
|
|
18
|
-
|
|
19
|
+
__slots__ = (
|
|
20
|
+
"_client",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
name: ClassVar[str] = "google"
|
|
19
24
|
|
|
20
25
|
def __init__(
|
|
21
26
|
self,
|
git_commit_message/_gpt.py
CHANGED
|
@@ -9,6 +9,8 @@ from __future__ import annotations
|
|
|
9
9
|
from openai import OpenAI
|
|
10
10
|
from openai.types.responses import Response
|
|
11
11
|
from os import environ
|
|
12
|
+
from typing import ClassVar
|
|
13
|
+
|
|
12
14
|
from tiktoken import Encoding, encoding_for_model, get_encoding
|
|
13
15
|
from ._llm import LLMTextResult, LLMUsage
|
|
14
16
|
|
|
@@ -24,7 +26,11 @@ def _encoding_for_model(
|
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
class OpenAIResponsesProvider:
|
|
27
|
-
|
|
29
|
+
__slots__ = (
|
|
30
|
+
"_client",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
name: ClassVar[str] = "openai"
|
|
28
34
|
|
|
29
35
|
def __init__(
|
|
30
36
|
self,
|
git_commit_message/_llm.py
CHANGED
|
@@ -12,16 +12,19 @@ from __future__ import annotations
|
|
|
12
12
|
|
|
13
13
|
from babel import Locale
|
|
14
14
|
from os import environ
|
|
15
|
-
from typing import Final, Protocol
|
|
15
|
+
from typing import ClassVar, Final, Protocol
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
_DEFAULT_PROVIDER: Final[str] = "openai"
|
|
19
19
|
_DEFAULT_MODEL_OPENAI: Final[str] = "gpt-5-mini"
|
|
20
20
|
_DEFAULT_MODEL_GOOGLE: Final[str] = "gemini-2.5-flash"
|
|
21
|
+
_DEFAULT_MODEL_OLLAMA: Final[str] = "gpt-oss:20b"
|
|
21
22
|
_DEFAULT_LANGUAGE: Final[str] = "en-GB"
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class UnsupportedProviderError(RuntimeError):
|
|
26
|
+
__slots__ = ()
|
|
27
|
+
|
|
25
28
|
pass
|
|
26
29
|
|
|
27
30
|
|
|
@@ -66,7 +69,9 @@ class LLMTextResult:
|
|
|
66
69
|
|
|
67
70
|
|
|
68
71
|
class CommitMessageProvider(Protocol):
|
|
69
|
-
|
|
72
|
+
__slots__ = ()
|
|
73
|
+
|
|
74
|
+
name: ClassVar[str]
|
|
70
75
|
|
|
71
76
|
def generate_text(
|
|
72
77
|
self,
|
|
@@ -147,6 +152,9 @@ def _resolve_model(
|
|
|
147
152
|
if provider_name == "google":
|
|
148
153
|
default_model = _DEFAULT_MODEL_GOOGLE
|
|
149
154
|
provider_model = None
|
|
155
|
+
elif provider_name == "ollama":
|
|
156
|
+
default_model = _DEFAULT_MODEL_OLLAMA
|
|
157
|
+
provider_model = environ.get("OLLAMA_MODEL")
|
|
150
158
|
else:
|
|
151
159
|
default_model = _DEFAULT_MODEL_OPENAI
|
|
152
160
|
provider_model = environ.get("OPENAI_MODEL")
|
|
@@ -164,6 +172,8 @@ def _resolve_language(
|
|
|
164
172
|
def get_provider(
|
|
165
173
|
provider: str | None,
|
|
166
174
|
/,
|
|
175
|
+
*,
|
|
176
|
+
host: str | None = None,
|
|
167
177
|
) -> CommitMessageProvider:
|
|
168
178
|
name = _resolve_provider(provider)
|
|
169
179
|
|
|
@@ -179,8 +189,14 @@ def get_provider(
|
|
|
179
189
|
|
|
180
190
|
return GoogleGenAIProvider()
|
|
181
191
|
|
|
192
|
+
if name == "ollama":
|
|
193
|
+
# Local import to avoid import cycles: providers may import shared types from this module.
|
|
194
|
+
from ._ollama import OllamaProvider
|
|
195
|
+
|
|
196
|
+
return OllamaProvider(host=host)
|
|
197
|
+
|
|
182
198
|
raise UnsupportedProviderError(
|
|
183
|
-
f"Unsupported provider: {name}. Supported providers: openai, google"
|
|
199
|
+
f"Unsupported provider: {name}. Supported providers: openai, google, ollama"
|
|
184
200
|
)
|
|
185
201
|
|
|
186
202
|
|
|
@@ -459,13 +475,14 @@ def generate_commit_message(
|
|
|
459
475
|
language: str | None = None,
|
|
460
476
|
chunk_tokens: int | None = 0,
|
|
461
477
|
provider: str | None = None,
|
|
478
|
+
host: str | None = None,
|
|
462
479
|
/,
|
|
463
480
|
) -> str:
|
|
464
481
|
chosen_provider = _resolve_provider(provider)
|
|
465
482
|
chosen_model = _resolve_model(model, chosen_provider)
|
|
466
483
|
chosen_language = _resolve_language(language)
|
|
467
484
|
|
|
468
|
-
llm = get_provider(chosen_provider)
|
|
485
|
+
llm = get_provider(chosen_provider, host=host)
|
|
469
486
|
|
|
470
487
|
normalized_chunk_tokens = 0 if chunk_tokens is None else chunk_tokens
|
|
471
488
|
|
|
@@ -513,13 +530,14 @@ def generate_commit_message_with_info(
|
|
|
513
530
|
language: str | None = None,
|
|
514
531
|
chunk_tokens: int | None = 0,
|
|
515
532
|
provider: str | None = None,
|
|
533
|
+
host: str | None = None,
|
|
516
534
|
/,
|
|
517
535
|
) -> CommitMessageResult:
|
|
518
536
|
chosen_provider = _resolve_provider(provider)
|
|
519
537
|
chosen_model = _resolve_model(model, chosen_provider)
|
|
520
538
|
chosen_language = _resolve_language(language)
|
|
521
539
|
|
|
522
|
-
llm = get_provider(chosen_provider)
|
|
540
|
+
llm = get_provider(chosen_provider, host=host)
|
|
523
541
|
|
|
524
542
|
normalized_chunk_tokens = 0 if chunk_tokens is None else chunk_tokens
|
|
525
543
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Ollama provider implementation.
|
|
2
|
+
|
|
3
|
+
Mirrors the Gemini provider structure: a single provider class that exposes
|
|
4
|
+
`generate_text` and `count_tokens`. Provider-agnostic orchestration lives in
|
|
5
|
+
`_llm.py`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from os import environ
|
|
11
|
+
from typing import ClassVar, Final
|
|
12
|
+
|
|
13
|
+
from ollama import Client, ResponseError
|
|
14
|
+
from tiktoken import Encoding, get_encoding
|
|
15
|
+
|
|
16
|
+
from ._llm import LLMTextResult, LLMUsage
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_DEFAULT_OLLAMA_HOST: Final[str] = "http://localhost:11434"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _resolve_ollama_host(
|
|
23
|
+
host: str | None,
|
|
24
|
+
/,
|
|
25
|
+
) -> str:
|
|
26
|
+
"""Resolve the Ollama host URL from arg, env, or default."""
|
|
27
|
+
|
|
28
|
+
return host or environ.get("OLLAMA_HOST") or _DEFAULT_OLLAMA_HOST
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _get_encoding() -> Encoding:
|
|
32
|
+
"""Get a fallback encoding for token counting."""
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
return get_encoding("cl100k_base")
|
|
36
|
+
except Exception:
|
|
37
|
+
return get_encoding("gpt2")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class OllamaProvider:
|
|
41
|
+
"""Ollama provider implementation for the LLM protocol."""
|
|
42
|
+
|
|
43
|
+
__slots__ = (
|
|
44
|
+
"_host",
|
|
45
|
+
"_client",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
name: ClassVar[str] = "ollama"
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
/,
|
|
53
|
+
*,
|
|
54
|
+
host: str | None = None,
|
|
55
|
+
) -> None:
|
|
56
|
+
self._host = _resolve_ollama_host(host)
|
|
57
|
+
self._client = Client(host=self._host)
|
|
58
|
+
|
|
59
|
+
def generate_text(
|
|
60
|
+
self,
|
|
61
|
+
/,
|
|
62
|
+
*,
|
|
63
|
+
model: str,
|
|
64
|
+
instructions: str,
|
|
65
|
+
user_text: str,
|
|
66
|
+
) -> LLMTextResult:
|
|
67
|
+
"""Generate text using Ollama (non-streaming)."""
|
|
68
|
+
|
|
69
|
+
messages = [
|
|
70
|
+
{"role": "system", "content": instructions},
|
|
71
|
+
{"role": "user", "content": user_text},
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
response = self._client.chat(model=model, messages=messages)
|
|
76
|
+
except ResponseError as exc:
|
|
77
|
+
raise RuntimeError(
|
|
78
|
+
f"Ollama API error: {exc}"
|
|
79
|
+
) from exc
|
|
80
|
+
except Exception as exc:
|
|
81
|
+
raise RuntimeError(
|
|
82
|
+
f"Failed to connect to Ollama at {self._host}. Make sure Ollama is running: {exc}"
|
|
83
|
+
) from exc
|
|
84
|
+
|
|
85
|
+
response_text = response.message.content or ""
|
|
86
|
+
|
|
87
|
+
# Extract token usage if available
|
|
88
|
+
prompt_tokens: int | None = None
|
|
89
|
+
completion_tokens: int | None = None
|
|
90
|
+
total_tokens: int | None = None
|
|
91
|
+
|
|
92
|
+
if hasattr(response, "prompt_eval_count") and response.prompt_eval_count:
|
|
93
|
+
prompt_tokens = response.prompt_eval_count
|
|
94
|
+
if hasattr(response, "eval_count") and response.eval_count:
|
|
95
|
+
completion_tokens = response.eval_count
|
|
96
|
+
if prompt_tokens is not None and completion_tokens is not None:
|
|
97
|
+
total_tokens = prompt_tokens + completion_tokens
|
|
98
|
+
|
|
99
|
+
return LLMTextResult(
|
|
100
|
+
text=response_text.strip(),
|
|
101
|
+
response_id=None,
|
|
102
|
+
usage=LLMUsage(
|
|
103
|
+
prompt_tokens=prompt_tokens,
|
|
104
|
+
completion_tokens=completion_tokens,
|
|
105
|
+
total_tokens=total_tokens,
|
|
106
|
+
),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
def count_tokens(
|
|
110
|
+
self,
|
|
111
|
+
/,
|
|
112
|
+
*,
|
|
113
|
+
model: str,
|
|
114
|
+
text: str,
|
|
115
|
+
) -> int:
|
|
116
|
+
"""Approximate token count using tiktoken; fallback to whitespace split."""
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
encoding = _get_encoding()
|
|
120
|
+
return len(encoding.encode(text))
|
|
121
|
+
except Exception:
|
|
122
|
+
return len(text.split())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-commit-message
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
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
|
-
|
|
54
|
+
Generate a commit message from your staged changes using OpenAI, Google Gemini, or Ollama.
|
|
54
55
|
|
|
55
56
|
[](https://asciinema.org/a/jk0phFqNnc5vaCiIZEYBwZOyN)
|
|
56
57
|
|
|
57
|
-
##
|
|
58
|
+
## Requirements
|
|
59
|
+
|
|
60
|
+
- Python 3.13+
|
|
61
|
+
- A Git repo with staged changes (`git add ...`)
|
|
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
|
-
|
|
87
|
+
## Setup
|
|
88
|
+
|
|
89
|
+
### OpenAI
|
|
82
90
|
|
|
83
91
|
```sh
|
|
84
92
|
export OPENAI_API_KEY="sk-..."
|
|
85
93
|
```
|
|
86
94
|
|
|
87
|
-
|
|
95
|
+
### Google Gemini
|
|
88
96
|
|
|
89
97
|
```sh
|
|
90
98
|
export GOOGLE_API_KEY="..."
|
|
91
99
|
```
|
|
92
100
|
|
|
93
|
-
|
|
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,116 @@ python -m pip install -e .
|
|
|
104
134
|
|
|
105
135
|
## Usage
|
|
106
136
|
|
|
107
|
-
|
|
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
|
-
|
|
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
|
-
|
|
150
|
+
Select provider:
|
|
121
151
|
|
|
122
152
|
```sh
|
|
123
|
-
|
|
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
|
|
124
161
|
```
|
|
125
162
|
|
|
126
|
-
|
|
163
|
+
Commit immediately (optionally open editor):
|
|
127
164
|
|
|
128
165
|
```sh
|
|
129
|
-
git-commit-message --
|
|
166
|
+
git-commit-message --commit "refactor parser for speed"
|
|
167
|
+
git-commit-message --commit --edit "refactor parser for speed"
|
|
130
168
|
```
|
|
131
169
|
|
|
132
|
-
|
|
170
|
+
Limit subject length:
|
|
133
171
|
|
|
134
172
|
```sh
|
|
135
|
-
git-commit-message --one-line --max-length 50
|
|
173
|
+
git-commit-message --one-line --max-length 50
|
|
136
174
|
```
|
|
137
175
|
|
|
138
|
-
|
|
176
|
+
Chunk/summarise long diffs by token budget:
|
|
139
177
|
|
|
140
178
|
```sh
|
|
141
179
|
# force a single summary pass over the whole diff (default)
|
|
142
|
-
git-commit-message --chunk-tokens 0
|
|
180
|
+
git-commit-message --chunk-tokens 0
|
|
143
181
|
|
|
144
182
|
# chunk the diff into ~4000-token pieces before summarising
|
|
145
|
-
git-commit-message --chunk-tokens 4000
|
|
183
|
+
git-commit-message --chunk-tokens 4000
|
|
146
184
|
|
|
147
185
|
# disable summarisation and use the legacy one-shot prompt
|
|
148
|
-
git-commit-message --chunk-tokens -1
|
|
186
|
+
git-commit-message --chunk-tokens -1
|
|
149
187
|
```
|
|
150
188
|
|
|
151
|
-
|
|
189
|
+
Select output language/locale (IETF language tag):
|
|
152
190
|
|
|
153
191
|
```sh
|
|
154
|
-
git-commit-message --
|
|
192
|
+
git-commit-message --language en-US
|
|
193
|
+
git-commit-message --language ko-KR
|
|
194
|
+
git-commit-message --language ja-JP
|
|
155
195
|
```
|
|
156
196
|
|
|
157
|
-
|
|
197
|
+
Print debug info:
|
|
158
198
|
|
|
159
199
|
```sh
|
|
160
|
-
git-commit-message --debug
|
|
200
|
+
git-commit-message --debug
|
|
161
201
|
```
|
|
162
202
|
|
|
163
|
-
|
|
203
|
+
Configure Ollama host (if running on a different machine):
|
|
164
204
|
|
|
165
205
|
```sh
|
|
166
|
-
|
|
167
|
-
|
|
206
|
+
git-commit-message --provider ollama --host http://192.168.1.100:11434
|
|
207
|
+
```
|
|
168
208
|
|
|
169
|
-
|
|
170
|
-
git-commit-message --language ko-KR
|
|
209
|
+
## Options
|
|
171
210
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
211
|
+
- `--provider {openai,google,ollama}`: provider to use (default: `openai`)
|
|
212
|
+
- `--model MODEL`: model override (provider-specific)
|
|
213
|
+
- `--language TAG`: output language/locale (default: `en-GB`)
|
|
214
|
+
- `--one-line`: output subject only
|
|
215
|
+
- `--max-length N`: max subject length (default: 72)
|
|
216
|
+
- `--chunk-tokens N`: token budget per diff chunk (`0` = single summary pass, `-1` disables summarisation)
|
|
217
|
+
- `--debug`: print request/response details
|
|
218
|
+
- `--commit`: run `git commit -m <message>`
|
|
219
|
+
- `--edit`: with `--commit`, open editor for final message
|
|
220
|
+
- `--host URL`: host URL for providers like Ollama (default: `http://localhost:11434`)
|
|
221
|
+
|
|
222
|
+
## Environment variables
|
|
175
223
|
|
|
176
|
-
|
|
224
|
+
Required:
|
|
177
225
|
|
|
178
|
-
-
|
|
179
|
-
-
|
|
226
|
+
- `OPENAI_API_KEY`: when provider is `openai`
|
|
227
|
+
- `GOOGLE_API_KEY`: when provider is `google`
|
|
180
228
|
|
|
181
|
-
|
|
229
|
+
Optional:
|
|
182
230
|
|
|
183
|
-
- `
|
|
184
|
-
- `
|
|
185
|
-
- `
|
|
186
|
-
- `
|
|
187
|
-
- `
|
|
188
|
-
- `GIT_COMMIT_MESSAGE_LANGUAGE`:
|
|
189
|
-
- `GIT_COMMIT_MESSAGE_CHUNK_TOKENS`:
|
|
231
|
+
- `GIT_COMMIT_MESSAGE_PROVIDER`: default provider (`openai` by default). `--provider` overrides this.
|
|
232
|
+
- `GIT_COMMIT_MESSAGE_MODEL`: model override for any provider. `--model` overrides this.
|
|
233
|
+
- `OPENAI_MODEL`: OpenAI-only model override (used if `--model`/`GIT_COMMIT_MESSAGE_MODEL` are not set)
|
|
234
|
+
- `OLLAMA_MODEL`: Ollama-only model override (used if `--model`/`GIT_COMMIT_MESSAGE_MODEL` are not set)
|
|
235
|
+
- `OLLAMA_HOST`: Ollama server URL (default: `http://localhost:11434`)
|
|
236
|
+
- `GIT_COMMIT_MESSAGE_LANGUAGE`: default language/locale (default: `en-GB`)
|
|
237
|
+
- `GIT_COMMIT_MESSAGE_CHUNK_TOKENS`: default chunk token budget (default: `0`)
|
|
190
238
|
|
|
191
|
-
|
|
239
|
+
Default models (if not overridden):
|
|
192
240
|
|
|
193
|
-
-
|
|
241
|
+
- OpenAI: `gpt-5-mini`
|
|
242
|
+
- Google: `gemini-2.5-flash`
|
|
243
|
+
- Ollama: `gpt-oss:20b`
|
|
194
244
|
|
|
195
|
-
## AI
|
|
245
|
+
## AI-generated code notice
|
|
196
246
|
|
|
197
247
|
Parts of this project were created with assistance from AI tools (e.g. large language models).
|
|
198
|
-
All AI
|
|
248
|
+
All AI-assisted contributions were reviewed and adapted by maintainers before inclusion.
|
|
199
249
|
If you need provenance for specific changes, please refer to the Git history and commit messages.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
git_commit_message/__init__.py,sha256=bmUVTlV1SYJAnoSaIKcpDCPkJ5JW2BANfFGvKt_A22w,190
|
|
2
|
+
git_commit_message/__main__.py,sha256=n5lvkLiCZ1Q4dwhEwonWntcKTeTaJL9qOJzdiLf0Gfk,99
|
|
3
|
+
git_commit_message/_cli.py,sha256=HHaXYtmirBGjym6t1va2DvYoJSCZ7wqvT-BhU5TSH9o,8898
|
|
4
|
+
git_commit_message/_gemini.py,sha256=QBKWnFCgc62KqC8agPhfO6eIizNj3V0oPTj6rqbTKiY,3487
|
|
5
|
+
git_commit_message/_git.py,sha256=foQIG6e4QLv00JAhQgMUQ1cw7WExxU5SFezfgXJ10XA,2424
|
|
6
|
+
git_commit_message/_gpt.py,sha256=RSw3JyjuzfQ3sRHJu224CosfEHhjdUOGmRjU079G7io,2414
|
|
7
|
+
git_commit_message/_llm.py,sha256=_d0pKfs8BArx6RlJ-09DRMOj8WzYOmYQVJVTVxNli98,18279
|
|
8
|
+
git_commit_message/_ollama.py,sha256=-HI73J_n4kU7WGl3oBweRHw23JRWq7QH9tsEy-6dxlA,3308
|
|
9
|
+
git_commit_message-0.8.0.dist-info/METADATA,sha256=QAjCdnDgKUDdN1lU4qHM2NphmXa2ZJsjrFCqScI9TjQ,7025
|
|
10
|
+
git_commit_message-0.8.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
+
git_commit_message-0.8.0.dist-info/entry_points.txt,sha256=e2cRvoyZnmP7yVItmFKwZofYG86WWKhm8KbzZSo2mf0,63
|
|
12
|
+
git_commit_message-0.8.0.dist-info/top_level.txt,sha256=qeP45y7y44R4KrPEihvMdwdM8tXYDY_3nCvCD3I9EcI,19
|
|
13
|
+
git_commit_message-0.8.0.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
git_commit_message/__init__.py,sha256=bmUVTlV1SYJAnoSaIKcpDCPkJ5JW2BANfFGvKt_A22w,190
|
|
2
|
-
git_commit_message/__main__.py,sha256=n5lvkLiCZ1Q4dwhEwonWntcKTeTaJL9qOJzdiLf0Gfk,99
|
|
3
|
-
git_commit_message/_cli.py,sha256=62lKSJmeW5JoEc-6-Xq2uZn_KK_o6zvU4V3oEYRcdUY,7982
|
|
4
|
-
git_commit_message/_gemini.py,sha256=AwevAnGB8LPekwVGroS2lwDVPszfGw0Xa_aPP9DP2yY,3400
|
|
5
|
-
git_commit_message/_git.py,sha256=foQIG6e4QLv00JAhQgMUQ1cw7WExxU5SFezfgXJ10XA,2424
|
|
6
|
-
git_commit_message/_gpt.py,sha256=in6hf78pQKt3PWEgw8-kD9X33yicY-Bg7COVcabCur8,2326
|
|
7
|
-
git_commit_message/_llm.py,sha256=ZUl1mRxuz37UIWXPXLBJJgppVS-a3HrnxdYTVvkXYm8,17699
|
|
8
|
-
git_commit_message-0.7.0.dist-info/METADATA,sha256=Z1Xni2T94vfpow9g_fHwrscaZETMtjNtnVklSAFYL7Y,6106
|
|
9
|
-
git_commit_message-0.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
10
|
-
git_commit_message-0.7.0.dist-info/entry_points.txt,sha256=e2cRvoyZnmP7yVItmFKwZofYG86WWKhm8KbzZSo2mf0,63
|
|
11
|
-
git_commit_message-0.7.0.dist-info/top_level.txt,sha256=qeP45y7y44R4KrPEihvMdwdM8tXYDY_3nCvCD3I9EcI,19
|
|
12
|
-
git_commit_message-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|