🌿 Git — Control de versiones
Git es un sistema de control de versiones distribuido. Registra el historial completo de cambios de un proyecto, permite trabajar en paralelo mediante ramas, y sincronizar el trabajo entre múltiples máquinas o colaboradores. A diferencia de sistemas centralizados, cada copia del repositorio contiene el historial completo — no hay un servidor que sea indispensable.
1. 🧱 Cómo funciona Git por dentro
Git es un sistema de control de versiones distribuido. Su función principal es guardar el historial de cambios de un proyecto para poder: saber qué cambió, quién hizo el cambio y cuándo lo hizo.
Tambien permite volver a una version anterior y así poder experimentar sin romper el código principal mientras otras personas tambien lo hacen en paralelo. Luego, se pueden combinar cambios de diferentes personas en una versión final.
Es similar a un archivo de guardado de un videojuego o una snapshot.
El pilar central de Git es el repositorio; es un proyecto cuyo historial está siendo controlado por Git. Se ubica en la carpeta .git
El proceso
Primero, toda nuestra carpeta se llama la "Working directory". Cualquier archivo que creemos, sera parte de esta carpeta. Git detectara todos los cambios que hagamos en este lugar, pero no significa que forme parte todavia de nuestro repositorio.
Podemos decidir que incluir en el repositorio, que archivos formaran parte del control de versiones y sobre los que tendremos seguimiento. Estos formaran parte del "Staging area". Es por tanto, un subconjunto de datos dentro del "Working directory".
*"Un Commit" es un snapshot o una fotografia, de los archivos del repositorio. Es una version concreta del proyecto a la que se puede volver en cualquier momento. Representa un cambio mayor y coherente con codigo terminado y funcional.
El "commit" es como el archivo de guardado de un videojuego, el "Staging area" decide que se guardara en ese archivo y el "working directory" es el conjunto de lo guardado y lo no guardado
1.1. Autenticación y configuración
Antes de hacer commits debemos autenticarnos
git config --global user.name "Jessica García"
git config --global user.email "jessica@empresa.com"
Tambien podemos indicar el editor que se usará, por ejemplo
git config --global core.editor vim
Y crear alias para comandos largos
git config --global alias.tree "log --graph --decorate --all --online"
1.2. Crear un repositorio
Tenemos esta carpeta
$: ls
# index.html
Primero hacemos git init para crear un repositorio sobre la carpeta actual (nuestro working dir, com los archivos de nuestro proyecto).
Podemos anadir esos archivos al "Staging Area" para que se incluyan en el commit. Para ello usaremos git add
$: git init # inicializar el repo, se crea la carpeta .git en el directorio actual
$: ls
# index.html
# .git
git add index.html # Añadir un archivo al staging area
git add . # Añadir todo al staging area
$: git commit -m "Creando el repositorio" # Crear un commit con lo que hay en el staging
# [master (root-commit) 4d51fbd] Creando el repositorio
# 1 file changed, 1 insertion(+)
# create mode 100644 index.html
Flujo completo
Cada vez que queramos registrar un cambio en un nuevo commit es con git add y git commit. Git add decide que se guardará en un checkpoint y git commit crea el checkpoint.
[Working directory] - git add → [Staging Area] - git commit → [Commit]
Excluir archivos con gitignore
El archivo .gitignore estará en la raiz del proyecto y permite excluir archivos para evitar que se registren con git add. Por ejemplo
node_modules/
.env
*.log
Esto permite quitar archivos como claves secretas, archivos de cache o demás artefactos que solo ocupen espacio, que no sean esenciales para que funcione nuestro proyecto.
1.3. Realizar cambios
Hemos realizado el flujo git add -> git commit. Pero podemos hacer cambios sin tener que commitear cada cosa.
Untracked file
Si creamos un archivo (archivo) y NO lo añadimos con git add, será un Untracked file, es decir, todavía no está incluido en el repositorio y no se guarda su cambio de versiones.
$: echo "Esto es un archivo" > archivo
$: git status # Untracked files: archivo.md
$: git add archivo.md
$: git status # Changes to be committed: new file: archivo
Ver informacion de cambios
El comando git status nos informa de los cambios que hemos hecho desde el ultimo commit. Nos permite saber si va a haber archivos que no se incluiran (Untracked) o si dara lugar algun tipo de conflicto.
Decidiremos asi que hay qe mover al staging area.
$: echo "Un cambio en el archivo" >> archivo
$: git status
# Changes to be committed: new file: archivo
# Changes not staged for commit: modified: archivo
$: git diff
# diff --git a/archivo.md b/archivo
# --- a/archivo
# +++ b/archivo
# Esto es un archivo
# +Un cambio en el archivo
Si tenemos "Untracked file" y queremos meterlos en el repo, es con git add y git commit
El git diff tambien nos permite ver cambios de ramas, commits, etc
| Uso | Comando |
|---|---|
| Ver que se ha actualizado en ese commit | git show <commit> |
| Ver que se ha actualizado hace dos commits | git show HEAD~2 |
Cambios desde el ultimo git add) |
git diff |
| Todos los cambios sin commitear | git diff HEAD |
| Cambios entre dos ramas | git diff main feature |
| Cambios entre dos commits | git diff <commit1> <commit2> |
Revertir cambios desde el ultimo commit
Podemos volver a un punto anterior con git checkout
$: echo "Otro cambio" >> archivo # Marcado como modified en git status
$: git diff # Se refleja "Otro cambio" en archivo
$: git checkout archivo.md # Elimina los cambios, se queda como estaba al committear
$: git diff # No sale nada
Revertir cambios a un commit anterior
Ahora, podemos tambien volver a como estaba todo en un commit anterior. Para ello hacemos git checkout a ese commit
$: git log --oneline
# 83bfe88 (HEAD -> master) Se anade un nuevo archivo
# 4d51fbd Creando el repositorio
$: git checkout 4d51fbd # Se elimina archivo.md
$: git checkout 83bfe88 # Volvemos a donde estabamos, se vuelve a crear el archivo
Git checkout por tanto sirve para viajar entre puntos de guardado, dos checkpoints, sin eliminar ningun dato
1.4. Gestionar los commits
Digamos que hemos trabajado bastante en nuestra carpeta y queremos ver los commits Para ver los commits hacemos:
$: git log
# commit 4d51fbd37fdda883e590350b9edd5109da17fc48 (HEAD -> master)
# Author: jessica-diaz <correo@mail.com>
# Date: Wed Sep 2 14:30:04 2026 -0400
# Creando el repositorio
# (...)
$: git log --oneline
# 8f71045 (HEAD -> master) Creando el repositorio
$: git log --author="jessica-diaz" # Ver los commits de un autor
$: git log -5 # Ver ultimos 5 commits
$: git log -- index.html # Ver que commits tocaron un archivo
Los commits se identifican por un hash. Ej: 4d51fbd37fdda883e590350b9edd5109da17fc48, aunque se suele representar solo el principio (4d51fbd). El último commit será el HEAD
2. Ramas
Al crear el repositorio, se creará la rama main (o master), que va a ser la linea principal de nuestro proyecto.
Branches
En el futuro se pueden crear ramas secundarias paralelas ("branches") para hacer desarollos paralelos de features que no afecten al código principal.
Si el equipo de desarollo ve que el codigo de una rama funciona y anade valor al proyecto, incorporara esos cambios al main y eliminara la bifurcacion, por que ya no tendra sentido. A eso se le llama merge.
Internamente una rama no es una copia del código, sino un puntero que apunta al hash SHA del commit mas reciente (archivo en .git/refs/heads/) .
La rama HEAD es el puntero que indica en que rama o commit está el "working dir" ahora mismo
| Uso | Comando |
|---|---|
| Crear una rama | git branch login |
| Cambiarse a esa rama | git switch login |
| Crear la rama y migrar a ella instantaneamente | git switch -c login |
2.1. Crear ramas
Por tanto, tenemos el repositorio y queremos crear una nueva funcionalidad. Hacemos algun commit sobre la nueva branch, que tendrá contenido diferente
$(main): git switch -c login # Creamos la rama de la funcionalidad del login
$(login): echo "Archivo de la branch login" > archivo_login
$(login): git add . && git commit -m "Commit de la branch login"
$(login): git switch main # No existe archivo_login porque es de la otra
Seguimos haciendo otro commit y queda así
E ←(HEAD) # login
/
A - B - C - D # main
2.2. Integrar cambios con merge
Ahora, si creamos un archivo en la main
$(main): echo "Archivo de la branch main" >> archivo_main
$(main): git add . && git commit -m "Commit de la branch main"
Ahora, digamos que queremos mezclar ambas ramas. Nos queremos traer un archivo de main a login pero sin afectar al resto de codigo.
$(login): git merge main
# En main -> archivo y archivo_login
# En login -> archivo, archivo_main y archivo_login
El diagrama es tal que así:
E - F ←(HEAD) # login
/
A - B - C - D # main
A que hacer merge
Si queremos traernos un archivo de la rama login a main es con git merge login dentro de main
Si queremos traernos un archivo de main a login es con git merge main dentro de login
Conflicto
Digamos que una persona trabaja en login
$(login): echo "login" >> archivo
$(login): git add archivo && git commit -m "Login: modifico archivo"
Y otra, trabaja en el mismo archivo en main
$(main): echo "main" >> archivo
$(main): git add archivo && git commit -m "Main: modifico archivo"
El diagrama es tal que así:
E - F - G # login
/
A - B - C - D - H # main
Por tanto, los de login quieren recibir las actualizaciones en la rama principal, pero encontramos el conflicto, ya que hay dos versiones paralelas del mismo archivo. Git no sabe que version priorizar.
$(login): git merge master # CONFLICT (content): Merge conflict in archivo
$(login): git status # both modified: archivo.md
Para resolver el problema se hace un nuevo commit con el archivo y se hace el merge de la version que queremos que se quede
$(login): git add archivo.md && git commit -m "Conflicto resuelto"
$(login): git merge main
$(login): cat archivo | tail -n 1 # main
2.3. Stash: Guardado temporal
Si hacemos un cambio en un archivo en la rama login pero no lo guardamos con git add, saldrá un error. No lo hemos querido commitear porque es código inacabado.
$(login): echo "Prueba" >> archivo
$(login): git switch master
# error: Your local changes to the following files would be overwritten by checkout:
# archivo.md
Para ello hacemos un git stash, que guarda ese cambio para la rama, sin llegar a hacer un commit.
$(login): git stash
$(login): git switch master
# Trabajamos
$(master): git switch login
$(login): git stash pop # Recuperamos lo del stash
Si en cambio queremos eliminar el stash es con git stash drop
2.4. Reintegrar rama
Si desde la rama principal integramos código de las ramas secundarias con git merge <rama_secundaria> y hemos hecho un commit, ya no necesitamos la rama secundaria. La caracteristica que hemos desarollado funciona bien y queremos que forme parte de nuestro código.
Por tanto destruimos la rama con git branch -d login. Al final la rama es un trabajo temporal que ya no cumple ninguna función
3. Repostorios remotos
Puede que el repositorio esté tambien en otro ordenador (en github o en el ordenador de otro compañero). A esto se le llama repositorio remoto
Primero añadimos emparejamos nuestro repositorio local con el remoto.
$: git remote add origin git@github.com:repositorio.git
Normalmente este repositorio se llama origin y se ve con git remote -v
$: git remote -v
# origin git@github-jessica:mi_proyecto/.git (fetch)
# origin git@github-jessica:mi_proyecto/.git (push)
3.1. Sincronizar cambios
Ahora, tenemos estos dos comandos para sincronizar con github:
$: git push origin main # Subir cambios a github
Si hemos editado con otro sistema o con github y la versión más moderna es la remota, debemos descargarlo en nuestro sistema
$: git pull origin main # Descargar cambios de github
Por otro lado tenemos git fetch , que simplemente descarga los cambios sin integrarlos en nuestra rama local. Esto es util para saber que ha ocurrido en el remoto y decidir si mezclarlo con el local o no.
3.2. Clonar un repo remoto
Si queremos descargar un repositorio remoto, se hace con git clone, incluyendo su historial.
git clone https://github.com/usuario/repo.git
git clone git@github.com:usuario/repo.git # via SSH
git clone https://... mi-carpeta # con nombre personalizado
git clone --depth 1 https://... # solo el último commit (shallow)
git clone --branch dev https://... # clonar una rama concreta
3.4. Fork
Si queremos trabajar con un repositorio de otra persona, se crea un fork o clon propio de el repositorio. Crea una versión propia independiente. Esto se realiza desde la web de github.
Además, podemos darle a sync fork para sincronizar cambios y actualizar el código.
Si queremos enviarle el cambio al desarollador original,