Skip to content

Reset branch from header commit picker#123

Open
friuns2 wants to merge 3 commits intomainfrom
codex/header-git-reset-commit
Open

Reset branch from header commit picker#123
friuns2 wants to merge 3 commits intomainfrom
codex/header-git-reset-commit

Conversation

@friuns2
Copy link
Copy Markdown
Owner

@friuns2 friuns2 commented May 3, 2026

Summary

  • change header commit selection from detached checkout to guarded branch reset
  • save pre-reset branch tips under internal reset-history refs
  • include reset-history refs when loading branch commits so previous commits remain visible after one or more resets
  • allow reset/switch when the only dirty worktree entries are untracked files, while still blocking tracked/staged changes
  • disable reset actions for remote branch commit rows
  • reuse worktree-lock checkout recovery before reset and cap reset-history refs per branch
  • update manual test docs for reset, untracked-file, remote-row, and repeated-reset behavior

Tests

  • pnpm run build:frontend
  • pnpm run build:cli
  • git diff --check
  • temp repo smoke: reset branch to older commit and confirmed old tip still appears via saved ref
  • temp repo smoke: reset succeeds with an untracked file present and tracked modifications are still detected
  • temp repo smoke: reset-history ref pruning keeps 25 refs

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Review Summary by Qodo

Replace detached commit checkout with branch reset and reset-history tracking

✨ Enhancement 🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Replace detached HEAD checkout with guarded branch reset operation
• Save pre-reset branch tips under internal reset-history refs
• Include reset-history refs when loading commits for visibility
• Update API and UI to support branch-aware reset operations
Diagram
flowchart LR
  A["User selects commit<br/>in branch dropdown"] -->|emit resetBranchToCommit| B["API: resetGitBranchToCommit"]
  B -->|checkout branch if needed| C["Ensure on target branch"]
  C -->|save current HEAD| D["Create reset-history ref"]
  D -->|git reset --hard| E["Reset branch to commit"]
  E -->|load commits with refs| F["Include reset-history refs<br/>in git log"]
  F -->|display commits| G["UI shows previous commits<br/>after reset"]
Loading

Grey Divider

File Changes

1. src/api/codexGateway.ts ✨ Enhancement +4/-3

Rename checkout to reset with branch parameter

• Rename checkoutGitCommit to resetGitBranchToCommit with new branch parameter
• Update API endpoint from /codex-api/git/checkout-commit to /codex-api/git/reset-to-commit
• Include branch name in request body for reset operation
• Update error messages to reflect reset operation instead of checkout

src/api/codexGateway.ts


2. src/server/codexAppServerBridge.ts ✨ Enhancement +37/-5

Implement branch reset with reset-history ref tracking

• Add toHeaderGitResetHistoryRef helper to generate reset-history ref paths
• Add assertLocalGitBranch helper to verify branch exists locally
• Update error message in assertCleanGitWorktree to mention branch reset
• Modify /codex-api/git/branch-commits endpoint to include reset-history refs in git log query
• Replace detached checkout with branch checkout, reset-history ref creation, and hard reset
• Add branch validation and checkout logic before performing reset

src/server/codexAppServerBridge.ts


3. src/App.vue ✨ Enhancement +8/-7

Update event handlers for branch reset operation

• Update event binding from @checkout-commit to @reset-branch-to-commit
• Rename handler from onCheckoutContentHeaderCommit to onResetContentHeaderBranchToCommit
• Update handler to accept payload object with branch and sha instead of just sha
• Replace checkoutGitCommit import with resetGitBranchToCommit
• Update error message handling to reflect reset operation

src/App.vue


View more (2)
4. src/components/content/HeaderGitBranchDropdown.vue ✨ Enhancement +4/-3

Update commit selection to emit reset event with branch

• Rename emitted event from checkoutCommit to resetBranchToCommit
• Update event payload to include both branch name and commit sha
• Add tooltip showing reset action description
• Update trigger label from "Git checkout" to "Git branch"
• Update event emit definition in defineEmits

src/components/content/HeaderGitBranchDropdown.vue


5. tests.md 📝 Documentation +16/-13

Update manual test documentation for reset workflow

• Rename test section from "commit checkout" to "commit reset"
• Update feature description to emphasize branch reset instead of detached HEAD
• Revise prerequisites to use disposable local branch for testing
• Update test steps to verify branch remains checked out after reset
• Add verification steps for reset-history ref preservation
• Update expected results to document reset-history commit visibility
• Simplify cleanup instructions for reset-based workflow

tests.md


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects Bot commented May 3, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Remote reset button breaks🐞 Bug ≡ Correctness
Description
The dropdown emits resetBranchToCommit for commits under remote branches (e.g. origin/main), but
the server reset endpoint requires a local branch (refs/heads/), so the action will always fail
for remote entries.
Code

src/components/content/HeaderGitBranchDropdown.vue[R79-80]

+                :title="`Reset ${branch.value} to ${commit.shortSha}`"
+                @click="emit('resetBranchToCommit', { branch: branch.value, sha: commit.sha })"
Evidence
Backend branch options include both local heads and remotes, and the UI displays remote branches as
selectable/expandable. The reset endpoint verifies only refs/heads/ via assertLocalGitBranch, so
remote branch names cannot pass validation, making the reset action non-functional for those UI
entries.

