Control de versiones
Git y Git Hub
¿Qué es el control de versiones?
Registro de cambios
Sistema que registra cambios en archivos a lo largo del tiempo, permitiendo recuperar versiones anteriores.
Beneficios principales
  • Volver a versiones anteriores de archivos o proyectos completos.
  • Comparar cambios, identificar quién y cuándo modificó algo.
  • Recuperar archivos perdidos o dañados fácilmente.
Recuperación de archivos
Usar un VCS también significa generalmente que si fastidias o pierdes archivos, puedes recuperarlos fácilmente. Además, obtienes todos estos beneficios a un coste muy bajo.
No solo aplica a código fuente, sino también a otros tipos de archivos (ej. diseños gráficos).
Sistemas de control de versiones locales
Algunas personas realizan control de versiones manual copiando archivos a diferentes directorios (a veces con fechas para identificarlos).
Sin embargo, este método es:
  • Sencillo, pero propenso a errores (ej. sobrescribir archivos accidentalmente o perder versiones).
Para solucionarlo, surgieron los VCS locales, que:
  • Usan una base de datos para registrar cambios en los archivos.
  • Permiten un mejor seguimiento de las versiones sin depender de copias manuales.
Estos sistemas fueron un primer paso hacia herramientas más eficientes de control de versiones.
Sistemas de control de versiones centralizados (RCS)
Sistemas como CVS, Subversion y Perforce usan un servidor central que almacena todos los archivos, mientras los clientes descargan y envían cambios a él.
Fueron el estándar por años, pero su dependencia de un servidor único llevó luego al desarrollo de sistemas distribuidos como Git.
Ventajas
Colaboración mejorada
  • Todos los colaboradores conocen el estado del proyecto.
  • Evita conflictos al trabajar en archivos compartidos.
Control administrativo
  • Gestión de permisos por usuario.
  • Más fácil de administrar que múltiples bases de datos locales.
Desventajas
Punto único de fallo
  • Si el servidor central falla, se detiene toda la colaboración.
  • Pérdida total de datos si el disco se corrompe sin backups.
Dependencia del servidor
  • Sin conexión, no se pueden guardar cambios centralizados.
  • Similar al riesgo de los VCS locales (historia concentrada en un solo lugar).
Sistemas de control de versiones distribuído
Los sistemas como Git, Mercurial y Bazaar revolucionaron el control de versiones al distribuir el repositorio completo en cada copia local.
Ventajas
Resistencia
Si falla el servidor, cualquier copia local puede restaurar el proyecto
Flexibilidad
Cada desarrollador tiene un historial completo y puede trabajar offline
Colaboración avanzada
Permite múltiples flujos de trabajo y tipos de colaboración simultáneos
A diferencia de los sistemas centralizados, los DVCS permiten modelos de trabajo más dinámicos y descentralizados.
Este enfoque resolvió las limitaciones de los sistemas centralizados, dando más poder y autonomía a los desarrolladores.
¿Qué es GIT?
Software de control de versiones
Diseñado por Linus Torvalds, pensando en la eficiencia y la confiabilidad del mantenimiento de versiones de aplicaciones cuando éstas tienen un gran número de archivos de código fuente.
Creado el 17 de abril de 2005, ha tenido gran número de versiones desde entonces.
Características
  • Código abierto
  • Velocidad
  • Diseño sencillo
  • Gran soporte para desarrollo no lineal (miles de ramas paralelas)
  • Completamente distribuido
  • Capaz de manejar grandes proyectos
Propósito principal
Llevar registro de los cambios en archivos de computadora y coordinar el trabajo que varias personas realizan sobre archivos compartidos.
Fundamentos de Git
Esencia de Git:
• No es solo un VCS, es un sistema distribuido con filosofía única
• Requiere "desaprender" conceptos de SVN/Perforce para aprovecharlo plenamente
Diferencias clave:
✓ Almacenamiento inteligente: Guarda instantáneas (no solo cambios)
✓ Operación local: 90% de acciones no necesitan conexión
✓ Integridad de datos: Usa checksums (SHA-1) para todo registro
Por qué importa:
➤ Los errores comunes surgen de aplicar mentalidad centralizada
➤ Su modelo distribuido habilita flujos de trabajo imposibles en otros VCS
Instantáneas
Mientras otros VCS guardan cambios incrementales (deltas), Git almacena el estado completo del proyecto en cada commit, como una fotografía del sistema de archivos.
  • Cada commit contiene una copia completa (pero optimizada)
  • Archivos sin cambios se reutilizan mediante enlaces
  • Permite operaciones locales rápidas y ramificación eficiente
Almacenamiento de datos como cambios en una versión de la base de cada archivo.
Almacenamiento de datos como instantáneas del proyecto a través del tiempo.
Casi todas las operaciones son locales
Mientras otros sistemas (como SVN o Perforce) dependen constantemente del servidor, casi todas las operaciones en Git se ejecutan localmente usando tu repositorio completo.
Ventajas
Velocidad ultrarrápida
Acceso inmediato al historial completo y diferencias entre versiones
Trabajo offline
Puedes commitear, crear ramas y explorar el historial sin conexión
Independencia
No necesitas VPN ni conexión estable para trabajar productivamente
Tiene identidad
Git protege tus datos mediante hashes SHA-1 únicos:
  • Cada archivo y commit genera un checksum de 40 caracteres
  • Cualquier alteración cambia completamente el hash
  • Beneficios principales
Protección automática
Detecta cualquier corrupción o cambio no autorizado
Identificación precisa
Todo se referencia por su contenido (no por nombres)
Eficiencia
La misma estructura verifica datos al moverlos
Ejemplo práctico:
Si modificas 1 byte en un archivo antiguo:
  • Su hash SHA-1 cambiará completamente
  • Git invalidará todas las referencias asociadas
Nunca perderás trabajo por fallos de almacenamiento o transferencia sin que Git lo detecte.
Tres estados fundamentales
Estados de los archivos
Modificado (Modified)
Cambiado en el directorio de trabajo, pero no marcado para commit.
Preparado (Staged)
Añadido al staging area (índice) listo para el próximo commit.
Confirmado (Committed)
Almacenado permanentemente en el repositorio local (Git directory).
Áreas clave
Working Directory
Donde editas los archivos (copia actual del proyecto).
Staging Area (Índice)
Filtro para seleccionar qué cambios se incluirán en el commit.
Git Directory (.git)
  • Base de datos segura con toda la historia y metadatos.
Flujo de trabajo típico
1
Modificas archivos en el working directory → modified.
2
git add → Mueves cambios al staging area → staged.
3
git commit → Guardas en el repositorio local → committed.
Uso de Git
  • Línea de comandos (Terminal)
  • Control total: Acceso a todos los comandos y funciones de Git.
  • Transferible: Lo aprendido aplica a cualquier interfaz gráfica (pero no al revés).
  • Universal: Incluido en todas las instalaciones de Git (Mac/Linux/Windows).
  • Interfaz gráfica
Clientes gráficos vs. Terminal
Instalación de Git
Linux
  • Por defecto tiene una instalación de git pero esta no estará actualizada
  • Para actualizar la instalación de git: apt-get install git
Windows
Mac
  • Por defecto tiene una instalación de git pero esta no estará actualizada
A partir de aquí todos los comandos de Git funcionan igual en todas las plataformas
Comprobación de la instalación
Una vez instalado y ejecutado el bash de Git, desde la terminal introducir el comando:
git --version
De esta forma podemos saber la versión y si se ha instalado correctamente
Identificación en Git (Configuración inicial)
Git requiere tu nombre y email para identificar tus commits:
git config --global user.name "Tu Nombre" git config --global user.email "tu@email.com"
⚠️ Esta información queda grabada permanentemente en todos tus commits.
  • Global (--global): Aplica a todos tus repositorios (solo configurar una vez).
  • Por proyecto: Omite --global para sobrescribir la configuración en un repo específico.
Para ver/modificar tu configuración:
git config --list # Muestra toda la configuración
Para obtener ayuda sobre git, utiliza:
git help <comando>
Operaciones en Git
1
Inicialización
Crear un nuevo repositorio o clonar uno existente
2
Modificación
Realizar cambios en los archivos del proyecto
3
Preparación
Añadir archivos modificados al área de preparación
4
Confirmación
Guardar los cambios en el repositorio local
5
Sincronización
Compartir cambios con el repositorio remoto
Inicialización de un proyecto
1
Inicializa el repositorio
Para indicar que queremos realizar un control de versiones en un directorio:
git init
Esto crea un nuevo subdirectorio llamado .git que contiene todos los archivos necesarios del repositorio —un esqueleto de un repositorio Git.
Todavía no hay nada en tu proyecto que esté bajo seguimiento.
2
Añadir archivos al staging
Especifica qué archivos quieres controlar:
git add archivo1.java git commit –m 'versión inicial del proyecto
3
Confirmar lo cambios
En este paso es obligatorio indicar un mensaje descriptivo
Cada vez que se confirma se indica cual es la rama y el checksum asociado a ese commit, ya que cada vez que se hace uno se genera un nuevo código.
git commit -m "Primer commit: versión inicial del proyecto"
Añadiendo la opción -a al comando git commit harás que Git prepare automáticamente todos los archivos rastreados antes de confirmarlos, ahorrándote el paso de git add:
$ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: archivo1.java no changes added to commit (use "git add" and/or "git commit -a") $ git commit -a -m 'added new benchmarks' [master 83e38c7] added new benchmarks 1 file changed, 5 insertions(+), 0 deletions(-)
Resumen
  • git init: Crea la estructura .git para empezar a versionar
  • git add: Prepara los archivos para el commit (los añade al staging area)
  • git commit: Guarda permanentemente una "foto" de los archivos en ese estado
Estado de los archivos
Después de realizar esta pequeña práctica podemos deducir que los archivos tienen dos estados:
Tracked (Rastreados):
  • Archivos presentes en el último commit
  • Pueden estar:
  • Unmodified (Sin cambios)
  • Modified (Modificados)
  • Staged (Preparados para commit)
Untracked (No rastreados):
  • Archivos nuevos que Git no controla aún
  • No estaban en el último commit ni en el staging area
Ciclo de trabajo típico
Como ya hemos visto
  1. Modificas archivos → Modified
  1. git add → Mueves a Staged
  1. git commit → Guardas en el historial (Tracked - Unmodified)
Revisar el estado de un repositorio
git status
Es el comando diagnóstico más útil para entender el estado actual del trabajo.
Muestra el estado actual del repositorio, incluyendo:
  • Archivos rastreados (tracked) y no rastreados (untracked)
  • Cambios pendientes de commit
  • La rama actual y su estado respecto al repositorio remoto
Salidas típicas Directorio limpio
On branch master nothing to commit, working directory clean
Significado:
  • No hay archivos modificados
  • No hay archivos nuevos sin rastrear
Archivos no rastreados (ejemplo: README nuevo)
On branch master Untracked files: (use "git add ..." to include in what will be committed) README nothing added to commit but untracked files present
Significado:
  • Git detectó un archivo nuevo (README)
  • No se incluirá en commits hasta que se marque explícitamente con git add
  • Información clave Rama predeterminada: master (o main en repositorios nuevos)
Confirmar si la rama se ha sincronizado en archivos remotos
Flujo recomendado:
Usar git status frecuentemente para:
  • Verificar cambios antes de commits
  • Identificar archivos nuevos/modificados
Ejemplo de uso
# Crear archivo nuevo echo "Contenido" > archivo.txt # Ver estado git status # Muestra archivo.txt como "untracked" # Añadir al control de versiones git add archivo.txt git status # Ahora aparece listo para commit
Ignorar archivos
Es un archivo de texto que le indica a Git qué archivos o directorios no debe rastrear, evitando que se incluyan accidentalmente en commits.
Para ello, se crea un archivo llamado .gitignore, el cual debemos de editar para añadir los nombres de los ficheros o directorios que se deben de ignorar.
Casos comunes para ignorar archivos:
  • Archivos generados automáticamente (logs, caché, binarios).
  • Archivos temporales de editores (ej. *.swp, *~).
  • Dependencias (ej. node_modules/, __pycache__/).
  • Configuraciones locales o sensibles (ej. .env, *.key).
Sintaxis básica de .gitignore
Buenas prácticas
  • Crearlo al inicio del proyecto: Evita commits accidentales.
  • Usar patrones estándar: Como *.log o temp/.
  • Excluir lo necesario: Con ! (ej. !config.important).
Ejemplo de .gitignore
# Ignorar archivos de compilación *.o *.a # Excepción: un archivo específico !lib.a # Ignorar directorios build/ node_modules/ # Ignorar archivos temporales de editores *~ *.swp # Ignorar archivos de documentación generada doc/**/*.pdf
Importante
Git no ignora archivos ya rastreados. Para eliminarlos del repositorio:
git rm --cached archivo.txt
  • Las líneas que empiezan con # son comentarios.
  • Los cambios en .gitignore deben confirmarse con git add y git commit.
Utilidad
  • Mantiene el repositorio limpio: Sin archivos innecesarios.
  • Protege datos sensibles: Evita subir contraseñas o configuraciones locales.
  • Optimiza el espacio: Evita rastrear archivos generados automáticamente.
Visualización detallada de cambios
git diff
Muestra diferencias exactas entre versiones de archivos, permitiendo:
  • Ver modificaciones no preparadas (working directory vs staging area)
  • Ver cambios preparados (staging area vs último commit)
  • Comparar versiones específicas
Uso
Ejemplo práctico Situación
Editaste README.md y lo añadiste al staging (git add)
Luego modificaste CONTRIBUTING.md sin añadirlo
git status # Cambios para commit: # (usar "git restore --staged <file>..." para sacar del staging) # modified: README.md # # Cambios no preparados: # (usar "git add <file>..." para actualizar) # modified: CONTRIBUTING.md
Sirve para ver:
Cambios no preparados en CONTRIBUTING.md:
bash git diff
Cambios preparados en el README.md
bash git diff --staged
Todos los cambios pendientes:
bash git diff HEAD
Interpretación de la salida
La salida muestra:
  • Líneas eliminadas (prefijadas con -)
  • Líneas añadidas (prefijadas con +)
  • Contexto alrededor de los cambios (líneas sin prefijo)
  • Encabezado con rutas y metadatos
@@ -65,7 +65,8 @@ branch directly... Please include a nice description... if we have to read the whole diff... -merged in. +merged in. Also, split your changes... +longer than a dozen lines.
Importante
git diff sin parámetros no muestra cambios ya preparados
Para comparar entre commits específicos:
git diff commit1 commit2
Alternativa gráfica:
git difftool
Casos de uso típicos
  1. Antes de hacer commit:
  • Verificar exactamente qué se incluirá
  • Detectar cambios accidentales
  1. Durante conflictos:
  • Entender diferencias entre versiones
  1. Revisión de historial:
  • Comparar versiones antiguas
Eliminar archivos
Permite eliminar los archivos del respositorio
Eliminar archivos correctamente
Para quitar archivos del control de versiones:
git rm archivo.txt # Elimina del repositorio y del sistema de archivos git commit -m "Eliminado archivo.txt"
Diferencia con borrado manual
Si solo borras con rm archivo.txt:
  • Git lo detecta como "Change not staged for commit" (eliminación pendiente)
  • Requiere:
git add archivo.txt #o git rm archivo.txt git commit
Casos especiales
Ejemplo completo
# Eliminar directorio y su contenido git rm -r directorio/ git commit -m "Eliminado directorio/" # Quitar del repositorio pero mantener local git rm --cached config.ini git commit -m "Dejar de trackear config.ini"
Recuperación accidental
Si borraste un archivo importante:
git checkout HEAD -- archivo.txt # Recupera la última versión guardada
Importante
  • Usa git status para ver el estado de los borrados
  • La opción --cached es útil para archivos que deben ignorarse (como .env)
  • Git no permite borrar cambios no guardados sin -f (protección contra pérdidas)
Cambiar el nombre de los archivos
Git no rastrea explícitamente cambios de nombre, pero detecta automáticamente renombramientos mediante análisis de contenido. Esto ocurre cuando:
  • Un archivo desaparece (equivalente a git rm)
  • Un nuevo archivo aparece (equivalente a git add)
  • El contenido es similar
Métodos para renombrar
  • Comando dedicado (recomendado):
git mv archivo_viejo archivo_nuevo
  • Equivale a tres operaciones automáticas:
mv archivo_viejo archivo_nuevo # Renombra en disco git rm archivo_viejo # Elimina el nombre antiguo git add archivo_nuevo # Añade el nombre nuevo
  • Forma manual (alternativa):
mv archivo_viejo archivo_nuevo git rm archivo_viejo git add archivo_nuevo
Ejemplo práctico
# Caso 1: Uso de git mv git mv README.md LEEME.md # Caso 2: Proceso manual equivalente mv guia_usuario.pdf manual.pdf git rm guia_usuario.pdf git add manual.pdf
Verificación:
git status # Muestra: # renamed: README.md -> LEEME.md # renamed: guia_usuario.pdf -> manual.pdf
Importante
  • Git usa similitud de contenido (50%+ coincidencias) para detectar renombramientos
  • Funciona mejor con archivos de texto que binarios
  • El historial se mantiene intacto (los commits antiguos mostrarán el nombre original)
Usos
  • Para renombres complejos (múltiples archivos):
git add -A # Detecta automáticamente renombres
  • Si Git no detecta el renombre:
git mv -f archivo_viejo archivo_nuevo # Fuerza la detección
Historial de confirmaciones
git log
Muestra el historial de commits en orden cronológico inverso (más recientes primero), incluyendo:
  • Hash SHA-1 completo
  • Autor (nombre y email)
  • Fecha
  • Mensaje del commit
Este comando es esencial para auditorías de código, investigación de bugs y comprensión de la evolución del proyecto.
Formatos de visualización
Filtro avanzado
Ejemplos prácticos
  • Ver cambios recientes con detalles:
git log -p -3 # Muestra diferencias de los últimos 3 commits
  • Historial resumido con gráfico de ramas:
git log --oneline --graph --all
  • Buscar commits de un autor este mes:
git log --author="Juan" --since="1 month ago"
  • Cambios que afectan a una función:
git log -S"calcularTotal" --stat
Importante
  • Los hashes SHA-1 identifican commits de forma única
  • --since/--until aceptan formatos:
  • Relativos: "3 days ago"
  • Absolutos: "2023-05-01"
  • --grep busca en mensajes de commit (combinar con --all-match para AND lógico)
Deshacer cosas
Podemos deshacer acciones que hayamos realizado en git
Corregir el Último Commit
git commit --amend
Cuándo usarlo:
  • Olvidaste añadir archivos al commit
  • Te equivocaste en el mensaje del commit
  • Quieres combinar cambios nuevos con el commit anterior
Pasos:
# 1. Añade los archivos olvidados (si aplica) git add archivo_olvidado.py # 2. Reescribe el commit git commit --amend
Qué ocurre:
  • El archivo contiene el mensaje anterior
  • Al guardar, se reemplaza el último commit (mismo hash si solo cambia el mensaje)
Importante:
Para commits remotos (Ya lo veremos)
  • Nunca uses --amend en commits ya pusheados (rompe el historial compartido)
  • Para commits remotos, usa git revert + nuevo commit
Quitar Archivos del Staging
git reset HEAD
Cuándo usarlo:
  • Añadiste archivos accidentalmente con git add
  • Quieres dividir cambios en múltiples commits
Flujo detallado:
# 1. Ver estado actual git status # Muestra archivos en staging # 2. Quitar archivo específico git reset HEAD archivo_accidental.txt # Opción alternativa (todos los archivos) git reset HEAD .
Efecto:
  • Los cambios siguen en tu directorio de trabajo
  • El archivo vuelve a aparecer como "Changes not staged"
Ejemplo:
$ git status Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: script.js # ← Este queremos sacar $ git reset HEAD script.js $ git status Changes not staged for commit: (use "git add <file>..." to update what will be committed) modified: script.js # ← Ahora está fuera del staging
Descartar Cambios Locales
git checkout -- / git restore
Cuándo usarlo:
  • Experimentaste cambios no deseados
  • Quieres volver a la versión del último commit
Comandos equivalentes:
# Forma tradicional (aún válida) git checkout -- archivo_dañado.html # Versión moderna (Git 2.23+) git restore archivo_dañado.html
Advertencia crítica:
  • Esto borra permanentemente los cambios no commiteados
  • Alternativa segura:
git stash # Guarda cambios temporalmente git stash drop # Si decides eliminarlos después
Deshacer múltiples commits
git reset --hard
Escenario:
  • Hiciste 2-3 commits experimentales
  • Quieres volver a un estado anterior
Solución:
# 1. Ver historial (copiar hash objetivo) git log --oneline # 2. Retroceder (ej: 2 commits) git reset --hard HEAD~2
Efecto:
  • Elimina los últimos 2 commits del historial
  • Pérdida total de los cambios en working directory
Etiquetas en Git
Git permite etiquetar puntos importantes en el historial
Útil para marcar lanzamientos o hitos relevantes.
Listar Etiquetas
Muestra todas las etiquetas en orden alfabético.
git tag
Buscar etiquetas con patrones
git tag -l 'v1.8.5*'
Crear una etiqueta
git tag nombre_etiqueta
Ver detalles de una etiqueta
git show nombre_etiqueta
Eliminar una etiqueta
git tag -d nombre_etiqueta
Alias en Git
Se usa para conseguir atajos para comandos largos o frecuentes en Git.
Personalizan la CLI para hacerla más eficiente y fácil de usar.
Crear Alias
git config --global alias.<nombre-corto> "<comando-original>"
Ejemplos comunes
git config --global alias.co checkout # git co git config --global alias.br branch # git br git config --global alias.ci commit # git ci git config --global alias.st status # git st
Ejemplo práctico
# Crear alias para ver historial simplificado git config --global alias.lg "log --oneline --graph --all" # Uso: git lg # Muestra el historial en formato resumido.
Ventajas
  • Ahorra tiempo en comandos repetitivos.
  • Reduce errores al teclear menos.
  • Personalización para flujos de trabajo específicos.
Para listar los alias actuales
git config --global --list | grep alias
Creando nuestro primer respositorio
Crea una carpeta en llamada "Hola Git"
Desde la línea de comando nos situamos en esa carpeta e inicializamos Git
git init
Podemos ver como se crea la carpeta oculta .git dentro del directorio "Hola Git"
La rama inicial se llama master como indica el archivo anterior, pero su tendencia es a cambiar su nombre a "main"
Podemos hacerlo con el siguiente comando:
git branch -m main
En todo momento podemos ver el estado de nuestro Git usando
git status
En este momento del proyecto estará así:
Indica que estamos en la rama "main". Que no se ha confirmado ningún archivo
Ahora vamos a crear un archivo de texto en su interior que se llame git1.py
Comprobamos el estado
En este caso, nos indica que hay un archivo nuevo pero que no se ha añadido ni comiteado.
Cuando es así aparece el archivo en rojo
Procedemos a añadir el archivo
git add git1.py
Comprobamos de nuevo el estado
Ahora vemos que se ha añadido el archivo porque aparece en verde, pero no se ha confirmado, de ahí que aparezca que no hay commits
A continuación lo confirmamos
git commit -m "comentario"
Comprobamos de nuevo el estado y me indica que no hay nada pendiente
Si queremos comprobar el código hash asignado y las ramas usamos
git log
Modifica git1.py, añade y confirma los cambios
Ahora hay dos versiones
Crear archivo .gitignore
Añade los archivo que quieras dentro de .gitignore
Comprobar .gitignore y añadir al commit
Comprobamos el log
Mirar las diferencias del archivo git1.py
Modifica git1.py
Usa el comando git diff
Añade un directorio temporal
Elimina el archivo temporal
Renombrar un archivo
Deshacer cambios
Puede verse como el archivo vuelve a su estado original:
Ramificaciones en Git
Los sistemas de control de versiones modernos permiten trabajar con ramas.
Una rama es una línea de desarrollo independiente que surge a partir de la rama principal (generalmente master o main).
En otros sistemas, crear ramas puede ser costoso (requiere copiar todo el código), pero en Git es rápido y eficiente.
Ventajas de Git en el manejo de ramas
  • Rapidez: Crear, cambiar y fusionar ramas es casi instantáneo.
  • Flujo de trabajo flexible: Git fomenta el uso frecuente de ramas (incluso varias veces al día).
  • Potencia: Permite experimentar sin afectar la rama principal.
¿Qué es una rama en Git?
Git almacena datos como instantáneas (snapshots) en lugar de diferencias.
Una rama en Git es simplemente un apuntador móvil que señala a un commit específico.
Cada commit guarda:
  • Una copia de los archivos (blobs).
  • Un árbol (tree) que referencia los archivos y su estructura.
  • Metadatos (autor, mensaje) y un apuntador al commit anterior.
Rama por defecto: Al inicializar un repositorio (git init), Git crea automáticamente la rama master (o main en repositorios nuevos).
  • No tiene nada de especial, es igual que cualquier otra rama.
  • Su uso común se debe a que es la rama predeterminada, no a una diferencia técnica.
  • Con el primer commit, la rama master apunta a ese commit.
  • Cada nuevo commit mueve automáticamente el apuntador de la rama hacia adelante.
Crear una nueva rama en Git
Git crea un nuevo apuntador que señala al mismo commit actual.
Ejemplo:
git branch testing # Crea la rama "testing"
No cambia tu rama actual, solo añade un nuevo puntero.
Qué pasa con el puntero HEAD
Indica la rama actual en la que estás trabajando.
git branch solo crea la rama, pero no mueve HEAD (sigues en la misma rama).
Ver ramas y commits
Usa git log --oneline --decorate para ver:
  • Dónde apunta cada rama.
  • Cuál es el commit actual (HEAD).
Ejemplo de salida:
f30ab (HEAD, master, testing) add feature #32 34ac2 fixed bug #1328 98ca9 initial commit
Aquí, tanto master como testing apuntan a f30ab, pero HEAD indica que estás en master.
Cambiar entre ramas
Para moverse a otra rama, se usa:
git checkout <rama> # Ejemplo: `git checkout testing`
Si se hace un commit, la rama HEAD, avanza sobre la rama en la que nos encontramos, si no hemos hecho ningún cambio, será sobre master o main
Esto mueve el puntero HEAD a la rama especificada.
Después de esto, vemos que la rama testing avanza, mientras que la rama master permanece en la última confirmación creada.
Si volvemos a master con:
git checkout master # Vuelve a `master` git commit -a -m "otros cambios" # Ahora `master` y `testing` tienen historiales distintos
Esto produce dos acciones:
  1. Mueve el puntero HEAD a la rama master
  1. Restaura los archivos del directorio de trabajo a su estado en el último commit de master
Efectos
Es como un "rebobinado" temporal del proyecto
  • Se deja una línea de trabajo (testing)
  • Se retoma otra línea diferente (master)
  • Ambas ramas pueden evolucionar independientemente (Al hacer commit en testing, solo esa rama avanza; master permanece donde estaba)
  • Al alternar entre ramas y hacer commits, el historial se bifurca.
Implicaciones:
  1. Git maneja automáticamente estos cambios de estado
  1. Si hay conflictos, Git previene el cambio para evitar pérdida de trabajo
  1. Cada rama mantiene su propio historial de cambios intacto
Visualización del historial divergente
Se usa git log con opciones para ver ramas y divergencias:
git log --oneline --decorate --graph --all
  • Muestra commits, ramas y cómo se separan.
  • Ejemplo de salida:
* c2b9e (HEAD,master) otros cambios | * 87ab2 (testing) un cambio |/ * f30ab commit anterior * 34ac2 * 98ca9
Ventajas de las ramas en Git
  • Creación y eliminación instantánea:
  • Una rama es solo un archivo pequeño (40 bytes) que apunta a un commit SHA-1.
  • No requiere copiar todo el proyecto (a diferencia de otros sistemas como SVN o CVS).
  • Fusión sencilla:
  • Git rastrea automáticamente los commits padres, facilitando merges.
  • Flujo de trabajo flexible:
  • Permite experimentar en ramas aisladas y alternar entre ellas sin costo.
Conclusión
Git incentiva el uso frecuente de ramas gracias a su rapidez y eficiencia.
  • Comandos
  • git branch: Crear ramas.
  • git checkout: Moverse entre ramas.
  • git commit: Avanzar el historial.
  • git log --graph Visualiza el historial para entender la divergencia.
Procesos básicos de ramificación
Escenario práctico
Situación Inicial
Partimos de un historial lineal con algunos commits en master
Crear una Rama para un Nuevo Issue (#53)
Comando rápido para crear y cambiar a la rama iss53:
git checkout -b iss53 # Equivalente a: git branch iss53 + git checkout iss53
Aparece un nuevo puntero iss53 en el mismo commit que master
Trabajar en la Rama iss53
Realizar cambios y commits:
git commit -a -m 'added a new footer [issue 53]'
La rama iss53 avanza, mientras master se queda atrás
Problema Crítico (Hotfix)
Cambiar a master para resolverlo:
git checkout master # ¡El directorio de trabajo revierte al estado de `master`!
  • Importante: Git no permite cambiar de rama si hay cambios sin commit (conflictos potenciales).
Resolver el problema
Crear rama hotfix y solucionar el problema:
git checkout -b hotfix git commit -a -m 'fixed the broken email address'
La rama hotfix avanza desde master
Fusionar hotfix en master
Fusión rápida (fast-forward):
git checkout master git merge hotfix # Git mueve `master` al mismo commit que `hotfix`
  • Fast-forward: Ocurre cuando no hay divergencias (la rama a fusionar está directamente adelante).
Una vez resuelto el problema
Eliminar hotfix (ya no es necesaria):
git branch -d hotfix
Retomar el Trabajo en iss53: Volver a la rama original y continuar:
git checkout iss53 git commit -a -m 'finished the new footer [issue 53]'
iss53 sigue su curso independiente de master
Procesos básicos de fusión
Fusión Simple (Fast-Forward)
Ejemplo previo: La rama hotfix se fusionó con master mediante un fast-forward, ya que no había divergencias .
Qué ocurre cuando hay conflicto?
Causa:
Modificaciones contradictorias en el mismo archivo en ambas ramas.
Auto-merging index.html CONFLICT (content): Merge conflict in index.html
Solución:
  1. Identificar conflictos con git status (archivos marcados como "unmerged").
  1. Editar manualmente los archivos conflictivos, donde Git inserta marcadores:
<<<<<<< HEAD:index.html <!-- Versión en master --> <div id="footer">contact : email.support@github.com</div> ======= <div id="footer"> <!-- Versión en iss53 --> please contact us at support@github.com </div> >>>>>>> iss53:index.html
3. Resolver eligiendo un cambio o combinando ambos, eliminando los marcadores.
4. Marcar como resuelto y completar la fusión:
git add index.html # Marca el conflicto como resuelto git commit # Finaliza el merge commit
Herramientas Gráficas para Conflictos
Ejecutar git mergetool para abrir una herramienta visual (ej.: meld, kdiff3).
Tras resolver, Git marca los archivos como "staged" y permite completar el commit.
Eliminar la Rama Fusionada
Una vez fusionado iss53, eliminarla:
git branch -d iss53
Gestión de ramas: Comandos
Listado de Ramas
git branch
Muestra todas las ramas locales.
El asterisco (*) indica la rama actual (donde está HEAD).
Ver Último Commit por Rama
git branch -v
Ejemplo de salida:
iss53 93b412c fix javascript issue * master 7a98805 Merge branch 'iss53' testing 782fd34 add scott to the author list
Filtrar Ramas Fusionadas/No Fusionadas
Ramas ya fusionadas con la rama actual:
git branch --merged
  • Uso práctico: Identifica ramas que pueden eliminarse sin perder trabajo (ej.: iss53 ya fusionada).
Ramas con trabajo no fusionado:
git branch --no-merged
  • Importante: Git bloquea su eliminación con git branch -d para evitar pérdida de cambios.
Eliminación de Ramas
Eliminar ramas fusionadas (seguro):
git branch -d iss53 # Elimina solo si está fusionada
Forzar eliminación (pérdida de cambios):
git branch -D testing # Ignora advertencias
  • Útil para descartar experimentos fallidos.
Buenas Prácticas
Mantener limpio el repositorio:
  • Eliminar ramas fusionadas para reducir ruido.
Verificar estado antes de eliminar:
  • Usar --merged/--no-merged para evitar errores.
Ejemplo de flujo
  1. Listar ramas:
git branch -v
2. Filtrar no fusionadas:
git branch --no-merged
3. Eliminar rama segura:
git branch -d iss53
4. Forzar eliminación si es necesario:
git branch -D testing
Resumen de comandos
Resumen de ramificación
Escenario práctico para comprender la ramificación
Trabajo inicial:
  • Estás desarrollando un sitio web en la rama principal (ej. main o master).
Nueva funcionalidad:
  • Creas una rama para un nuevo tema:
git branch nueva-funcionalidad git checkout nueva-funcionalidad
  • Trabajas en los cambios necesarios.
Problema crítico:
  • Recibes un reporte de un bug urgente que debe resolverse inmediatamente.
Manejo del bug:
  • Vuelves a la rama de producción:
git checkout main
  • Creas una rama para la corrección:
git checkout -b hotfix-bug
  • Trabajas en la solución, pruebas y confirmas los cambios:
git commit -m "Solución al bug crítico"
Fusión:
  • Fusionas la corrección a la rama principal:
git checkout main git merge hotfix-bug
Retomar el trabajo:
  • Regresas a tu rama original para continuar con la nueva funcionalidad:
git checkout nueva-funcionalidad
Beneficios de este Flujo
Aislamiento de cambios:
  • El trabajo en la nueva funcionalidad no se ve afectado por la corrección urgente.
Respuesta rápida a problemas:
  • Puedes atender bugs críticos sin comprometer el trabajo en progreso.
Organización clara:
  • Cada tarea tiene su propia rama, facilitando el seguimiento y la colaboración.
  • Este flujo permite manejar múltiples tareas simultáneamente, manteniendo un historial limpio y facilitando la colaboración en equipo.
Comandos
Git en el Servidor
Importancia del repositorio remoto
Colaboración: Necesario para trabajar en equipo, evitando confusiones al compartir cambios directamente entre individuos.
Acceso permanente: Permite a colaboradores acceder al código incluso cuando tu computadora está offline.
Configuración básica Repositorio básico
No tiene directorio de trabajo (solo contiene datos internos de Git, equivalentes al directorio .git).
Funciona como punto centralizado para push y pull (subir y descargar del repositorio)
Protocolos soportados
Local
Sistemas de archivos compartidos (ej: NFS o mismo equipo).
git clone /opt/git/project.git # Sin prefijo (usa hardlinks) git clone file:///opt/git/project.git # Con prefijo (más lento)
Ventajas:
  • Simplicidad y permisos de archivos existentes.
Desventajas:
  • Acceso remoto complicado (requiere montar discos) y menor velocidad en NFS vs SSH.
Protocolo SSH
Conexión segura a servidores remotos mediante SSH (el más común para repositorios privados).
git clone ssh://user@server:/ruta/project.git # Formato explícito git clone user@server:/ruta/project.git # Formato abreviado
Ventajas:
  • Seguridad: Encriptación integral (autenticación y transferencia de datos).
  • Facilidad de acceso remoto: No requiere montar sistemas de archivos.
  • Permisos: Usa cuentas de usuario del servidor (control granular con claves SSH).
  • Eficiencia: Protocolo optimizado para transferencia de datos (similar en velocidad a local).
Desventajas:
  • Configuración inicial: Requiere gestionar claves SSH y acceso de usuarios.
  • Acceso anónimo: No es adecuado para repositorios públicos (obliga a tener cuenta SSH).
Protocolo HTTP/HTTPS
Ideal para repositorios públicos o con autenticación básica (ej: GitHub, GitLab).
git clone http://example.com/ruta/project.git # Sin encriptar git clone https://example.com/ruta/project.git # Con encriptación SSL
Ventajas:
  • Acceso universal: Funciona detrás de firewalls/proxies (puertos 80/443 abiertos).
  • Autenticación flexible: Compatible con sistemas como OAuth o LDAP (vía HTTPS).
  • Repositorios públicos: Permite clonar sin credenciales (solo lectura).
  • Fácil despliegue: Usa servidores web estándar (Apache, Nginx).
Desventajas:
  • Rendimiento: Más lento que SSH o local (overhead de HTTP).
  • Autenticación básica: En HTTP, credenciales viajan en texto plano (HTTPS es obligatorio para seguridad).
  • Complejidad en push: Requiere configuración adicional (WebDAV o Smart HTTP).
Git Hub
GitHub es una plataforma de desarrollo colaborativo en la nube que permite gestionar proyectos de software utilizando Git. Ofrece herramientas para:
  • Alojar repositorios de código.
  • Realizar seguimiento de cambios.
  • Colaborar mediante pull requests y issues.
  • Gestionar flujos de trabajo con integración continua y despliegue automático.
Cambio de "master" a "main"
GitHub modificó el nombre predeterminado de la rama principal de master a main como parte de una iniciativa para promover un lenguaje más inclusivo.
Motivación: Evitar connotaciones negativas asociadas a "master" (en contextos históricos de esclavitud).
Impacto: Otras plataformas también adoptaron términos neutrales, aunque Git internamente aún usa "master" en algunos comandos.
Creación de un repositorio
Antes de empezar, es necesario crear un repositorio (local o remoto en GitHub) para gestionar el código.
Usaremos VS Code para trabajar con GitHub.
Repositorios públicos o privados
Configuración Inicial del Repositorio
Tres elementos clave al crear un repositorio en GitHub:
  1. README.md
  • Función: Documentación principal del proyecto (propósito, instalación, uso).
  • Formato: Markdown (.md). Se muestra automáticamente en la página del repositorio.
  • Importancia: Primera impresión para colaboradores/visitantes.
  1. .gitignore
  • Función: Excluir archivos no relevantes (ej: temporales, binarios) del control de versiones.
  • Ventaja: Mantiene el repositorio limpio y evita subir archivos innecesarios.
  1. Licencia
  • Objetivo: Define términos legales para usar/modificar/distribuir el código.
  • Opciones comunes:
  • MIT: Libre uso (requiere atribución).
  • GPL: Código derivado debe ser open-source bajo misma licencia.
  • Apache: Similar a MIT, pero con cláusulas adicionales de patentes.
En este caso, se configurará el repositorio con:
  • Un README.md básico (formato Markdown).
  • Archivo .gitignore para excluir archivos generados automáticamente (ej: node_modules/, .env).
  • Licencia MIT (permisiva y ampliamente adoptada).
Pasos para configurar un repositorio local y sincronizarlo con GitHub
1. Crear el archivo README.md
echo "# cursoGit" >> README.md
Crea un archivo README.md con el texto # cursoGit (formato Markdown).
2. Inicializar el repositorio Git
git init
Crea un directorio oculto .git con la estructura necesaria para el control de versiones.
3. Agregar el README al área de staging
git add README.md
Prepara el archivo para ser incluido en el primer commit.
4. Realizar el primer commit
git commit -m "first commit"
Guarda los cambios en el historial del repositorio con un mensaje descriptivo.
5. Renombrar la rama principal a main (opcional)
git branch -M main
Cambia el nombre de la rama predeterminada de master a main (práctica recomendada).
6. Vincular el repositorio local con GitHub
git remote add origin https://github.com/martin2745/cursoGit.git
Asocia el repositorio local con el remoto usando el alias origin (nombre convencional).
7. Subir cambios al repositorio remoto
git push -u origin main
Envía los commits a GitHub y establece main como rama predeterminada para futuros push.
Conceptos clave
  • origin: Es el nombre por defecto que Git asigna al repositorio remoto. Simplifica futuros comandos como git push o git pull.
  • Eliminar ramas locales no necesarias: Elimina ramas locales que ya no se usen (ej: ramas de prueba).
git branch -d nombreRama
Nota: Estos pasos son esenciales para comenzar un proyecto bajo control de versiones y colaborar mediante GitHub. La opción -u en git push evita especificar la rama remota en futuras actualizaciones.
Secciones clave de un repositorio en GitHub
Wiki vs README:
  • El README.md es la carta de presentación del repositorio.
  • La Wiki alberga documentación extensa (ej: manuales de usuario).
Estas herramientas facilitan la colaboración, automatización y mantenimiento de proyectos en GitHub. La pestaña Settings es crítica para gestionar permisos y seguridad.
Opciones para clonar un repositorio (Botón "Code")
HTTPS
  • Proporciona una URL para clonar el repositorio mediante el protocolo HTTPS.
git clone https://github.com/usuario/repositorio.git
  • Ventajas:
  • Funciona sin configuración adicional.
  • Ideal para principiantes o acceso rápido.
SSH
  • Ofrece una URL para clonar usando autenticación con claves SSH.
  • Requisitos:
  • Uso:
git clone git@github.com:usuario/repositorio.git
  • Ventajas:
  • Mayor seguridad (encriptación).
  • No requiere ingresar credenciales repetidamente.
Descargar ZIP
  • Permite descargar el código fuente como archivo ZIP.
  • Limitaciones:
  • No mantiene el historial de Git.
  • No permite actualizaciones posteriores con git pull.
Visualización de commits
Clic en "Commits" en la interfaz de GitHub.
  • Funcionalidades:
  • Historial completo: Lista ordenada de todos los commits.
  • Detalles por commit:
  • Cambios realizados (diff).
  • Autor y fecha.
  • Mensaje del commit.
  • Ejemplo: Al inspeccionar el commit "Conflicto solucionado", se pueden ver:
  • Archivos modificados.
  • Líneas específicas añadidas/eliminadas.
Hacer un commit desde GitHub
Vamos a modificar README.md y después hacemos un commit
Ahora tenemos dos commits
Es importante mencionar que estas modificaciones tenemos que añadirlas a nuestro repositorio local ya que en este momento solo existe en remoto.
Para ello empleamos el comando:
git pull
Cargar y descargar de GitHub
1. Traer cambios del remoto sin fusionar automáticamente con el local
  • Sincroniza información remota sin modificar el código local.
  • Verifica diferencias entre tu rama local y la remota antes de fusionar (git diff).
  • Es seguro: No altera tu historial ni tus archivos de trabajo.
git fetch <remoto> <rama>
  • <remoto>: Nombre del repositorio remoto (usualmente origin).
  • <rama>: Rama específica a descargar (opcional).
Ejemplos:
Descargar todos los cambios del remoto:
git fetch origin
Descargar cambios de una rama específica (ej: main):
git fetch origin main
2. Traer cambios del remoto fusionando con el local
Descarga los últimos cambios del repositorio remoto y los fusiona con tu rama local.
git pull <remoto> <rama>
  • <remoto>: Generalmente origin (el nombre por defecto del repositorio remoto).
  • <rama>: La rama que quieres actualizar (ej: main, develop).
Ejemplo
git pull origin main
  • Descarga los cambios de la rama main del remoto origin y los fusiona con tu rama local actual.
Opciones:
3. Enviar cambios al remoto
Sube tus commits locales al repositorio remoto.
git push <remoto> <rama>
  • <remoto>: Normalmente origin.
  • <rama>: La rama que quieres subir (ej: main, feature/login).
Ejemplo
git push origin main
  • Sube los commits de tu rama local main al repositorio remoto (origin).
Opciones:
Resumen de Flujo de Trabajo
1. Antes de trabajar:
git pull origin main # Actualiza tu repositorio local.
2. Después de hacer cambios:
git add . # Añade los cambios al staging. git commit -m "Mensaje" # Crea un commit. git push origin main # Sube los cambios al remoto.
Posibles Errores y Soluciones
! [rejected] main -> main (non-fast-forward)
  • Causa: El remoto tiene cambios que no tienes localmente.
  • Solución:
git pull origin main # Fusiona los cambios primero. git push origin main # Vuelve a intentar el push.
fatal: The current branch has no upstream branch
  • Causa: No has configurado la rama remota.
  • Solución:
git push -u origin main # Establece upstream.
Resumiendo…
  • git pull → Actualiza tu repositorio local con cambios remotos.
  • git push → Envía tus cambios locales al repositorio remoto.
  • git fetch → Ideal para flujos de trabajo colaborativos donde la revisión de código es fundamental.
  • Siempre haz pull antes de push para evitar conflictos.
Si trabajas en equipo, evita --force para no romper el historial de tus compañeros.
Clonar un repositorio
Clonar repositorio
Puedes clonar un repositorio con git clone [url]:
git clone git://github.com/schacon/grit.git
Crear directorio
Esto crea un directorio llamado "grit", inicializa un directorio .git en su interior, descarga toda la información de ese repositorio, y saca una copia de trabajo de la última versión.
Personalizar nombre
Si quieres clonar el repositorio a un directorio con otro nombre que no sea grit, puedes especificarlo con la siguiente opción de línea de comandos:
git clone git://github.com/schacon/grit.git mygrit
Práctica guiada de GitHub
Objetivo: Practicar comandos básicos de Git (clone, add, commit, push, pull, fetch) y familiarizarte con GitHub.
Crear un repositorio en GitHub
  1. Ve a GitHub y haz clic en "New repository".
  1. Nómbralo mi-primer-proyecto.
  1. Elige público y marca la opción "Add a README.md".
  1. Haz clic en "Create repository".
Clonar el repositorio a tu máquina local
git clone https://github.com/tu-usuario/mi-primer-proyecto.git cd mi-primer-proyecto
Hacer cambios locales y subirlos a GitHub
Crea un archivo hola-mundo.txt:
echo "¡Hola, GitHub!" > hola-mundo.txt
Añádelo al área de staging y haz un commit:
git add hola-mundo.txt git commit -m "Añadir archivo de saludo"
Súbelo a GitHub:
git push origin main
Simular un cambio externo (en GitHub)
  1. Ve a tu repositorio en GitHub.
  1. Edita el README.md directamente en GitHub (añade una línea como ## Este es mi primer proyecto).
  1. Guarda los cambios (haz clic en "Commit changes").
Sincronizar cambios locales con GitHub
Descarga los cambios remotos (sin fusionar aún):
git fetch origin
Compara diferencias entre tu rama local y la remota:
git diff main origin/main
Fusiona los cambios en tu repositorio local:
git pull origin main
Resolver un conflicto (opcional avanzado)
Edita localmente el README.md (añade algo como ### Hecho desde mi computadora).
Haz commit:
git add README.md git commit -m "Editar README localmente"
Antes de hacer push, edita el mismo archivo desde GitHub (cambia la misma línea).
Intenta hacer git push origin main. Verás un error.
Resuelve el conflicto:
git pull origin main # Fusiona los cambios y marca conflictos. # Edita README.md manualmente (elimina marcas de conflicto <<<<<<<). git add README.md git commit -m "Resolver conflicto en README" git push origin main
Trabajar con ramas
Crea una rama nueva:
git checkout -b nueva-rama
Añade un archivo contribucion.txt y haz push de la rama:
git push origin nueva-rama