Inicialmente usaba Git en un proyecto privado donde yo era el único desarrollador. Entre los comandos relacionados a la naturaleza distribuida de Git, sólo necesitaba pull y clone así yo podía mantener el mismo proyecto en diferentes lugares.
Más tarde quise publicar mi código con Git, e incluir cambios de los contribuyentes. Tuve que aprender a administrar proyectos con múltiples desarrolladores de todo el mundo. Afortunadamente, esta es la fortaleza de Git, y podría decirse que su razón de ser.
Cada commit tiene un nombre de autor y email, los cuales son mostrados por git log. Por defecto, Git usa la configuración del sistema para rellenar estos campos. Para decirle explícitamente, escribe:
$ git config --global user.name "John Doe" $ git config --global user.email johndoe@ejemplo.com
Omite el parámetro --global si quieres que estas opciones sólo sean aplicadas en el repositorio actual.
Supón que tienes acceso SSH a un servidor web, pero Git no está instalado. Aunque es menos eficiente que su protocolo nativo, Git se puede comunicar por HTTP.
Descarga, compila e instala Git en tu cuenta, y crea un repositorio en tu directorio web:
$ GIT_DIR=proj.git git init $ cd proj.git $ git --bare update-server-info $ cp hooks/post-update.sample hooks/post-update
En versiones antiguas de Git, el comando cp falla y debes ejecutar:
$ chmod a+x hooks/post-update
Ahora tú puedes publicar tus últimas ediciones via SSH desde cualquier clon:
$ git push servidor.web:/ruta/al/proyecto.git master
y cualquiera puede obtener tu proyecto con:
$ git clone http://servidor.web/proyecto.git
¿Quieres sincronizar repositorios sin servidores, o incluso sin conexión de red? ¿Necesitas improvisar durante una emergencia? Hemos visto cómo git fast-export y git fast-import pueden convertir repositorios a un único archivo y viceversa. Podríamos transportar tales archivos de ida y vuelta para enviar repositorios git sobre cualquier medio, pero una herramienta más eficiente es git bundle.
El emisor crea un bundle (paquete):
$ git bundle create algunarchivo HEAD
Luego envía el paquete, algunarchivo
, a la otra parte de alguna
forma: email, pendrive, una impresión xxd y un escáner OCR,
leyendo bits a través del teléfono, señales de humo, etc. El
receptor recupera los commits del paquete escribiendo:
$ git pull algunarchivo
El receptor puede incluso hacer esto desde un repositorio
vacío. A pesar de su tamaño, algunarchivo
contiene el repositorio git
original completo.
En proyectos más grandes, elimina la basura empaquetando sólo los cambios de los que carece el otro repositorio. Por ejemplo, supón que el commit “1b6d…” es el commit más reciente compartido por ambas partes:
$ git bundle create algunarchivo HEAD ^1b6d
Si se hace a menudo, uno puede olvidar fácilmente cual commit fue el último enviado. La página de ayuda sugiere usar tags para resolver esto. Es decir, después de que envías un paquete, escribe:
$ git tag -f ultimopaquete HEAD
y crea nuevos paquetes de actualización con:
$ git bundle create nuevopaquete HEAD ^ultimopaquete
Los parches son representaciones de texto de tus cambios que pueden ser fácilmente entendidos por computadores y humanos por igual. Esto les da una calidad universal. Puedes enviar por email un parche a los desarrolladores sin importar qué sistema de control de versiones estén usando. Mientras tu audiencia pueda leer su email, ella puede ver tus ediciones. Similarmente, por tu lado, todo lo que requieres es una cuenta de correo: no hay necesidad de crear un repositorio Git en línea.
Recuerda del primer capítulo:
$ git diff 1b6d > my.patch
obtiene un parche que puede se pegado en un email para discusión. En un repositorio Git, escribe:
$ git apply < my.patch
para aplicar el parche.
En un ambiente más formal, cuando los nombres de los autores y quizás las firmas deben ser guardadas, genera los parches correspondientes pasados un cierto punto escribiendo:
$ git format-patch 1b6d
Los archivos resultantes pueden ser enviados a git-send-email, o enviado a mano. También puedes especificar un rango de commits:
$ git format-patch 1b6d..HEAD^^
En el extremo receptor, guarda el mensaje a un archivo, luego escribe:
$ git am < email.txt
Esto aplica el parche entrante y también crea el commit, incluyendo información tal como el autor.
Con un cliente de correo, puedes necesitar hacer clic en un botón para ver el mensaje en su forma original antes de guardar el parche a un archivo.
Hay algunas ligeras diferencias para los clientes basados en casillas de correo, pero si tú usas uno de esos, ¡eres probablemente la persona que puede deducirlo fácilmente sin leer tutoriales!
Después de clonar un repositorio, correr git push o git pull hará push hacia o pull desde la URL original. ¿Cómo Git hace esto? El secreto está en las opciones de configuración creadas con el clone. Echemos un vistazo:
$ git config --list
La opción remote.origin.url
controla la URL fuente; “origin” es un alias dado al
repositorio fuente. Al igual que con la convención de la rama
“master”, podemos cambiar o borrar este alias, pero
usualmente no hay razón para hacerlo.
Si el repositorio original se mueve, podemos actualizar la URL con:
$ git config remote.origin.url git://nueva.url/proyecto.git
La opción branch.master.merge
especifica la rama remota por defecto en un git pull. Durante la
clonación inicial, se configura a la rama actual del
repositorio fuente, incluso si el HEAD del repositorio fuente
se mueve posteriormente a una rama diferente, más tarde un
pull va a seguir fielmente la rama original.
Esta opción sólo se aplica al repositorio en la primera
vez que se clona, que es guardado en la opción branch.master.remote
. Si tiramos desde otros
repositorios debemos decirle explícitamente que rama
queremos:
$ git pull git://example.com/other.git master
El ejemplo de más arriba explica por qué algunos de nuestros ejemplos anteriores de push y pull no tenían argumentos.
Cuando clonas un repositorio, también clonas todas sus ramas. Tú puedes no haber notado esto porque Git los esconde: debes consultar por ellos específicamente. Esto evita que las ramas en el repositorio remoto interfieran con tus ramas, y también hace a Git más fácil para los principiantes.
Lista las ramas remotas con:
$ git branch -r
Deberías ver algo como esto:
origin/HEAD origin/master origin/experimental
Estas representan ramas y el HEAD del repositorio remoto, y pueden ser usados en los comandos regulares de Git. Por ejemplo, supón que has hecho muchos commits, y deseas compararlos con la última versión traída. Tú podrías buscar en los registros (logs) por el hash SHA1 adecuado, pero es mucho más fácil escribir:
$ git diff origin/HEAD
O puedes ver lo que ha sucedido con la rama “experimental”:
$ git log origin/experimental
Supón que otros dos desarrolladores están trabajando en nuestro proyecto, y queremos mantener pestañas en ambos. Podemos seguir más de un repositorio a la vez con:
$ git remote add otro git://ejemplo.com/algun_repositorio.git $ git pull otro alguna_rama
Ahora hemos mezclado una rama desde el segundo repositorio, y tenemos acceso fácil a todas las ramas de todos los repositorios:
$ git diff origin/experimental^ otro/alguna_rama~5
Pero, ¿qué pasa si queremos comparar sus cambios sin afectar nuestro propio trabajo? En otras palabras, queremos examinar las ramas evitando que sus cambios invadan nuestro directorio de trabajo. Entonces, en vez de pull, ejecuta:
$ git fetch # Recuperamos desde el origen, por defecto. $ git fetch otro # Recuperamos lo del segundo programador.
Esto sólo obtiene historias. Aunque el directorio de trabajo permanece intacto, podemos referirnos a cualquier rama de cualquier repositorio en un comando Git ya que ahora poseemos una copia local.
Recuerda que detrás de las cámaras, un pull es simplemente un fetch luego merge. Usualmente hacemos pull porque queremos mezclar el último commit después de un fetch; esta situación es una excepción notable.
Vea git help remote para saber cómo remover repositorios, ignorar ciertas ramas, y más.
En mis proyectos, me gusta que los contribuyentes preparen los repositorios desde los cuales voy a hacer pull. Algunos servicios de hosting Git te permiten hospedar tu propia bifurcación de un proyecto con el clic de un botón.
Después de que obtengo un árbol, uso comandos Git para navegar y examinar los cambios, los que idealmente están bien organizados y bien descritos. Mezclo mis propios cambios, y quizás hago más ediciones. Una vez satisfecho, los empujo al repositorio principal.
Aunque rara vez recibo contribuciones, creo que este enfoque escala bien. Vea esta entrada de blog por Linus Torvalds.
Permanecer en el mundo Git es ligeramente más conveniente que parchar archivos, dado que me ahorra convertirlos a commits de Git. Además, Git maneja detalles como grabar el nombre y dirección de email del autor, así como la hora y fecha, y le pide al autor describir sus propios cambios.