Hoja de trucos de Git [PDF]
(wizardzines.com)- Un PDF que organiza las tareas en las que uno suele atorarse en Git para poder consultar rápido creación de commits, cambio de ramas, comparación de cambios, sincronización remota y comandos para deshacer cambios
- El flujo de trabajo local se centra en
git status,git add,git commitygit diff, y muestra cómo revisar el estado antes y después del staging para crear commits - El trabajo con ramas usa
git switch,git checkout,git branch,git merge,git rebaseygit cherry-pickpara crear, moverse, fusionar y reubicar cambios - La exploración del historial y la recuperación incluyen
git log,git blame,git show,git reflog,git resetygit restore, y también se pueden usar ramas, tags,HEADy ramas remotas como referencias de commits - Las operaciones con repositorios remotos cubren
git remote add,git fetch,git pull,git push,git push --force-with-leaseygit push --tagspara traer y enviar cambios
Iniciar un repositorio y revisar el estado actual
- Iniciar un repositorio nuevo:
git init
- Clonar un repositorio existente:
git clone $URL
- Revisar la ubicación y el estado actual:
git status
Preparar y crear commits
- Agregar archivos no rastreados:
git add $FILE
- Agregar todos los archivos no rastreados y los cambios sin staging:
git add .
- Hacer staging solo de algunas partes de los cambios de un archivo:
git add -p
- Eliminar o mover un archivo:
git rm $FILEgit mv $OLD $NEW
- Excluir un archivo del seguimiento de Git sin borrarlo:
git rm --cached $FILE
- Cancelar todo el staging:
git reset HEAD
- Crear un commit:
git commit- abre un editor de texto para escribir el mensaje
- Hacer un commit indicando el mensaje directamente:
git commit -m 'message'
- Hacer un commit con mensaje incluyendo también los cambios sin staging:
git commit -am 'message'
Moverse entre ramas y administrarlas
- Cambiar de rama:
git checkout $NAMEgit switch $NAME
- Crear una rama:
git checkout -b $NAMEgit switch -c $NAME
- Ver la lista de ramas:
git branch
- Ordenar ramas según el commit más reciente:
git branch --sort=-committerdate
- Eliminar una rama:
git branch -d $NAME
- Forzar la eliminación de una rama:
git branch -D $NAME
Explorar el historial y rastrear código
- Ver el historial de una rama:
git log main
- Ver en gráfico la relación entre dos ramas:
git log --graph a b
- Ver el log en una sola línea:
git log --oneline
- Ver quién modificó por última vez cada línea de un archivo:
git blame $FILENAME
- Ver todos los commits que modificaron un archivo:
git log $FILENAME
- Buscar commits que agregaron o eliminaron un texto específico:
git log -S banana
Comparar cambios
- Ver la diferencia entre un commit y su commit padre:
git show $COMMIT_ID
- Ver la diferencia entre un merge commit y los padres que fusionó:
git show --remerge-diff $COMMIT_ID
- Ver un resumen del diff:
git diff $COMMIT_ID --statgit show $COMMIT_ID --stat
- Comparar dos commits:
git diff $COMMIT_ID $COMMIT_ID
- Comparar solo un archivo con un commit específico:
git diff $COMMIT_ID $FILENAME
- Comparar todos los cambios en staging y sin staging:
git diff HEAD
- Comparar solo los cambios en staging:
git diff --staged
- Comparar solo los cambios sin staging:
git diff
Archivos de configuración y opciones
- Archivo de configuración local de Git:
.git/config
- Archivo de configuración global de Git:
~/.gitconfig
- Lista de archivos a ignorar:
.gitignore
- Definir una opción de configuración:
git config user.name 'Julia'
- Definir una opción global:
git config --global ...
- Agregar un alias:
git config alias.st status
- Ver las opciones de configuración disponibles:
man git-config
Modificar historial y restaurar archivos
- Deshacer el commit más reciente y mantener intacto el directorio de trabajo:
git reset HEAD^
- Deshacer un rebase fallido:
git reflog BRANCHNAMEgit reset --hard $COMMIT_ID
- Combinar los últimos 5 commits en uno solo:
git rebase -i HEAD^^^^^^- cambia
pickporfixupen los commits que quieras combinar
- Traer la versión de un archivo desde otra rama o commit:
git checkout $COMMIT_ID $FILEgit restore $FILE --source $COMMIT_ID
- Cambiar el mensaje de un commit o agregar un archivo que faltó:
git commit --amend
Fusionar ramas
- Fast-forward merge para actualizar la rama actual con otra rama:
git switch maingit merge banana
- Copiar un commit a otra rama:
git cherry-pick $COMMIT_ID
- Unir ramas divergentes con rebase:
git switch bananagit rebase main
- Unir ramas divergentes con merge:
git switch maingit merge bananagit commit
- Unir ramas divergentes con squash merge:
git switch maingit merge --squash bananagit commit
Repositorios remotos y sincronización
- Agregar un repositorio remoto:
git remote add $NAME $URL
- Hacer push de la rama
mainal remotoorigin:git push origin main
- Subir por primera vez una rama a
originy configurar la rama de seguimiento:git push -u origin $NAME
- Hacer push de la rama actual a su rama remota de seguimiento:
git push
- Force push:
git push --force-with-lease
- Hacer push de tags:
git push --tags
- Traer cambios sin modificar la rama local:
git fetch origin main
- Hacer fetch de todas las ramas:
git fetch --all
- Hacer rebase sobre la rama actual después de fetch:
git pull --rebase
- Hacer merge sobre la rama actual después de fetch:
git pull origin maingit pull
Formas de referirse a un commit
- En lugar de
$COMMIT_ID, se pueden usar varias referencias:- rama:
main - tag:
v0.1 - ID de commit:
3e887ab - rama remota:
origin/main - commit actual:
HEAD - commit de hace 3 commits:
HEAD^^^ - commit de hace 3 commits:
HEAD~3
- rama:
Descartar cambios
- Eliminar de un archivo tanto los cambios en staging como los cambios sin staging:
git checkout HEAD $FILE
- Eliminar de un archivo los cambios sin staging:
git checkout $FILE
- Eliminar todos los cambios en staging y sin staging:
git reset --hard
- Guardar en stash los cambios en staging y sin staging:
git stash
- Eliminar archivos no rastreados:
git clean
1 comentarios
Comentarios de Hacker News
Hay varios comandos que son joyitas ocultas:
git diff --stagedmuestra la diferencia entre el último commit y lo que tienes en staging ahora, así que sirve para verificar que solo entre lo que querías al subir archivos o hunks de forma detalladagit log <file>muestra solo los commits en los que cambió ese archivo, así que reduce la necesidad de revisar todo elgit log, y es especialmente útil en archivos que no cambian seguidoSi usas
git add --patchy quieres elegir con más detalle que los hunks en que Git divide los cambios, vale la pena probar la opcióne. Te indica cómo incluir o excluir líneas individuales, así que no hace falta memorizarlogit diff --stagedes un alias degit diff --cached. Llevo años usandocached, perostagedsí se siente mucho más intuitivo. Aunque no sé si podré borrar esa memoria muscularSi te interesa, puedes ver o sugerir alias aquí: https://gitlab.com/Falimonda/gitrc
git config --global commit.verbose true, Git agrega automáticamente la diferencia en staging en el área de comentarios del editor de mensajes de commitUno de mis comandos favoritos que no aparece en la lista es
git log -LstartLine,endLine:fileNameEs como un
git blameextendido: muestra cómo cambiaron con el tiempo las líneas indicadas y quién las cambió. Hace seguimiento incluso si cambian los números de línea o si el archivo se mueveResponde preguntas como “¿quién hizo esto, cuándo y por qué?” o “¿desde cuándo está así?”
Me recordó la frase de Phil Karlton: “Solo hay dos cosas difíciles en ciencias de la computación: invalidación de caché y poner nombres.”
Desde esa perspectiva, que un comando de Git se llame
blamesiempre me ha parecido bastante raro, y no soy el único que lo pensóWhat does 'git blame' do? https://stackoverflow.com/questions/31203001/what-does-git-blame-do
Blame someone else for your bad code https://news.ycombinator.com/item?id=27963868
Git blame should be called git credit https://dev.to/damcosset/git-blame-should-be-called-git-credit-27h5
Does Git Blame sound too negative? https://www.reddit.com/r/ProgrammerHumor/comments/r5lzyo/does_git_blame_sound_too_negative_just_look_up/
git,blamesuena como un nombre acorde a la marcablameawhoen mi configuración. De hecho, como soy usuario hardcore de Vim, simplemente usowMe gustó la forma en que aprendió Git. Al principio empecé con Sourcetree, una GUI de Git de terceros, y era muy fácil de usar y entender
Luego pasé a
git gui, aunque esta etapa se puede saltar. Después me empezó a dar flojera abrir una UI y aprendí los comandos de terminalLo recomiendo a quienes empiezan con Git, aunque claro, esa es solo mi experiencia n=1
clone,pull,commitypush, y hasta ahora con eso me ha bastado. Git puede ser así de simple. Claro, si hace falta también puedes aprender usos más complejosEn el momento en que empecé a usar Magit, Git empezó a tener sentido para mí
Solo tengo cosas buenas que decir de Sublime Merge
Se preguntan si hay una razón histórica por la que Git es innecesariamente complejo.
Viendo esta chuleta, esa complejidad se siente todavía más real.
Que se haya usado tan ampliamente puede haber sido un “accidente feliz”, o quizá una desgracia. GitHub tuvo mucho mérito al popularizar Git como “hosting gratuito de Git”, pero no creo que Git sea el sistema de control de versiones ideal para muchos proyectos.
Como fue hecho para Linus y para Linux, a veces la terminología y el flujo de trabajo se sienten invertidos frente a los sistemas de control de versiones más comunes. Incluso el nombre
Pull Requestviene de que, en el desarrollo de Linux, Linus o un mantenedor “jalan” los cambios hacia el árbol del kernel. En otros sistemas normalmente se le llamaMerge Request, lo cual es mucho más lógico en el sentido de que integra al árbol cambios vengan de donde vengan.Git era prácticamente el único sistema de control de versiones distribuido de código abierto que podía manejar bases de código gigantes con rapidez, y por eso también ganó inercia en las grandes empresas.
Para proyectos personales prefiero mucho más Mercurial y de hecho lo uso, pero si pruebas Hg en una base de código grande como Android AOSP, se pone terriblemente lento. Mercurial tiene una mejor interfaz de usuario y un mejor sistema de comandos, e incluso puede levantar un servidor web al vuelo para ver el árbol de cambios, pero al estar escrito en Python no es ideal en rendimiento ni escalabilidad.
git checkout, y eso volvió más confusa la experiencia de usuario.En el Git moderno, el costo de agregar subcomandos nuevos bajó, y empezaron a aparecer comandos más específicos como
git switch.log,add,commit,pullypush. También hay herramientas con GUI.Sinceramente, no creo que Git sea tan complejo para el trabajo común. Más bien tiene muchas funciones potentes disponibles cuando las necesitas.
Los desarrolladores del kernel tenían que comunicarse entre sí de forma descentralizada y volver a trabajar sobre el trabajo de otros. ¿Cómo trabajas en un proyecto donde 15,000 personas escriben código? Git fue creado para ese propósito.
Es tan complejo como necesita serlo para soportar el flujo de trabajo para el que fue diseñado. Hacer una herramienta más simple es fácil, pero entonces no podría soportar flujos complejos como el desarrollo del kernel de Linux. Así que no es innecesariamente complejo, aunque sí es más complejo de lo necesario para usos simples.
Si necesitas un frontend menos complejo, hay muchas herramientas que facilitan usar Git. Si no eres desarrollador de software de tiempo completo, no te recomendaría usar Git directamente. Pero si sí lo eres, vale la pena dedicar tiempo a entender los conceptos internos, y una vez que lo entiendes, Git es bastante elegante para lo que hace.
No diría que conocer Git determina si calificas como desarrollador de software o no, pero si entender por tu cuenta cómo funciona este tipo de sistema básico no te produce nada de dopamina, quizá esta área no va contigo. Y no pasa nada: no todo es para todo el mundo.
Para aprender a moverte en Git, recomiendo https://learngitbranching.js.org. Claro, también aplica https://xkcd.com/1597/.
No conocía
git add -py de verdad es muy útil.-p,--patchte permite elegir de forma interactiva los hunks del parche entre el índice y el árbol de trabajo para agregarlos al índice. Te da la oportunidad de revisar las diferencias antes de añadir los cambios al índice.Algo que quisiera agregar aquí es la combinación de
git commit --fixup $COMMIT_IDygit rebase -i upstream/master --autosquash.Se volvió una pieza esencial de mi flujo de trabajo reciente. En el ejemplo de Julia usan
HEAD^^^^^para rebasear los 5 commits anteriores, pero yo hasta hace poco usabaHEAD~5. Ahora me enteré de que simplemente puedes rebasear todos los commits hasta elHEADde upstream.git commit --fixup $COMMIT_IDlo tengo que adoptar de inmediato. Yo siempre hacía pequeños commits de corrección tipo “oops GET users/me”, y luego en el siguiente rebase interactivo los movía manualmente para hacerles fixup, pero esta forma es mucho mejor.“Combinar los últimos 5 commits en uno:
git rebase -i HEAD^^^^^^” me parece que debería sergit rebase -i HEAD~5.Asumiendo, claro, que lo que quieres rebasear es solo un historial lineal.
https://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git
La revelación más grande fue entender que todos los commits siguen ahí dentro. Las etiquetas y las ramas solo apuntan a commits, y los commits a los que una rama apuntaba antes no desaparecen
Muchos comandos, probablemente casi todos, son no destructivos, así que es fácil referenciar estados anteriores de una rama
Había visto
git reflog, pero casi siempre lo usaba solo para recordar “¿cuál era esa rama en la que había trabajado antes?”Desarrollé un miedo medio saludable a las operaciones que pueden meterte en medio de una resolución de conflictos no deseada. Normalmente los conflictos aparecían por referenciar el commit o la rama equivocados
Ese miedo no ha desaparecido por completo, pero al menos ahora me siento bastante cómodo recuperando trabajo anterior entre operaciones como un rebase
Si no sé si algo va a generar conflictos después de cierta operación, simplemente lo intento y veo qué pasa. Si hay conflictos, los resuelvo, revierto la operación que los causó, o creo un commit nuevo en otro lugar y dejo el conflicto para después
Si ya sé que habrá conflictos, duplico la rama relacionada y pruebo de antemano, o ejecuto la operación conflictiva y sigo el proceso de resolución. Si resolverlo se vuelve demasiado enredado, puedo deshacer solo una parte de la resolución y seguir intentando, dejarlo en pausa un rato para hacer otra cosa, o descartar todo el árbol
Dicho sin rodeos, hay que dejar Git y mirar JJ
https://martinvonz.github.io/jj/v0.17.1/
Hasta Linus probablemente pensaría que la UI de Git es pésima. JJ tiene un flujo de trabajo excelente
Aun así, fuera de haberlo probado un poco, no lo he usado a fondo en trabajo real, así que no puedo afirmarlo con total certeza