#!/bin/sh
# Contrôle de la base d'une branche, avant envoi (hook pre-push) et en CI.
#
# Les MR sont fusionnées en squash : GitLab remplace les commits de la branche
# par un nouveau commit sur master. Une branche créée depuis une autre branche
# de fonctionnalité, au lieu d'origin/master, transporte alors une copie du
# travail déjà fusionné : conflit assuré sur sa MR (cas de !63, partie de
# feat/caisse-hors-ligne après le squash de !62).
#
# Refuse :
#   1. un commit dont le contenu est déjà dans la base (squash d'une MR passée) ;
#   2. un commit qui appartient aussi à une autre branche distante (branche
#      empilée), sauf ALLOW_STACKED=1 quand c'est voulu.
#
# Usage : check-branch-base.sh [base] [tête] [nom de la branche]
# Correction : git rebase --onto origin/master <dernier commit étranger> <branche>

set -eu

base="${1:-origin/master}"
head="${2:-HEAD}"
branch="${3:-$(git rev-parse --abbrev-ref HEAD)}"

commits=$(git rev-list --no-merges "$base..$head")
[ -z "$commits" ] && exit 0

tmp_index=$(mktemp)
trap 'rm -f "$tmp_index"' EXIT INT TERM

failed=0
for commit in $commits; do
    label=$(git log -1 --format='%h %s' "$commit")

    # 1. Le patch inverse s'applique sur la base : la base contient déjà ce changement.
    GIT_INDEX_FILE="$tmp_index" git read-tree "$base"
    if git diff --binary "$commit^" "$commit" | GIT_INDEX_FILE="$tmp_index" git apply --cached --check -R 2>/dev/null; then
        echo "✗ $label : déjà présent dans $base (MR fusionnée en squash)."
        failed=1
        continue
    fi

    # 2. Le commit appartient aussi à une autre branche distante.
    if [ "${ALLOW_STACKED:-0}" != "1" ]; then
        others=$(git branch -r --contains "$commit" --format='%(refname:short)' \
            | grep -v -x -e "$base" -e "origin/HEAD" -e "origin" -e "origin/$branch" || true)
        if [ -n "$others" ]; then
            echo "✗ $label : appartient aussi à $(echo "$others" | tr '\n' ' ')(branche empilée)."
            failed=1
        fi
    fi
done

if [ "$failed" = "1" ]; then
    echo ""
    echo "La branche « $branch » doit partir de $base à jour :"
    echo "  git fetch origin && git rebase --onto $base <dernier commit étranger> $branch"
    echo "Pour une branche volontairement empilée : ALLOW_STACKED=1 git push ..."
    exit 1
fi
