Chuleta sobre GIT
Este apunte contiene mi ficha de ayuda sobre GIT: Es mi hoja recordatorio que utilizo como programador, donde tengo las comando que más utilizo. Viene bien por ejemplo cuando borro accidentalmente un fichero, quiero consultar una versión anterior de código o quiero ignorar una modificación en un archivo concreto.
Importante: Este apunte lo uso como referencia, por lo tanto asume que conoces GIT. Si necesitas saber más te recomiendo este otro apunte sobre GIT en detalle |
Básico
git config --global user.name "Don Quijote"
git config --global user.email "donquijote@email.com"
mkdir -p /home/proyectos/miproyecto
cd /home/proyectos/miproyecto
git init
cd /home/proyectos
git clone https://github.com/LuisPalacios/LuisPalacios.github.io
cd /home/proyectos/miproyecto
git status
Tags
$ git log --pretty=oneline
a7a05..d9114 (HEAD -> master, origin/master, origin/HEAD) Nueva versión
:
3f64b..37101 Versión terminada
ce5d4..1e621 Primer commit
$ git tag 1.0 3f64b <== Aplicada al commit con hash 3f64b
$ git tag -d 1.0 <== La borro para añadirla de nuvo con anotación
$ git tag -a 1.0 -m "Primera versión operativa" 3f64b
$ git tag 2.0 <== Aplica al último commit
$ git push origin 1.0 <== Envío tag o tags al origen.
$ git push origin --tags
Alias
$ git config --global alias.lo '!git --no-pager log --graph --decorate --pretty=oneline --abbrev-commit'
$ git config --global alias.lg '!git lg1'
$ git config --global alias.lg1 '!git lg1-specific --all'
$ git config --global alias.lg1-specific "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %s - %an %C(blue)%d%C(reset)'"
$ git lo
$ git lg
Deshacer
Técnicamente consiste en Volver a la versión anterior de un archivo de la working copy. Muy útil cuando hemos borrado o modificado un archivo por error y queremos deshacer por completo y volver a su versión anterior (la del último commit). Ojo que es destructivo, vuelve a dejar el contenido anterior del fichero y lo que hayamos modificado se pierde…
$ git restore Capstone/dataset/0.dataclean/datos.ipynb
Importar un repositorio GIT local a GitHub
Está aquí documentado, hay dos formas de hacerlo y voy a describir la primera, con el GitHub CLI.
- “Adding a local repository to GitHub with GitHub CLI” - Lo puedes hacer todo desde tu ordenador, previa instalación del comando
gh
-
“Adding a local repository to GitHub using Git” - Necesitas trabajar en tu ordenador y en GitHub.
- Instalo GitHub CLI (
gh
)
brew install gh (MacOS)
apt install gh (Ubuntu)
- Creo un repositorio local
mirepo
congit init
mkdir -p /home/luis/prog/github-luispa/mirepo
cd /home/luis/prog/github-luispa/mirepo
git init
e README.md
git add .
git commit -m "primer commit"
- Antes de seguir, es bueno tener un Authentication Token. Puedes crear uno en tu usuario de GitHub -> Token. El token necesita los permisos de ‘repo’, ‘read:org’, ‘admin:public_key’.
$ gh auth login
? What account do you want to log into? GitHub.com
? What is your preferred protocol for Git operations on this host? SSH
? Upload your SSH public key to your GitHub account? /Users/luis/.ssh/id_ed25519.pub
? Title for your SSH key: GitHub CLI
? How would you like to authenticate GitHub CLI? Paste an authentication token
? Paste your authentication token: ****************************************
:
- A continuación uso
gh
para “subir” mi repositorio localmirepo
a GitHub, prefiero hacerlo de golpe en un solo comando:
cd /home/luis/prog/github-luispa/mirepo
gh repo create --description "Composición sobre Herencia en C++" --remote "CompositionOverInheritance" --source=. --public --push
✓ Created repository LuisPalacios/testLuisPa on GitHub
https://github.com/LuisPalacios/testLuisPa
✓ Added remote git@github.com:LuisPalacios/testLuisPa.git
:
rama 'master' configurada para rastrear 'CompositionOverInheritance/master'.
✓ Pushed commits to git@github.com:LuisPalacios/testLuisPa.git
Github y Visual Studio Code basado en Web*
Si quieres trabajar con VSCode desde tu navegador, directamente conectado culaquier repositorio alojado en GitHub, solo tienes que reemplazar .com
por .dev
. Si el repositorio es tuyo (has hecho login en GitHub) entonces tendrás derechos de edición y podrás hacer commits directamente. Un par de ejemplos:
- https://github.dev/CiscoDevNet/netprog_basics
- https://github.dev/LuisPalacios/LuisPalacios.github.io/tree/gh-pages
Agrupar commits en ORIGIN/main
Esto es PELIGROSO, DESACONSEJADO y solo recomendado SI TIENES MUY CLARO LO QUE ESTÁS HACIENDO. De hecho solo lo aconsejo en repo’s tuyos donde no estás colaborando, para limpiarlos (de muchos commits). A veces nos puede interesar.
El caso de uso es cuando tengo una única rama main
en GitHub y solo estoy yo como desarrollador, he hecho muchos, pero que muchos commits con pequeñas modificaciones, mal documentados y quiero “limpiar” porque me encuentro con una rama main
bastante sucia.
-
Voy a coger como ejemplo mi rama
main
de un proyecto llamadorefrescar
. Mi situación original es que mi repo tiene 48 commits y quiero hacer unsquash
de los últimos 45 commits (fusionar los últimos 45 commits en uno solo). -
Lo curioso del tema es que esos commits están ya en ORIGIN (es decir en GitHub).
-
El primer paso es hacer un clone o asegurarme de que mi copia local está a la última, completamente sincronizada y sobre todo que NO HAYA NADIE (ningún otro desarrollador haciendo push a origin/main).
🍏 luis@asterix:refrescar (main) % git pull
🍏 luis@asterix:refrescar (main) % git rev-parse --short HEAD
28f5b2d
🍏 luis@asterix:refrescar (main) % git ls-remote --quiet | grep HEAD | cut -c 1-7
28f5b2d
Estos son los hash de los 48 commits...
28f5b2d oop 48 <== último commit
:
483583a update gitignore 4
86dc978 update readme 3
ddea7e7 Update README.md 2
326d415 Initial commit 1er commit
-
Preparo el editor que usa
git
. Lo vamos a necesitar a continuación, durante la operación derebase
.git config --global core.editor code
-
IMPORTANTE. Una vez que inicias el
rebase
, si ves problemas, aborta con:git rebase --abort
-
Empieza la fiesta, hago un
rebase
de los últimos 45 commits
🍏 luis@asterix:refrescar (main) % git rebase -i origin/main~45 main
- Se abrirá el editor automáticamente y mostrará todos los commits, desde el tercero #86dc978 (48-45=3) hasta el último #28f5b2d.
pick 86dc978 update readme <== 3er commit (48-45) \
squash 483583a update gitignore |
: > Fusionar
squash fe1dd07 oop |
squash 28f5b2d oop <== ÚLTIMO COMMIT /
- En el editor aparecen todos los commits con la palabra
pick
. Ahora tengo que decidir, entre estas opciones:- pick: Mantiene el commit tal como está.
- reword: Permite cambiar el mensaje del commit.
- edit: Permite editar el contenido del commit.
- squash: Combina este commit con el anterior, conservando ambos mensajes de commit.
- fixup: Similar a squash, pero solo guarda el mensaje del commit anterior.
- drop: Elimina el commit de la lista.
- Dejo la primera línea (3er commit histórico) con
pick 86dc978
y cambio todos los otros pick’s asquash
. Salvo el fichero y salgo del editor. Automáticamente intenta hacer lo que le hemos pedido, pero en mi caso detecta un conflicto (esto es normal y viene bien para que veas cómo resolverlo):
🍏 luis@asterix:refrescar (main) % git rebase -i origin/main~45 main
Auto-fusionando 29-oop-rpg/src/programa.cpp
CONFLICTO (contenido): Conflicto de fusión en 29-oop-rpg/src/programa.cpp
error: no se pudo aplicar 357d14f... oop
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config advice.mergeConflict false"
No se pudo aplicar 357d14f... oop
- Edito el fichero con el conflicto en cuestión, resuelvo los conflictos y lo salvo.
🍏 luis@asterix:refrescarA ● ●(main) rebase-i +?) % e 29-oop-rpg/src/programa.cpp
- Los marco como resueltos añadiendolos y continúo con el rebase
🍏 luis@asterix:refrescarA ● ●(main) rebase-i +?) % git add .
🍏 luis@asterix:refrescarA ● ●(main) rebase-i +?) % git rebase --continue
- Podriá volver a ocurrir que hay conflictos, repito los pasos…
🍏 luis@asterix:refrescar (main) % e fichero-con-conflicto...
🍏 luis@asterix:refrescar (main) % git add .
🍏 luis@asterix:refrescar (main) % git rebase --continue
Irá mostrando el editor y este proceso puede tardar un rato, depende de cuantos conflictos tengas...
- Llegará un momento donde dejas de tener conflictos, verás el mensaje
Rebase aplicado satisfactoriamente y actualizado refs/heads/main.
Rebase aplicado satisfactoriamente y actualizado refs/heads/main.
🍏 luis@asterix:refrescar (● main ↕) % git status
En la rama main
Tu rama y 'origin/main' han divergido,
y tienen 1 y 46 commits diferentes cada una respectivamente.
(use "git pull" if you want to integrate the remote branch with yours)
nada para hacer commit, el árbol de trabajo está limpio
- Ahora llegamos al punto crítico. Vamos a mandar a ORIGIN/main nuestra copia haciendo un FORCE PUSH
🍏 luis@asterix:refrescar (● main ↕) % git push origin +main
Enumerando objetos: 117, listo.
Contando objetos: 100% (117/117), listo.
Compresión delta usando hasta 12 hilos
Comprimiendo objetos: 100% (105/105), listo.
Escribiendo objetos: 100% (114/114), 30.13 KiB | 10.04 MiB/s, listo.
Total 114 (delta 19), reused 82 (delta 8), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (19/19), completed with 1 local object.
To github.com-LuisPalacios:LuisPalacios/refrescar.git
+ 5a42ca6...96b4c8d main -> main (forced update)
- Muestro el log de mis commits
🍏 luis@asterix:refrescar (main) % git log --all --decorate --oneline --graph
* 96b4c8d (HEAD -> main, origin/main, origin/HEAD) Commit agregado de 45 commits final
* ddea7e7 Update README.md
* 326d415 Initial commit
- El repo queda ya con solo 3 commits !!
- Los commits que han quedado son:
96b4c8d Commit agregado de 45 commits 3er <== COMMIT que agrega todo
ddea7e7 Update README.md 2o
326d415 Initial commit 1er commit
Nota: ATENCIÓN !!!! Es muy importante que el resto de desarrolladores borren su copia local o hagan un reset de su clone actual |
Si otro desarrollador hace un push (–force) desde una rama local (antigua) volverán a aparecer todos los commits. La recomendación es volver a hacer una de las opciones siguientes:
-
Borrar el repositorio local y volver a hacer un clone
-
Reset del respositorio local y pull. A continuación muestro un ejemplo, tenía el repositorio ANTIGUO copiado en “refrescar.old”
🍏 luis@asterix:refrescar.old (● main ↕) % git reset --hard origin/main
HEAD está ahora en 96b4c8d Commit agregado de 45 commits final
🍏 luis@asterix:refrescar.old (main) % git clean -xdf
🍏 luis@asterix:refrescar.old (main) % git pull
Ya está actualizado.
🍏 luis@asterix:refrescar.old (main) % git log --all --decorate --oneline --graph
* 96b4c8d (HEAD -> main, origin/main, origin/HEAD) Commit agregado de 45 commits final
* ddea7e7 Update README.md
* 326d415 Initial commit