Header Ads

git filter-branch: A rey muerto rey puesto

Si queríamos eliminar archivos grandes de un repositorio de github o similar y de paso hacer limpieza, con los siguientes comandos lo hacíamos:
#!/bin/bash
bigfile="bigfile.tar.gz"
project="/path_to_mygitproject/"
cd $project
git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch '"$bigfile"'' --prune-empty --tag-name-filter cat -- --all
git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch '"$bigfile"'' HEAD
git clean -nd
git clean -fd
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now --aggressive
O también podríamos limpiar la basura con el script git-gc-all; en fin, sin importar el método que use para limpiar su repositorio, si involucra el comando  git filter-branch sepa que llegó a su fin y al ejecutarlo arroja el siguiente mensaje:
WARNING: git-filter-branch has a glut of gotchas generating mangled history
     rewrites.  Hit Ctrl-C before proceeding to abort, then use an
     alternative filtering tool such as 'git filter-repo'
     (https://github.com/newren/git-filter-repo/) instead.  See the
     filter-branch manual page for more details; to squelch this warning,
     set FILTER_BRANCH_SQUELCH_WARNING=1.
Para solucionarlo, algunos optan por el proyecto  BFG Repo-Cleaner, pero lo que se recomienda en el mensaje anterior es el proyecto  git-filter-repo.
Para usarlo, descargamos el script en python:
echo $PATH
/home/user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
wget https://raw.githubusercontent.com/newren/git-filter-repo/master/git-filter-repo -O /home/user/.local/bin/git-filter-repo
chmod +x /home/user/.local/bin/git-filter-repo
Según la documentacióngit filter-repo simplifica todo, por ejemplo, estos comandos para eliminar archivos:
git filter-branch --tree-filter 'rm filename' HEAD
git filter-branch --tree-filter 'rm -f filename' HEAD
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
Se convierten en uno solo:
git filter-repo --invert-paths --path filename
Y para nuestro ejemplo sería así:
git filter-repo --force --path /path_to_mygitproject/bigfile.tar.gz --invert-paths
clean git repo
Eso reemplazaría las dos primeras líneas del script bash. Pero si quiere eliminar cualquier archivo de su repositorio, por ejemplo que tenga más de 10 M, entonces con este:
git filter-repo --force --strip-blobs-bigger-than 10M
Como vemos es mucho más simple. Para mayor información sobre otros comandos pulse AQUI
source

Actualización 2023
Algunos comandos cambiaron. Ahora para trabajar con filter-repo hay que instalarlo. 
En Ubuntu 22.04 es:
sudo apt install git-filter-repo
Y se reemplaza:
git filter-repo
Por:
git-filter-repo
Otra cosa que cambió es que gitlab ya no permite hacer pull para hacer mirror de github a gitlab en cuentas gratis (solo lo permite en premium y no sabemos si lo contrario también). 
En este caso, hay un workaround. Ejecute lo siguiente: (asumiendo que tiene un repositorio en github y gitlab con el mismo nombre, reemplace foo por el nombre de su repo)
cd foo
git remote add backup https://gitlab.com/myuser/foo.git # solamente una vez
git push -f backup master
Y a partir de ahora puede usar el siguiente script para actualizar su repo en ambos lados:
#!/bin/bash
# date
now="$(date +'%m/%d/%Y')"
while true; do
    read -p "Do you want to update-backup your repo? (y/n)" answer
        case $answer in
          [Yy]* )
        # execute command yes
    cd foo
    git add .
    git commit -m "Update $now" # Modify it according to your needs 
    git push -f origin master
    git push -f backup master
    cd -
    echo OK
            break;;
            [Nn]* )
        # execute command no
            break;;
        * ) echo; echo "Please answer YES (y) or NO (n).";;
    esac
done
Con la tecnología de Blogger.