Git
Chapters ▾ 2nd Edition

8.1 Personalización de Git - Configuración de Git

Hasta ahora, hemos visto los aspectos básicos del funcionamiento de Git y la manera de utilizarlo; además de haber presentado una serie de herramientas suministradas con Git para ayudarnos a usarlo de manera sencilla y eficiente. En este capítulo, avanzaremos sobre ciertas operaciones que puedes utilizar para personalizar el funcionamiento de Git ; presentando algunos de sus principales ajustes y el sistema de anclajes (hooks). Con estas operaciones, será fácil conseguir que Git trabaje exactamente como tú, tu empresa o tu grupo necesitéis.

Configuración de Git

Como se ha visto brevemente en Inicio - Sobre el Control de Versiones, podemos acceder a los ajustes de configuración de Git a través del comando git config. Una de las primeras acciones que has realizado con Git ha sido el configurar tu nombre y tu dirección de correo-e.

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

Ahora vas a aprender un puñado de nuevas e interesantes opciones que puedes utilizar para personalizar el uso de Git.

Primeramente, vamos a repasar brevemente los detalles de configuración de Git que ya has visto. Para determinar su comportamiento no estándar, Git emplea una serie de archivos de configuración. El primero de ellos es el archivo /etc/gitconfig, que contiene valores para todos y cada uno de los usuarios en el sistema y para todos sus repositorios. Con la opción --system del comando git config, puedes leer y escribir de/a este archivo.

El segundo es el archivo ~/.gitconfig (o ~/.config/git/config), específico para cada usuario. Con la opción --global, git config lee y escribe en este archivo.

Y por último, Git también puede considerar valores de configuración presentes en el archivo .git/config de cada repositorio que estés utilizando. Estos valores se aplicarán únicamente a dicho repositorio.

Cada nivel sobreescribe los valores del nivel anterior; es decir lo configurado en .git/config tiene preferencia con respecto a lo configurado en /etc/gitconfig, por ejemplo.

Note

Los archivos de configuración de Git son de texto plano, por lo que también puedes ajustar manualmente los valores de configuración, editando directamente los archivos correspondientes y escribiendo en ellos con la sintaxis correspondiente; pero suele ser más sencillo hacerlo siempre a través del comando git config.

Configuración básica del cliente

Las opciones de configuración reconocidas por Git pueden distribuirse en dos grandes categorías: las del lado cliente y las del lado servidor. La mayoría de las opciones están en el lado cliente, – configurando tus preferencias personales de trabajo –. Aunque hay multitud de ellas, aquí vamos a ver solamente unas pocas, las más comúnmente utilizadas o las que afectan significativamente a tu forma de trabajar. No vamos a revisar aquellas opciones utilizadas solo en casos muy especiales. Si quieres consultar una lista completa, con todas las opciones contempladas en tu versión de Git, puedes lanzar el comando:

$ man git-config

Este comando muestra todas las opciones con cierto nivel de detalle. También puedes encontrar esta información de referencia en http://git-scm.com/docs/git-config.html.

core.editor

Por defecto, Git utiliza cualquier editor que hayas configurado como editor de texto por defecto de tu sistema ($VISUAL o $EDITOR). O, si no lo has configurado, utilizará vi como editor para crear y editar las etiquetas y mensajes de tus confirmaciones de cambio (commit). Para cambiar ese comportamiento, puedes utilizar el ajuste core.editor:

$ git config --global core.editor emacs

A partir de ese comando, por ejemplo, git lanzará Emacs cada vez que vaya a editar mensajes; indistintamente del editor configurado en la línea de comandos (shell) del sistema.

commit.template

Si preparas este ajuste para apuntar a un archivo concreto de tu sistema, Git lo utilizará como mensaje por defecto cuando hagas confirmaciones de cambio. Por ejemplo, imagina que creas una plantilla en ~/.gitmessage.txt con un contenido tal como:

subject line

what happened

[ticket: X]

Para indicar a Git que lo utilice como mensaje por defecto y que aparezca en tu editor cuando lances el comando git commit, tan solo has de ajustar commit.template:

$ git config --global commit.template ~/.gitmessage.txt
$ git commit

A partir de entonces, cada vez que confirmes cambios (commit), tu editor se abrirá con algo como esto:

subject line

what happened

[ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# modified:   lib/test.rb
#
~
~
".git/COMMIT_EDITMSG" 14L, 297C

Si tienes una política concreta con respecto a los mensajes de confirmación de cambios, puedes aumentar las posibilidades de que sea respetada si creas una plantilla acorde a dicha política y la pones como plantilla por defecto de Git.

core.pager

El parámetro core.pager selecciona el paginador utilizado por Git cuando muestra resultados de comandos tales como log o diff.. Puedes ajustarlo para que utilice more o tu paginador favorito, (por defecto, se utiliza less); o puedes anular la paginación si le asignas una cadena vacía.

$ git config --global core.pager ''

Si lanzas esto, Git mostrará siempre el resultado completo de todos los comandos, independientemente de lo largo que sea éste.

user.signingkey

Si tienes costumbre de firmar tus etiquetas (tal y como se ha visto en Firmando tu trabajo), configurar tu clave de firma GPG puede facilitarte la labor. Puedes configurar tu clave ID de esta forma:

$ git config --global user.signingkey <gpg-key-id>

Ahora podrás firmar etiquetas sin necesidad de indicar tu clave cada vez en el comando git tag.

$ git tag -s <tag-name>

core.excludesfile

Se pueden indicar expresiones en el archivo .gitignore de tu proyecto para indicar a Git lo que debe considerar o no como archivos sin seguimiento, o lo que interará o no seleccionar cuando lances el comando git add, tal y como se indicó en Ignorar Archivos.

Pero a veces, necesitas ignorar ciertos archivos en todos los repositorios con los que trabajas. Por ejemplo, si trabajas en una computadora con Mac OS X, estarás al tanto de la existencia de los archivo .DS_Store. O si usas Emacs o Vim, también conocerás los archivos terminados en ~.

Este ajuste puedes grabarlo en un archivo global, llamado ~/.gitignore_global, con estos contenidos:

*~
.DS_Store

…y si ahora lanzas git config --global core.excludesfile ~/.gitignore_global, Git ya nunca más tendrá en cuenta esos archivos en tus repositorios.

help.autocorrect

Si te equivocas al teclear un comando de Git, te mostrará algo como:

$ git chekcout master
git: 'chekcout' is not a git command. See 'git --help'.

Did you mean this?
    checkout

Git intenta imaginar qué es lo que querías escribir, pero aun así no lo intenta ejecutar. Si pones la opción help.autocorrect a 1, Git sí lanzará el comando corrigiendo tu error:

$ git chekcout master
WARNING: You called a Git command named 'chekcout', which does not exist.
Continuing under the assumption that you meant 'checkout'
in 0.1 seconds automatically...

Observa lo de “0.1 seconds”. Es un entero que representa décimas de segundo. Si le das un valor 50, Git retrasará la ejecución final del comando 5 segundos con el fin de que puedas abortar la operación auto-corregida con la opción help.autocorrect.

Colores en Git

Git puede marcar con colores los resultados que muestra en tu terminal, ayudándote así a leerlos más fácilmente. Hay unos cuantos parámetros que te pueden ayudar a configurar tus colores favoritos.

color.ui

Si se lo pides, Git coloreará automáticamente la mayor parte de los resultados que muestre. Puedes ajustar con precisión cada una de las partes a colorear; pero si deseas activar de un golpe todos los colores por defecto, no tienes más que poner a "true" el parámetro color.ui.

Para desactivar totalmente los colores, puedes hacer esto:

$ git config --global color.ui false

El valor predeterminado es auto, que colorea la salida cuando va a un terminal, pero no lo hace cuando se envía la salida a un archivo o a una tubería.

También puedes ponerlo a always para hacer que se coloree siempre. Es muy raro que quieras hacer esto, ya que cuando se quiere puntualmente colorear la salida redirigida se puede pasar un flag --color al comando Git.

color.*

Cuando quieras ajustar específicamente, comando a comando, donde colorear y cómo colorear, puedes emplear los ajustes particulares de color. Cada uno de ellos puede fijarse a true (verdadero), false (falso) o always (siempre):

color.branch
color.diff
color.interactive
color.status

Además, cada uno de ellos tiene parámetros adicionales para asignar colores a partes específicas, por si quieres precisar aún más. Por ejemplo, para mostrar la meta-información del comando diff con letra azul sobre fondo negro y con caracteres en negrita, puedes indicar:

$ git config --global color.diff.meta "blue black bold"

Puedes ajustar un color a cualquiera de los siguientes valores: normal, black (negro), red (rojo), green (verde), yellow (amarillo), blue (azul), magenta, cyan (cian), o white (blanco).

También puedes aplicar atributos tales como bold (negrita), dim (tenue), ul (subrayado), blink (parpadeante) y reverse(video inverso).

Herramientas externas para fusión y diferencias

Aunque Git lleva una implementación interna de diff, la que se utiliza habitualmente, se puede sustituir por una herramienta externa. Puedes incluso configurar una herramienta gráfica para la resolución de conflictos, en lugar de resolverlos manualmente. Lo voy a demostrar configurando Perforce Visual Merge (P4Merge) como herramienta para realizar las comparaciones y resolver conflictos; ya que es una buena herramienta gráfica y es libre.

Si lo quieres probar, P4Merge funciona en todas las principales plataformas. Los nombres de carpetas que utilizaré en los ejemplos funcionan en sistemas Mac y Linux; para Windows, tendrás que sustituir /usr/local/bin por el correspondiente camino al ejecutable en tu sistema.

P4Merge se puede descargar desde http://www.perforce.com/downloads/Perforce/.

Para empezar, tienes que preparar los correspondientes scripts para lanzar tus comandos. En estos ejemplos, voy a utilizar caminos y nombres Mac para los ejecutables; en otros sistemas, tendrás que sustituirlos por los correspondientes donde tengas instalado p4merge. El primer script a preparar es uno al que denominaremos extMerge, para llamar al ejecutable con los correspondientes argumentos:

$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/p4merge.app/Contents/MacOS/p4merge $*

El script para el comparador, ha de asegurarse de recibir siete argumentos y de pasar dos de ellos al script de fusión (merge). Por defecto, Git pasa los siguientes argumentos al programa diff (comparador):

path old-file old-hex old-mode new-file new-hex new-mode

Ya que solo necesitarás old-file y new-file, puedes utilizar el siguiente script para extraerlos:

$ cat /usr/local/bin/extDiff
#!/bin/sh
[ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"

Además has de asegurarte de que estas herramientas son ejecutables:

$ sudo chmod +x /usr/local/bin/extMerge
$ sudo chmod +x /usr/local/bin/extDiff

Una vez preparado todo esto, puedes ajustar el archivo de configuración para utilizar tus herramientas personalizadas de comparación y resolución de conflictos. Tenemos varios parámetros a ajustar: merge.tool para indicar a Git la estrategia que ha de usar, mergetool.*.cmd para especificar como lanzar el comando, mergetool.trustExitCode para decir a Git si el código de salida del programa indica una fusión con éxito o no, y diff.external para decir a Git qué comando lanzar para realizar comparaciones. Es decir, has de ejecutar cuatro comandos de configuración:

$ git config --global merge.tool extMerge
$ git config --global mergetool.extMerge.cmd \
  'extMerge \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"'
$ git config --global mergetool.extMerge.trustExitCode false
$ git config --global diff.external extDiff

o puedes editar tu archivo ~/.gitconfig para añadirle las siguientes líneas:

[merge]
  tool = extMerge
[mergetool "extMerge"]
  cmd = extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
  trustExitCode = false
[diff]
  external = extDiff

Tras ajustar todo esto, si lanzas comandos tales como:

$ git diff 32d1776b1^ 32d1776b1

En lugar de mostrar las diferencias por línea de comandos, Git lanzará P4Merge, que tiene una pinta como:

P4Merge.
Figure 143. P4Merge.

Si intentas fusionar (merge) dos ramas y tienes los consabidos conflictos de integración, puedes lanzar el comando git mergetool; lanzará P4Merge para ayudarte a resolver los conflictos por medio de su interfaz gráfica.

Lo bonito de estos ajustes con scripts, es que puedes cambiar fácilmente tus herramientas de comparación (diff) y de fusión (merge). Por ejemplo, para cambiar tus scripts extDiff y extMerge para utilizar KDiff3, tan solo has de editar el archivo extMerge:

$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/kdiff3.app/Contents/MacOS/kdiff3 $*

A partir de ahora, Git utilizará la herramienta KDiff3 para mostrar y resolver conflictos de integración.

Git viene preparado para utilizar bastantes otras herramientas de resolución de conflictos, sin necesidad de andar ajustando la configuración. Para listar las herramientas soportadas solo has de lanzar el comando:

$ git mergetool --tool-help
'git mergetool --tool=<tool>' may be set to one of the following:
        emerge
        gvimdiff
        gvimdiff2
        opendiff
        p4merge
        vimdiff
        vimdiff2

The following tools are valid, but not currently available:
        araxis
        bc3
        codecompare
        deltawalker
        diffmerge
        diffuse
        ecmerge
        kdiff3
        meld
        tkdiff
        tortoisemerge
        xxdiff

Some of the tools listed above only work in a windowed
environment. If run in a terminal-only session, they will fail.

Si no te interesa utilizar KDiff3 para comparaciones, sino que tan solo te interesa utilizarlo para resolver conflictos de integración; teniendo kdiff3 en el path de ejecución, solo has de lanzar el comando:

$ git config --global merge.tool kdiff3

Si utilizas este comando en lugar de preparar los archivos extMerge y extDiff antes comentados, Git utilizará KDiff3 para resolución de conflictos de integración y la herramienta estándar diff para las comparaciones.

Formateo y espacios en blanco

El formato y los espacios en blanco son la fuente de los problemas más sutiles y frustrantes que muchos desarrolladores se pueden encontrar en entornos colaborativos, especialmente si son multi-plataforma. Es muy fácil que algunos parches u otro trabajo recibido introduzcan sutiles cambios de espaciado, porque los editores suelen hacerlo inadvertidamente o, trabajando en entornos multi-plataforma, porque programadores Windows suelen añadir retornos de carro al final de las lineas que tocan. Git dispone de algunas opciones de configuración para ayudarnos con estos problemas.

core.autocrlf

Si estás programando en Windows o utilizando algún otro sistema, pero colaborando con gente que programa en Windows. Es muy posible que alguna vez te topes con problemas de finales de línea. Esto se debe a que Windows utiliza retorno-de-carro y salto-de-linea para marcar los finales de línea de sus archivos. Mientras que Mac y Linux utilizan solamente el carácter de salto-de-linea. Esta es una sutil, pero molesta, diferencia cuando se trabaja en entornos multi-plataforma.

Git la maneja convirtiendo automáticamente los finales CRLF en LF al hacer confirmaciones de cambios (commit); y, viceversa, al extraer código (checkout) a la carpeta de trabajo. Puedes activar esta funcionalidad con el parámetro core.autocrlf. Si estás trabajando en una máquina Windows, ajustalo a true, para convertir finales LF en CRLF cuando extraigas código (checkout), puedes hacer esto:

$ git config --global core.autocrlf true

Si estás trabajando en una máquina Linux o Mac, entonces no te interesa convertir automáticamente los finales de línea al extraer código, sino que te interesa arreglar los posibles CRLF que pudieran aparecer accidentalmente. Puedes indicar a Git que convierta CRLF en LF al confirmar cambios (commit), pero no en el otro sentido; utilizando también el parámetro core.autocrlf:

$ git config --global core.autocrlf input

Este ajuste dejará los finales de línea CRLF en las extracciones de código (checkout), pero dejará los finales LF en sistemas Mac o Linux, y en el repositorio.

Si eres un programador Windows, trabajando en un entorno donde solo haya máquinas Windows, puedes desconectar esta funcionalidad, para almacenar CRLFs en el repositorio. Ajustando el parámero a false:

$ git config --global core.autocrlf false

core.whitespace

Git viene preajustado para detectar y resolver algunos de los problemas más típicos relacionados con los espacios en blanco. Puede vigilar acerca de seis tipos de problemas de espaciado: tres los tiene activados por defecto, pero se pueden desactivar; y tres vienen desactivados por defecto, pero se pueden activar.

Los que están activos de forma predeterminada son blank-at-eol, que busca espacios al final de la línea; blank-at-eof, que busca líneas en blanco al final del archivo y espace-before-tab, que busca espacios delante de las tabulaciones al comienzo de una línea.

Los que están inactivos de forma predeterminada son ident-with-non-tab, que busca líneas que empiezan con espacios en blanco en lugar de tabulaciones (y se controla con la opción tabwidth); tab-in-indent, que busca tabulaciones en el trozo indentado de una línea; y cr-at-eol, que informa a Git de que los CR al final de las líneas son correctos.

Puedes decir a Git cuales de ellos deseas activar o desactivar, ajustando el parámetro core.whitespace con los valores on/off separados por comas. Puedes desactivarlos tanto dejándolos fuera de la cadena de ajustes, como añadiendo el prefijo - delante del valor. Por ejemplo, si deseas activar todos menos cr-at-eol puedes lanzar:

$ git config --global core.whitespace \
    trailing-space,space-before-tab,indent-with-non-tab

Git detectará posibles problemas cuando lance un comando git diff, e intentará destacarlos en otro color para que puedas corregirlos antes de confirmar cambios (commit). También pueden ser útiles estos ajustes cuando estás incorporando parches con git apply. Al incorporar parches, puedes pedirle a Git que te avise específicamente sobre determinados problemas de espaciado:

$ git apply --whitespace=warn <patch>

O puedes pedirle que intente corregir automáticamente los problemas antes de aplicar el parche:

$ git apply --whitespace=fix <patch>

Estas opciones se pueden aplicar también al comando git rebase. Si has confirmado cambios con problemas de espaciado, pero no los has enviado (push) aún "aguas arriba" (upstream). Puedes realizar una reorganización (rebase) con la opción --whitespace=fix para que Git corrija automáticamente los problemas según va reescribiendo los parches.

Configuración del servidor

No hay tantas opciones de configuración en el lado servidor de Git, pero hay unas pocas interesantes que merecen ser tenidas en cuenta.

receive.fsckObjects

Por defecto, Git no suele comprobar la consistencia de todos los objetos que recibe durante un envío (push), aunque Git tiene la capacidad para asegurarse de que cada objeto sigue casando con su suma de control SHA-1 y sigue apuntando a objetos válidos. No lo suele hacer en todos y cada uno de los envíos (push). Es una operación costosa, que, dependiendo del tamaño del repositorio, puede llegar a añadir mucho tiempo a cada operación de envío (push). De todas formas, si deseas que Git compruebe la consistencia de todos los objetos en todos los envíos, puedes forzarle a hacerlo ajustando a true el parámetro receive.fsckObjects:

$ git config --system receive.fsckObjects true

A partir de ese momento, Git comprobará la integridad del repositorio antes de aceptar ningún envío (push), para asegurarse de que no está introduciendo datos corruptos.

receive.denyNonFastForwards

Si reorganizas (rebase) confirmaciones de cambio (commit) que ya habías enviado y tratas de enviarlas (push) de nuevo; o si intentas enviar una confirmación a una rama remota que no contiene la confirmación actualmente apuntada por la rama, normalmente, la operación te será denegada por la rama remota sobre la que pretendías realizarla. Habitualmente, este es el comportamiento más adecuado. Pero, en el caso de las reorganizaciones, cuando estás totalmente seguro de lo que haces, puedes forzar el envío, utilizando la opción -f en el comando git push a la rama remota.

Para impedir estos envíos forzados de referencias de avance no directo (no fast-forward) a ramas remotas, es para lo que se emplea el parámetro receive.denyNonFastForwards:

$ git config --system receive.denyNonFastForwards true

Otra manera de obtener el mismo resultado, es a través de los enganches (hooks) en el lado servidor, enganches de los que hablaremos en breve. Esta otra vía te permite realizar ajustes más finos, tales como denegar referencias de avance no directo, (non-fast-forwards), únicamente a un grupo de usuarios.

receive.denyDeletes

Uno de los cortocircuitos que suelen utilizar los usuarios para saltarse la politica de denyNonFastForwards, suele ser el borrar la rama y luego volver a enviarla de vuelta con la nueva referencia. Puedes evitar esto poniendo a true el parámetro receive.denyDeletes:

$ git config --system receive.denyDeletes true

Esto impide el borrado de ramas o de etiquetas por medio de un envío a través de la mesa (push across the board), --ningún usuario lo podrá hacer--. Para borrar ramas remotas, tendrás que borrar los archivos de referencia manualmente sobre el propio servidor. Existen también algunas otras maneras más interesantes de hacer esto mismo, pero para usuarios concretos, a través de permisos (ACLs); tal y como veremos en Un ejemplo de implantación de una determinada política en Git.