Add ability to create a worktree based on a remote branch

Open 💬 6 comments Opened Apr 22, 2026 by ustun

What variant of Codex are you using?

Codex App

What feature would you like to see?

When reviewing Github PRs, here is my workflow right now:

1/ Track the remote branch locally.
2/ Create a new worktree in Codex to review the branch.

Ideally, I should be able to skip step 1 and specify a remote branch name, where Codex switched to a worktree tracking that branch.

Additional information

_No response_

View original on GitHub ↗

6 Comments

meck93 · 3 months ago

In the Codex app, the branch dropdown also includes remote branches that I haven't checked out on my local machine yet.
If I try to create a worktree without checking out the branch first, it fails. Once checked out, it works fine.
Codex App Bug Report ID: 019df174-ff6f-79b0-8d59-731f9771b103

thomast8 · 3 months ago

I wish it worked for me, but the Codex MacOS app doesn't automatically fetch remote branches which makes it pretty useless for my work especially because there's no programmatic way to switch to another branch in the UI once a conversation has started.

dtretyakov · 3 months ago

I also want to eliminate the step with opening terminal and doing git fetch origin main before starting new session with worktree from that branch.

ohdnf · 2 months ago

I reproduced a related stale-base case when creating a new Codex-managed worktree from a local default branch.

Environment

  • OS: macOS, Darwin 25.5.0, arm64
  • Git: 2.50.1 (Apple Git-155)
  • Codex App version: 26.616.51431
  • Selected mode: Worktree
  • Selected starting branch: main
  • Worktree state: detached HEAD
  • Local Environment: disabled for this reproduction
  • SessionStart fetch hook: disabled for this reproduction

The reproduction used a temporary local bare repository, so network latency, remote authentication, and an external Git hosting service were not involved.

Reproduction steps

I reproduced this using only a temporary local bare Git repository. No external Git hosting service or network access was required.

1. Create a source checkout at commit A

ROOT="$(mktemp -d "${TMPDIR:-/tmp}/codex-stale-base.XXXXXX")"
REMOTE="$ROOT/remote.git"
SOURCE="$ROOT/source"
PUBLISHER="$ROOT/publisher"

git init --bare --initial-branch=main "$REMOTE"

git clone "$REMOTE" "$SOURCE"
git -C "$SOURCE" config user.name "Codex Repro"
git -C "$SOURCE" config user.email "codex-repro@example.invalid"

mkdir -p "$SOURCE/src"

cat > "$SOURCE/package.json" <<'JSON'
{
  "name": "codex-worktree-stale-base-repro",
  "private": true,
  "version": "0.0.0"
}
JSON

cat > "$SOURCE/src/index.ts" <<'TS'
export const version = "A";
TS

git -C "$SOURCE" add package.json src/index.ts
git -C "$SOURCE" commit -m "commit A"
git -C "$SOURCE" push -u origin main

2. Advance the actual remote to commit B from another checkout

git clone "$REMOTE" "$PUBLISHER"
git -C "$PUBLISHER" config user.name "Codex Repro"
git -C "$PUBLISHER" config user.email "codex-repro@example.invalid"

cat > "$PUBLISHER/src/index.ts" <<'TS'
export const version = "B";
TS

git -C "$PUBLISHER" add src/index.ts
git -C "$PUBLISHER" commit -m "commit B"
git -C "$PUBLISHER" push origin main

At this point, do not run git fetch or git pull in the source checkout.

Verify the intentionally stale state:

git -C "$SOURCE" rev-parse refs/heads/main
git -C "$SOURCE" rev-parse refs/remotes/origin/main
git -C "$SOURCE" ls-remote origin refs/heads/main

The first two commands should return commit A, while ls-remote should return commit B.

3. Create a Codex worktree

  1. Open the $SOURCE directory as a project in Codex App.
  2. Start a new conversation in Worktree mode.
  3. Select local branch main as the starting branch.
  4. Do not use a Local Environment setup script that runs git fetch, git pull, or git reset.
  5. Submit a prompt that only runs the following read-only commands:
pwd
git rev-parse --show-toplevel
git rev-parse HEAD
git symbolic-ref --short -q HEAD || echo DETACHED
git status --short --branch
git log -1 --oneline
git worktree list --porcelain

4. Observe the result

The new Codex worktree was created at commit A, even though the actual remote main had already advanced to commit B.

Repository state before worktree creation

The source checkout was intentionally left stale.

local refs/heads/main:
3ddf2585df630c0289062b2a6ea2f428cf9cb549

locally cached refs/remotes/origin/main:
3ddf2585df630c0289062b2a6ea2f428cf9cb549

actual remote refs/heads/main:
1137083843a3ab65cfa4cf9d1224d9f49190b91e

The source checkout was clean:

## main...origin/main

The source checkout's latest commit was:

3ddf258 commit A

Result

Codex created the new managed worktree at the stale local commit:

git rev-parse HEAD
3ddf2585df630c0289062b2a6ea2f428cf9cb549

The worktree was detached:

git symbolic-ref --short -q HEAD || echo DETACHED
DETACHED

The worktree status was:

## HEAD (no branch)

The worktree's latest commit was:

3ddf258 commit A

The worktree list showed:

worktree <SOURCE_TREE>
HEAD 3ddf2585df630c0289062b2a6ea2f428cf9cb549
branch refs/heads/main

worktree <CODEX_WORKTREE>
HEAD 3ddf2585df630c0289062b2a6ea2f428cf9cb549
detached

The final state was therefore:

| Ref or worktree | Commit |
| --- | --- |
| Local main | 3ddf2585df630c0289062b2a6ea2f428cf9cb549 |
| Cached origin/main | 3ddf2585df630c0289062b2a6ea2f428cf9cb549 |
| Actual remote main | 1137083843a3ab65cfa4cf9d1224d9f49190b91e |
| New Codex worktree | 3ddf2585df630c0289062b2a6ea2f428cf9cb549 |

In other words:

local main      = commit A
actual remote   = commit B
Codex worktree  = commit A

The origin/main reflog also showed no fetch or update during worktree creation:

3ddf258 origin/main@{2026-06-22 13:54:15 +0700} update by push 2026-06-22 13:54:15 +0700

This demonstrates that Codex created the worktree from the stale local branch HEAD without first refreshing the corresponding remote-tracking branch.

Expected behavior

This appears closely related to creating worktrees directly from remote branches. Both cases require Codex to refresh and resolve the intended base commit before creating the worktree.

I suggest avoiding an automatic git pull, because that would mutate the user's local branch and could introduce merge or rebase behavior.

A safer flow would be:

  1. Discover the selected branch's configured upstream.
  2. Fetch the relevant remote.
  3. Compare the local and upstream commits.
  4. Resolve an immutable base commit OID.
  5. Create the detached worktree from that OID.
  6. Leave the local branch and source checkout unchanged.

When the local branch is only behind its upstream, Codex could create the worktree from the fetched upstream OID without updating refs/heads/main.

For ahead, diverged, no-upstream, dirty, or fetch-failure states, Codex should ask the user or report the state instead of silently merging, rebasing, or falling back to a stale commit.

A key regression assertion could be:

Creating a worktree from the latest upstream must not move the local branch ref or modify the source checkout.

Would the maintainers prefer this stale-local-default-branch case to remain under #18961, or should it be tracked as a separate pre-worktree base-refresh issue?

Also, is the relevant base-resolution logic part of the open-source App Server or Git utility layer? I would be interested in contributing tests and an implementation if an external PR is invited.

keenranger · 1 month ago

I am seeing the same stale-starting-branch failure mode in Codex App worktree mode, especially when starting from a clean local develop branch that is behind origin/develop.

Environment where this is still relevant:

  • Codex App: 26.623.70822
  • Codex-managed worktree mode
  • Starting branch: local develop
  • Resulting worktree: detached HEAD

Practical failure mode:

  1. The source checkout has local develop at commit A.
  2. The actual remote origin/develop has advanced to commit B.
  3. The source checkout has not fetched yet, so local develop and the cached refs/remotes/origin/develop still point at A.
  4. In Codex App, start a new thread in Worktree mode and select develop.
  5. Codex creates the detached worktree from A.
  6. The agent then works or reviews from an old base, even though the user's intent was the current upstream develop at B.

The important safety point is that fixing this should not require git pull or moving the user's local branch. Since Codex creates a detached worktree, it can safely resolve a fresh immutable base OID first:

  • discover the selected local branch's configured upstream;
  • fetch the relevant remote before creating the worktree;
  • compare local branch, remote-tracking branch, and fetched upstream OID;
  • if the selected local branch is only behind upstream, create the detached worktree from the fetched upstream OID;
  • do not merge, rebase, git pull, or move refs/heads/develop / refs/heads/main;
  • if the branch is ahead, diverged, dirty, has no upstream, or fetch fails, surface that state instead of silently falling back to the stale local commit.

A useful regression assertion would be:

Creating a Codex-managed detached worktree from an upstream-tracking branch that is only behind its upstream must not move the local branch ref, but also must not start the worktree from a stale pre-fetch commit.

A SessionStart hook is not an equivalent workaround: it fires after the worktree already exists, and at that point the hook cannot reliably know which branch/upstream was selected to create the detached worktree. This seems best handled in Codex's pre-worktree base resolution step.

tonydehnke · 4 days ago

I am seeing the same stale-base problem in the Codex macOS app with a repository whose default development branch is staging.

When starting a new worktree chat, Codex defaults the branch picker to staging. The intended base is the latest origin/staging, but the local staging ref may be behind. This can create a new detached worktree from stale code unless I leave Codex and manually fetch or pull first.

The ideal behavior would be either:

  • allow a per-project default such as origin/staging; or
  • when the selected local branch tracks an upstream, fetch that upstream and create the detached worktree from the freshly resolved upstream commit.

This should not move, merge, rebase, or otherwise modify the local staging branch. If the local branch is ahead, diverged, dirty, lacks an upstream, or the fetch fails, Codex should show that state and ask what to do rather than silently using a stale commit.

In short: new worktree chats should be able to start from the current upstream commit while leaving the main local checkout untouched.