Skip to content

[Feature Request] Fetch origin/<base> before creating a workspace so it branches from an up-to-date ref #79

Description

@EvgeniiaVak

Problem / use case

When I create a workspace, its branch is cut from my local origin/<base> remote-tracking ref — whatever it happened to be at my last manual fetch. If a teammate has pushed since (or I just haven't fetched in a while), the new workspace silently starts from a stale base. I usually only notice after the agent has done work, and then have to rebase/merge origin/main inside the workspace — exactly the manual step isolated workspaces are meant to avoid.

Concretely: I branch feature workspaces off origin/develop several times a day across a few repos. Any push by a colleague between my fetches means a stale start, a surprise merge, and occasionally conflicts the agent introduced against already-moved code.

Root cause (current behavior)

task_create in src-tauri/src/lib.rs branches directly off the local ref with no preceding fetch:

let base_full = args.base_branch.unwrap_or_else(|| proj.base_branch.clone()); // e.g. "origin/develop"
// ...
git(&["branch", "--no-track", &branch, &base_full], &repo)   // uses whatever origin/develop points at locally
// ...
git(&["worktree", "add", wt_arg, &branch], &repo)

The only git calls before the branch is cut are worktree prune/list and rev-parse — no fetch/pull/remote update anywhere in the create path (single- or multi-repo). So freshness depends entirely on the user having fetched recently.

Conductor already does this — it fetches from origin before creating a workspace, so the new branch is based on the latest remote commit even if the local checkout is behind. This is a straight parity gap.

Proposed solution

Before the git branch --no-track <branch> <base_full> call, do a best-effort, time-bounded fetch of just the base ref:

// base_full = "origin/develop" -> remote="origin", ref="develop"; skip if base is a local branch (no remote prefix)
// best-effort: never block or fail workspace creation on it
let _ = git_fetch_base(&repo, remote, base_branch); // git fetch --prune <remote> <base-branch>, bounded
  • A single-ref fetch (git fetch <remote> <base>) updates refs/remotes/<remote>/<base> and is fast — no need to fetch all refs.
  • Same insertion in the multi-repo path (host + each member around the worktree add sites), each honoring its own remote/base_branch.
  • task_create already runs off the IPC handler thread (per the comment at its top), so the added network call won't block the UI.

Critical: it must never hang or block create

A naive fetch-before-create is dangerous precisely because of auth/network. Guard it so a dead remote can't wedge workspace creation:

  • Env: GIT_TERMINAL_PROMPT=0 and GIT_SSH_COMMAND="ssh -oBatchMode=yes -oConnectTimeout=10" so a credential-less remote fails fast instead of prompting.
  • A hard timeout on the fetch (e.g. 10–15s) with the child killed on expiry.
  • Fetch failure is non-fatal — log it and proceed to branch off the existing local ref. Offline / auth-broken must still create the workspace, just from the stale ref (today's behavior), never an error.

Scope / config

  • A toggle (global pref and/or .termic.yaml per-project), default on, e.g. fetch_before_create: true, so users on flaky networks can opt out.
  • Optional nicety: surface a subtle "fetching base…" state during create, but the minimal version needs no new IPC surface — it's internal to the existing create command.

Note

I currently work around this with an external launchd LaunchAgent that runs git fetch --prune across all my Termic repos every 30s, which keeps the local origin/* refs current so workspaces start fresh. That works, but doing the fetch at create-time (targeted, bounded) is the right home for it and removes the polling.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions