Editar la historia sin reescribirla
A veces quieres empalmar historias (un import de Subversion convertido encontrándose con una continuación, por ejemplo) sin reescribir commits. Los grafts y el namespace refs/replace/ le permiten a Git fingir que el padre de un commit es un commit diferente, dejando los objetos originales intactos.
Grafts (legacy)
.git/info/grafts es un archivo de texto plano: cada línea especifica los padres de un commit. Los grafts están obsoletos en favor de replace refs porque son solo locales y confusos.
# .git/info/grafts
<child-sha> <new-parent-sha>
Replace refs
Las replace refs son refs reales bajo refs/replace/. Mapean un SHA "original" a un SHA de "reemplazo". A diferencia de los grafts, pueden ser pushed y compartidas.
git replace --graft <child> <new-parent>
git replace --graft v3.0.0 v2.99.0
git replace --convert-graft-file
git replace -d <sha>
git replace -l
Caso de uso: empalmar imports
git replace --graft $(git rev-list --max-parents=0 main | head -1) svn-history-tip
Compartir
git push origin 'refs/replace/*:refs/replace/*'
Deshabilitar temporalmente
git --no-replace-objects log
GIT_NO_REPLACE_OBJECTS=1 git log
Errores comunes
Confundir replace con reescritura — replace no cambia los SHAs de objetos, así que las firmas siguen siendo válidas pero el padre "real" de un commit no es lo que ves.