Problemas comunes de Git y cómo solucionarlos
Escribo esto como guía de referencia para mí y para uno que otro tonto como yo.
1. Descartar modificaciones de archivos locales
A veces, la mejor manera de tener una idea de un problema es sumergirse y jugar con el código. Desafortunadamente, los cambios realizados en el proceso a veces resultan ser menos que óptimos, en cuyo caso revertir el archivo a su estado original puede ser la solución más rápida y sencilla:
git checkout -- Gemfile # restablece rutas específicas
git checkout -- lib bin # también funciona con múltiples argumentos
En caso de que se lo pregunte, el doble guión (
--
) es una forma común en que las utilidades de la línea de comandos indican el final de las opciones de comando.2. Deshacer confirmaciones locales
Lamentablemente, a veces nos lleva un poco más de tiempo darnos cuenta de que estamos en el camino equivocado, y para ese momento es posible que uno o más cambios ya se hayan cometido localmente. Esto es cuando
git reset
es útil:git reset HEAD~2 # deshace las dos últimas confirmaciones, mantener los cambios
git reset --hard HEAD~2 # deshace las dos últimas confirmaciones, descarta los cambios
¡Cuidado con la
--hard
opción! Restablece su árbol de trabajo, así como el índice, por lo que todas sus modificaciones se perderán para siempre.3. Elimine un archivo de git sin eliminarlo de su sistema de archivos
Si no tiene cuidado durante a
git add
, puede terminar agregando archivos que no quiere confirmar. Sin embargo, git rm
lo eliminará de su área de almacenamiento, así como de su sistema de archivos, que puede no ser lo que desea. En ese caso, asegúrese de que solo elimine la versión preparada y agregue el archivo a su .gitignore
para evitar cometer el mismo error por segunda vez:git reset filename # eliminar git --archivo archivado
echo filename >> .gitignore # agregue a .gitignore para evitar volver a agregarlo
4. Editar un mensaje de confirmación.
Los errores tipográficos ocurren, pero afortunadamente, en el caso de los mensajes de confirmación, es muy fácil corregirlos:
git commit --amend # iniciar $EDITOR para agregar mensaje
git commit --amend -m "New message" # configure el nuevo mensaje directamente
Pero eso no es todo lo que
git-amend
puedes hacer por ti. ¿Olvidaste agregar un archivo? Solo agrégalo y modifica el commit anterior!git add forgotten_file
git commit --amend
Tenga en cuenta que en
--amend
realidad creará una nueva confirmación que reemplaza a la anterior, así que no la use para modificar confirmaciones que ya se han enviado a un repositorio central. Se puede hacer una excepción a esta regla si está absolutamente seguro de que ningún otro desarrollador ya ha revisado la versión anterior y ha basado su propio trabajo en ella, en cuyo caso, un empuje forzado ( git push --force
) todavía puede estar bien. La --force
opción es necesaria aquí ya que el historial del árbol se modificó localmente, lo que significa que el servidor remoto rechazará la inserción, ya que no es posible una combinación de avance rápido.5. Limpiar los compromisos locales antes de empujar
Si bien
--amend
es muy útil, no ayuda si la confirmación que desea volver a redactar no es la última. En ese caso, una rebase interactiva es útil:git rebase --interactive
# si no se ha especificado ninguna información de seguimiento para esta rama
# tendrás que agregar upstream y remote branch a la información:
git rebase --interactive origin branch
Esto abrirá su editor configurado y le presentará el siguiente menú:
pick 8a20121 Upgrade Ruby version to 2.1.3
pick 22dcc45 Add some fancy library
# Rebase fcb7d7c..22dcc45 onto fcb7d7c
#
# Commands: # p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
En la parte superior verá una lista de confirmaciones locales, seguida de una explicación de los comandos disponibles. Simplemente seleccione los compromisos que desea actualizar, cambie
pick
a reword
(o r
para abreviar), y se lo llevará a una nueva vista donde puede editar el mensaje.
Sin embargo, como puede verse en la lista anterior, las reorganizaciones interactivas ofrecen mucho más que la simple edición de mensajes de confirmación: puede eliminar completamente las confirmaciones eliminandolas de la lista, así como editarlas, reordenarlas y eliminarlas. Squashing te permite unir varias confirmaciones en una, lo cual es algo que me gusta hacer en las ramas de características antes de empujarlas hacia el control remoto. ¡No más las confirmaciones de "Agregar archivo olvidado" y "Reparar error tipográfico" grabadas por toda la eternidad!
6. Revertir cometidos empujados
A pesar de las correcciones demostradas en los consejos anteriores, las confirmaciones defectuosas se convierten ocasionalmente en el repositorio central. Aún así, esta no es razón para desesperarse, ya que
git
ofrece una manera fácil de revertir los compromisos simples o múltiples: git revert c761f5c # revierte la confirmación con el id especificado
git revert HEAD^ # revierte el segundo commit
git revert develop~4..develop~2 # revierte toda una gama de commits
En caso de que no desee crear confirmaciones de reversión adicionales pero solo aplique los cambios necesarios a su árbol de trabajo, puede usar la opción
--no-commit
/ -n
.# deshace el ultimo commit, pero no crea un revertido commit
git revert -n HEAD
La página de manual
man 1 git-revert
contiene más opciones y proporciona algunos ejemplos adicionales.7. Evite los conflictos de fusión repetidos
Como todos los desarrolladores saben, arreglar conflictos de combinación puede ser tedioso, pero resolver el mismo conflicto repetidamente (por ejemplo, en ramas de características de larga ejecución) es francamente molesto. Si sufrió esto en el pasado, le complacerá conocer la función de resolución grabada de reutilización infrautilizada. Agréguese a su configuración global para habilitarlo para todos los proyectos:
git config --global rerere.enabled true
Alternativamente, puede habilitarlo por proyecto creando manualmente el directorio
.git/rr-cache
.
Esto seguro no es una característica para todos, pero para las personas que lo necesitan, puede ser un ahorro de tiempo real. Imagina que tu equipo está trabajando en varias ramas de características al mismo tiempo. Ahora desea fusionarlos todos juntos en una rama comprobable de prelanzamiento. Como era de esperar, hay varios conflictos de fusión, que usted resuelve. Lamentablemente, resulta que una de las sucursales aún no está allí, por lo que decide desarmar nuevamente. Varios días (o semanas) más tarde, cuando la rama finalmente esté lista, la fusionaras nuevamente, pero gracias a las resoluciones registradas, no tendrás que volver a resolver los mismos conflictos de combinación.
La página del manual (
man git-rerere
) tiene más información sobre otros casos de uso y comandos ( git rerere status
, git rerere diff
, etc.).8. Encuentra el compromiso que rompió algo después de una fusión
El seguimiento de la confirmación que introdujo un error después de una gran fusión puede llevar bastante tiempo. Afortunadamente
git
ofrece una gran facilidad de búsqueda binaria en la forma de git-bisect
. Primero tienes que realizar la configuración inicial: git bisect start # inicia la sesión de bisecting
git bisect bad # marca la revisión actual como mala
git bisect good revision # marca la revisión actual como buena
Después de esto, git comprobará automáticamente una revisión a mitad de camino entre las versiones "buenas" y "malas" conocidas. Ahora puede ejecutar sus especificaciones nuevamente y marcar la confirmación como "buena" o "mala" en consecuencia.
git bisect good # o git bisec malo
Este proceso continúa hasta que llegue a la confirmación que introdujo el error.
9. Evita los errores comunes con los ganchos git.
Algunos errores ocurren repetidamente, pero serían fáciles de evitar ejecutando ciertas comprobaciones o tareas de limpieza en una etapa definida del
git
f lujo de trabajo. Este es exactamente el escenario para el que fueron diseñados los ganchos. Para crear un nuevo gancho, agregue un archivo ejecutable a .git/hooks
. El nombre del script debe corresponder a uno de los ganchos disponibles, una lista completa de los cuales está disponible en la página del manual ( man githooks
). También puede definir enlaces globales para usar en todos sus proyectos creando un directorio de plantillas que git utilizará al inicializar un nuevo repositorio (consulte man git-init para obtener más información). Así es como se ~/.gitconfig
ve la entrada relevante en un directorio de plantilla de ejemplo:[init]
templatedir = ~/.git_template
→ tree .git_template
.git_template
└── hooks
└── pre-commit
Cuando inicie un nuevo repositorio, los archivos en el directorio de plantillas se copiarán a la ubicación correspondiente en el
.git
directorio de su proyecto .
Lo que sigue es un
commit-msg
gancho de ejemplo ligeramente artificial , que asegurará que cada mensaje de confirmación haga referencia a un número de ticket como " #123
".ruby
#!/usr/bin/env ruby
message = File.read(ARGV[0])
unless message =~ /\s*#\d+/
puts "[POLICY] Your message did not reference a ticket."
exit 1
end
10. Cuando todo lo demás falla
Hasta ahora hemos cubierto bastante terreno sobre cómo corregir errores comunes al trabajar con
git
. La mayoría de ellos tienen soluciones bastante fáciles, sin embargo, hay veces en que uno tiene que sacar las armas grandes y volver a escribir la historia de una rama completa. Un caso de uso común para esto es la eliminación de datos confidenciales (por ejemplo, credenciales de inicio de sesión para sistemas de producción) que se confirmaron en un repositorio público:git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch secrets.txt' \
--prune-empty --tag-name-filter cat -- --all
Esto eliminará el archivo
secrets.txt
de cada rama y etiqueta. También eliminará cualquier confirmación que esté vacía como resultado de la operación anterior. Tenga en cuenta que esto reescribirá todo el historial de su proyecto, lo que puede ser muy perjudicial en un flujo de trabajo distribuido. Además, mientras que el archivo en cuestión ahora se ha eliminado, las credenciales que contenía deben considerarse comprometidas.
No hay comentarios.: