Skip to content

Latest commit

 

History

History
90 lines (64 loc) · 5.66 KB

File metadata and controls

90 lines (64 loc) · 5.66 KB

Case Study: Issue #1230 - Empty Repository Branch Creation Failure

Summary

When the solve command attempted to work on an issue in an empty repository (no commits), it failed silently during branch creation instead of providing actionable guidance or automatically resolving the problem.

Timeline of Events

  1. User runs solve command against https://github.com/DeepYV/Healora/issues/1
  2. Repository access check passes - User has write access to the private repository
  3. Clone succeeds - Empty repository is cloned (a valid operation)
  4. Default branch detection succeeds - Returns main (from HEAD symbolic ref)
  5. Branch creation fails - git checkout -b issue-1-xxx origin/main fails because origin/main is not a valid commit (no commits exist)
  6. Error message is misleading - Suggests branch name conflicts, uncommitted changes, or git config issues, none of which are the actual problem

Root Cause Analysis

Primary Root Cause

The repository DeepYV/Healora was completely empty (no commits, no files). When attempting to create a branch from origin/main, git fails with:

fatal: 'origin/main' is not a commit and a branch 'issue-1-4529e36b433e' cannot be created from it

Contributing Factors

  1. Existing empty repo handling was fork-only: The codebase already had tryInitializeEmptyRepository() in solve.repository.lib.mjs, but it was only triggered during the fork creation path (HTTP 403 "Empty repositories cannot be forked"). When the user has direct write access, the fork path is skipped entirely.

  2. No empty repo detection in the direct access path: The verifyDefaultBranchAndStatus() function checks for empty default branch but doesn't distinguish between "empty repository" and "other git issues."

  3. Error handler lacks empty repo context: handleBranchCreationError() suggests generic causes (branch exists, uncommitted changes) without detecting the specific "is not a commit" pattern.

Code Flow (Before Fix)

solve.mjs:
  ├── checkRepositoryWritePermission() → PASS (has write access)
  ├── setupRepositoryAndClone()
  │   ├── setupRepository() → No fork needed (direct access)
  │   └── cloneRepository() → SUCCESS (cloning empty repo is valid)
  ├── verifyDefaultBranchAndStatus()
  │   └── git branch --show-current → "" (empty - no commits!)
  │   └── THROWS: "Default branch detection failed"
  └── createOrCheckoutBranch() → NEVER REACHED
      └── git checkout -b ... origin/main → Would fail (no commits)

Solution

New Feature: --auto-init-repository

Added a new CLI option --auto-init-repository that:

  1. Detects empty repositories via detectEmptyRepository() - checks for absence of commits and remote branches
  2. Auto-initializes using the existing tryInitializeEmptyRepository() function (creates README.md via GitHub API)
  3. Re-fetches and continues - After initialization, fetches the new commit, checks out the default branch, and proceeds normally

Improved Error Messages and Issue Comments

  • When --auto-init-repository is NOT enabled: Clear message suggesting the flag + comment on the issue informing the user
  • When --auto-init-repository fails: Clear error message + comment on the issue with actionable guidance
  • When --auto-init-repository succeeds: No issue comment posted (no user action needed)
  • When branch creation fails due to empty repo: Specific "is not a commit" pattern detection with actionable fix suggestion
  • Reuses existing tryInitializeEmptyRepository() code (DRY principle)
  • Issue comment behavior mirrors the existing fork-path comment in solve.repository.lib.mjs

Files Changed

File Change
src/solve.config.lib.mjs Added --auto-init-repository option definition
src/option-suggestions.lib.mjs Added to KNOWN_OPTION_NAMES for typo detection
src/solve.repository.lib.mjs Exported tryInitializeEmptyRepository for reuse
src/solve.repo-setup.lib.mjs Added empty repo detection, auto-init, and issue comment in verifyDefaultBranchAndStatus()
src/solve.mjs Pass argv, owner, repo, issueUrl to verifyDefaultBranchAndStatus()
src/solve.branch-errors.lib.mjs Improved error message for empty repo branch creation failures

Artifacts

Lessons Learned

  1. Edge cases need end-to-end coverage: The empty repo case was handled in the fork path but not the direct access path. Both code paths need the same level of resilience.
  2. Error messages should diagnose, not just report: The original error message listed generic causes. Pattern-matching on error output ("is not a commit") enables specific, actionable suggestions.
  3. Reuse existing solutions: tryInitializeEmptyRepository() already existed and worked correctly - it just needed to be exported and called from the right place.