# Configuración de la cuenta: Nombre, correo y editor predeterminado. git config --global user.name "Nombre Apellidos" git config --global user.email usuario@dominio.com git config --list # Lista la configuración en uso. # Si se desea usar vimdiff para visualizar y trabajar sobre conflictos de código. git config --global core.editor vim git config --global diff.tool = 'vimdiff' git config --global merge.tool = 'vimdiff'
## Clonar un repositorio. git clone ssh://usuario@server/repo.git git clone ssh://user@server/home/user/.git/repositorio # No todos los repositorios tienen extensión ".git"
Crear repositorios / Permitir acceso remotamente (simplemente se necesita un servidor SSH).
mkdir /home/user/repositorio.git cd /home/user/repositorio.git git init # Agregar ficheros del repositorio si se quiere. git add . git commit -m "commit inicial" ## Clonar en local el repositorio creado en el paso anterior. git clone /home/user/repositorio.git /home/otro_user/repositorio ## Clonar en remoto mediante SSH el repositorio creado en el paso anterior. El usuario debe tener acceso mediante password o llave SSH. git clone ssh://user@server/home/user/repositorio.git cd repositorio
git status # Información sobre los cambios realizados en los ficheros traceados por git. git diff # Diferencias de los ficheros modificados y la versión anterior de los mismos. git diff <commit hash> <fichero> # Muestra las diferencias sobre un fichero comparando el estado actual con el de un commit concreto. git diff --color | diff-so-fancy # diff-so-fancy es una herramienta externa. git diff --word-diff file1 file2 # Muestra la diferencia por palabras, útil también fuera del mundo git para simplemente comparar dos archivos. NOTA: Los ficheros nuevos agregados que todavía no hayan sido traceados mediante "git add", no saldrán en "git diff". Es decir, si se agregan nuevos ficheros, se editan otros y luego se usa "git diff" para saber qué cambios se realizaron en el repositorio, no se tendrá constancia de los nuevos ficheros agregados. Solo se mostrarán los que han sufrido algunos cambios y ya estaban siendo seguidos. git diff master...XXXX # Muestra las diferencias entre la rama master y XXXX. git diff origin/master... # Estando dentro de una rama cualquiera, se quiere ver qué la diferencia de la rama master. git add . # Agrega los cambios al commit y empieza a seguir cualquier nuevo archivo creado. git add -p fichero # Agrega el fichero para el próximo commit. git commit -m "xx" # Ejecuta el commit y se le pasa la descripción directamente. git commit --amend # Sobrescribe / Cambia el último commit. Agregar "--no-edit" si no se quiere editar la descripción del commit. (No usarlo en repositorios públicos con commits ajenos).
git log # Muestra información de todos los commits. git shortlog # Muestra información de todos los commits resumida por usuario. # Muestra información de todos los commits en formato agradable a la vista. git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' git log -p <fichero> # Muestra información de los commits de un fichero en particular. git log --since='FEB 11 2016' --until='FEB 11 2016' # Muestra información de los commits entre dos fechas. git blame <fichero> # Muestra quién cambió qué en un fichero. git log --name-status -2 # Muestra los ficheros modificados en los dos últimos commits. Útil para saber qué ficheros se ha modificado después de hacer un git pull (dos commits porque el merge es un commit también). git log -p -2 # Muestra los cambios de los dos últimos commits. Útil para saber qué se ha modificado después de hacer un git pull (dos commits porque el merge es un commit también). git log --all --grep='<texto>' # Buscar en todas las ramas una palabra o texto (NO de ficheros, si no commits). git log --all -- fichero # Busca en todas las ramas información sobre commits donde el fichero haya estado envuelto. git log --diff-filter=D --summary # Listar ficheros borrados mediante "git rm". git log --follow -p -- <fichero> # Lista commits y cambios sobre un fichero concreto. git show <commit1> <commit2> # Muestra los ficheros editados y sus cambios en uno o varios commits. git diff-tree --no-commit-id --name-only -r <commit> # Muestra únicamente qué ficheros fueron modificados en un commit (Opción 1). git show --pretty="" --name-only # Muestra únicamente qué ficheros fueron modificados en un commit (Opción 2). # NOTA En la sección "Deshacer acciones" se puede ver como restaurar ficheros al estado de un determinado commit.
Cuando se trabaja en Git con varias ramas en local, hay que tener en cuenta algo. Al crear una rama e introducirse en ella, los cambios en local que se hayan hecho en cualquier otra rama de manera previa y que no hayan sido agregados mediante un commit, se verán en el resto de ramas. Esos ficheros que no están bajo seguimiento de ninguna rama pueden ser mediante un commit pasados a seguimiento en una determinada rama. Eso hará que dichos cambios o ficheros desaparezcan del resto de ramas. Por eso es importante prestar atención cuando se está trabajando con varias ramras a la vez saltando de una a otra realizando cambios.
Visualizar ramas / commits gráficamente / modo texto.
gitk # Aplicación gráfica (se necesita tk instalado). git log --pretty=oneline --graph --decorate --all # Modo texto. git log --graph --pretty=format:'%C(auto) %h | %s | %an | %ar%d' # Modo texto.
Operaciones sobre ramas en git.
git branch -avv # Lista todas las ramas y algunos commits. git branch -r # Lista las ramas remotas (se puede usar con --merged y --no-merged) git branch --merged # Lista las ramas que ya han sido fusionadas (normalmente candidatas para ser eliminadas). git branch --no-merged # Lista ramas todavía pendientes de ser fusionadas. git branch <rama> # Crea una rama. Esto es siempre a partir de la rama donde se esté trabajando, es decir, master u otra rama. git checkout <rama> # Cambiar de rama = Cambiar el puntero HEAD. / Si se usa "-" se va a la rama anterior. git checkout -b <rama> # Crea una rama y cambia a la rama creada, equivale a los dos comandos anteriores. git branch -d <rama> # Borrar una o varias ramas locales que haya sido fusionada. De haber sido fusionada la rama mostrará un error. git branch -D <rama> # Borrar una o varias ramas local aunque no haya sido fusionada. git branch -d `git branch --merged | grep -v \* | xargs` # Borrar todas las ramas en local (-d o -D según se necesite). git push origin --delete <rama> # Borrar una rama en nuestro repositorio remoto. git branch -dr <remote>/<rama> # Deja de seguir una rama remota en local. git tag # Lista las etiquetas del repositorio git tag <nombre> # Crea una etiqueta para el commit. Útil para marcar puntos donde se ha lanzado alguna versión, ej "v2.0". git show <rama>:<fichero> # Muestra el contenido de un fichero de otra rama.
Eliminar varias ramas de forma simultanea
# Borra todas las tamas locales ya fusionadas excluyendo master y XXX. git branch --merged | grep -Ev "(^\*|master|XXX)" | xargs git branch -d # Elimina todas las ramas remotas que hayan sido fusionadas (Usar -D para todas las ramas remotas, estén o no fusionadas) a excepcion de master y XXXX. git branch -r --merged | grep -Ev "(^\*|master|XXX)" | sed 's/origin\///' | xargs -n 1 git push origin --delete # Listar y borrar ramas locales que hayan sido eliminadas en el remoto. "<remote>" suele referenciar a "origin" si no se ha cambiado el nombre del repositorio remoto. git remote prune <remote> --dry-run # Lista git remote prune <remote> # Borra
Exportar / Importar ramas con historial.
git bundle create <fichero> <rama> # Exportar a un fichero. git clone repo.bundle <repo-dir> -b <rama> # Importar rama a un repositorio.
Los repositorios remotos son versiones de tu proyecto que se encuentran alojados en Internet o en algún punto de la red. Si solo hay uno se le define con el nombre de “origin”, pero es factible que un proyecto tenga diferentes repositorios (Normalmente de diferentes usuarios que lo han clonado).
git remote -v # Lista los repositorios remotos git remote add <name> <repo> # Añadir un repositorio remoto con nombre / alias <name>. git remote rename user12 u12 # Renombramos el repositorio remoto de "user12" a "u12". git fetch <name> # Recupera la información que no se tenga del repositorio remoto <name>. git pull <repo> <rama> # Actualiza el repositorio local con los cambios remotos. No es necesario especificar <repo> <rama> si ya estamos ahí. git push <repo> <rama> # Actualiza el repositorio remoto en la rama especificada. No es necesario especificar repo y rama si ya estamos ahí. git push --tags # Publica las etiquetas. git remote set-url origin <url> # Cambiar la URL de un repositorio remoto.
Si git pull falla porque se modificó algún archivo en el repositorio y posteriormente se quiso actualizar, la solución es descartar todos esos cambios si estos no son necesarios.
git pull Updating 194fda4..8b0a6ee error: Your local changes to the following files would be overwritten by merge: XXXXXXX Please, commit your changes or stash them before you can merge. Aborting git stash save --keep-index git stash drop git pull
NOTA: Esto eliminará todos los cambios locales, si se quieren mantener algunos cambios no se deben seguir estos pasos.
Tanto merge como rebase se utilizan para el mismo fin. Cual usar depende de la información que se quiera guardar. Si los commits fueron publicados en un repositorio público donde trabajan más personas, no se debe hacer un rebase ya que se pueden perder commits de otros usuarios.
El rebase está orientado a hacer limpieza y unificar commits todavía no publicados, permite visualizar gráficos de representación de flujos de trabajo menos ramificados y confusos. A la hora de resolver conflictos es más complejo ya que hay cierta información que se ha sido eliminada.
Cuando se hace un rebase, los commits locales se eliminan de la rama temporalmente, se ejecuta un git pull y los commits locales se insertan nuevamente a continuación. Los commits locales aparecen por tanto al final, independientemente de cuando fueron realizados. Si otra persona realizó commits pero que no han sido publicados todavía , al hacer el rebase esos cambios se fusionarán con los nuestros y desapareciendo del historial.
El merge mantiene todo el historial de commits, más cómodo a la hora de visualizar conflictos al fusionar ramas o saber quŕ programador hizo qué cosa. También es más simple de deshacer cambios. El merge obliga a realizar un commit para fusionar las ramas.
Esto quiere decir que todos tus commits locales aparecen al final, después de los commits remotos. Esto es, si haces git log, los commits de la rama que has rebasado aparecen como si fueran más antiguos, independientemente de cuándo se hicieran.
git merge <rama> # Fusiona una rama con nuestra rama actual (HEAD). git rebase <rama> # Reorganiza fusionando una rama con nuestra rama actual (HEAD). (No en proyectos colaborativos.) git rebase --abort # Aborta un rebase. git rebase --continue # Continuar con un rebase después de resolver conflictos. git mergetool # Usa la aplicación de resolución de conflictos. # NOTA: Si no se usa mergetool se puede utilizar un editor, una vez resuelto el conflicto se debe agregar con "git add <fichero>". # Si solucionar el conflicto requiere de la eliminación de un fichero se debe utilizar "git rm fichero". # Si solo se quiere dejar de tracear pero no eliminar un fichero, utilizar git rm --cached fichero
Es común el estar trabajando en una rama distinta a la principal y se requiera incorporar cambios actuales que se han realizado sobre la rama master y no están en la rama de donde se está trabajando.
# Nos encontramos en la rama TEST y procedemos a cambiar a la rama master # IMPORTANTE; Los cambios realizados en la rama deben ser guardados si no queremos que se pierda todo, es decir, "git add" y "git commit" en la rama TEST. git checkout master # Actualizamos el estado de la rama master git pull # Se vuele a la rama TEST git checkout TEST # Incorporamos los cambios de la rama principal a nuestra rama TEST. git merge master # Esto puede generar algún tipo de conflicto si en la rama master se editaron ficheros que también fueron editados en la rama TEST. # Al ejecutar el comando anterior git nos avisará de qué ficheros se vieron afectados. # Se deben editar los ficheros correspondientes y posteriormente se podrá realizar un "git add" y "git commit".
Este error se muestra cuando los cambios en la rama no han sido guardados y se quiere realizar un git pull sobre la rama master. Para solucionarlo se deben guardar los cambios en la rama mediante “git add” y “git commit”.
Actualizando f50a07be..061cd018 error: Los cambios locales de los siguientes archivos serán sobrescritos al fusionar: ruta/fichero1 ruta/fichero2 ... Por favor, confirma tus cambios o guárdalos antes de fusionar. Abortando
Es posible usando frameworks como Bitbucket encontrarse en la situación, donde alguien ha realizado una pull request sobre una rama y esta todavía no ha sido aceptada por nadie para que pase a la rama manager. Al clonar el repositorio e ingresar en dicha rama, los cambios de esas pull request que todavía no ha sido aceptada no están en el código. Es decir, solo la persona que hizo la pull request tiene esos cambios en su repositorio local accesibles de manera directa.
La solución para las personas que quieran tener esos cambios de la pull request, es identificar el commit perteneciente a dicha pull request y usar el comando cherry-pick. Este comando de git se usa para coger commits de otras ramas e insertarlos en otra, pero en este caso, pese a ser la misma rama es también muy útil.
# Se clona el repositorio y se empieza a usar la rama BRANCH_XX, que es donde hay una PR pendiente de ser revisada. git clone XXXX git checkout BRANCH_XX # Se busca el commit perteneciente a la Pull request, por ejemplo 0ef16eb1370 y se le indica a git que debe coger ese commit. git cherry-pick 0ef16eb1370
git reset --hard HEAD # Deshace todos los cambios locales. git checkout HEAD <file> # Deshace todos los cambios locales realizados sobre un archivo. git checkout <commit> # Nos posiciona sobre el commit deseado. git revert <commit> # Deshace un commit mediante otro commit que hace justo lo contrario. git checkout <commit> -- file1 file2 # Restaura los ficheros al estado que tenían en un determinado commit. git reset <commit> <file> # Restaura un fichero al estado que tenía en un determinado commit (Lo mismo que el anterior). git restore --staged file1 file2 # Para poder usar git diff y ver los cambios realizados al restaurar los ficheros. # NOTA: En la sección "Historial de commits y búsquedas" se muestra como ver las diferencias de ficheros entre commits. git reset --hard <commit> # Se posiciona sobre un commit especifico eliminando todos los cambios y commits posteriores. git reset <commit> # Nos posiciona en un commit pero sin eliminar cambios siempre que se hayan fijado mediante un commit. git reset --keep <commit> # Nos posiciona en un commit pero sin eliminar cambios, aunque estos no se hayan fijado mediante un commit. git checkout -- <filename> # Recuperar un fichero accidentalmente borrado con rm (no git rm). # Recuperar ficheros borrados que todavía no han recibido un commit. git reset -- <filename> # Deshacer borrado de un fichero con "git rm" (paso 1). git checkout -- <filename> # Después de que ya no esté el fichero en el commit (paso 1) se restaura con checkout (paso 2). ## Recuperar ficheros borrados después de realizar un commit. git rev-list -n 1 HEAD -- <filename> # Buscar el último commit (donde se borraron). git checkout <commit>^ -- <filename> # Recuperar el/los fichero/s del commit anterior.
Editar un mensaje de commit que todavía no haya sido subido mediante push.
git add . gut commit -m "Mensaje erroneo" git commit --amend -m "Mensaje correcto anulando el anterior."
Editar el mensaje del último commit publicado con push.
git commit --amend -m "Mensaje correcto anulando el anterior." git push --force nombre_rama
Deshacer el ultimo commit que no ha sido subido mediante un push, modificar algo y rehacer el commit con el mismo mensaje.
git commit -m "Cagada gorda." git reset HEAD~ # git reset HEAD~10 # Deshace los últimos 10 commits. # Editamos lo que necesitemos. git add . # Realiza el commit con el mensaje del commit anterior. git commit -c ORIG_HEAD
NOTA: Al igual que “.”, se agregaran todos los fichero y directorios a partir del directorio actual. Si hay carpetas y ficheros modificados en carpetas por encima de donde se realice el “git add”, estas no serán incluidas.
Sincroniza el repositorio local con el remoto eliminando todos los cambios realizados. Tiene el mismo efecto que borrar y clonar de nuevo.
git fetch origin git reset --hard origin/master git clean -f -d
Obtener los 5 ficheros más pesados del repositorio, la salida es en bytes.
git ls-tree -r -t -l --full-name HEAD | sort -n -k 4 | tail -n 5 100644 blob 2d39bc8c79404767f7ccc017664ea8cbbd0ed1f3 4981 conkyrc0 100644 blob d2ae61dcd3e1553d92d35937fda2a5d47ad8fc85 6592 conkyrc1 100644 blob fa002ad9343ce76dd344ff85a9a1c19b45ccfbb0 7415 lua/clock2.lua 100644 blob e9b145eaebecc676d12172c71efaf0059faf2ab8 7834 lua/clock.lua 100644 blob c32867067b297557a47eece0377ec0c87c49f5ca 3153203 Black_Pearl_clean.png
Este comando visualiza todos los nombres de ficheros que fueron usados en un repositorio, aunque estos fueran borrados en el pasado o se incluyan en otras ramas diferentes a la rama maestra.
git log --all --pretty=format: --name-status | cut -f2- |sort -u
Hacer un Fork del repositorio en cuestión: Puede hacerse desde la propia página de GitHub, entrando en un repositorio y pulsando el botón “Fork”, arriba a la derecha.
# Clonamos el repositorio y se realizan los cambios que se crean oportunos. git commit -m "Decripción del commit" [--signoff] # --signoff es necesario en algunos proyectos, por ejemplo Docker o el Kernel de Linux. git push origin master # Se envían los cambios a la rama master del repositorio origin (remoto de GitHub).
Ir a Github y pulsar sobre la opción de “Pull request”. Si en el proyecto donde realizamos “pull request” tienen el fichero CONTRIBUTING.md te saldrá un enlace para conocer las políticas necesarias a seguir para poder hacer aportaciones al código.
Como solucionar cuando el test automático de una PR en GitHub muestra un problema con DCO.
Algunos proyectos requieren DCO (Deja constancia de una manera explícita que entiendes y aceptas que el proyecto y la contribución son públicos y que un registro de la contribución (incluyendo toda la información personal que envíe con ella, incluyendo mi firma) se mantiene indefinidamente y puede ser redistribuido de acuerdo con este proyecto o con la(s) licencia(s) de código abierto involucradas.) Si esta no ha sido realizada en el commit, el test que compruebe la PR avisará del problema. Esto puede solucionarse de la siguiente manera.
Localizamos la rama donde se encuentra nuestra PR y saltamos a ella, en este caso para el ejemplo “path-1”.
git checkout patch-1 git commit --amend --no-edit --signoff # Sobrescribe el último commit sin editar su descripción del commit y agrega la opción --sifnoff git push --force-with-lease origin patch-1 # Sobrescribe si no se hicieron otros commits posteriores en la rama.
Una vez realizado el push, se puede visitar de nuevo el estado de la PR y el test DCO debería ser exitoso.
Como ya es sabido, git no implementa ninguna posibilidad de cifrar variables o ficheros de manera nativa, por lo que es mejor intentar mantener ese tipo de información sensible fuera de los repositorios.
Lo mejor para auditar repositorios es clonarlos con la opción --mirror, ya que de esta manera la información del repositorio es más completa y se puede obtener más información dependiendo del caso. Los frameworks vomo github, gitlab, etc no suelen usar --mirror de manera predeterminada.
Una vez se tiene el repositorio clonado se pueden usar un sin fin de herramientas para buscar información que no debería estar ahí como llaves SSH, SSL, Certificados cliente, secretos, etc. Estas herramientas se centran en el uso de expresiones regulares y el uso de algoritmos probabilistas.