Guía9 min

git branch para coding agents: crear refs, no cambiar de árbol

Resumen

git branch lista, crea o borra refs. No cambia el working tree: para eso es switch -c. Un agente usa --list con patrón, --show-current y -d solo si --merged. Cero -D/-M/-C/-f autónomos. Nombres vía check-ref-format --branch. Git 2.50.1 / Apple Git-155.

GitHub
Una ref nueva apunta al start-point; el working tree sigue en la rama actual

Qué resuelve

Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.

git branch no cambia el working tree. El man (git-branch(1), Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-branch HTTP 200, actualizado en 2.51.0): lista, crea o borra ramas. La forma que crea un head nuevo apunta al HEAD actual o a un <start-point>; el árbol se queda donde está. El propio man remite a git switch para entrar a esa rama.

Esta guía no sustituye switch, worktrees ni branch protection. El contrato: qué forma corre un agente, qué flags fuerzan, y cómo se nombra una ref.

Lista, no pager, no crear por accidente

Sin argumentos no opcionales, o con --list, lista. El man: la rama actual va con asterisco; un checkout en worktree ligado se marca con más. -r son tracking remotas; -a mezcla locales y remotas.

Un <pattern> es un glob de shell. Hay que pasar --list: si no, Git puede interpretar el patrón como creación. pager.branch solo aplica al listado; un agente no pagina.

--show-current imprime el nombre de la rama actual. HEAD detached: no imprime nada. No es un error silencioso que se trague: si sale vacío, para.

--format interpola %(fieldname) como git-for-each-ref. Para un agente, --format='%(refname:short)' o --show-current bastan. -v / -vv añaden SHA, subject, upstream y, al duplicar, la ruta del worktree. No dumps.

Listado con --list y --show-current; el working tree no se mueve

Lo que el agente sí / no corre

QuieroComandoTrampa
Rama actualgit branch --show-currentVacío = detached. No asumas main
Listar localesgit branch --listgit branch 'feat-*' sin --list (puede crear)
Crear sin entrargit branch <name> origin/mainEntrar = switch -c
Crear y entrargit switch -c <name> origin/maingit checkout -b (mezcla restore)
Borrar fusionadagit branch -d <name>-D / -d --force sin --merged
Trackingnace de una remote-tracking, o -u--set-upstream ya no existe

Prohibido en autónomo:

  • -f / --force al crear. El man: sin -f, se niega a cambiar una rama que ya existe. Con -f, resetea <branch-name> al start-point. Reescribe la ref. Además se niega si esa rama está checked out en otro worktree.
  • -D (--delete --force). -d exige que esté fusionada en su upstream, o en HEAD si no hay upstream. -D borra igual, incluso si el tip no es un commit válido. El ejemplo del man borra test aunque la rama actual no contenga esos commits.
  • -M / -C. -m renombra con config y reflog; -c copia. Las mayúsculas fuerzan si el destino ya existe.
  • --edit-description. Abre editor. Un agente no edita la descripción de la rama a ciegas.
  • --recurse-submodules. El man lo marca experimental. Solo creación, y solo si submodule.propagateBranches está on.
  • --set-upstream. El man: sintaxis confusa, ya no se soporta. Usa --track o --set-upstream-to / -u.
  • Borrar -d -r origin/... “para limpiar”. El ejemplo del man: el próximo fetch las recrea salvo que el fetch esté configurado para no traerlas. El prune va en git-remote, no en un -d -r suelto.
  • Crear sobre main / master / la default. GitHub Docs (Branches, HTTP 200 2026-09-04, /pull-requests/reference/branches): en repos nuevos con contenido, GitHub crea una rama, la default; es la que muestra al visitar, la que Git hace checkout al clonar, y —si no se indica otra— la base de PRs y commits. Por defecto esa default se llama main. Cambiarla es Settings de admin (Changing the default branch, HTTP 200): el repo debe tener más de una rama. Un agente no la renombra ni la borra.

-- delante del nombre. Un name que parece opción se parsea mal.

Receta (60 segundos)

Solo en un worktree propio:

git branch --show-current          # vacío → detached; para
git check-ref-format --branch feat/foo
git fetch origin
git switch -c feat/foo origin/main

Si el contrato del repo pide la ref sin entrar al árbol (otro proceso ya tiene el checkout):

git branch feat/foo origin/main
git worktree add ../feat-foo feat/foo

Listar sin crear:

