Desenvolupament d'Aplicacions

GIT: Solucions per a errors típics

Et mostro alguns errors de GIT i t'explico com he arribat a solucionar-los mitjançant alguns snippets

Errors populars GIT

Els reptes que ens presenta GIT

Git, a més de ser una gran eina que permet treballar en sincronia, controlar versions i desplegaments, ens presenta constantment reptes a mesura que ho anem incorporant a la nostra rutina i certs ordres com commit, pull, fetch, push els llancem gairebé com un automatisme.

La veritat és que treballar amb git és molt més que anar concatenant millores en una cadena de desenvolupament. Les branques, els errors humans i la ignorància sobre la big picture de git ens fa trobar-nos amb moltes problemàtiques que ens poden portar de cap si no sabem què fer.

Heus aquí una petita mostra d'errors i com he arribat a solucionar-los:

1. Solucionar un detached head

Potset t'has trobat alguna vegada amb aquest missatge:

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

  HEAD is now at 2546ab73 checkout now allows jp

Quan això succeeix, els nostres canvis no seran guardats en cap branca, no podem fer push, ni commits, ni pulls. El que ha passat és que el punter de git ja no està apuntant a l'última versió, sinó que ha deixat d'apuntar al repositori remot per complet mentre solucionem l'embolic en local. En aquests casos, si l'únic que volem és tornar a estar en sincronia amb el repositori remot, simplement hem de tornar a la branca en la qual estàvem treballant.

# Por ejemplo, si la rama en la que estábamos es "master"
git checkout master

Si queremos hacer cambios en local y persistirlos, es simple:
# miramos el último commit
git log -n 1

# tenemos que copiar el hash identificador
# cambiamos a la rama de la que venimos, en mi caso, es master
git checkout master

# creamos una rama local temporal en la que mantendremos los cambios
git branch tmp <commit-hash>

# volvemos a la rama origen
git checkout master
# unimos los cambios que hemos guardado
git merge tmp

2. On sóc?

Relacionat amb el punt anterior, és important entendre com funciona la sincronia entre repositoris. Sovint volem veure els canvis que hem fet i no sabem quin comandament utilitzar.

Si hem fet canvis en local i encara no hem fet commit:

git diff
# muestra todos los cambios que hay entre el último commit y nuestros archivos
# muchas veces se utiliza con un nombre de archivo, para limitar las líneas y entender mejor los cambios que hemos realizado.
git diff ruta/a/nuestro/archivo/modificado

Git diff és molt més potent que per comparar canvis locals, ja que també permet veure versions emmagatzemades en diverses branques o commits. No obstant això, aquest ús és molt diferent i generalment no comporta malentesos.

Si hem fet commit dels nostres canvis, el normal és que estiguem segurs de què és el que hem fet. No obstant això, potser hagi passat un temps i haguem de recapitular. En aquests casos, per veure els canvis que ha fet l'últim commit, podem fer-ho d'aquesta manera:

git show
# muestra los cambios realizados en el último commit, sea este local o remoto
# igual que git diff, nos permite poner una ruta a un archivo para ver si ese archivo en concreto ha sido modificado.
# también nos acepta si le ponemos el hash de un commit en concreto para ver los cambios de aquel

Si el que volem és entendre què és el que ha passat, la comanda git log és el nostre amic. Mostra les ids de tots els commits i el seu comentari. Si volem una vista més detallada, podem provar amb:

git log --graph --decorate --pretty=oneline --abbrev-commit 
Este comando nos dará un output similar a este
* 2546ab73 (master) checkout now allows jp
*   5f4f35a6 Merge branch 'FeatureFix' into master
|\
| * c394bc03 (origin/FeatureFix, FeatureFix) final fix for 277
| * 0b401d6e small fix for Controllers
* | bdd0c919 Test
* | e15152aa OBLIGED TO FILL ADDRESS2 IN CN IN JP
|/
* efee567a Added default when querystring returns null
* 9c77302e Added querystring awareness
* ff606371 Retrieves now subscriptions dynamically
* 7cbd072a Syntax error
* 32b72c2e Small bugfix on Controller
* bbe9e2aa Modificar ciertos inputs en personal details

