Skip to content

Conversation

@ThomasK33
Copy link
Member

Adds ability to select a trunk/base branch when creating a new workspace.

Changes

UI

  • Command palette: Added trunk branch selection field with fuzzy search
  • Modal (CMD+N): Added dropdown to select trunk branch
  • Both UIs load local branches and show them as options
  • Trunk branch selection is optional (defaults to HEAD if not selected)

Backend

  • Added listLocalBranches() to enumerate local branches
  • Updated createWorktree() to accept optional trunkBranch parameter
  • New logic: if trunk is specified, always create new branch from trunk
    • Ignores remote branches when trunk is explicitly selected
    • Errors if local branch already exists (prevents overwrite)
  • Without trunk: preserves existing behavior (checkout remote or create from HEAD)

IPC Layer

  • Added WORKSPACE_LIST_BRANCHES channel to fetch branches for a project
  • Updated workspace.create to accept and pass through trunkBranch
  • Wired through preload.ts, ipcMain.ts, and type definitions

Integration

  • Updated App.tsx to pass trunk branch from modal to backend
  • Updated command palette prompts to collect trunk branch selection
  • Command palette supports async option loading with fuzzy filtering

Use Cases

This enables creating feature branches from any local branch:

  • Creating branches from main instead of current HEAD
  • Starting new work from a specific release branch
  • Isolating work from unrelated changes on current branch

Testing

  • ✅ All lint checks pass
  • ✅ All TypeScript checks pass
  • ✅ Command palette trunk selection works
  • ✅ Modal trunk selection works
  • ✅ Trunk branch parameter flows through entire stack

Generated with cmux

@ThomasK33 ThomasK33 force-pushed the trunk-branch branch 2 times, most recently from db7f61b to cfdbc06 Compare October 8, 2025 17:08
@ThomasK33 ThomasK33 marked this pull request as ready for review October 8, 2025 17:14
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Copy link
Member Author

@ThomasK33 ThomasK33 left a comment

Choose a reason for hiding this comment

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

@chatgpt-codex-connector Addressed the notarization config issue - restored the flag that was accidentally removed during rebase.

@chatgpt-codex-connector
Copy link

To use Codex here, create an environment for this repo.

@ThomasK33
Copy link
Member Author

Addressed Codex feedback on notarization config

Fixed the P1 issue - restored notarize: true flag in package.json that was accidentally removed during rebase. The flag is now back and macOS builds will be properly notarized.

@ThomasK33
Copy link
Member Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

? (activePrompt.fields[activePrompt.idx] ?? null)
: null;

