#!/usr/bin/env bash # git_pull_with_stash — Si el repo tiene cambios, los stashea antes de pullear. # Hace fetch + pull --ff-only. Si hay divergencia, restaura el stash y reporta. # Exit 0 siempre (el caller decide como manejar los errores). git_pull_with_stash() { local repo_dir="${1:-.}" if [[ ! -d "$repo_dir/.git" ]]; then echo "git_pull_with_stash: '$repo_dir' no es un repo git" >&2 return 1 fi local abs_repo abs_repo="$(cd "$repo_dir" && pwd)" local repo_name repo_name="$(basename "$abs_repo")" # Comprobar si hay cambios pendientes local dirty dirty=$(git -C "$abs_repo" status --porcelain | wc -l) local stashed=0 if [[ "$dirty" -gt 0 ]]; then git -C "$abs_repo" stash push \ --include-untracked \ -m "auto-stash before pull" \ >/dev/null 2>&1 || true stashed=1 fi # Fetch origin git -C "$abs_repo" fetch origin >/dev/null 2>&1 || { # Sin remote configurado o sin red — considerar up-to-date if [[ "$stashed" -eq 1 ]]; then git -C "$abs_repo" stash pop >/dev/null 2>&1 || true fi echo "[up-to-date] $repo_name (no remote)" return 0 } # Pull --ff-only local pull_out pull_out=$(git -C "$abs_repo" pull --ff-only 2>&1) local pull_exit=$? if [[ $pull_exit -ne 0 ]]; then # Divergencia — restaurar stash y reportar if [[ "$stashed" -eq 1 ]]; then git -C "$abs_repo" stash pop >/dev/null 2>&1 || true fi echo "[diverged] $repo_name" return 0 fi # Pull exitoso — restaurar stash si habia if [[ "$stashed" -eq 1 ]]; then local pop_out pop_out=$(git -C "$abs_repo" stash pop 2>&1) local pop_exit=$? if [[ $pop_exit -ne 0 ]]; then echo "[stash-conflict] $repo_name" return 0 fi fi # Determinar si se trajo algo nuevo if echo "$pull_out" | grep -q "Already up to date"; then echo "[up-to-date] $repo_name" else local commits commits=$(echo "$pull_out" | grep -c 'Fast-forward\|commit\|Merge' || true) echo "[pulled] $repo_name" fi } if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then git_pull_with_stash "$@" fi