From a634dbd3a93aa7aa84505679e079ac9021c07672 Mon Sep 17 00:00:00 2001 From: saksham-jain177 <177sakshamjain@gmail.com> Date: Fri, 9 Jan 2026 02:06:33 +0530 Subject: [PATCH 1/3] feat: add commit title and description support --- src/autocommitt/core/commit_manager.py | 98 +++++++++++++++++--------- 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/src/autocommitt/core/commit_manager.py b/src/autocommitt/core/commit_manager.py index f113e57..cedeb2d 100644 --- a/src/autocommitt/core/commit_manager.py +++ b/src/autocommitt/core/commit_manager.py @@ -67,24 +67,20 @@ def generate_commit_message(diff_output: str, model: str = model_name) -> str: Returns: str: Generated commit message. """ - system_prompt = """You are a Git expert specializing in concise and meaningful commit messages based on output of git diff command. - Choose a type from below that best describes the git diff output : - fix: A bug fix, - docs: Documentation only changes, - style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc), - refactor: A code change that neither fixes a bug nor adds a feature, - perf: A code change that improves performance, - test: Adding missing tests or correcting existing tests, - build: Changes that affect the build system or external dependencies, - ci: Changes to our CI configuration files and scripts, - chore: Other changes that don't modify src or test files, - revert: Reverts a previous commit', - feat: A new feature, - Now, generate a concise git commit message written in present tense in the format type: description for the output of git diff command which is provided by the user. - The git diff output can have changes in multiple files so analyze that properly and generate a commit message all taking all the changes into consideration. - Exclude anything unnecessary such as translation. Your entire response will be passed directly into git commit. - Generate only one commit message of maximum length 60 characters, no explanations. - """ + system_prompt = """You are a Git commit message generator. + + Rules (mandatory): + - Output plain text only. + - Line 1: concise title in imperative mood, max 72 characters. + - Line 2: must be empty. + - Remaining lines: bullet points describing individual changes. + - Do not repeat the title in the body. + - Do not include explanations, markdown, or quotes. + + Context: + You are given the output of `git diff --staged`. + Analyze all changes and generate a structured commit message. + """ message = "" stream = ollama.chat( @@ -100,7 +96,51 @@ def generate_commit_message(diff_output: str, model: str = model_name) -> str: content = chunk["message"]["content"] message += content - return message.strip() + return CommitManager.normalize_commit_message(message.strip()) + + @staticmethod + def normalize_commit_message(message: str) -> str: + lines = [l.strip() for l in message.splitlines() if l.strip()] + + if not lines: + return "chore: update files" + + first = lines[0] + + # If the model did NOT give a real title, synthesize one + if ( + first.startswith("-") + or first.lower().startswith("here is") + or len(first.split()) > 12 + ): + title = "chore: update project files" + body_lines = lines + else: + title = first[:72] + body_lines = lines[1:] + + bullets = [] + for line in body_lines: + line = line.lstrip("-*• ").strip() + + # Drop LLM meta commentary + lowered = line.lower() + if ( + lowered.startswith("here is") + or lowered.startswith("note that") + or "i've followed" in lowered + or "rules specified" in lowered + or "concise title" in lowered + or "bullet points" in lowered + ): + continue + if line: + bullets.append(f"- {line}") + if bullets: + return f"{title}\n\n" + "\n".join(bullets) + + return title + @staticmethod def edit_commit_message(initial_message: str) -> str: @@ -138,26 +178,20 @@ def hook(): @staticmethod def perform_git_commit(message: str) -> bool: - """ - Perform Git commit with the provided message. + try: + import tempfile - Args: - message (str): Commit message. + with tempfile.NamedTemporaryFile(mode="w", delete=False, encoding="utf-8") as f: + f.write(message) + commit_file = f.name - Returns: - bool: True if commit was successful, False otherwise. - """ - try: - # Use shell=False for security and to avoid shell injection subprocess.run( - ["git", "commit", "-m", message], - check=True, # Raise an exception if the command fails + ["git", "commit", "-F", commit_file], + check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, creationflags=subprocess.CREATE_NO_WINDOW if os.name == "nt" else 0, - encoding="utf-8", - errors="replace", ) return True except subprocess.CalledProcessError as e: From 44e340cc109ff7c7fea9ecaa4215df6387bae95e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 20:40:56 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/autocommitt/core/commit_manager.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/autocommitt/core/commit_manager.py b/src/autocommitt/core/commit_manager.py index cedeb2d..a1dfe99 100644 --- a/src/autocommitt/core/commit_manager.py +++ b/src/autocommitt/core/commit_manager.py @@ -141,7 +141,6 @@ def normalize_commit_message(message: str) -> str: return title - @staticmethod def edit_commit_message(initial_message: str) -> str: """ @@ -181,7 +180,9 @@ def perform_git_commit(message: str) -> bool: try: import tempfile - with tempfile.NamedTemporaryFile(mode="w", delete=False, encoding="utf-8") as f: + with tempfile.NamedTemporaryFile( + mode="w", delete=False, encoding="utf-8" + ) as f: f.write(message) commit_file = f.name From 77754c497d1ec9d8c249f7f3a79a6868788b5188 Mon Sep 17 00:00:00 2001 From: saksham-jain177 <177sakshamjain@gmail.com> Date: Fri, 9 Jan 2026 02:13:43 +0530 Subject: [PATCH 3/3] fix ruff ambiguous variable name --- src/autocommitt/core/commit_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autocommitt/core/commit_manager.py b/src/autocommitt/core/commit_manager.py index a1dfe99..c536cd7 100644 --- a/src/autocommitt/core/commit_manager.py +++ b/src/autocommitt/core/commit_manager.py @@ -100,7 +100,7 @@ def generate_commit_message(diff_output: str, model: str = model_name) -> str: @staticmethod def normalize_commit_message(message: str) -> str: - lines = [l.strip() for l in message.splitlines() if l.strip()] + lines = [line.strip() for line in message.splitlines() if line.strip()] if not lines: return "chore: update files"