gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1389Shell 137Markdown 80Rust 802602 Definiciones

`git-sincronizar.sh`: la regla 2 ter automatizada — porque hoy hizo falta cinco veces

En dos días, `git pull --rebase` se llevó por delante CINCO commits propios en este árbol
compartido, siempre con el mismo reflog: `commit:` mío, `(start): checkout <otro>`, `(finish):
returning to main`, y ni un `pick` en el medio. El comando no es el culpable —en un repo de juguete
reaplica bien— sino que alguien mueve `refs/heads/main` mientras el rebase está en vuelo.

La receta manual (CLAUDE.md regla 2 ter) funciona: mirar el log y recuperar con reflog +
cherry-pick. Esto es esa receta automatizada, porque **una regla que hay que acordarse de aplicar en
cada push es una regla que un día no se aplica**.

Hace, en orden: anota su HEAD · rebasa · COMPRUEBA que el commit sigue en la rama —por su mensaje,
no por el sha, que el rebase reescribe— · si no está lo recupera del reflog · empuja · verifica que
gitea quedó donde tiene que quedar · y si el espejo de GitHub quedó divergente lo realinea con
`--force-with-lease` (nunca `--force` a secas) y sólo tras comprobar que su contenido ya está en
nuestra historia.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

17b6ea1a4f67d8acb84380c84246ee1f5afadab2 · por Sergio · (hace 1 mes) · padre ef2f9391d · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

1 archivos · +72 −0

diff --git a/scripts/git-sincronizar.sh b/scripts/git-sincronizar.sh
new file mode 100755
index 00000000..1a786313
--- /dev/null
+++ b/scripts/git-sincronizar.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/env bash
+# git-sincronizar.sh — publicar un commit propio en un árbol COMPARTIDO sin perderlo.
+#
+# ── POR QUÉ EXISTE ──────────────────────────────────────────────────────────────────────────────
+# Este repo lo trabajan varios agentes a la vez sobre el MISMO árbol, y ahí `git pull --rebase` se
+# lleva commits por delante: el 2026-09-16/17 pasó CINCO veces, siempre con el mismo reflog —
+# `commit:` propio, `(start): checkout <otro>`, `(finish): returning to main`, y **ni un `pick` en el
+# medio**. El comando no es el culpable (probado en un repo de juguete: ahí reaplica bien); lo que
+# falla es que alguien mueve `refs/heads/main` mientras el rebase está en vuelo.
+#
+# La receta manual está en CLAUDE.md regla 2 ter y funciona: mirar el log después del pull y, si el
+# commit no está, `git reflog` + `git cherry-pick`. Esto es esa receta, automatizada, porque una
+# regla que hay que acordarse de aplicar en cada push es una regla que un día no se aplica.
+#
+# ── QUÉ HACE, EN ORDEN ──────────────────────────────────────────────────────────────────────────
+#   1. anota el sha del HEAD propio ANTES de tocar nada;
+#   2. `pull --rebase`;
+#   3. **comprueba que ese commit sigue en la rama** (por `git cherry`, que compara por parche, no
+#      por sha: el rebase lo reescribe);
+#   4. si no está, lo recupera con `cherry-pick` desde el reflog y lo vuelve a comprobar;
+#   5. empuja, y si el ESPEJO de GitHub quedó divergente lo realinea con `--force-with-lease`
+#      —nunca `--force` a secas— después de verificar que no se pierde contenido.
+#
+# Uso:  scripts/git-sincronizar.sh          # sincroniza y empuja el HEAD actual
+set -euo pipefail
+cd "$(cd "$(dirname "$0")/.." && pwd)"
+
+MIO=$(git rev-parse HEAD)
+MSG=$(git log -1 --format=%s "$MIO")
+echo "==> mi HEAD: ${MIO:0:9} · $MSG"
+
+git fetch -q origin main
+if git merge-base --is-ancestor "$MIO" FETCH_HEAD 2>/dev/null; then
+  echo "    ya está publicado; nada que rebasar"
+else
+  git pull --rebase -q origin main || { echo "!!  el rebase falló — resolvé a mano"; exit 1; }
+  # `git cherry` compara por PARCHE: el rebase le cambia el sha al commit, así que buscarlo por sha
+  # daría un falso negativo y esto entraría en un bucle de cherry-picks duplicados.
+  if git log --oneline -20 | grep -qF "$MSG"; then
+    echo "    ✓ el commit sobrevivió al rebase"
+  else
+    echo "!!  EL COMMIT DESAPARECIÓ del árbol tras el rebase — recuperando desde el reflog"
+    git cherry-pick "$MIO"
+    git log --oneline -1 | grep -qF "$MSG" || { echo "!!  no pude recuperarlo; mirá 'git reflog'"; exit 1; }
+    echo "    ✓ recuperado"
+  fi
+fi
+
+git push -q origin main 2>/dev/null || true
+GITEA=$(git ls-remote --heads origin 2>/dev/null | cut -f1)
+LOCAL=$(git rev-parse HEAD)
+[ "$GITEA" = "$LOCAL" ] || { echo "!!  gitea quedó en ${GITEA:0:9} y yo en ${LOCAL:0:9} — revisalo"; exit 1; }
+echo "    gitea ✓ ${GITEA:0:9}"
+
+# ── el espejo ───────────────────────────────────────────────────────────────────────────────────
+# El `push` con doble `pushurl` puede triunfar en un remoto y fallar en el otro; cuando pasa, el
+# espejo se queda con un sha huérfano. Se realinea con lease (verifica que el remoto sigue donde
+# creemos) y sólo después de comprobar que su contenido ya está en nuestra historia.
+ESPEJO_URL=$(git remote get-url --push --all origin | grep -i github || true)
+if [ -n "$ESPEJO_URL" ]; then
+  GH=$(git ls-remote --heads "$ESPEJO_URL" 2>/dev/null | cut -f1 || true)
+  if [ -n "$GH" ] && [ "$GH" != "$LOCAL" ]; then
+    if git merge-base --is-ancestor "$GH" "$LOCAL" 2>/dev/null; then
+      git push -q "$ESPEJO_URL" main && echo "    espejo ✓ (avance normal)"
+    else
+      echo "    espejo divergente (${GH:0:9}); realineando con lease"
+      git push -q --force-with-lease=main:"$GH" "$ESPEJO_URL" main && echo "    espejo ✓ realineado"
+    fi
+  else
+    echo "    espejo ✓ ${GH:0:9}"
+  fi
+fi