Skip to content

Commit 9c8a2f2

Browse files
authored
Merge pull request #3 from Arakiss/codex/identificar-características-a-mejorar-o-agregar
Improve large commit handling
2 parents 05c5dfc + f61ab81 commit 9c8a2f2

File tree

5 files changed

+87
-5
lines changed

5 files changed

+87
-5
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ loom -y # Non-interactive mode
6060
- 🤖 **AI-Powered Analysis**: Intelligently analyzes your changes and generates structured, semantic commit messages
6161
- 🧵 **Smart Batching**: Weaves multiple changes into coherent, logical commits
6262
- 📊 **Complexity Analysis**: Identifies when commits are getting too large or complex
63+
- 🌿 **Branch Suggestions**: Offers to create a new branch for very large commits
6364
- 💰 **Cost Control**: Built-in token and cost estimation to keep API usage efficient
6465
- 📈 **Usage Metrics**: Track your usage, cost savings, and productivity gains with built-in metrics
6566
- 🔍 **Binary Support**: Special handling for binary files with size and type detection
@@ -252,6 +253,7 @@ CommitLoom automatically:
252253
2. Warns about potentially oversized commits
253254
3. Suggests splitting changes when appropriate
254255
4. Maintains context across split commits
256+
5. Optionally creates a new branch when commits are very large
255257

256258
## 🛠️ Development Status
257259

commitloom/cli/cli_handler.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
import os
66
import subprocess
77
import sys
8+
from datetime import datetime
89

910
from dotenv import load_dotenv
1011

11-
from ..core.analyzer import CommitAnalyzer
12+
from ..core.analyzer import CommitAnalysis, CommitAnalyzer
1213
from ..core.git import GitError, GitFile, GitOperations
1314
from ..services.ai_service import AIService
1415
from ..services.metrics import metrics_manager # noqa
@@ -53,6 +54,18 @@ def __init__(self, test_mode: bool = False, api_key: str | None = None):
5354
self.combine_commits = False
5455
self.console = console
5556

57+
def _maybe_create_branch(self, analysis: CommitAnalysis) -> None:
58+
"""Offer to create a new branch if the commit is complex."""
59+
if not analysis.is_complex:
60+
return
61+
branch_name = f"loom-large-{datetime.now().strftime('%Y%m%d_%H%M%S')}"
62+
if console.confirm_branch_creation(branch_name):
63+
try:
64+
self.git.create_and_checkout_branch(branch_name)
65+
console.print_info(f"Switched to new branch {branch_name}")
66+
except GitError as e:
67+
console.print_error(str(e))
68+
5669
def _process_single_commit(self, files: list[GitFile]) -> None:
5770
"""Process files as a single commit."""
5871
try:
@@ -69,6 +82,8 @@ def _process_single_commit(self, files: list[GitFile]) -> None:
6982

7083
# Print analysis
7184
console.print_warnings(analysis)
85+
self._maybe_create_branch(analysis)
86+
self._maybe_create_branch(analysis)
7287

7388
try:
7489
# Generate commit message
@@ -236,12 +251,18 @@ def _create_batches(self, changed_files: list[GitFile]) -> list[list[GitFile]]:
236251
console.print_warning("No valid files to process.")
237252
return []
238253

239-
# Create batches from valid files
254+
# Group files by top-level directory for smarter batching
255+
grouped: dict[str, list[GitFile]] = {}
256+
for f in valid_files:
257+
parts = f.path.split(os.sep)
258+
top_dir = parts[0] if len(parts) > 1 else "root"
259+
grouped.setdefault(top_dir, []).append(f)
260+
240261
batches = []
241262
batch_size = BATCH_THRESHOLD
242-
for i in range(0, len(valid_files), batch_size):
243-
batch = valid_files[i : i + batch_size]
244-
batches.append(batch)
263+
for group_files in grouped.values():
264+
for i in range(0, len(group_files), batch_size):
265+
batches.append(group_files[i : i + batch_size])
245266

246267
return batches
247268

commitloom/cli/console.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,17 @@ def confirm_batch_continue() -> bool:
222222
return False
223223

224224

225+
def confirm_branch_creation(branch_name: str) -> bool:
226+
"""Ask user to confirm creation of a new branch for large commits."""
227+
if _auto_confirm:
228+
return True
229+
try:
230+
prompt = f"Create a new branch '{branch_name}' for these large changes?"
231+
return Confirm.ask(f"\n{prompt}")
232+
except Exception:
233+
return False
234+
235+
225236
def select_commit_strategy() -> str:
226237
"""Ask user how they want to handle multiple commits."""
227238
if _auto_confirm:

commitloom/core/git.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,18 @@ def unstage_file(file: str) -> None:
284284
except subprocess.CalledProcessError as e:
285285
error_msg = e.stderr if e.stderr else str(e)
286286
raise GitError(f"Failed to unstage file: {error_msg}")
287+
288+
@staticmethod
289+
def create_and_checkout_branch(branch: str) -> None:
290+
"""Create and switch to a new branch."""
291+
try:
292+
result = subprocess.run(
293+
["git", "checkout", "-b", branch],
294+
capture_output=True,
295+
text=True,
296+
check=True,
297+
)
298+
GitOperations._handle_git_output(result, f"while creating branch {branch}")
299+
except subprocess.CalledProcessError as e:
300+
error_msg = e.stderr if e.stderr else str(e)
301+
raise GitError(f"Failed to create branch '{branch}': {error_msg}")

tests/test_cli_handler.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pytest
77

88
from commitloom.cli.cli_handler import CommitLoom
9+
from commitloom.core.analyzer import CommitAnalysis
910
from commitloom.core.git import GitError, GitFile
1011
from commitloom.services.ai_service import TokenUsage
1112

@@ -250,3 +251,35 @@ def test_handle_batch_git_error(cli):
250251
result = cli._handle_batch(mock_files, 1, 1)
251252

252253
assert result is None
254+
255+
256+
def test_maybe_create_branch(cli):
257+
"""Ensure branch is created when commit is complex."""
258+
analysis = CommitAnalysis(
259+
estimated_tokens=2000,
260+
estimated_cost=0.2,
261+
num_files=10,
262+
warnings=[],
263+
is_complex=True,
264+
)
265+
cli.git.create_and_checkout_branch = MagicMock()
266+
with patch("commitloom.cli.cli_handler.console") as mock_console:
267+
mock_console.confirm_branch_creation.return_value = True
268+
cli._maybe_create_branch(analysis)
269+
cli.git.create_and_checkout_branch.assert_called_once()
270+
271+
272+
def test_maybe_create_branch_not_complex(cli):
273+
"""Ensure no branch is created when commit is simple."""
274+
analysis = CommitAnalysis(
275+
estimated_tokens=10,
276+
estimated_cost=0.0,
277+
num_files=1,
278+
warnings=[],
279+
is_complex=False,
280+
)
281+
cli.git.create_and_checkout_branch = MagicMock()
282+
with patch("commitloom.cli.cli_handler.console") as mock_console:
283+
mock_console.confirm_branch_creation.return_value = True
284+
cli._maybe_create_branch(analysis)
285+
cli.git.create_and_checkout_branch.assert_not_called()

0 commit comments

Comments
 (0)