git branch --list 'feat/*'
git branch --merged
git branch --no-merged

--merged (commit omitido = HEAD): tips alcanzables desde HEAD; el man, NOTES: candidatas a borrar con seguridad. --no-merged: las que no están contenidas; candidatas a mergear hacia HEAD. --contains <commit>: tips que descienden de ese commit (quién se rompe si lo reescribes). No son el mismo filtro.

Cierre: PR. No push a la default.

 -f resetea una ref existente; -D borra sin mirar --merged

Nombres, tracking y default main

El man: el nombre nuevo tiene que pasar git-check-ref-format(1). Verificado 2026-09-04 (git-check-ref-format(1), Git 2.54.0 / 2026-04-19; git-scm.com/docs/git-check-ref-format HTTP 200) y en esta máquina (Git 2.50.1 / Apple Git-155):

Nombregit check-ref-format --branchPor qué
feat/foo0Componente con / válido
-bad128El man --branch: un guion al inicio del nombre de rama está prohibido
foo..bar128Dos puntos seguidos (rango A..B)
foo.lock128Componente que termina en .lock
foo@{bar}128Secuencia @{ (reflog)

Otras reglas del mismo man, sin improvisar nombres: nada de espacio, ~, ^, :, ?, *, [, barra al inicio/final, punto al final, ni la barra invertida. --branch es lo que deben usar los porcelains: primero expande @{-n} (último switch/checkout). Un agente valida antes de crear.

Tracking. Si la rama nace de una remote-tracking, Git rellena branch.<name>.remote y branch.<name>.merge para que pull sepa de dónde mergear. branch.autoSetupMerge default true: equivale a --track=direct cuando el start-point es remote-tracking. false = --no-track. always trackea también desde local. inherit copia el upstream del start-point. simple solo si el start-point es remote-tracking y el nombre coincide. --track=inherit vs --track=direct pisan ese default. Un agente no pone branch.autoSetupRebase (default never): rebase automático no es el contrato de pull.

GitHub Docs (Branches): hace falta write para crear rama, abrir PR, o borrar/restaurar ramas en un PR. Una rama de feature se crea desde otra, casi siempre la default. Las protected branches pueden bloquear force-push y delete, exigir checks, reviews, code owners o commits firmados: detalle en branch protection. El agente no bypassea eso ni hace force-push a main.

NOTES del man: si vas a entrar a la rama al crearla, git switch -c es un solo paso. switch -c es transaccional: si el switch falla, no deja la ref a medias. git branch + git switch son dos comandos; el segundo puede abortar y dejar la rama huérfana de checkout. Prefiere switch cuando el worktree es tuyo.

Checklist

  • Worktree propio. git branch --show-current no vacío.
  • Nombre: git check-ref-format --branch <name> exit 0. Cero -bad, .., .lock, @{.
  • Crear y entrar: git switch -c <name> origin/main. Cero checkout -b.
  • Solo crear la ref: git branch <name> <start> y worktree, no -f.
  • Listar: --list + patrón. Cero patrón suelto.
  • Borrar: -d después de --merged. Cero -D / -M / -C.
  • Cero --set-upstream, --edit-description, --recurse-submodules.
  • Cierre = PR, no commit en la default.

FAQ

¿git branch feat y luego switch? Sí, pero el man recomienda switch -c si vas a entrar. Menos estados a medias.

¿Puedo -D de una rama que “ya mergeé en GitHub”? -d mira upstream o HEAD local, no el botón de GitHub. Si el tracking no está, HEAD tiene que contener el tip. Si no, no borres.

¿git branch -m de main a trunk? Renombrar la default es un cambio de admin en GitHub (Changing the default branch): Settings, más de una rama, confirmación. Un agente no.

¿Patrón feat-* sin --list? El man: puede leerse como creación. Siempre --list.

El curso instalar un agente cubre el loop local. Hub: comparativas y decisiones. Branch no es switch: mueve la ref, no el árbol.

Verificado 2026-09-04 contra git-branch(1) (Git 2.50.1 / Apple Git-155; git-scm.com/docs/git-branch HTTP 200, last updated 2.51.0), git-check-ref-format(1) (git-scm.com/docs/git-check-ref-format HTTP 200; --branch exit 128 para -bad, foo..bar, foo.lock, foo@{bar} en esta máquina) y GitHub Docs “Branches” (/pull-requests/reference/branches, HTTP 200; default main en repos nuevos) y “Changing the default branch” (HTTP 200).