Skip to content

fix: auto-commit worktree changes and validate commits before PR creation#2006

Open
octo-patch wants to merge 1 commit intoAndyMik90:developfrom
octo-patch:fix/issue-1928-pr-creation-empty-worktree
Open

fix: auto-commit worktree changes and validate commits before PR creation#2006
octo-patch wants to merge 1 commit intoAndyMik90:developfrom
octo-patch:fix/issue-1928-pr-creation-empty-worktree

Conversation

@octo-patch
Copy link
Copy Markdown

@octo-patch octo-patch commented Apr 11, 2026

Fixes #1928

Problem

When the AI agent writes files to the worktree but does not explicitly run
git add + git commit, clicking Create PR in the UI fails with a
cryptic GitHub GraphQL error:

pull request create failed: GraphQL: Head sha can't be blank,
Base sha can't be blank, No commits between main and <branch>

The branch is pushed successfully, but because it has no commits ahead of
the base branch, GitHub refuses to create the PR.

Solution

Two changes to pr-creator.ts:

  1. Auto-commit before pushing — Before calling git push, check for
    uncommitted changes in the worktree (git status --porcelain). If any
    exist, stage them with git add . and commit them with a descriptive
    message (auto-claude: implement <specId>). This handles the common case
    where the agent wrote files but skipped the commit step.

  2. Validate commit count after pushing — After the push succeeds, run
    git rev-list --count origin/<base>..HEAD to verify at least one commit
    exists ahead of the base. If none are found, return a clear, actionable
    error message instead of letting gh pr create fail with a confusing
    GraphQL error.

Testing

  • Simulated an uncommitted worktree (agent wrote files, no commit): PR
    creation now auto-commits and succeeds.
  • Simulated a completely empty worktree (no files changed): now returns a
    human-readable error explaining that the agent may not have committed
    any changes.
  • Existing flow (agent committed properly): no behavior change.

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced pull request creation with automatic staging and committing of pending changes before pushing updates.
    • Added validation to verify commits exist between branches before pull request creation.
  • Refactor

    • Optimized branch reference computation and reuse for improved reliability and consistency.
  • Chores

    • Updated process step numbering and comments to reflect workflow changes.

…tion (fixes AndyMik90#1928)

When the agent writes files to the worktree but does not call `git commit`,
the subsequent `gh pr create` fails with a cryptic GraphQL error:
'Head sha can\'t be blank, Base sha can\'t be blank, No commits between
main and <branch>'.

Fix:
- Auto-stage and commit any uncommitted changes in the worktree before
  pushing (handles agents that skip the commit step)
- After pushing, verify at least one commit exists ahead of the base branch
  and return a clear, actionable error message if none are found
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 11, 2026

📝 Walkthrough

Walkthrough

Enhanced PR creation process with automatic git change handling and pre-validation. Added autoCommitWorktreeChanges() helper to stage and commit uncommitted changes, refactored base-branch computation for reuse, and introduced commit count verification between branches before PR creation to prevent empty PR attempts.

Changes

Cohort / File(s) Summary
PR Creation Enhancement
apps/desktop/src/main/ai/runners/github/pr-creator.ts
Added autoCommitWorktreeChanges() helper to automatically stage and commit uncommitted changes with message auto-claude: implement ${specId}. Refactored base-branch handling to compute effectiveBase once and reuse throughout. Integrated pre-push auto-commit step and added commit count verification before PR creation, returning explicit error when no commits exist between base and head branches.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A worktree with changes, no longer lost in the git,
Auto-commits spring forth, each piece perfectly knit,
Validation ensures no empty PRs take flight,
The branch count checks twice—now creation done right! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: auto-committing worktree changes and validating commits before PR creation, directly addressing the core issues.
Linked Issues check ✅ Passed The pull request successfully implements all coding requirements from issue #1928: auto-committing uncommitted changes and validating commit count with clear error messaging.
Out of Scope Changes check ✅ Passed All changes are scoped to the pr-creator.ts file and directly address the linked issue without introducing unrelated modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment on lines +247 to +257
gitPath,
['commit', '-m', `auto-claude: implement ${specId}`],
{ cwd: worktreePath, encoding: 'utf-8', stdio: 'pipe' },
);

