git-commit-message 0.4.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.
@@ -0,0 +1,10 @@
1
+ """Public package exporting the CLI and internal utilities.
2
+
3
+ This module exposes only public symbols in accordance with the codestyle guide.
4
+ """
5
+
6
+ from ._cli import main
7
+
8
+ __all__ = (
9
+ "main",
10
+ )
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ from ._cli import main
4
+
5
+
6
+ if __name__ == "__main__":
7
+ main()
@@ -0,0 +1,222 @@
1
+ from __future__ import annotations
2
+
3
+ """Command-line interface entry point.
4
+
5
+ Collect staged changes from the repository and call an OpenAI GPT model
6
+ to generate a commit message, or create a commit straight away.
7
+ """
8
+
9
+ from argparse import ArgumentParser, Namespace
10
+ from pathlib import Path
11
+ import sys
12
+ from typing import Final
13
+
14
+ from ._git import commit_with_message, get_repo_root, get_staged_diff, has_staged_changes
15
+ from ._gpt import (
16
+ generate_commit_message,
17
+ generate_commit_message_with_info,
18
+ CommitMessageResult,
19
+ )
20
+
21
+
22
+ def _build_parser() -> ArgumentParser:
23
+ """Create the CLI argument parser.
24
+
25
+ Returns
26
+ -------
27
+ ArgumentParser
28
+ A configured argument parser.
29
+ """
30
+
31
+ parser: ArgumentParser = ArgumentParser(
32
+ prog="git-commit-message",
33
+ description=(
34
+ "Generate a commit message with OpenAI GPT based on the staged changes."
35
+ ),
36
+ )
37
+
38
+ parser.add_argument(
39
+ "description",
40
+ nargs="?",
41
+ help="Optional auxiliary description of the changes.",
42
+ )
43
+
44
+ parser.add_argument(
45
+ "--commit",
46
+ action="store_true",
47
+ help="Commit immediately with the generated message.",
48
+ )
49
+
50
+ parser.add_argument(
51
+ "--edit",
52
+ action="store_true",
53
+ help="Open an editor to amend the message before committing. Use with '--commit'.",
54
+ )
55
+
56
+ parser.add_argument(
57
+ "--model",
58
+ default=None,
59
+ help=(
60
+ "OpenAI model name to use. If unspecified, uses the environment variables (GIT_COMMIT_MESSAGE_MODEL, OPENAI_MODEL) or 'gpt-5-mini'."
61
+ ),
62
+ )
63
+
64
+ parser.add_argument(
65
+ "--language",
66
+ dest="language",
67
+ default=None,
68
+ help=(
69
+ "Target language/locale IETF tag for the output (default: en-GB). "
70
+ "You may also set GIT_COMMIT_MESSAGE_LANGUAGE or OPENAI_LANGUAGE."
71
+ ),
72
+ )
73
+
74
+ parser.add_argument(
75
+ "--debug",
76
+ action="store_true",
77
+ help="Print the request/response and token usage.",
78
+ )
79
+
80
+ parser.add_argument(
81
+ "--one-line",
82
+ dest="one_line",
83
+ action="store_true",
84
+ help="Use only a single-line subject.",
85
+ )
86
+
87
+ parser.add_argument(
88
+ "--max-length",
89
+ dest="max_length",
90
+ type=int,
91
+ default=None,
92
+ help="Maximum subject (first line) length (default: 72).",
93
+ )
94
+
95
+ return parser
96
+
97
+
98
+ def _run(
99
+ *,
100
+ args: Namespace,
101
+ ) -> int:
102
+ """Main execution logic.
103
+
104
+ Parameters
105
+ ----------
106
+ args
107
+ Parsed CLI arguments.
108
+
109
+ Returns
110
+ -------
111
+ int
112
+ Process exit code. 0 indicates success; any other value indicates failure.
113
+ """
114
+
115
+ repo_root: Path = get_repo_root()
116
+
117
+ if not has_staged_changes(cwd=repo_root):
118
+ print("No staged changes. Run 'git add' and try again.", file=sys.stderr)
119
+ return 2
120
+
121
+ diff_text: str = get_staged_diff(cwd=repo_root)
122
+
123
+ hint: str | None = args.description if isinstance(args.description, str) else None
124
+
125
+ result: CommitMessageResult | None = None
126
+ try:
127
+ if args.debug:
128
+ result = generate_commit_message_with_info(
129
+ diff=diff_text,
130
+ hint=hint,
131
+ model=args.model,
132
+ single_line=getattr(args, "one_line", False),
133
+ subject_max=getattr(args, "max_length", None),
134
+ language=getattr(args, "language", None),
135
+ )
136
+ message = result.message
137
+ else:
138
+ message = generate_commit_message(
139
+ diff=diff_text,
140
+ hint=hint,
141
+ model=args.model,
142
+ single_line=getattr(args, "one_line", False),
143
+ subject_max=getattr(args, "max_length", None),
144
+ language=getattr(args, "language", None),
145
+ )
146
+ except Exception as exc: # noqa: BLE001 - to preserve standard output messaging
147
+ print(f"Failed to generate commit message: {exc}", file=sys.stderr)
148
+ return 3
149
+
150
+ # Option: force single-line message
151
+ if getattr(args, "one_line", False):
152
+ # Use the first non-empty line only
153
+ for line in (ln.strip() for ln in message.splitlines()):
154
+ if line:
155
+ message = line
156
+ break
157
+ else:
158
+ message = ""
159
+
160
+ if not args.commit:
161
+ if args.debug and result is not None:
162
+ # Print debug information
163
+ print("==== OpenAI Usage ====")
164
+ print(f"model: {result.model}")
165
+ print(f"response_id: {getattr(result, 'response_id', '(n/a)')}")
166
+ if result.total_tokens is not None:
167
+ print(
168
+ f"tokens: prompt={result.prompt_tokens} completion={result.completion_tokens} total={result.total_tokens}"
169
+ )
170
+ else:
171
+ print("tokens: (provider did not return usage)")
172
+ print("\n==== Prompt ====")
173
+ print(result.prompt)
174
+ print("\n==== Response ====")
175
+ print(result.response_text)
176
+ print("\n==== Commit Message ====")
177
+ print(message)
178
+ else:
179
+ print(message)
180
+ return 0
181
+
182
+ if args.debug and result is not None:
183
+ # Also print debug info before commit
184
+ print("==== OpenAI Usage ====")
185
+ print(f"model: {result.model}")
186
+ print(f"response_id: {getattr(result, 'response_id', '(n/a)')}")
187
+ if result.total_tokens is not None:
188
+ print(
189
+ f"tokens: prompt={result.prompt_tokens} completion={result.completion_tokens} total={result.total_tokens}"
190
+ )
191
+ else:
192
+ print("tokens: (provider did not return usage)")
193
+ print("\n==== Prompt ====")
194
+ print(result.prompt)
195
+ print("\n==== Response ====")
196
+ print(result.response_text)
197
+ print("\n==== Commit Message ====")
198
+ print(message)
199
+
200
+ if args.edit:
201
+ rc: int = commit_with_message(message=message, edit=True, cwd=repo_root)
202
+ else:
203
+ rc = commit_with_message(message=message, edit=False, cwd=repo_root)
204
+
205
+ return rc
206
+
207
+
208
+ def main() -> None:
209
+ """Script entry point.
210
+
211
+ Parse command-line arguments, delegate to the execution logic, and exit with its code.
212
+ """
213
+
214
+ parser: Final[ArgumentParser] = _build_parser()
215
+ args: Namespace = parser.parse_args()
216
+
217
+ if args.edit and not args.commit:
218
+ print("'--edit' must be used together with '--commit'.", file=sys.stderr)
219
+ sys.exit(2)
220
+
221
+ code: int = _run(args=args)
222
+ sys.exit(code)
@@ -0,0 +1,114 @@
1
+ from __future__ import annotations
2
+
3
+ """Git-related helper functions.
4
+
5
+ Provides repository root discovery, extraction of staged changes, and
6
+ creating commits from a message.
7
+ """
8
+
9
+ from pathlib import Path
10
+ import subprocess
11
+
12
+
13
+ def get_repo_root(
14
+ *,
15
+ cwd: Path | None = None,
16
+ ) -> Path:
17
+ """Find the repository root from the current working directory.
18
+
19
+ Parameters
20
+ ----------
21
+ cwd
22
+ Starting directory for the search. Defaults to the current working directory.
23
+
24
+ Returns
25
+ -------
26
+ Path
27
+ The repository root path.
28
+ """
29
+
30
+ start: Path = cwd or Path.cwd()
31
+ try:
32
+ out: bytes = subprocess.check_output(
33
+ [
34
+ "git",
35
+ "rev-parse",
36
+ "--show-toplevel",
37
+ ],
38
+ cwd=str(start),
39
+ )
40
+ except subprocess.CalledProcessError as exc: # noqa: TRY003
41
+ raise RuntimeError("Not a Git repository.") from exc
42
+
43
+ root = Path(out.decode().strip())
44
+ return root
45
+
46
+
47
+ def has_staged_changes(
48
+ *,
49
+ cwd: Path,
50
+ ) -> bool:
51
+ """Check whether there are staged changes."""
52
+
53
+ try:
54
+ subprocess.check_call(
55
+ ["git", "diff", "--cached", "--quiet", "--exit-code"],
56
+ cwd=str(cwd),
57
+ )
58
+ return False
59
+ except subprocess.CalledProcessError:
60
+ return True
61
+
62
+
63
+ def get_staged_diff(
64
+ *,
65
+ cwd: Path,
66
+ ) -> str:
67
+ """Return the staged changes as diff text."""
68
+
69
+ out: bytes = subprocess.check_output(
70
+ [
71
+ "git",
72
+ "diff",
73
+ "--cached",
74
+ "--patch",
75
+ "--minimal",
76
+ "--no-color",
77
+ ],
78
+ cwd=str(cwd),
79
+ )
80
+ return out.decode()
81
+
82
+
83
+ def commit_with_message(
84
+ *,
85
+ message: str,
86
+ edit: bool,
87
+ cwd: Path,
88
+ ) -> int:
89
+ """Create a commit with the given message.
90
+
91
+ Parameters
92
+ ----------
93
+ message
94
+ Commit message.
95
+ edit
96
+ If True, use the `--edit` flag to open an editor for amendments.
97
+ cwd
98
+ Git working directory.
99
+
100
+ Returns
101
+ -------
102
+ int
103
+ The subprocess exit code.
104
+ """
105
+
106
+ cmd: list[str] = ["git", "commit", "-m", message]
107
+ if edit:
108
+ cmd.append("--edit")
109
+
110
+ try:
111
+ completed = subprocess.run(cmd, cwd=str(cwd), check=False)
112
+ return int(completed.returncode)
113
+ except OSError as exc: # e.g., editor launch failure, etc.
114
+ raise RuntimeError(f"Failed to run 'git commit': {exc}") from exc
@@ -0,0 +1,266 @@
1
+ from __future__ import annotations
2
+
3
+ """Generate Git commit messages by calling an OpenAI GPT model."""
4
+
5
+ import os
6
+ from typing import Final, Any, cast
7
+ from openai import OpenAI
8
+
9
+
10
+ _DEFAULT_MODEL: Final[str] = "gpt-5-mini"
11
+ _DEFAULT_LANGUAGE: Final[str] = "en-GB"
12
+
13
+ def _build_system_prompt(
14
+ *,
15
+ single_line: bool,
16
+ subject_max: int | None,
17
+ language: str,
18
+ ) -> str:
19
+ max_len = subject_max or 72
20
+ if single_line:
21
+ return (
22
+ f"You are an expert Git commit message generator. "
23
+ f"Always use '{language}' spelling and style. "
24
+ f"Return a single-line imperative subject only (<= {max_len} chars). "
25
+ f"Do not include a body, bullet points, or any rationale. Do not include any line breaks. "
26
+ f"Consider the user-provided auxiliary context if present. "
27
+ f"Return only the commit message text (no code fences or prefixes like 'Commit message:')."
28
+ )
29
+ return (
30
+ f"You are an expert Git commit message generator. "
31
+ f"Always use '{language}' spelling and style. "
32
+ f"The subject line is mandatory: you MUST start the output with the subject as the very first non-empty line, "
33
+ f"in imperative mood, and keep it <= {max_len} chars. Insert exactly one blank line after the subject. "
34
+ f"Never start with bullets, headings, labels, or any other text. Then include a body in this format.\n\n"
35
+ f"Example format (do not include the --- lines in the output):\n\n"
36
+ f"---\n\n"
37
+ f"<Subject line>\n\n"
38
+ f"- <detail 1>\n"
39
+ f"- <detail 2>\n"
40
+ f"- <detail N>\n\n"
41
+ f"<Rationale label translated into the target language>: <1-2 concise sentences explaining the intent and why>\n\n"
42
+ f"---\n\n"
43
+ f"Guidelines:\n"
44
+ f"- The first non-empty line MUST be the subject line; include exactly one blank line after it.\n"
45
+ f"- Never place bullets, headings, or labels before the subject line.\n"
46
+ f"- Use '-' bullets; keep each bullet short (<= 1 line).\n"
47
+ f"- Prefer imperative mood verbs (Add, Fix, Update, Remove, Refactor, Document, etc.).\n"
48
+ f"- Focus on what changed and why; avoid copying diff hunks verbatim.\n"
49
+ f"- The only allowed label is the equivalent of 'Rationale:' translated into the target language; do not add other headings or prefaces.\n"
50
+ f"- Do not include the '---' delimiter lines, code fences, or any surrounding labels like 'Commit message:'.\n"
51
+ f"- Do not copy or reuse any example text verbatim; produce original content based on the provided diff and context.\n"
52
+ f"- If few details are necessary, include at least one bullet summarising the key change.\n"
53
+ f"- If you cannot provide any body content, still output the subject line; the subject line must never be omitted.\n"
54
+ f"- Consider the user-provided auxiliary context if present.\n"
55
+ f"Return only the commit message text in the above format (no code fences or extra labels)."
56
+ )
57
+
58
+
59
+ def _system_message(
60
+ *,
61
+ single_line: bool,
62
+ subject_max: int | None,
63
+ language: str,
64
+ ) -> dict[str, str]:
65
+ """Create the system message dictionary."""
66
+ return {"role": "system", "content": _build_system_prompt(single_line=single_line, subject_max=subject_max, language=language)}
67
+
68
+
69
+ class CommitMessageResult:
70
+ """Hold the generated commit message and debugging information.
71
+
72
+ Notes
73
+ -----
74
+ Treat all fields as read-only by convention.
75
+ """
76
+
77
+ __slots__ = (
78
+ "message",
79
+ "model",
80
+ "prompt",
81
+ "response_text",
82
+ "response_id",
83
+ "prompt_tokens",
84
+ "completion_tokens",
85
+ "total_tokens",
86
+ )
87
+
88
+ def __init__(
89
+ self,
90
+ /,
91
+ *,
92
+ message: str,
93
+ model: str,
94
+ prompt: str,
95
+ response_text: str,
96
+ response_id: str | None,
97
+ prompt_tokens: int | None,
98
+ completion_tokens: int | None,
99
+ total_tokens: int | None,
100
+ ) -> None:
101
+ self.message = message
102
+ self.model = model
103
+ self.prompt = prompt
104
+ self.response_text = response_text
105
+ self.response_id = response_id
106
+ self.prompt_tokens = prompt_tokens
107
+ self.completion_tokens = completion_tokens
108
+ self.total_tokens = total_tokens
109
+
110
+
111
+ def _resolve_model(
112
+ *,
113
+ model: str | None,
114
+ ) -> str:
115
+ """Resolve the model name."""
116
+
117
+ return (
118
+ model
119
+ or os.environ.get("GIT_COMMIT_MESSAGE_MODEL")
120
+ or os.environ.get("OPENAI_MODEL")
121
+ or _DEFAULT_MODEL
122
+ )
123
+
124
+
125
+ def _resolve_language(
126
+ *,
127
+ language: str | None,
128
+ ) -> str:
129
+ """Resolve the target language/locale tag used for output style."""
130
+
131
+ return (
132
+ language
133
+ or os.environ.get("GIT_COMMIT_MESSAGE_LANGUAGE")
134
+ or os.environ.get("OPENAI_LANGUAGE")
135
+ or _DEFAULT_LANGUAGE
136
+ )
137
+
138
+
139
+ def _build_user_messages(
140
+ *,
141
+ diff: str,
142
+ hint: str | None,
143
+ ) -> tuple[str, list[dict[str, str]]]:
144
+ """Compose user messages, separating auxiliary context and diff.
145
+
146
+ Returns
147
+ -------
148
+ tuple[str, list[dict[str, str]]]
149
+ The first element is the combined string for debugging output; the
150
+ second is the list of user messages to send to the Chat Completions API.
151
+ """
152
+
153
+ hint_content: str | None = (
154
+ f"# Auxiliary context (user-provided)\n{hint}" if hint else None
155
+ )
156
+ diff_content: str = f"# Changes (diff)\n{diff}"
157
+
158
+ messages: list[dict[str, str]] = []
159
+ if hint_content:
160
+ messages.append({"role": "user", "content": hint_content})
161
+ messages.append({"role": "user", "content": diff_content})
162
+
163
+ combined_prompt: str = "\n\n".join(
164
+ [part for part in (hint_content, diff_content) if part is not None]
165
+ )
166
+ return combined_prompt, messages
167
+
168
+
169
+ def generate_commit_message(
170
+ *,
171
+ diff: str,
172
+ hint: str | None,
173
+ model: str | None,
174
+ single_line: bool = False,
175
+ subject_max: int | None = None,
176
+ language: str | None = None,
177
+ ) -> str:
178
+ """Generate a commit message using an OpenAI GPT model."""
179
+
180
+ chosen_model: str = _resolve_model(model=model)
181
+ chosen_language: str = _resolve_language(language=language)
182
+ api_key = os.environ.get("OPENAI_API_KEY")
183
+ if not api_key:
184
+ raise RuntimeError("The OPENAI_API_KEY environment variable is required.")
185
+
186
+ client = OpenAI(api_key=api_key)
187
+
188
+ _combined_prompt, user_messages = _build_user_messages(diff=diff, hint=hint)
189
+
190
+ # Use Chat Completions API to generate a single response (send hint and diff as separate user messages)
191
+ all_messages: list[dict[str, str]] = [
192
+ _system_message(single_line=single_line, subject_max=subject_max, language=chosen_language),
193
+ *user_messages,
194
+ ]
195
+
196
+ resp = client.chat.completions.create(
197
+ model=chosen_model,
198
+ messages=cast(Any, all_messages),
199
+ )
200
+
201
+ text: str = (resp.choices[0].message.content or "").strip()
202
+ if not text:
203
+ raise RuntimeError("An empty commit message was generated.")
204
+ return text
205
+
206
+
207
+ def generate_commit_message_with_info(
208
+ *,
209
+ diff: str,
210
+ hint: str | None,
211
+ model: str | None,
212
+ single_line: bool = False,
213
+ subject_max: int | None = None,
214
+ language: str | None = None,
215
+ ) -> CommitMessageResult:
216
+ """Return the OpenAI GPT call result together with debugging information.
217
+
218
+ Returns
219
+ -------
220
+ CommitMessageResult
221
+ The generated message, token usage, and prompt/response text.
222
+ """
223
+
224
+ chosen_model: str = _resolve_model(model=model)
225
+ chosen_language: str = _resolve_language(language=language)
226
+ api_key = os.environ.get("OPENAI_API_KEY")
227
+ if not api_key:
228
+ raise RuntimeError("The OPENAI_API_KEY environment variable is required.")
229
+
230
+ client = OpenAI(api_key=api_key)
231
+ combined_prompt, user_messages = _build_user_messages(diff=diff, hint=hint)
232
+
233
+ all_messages = [
234
+ _system_message(single_line=single_line, subject_max=subject_max, language=chosen_language),
235
+ *user_messages,
236
+ ]
237
+
238
+ resp = client.chat.completions.create(
239
+ model=chosen_model,
240
+ messages=cast(Any, all_messages),
241
+ )
242
+
243
+ response_text: str = (resp.choices[0].message.content or "").strip()
244
+ if not response_text:
245
+ raise RuntimeError("An empty commit message was generated.")
246
+
247
+ response_id: str | None = getattr(resp, "id", None)
248
+ usage = getattr(resp, "usage", None)
249
+ prompt_tokens: int | None = None
250
+ completion_tokens: int | None = None
251
+ total_tokens: int | None = None
252
+ if usage is not None:
253
+ prompt_tokens = getattr(usage, "prompt_tokens", None)
254
+ completion_tokens = getattr(usage, "completion_tokens", None)
255
+ total_tokens = getattr(usage, "total_tokens", None)
256
+
257
+ return CommitMessageResult(
258
+ message=response_text,
259
+ model=chosen_model,
260
+ prompt=combined_prompt,
261
+ response_text=response_text,
262
+ response_id=response_id,
263
+ prompt_tokens=prompt_tokens,
264
+ completion_tokens=completion_tokens,
265
+ total_tokens=total_tokens,
266
+ )
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: git-commit-message
3
+ Version: 0.4.0
4
+ Summary: Generate Git commit messages from staged changes using OpenAI GPT
5
+ Requires-Python: >=3.13
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: openai>=2.6.1
8
+
9
+ # git-commit-message
10
+
11
+ Staged changes -> GPT commit message generator.
12
+
13
+ ## Install (editable)
14
+
15
+ ```fish
16
+ python -m pip install -e .
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ - Print commit message only:
22
+
23
+ ```fish
24
+ git add -A
25
+ git-commit-message "optional extra context about the change"
26
+ ```
27
+
28
+ - Force single-line subject only:
29
+
30
+ ```fish
31
+ git-commit-message --one-line "optional context"
32
+ ```
33
+
34
+ - Limit subject length (default 72):
35
+
36
+ ```fish
37
+ git-commit-message --one-line --max-length 50 "optional context"
38
+ ```
39
+
40
+ - Commit immediately with editor:
41
+
42
+ ```fish
43
+ git-commit-message --commit --edit "refactor parser for speed"
44
+ ```
45
+
46
+ - Select output language/locale (default: en-GB):
47
+
48
+ ```fish
49
+ # American English
50
+ git-commit-message --language en-US "optional context"
51
+
52
+ # Korean
53
+ git-commit-message --language ko-KR
54
+
55
+ # Japanese
56
+ git-commit-message --language ja-JP
57
+ ```
58
+
59
+ Notes:
60
+
61
+ - The model is instructed to write using the selected language/locale.
62
+ - In multi-line mode, the only allowed label ("Rationale:") is also translated into the target language.
63
+
64
+ Environment:
65
+
66
+ - `OPENAI_API_KEY`: required
67
+ - `GIT_COMMIT_MESSAGE_MODEL` or `OPENAI_MODEL`: optional (default: `gpt-5-mini`)
68
+ - `GIT_COMMIT_MESSAGE_LANGUAGE` or `OPENAI_LANGUAGE`: optional (default: `en-GB`)
69
+
70
+ ## AI‑generated code notice
71
+
72
+ Parts of this project were created with assistance from AI tools (e.g. large language models).
73
+ All AI‑assisted contributions were reviewed and adapted by maintainers before inclusion.
74
+ If you need provenance for specific changes, please refer to the Git history and commit messages.
@@ -0,0 +1,10 @@
1
+ git_commit_message/__init__.py,sha256=cJvTj8-8_I1VYz3EO7Eq1LJZ6RS-WhNSAhjVVliVLtU,196
2
+ git_commit_message/__main__.py,sha256=n5lvkLiCZ1Q4dwhEwonWntcKTeTaJL9qOJzdiLf0Gfk,99
3
+ git_commit_message/_cli.py,sha256=N1ZF3hPTnIO-K6vh-VgT9JnqTOeWP-Xp2xZJ6Rz1Nig,6510
4
+ git_commit_message/_git.py,sha256=-FNXmFtlsbuArgCvEcCqpXSB7CjwdLdhoXgdZk1qtcE,2435
5
+ git_commit_message/_gpt.py,sha256=etsE_IcxR-atZKPzJqOl30wlOxtcRGTK6tTLm28L-U8,9040
6
+ git_commit_message-0.4.0.dist-info/METADATA,sha256=VHuXMRfyiGJNqsRSjgJTZ4onUh7CKXPQIqHJWiyMpSw,1753
7
+ git_commit_message-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ git_commit_message-0.4.0.dist-info/entry_points.txt,sha256=e2cRvoyZnmP7yVItmFKwZofYG86WWKhm8KbzZSo2mf0,63
9
+ git_commit_message-0.4.0.dist-info/top_level.txt,sha256=qeP45y7y44R4KrPEihvMdwdM8tXYDY_3nCvCD3I9EcI,19
10
+ git_commit_message-0.4.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ git-commit-message = git_commit_message:main
@@ -0,0 +1 @@
1
+ git_commit_message