el git nuestro de cada dia
TRANSCRIPT
Objetivos● Entender mejor lo que hacemos diariamente● Hacer menos preguntas (entender el man)● Mejorar algunas prácticas● Cometer menos errores● Hacer algo super puntual ;)
Orígenes y filosofía● 2005, kernel de Linux● Eficiencia, diseño simple● Desarrollo no lineal (miles de
branches en paralelo)● Completamente distribuído
Distribuído● Casi toda operación es
local● Todas las máquinas
tienen TODA la información
● Contraste SVN, CVS, etc.
Algo de teoría● git init inicializa un repositorio● Crea un único directorio .git en la raíz (no contamina)● Mini filesystem● Snapshots, no diferencias!
Git y el contenido● Tracking de contenido, NO archivos● Vocabulario: tracked / untracked● Objetos de git
○ Blob (contenido)○ Tree (estructura)○ Commit (apunta a un tree, + data)○ Tag (apunta a un commit, + data)
SHA-1
Blob● Un archivo por “contenido”● SHA-1 del contenido (zlib) + un
header● Inicialmente, loose object● Luego packfile (eficiencia,
heurísticas…)● Ejemplo: find .git/objects -type f
Tree● Como una estructura de
directorios● Punteros a blobs u otros trees● Representa un snapshot
completo del estado● Ejemplo: git ls-tree <sha-1>
Commit● Información sobre los trees● Quién, cuándo, por qué guardó el tree● Apunta al tree de “más arriba” (top level) del
proyecto● Jerarquía de árbol● También SHA-1, diferente hash que el tree
al que apunta
La santa Trinidad (2)Tres partes un proyecto:● Working directory● Staging area (o index)● .git (repository)
Comandos básicos● git add - agrega al index (staging)● git commit - guarda el index actual con el autor,
mensaje, fecha, etc.● git status - muestra los archivos con diferencias en
working dir, staging, y los untracked● git diff - lo que cambió pero no está staged● git diff --cached - lo que va para el próximo commit● git log
Saltear el staging● A veces, puede ser más fácil saltear el
staging● git commit -a | git commit <archivo>● Agregan automáticamente al staging, luego
commitean
Branches● Simplemente un puntero a un commit● Tan rápido como escribir 41 caracteres a un
archivo (SHA-1 + \n)● Por defecto master● Puntero especial HEAD (branch actual)● Ejemplo: cat .git/HEAD
Referencias● El puntero HEAD es un caso particular● Los tags también: “una branch inamovible”
(lightweight tags)
Ejemplo: find .git/refs
Remotes● No hay servidor central● Se pueden agregar varios remotes, copias
externas del repositorio (URL)● El famoso origin :)
Branches remotas● Guardan el estado de las branches en los repositorios
remotos● Son locales, pero no se pueden mover; solo cuando se
hacen operaciones en la red (ej. git fetch).● Forma <remote>/<branch>
Ejemplo: cat .git/refs/remotes/origin/master
Fetch, push● git fetch - sincroniza y actualiza branches remotas
(mueve punteros)● Ej. git fetch <remote>● git pull - equivalente a git fetch y luego git merge,
mergea la branch local con cambios en la remota
● git push - actualiza branch remota con lo local● Ej. git push <remote> <branch>
Tracking branches● Branches locales pueden “seguir” remotas● Dos posibilidades:
○ git checkout --track <remote>/<branch>○ git push --set-upstream <remote> <branch>
● Así, al pushear no hay que escribir el nombre del remote y la branch :)
Merges
● Fast-forward: git es inteligente y solo necesita mover un puntero
● Integrar cambios de una branch en otra
Merges (2)● Three way merge: commit no es ancestro
directo de lo que se mergea (no lineal)● Git determina el mejor ancestro común● Se crea un merge commit, especial pues
tiene más de un padre● Conflictos...
Rebasing● Otra forma de introducir cambios de una
branch en otra● Rewind & replay, reescribe los commits● A partir de un ancestro común● Historia queda siempre lineal, más allá de
que originalmente fue en paralelo
Rebasing (2)● git rebase <new-base>
mueve los commits de la branch actual a la nueva base
● git rebase -i <new-base>selecciona acciones para cada commit
● git pull --rebase
Reglas doradas● Nunca hacer rebase de una branch que está
pusheada, o pulleaste de otra persona○ Commits duplicados si se hace merge○ Discutible: si la branch remota la usa solo uno a modo de backup.○ Usar git push --force, si se sabe que otros developers no trabajan en
la branch.● Si se hace rebase para traer cambios de otros
developers al local, hacerlo tan seguido como sea posible.
Rebase vs Merge¿Por qué rebase?● Historial limpio● Colaboración open-source, muchos lo exigen● Más fácil code review
¿Por qué merge?● Más fácil solucionar conflictos● Menor riesgo
git reset● Se usa a menudo● Mal usado, puede generar pérdida de
datos (workdir unsafe)● Tres opciones más usadas:
○ --soft○ --mixed○ --hard
git reset...● mueve la branch a la que apunta HEAD para que
apunte al commit destino (frena si --soft)● luego hace que el staging se vea como eso (frena si --
mixed, opción por defecto)● luego hace que el working dir se vea como eso (si --
hard, es workdir usafe!)
Ejemplos git reset● Con HEAD en branch dev, hago git reset master
○ ahora dev y master apuntan al mismo commit● Con HEAD en branch master, hago git reset --hard
origin/master○ ahora mi branch master es idéntica a la remote
(descartar cambios locales)● git reset --soft HEAD~
○ Deshace el último commit sin perder cambios
Unstaging de archivos● Al hacer git reset <file> no especifica branch
ni commit SHA● Equivalente a git reset --mixed HEAD <file>● Saca un archivo particular del staging,
opuesto de git add :)
git checkout● git checkout <branch> es superficialmente
parecido a git reset --hard <branch>
● Dos diferencias:○ Workdir safe! :D Chequea por pérdida de datos.○ reset mueve la branch a la que apunta HEAD,
checkout mueve el puntero HEAD.
git checkout de archivo● git checkout <branch> <file>
○ Al igual que reset, ahora no tiene sentido que mueva HEAD. Reemplaza solamente <file> en workdir (workdir usafe!).
○ Sería lo mismo que git reset --hard <branch> <file>○ Pero ese comando no existe :)
Situaciones comunes (1)● “Necesito hacer pull pero tengo cambios en
los que estoy trabajando y no quiero commitear todavía”○ git stash○ Es un stack○ Vaciarlo con git stash pop.
Situaciones comunes (2)● “Hay un bug en una branch, necesito saber
qué commit lo introdujo”○ git bisect○ Búsqueda binaria, conducida por git. Muy fácil!○ git bisect start
git bisect bad <commit>git bisect good <commit>
● Probamos en cada paso (git hace checkout)
Situaciones comunes (3)● “Hice uno (o varios) commits en la branch
equivocada, todavía no pushee!”○ Si la branch correcta no existe
■ git checkout -b <branch correcta>■ git reset sobre vieja branch
○ Si la branch ya existía■ git cherry-pick (o git rebase --onto)■ git reset sobre vieja branch
Situaciones comunes (4)● “Tengo muchos cambios en un archivo y
solo quiero comittear parte de ellos”○ git add -p o git commit -p○ git va a preguntar por cada parte, si queremos
agregarla o no
Situaciones comunes (5)● “Necesito cambiar unos commits”● “Necesito borrar unos commits”● “Necesito cambiar de orden unos commits”
○ git rebase -i (--interactive)○ Fácil de usar○ Reescribiendo la historia, preguntándonos qué
queremos hacer por cada commit
Situaciones comunes (6)● “Estoy haciendo un merge con muchos
conflictos y quiero volver a como estaba antes de comenzarlo”○ git merge --abort