Capítulo 1. Introducción a Git Introducción a Git

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

En pocas palabras, Git es un rastreador de contenidos. Dada esa noción, Git comparte los principios comunes de la mayoría de los sistemas de control de versiones. Sin embargo, la característica distintiva que hace único a Git entre la variedad de herramientas disponibles hoy en día es que se trata de un sistema de control de versiones distribuido. Esta distinción significa que Git es rápido y escalable, tiene una rica colección de conjuntos de comandos que proporcionan acceso a operaciones de alto y bajo nivel, y está optimizado para operaciones locales.

En este capítulo aprenderás los principios fundamentales de Git, sus características y los comandos básicos de git, y recibirás algunas orientaciones rápidas para crear y añadir cambios a un repositorio.

Te recomendamos encarecidamente que dediques tiempo a comprender los conceptos importantes que aquí se explican. Estos temas son los cimientos de Git y te ayudarán a comprender las técnicas intermedias y avanzadas para gestionar un repositorio Git como parte de tu trabajo diario. Estos conceptos fundamentales también te ayudarán a acelerar tu aprendizaje cuando desglosemos el funcionamiento interno de Git en los capítulos agrupados en la Parte II, "Fundamentos de Git", la Parte III, "Habilidades intermedias", y la Parte IV, "Habilidades avanzadas".

Componentes Git

Antes de sumergirnos en el mundo de los comandos de git, demos un paso atrás y visualicemos una visión general de los componentes que forman el ecosistema Git. La Figura 1-1 muestra cómo funcionan juntos los componentes.

Las herramientas GUI de Git actúan como una interfaz para la línea de comandos de Git, y algunas herramientas tienen extensiones que se integran con las plataformas de alojamiento de Git más populares. Las herramientas cliente Git trabajan principalmente en la copia local de tu repositorio.

vcg3 0101
Figura 1-1. Visión general de los componentes de Git

Cuando trabajas con Git, una configuración típica incluye un servidor Git y clientes Git. Posiblemente puedas prescindir de un servidor, pero eso añadiría complejidad a la forma de mantener y gestionar repositorios cuando compartes cambios de revisión en una configuración colaborativa y dificultaría la coherencia (volveremos sobre esto en el Capítulo 11). El servidor y los clientes Git funcionan de la siguiente manera:

Servidor Git

Un servidor Git te permite colaborar más fácilmente en porque garantiza la disponibilidad de una fuente central y fiable de la verdad para los repositorios en los que vas a trabajar. Un servidor Git es también donde se almacenan tus repositorios Git remotos; como es práctica común, el repositorio tiene la fuente más actualizada y estable de tus proyectos. Tienes la opción de instalar y configurar tu propio servidor Git, o puedes renunciar a los gastos generales y optar por alojar tus repositorios Git en sitios de alojamiento de terceros fiables, como GitHub, GitLab y Bitbucket.

Clientes Git

Los clientes Git interactúan con tus repositorios locales, y puedes interactuar con los clientes Git a través de la línea de comandos Git o de las herramientas GUI Git. Cuando instales y configures un cliente Git, podrás acceder a los repositorios remotos, trabajar en una copia local del repositorio y enviar los cambios al servidor Git. Si eres nuevo en Git, te recomendamos que empieces utilizando la línea de comandos de Git; familiarízate con el subconjunto común de comandos git necesarios para tus operaciones cotidianas y, a continuación, avanza hacia la herramienta Git GUI de tu elección.

La razón de este enfoque es que, hasta cierto punto, las herramientas GUI de Git tienden a proporcionar terminologías que representan un resultado deseado que puede no formar parte de los comandos estándar de Git. Un ejemplo sería una herramienta con una opción llamada sync, que enmascara el encadenamiento subyacente de dos o más comandos git para lograr un resultado deseado. Si por alguna razón introdujeras el subcomando sync en la línea de comandos, podrías obtener esta salida confusa:

$ git sync

git: 'sync' is not a git command. See 'git --help'.

The most similar command is
       svn
Nota

git sync no es un subcomando válido de git. Para asegurarte de que tu copia de trabajo local del repositorio está sincronizada con los cambios del repositorio Git remoto, tendrás que ejecutar una combinación de estos comandos: git fetch, git merge, git pull, o git push.

Hay una plétora de herramientas a tu disposición. Algunas herramientas Git GUI son extravagantes y extensibles mediante un modelo de plug-in que te ofrece la opción de conectar y aprovechar funciones disponibles en populares sitios de alojamiento Git de terceros. Por muy cómodo que sea aprender Git mediante una herramienta GUI, nos centraremos en la herramienta de línea de comandos Git para los ejemplos y las discusiones sobre el código, ya que así se construyen unos buenos conocimientos básicos que conducirán a la destreza con Git.

Características de Git

Ahora que hemos dado una visión general de los componentes de Git, vamos a conocer las características de Git. Comprender estos rasgos distintivos de Git te permite cambiar sin esfuerzo de una mentalidad de control de versiones centralizado a una mentalidad de control de versiones distribuido. Nos gusta referirnos a esto como "Pensar en Git":

Git almacena los cambios de revisión como instantáneas

El primer concepto que hay que desaprender es la forma en que Git almacena las múltiples revisiones de un archivo en el que estás trabajando. A diferencia de otros sistemas de control de versiones, Git no rastrea los cambios de revisión como una serie de modificaciones, comúnmente conocidas como deltas; en su lugar, toma una instantánea de los cambios realizados en el estado de tu repositorio en un momento concreto. En la terminología de Git esto se conoce como una confirmación. Piensa en esto como capturar un momento en el tiempo, como a través de una fotografía.

Git se potencia para el desarrollo local

En Git, trabajas en una copia del repositorio en tu máquina de desarrollo local. Esto se conoce como repositorio local, o un clon del repositorio remoto en un servidor Git. Tu repositorio local tendrá los recursos y las instantáneas de los cambios de revisión realizados en esos recursos, todo en una ubicación. Git denomina a estas colecciones de instantáneas enlazadas historial de confirmaciones del repositorio, o historial del repositorio para abreviar. Esto te permite trabajar en un entorno desconectado, ya que Git no necesita una conexión constante con el servidor Git para controlar las versiones de tus cambios. Como consecuencia natural, puedes trabajar en proyectos grandes y complejos en equipos distribuidos sin comprometer la eficacia y el rendimiento de las operaciones de control de versiones.

Git es definitivo

Definitivo significa que los comandos de git son explícitos. Git espera a que le des instrucciones sobre qué hacer y cuándo hacerlo. Por ejemplo, Git no sincroniza automáticamente los cambios de tu repositorio local con el repositorio remoto, ni guarda automáticamente una instantánea de una revisión en el historial de tu repositorio local. Cada acción requiere tu comando o instrucción explícita para decirle a Git lo que se necesita, incluyendo añadir nuevas confirmaciones, corregir confirmaciones existentes, empujar cambios de tu repositorio local al repositorio remoto, e incluso recuperar nuevos cambios del repositorio remoto. En resumen, tienes que ser intencionado con tus acciones. Esto también incluye hacer saber a Git qué archivos pretendes seguir, ya que Git no añade automáticamente nuevos archivos para ser controlados por versiones.

Git está diseñado para impulsar el desarrollo no lineal

Git te permite idear y experimentar con diversas implementaciones de características para soluciones viables para tu proyecto, al permitirte divergir y trabajar en paralelo a lo largo de la base de código principal y estable de tu proyecto. Esta metodología, denominada ramificación, es una práctica muy común y garantiza la integridad de la línea de desarrollo principal, evitando cualquier cambio accidental que pueda romperla.

En Git, el concepto de bifurcación se considera ligero y económico porque una bifurcación en Git es sólo un puntero a la última confirmación de una serie de confirmaciones enlazadas. Por cada rama que creas, Git mantiene un registro de la serie de confirmaciones de esa rama. Puedes cambiar de rama localmente. A continuación, Git restaura el estado del proyecto al momento más reciente en que se creó la instantánea de la rama especificada. Cuando decides fusionar los cambios de cualquier rama en la línea de desarrollo principal, Git es capaz de combinar esas series de confirmaciones aplicando técnicas que discutiremos en el Capítulo 6.

Consejo

Puesto que Git ofrece muchas novedades, ten en cuenta que los conceptos y prácticas de otros sistemas de control de versiones pueden funcionar de forma diferente o no ser aplicables en absoluto en Git.

La línea de comandos de Git

La interfaz de línea de comandos de Git es fácil de usar. Está diseñada para poner en tus manos el control total de tu repositorio. Como tal, hay muchas formas de hacer lo mismo. Centrándonos en qué comandos son importantes para tu trabajo diario, podemos simplificarlos y aprenderlos en mayor profundidad.

Como punto de partida, escribe git version o git --version para determinar si tu máquina ya está precargada con Git. Deberías ver una salida similar a la siguiente:

$ git --version
git version 2.37.0

Si no tienes Git instalado en tu máquina, consulta el Apéndice B para saber cómo puedes instalar Git según la plataforma de tu sistema operativo antes de continuar con la siguiente sección.

Tras la instalación, escribe git sin ningún argumento. Git listará entonces sus opciones y los subcomandos más comunes:

   $ git

   usage: git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
              [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
              [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
              [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
              [--super-prefix=<path>] [--config-env=<name>=<envvar>]
              <command> [<args>]

   These are common Git commands used in various situations:

   start a working area (see also: git help tutorial)
      clone     Clone a repository into a new directory
      init      Create an empty Git repository or reinitialize an existing one

   work on the current change (see also: git help everyday)
      add       Add file contents to the index
      mv        Move or rename a file, a directory, or a symlink
      restore   Restore working tree files
      rm        Remove files from the working tree and from the index

   examine the history and state (see also: git help revisions)
      bisect    Use binary search to find the commit that introduced a bug
      diff      Show changes between commits, commit and working tree, etc
      grep      Print lines matching a pattern
      log       Show commit logs
      show      Show various types of objects
      status    Show the working tree status

   grow, mark and tweak your common history
      branch    List, create, or delete branches
      commit    Record changes to the repository
      merge     Join two or more development histories together
      rebase    Reapply commits on top of another base tip
      reset     Reset current HEAD to the specified state
      switch    Switch branches
      tag       Create, list, delete or verify a tag object signed with GPG

   collaborate (see also: git help workflows)
      fetch     Download objects and refs from another repository
      pull      Fetch from and integrate with another repository or a local branch
      push      Update remote refs along with associated objects

   'git help -a' and 'git help -g' list available subcommands and some((("git help command")))
   concept guides. See 'git help <command>' or 'git help <concept>'
   to read about a specific subcommand or concept.
   See 'git help git' for an overview of the system.
Consejo

Para obtener una lista completa de los subcomandos de git, escribe git help --all.

Como puedes ver en la sugerencia de uso, un pequeño puñado de opciones se aplican a git. La mayoría de las opciones, mostradas como [ARGS] en la sugerencia, se aplican a subcomandos específicos.

Por ejemplo, la opción --version afecta al comando git y produce un número de versión:

   $ git --version
   git version 2.37.0

En cambio, --amend es un ejemplo de opción específica del subcomando git commit :

   $ git commit --amend

Algunas invocaciones requieren ambas formas de opciones (en este caso, los espacios adicionales en la línea de comandos sólo sirven para separar visualmente el subcomando del comando base y no son necesarios):

   $ git --git-dir=project.git    repack -d

Para mayor comodidad, la documentación de cada subcomando git está disponible utilizando git help subcommand, git --help subcommand, git subcommand --help, o man git-subcommand.

Nota

La documentación completa de Git está en línea.

Históricamente, Git se ofrecía como un conjunto de muchos comandos sencillos, distintos e independientes, desarrollados según la filosofía Unix: construir herramientas pequeñas e interoperables. Cada comando tenía un nombre con guión, como git-commit y git-log. Sin embargo, las instalaciones modernas de Git ya no admiten las formas de comando con guión y, en su lugar, utilizan un único ejecutable git con un subcomando.

Los comandos git entienden tanto las opciones "cortas" como las "largas". Por ejemplo, el comando trata los siguientes ejemplos de forma equivalente: git commit

   $ git commit -m "Fix a typo."
   $ git commit --message="Fix a typo."

La forma corta, -m, utiliza un guión, mientras que la forma larga, --message, utiliza dos. (Esto es coherente con la extensión de opciones largas de GNU.) Algunas opciones sólo existen en una forma.

Consejo

Puedes crear un resumen de confirmación y un mensaje detallado para el resumen utilizando varias veces la opción -m:

   $ git commit -m "Summary" -m "Detail of Summary"

Por último, puedes separar las opciones de una lista de argumentos mediante la convención del doble guión. Por ejemplo, utiliza el guión doble para contrastar la parte de control de la línea de comandos de una lista de operandos, como nombres de archivos:

   $ git diff -w main origin -- tools/Makefile

Puede que necesites utilizar el doble guión para separar e identificar explícitamente los nombres de archivo para que no se confundan con otra parte del comando. Por ejemplo, si resulta que tienes un archivo y una etiqueta llamados main.c, tendrás que ser intencionado con tus operaciones:

   # Checkout the tag named "main.c"
   $ git checkout main.c

   # Checkout the file named "main.c"
   $ git checkout -- main.c

Introducción rápida al uso de Git

Para ver Git en acción, puedes crear un nuevo repositorio, añadir algo de contenido y hacer un seguimiento de algunas revisiones. Puedes crear un repositorio de dos formas: crear un repositorio desde cero y rellenarlo con algún contenido, o trabajar con un repositorio existente clonándolo desde un servidor Git remoto.

Prepararse para trabajar con Git

Tanto si vas a crear un nuevo repositorio como si vas a trabajar con un repositorio existente, hay configuraciones básicas previas que debes completar tras instalar Git en tu máquina de desarrollo local. Esto es similar a configurar la fecha, la zona horaria y el idioma correctos en una cámara nueva antes de hacer tu primera instantánea.

Como mínimo, Git requiere tu nombre y tu dirección de correo electrónico antes de que hagas tu primera confirmación en tu repositorio. La identidad que proporciones se mostrará como autor de la confirmación, junto con otros metadatos de la instantánea. Puedes guardar tu identidad en un archivo de configuración utilizando el comando git config:

   $ git config user.name "Jon Loeliger"
   $ git config user.email "jdl@example.com"

Si decides no incluir tu identidad en un archivo de configuración, tendrás que especificar tu identidad para cada subcomando git commit añadiendo el argumento --author al final del comando:

   $ git commit -m "log message" --author="Jon Loeliger <jdl@example.com>"

Ten en cuenta que éste es el camino difícil, y puede volverse tedioso rápidamente.

También puedes especificar tu identidad proporcionando tu nombre y dirección de correo electrónico a las variables de entorno GIT_AUTHOR_NAME y GIT_AUTHOR_EMAIL, respectivamente. Si se establecen, estas variables anularán todos los ajustes de configuración. Sin embargo, para las especificaciones establecidas en la línea de comandos, Git anulará los valores suministrados en el archivo de configuración y en la variable de entorno.

Trabajar con un repositorio local

Ahora que has configurado tu identidad, estás preparado para empezar a trabajar con un repositorio. Empieza creando un nuevo repositorio vacío en tu máquina de desarrollo local. Empezaremos de forma sencilla y avanzaremos hacia técnicas para trabajar con un repositorio compartido en un servidor Git.

Crear un repositorio inicial

Vamos a modelar una situación típica creando un repositorio para tu sitio web personal. Supongamos que empiezas de cero y vas a añadir contenido para tu proyecto en el directorio local ~/mi_website, que colocas en un repositorio Git.

Escribe los siguientes comandos para crear el directorio, y coloca algo de contenido básico en un archivo llamado index.html:

   $ mkdir ~/my_website
   $ cd ~/my_website
   $ echo 'My awesome website!' > index.html

Para convertir ~/mi_sitio_web en un repositorio Git , ejecuta git init. Aquí proporcionamos la opción -b seguida de una rama por defecto llamada main:

   $ git init -b main

   Initialized empty Git repository in ../my_website/.git/

Si prefieres inicializar primero un repositorio Git vacío y luego añadirle archivos, puedes hacerlo ejecutando los siguientes comandos:

   $ git init -b main ~/my_website

   Initialized empty Git repository in ../my_website/.git/

   $ cd ~/my_website
   $ echo 'My awesome website!' > index.html
Consejo

Puedes inicializar un directorio completamente vacío o un directorio existente lleno de archivos. En cualquier caso, el proceso de convertir el directorio en un repositorio Git es el mismo.

El comando git init crea un directorio oculto llamado .git en el nivel raíz de tu proyecto. Toda la información de las revisiones, junto con los metadatos de apoyo y las extensiones de Git, se almacenan en esta carpeta .git oculta de nivel superior.

Git considera que ~/mi_website es el directorio de trabajo. Este directorio contiene la versión actual de los archivos de tu sitio web. Cuando realizas cambios en los archivos existentes o añades nuevos archivos a tu proyecto, Git registra esos cambios en la carpeta oculta .git.

A efectos de aprendizaje, haremos referencia a dos directorios virtuales que llamaremos Historia local e Índice para ilustrar el concepto de inicialización de un nuevo repositorio Git. Hablaremos del Historial Local y del Índice en los Capítulos 4 y 5, respectivamente.

La Figura 1-2 representa lo que acabamos de explicar:

.
└── my_website
   ├── .git/
   │   └── Hidden git objects
   └── index.html
vcg3 0102
Figura 1-2. Depósito inicial

Las líneas de puntos que rodean el Historial local y el Índice representan los directorios ocultos dentro de la carpeta .git.

Añadir un archivo a tu repositorio

Hasta este punto, sólo has creado un nuevo repositorio Git . En otras palabras, este repositorio Git está vacío. Aunque el archivo index.html existe en el directorio ~/mi_sitio_web, para Git, éste es el directorio de trabajo, una representación de un bloc de notas o directorio donde alteras frecuentemente tus archivos.

Cuando hayas finalizado los cambios en los archivos y quieras depositar esos cambios en el repositorio Git, tienes que hacerlo explícitamente utilizando el comando git add. file :

   $ git add index.html
Advertencia

Aunque puedes dejar que Git añada todos los archivos del directorio y todos los subdirectorios mediante el comando git add ., esto lo escenifica todo, y te aconsejamos que seas intencionado con lo que planeas escenificar, principalmente para evitar que se incluya información sensible o archivos no deseados cuando se hagan los commits. Para evitar incluir dicha información, puedes utilizar el archivo .gitignore, que se trata en el Capítulo 5.

El argumento ., el punto o punto en la jerga Unix, es una abreviatura del directorio actual.

Con el comando git add, Git entiende que pretendes incluir la iteración final de la modificación en index. html como una revisión en el repositorio. Sin embargo, hasta ahora Git se ha limitado a preparar el archivo, un paso intermedio antes de tomar una instantánea mediante una confirmación.

Git separa los pasos add y commit para evitar la volatilidad, a la vez que proporciona flexibilidad y granularidad en la forma de registrar los cambios. Imagina lo perturbador, confuso y lento que sería actualizar el repositorio cada vez que añades, eliminas o cambias un archivo. En lugar de eso, se pueden agrupar por lotes varios pasos provisionales y relacionados, como una adición, manteniendo así el repositorio en un estado estable y coherente. Este método también nos permite elaborar una narrativa de por qué estamos cambiando el código. En el Capítulo 4 profundizaremos en este concepto.

Te recomendamos que te esfuerces en agrupar lotes de cambios lógicos antes de hacer una confirmación. Esto se denomina confirmación atómica y te ayudará en situaciones en las que necesitarás realizar algunas operaciones avanzadas de Git en capítulos posteriores.

Ejecutando el comando git status se revela este estado intermedio de index.html:

   $ git status

   On branch main

   No commits yet

   Changes to be committed:
     (use "git rm --cached <file>..." to unstage)
	    new file:   index.html

El comando informa de que el nuevo archivo index.html se añadirá al repositorio durante la próxima confirmación.

Después de preparar el archivo, el siguiente paso lógico es enviar el archivo al repositorio. Una vez que envías el archivo, pasa a formar parte del historial de envíos del repositorio; para abreviar, nos referiremos a él como historial del repositorio. Cada vez que realizas una confirmación, Git registra otros metadatos junto con ella, sobre todo el mensaje de registro de la confirmación y el autor del cambio.

Un comando git commit completamente cualificado debe proporcionar un mensaje de registro escueto y significativo utilizando lenguaje activo para denotar el cambio que introduce la confirmación. Esto es muy útil cuando necesitas recorrer el historial del repositorio para localizar un cambio concreto o identificar rápidamente los cambios de una confirmación sin tener que profundizar en los detalles del cambio. Profundizaremos en este tema en los Capítulos 4 y 8.

Vamos a confirmar el archivo index.html de tu sitio web:

   $ git commit -m "Initial contents of my_website"

   [main (root-commit) c149e12] initial contents of my_website
    1 file changed, 1 insertion(+)
    create mode 100644 index.html
Nota

Los datos del autor que realiza la confirmación se obtienen de la configuración de Git que establecimos anteriormente.

En el ejemplo de código, proporcionamos el argumento -m para poder proporcionar el mensaje de registro directamente en la línea de comandos. Si prefieres proporcionar un mensaje de registro detallado a través de una sesión de editor interactiva, también puedes hacerlo. Tendrás que configurar Git para que lance tu editor favorito durante una git commit (omite el argumento -m ); si aún no está configurado, puedes establecer la variable de entorno $GIT_EDITOR como sigue:

   # In bash or zsh
   $ export GIT_EDITOR=vim

   # In tcsh
   $ setenv GIT_EDITOR emacs
Nota

Git respetará el editor de texto predeterminado configurado en las variables de entorno del intérprete de comandos VISUAL y EDITOR. Si no está configurado ninguno de los dos, volverá a utilizar el editor vi.

Después de confirmar el archivo index. html en el repositorio, ejecuta git status para obtener una actualización del estado actual de tu repositorio. En nuestro ejemplo, la ejecución de git status debería indicar que no hay cambios pendientes de confirmar:

   $ git status

   On branch main
   nothing to commit, working tree clean

Git también te dice que tu directorio de trabajo está limpio, lo que significa que el directorio de trabajo no tiene archivos nuevos o modificados que difieran de lo que hay en el repositorio.

La Figura 1-3 te ayudará a visualizar todos los pasos que acabas de aprender.

La diferencia entre git add y git commit es muy parecida a cuando organizas a un grupo de escolares en un orden preferente para conseguir la fotografía perfecta de la clase: git add hace la organización, mientras que git commit hace la instantánea.

vcg3 0103
Figura 1-3. Preparar y añadir un archivo a un repositorio

Hacer otro commit

A continuación, vamos a hacer algunas modificaciones en index.html y a crear un historial de repositorio dentro del repositorio.

Convierte index.html en un archivo HTML adecuado, y confirma la alteración en él:

   $ cd ~/my_website

   # edit the index.html file.

   $ cat index.html
   <html>
   <body>
   My website is awesome!
   </body>
   </html>

   $ git commit index.html -m 'Convert to HTML'
   [main 521edbe] Convert to HTML
    1 file changed, 5 insertions(+), 1 deletion(-)

Si ya estás familiarizado con Git, puede que te preguntes por qué nos hemos saltado el paso git add index.html antes de confirmar el archivo. Se debe a que el contenido a confirmar puede especificarse de más de una forma en Git.

Escribe git commit --help para saber más sobre estas opciones:

   $ git commit --help

   NAME
       git-commit - Record changes to the repository

   SYNOPSIS
       git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
                  [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]
                  [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
                  [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
                  [--date=<date>] [--cleanup=<mode>] [--[no-]status]
                  [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
                  [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]
                  [--] [<pathspec>...]

   ...
Consejo

Las explicaciones detalladas de los distintos métodos de confirmación también se explican en las páginas del manual git commit --help.

En nuestro ejemplo, decidimos confirmar el archivo index. html con un argumento adicional, el modificador -m, que proporcionaba un mensaje explicando los cambios en la confirmación: 'Convert to HTML'. La Figura 1-4 explica el método que acabamos de comentar.

vcg3 0104
Figura 1-4. Poner en escena y añadir cambios a un archivo rastreado en un repositorio

Ten en cuenta que nuestro uso de git commit index.html -m 'Convert to HTML' no omite la puesta en escena del archivo; Git se encarga de ello automáticamente como parte de la acción de confirmación.

Ver tus confirmaciones

Ahora que tienes más commits en el historial del repositorio, puedes inspeccionarlos de varias formas. Algunos comandos de git muestran la secuencia de confirmaciones individuales, otros muestran el resumen de una confirmación individual, y otros muestran los detalles completos de cualquier confirmación que especifiques en el repositorio.

El comando git log proporciona un historial secuencial de las confirmaciones individuales dentro del repositorio:

   $ git log

   commit 521edbe1dd2ec9c6f959c504d12615a751b5218f (HEAD -> main)
   Author: Jon Loeliger <jdl@example.com>
   Date:   Mon Jul 4 12:01:54 2022 +0200

        Convert to HTML

   commit c149e12e89a9c035b9240e057b592ebfc9c88ea4
   Author: Jon Loeliger <jdl@example.com>
   Date:   Mon Jul 4 11:58:36 2022 +0200

        Initial contents of my_website

En la salida anterior, el comando git log imprime información de registro detallada para cada confirmación en el repositorio. En este momento sólo tienes dos confirmaciones en el historial de tu repositorio, lo que facilita la lectura de la salida. Para repositorios con muchos historiales de confirmaciones, puede que esta vista estándar no te ayude a recorrer una larga lista de información detallada de confirmaciones con facilidad; en tales situaciones puedes proporcionar el modificador --oneline para listar un número ID de confirmación resumido junto con el mensaje de confirmación:

   $ git log --oneline

   521edbe (HEAD -> main) Convert to HTML
   c149e12 Initial contents of my_website

Las entradas del registro de confirmaciones se enumeran, por orden, de la más reciente a la más antigua1 (el archivo original); cada entrada muestra el nombre y la dirección de correo electrónico del autor de la confirmación, la fecha de la confirmación, el mensaje de registro del cambio y el número de identificación interno de la confirmación. El número de identificación de la confirmación se explica en "Base de datos de contenido". Hablaremos de las confirmaciones con más detalle en el Capítulo 4.

Si quieres ver más detalles sobre una confirmación concreta, utiliza el comando git show con un número de identificación de confirmación:

   $ git show c149e12e89a9c035b9240e057b592ebfc9c88ea4

   commit c149e12e89a9c035b9240e057b592ebfc9c88ea4
   Author: Jon Loeliger <jdl@example.com>
   Date:   Mon Jul 4 11:58:36 2022 +0200

   Initial contents of my_website

   diff --git a/index.html b/index.html
   new file mode 100644
   index 0000000..6331c71
   --- /dev/null
   +++ b/index.html
   @@ -0,0 +1 @@
   +My awesome website!
Consejo

Si ejecutas git show sin un número de confirmación explícito, simplemente muestra los detalles de la confirmación de HEAD, en nuestro caso, la más reciente.

El comando git log muestra los registros de confirmaciones para ver cómo se incluyen los cambios de cada confirmación en el historial del repositorio. Si quieres ver resúmenes concisos de una línea de la rama de desarrollo actual sin proporcionar opciones de filtro adicionales al comando git log --oneline, un enfoque alternativo es utilizar el comando git show-branch:

   $ git show-branch --more=10

   [main] Convert to HTML
   [main^] Initial contents of my_website

La frase --more=10 revela hasta 10 versiones adicionales, pero hasta ahora sólo existen dos, por lo que se muestran ambas. (Por defecto, en este caso sólo se mostraría la confirmación más reciente.) El nombre main es el nombre de rama por defecto.

Hablaremos de las ramas y revisaremos el comando git show-branch con más detalle en el capítulo 3.

Ver las diferencias de confirmación

Con el historial del repositorio en su lugar desde la adición de commits de , ahora puedes ver las diferencias entre las dos revisiones de index.html. Tendrás que recordar los números de ID de commit y ejecutar el comando git diff:

   $ git diff c149e12e89a9c035b9240e057b592ebfc9c88ea4 \
               521edbe1dd2ec9c6f959c504d12615a751b5218f

   diff --git a/index.html b/index.html
   index 6331c71..8cfcb90 100644
   --- a/index.html
   +++ b/index.html
   @@ -1 +1,5 @@
   -My awesome website!
   +<html>
   +<body>
    My website is awesome!
   +</body>
   +</html>

La salida se parece a la que produce el comando git diff. Según la convención, la primera revisión confirmada, 9da581d910c9c4ac93557ca4859e767f5caf5169, es la anterior del contenido de index.html, y la segunda revisión confirmada, ec232cddfb94e0dfd5b5855af8ded7f5eb5c90d6, es el contenido más reciente de index.html. Así, un signo más (+) precede a cada línea de contenido nuevo después del signo menos (), que indica el contenido eliminado.

Nota

No te dejes intimidar por los largos números hexadecimales. Git proporciona muchas formas más cortas y sencillas de ejecutar comandos similares para que puedas evitar los ID de confirmación grandes y complicados. Normalmente, los siete primeros caracteres de los números hexadecimales, como se muestra en el ejemplo anterior de git log --oneline, son suficientes. Nos explayaremos sobre esto en "Base de datos de contenido direccionable".

Eliminar y renombrar archivos de tu repositorio

Ahora que has aprendido a añadir archivos a un repositorio Git, veamos cómo eliminar un archivo de uno. Eliminar un archivo de un repositorio Git es análogo a añadir un archivo, pero utiliza el comando git rm. Supongamos que tienes el archivo anuncios.html en el contenido de tu sitio web y piensas eliminarlo. Puedes hacerlo de la siguiente manera:

   $ cd ~/my_website
   $ ls
   index.html  adverts.html

   $ git rm adverts.html
   rm  'adverts.html'

   $ git commit -m "Remove adverts html"
   [main 97ff70a] Remove adverts html
    1 file changed, 0 insertions(+), 0 deletions(-)
    delete mode 100644 adverts.html

De forma similar a una adición, una eliminación también requiere dos pasos: expresar tu intención de eliminar el archivo mediante git rm, que también escenifica el archivo que pretendes eliminar. Realiza el cambio en el repositorio con un git commit.

Nota

Al igual que con git add, con git rm no estamos borrando directamente el archivo, sino que estamos cambiando lo que se rastrea: la eliminación o adición de un archivo.

Puedes renombrar un archivo indirectamente utilizando una combinación de los comandos git rm y git add, o puedes renombrar el archivo más rápida y directamente con el comando git mv. He aquí un ejemplo de lo primero:

   $ mv foo.html bar.html
   $ git rm foo.html
   rm 'foo.html'

   $ git add bar.html

En esta secuencia, debes ejecutar mv foo.html bar.html al principio para evitar que git rm elimine permanentemente el archivo foo.html del sistema de archivos.

Aquí tienes la misma operación realizada con git mv:

   $ git mv foo.html bar.html

En cualquier caso, los cambios por etapas deben confirmarse posteriormente:

   $ git commit -m "Moved foo to bar"
   [main d1e37c8] Moved foo to bar
    1 file changed, 0 insertions(+), 0 deletions(-)
    rename foo.html => bar.html (100%)

Git gestiona las operaciones de movimiento de archivos de forma diferente a la mayoría de sistemas similares, empleando un mecanismo basado en la similitud del contenido entre dos versiones de archivos. Los detalles se describen en el Capítulo 5.

Trabajar con un repositorio compartido

A estas alturas ya has inicializado un nuevo repositorio y has ido haciendo cambios en él. Todos los cambios sólo están disponibles para tu máquina de desarrollo local. Este es un buen ejemplo de cómo puedes gestionar un proyecto que sólo está disponible para ti. Pero, ¿cómo puedes trabajar en colaboración en un repositorio que está alojado en un servidor Git? Vamos a discutir cómo puedes conseguirlo.

Hacer una copia local del repositorio

Puedes crear una copia completa, o un clon, de un repositorio utilizando el comando git clone. Así colaboras con otras personas, haciendo cambios en los mismos archivos y manteniéndote sincronizado con los cambios de otras versiones del mismo repositorio.

A efectos de este tutorial, vamos a empezar de forma sencilla creando una copia de tu repositorio existente; después podemos contrastar el mismo ejemplo como si estuviera en un servidor Git remoto:

   $ cd ~
   $ git clone my_website new_website

Aunque estos dos repositorios Git contienen ahora exactamente los mismos objetos, archivos y directorios, existen algunas diferencias sutiles. Tal vez quieras explorar esas diferencias con comandos como el siguiente:

   $ ls -lsa my_website new_website
   ...
   $ diff -r my_website new_website
   ...

En un sistema de archivos local como éste, utilizar git clone para hacer una copia de un repositorio es bastante similar a utilizar cp -a o rsync. En cambio, si tuvieras que clonar el mismo repositorio desde un servidor Git, la sintaxis sería la siguiente:

   $ cd ~

   $ git clone https://git-hosted-server.com/some-dir/my_website.git new_website
   Cloning into 'new_website'...
   remote: Enumerating objects: 2, done.
   remote: Counting objects: 100% (2/2), done.
   remote: Compressing objects: 100% (103/103), done.
   remote: Total 125 (delta 45), reused 65 (delta 18), pack-reused 0
   Receiving objects: 100% (125/125), 1.67 MiB | 4.03 MiB/s, done.
   Resolving deltas: 100% (45/45), done.

Una vez que clonas un repositorio, puedes modificar la versión clonada, hacer nuevos commits, inspeccionar sus logs e historial, etc. Es un repositorio completo con un historial completo. Recuerda que los cambios que hagas en el repositorio clonado no se enviarán automáticamente a la copia original del repositorio.

La Figura 1-5 representa este concepto.

vcg3 0105
Figura 1-5. Clonar un repositorio compartido

Intenta no distraerte con algunos de los términos que veas en la salida. Git admite un conjunto más rico de fuentes de repositorio, incluidos los nombres de red, para nombrar el repositorio que se va a clonar. Explicaremos estas formas y su uso en el Capítulo 11.

Archivos de configuración

Los archivos de configuración de Git son todos ellos simples archivos de texto al estilo de los archivos .ini. Los archivos de configuración se utilizan para almacenar preferencias y ajustes utilizados por varios comandos de git. Algunos de los ajustes representan preferencias personales (por ejemplo, ¿debería usarse color.pager?), otros son importantes para que un repositorio funcione correctamente (por ejemplo, core repositoryformatversion), y otros ajustan un poco el comportamiento del comando git (por ejemplo, gc.auto). Al igual que otras herramientas, Git admite una jerarquía de archivos de configuración.

Jerarquía de archivos de configuración

La Figura 1-6 representa la jerarquía de archivos de configuración de Git en orden de precedencia decreciente:

.git/config

Ajustes de configuración específicos del repositorio manipulados con la opción --file o por defecto. También puedes escribir en este archivo con la opción --local. Estos ajustes tienen la máxima prioridad.

~/.gitconfig

Ajustes de configuración específicos del usuario manipulados con la opción --global.

/etc/gitconfig

Los ajustes de configuración de todo el sistema se manipulan con la opción --system si tienes los permisos adecuados de escritura de archivos Unix en el archivo gitconfig. Estos ajustes tienen la menor precedencia. Dependiendo de tu instalación, el archivo de configuración del sistema puede estar en otro lugar (quizás en /usr/local/etc gitconfig) o puede estar ausente por completo.

vcg3 0106
Figura 1-6. Jerarquía de archivos de configuración de Git

Por ejemplo, para almacenar un nombre de autor y una dirección de correo electrónico que se utilizarán en todas las confirmaciones que hagas para todos tus repositorios, configura valores para user name y user.email en tu archivo $HOME/.gitconfig utilizando git config --global:

   $ git config --global user.name "Jon Loeliger"
   $ git config --global user.email "jdl@example.com"

Si necesitas establecer un nombre y una dirección de correo electrónico específicos del repositorio que anulen un ajuste de --global, simplemente omite la bandera --global o utiliza la bandera --local para ser explícito:

   $ git config user.name "Jon Loeliger"
   $ git config user.email "jdl@special-project.example.org"

Puedes utilizar git config -l (o la forma larga --list) para listar los ajustes de todas las variables que se encuentran colectivamente en el conjunto completo de archivos de configuración:

   # Make a brand-new, empty repository
   $ mkdir /tmp/new
   $ cd /tmp/new
   $ git init

   # Set some config values
   $ git config --global user.name "Jon Loeliger"
   $ git config --global user.email "jdl@example.com"
   $ git config user.email "jdl@special-project.example.org"

   $ git config -l
   user.name=Jon Loeliger
   user.email=jdl@example.com
   core.repositoryformatversion=0
   core.filemode=true
   core.bare=false
   core.logallrefupdates=true
   user.email=jdl@special-project.example.org
Consejo

Al especificar el comando git config -l, ¡añadir las opciones --show-scope y --show-origin ayudará a imprimir las distintas fuentes de las configuraciones! Pruébalo con git config -l --show-scope --show-origin en tu terminal.

Como los archivos de configuración son simples archivos de texto, puedes ver su contenido con cat y editarlos también con tu editor de texto favorito:

   # Look at just the repository-specific settings

   $ cat .git/config
   [core]
       repositoryformatversion = 0
       filemode = true
       bare = false
       logallrefupdates = true
ignorecase = true
	precomposeunicode = true

   [user]
       email = jdl@special-project.example.org
Nota

El contenido del fichero de texto de configuración puedepresentar ligeras diferencias según el tipo de tu sistema operativo. Muchas de estas diferencias permiten distintascaracterísticas del sistema de archivos.

Si necesitas eliminar un ajuste de los archivos de configuración, utiliza la opción --unset junto con la bandera de archivos de configuración correctos:

   $ git config --unset --global user.email

Git te proporciona muchas opciones de configuración y variables de entorno que existen frecuentemente con el mismo propósito. Por ejemplo, puedes establecer un valor para el editor que se utilizará al redactar un mensaje de registro de confirmación. En función de la configuración, la invocación sigue estos pasos:

  1. GIT_EDITOR variable de entorno

  2. core.editor opción de configuración

  3. VISUAL variable de entorno

  4. EDITOR variable de entorno

  5. El comando vi

Hay más de unos cientos de parámetros de configuración. No te aburriremos con ellos, pero señalaremos los importantes a medida que avancemos. Puedes encontrar una lista más extensa (aunque todavía incompleta) en la página del manual git config.

Consejo

La lista completa de todos los comandos de git está en Internet.

Configurar un alias

Los alias de Git te permiten sustituir los comandos comunes pero complejos git que escribes con frecuencia por alias sencillos y fáciles de recordar. Esto también te ahorra la molestia de recordar o teclear esos comandos largos, y te evita la frustración de encontrarte con errores tipográficos:

   $ git config --global alias.show-graph \
           'log --graph --abbrev-commit --pretty=oneline'

En este ejemplo, hemos creado el alias show-graph y lo hemos puesto a disposición de cualquier repositorio que creemos. Cuando utilicemos el comando git show-graph, nos dará la misma salida que obtuvimos cuando tecleamos ese largo comando git log con todas esas opciones.

Resumen

Seguramente tendrás muchas preguntas sin respuesta sobre cómo funciona Git, incluso después de todo lo que has aprendido hasta ahora. Por ejemplo, ¿cómo almacena Git cada versión de un archivo? ¿Qué constituye realmente un commit? ¿De dónde vienen esos graciosos números de confirmación? ¿Por qué el nombre "principal"? ¿Y es una "rama" lo que creo que es? Son buenas preguntas. Lo que hemos tratado te da una idea de las operaciones que utilizarás habitualmente en tus proyectos. La respuesta a tus preguntas se explicará en detalle en la Parte II.

En el siguiente capítulo se define cierta terminología, se introducen algunos conceptos de Git y se sientan las bases para las lecciones del resto del libro.

1 En sentido estricto, no están en orden cronológico, sino que son una ordenación topológica de los commits.

Get Control de versiones con Git, 3ª edición now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.