return undefined;
} catch (err: unknown) {
const stderr = err instanceof Error && 'stderr' in err
? String((err as NodeJS.ErrnoException & { stderr?: string }).stderr)
: String(err);
return stderr || 'Auto-commit failed';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The autoCommitWorktreeChanges function silently fails if git user identity is not configured. The error is caught but ignored, leading to a misleading downstream error message.
Severity: MEDIUM

Suggested Fix

At the call site for autoCommitWorktreeChanges (around line 357), log the error if the function returns one. This will make the root cause (e.g., missing git identity) visible during debugging, instead of being masked by a misleading downstream error message.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: apps/desktop/src/main/ai/runners/github/pr-creator.ts#L246-L257

Potential issue: The `autoCommitWorktreeChanges` function attempts to commit staged
files but can fail if a git user identity is not configured in the environment. This is
common in CI/CD or containerized environments. The function catches the error from the
failed `git commit` command and returns it. However, the caller at line 357 explicitly
ignores this return value and does not log the error, leading to a silent failure.
Consequently, a downstream validation check incorrectly reports a misleading error, "No
commits found...", which masks the true root cause of the problem.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/main/ai/runners/github/pr-creator.ts`:
- Around line 238-250: The PR currently stages all files using
execFileSync(gitPath, ['add', '.'], { cwd: worktreePath, ... }) which can
accidentally include unintended or sensitive files; change this to a targeted
staging approach by using either git add -u to stage only tracked changes or by
generating an explicit list of paths to add (e.g., parse git status or your
expected output list) and call execFileSync with those specific paths; update
the code that calls execFileSync for staging (the git add invocation referencing
gitPath and worktreePath) to implement one of these safer strategies and ensure
the commit message logic that uses specId remains unchanged.
- Around line 390-391: The call to gatherPRContext is using baseBranch (which
can contain an origin/ prefix) instead of the normalized effectiveBase, causing
double-prefixing; update the invocation to pass effectiveBase (i.e., call
gatherPRContext(worktreePath, gitPath, effectiveBase)) so the function receives
the already-normalized branch name and avoids trying "origin/origin/...". Ensure
you change the argument at the gatherPRContext call and keep worktreePath and
gitPath unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c2f05d49-fa57-4aa9-884a-f0e81a9b3630

📥 Commits

Reviewing files that changed from the base of the PR and between cba7a02 and 93996b1.

📒 Files selected for processing (1)
  • apps/desktop/src/main/ai/runners/github/pr-creator.ts

Comment on lines +238 to +250
// Stage all changes
execFileSync(
gitPath,
['add', '.'],
{ cwd: worktreePath, encoding: 'utf-8', stdio: 'pipe' },
);

// Commit with a descriptive message
execFileSync(
gitPath,
['commit', '-m', `auto-claude: implement ${specId}`],
{ cwd: worktreePath, encoding: 'utf-8', stdio: 'pipe' },
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider security implications of staging all files.

Using git add . stages all unignored files in the worktree, which could include files the agent created that weren't intended for commit (e.g., debug files, downloaded dependencies, or files with sensitive data that aren't in .gitignore).

Consider a more targeted approach using git add -u (staged only tracked files) or parsing the status output to selectively stage expected file patterns.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/ai/runners/github/pr-creator.ts` around lines 238 -
250, The PR currently stages all files using execFileSync(gitPath, ['add', '.'],
{ cwd: worktreePath, ... }) which can accidentally include unintended or
sensitive files; change this to a targeted staging approach by using either git
add -u to stage only tracked changes or by generating an explicit list of paths
to add (e.g., parse git status or your expected output list) and call
execFileSync with those specific paths; update the code that calls execFileSync
for staging (the git add invocation referencing gitPath and worktreePath) to
implement one of these safer strategies and ensure the commit message logic that
uses specId remains unchanged.

Comment on lines 390 to 391
// Step 2: Gather context for AI description
const { diffSummary, commitLog } = gatherPRContext(worktreePath, gitPath, baseBranch);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent use of baseBranch vs effectiveBase.

This call passes the original baseBranch (which may include origin/ prefix), while line 375 correctly uses effectiveBase. The gatherPRContext function prepends origin/ internally (lines 103, 122), so if baseBranch is "origin/main", it attempts "origin/origin/main" before falling back.

Pass effectiveBase for consistency:

🔧 Proposed fix
   // Step 2: Gather context for AI description
-  const { diffSummary, commitLog } = gatherPRContext(worktreePath, gitPath, baseBranch);
+  const { diffSummary, commitLog } = gatherPRContext(worktreePath, gitPath, effectiveBase);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/ai/runners/github/pr-creator.ts` around lines 390 -
391, The call to gatherPRContext is using baseBranch (which can contain an
origin/ prefix) instead of the normalized effectiveBase, causing
double-prefixing; update the invocation to pass effectiveBase (i.e., call
gatherPRContext(worktreePath, gitPath, effectiveBase)) so the function receives
the already-normalized branch name and avoids trying "origin/origin/...". Ensure
you change the argument at the gatherPRContext call and keep worktreePath and
gitPath unchanged.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a mechanism to automatically commit uncommitted changes and verifies that the branch is ahead of the base before creating a PR. Key feedback includes transitioning from synchronous to asynchronous process execution to prevent UI hangs, improving error reporting for the auto-commit step, and making the remote name configurable instead of hardcoding 'origin'.

Comment on lines +373 to +377
const commitCount = execFileSync(
gitPath,
['rev-list', '--count', `origin/${effectiveBase}..HEAD`],
{ cwd: worktreePath, encoding: 'utf-8', stdio: 'pipe' },
).trim();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The execFileSync call is synchronous and will block the main thread while counting commits. In a large repository or over a slow network (if origin needs to be resolved), this could cause the UI to hang. Since createPR is already an async function, it is better to use an asynchronous execution method like execFile from node:child_process wrapped in a promise, or a similar utility if available in the project.

// Step 1a: Auto-commit any uncommitted changes in the worktree before pushing.
// This handles the case where the agent wrote files but didn't run `git commit`.
// A failure here is non-fatal — we still attempt the push in case prior commits exist.
autoCommitWorktreeChanges(worktreePath, gitPath, specId);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The return value of autoCommitWorktreeChanges is ignored. While the comment states that failure is non-fatal, if the auto-commit fails due to a configuration issue (e.g., user.email not set), the user won't receive any feedback until the later commit count check fails. It would be better to at least log the error or provide a warning if the function returns an error string.

try {
const commitCount = execFileSync(
gitPath,
['rev-list', '--count', `origin/${effectiveBase}..HEAD`],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The commit count check hardcodes the remote name as origin. While this is consistent with the rest of the file (e.g., pushBranch), it will fail if the user has configured a different remote name for their upstream. Consider making the remote name configurable or detecting it from the git configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failed to create PR: pull request create failed: GraphQL: Head sha can't be blank, Base sha can't be blank

2 participants