HOWTO · Git
Solucionar problemas de error de parche de Git
Este artículo analiza cómo solucionar algunos errores comunes asociados con la aplicación de parches de git.
En esta página
Un parche de Git suele fallar porque el comando no corresponde a su formato, el repositorio parte de una base distinta de la que espera el parche o el contexto del parche ha cambiado. Identifica si se trata de un parche de correo o de un diff, inspecciona la rama de destino y el árbol de trabajo, y comprueba si puede aplicarse antes de elegir un método de recuperación. git apply procesa parches diff; git am procesa parches de correo y crea commits.
Identificar el tipo de parche y el comando de Git que se debe usar
Un parche diff simple suele contener líneas diff --git y fragmentos de archivo que empiezan con @@. Aplícalo al árbol de trabajo con git apply. Un parche creado con git format-patch es un mensaje de correo con metadatos del commit y normalmente se aplica con git am; este comando conserva el autor y el mensaje del commit al crear un commit. Los dos comandos no son intercambiables. Si no está claro el formato del archivo, examina sus primeras líneas con head y busca encabezados de correo y metadatos del commit antes de aplicarlo.
Si ya hay una operación am en curso, consulta git status antes de continuar. git am --continue sigue después de resolver el parche de correo actual; git am --abort detiene la operación y restaura el estado que tenía antes de iniciarla. git am --skip omite el parche de correo actual, así que úsalo solo si quieres descartarlo deliberadamente. Por lo general, no sirve para ignorar un error de índice de git apply.
Comprobar el repositorio y el parche antes de aplicarlo
Empieza con git status --short --branch y git branch --show-current. Confirma que la rama actual sea la de destino prevista y toma nota de todos los cambios rastreados, preparados y sin rastrear. No cambies de rama si podrías sobrescribir cambios locales; primero decide cómo conservarlos, por ejemplo, mediante un commit o guardándolos de forma segura con stash. Un parche creado para otro commit quizá no encaje con la rama actual, aunque ambas ramas contengan los mismos archivos.
Inspecciona el parche antes de ejecutarlo. Para inspeccionar el archivo del parche, git diff --stat -- my_patch.patch no es el comando adecuado; usa head, less o git apply --stat my_patch.patch para ver su contenido o las rutas afectadas. Después ejecuta git apply --check my_patch.patch. Esto comprueba si el diff puede aplicarse sin modificar archivos. No verifica que el cambio del parche sea el que necesitas ni que las ediciones posteriores sean correctas. Si es un parche de correo, inspecciona el mensaje y sigue el flujo correspondiente de git am en vez de tratarlo como un diff simple.
Ejecuta este ejemplo autocontenido en una shell con Git instalado. Crea un repositorio temporal, genera un diff, restaura el archivo original y aplica el diff sobre la misma base:
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
set -eu
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
repo="$tmp/repo"
mkdir "$repo"
git -C "$repo" init -q
git -C "$repo" config user.name Example
git -C "$repo" config user.email example@example.com
printf 'first line
' > "$repo/note.txt"
git -C "$repo" add note.txt
git -C "$repo" commit -qm 'Add note'
printf 'first line
second line
' > "$repo/note.txt"
git -C "$repo" diff > "$tmp/change.patch"
git -C "$repo" checkout -- note.txt
git -C "$repo" apply --check "$tmp/change.patch"
git -C "$repo" apply "$tmp/change.patch"
printf 'Applied content: '
cat "$repo/note.txt"
El git apply --check del ejemplo es una comprobación previa; el git apply que viene después realiza el cambio. En tu repositorio, sustituye la ruta del diff generado por la ruta del parche recibido y vuelve a inspeccionar git status antes de preparar cualquier cambio.
Diagnosticar errores comunes de parches de Git
Ante patch does not apply o un fragmento que falla, Git no pudo encontrar el contexto esperado en el archivo de destino. El parche puede proceder de otro commit, puede que se hayan editado las líneas pertinentes o puede haber diferencias de espacios en blanco. Compara las líneas alrededor del fragmento con el archivo actual y confirma cuál es la base prevista. Opciones de espacios en blanco como --ignore-space-change o --ignore-whitespace pueden ayudar si la única diferencia son los espacios; no resuelven cambios en la lógica, archivos ausentes ni conflictos de contenido no relacionados.
El mensaje file already exists in index señala una colisión en el índice o en la ruta, pero el mensaje por sí solo no explica por qué el parche la encontró. Comprueba git status, inspecciona la ruta indicada con git ls-files --stage -- path/to/file y lee el fragmento del parche. Averigua si el cambio ya está preparado, si el parche intenta agregar una ruta que ya está rastreada o si se creó para una base de repositorio distinta. No restablezcas el índice ni elimines el archivo hasta saber qué estado necesitas conservar.
El mensaje error in file también es demasiado general para identificar por sí solo la causa. Lee el resto de la salida de Git, inspecciona el archivo indicado y el fragmento pertinente del parche, y comprueba si la ruta del archivo existe con la ortografía y las mayúsculas esperadas. Elige una corrección basándote en los detalles más específicos del fallo, sin dar por hecho que el parche está dañado.
Elegir un método de recuperación para un parche fallido
Si git apply --check informa de que el contexto no coincide, primero aclara cuál es la base de destino correcta. Quizá necesites la rama o el commit adecuados, o quizá tengas que adaptar manualmente el parche al archivo actual. No cambies de rama a ciegas: revisa los cambios locales y consérvalos antes de cambiar el destino. Vuelve a ejecutar la comprobación después de preparar la base prevista.
Si algunos fragmentos son independientes y quieres que Git aplique los que pueda, git apply --reject my_patch.patch aplica los fragmentos que coinciden y escribe los rechazados en archivos .rej. La aplicación es parcial: inspecciona cada archivo de origen afectado y cada archivo .rej, y luego incorpora o descarta manualmente cada cambio rechazado. El comando no resuelve el contenido rechazado ni completa el parche en su conjunto. Si quieres que el intento se aplique íntegramente o no se aplique, usa el git apply normal después de que la comprobación termine correctamente.
Para los parches que contienen información de base aprovechable, git apply --3way my_patch.patch le pide a Git que use una combinación de tres vías. Los objetos base necesarios deben estar disponibles; de lo contrario, el comando puede fallar. Incluso si el intento de tres vías se realiza correctamente, puede dejar marcadores de conflicto que habrá que resolver manualmente. Es una opción cuando el contexto ha cambiado, no una solución universal. Las opciones de espacios en blanco son independientes: úsalas solo cuando la inspección indique que el obstáculo son diferencias de espacios.
Resolver conflictos y verificar el resultado
Después de cualquier recuperación, inspecciona git status --short y git diff -- para ver los archivos modificados y el contenido que aún no está preparado. Si aplicaste el parche con --reject, localiza los archivos .rej y compara cada fragmento rechazado con el código fuente actual. Si una aplicación de tres vías dejó conflictos, busca los marcadores, edita cada archivo para obtener el contenido final previsto y comprueba que no quede ningún marcador. Si se trata de una operación de parche de correo, sigue el estado de git am que muestra git status y continúa o cancélala según corresponda.
Antes de preparar cambios, revisa el diff completo con git diff --check para detectar problemas de espacios en blanco y con git diff para inspeccionar las ediciones. Si ya había cambios preparados, inspecciónalos también con git diff --cached. Confirma que los archivos resultantes contengan los cambios previstos y que se conserven los cambios locales no relacionados. Decide si vas a preparar o confirmar los cambios solo después de revisarlos. git log puede confirmar los commits nuevos creados por git am, pero no muestra todos los cambios del árbol de trabajo; usa también la salida de status y diff para verificar el resultado completo.