src/server/codexAppServerBridge.ts[5900-5927]
src/components/content/HeaderGitBranchDropdown.vue[45-90]
src/server/codexAppServerBridge.ts[2505-2507]
src/server/codexAppServerBridge.ts[6103-6106]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The UI offers a "reset branch to commit" action for commit rows under remote branches, but the server endpoint only supports resetting *local* branches. This creates a guaranteed failure path when users click commits under `isRemote` branches.
### Issue Context
- Branch list includes `refs/remotes` entries and marks them with `isRemote`.
- Reset endpoint validates with `refs/heads/<branch>` only.
### Fix Focus Areas
- src/components/content/HeaderGitBranchDropdown.vue[45-90]
- src/server/codexAppServerBridge.ts[5900-5927]
- src/server/codexAppServerBridge.ts[6079-6115]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Worktree-locked reset fails🐞 Bug ☼ Reliability
Description
The new /codex-api/git/reset-to-commit endpoint does a plain git checkout  without the existing
"branch is already checked out at <path>" recovery used by the checkout endpoint, so resets will
fail when the branch is locked by another worktree.
Code

src/server/codexAppServerBridge.ts[R6105-6111]

+          await assertLocalGitBranch(gitRoot, branch)
+          const currentBranch = (await runCommandCapture('git', ['branch', '--show-current'], { cwd: gitRoot })).trim()
+          if (currentBranch && currentBranch !== branch) {
+            await runCommand('git', ['checkout', branch], { cwd: gitRoot })
+          } else if (!currentBranch) {
+            await runCommand('git', ['checkout', branch], { cwd: gitRoot })
+          }
Evidence
The existing checkout endpoint explicitly handles the "branch already checked out" case by parsing
the error, detaching the other worktree, and retrying checkout; the new reset endpoint performs
checkout without that recovery, so the same scenario will now surface as a 500 error instead of
being handled.

src/server/codexAppServerBridge.ts[2543-2550]
src/server/codexAppServerBridge.ts[5987-6027]
src/server/codexAppServerBridge.ts[6079-6111]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`POST /codex-api/git/reset-to-commit` checks out the requested branch before resetting, but it doesn't handle the case where Git refuses because the branch is already checked out in another worktree. The existing `/codex-api/git/checkout` endpoint has explicit recovery logic for this scenario; `reset-to-commit` should have equivalent handling (or an alternative approach that avoids checkout failures).
### Issue Context
- The repo already has logic to detect the locked-worktree checkout error (`extractBranchLockedWorktreePath`) and recover by detaching the blocking worktree then retrying.
- The new reset endpoint currently does an unconditional checkout (when needed) and will throw if the branch is locked.
### Fix Focus Areas
- src/server/codexAppServerBridge.ts[5987-6027]
- src/server/codexAppServerBridge.ts[6079-6111]
- src/server/codexAppServerBridge.ts[2543-2550]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Unbounded reset-history growth🐞 Bug ➹ Performance
Description
Each reset writes a new reset-history ref and branch commit loading expands all of them into `git
log` arguments with no cap, which can grow unbounded over time and eventually cause slowdowns or
argument-length failures.
Code

src/server/codexAppServerBridge.ts[R6050-6063]

+          const resetHistoryRefPrefix = `refs/codex/header-git-reset-history/${branch}/`
+          const resetHistoryRefsRaw = await runCommandCapture(
+            'git',
+            ['for-each-ref', '--format=%(refname)', resetHistoryRefPrefix],
+            { cwd: gitRoot },
+          ).catch(() => '')
+          const resetHistoryRefs = resetHistoryRefsRaw
+            .split('\n')
+            .map((entry) => entry.trim())
+            .filter(Boolean)
        const output = await runCommandCapture(
          'git',
-            ['log', '-n', '12', '--date=short', '--format=%H%x09%h%x09%cd%x09%s', branch],
+            ['log', '-n', '12', '--date=short', '--format=%H%x09%h%x09%cd%x09%s', branch, ...resetHistoryRefs],
          { cwd: gitRoot },
Evidence
The reset endpoint persists the previous tip under a unique ref per reset. The branch-commits
endpoint then enumerates all such refs for a branch and spreads them into a single git log call;
without pruning/limiting, the number of refs and command arguments increases monotonically with each
reset.

src/server/codexAppServerBridge.ts[2501-2503]
src/server/codexAppServerBridge.ts[6046-6064]
src/server/codexAppServerBridge.ts[6112-6115]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Reset-history refs are created on every reset and never pruned. Commit loading enumerates *all* matching refs and passes them as positional arguments to `git log`, which can grow without bound.
### Issue Context
- `update-ref` creates `refs/codex/header-git-reset-history/<branch>/<sha>` on every reset.
- `branch-commits` does `for-each-ref` then `git log ... branch, ...resetHistoryRefs` with no limit.
### Fix Focus Areas
- src/server/codexAppServerBridge.ts[6046-6064]
- src/server/codexAppServerBridge.ts[6112-6115]
- src/server/codexAppServerBridge.ts[2501-2503]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread src/components/content/HeaderGitBranchDropdown.vue Outdated
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.

2 participants