-
1. Inicio - Sobre el Control de Versiones
-
2. Fundamentos de Git
-
3. Ramificaciones en Git
-
4. Git en el Servidor
- 4.1 Los Protocolos
- 4.2 Configurando Git en un servidor
- 4.3 Generando tu clave pública SSH
- 4.4 Configurando el servidor
- 4.5 El demonio Git
- 4.6 HTTP Inteligente
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Git en un alojamiento externo
- 4.10 Resumen
-
5. Git en entornos distribuidos
-
6. GitHub
-
7. Herramientas de Git
- 7.1 Revisión por selección
- 7.2 Organización interactiva
- 7.3 Guardado rápido y Limpieza
- 7.4 Firmando tu trabajo
- 7.5 Buscando
- 7.6 Reescribiendo la Historia
- 7.7 Reiniciar Desmitificado
- 7.8 Fusión Avanzada
- 7.9 Rerere
- 7.10 Haciendo debug con Git
- 7.11 Submódulos
- 7.12 Agrupaciones
- 7.13 Replace
- 7.14 Almacenamiento de credenciales
- 7.15 Resumen
-
8. Personalización de Git
-
9. Git y Otros Sistemas
- 9.1 Git como Cliente
- 9.2 Migración a Git
- 9.3 Resumen
-
10. Los entresijos internos de Git
-
A1. Apéndice A: Git en otros entornos
- A1.1 Interfaces gráficas
- A1.2 Git en Visual Studio
- A1.3 Git en Eclipse
- A1.4 Git con Bash
- A1.5 Git en Zsh
- A1.6 Git en Powershell
- A1.7 Resumen
-
A2. Apéndice B: Integrando Git en tus Aplicaciones
- A2.1 Git mediante Línea de Comandos
- A2.2 Libgit2
- A2.3 JGit
-
A3. Apéndice C: Comandos de Git
- A3.1 Configuración
- A3.2 Obtener y Crear Proyectos
- A3.3 Seguimiento Básico
- A3.4 Ramificar y Fusionar
- A3.5 Compartir y Actualizar Proyectos
- A3.6 Inspección y Comparación
- A3.7 Depuración
- A3.8 Parcheo
- A3.9 Correo Electrónico
- A3.10 Sistemas Externos
- A3.11 Administración
- A3.12 Comandos de Fontanería
7.14 Herramientas de Git - Almacenamiento de credenciales
Almacenamiento de credenciales
Si usa protocolo SSH para conectar a los remotos, es posible tener una llave sin clave, lo que permite tranferir la data
sin tener que escribir el nombre de usuario y la clave cada vez.
Sin embargo, esto no es posible por el protocolo HTTP - cada conexión necesita usuario y contraseña.
Incluso se vuelve más complicado para sistemas con autenticación de dos pasos, donde el token que
se usa para la clave es generado al azar y no puede ser reutilizado.
Afortunadamente, Git tiene un sistema de credenciales que lo ayuda con esto. Git tiene las siguientes funciones disponibles:
-
El “default” es no guardar cache para nada. Cada conexión solicitará el usuario y contraseña.
-
El modo “cache” mantiene las credenciales en memoria por un cierto período de tiempo. Ninguna de las claves es guardada en disco, y son borradas del cache tras 15 minutos.
-
El modo “store” guarda las credenciales en un archivo de texto plano en disco, y nunca expiran. Esto quiere decir que hasta que se cambie la contraseña en el host Git, no se necesitará escribir las credenciales de nuevo. La desventaja de este método es que sus claves son guardadas en texto plano en un archivo dentro de su máquina.
-
Si está usando Mac, Git viene con el modo “osxkeychain”, el cual guarda en cache las credenciales en el llavero que está conectado a su cuenta de sistema. Este método guarda las claves en disco, y nunca expiran, pero están encriptadas con el mismo sistema que guarda los certificados HTTPS y los auto-completar de Safari.
-
Si está en Windows, puede instalar un ayudante llamado “winstore.” Éste es similar al ayudante de “osxkeychain” descrito arriba, pero usa Windows Credential Store para controlar la información sensible. Se puede encontrar en https://gitcredentialstore.codeplex.com.
Se puede elegir cualquiera de estos métodos mediante el valor de configuración de Git:
$ git config --global credential.helper cache
Algunos de estos ayudantes tienen opciones.
El modo “store” puede tomar un argumento --file <ruta>', el cual personaliza la ubicación final del archivo en texto plano (el default es `~/.git-credentials
).
El modo “cache” acepta la opción --timeout <segundos>
, la cual cambia la cantidad de tiempo que el “demonio” se mantiene en ejecución (el default es “900”, o 15 minutos).
Aquí hay un ejemplo de cómo configurar el modo “store” con un nombre de archivo personalizado:
$ git config --global credential.helper store --file ~/.my-credentials
Git incluso permite configurar varios modos.
Cuando se buscan por credenciales para un host en particular, Git las mostrará en orden, y se detendrá después que la primer respuesta sea entregada.
Cuando se guardan credenciales, Git mandará el usuario y contraseña a todos los modos en la lista, y se podrá elegir qué hacer con ellos.
Aquí se muestra cómo se vería un archivo .gitconfig
si tuviera un archivo de credenciales en una memoria, pero quisiera usar lo almacenado en cache cuando la memoria no esté conectada:
[credential]
helper = store --file /mnt/thumbdrive/.git-credentials
helper = cache --timeout 30000
Bajo el sombrero
¿Cómo funciona todo esto?
El comando raíz de Git para el asistente de credenciales es git credential
, el cual toma un comando como argumento, y luego más inputs por medio de “stdin”.
Esto podría ser más fácil de entender con un ejemplo.
Supongamos que un modo de credenciales ha sido configurado, y que el asistente ha guardado credenciales para mygithost
.
Aquí hay una sesión que usa el comando “fill”, el cual es invocado cuando Git está intentando encontrar credenciales para el host:
$ git credential fill (1)
protocol=https (2)
host=mygithost
(3)
protocol=https (4)
host=mygithost
username=bob
password=s3cre7
$ git credential fill (5)
protocol=https
host=unknownhost
Username for 'https://unknownhost': bob
Password for 'https://bob@unknownhost':
protocol=https
host=unknownhost
username=bob
password=s3cre7
-
Este es el comando que inicia la interacción.
-
Git-credential entonces espera por un input en “stdin”. Nosotros lo proveemos con lo que conocemos: el protocolo y el nombre de host.
-
Una línea en blanco indica que el input está completo, y el sistema de credenciales debería responder con lo que conoce.
-
Git-credential entonces entra en acción, y escribe en “stdout” los bits de información que encontró.
-
Si no se encuentran credenciales, Git pregunta al usuario por el usuario y la contraseña, y los entrega de vuelta a “stdout” (aquí ya están conectados a la misma consola).
El sistema de credenciales en realidad está invocando un programa que está separado de Git; el que figura en el valor de configuración credential.helper
.
Hay varias formas que puede tomar:
Configuration Value | Behavior |
---|---|
|
Runs |
|
Runs |
|
Runs |
|
Code after |
Así, los modos descritos arriba en realidad se llaman git-credential-cache
, git-credential-store
, y en adelante, los podemos configurar para que tomen argumentos de línea de comando.
La forma general para conseguirlo es “git-credential-foo [args] <acción>.”
El protocolo “stdin/stdout” es el mismo que “git-credential”, pero usan un conjunto ligeramente distinto de acciones:
-
get
es una petición para un par usuario/contraseña. -
store
es una petición para guardar un grupo de credenciales en la memoria del modo. -
erase
purga las credenciales para las propiedades entregadas de la memoria del modo.
Para las acciones store
y erase
, no es necesaria una respuesta (Git la ignora de todos modos).
Para la acción get
, sin embargo, Git está muy interesado en lo que el modo tiene que decir.
Si el modo no sabe nada útil, puede simplemente salir sin mostrar inforamción, pero si sabe algo, debería aumentar la información provista con la información que ha almacenado.
El output es tratado como una serie de declaraciones de asignación; nada provisto remplazará lo que Git ya conoce.
Aquí hay un ejemplo de lo explicado, pero saltando git-credential y yendo directo a git-credential-store:
$ git credential-store --file ~/git.store store (1)
protocol=https
host=mygithost
username=bob
password=s3cre7
$ git credential-store --file ~/git.store get (2)
protocol=https
host=mygithost
username=bob (3)
password=s3cre7
-
Aquí decimos con
git-credential-store
que guarde las credenciales: username “bob” y la clave “s3cre7”, que serán usadas cuando se accese ahttps://mygithost
. -
Ahora vamos a recibir las credenciales. Proveemos las partes de la conexión que ya conocemos (
https://mygithost
), y una línea en blanco. -
git-credential-store
responde con el usuario y la contraseña que guardamos al comienzo.
Aquí se muestra cómo se vería ~/git.store
:
https://bob:s3cre7@mygithost
Es solamente una serie de líneas, cada una conteniendo una URL con credenciales.
Los modos osxkeychain
y winsoter
usan el formato nativo de sus almacenamientos, mientras cache
usa su propio formato en memoria (el cual no puede ser leído por ningún proceso).
Un cache de credenciales personalizado
Dado que git-credential-store
y amigos son programas separados de Git, no es difícil de notar que cualquier programa puede ser un asistente de credenciales de Git.
Los modos provistos por Git cubren muchos de los casos de uso, pero no todos.
Por ejemplo, supongamos que tu equipo tiene credenciales que son compartidas con el equipo entero, tal vez para despliegue.
Éstas están guardadas en un directorio compartido, pero no deseas copiarlas a tu almacén de credenciales, porque cambian de manera seguida.
Ninguno de los modos existentes cubre este caso; veamos lo que tomaría para escribir tu propio modo.
Existen muchas funcionalidades clave que necesita tener este programa:
-
La única acción que necesitamos vigilar es
get
, en tanto questore
yerase
son operaciones de escritura, así que sólo saldremos limpiamente cuando sean recibidas. -
El formato de archivo de la credencial compartida es el mismo que se usa por
git-credential-store
. -
La ubicación de ese archivo es relativamente estándar, pero deberías permitir al usuario entregar una ruta alterna, por si acaso.
Una vez más, vamos a escribir esta extensión en Ruby, pero cualquier lenguaje funcionará siempre y cuando Git pueda ejecutar el producto final. Aquí está el código de nuestro nuevo asistente de credenciales:
#!/usr/bin/env ruby
require 'optparse'
path = File.expand_path '~/.git-credentials' # (1)
OptionParser.new do |opts|
opts.banner = 'USAGE: git-credential-read-only [options] <action>'
opts.on('-f', '--file PATH', 'Specify path for backing store') do |argpath|
path = File.expand_path argpath
end
end.parse!
exit(0) unless ARGV[0].downcase == 'get' # (2)
exit(0) unless File.exists? path
known = {} # (3)
while line = STDIN.gets
break if line.strip == ''
k,v = line.strip.split '=', 2
known[k] = v
end
File.readlines(path).each do |fileline| # (4)
prot,user,pass,host = fileline.scan(/^(.*?):\/\/(.*?):(.*?)@(.*)$/).first
if prot == known['protocol'] and host == known['host'] then
puts "protocol=#{prot}"
puts "host=#{host}"
puts "username=#{user}"
puts "password=#{pass}"
exit(0)
end
end
-
Aquí analizamos las opciones de la línea de comando, permitiendo al usuario especificar un archivo. El default es
~/.git-credentials
. -
Este programa sólo responde si la acción es
get
y el archivo de almacenamiento existe. -
Este bucle lee de “stdin” hasta que se encuentre la primer línea en blanco. Los inputs son guardados en el hash
known
para una posterior referencia. -
Este bucle lee el contenido del archivo de almacenamiento, buscando por concordancias. Si el protocolo y el host de
known
concuerdan con la línea, el programa imprime el resultado a “stdout” y sale.
Guardaremos nuestro modo como git-credential-read-only
, ponlo en algún lugar en nuestro PATH
y lo marcamos como ejecutable.
Aquí se muestra cómo se vería una sesión interactiva:
$ git credential-read-only --file=/mnt/shared/creds get
protocol=https
host=mygithost
protocol=https
host=mygithost
username=bob
password=s3cre7
Dado que su nombre comienza con “git-”, podemos usar la sintaxis simple para el valor de configuración:
$ git config --global credential.helper read-only --file /mnt/shared/creds
Como se puede apreciar, extender este sistema es bastante sencillo, y puede resolver algunos problemas comunes para ti y tu equipo.