Skip to content

feat(source): follow the remote default branch when no ref is pinned#45

Merged
srnnkls merged 1 commit into
mainfrom
feat/default-branch-resolution
Jun 24, 2026
Merged

feat(source): follow the remote default branch when no ref is pinned#45
srnnkls merged 1 commit into
mainfrom
feat/default-branch-resolution

Conversation

@srnnkls

@srnnkls srnnkls commented Jun 24, 2026

Copy link
Copy Markdown
Owner

What

A git source with no branch/tag/rev resolved to a hardcoded main. A repository whose default branch is master or trunk failed to resolve and forced an explicit branch =. Resolution now defers to the repository's own default branch.

How

  • New Refspec::Default for the no-ref case; refspec() / intrinsic_refspec() return it instead of Branch("main").
  • Resolved by peeling the bare mirror's HEAD, which gix sets from the remote's advertised default at clone. Incremental fetches advance that branch's ref, so peeling HEAD always lands on the current tip.
  • Encoded as a stable default discriminator (network-independent), so the lock stays reproducible and encode_ref / Display round-trip without a branch name. A no-ref source records resolved = "default" with no ref discriminator.

Behavior

  • master/trunk/main repos all just work with no config.
  • phora update re-resolves the default branch to its current tip, exactly as it would track an explicit branch.
  • The pinned commit in the lock is unchanged by all this; only update re-resolves.

Known edge

HEAD is written once at clone and not refreshed if upstream renames its default branch — the stale symref resolves to the old branch until the disposable cache is re-cloned. The locked commit is unaffected. Pin an explicit branch to track a rename without a re-clone. Upgrade path: capture the HEAD symref from the fetch handshake and rewrite mirror HEAD each fetch.

Tests

  • resolve_default_follows_remote_default_branch_when_not_main — a trunk-default repo (no main) resolves via Default.
  • resolve_default_survives_an_incremental_fetch — tracks the tip across an incremental fetch.
  • Updated the two unit tests that pinned the old main default.
  • Re-validated on the main base after rebase: 1267 lib + all integration binaries + 7 scrut suites + clippy (pedantic, -D warnings) + rustfmt.

Docs

README documents the user-facing default. The GUIDE.md walkthrough for this change lands with the docs branch (#11) — GUIDE.md does not exist on main, so it cannot ride in this PR.

A git source with no branch/tag/rev resolved to a hardcoded `main`, so a
repository whose default branch is `master` or `trunk` failed to resolve and
forced an explicit `branch =`. Resolution now defers to the repository's own
default branch.

- add `Refspec::Default` for the no-ref case; `refspec()`/`intrinsic_refspec()`
  return it instead of `Branch("main")`
- resolve it by peeling the bare mirror's HEAD, which gix sets from the remote's
  advertised default at clone; incremental fetches advance that branch's ref, so
  HEAD always lands on the current tip
- encode as a stable `default` discriminator (network-independent), so the lock
  stays reproducible and `encode_ref`/`Display` round-trip without a branch name

Known edge: HEAD is written once at clone and not refreshed if upstream renames
its default branch; the pinned commit is unaffected and a re-clone of the
disposable cache picks up the rename.

README documents the user-facing default; the GUIDE.md walkthrough for this
change rides with the docs branch (GUIDE.md does not exist on main).
@srnnkls
srnnkls force-pushed the feat/default-branch-resolution branch from 3ef1449 to 347ffc3 Compare June 24, 2026 21:22
@srnnkls
srnnkls changed the base branch from docs/guide to main June 24, 2026 21:22
@srnnkls
srnnkls merged commit d1a466a into main Jun 24, 2026
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.

1 participant