#!/usr/bin/env bash # git_push_if_ahead — Decide si pushear un repo git sin tocar la red para decidir. # Usa refs locales (rev-list) para determinar si hay commits por enviar. # Stdout: linea de estado con [push|push -u|skip|error]. git_push_if_ahead() { local repo_dir="${1:-.}" if [[ ! -d "$repo_dir/.git" ]]; then echo "git_push_if_ahead: '$repo_dir' no es un repo git" >&2 return 1 fi local abs_repo abs_repo="$(cd "$repo_dir" && pwd)" # Nombre corto para display (basename del path) local repo_name repo_name="$(basename "$abs_repo")" # Rama actual local branch branch=$(git -C "$abs_repo" rev-parse --abbrev-ref HEAD 2>/dev/null) if [[ -z "$branch" || "$branch" == "HEAD" ]]; then echo "[error] $repo_name: no se puede determinar la rama actual" return 0 fi # Comprobar si existe upstream configurado local upstream upstream=$(git -C "$abs_repo" rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || true) if [[ -z "$upstream" ]]; then # Sin upstream: push -u para establecer tracking echo "[push -u] $repo_name ($branch)" >&2 local push_out push_out=$(git -C "$abs_repo" push -u origin "$branch" 2>&1) || { echo "[error] $repo_name: $push_out" return 0 } echo "$push_out" | tail -3 >&2 echo "[push -u] $repo_name ($branch)" return 0 fi # Contar commits locales que no estan en upstream (sin red) local ahead ahead=$(git -C "$abs_repo" rev-list --count '@{u}..HEAD' 2>/dev/null || echo "0") if [[ "${ahead:-0}" -gt 0 ]]; then echo "[push] $repo_name ($branch, $ahead commits ahead)" >&2 local push_out push_out=$(git -C "$abs_repo" push origin "$branch" 2>&1) || { # Preservar las lineas con los keywords que el orquestador usa para # decidir el auto-recover (rejected / fast-forward / non-fast-forward). # Un `tail -1` plano se quedaba con la linea final de `hint:` y perdia # "[rejected]" + "Updates were rejected", impidiendo el recover. local reason reason=$(echo "$push_out" | grep -iE 'rejected|fast-forward|denied|permission|error:' | head -3 | tr '\n' ' ') [[ -z "$reason" ]] && reason=$(echo "$push_out" | tail -1) echo "[error] $repo_name: $reason" return 0 } echo "$push_out" | tail -3 >&2 echo "[push] $repo_name ($branch, $ahead commits ahead)" else echo "[skip] $repo_name (up-to-date)" fi } if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then git_push_if_ahead "$@" fi