Bastant gràfic i fàcil d'entendre. 

3. Cherrypicking

Aquest fitxer modificat per un company en la seva branca, la qual va partir d'una versió anterior de màster i que no pot mergearse sense una marabunta de conflictes ara mateix et vindria bé. Com recuperar-lo i portar-te'l sense haver de fer Merges?

# necesitamos saber el id del último commit donde estén los cambios
git checkout rama_ajena
git log -p
# con estos comandos habremos cambiado a su rama y habremos visto los últimos cambios listados. Tan solo es cuestión de buscar (con tecla '/') en el log donde están los cambios que necesitamos y apuntarnos el ID de ese commit
# luego podemos importarnos este commit:
git checkout nuestra_rama
git cherry-pick <id-commit>
# si el commit conlleva más archivos o y se han dado problemas, podemos solucionarlos como si se tratara de un merge
# en mi caso, utilizo la default mergetool de git para resolver estos problemas:
git mergetool
# si hay demasiados problemas y queremos volver atrás, podemos hacerlo con
git cherry-pick --abort
# si hemos solucionado correctamente los conflictos, acabamos el cherry-pick con
git cherry-pick --continue
# estos dos comandos son los mismos que podemos utilizar con git merge para cancelar o continuar adelante.

4. Mergear automàticament

Moltes vegades ens trobem amb merge conflicts i realment sabem que la nostra versió d'un arxiu no està actualitzada i que volem la del repositori remot. O viceversa. Hi ha una manera més ràpida de fer això que no haver de repassar manualment cada canvi de l'arxiu:

# simplemente enviamos el parámetro --strategy-option, o -X
git merge --strategy-option theirs rama_remota
El opuesto, si queremos persistir nuestros cambios, sería:
git merge --strategy ours

5. He fet alguna cosa malament. Com la reverteixo?

Revertir un commit

# primero veamos el id de nuetros últimos dos commits
git log --oneline -n2
# cambiemos al commit anterior al que queremos eliminar
git checkout <commit-hash> 
# también podemos probar, si es el último commit, con
git checkout HEAD^1
# ahora estamos en estado detached, podemos revisar si está funcionando nuestro código en esta versión
# cuando acabemos la revisión, podemos revertir el commit problemático (tenemos su commit hash justo antes)
git revert <commit-hash-del-commit-problematico>
# git revert no elimina el commit, sino que genera uno nuevo en el que los cambios se quitan. 
# Así que si ahora nos sincronizamos a la última versión, tendremos los cambios revertidos:
git checkout <nombre-de-rama>

Revertir arxius dins d'un commit

# Si los archivos están modificados y queremos la versión anterior:
git checkout -- <nombre_de_archivo>
# Si los archivos están aún por commitear si bien están añadidos al repositorio:
git reset HEAD <nombre_de_archivo>
# Si los archivos están ya committeados, pero no los queremos:
git reset HEAD^ <nombre_de_archivo>
# en windows:
git reset HEAD~1 <nombre_de_archivo>

Revertir un push

# necesitamos conocer la ID del último commit:
git log --oneline -n1
# con esta id podemos revertir el commit:
git revert <hash-del-commit>
# esto genera un nuevo commit que revierte los cambios
git push
# finalmente, subimos este nuevo commit

Revertir un commit anterior

# podemos utilizar el método anterior pero con otra id de commit para revertirlo:
git revert <hash-del-commit>
# esto genera un nuevo commit que revierte los cambios
git push
# finalmente, subimos este nuevo commit

Conclusions

Espero que aquests snippets puguin ser d'ajuda per a solucionar problemes comuns. És important tenir un major coneixement sobre com funciona git internament, però moltes vegades ens trobem amb problemes que no esperàvem i és difícil tenir el temps per aprendre tot el que impliquen les causes del conflicte i necessitem una solució.

Comparteix aquest article

Articles Relacionats