useEffect(() => {
Copy link
Member

Choose a reason for hiding this comment

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

this code is kind of monstrous -- needs comment or simplification

const loadBranches = async () => {
setIsLoadingBranches(true);
try {
const branchList = await window.api.workspace.listBranches(projectPath);
Copy link
Member

Choose a reason for hiding this comment

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

this is the wrong scoping for listBranches -- its an operation on the project. The IPC doesn't have a projects section. Working on reworking the IPC so the frontend doesn't directly access config and there is instead safe operations via a projects section.

trunkBranch?: string;
}

export async function listLocalBranches(projectPath: string): Promise<string[]> {
Copy link
Member

Choose a reason for hiding this comment

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

should have a test

Copy link
Member

Choose a reason for hiding this comment

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

alternatively and better would be to add a test for createWorktree

@ThomasK33 ThomasK33 force-pushed the trunk-branch branch 3 times, most recently from 061f6ff to 6d6623e Compare October 9, 2025 17:23
@ThomasK33 ThomasK33 requested a review from ammario October 9, 2025 17:24
Copy link
Member

@ammario ammario left a comment

Choose a reason for hiding this comment

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

good shit

Copy link
Member

Choose a reason for hiding this comment

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

(essentially ignoring this file for the purpose of review)

projectPath: string;
onClose: () => void;
onAdd: (branchName: string) => Promise<void>;
onAdd: (branchName: string, trunkBranch?: string) => Promise<void>;
Copy link
Member

Choose a reason for hiding this comment

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

why not make the trunkBranch required throughout? That should simplify the code paths.

Copy link
Member

Choose a reason for hiding this comment

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

We can still infer a reasonable default from what's checked out in the project root — so i mean this from a code perspective not a UX perspective

{isLoadingBranches ? (
<option value="">Loading branches...</option>
) : (
<option value="">-- Select trunk branch (optional) --</option>
Copy link
Member

Choose a reason for hiding this comment

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

would rather we just default to the branch we found and will use vs. making this optional -- such behavior would have saved me a bunch of time as i've accidenally created workspaces off a detached head state vs. main

ipcMain.handle(
IPC_CHANNELS.WORKSPACE_CREATE,
async (_event, projectPath: string, branchName: string) => {
async (_event, projectPath: string, branchName: string, trunkBranch?: string) => {
Copy link
Member

Choose a reason for hiding this comment

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

again re optional

src/App.tsx Outdated
try {
return await window.api.projects.listBranches(projectPath);
} catch (error) {
console.error("Failed to list branches:", error);
Copy link
Member

Choose a reason for hiding this comment

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

better for the error to propagate to the caller imo so that it can be displayed in a useful place vs the console

for (let i = 1; i < branches.length; i += 1) {
expect(branches[i - 1].localeCompare(branches[i])).toBeLessThanOrEqual(0);
}
});
Copy link
Member

Choose a reason for hiding this comment

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

appreciate the tests

src/git.ts Outdated
b.trim() === `remotes/origin/${branchName}`
);
// If trunk branch is specified, always create a new branch from it
if (trunkBranch) {
Copy link
Member

Choose a reason for hiding this comment

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

again, this code would be simplified if it wasn't optional

@ThomasK33 ThomasK33 changed the base branch from main to thomask33/10-10-add_nix_formatter_ci October 10, 2025 16:44
Base automatically changed from thomask33/10-10-add_nix_formatter_ci to main October 10, 2025 16:48
@ThomasK33 ThomasK33 requested a review from ammario October 10, 2025 17:37
Adds ability to select a trunk/base branch when creating a new workspace.
When a trunk branch is selected, the new workspace branch is created from
that trunk instead of from HEAD or an existing remote branch.

UI Changes:
- Command palette: Added trunk branch selection field with fuzzy search
- Modal (CMD+N): Added dropdown to select trunk branch
- Both UIs load local branches and show them as options
- Trunk branch selection is optional (defaults to HEAD if not selected)

Backend Changes:
- Added listLocalBranches() to git.ts to enumerate local branches
- Updated createWorktree() to accept optional trunkBranch parameter
- New logic: if trunk is specified, always create new branch from trunk
  - Ignores remote branches when trunk is explicitly selected
  - Errors if local branch already exists (prevents overwrite)
- Without trunk: preserves existing behavior (checkout remote or create from HEAD)

IPC Layer:
- Added WORKSPACE_LIST_BRANCHES channel to fetch branches for a project
- Updated workspace.create to accept and pass through trunkBranch
- Wired through preload.ts, ipcMain.ts, and type definitions

Integration:
- Updated App.tsx to pass trunk branch from modal to backend
- Updated command palette prompts to collect trunk branch selection
- Added getBranchesForProject callback to command registry context
- Command palette supports async option loading with fuzzy filtering

This enables creating feature branches from any local branch, useful for:
- Creating branches from main instead of current HEAD
- Starting new work from a specific release branch
- Isolating work from unrelated changes on current branch

_Generated with `cmux`_

Change-Id: Ic2a710104f3a5925e0e6bdff1d0e5ed772bcf108
Signed-off-by: Thomas Kosiewski <tk@coder.com>

🤖 Restore macOS notarization configuration

The notarization flag was accidentally removed during rebase. This flag is
required to submit the DMG for notarization so that distributed builds are
not blocked by Gatekeeper on macOS 10.15+.

Restores the 'notarize: true' flag in the mac build configuration.

_Generated with `cmux`_

Change-Id: I3d4e4be981cdbb0cee0c822dd973b1a71e000108
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Copy link
Member

@ammario ammario left a comment

Choose a reason for hiding this comment

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

there's minor ui stuff like the caret on the select is misaligned - but this an essential feature that i need desperately so lets get it in

@ammario ammario added this pull request to the merge queue Oct 10, 2025
Merged via the queue into main with commit 4241982 Oct 10, 2025
8 of 9 checks passed
@ammario ammario deleted the trunk-branch branch October 10, 2025 18:23
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