Beruflich Dokumente
Kultur Dokumente
Git profesional
Tabla de contenido
licencia _ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ............................. ............ 1
resumen _ . . . . . . . . . . . . . . . . . . . . . . . . . ............................. . . . . . . . . . . . . . . . . . . . . . . . . 23
Etiquetado _ . . . . . . . . . . . . . . . . . . . . . . . . . . . ............................. . . . . . . . . . . . . . . . . . . . . . . . . 55
resumen _ . . . . . . . . . . . . . . . . . . . . . . . . . ............................. . . . . . . . . . . . . . . . . . . . . . . . . 62
Rebasando . . . . . . . . . . . . . . . . . . . . . . . . . . . ............................. . . . . . . . . . . . . . . . . . . . . . . . . 95
índice _ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
Machine Translated by Google
Licencia
Este trabajo está bajo la licencia Creative Commons Attribution-NonCommercial-ShareAlike 3.0
Licencia sin portar. Para ver una copia de esta licencia, visite https://creativecommons.org/licenses/by-nc sa/3.0 o envíe una carta
a Creative Commons, PO Box 1866, Mountain View, CA 94042, EE. UU.
1
Machine Translated by Google
Cuando escribí la primera edición, Git todavía era una herramienta relativamente difícil de usar y apenas adoptada por los
piratas informáticos más duros. Estaba comenzando a ganar fuerza en ciertas comunidades, pero no había alcanzado ni de
cerca la ubicuidad que tiene hoy. Desde entonces, casi todas las comunidades de código abierto lo han adoptado. Git ha
hecho un progreso increíble en Windows, en la explosión de interfaces gráficas de usuario para todas las plataformas, en
soporte IDE y en uso comercial. El Pro Git de hace cuatro años no sabe nada de eso. Uno de los principales objetivos de
esta nueva edición es abordar todas aquellas novedades
La comunidad de código abierto que usa Git también se ha disparado. Cuando originalmente me senté a escribir el libro hace
casi cinco años (me tomó un tiempo sacar la primera versión), acababa de comenzar a trabajar en una compañía muy poco
conocida que desarrollaba un sitio web de alojamiento de Git llamado GitHub. En el momento de la publicación, tal vez había
unos miles de personas usando el sitio y solo cuatro de nosotros trabajando en él.
Mientras escribo esta introducción, GitHub anuncia nuestro proyecto alojado número 10 millones, con casi 5 millones de
cuentas de desarrollador registradas y más de 230 empleados. Lo ames o lo odies, GitHub ha cambiado en gran medida
grandes franjas de la comunidad de código abierto de una manera que era apenas concebible cuando me senté a escribir la
primera edición.
Escribí una pequeña sección en la versión original de Pro Git sobre GitHub como un ejemplo de Git alojado con el que nunca
me sentí muy cómodo. No me gustó mucho que estaba escribiendo lo que sentía que era esencialmente un recurso de la
comunidad y también hablando de mi empresa en él. Si bien todavía no me gusta ese conflicto de intereses, la importancia
de GitHub en la comunidad de Git es inevitable. En lugar de un ejemplo de alojamiento de Git, he decidido convertir esa parte
del libro en una descripción más profunda de qué es GitHub y cómo usarlo de manera efectiva. Si va a aprender a usar Git,
saber cómo usar GitHub lo ayudará a participar en una gran comunidad, lo cual es valioso sin importar qué host de Git decida
usar para su propio código.
El otro gran cambio en el tiempo transcurrido desde la última publicación ha sido el desarrollo y el aumento del protocolo
HTTP para las transacciones de la red Git. La mayoría de los ejemplos del libro se han cambiado a HTTP desde SSH porque
es mucho más simple.
Ha sido increíble ver crecer a Git en los últimos años desde un sistema de control de versiones relativamente oscuro hasta
dominar básicamente el control de versiones comerciales y de código abierto. Estoy feliz de que a Pro Git le haya ido tan
bien y además haya podido ser uno de los pocos libros técnicos del mercado.
2
Machine Translated by Google
Ahora, años después, soy colaborador de una importante implementación de Git, he trabajado para la mayor
empresa de alojamiento de Git y he viajado por el mundo enseñando a la gente sobre Git. Cuando Scott me
preguntó si estaría interesado en trabajar en la segunda edición, ni siquiera tuve que pensar.
Ha sido un gran placer y un privilegio trabajar en este libro. Espero que te ayude tanto como lo hizo
me.
3
Machine Translated by Google
dedicatorias
A mi esposa, Becky, sin la cual esta aventura nunca hubiera comenzado. — ben
Esta edición está dedicada a mis niñas. A mi esposa Jessica que me ha apoyado durante todos estos
años ya mi hija Josephine, que me apoyará cuando sea demasiado mayor para saber lo que está pasando.
—Scott
4
Machine Translated by Google
Colaboradores
Dado que este es un libro de código abierto, hemos recibido varias erratas y cambios de contenido donados a
lo largo de los años. Aquí están todas las personas que han contribuido a la versión en inglés de Pro Git como
proyecto de código abierto. Gracias a todos por ayudar a hacer de este un libro mejor para todos.
5
Machine Translated by Google
Introducción
Estás a punto de pasar varias horas de tu vida leyendo sobre Git. Tomemos un minuto para explicar lo que tenemos reservado para
usted. He aquí un breve resumen de los diez capítulos y los tres apéndices de este libro.
En el Capítulo 1, cubriremos los sistemas de control de versiones (VCS) y los conceptos básicos de Git: sin detalles técnicos, solo qué
es Git, por qué surgió en una tierra llena de VCS, qué lo distingue y por qué tanta gente. lo están usando. Luego, explicaremos cómo
descargar Git y configurarlo por primera vez si aún no lo tiene en su sistema.
En el Capítulo 2, repasaremos el uso básico de Git: cómo usar Git en el 80 % de los casos que encontrará con mayor frecuencia.
Después de leer este capítulo, debería poder clonar un repositorio, ver lo que ha sucedido en el historial del proyecto, modificar archivos
y aportar cambios. Si el libro se quema espontáneamente en este punto, ya debería ser bastante útil manejando Git en el tiempo que le
toma ir a buscar otra copia.
El Capítulo 3 trata sobre el modelo de bifurcación en Git, a menudo descrito como la característica principal de Git. Aquí aprenderá lo
que realmente diferencia a Git del resto. Cuando haya terminado, puede sentir la necesidad de pasar un momento tranquilo reflexionando
sobre cómo vivía antes de que la ramificación de Git fuera parte de su vida.
El Capítulo 4 cubrirá Git en el servidor. Este capítulo es para aquellos de ustedes que desean configurar Git dentro de su organización
o en su propio servidor personal para la colaboración. También exploraremos varias opciones alojadas si prefiere dejar que alguien más
se encargue de eso por usted.
El Capítulo 5 repasará con todo detalle varios flujos de trabajo distribuidos y cómo lograrlos con Git. Cuando haya terminado con este
capítulo, debería poder trabajar de manera experta con múltiples repositorios remotos, usar Git por correo electrónico y hacer
malabarismos hábilmente con numerosas ramas remotas y parches contribuidos.
El Capítulo 6 cubre en profundidad el servicio de hospedaje y las herramientas de GitHub. Cubrimos registrarse y administrar una
cuenta, crear y usar repositorios Git, flujos de trabajo comunes para contribuir a proyectos y aceptar contribuciones a los suyos, la
interfaz programática de GitHub y muchos pequeños consejos para facilitarle la vida en general.
El Capítulo 7 trata sobre los comandos avanzados de Git. Aquí aprenderá sobre temas como dominar el aterrador comando 'restablecer',
usar la búsqueda binaria para identificar errores, editar el historial, seleccionar la revisión en detalle y mucho más. Este capítulo
completará tu conocimiento de Git para que seas verdaderamente un
Maestro.
El Capítulo 8 trata sobre la configuración de su entorno Git personalizado. Esto incluye la configuración de secuencias de comandos
de enlace para hacer cumplir o fomentar políticas personalizadas y el uso de ajustes de configuración del entorno para que pueda
trabajar de la manera que desee. También cubriremos la creación de su propio conjunto de secuencias de comandos para hacer cumplir
una política de confirmación personalizada.
El Capítulo 9 trata sobre Git y otros VCS. Esto incluye usar Git en un mundo de Subversion (SVN) y convertir proyectos de otros VCS
a Git. Muchas organizaciones todavía usan SVN y no están dispuestas a cambiar, pero en este punto habrás aprendido el increíble
poder de Git, y este capítulo te muestra cómo lidiar si todavía tienes que usar un servidor SVN. También cubrimos cómo importar
proyectos de
6
Machine Translated by Google
varios sistemas diferentes en caso de que convenzas a todos para dar el paso.
El capítulo 10 profundiza en las turbias pero hermosas profundidades de las funciones internas de Git. Ahora que
sabe todo acerca de Git y puede manejarlo con poder y gracia, puede pasar a discutir cómo Git almacena sus
objetos, cuál es el modelo de objeto, detalles de los archivos de paquete, protocolos de servidor y más. A lo largo
del libro, nos referiremos a secciones de este capítulo en caso de que tenga ganas de profundizar en ese punto;
pero si es como nosotros y desea profundizar en los detalles técnicos, es posible que desee leer primero el Capítulo 10.
Te lo dejamos a ti.
En el Apéndice A, observamos una serie de ejemplos del uso de Git en varios entornos específicos. Cubrimos
una serie de diferentes GUI y entornos de programación IDE en los que puede querer usar Git y lo que está
disponible para usted. Si está interesado en una descripción general del uso de Git en su shell, su IDE o su editor
de texto, eche un vistazo aquí.
En el Apéndice B, exploramos la creación de scripts y la extensión de Git a través de herramientas como libgit2 y JGit.
Si está interesado en escribir herramientas personalizadas complejas y rápidas y necesita acceso a Git de bajo nivel,
aquí es donde puede ver cómo se ve ese panorama.
Finalmente, en el Apéndice C, revisamos todos los comandos principales de Git uno por uno y revisamos en qué
parte del libro los cubrimos y qué hicimos con ellos. Si desea saber en qué parte del libro usamos un comando
específico de Git, puede buscarlo aquí.
Empecemos.
7
Machine Translated by Google
Empezando
Este capítulo tratará sobre cómo comenzar con Git. Comenzaremos explicando algunos antecedentes sobre las herramientas de control
de versiones, luego pasaremos a cómo hacer que Git se ejecute en su sistema y finalmente cómo configurarlo para comenzar a trabajar.
Al final de este capítulo, debe comprender por qué existe Git, por qué debe usarlo y debe estar preparado para hacerlo.
Si usted es un diseñador gráfico o web y desea conservar todas las versiones de una imagen o diseño (lo que sin duda desearía), un
Sistema de control de versiones (VCS) es una opción muy inteligente. Le permite revertir archivos seleccionados a un estado anterior,
revertir todo el proyecto a un estado anterior, comparar cambios a lo largo del tiempo, ver quién modificó por última vez algo que podría
estar causando un problema, quién introdujo un problema y cuándo, y más. El uso de un VCS generalmente también significa que si
arruina las cosas o pierde archivos, puede recuperarlos fácilmente. Además, obtienes todo esto por muy pocos gastos generales.
El método de control de versiones elegido por muchas personas es copiar archivos en otro directorio (quizás un directorio con marca de
tiempo, si son inteligentes). Este enfoque es muy común porque es muy simple, pero también es increíblemente propenso a errores. Es
fácil olvidar en qué directorio se encuentra y accidentalmente escribir en el archivo incorrecto o copiar archivos que no deseaba.
Para lidiar con este problema, los programadores desarrollaron hace mucho tiempo VCS locales que tenían una base de datos simple
que mantenía todos los cambios en los archivos bajo control de revisión.
8
Machine Translated by Google
Una de las herramientas VCS más populares fue un sistema llamado RCS, que todavía se distribuye con muchas
computadoras en la actualidad. RCS funciona manteniendo conjuntos de parches (es decir, las diferencias entre archivos)
en un formato especial en el disco; luego puede volver a crear el aspecto de cualquier archivo en cualquier momento
agregando todos los parches.
El siguiente gran problema que encuentran las personas es que necesitan colaborar con desarrolladores en otros sistemas.
Para hacer frente a este problema, se desarrollaron los Sistemas de Control de Versiones Centralizados (CVCS). Estos
sistemas (como CVS, Subversion y Perforce) tienen un solo servidor que contiene todos los archivos versionados y varios
clientes que extraen archivos de ese lugar central. Durante muchos años, este ha sido el estándar para el control de
versiones.
9
Machine Translated by Google
Esta configuración ofrece muchas ventajas, especialmente sobre los VCS locales. Por ejemplo, todos saben hasta
cierto punto lo que están haciendo los demás en el proyecto. Los administradores tienen un control detallado sobre
quién puede hacer qué, y es mucho más fácil administrar un CVCS que tratar con bases de datos locales en cada
cliente.
Sin embargo, esta configuración también tiene algunas desventajas serias. El más obvio es el único punto de falla que
representa el servidor centralizado. Si ese servidor se cae durante una hora, entonces durante esa hora nadie puede
colaborar en absoluto o guardar cambios versionados en cualquier cosa en la que estén trabajando. Si el disco duro en
el que se encuentra la base de datos central se corrompe y no se han realizado las copias de seguridad adecuadas,
perderá absolutamente todo: el historial completo del proyecto, excepto las instantáneas individuales que la gente tenga
en sus máquinas locales. Los VCS locales sufren el mismo problema: cada vez que tiene el historial completo del
proyecto en un solo lugar, corre el riesgo de perderlo todo.
Aquí es donde intervienen los sistemas de control de versiones distribuidos (DVCS). En un DVCS (como Git, Mercurial,
Bazaar o Darcs), los clientes no solo revisan la última instantánea de los archivos; más bien, reflejan completamente el
repositorio, incluido su historial completo. Por lo tanto, si algún servidor muere y estos sistemas estaban colaborando a
través de ese servidor, cualquiera de los repositorios del cliente se puede copiar en el servidor para restaurarlo. Cada
clon es realmente una copia de seguridad completa de todos los datos.
10
Machine Translated by Google
Además, muchos de estos sistemas manejan bastante bien tener varios repositorios remotos con los que
pueden trabajar, por lo que puede colaborar con diferentes grupos de personas de diferentes maneras
simultáneamente dentro del mismo proyecto. Esto le permite configurar varios tipos de flujos de trabajo
que no son posibles en sistemas centralizados, como modelos jerárquicos.
11
Machine Translated by Google
El kernel de Linux es un proyecto de software de código abierto de alcance bastante amplio. Durante los primeros años del mantenimiento
del kernel de Linux (1991–2002), los cambios en el software se transmitían como parches y archivos comprimidos. En 2002, el proyecto
del kernel de Linux comenzó a usar un DVCS patentado llamado BitKeeper.
En 2005, la relación entre la comunidad que desarrolló el kernel de Linux y la empresa comercial que desarrolló BitKeeper se rompió y
se revocó el estado gratuito de la herramienta. Esto llevó a la comunidad de desarrollo de Linux (y en particular a Linus Torvalds, el
creador de Linux) a desarrollar su propia herramienta basada en algunas de las lecciones que aprendieron mientras usaban BitKeeper.
Algunos de los objetivos del nuevo sistema eran los siguientes:
• Velocidad
• Diseño simple
• Totalmente distribuido
• Capaz de manejar proyectos grandes como el kernel de Linux de manera eficiente (velocidad y tamaño de datos)
Desde su nacimiento en 2005, Git ha evolucionado y madurado para ser fácil de usar y, sin embargo, conservar estas cualidades
iniciales. Es increíblemente rápido, es muy eficiente con proyectos grandes y tiene un increíble sistema de bifurcación para el desarrollo
no lineal (ver Git Branching).
¿Qué es Git?
Entonces, ¿qué es Git en pocas palabras? Esta es una sección importante para absorber, porque si comprende qué es Git y los
fundamentos de cómo funciona, entonces usar Git de manera efectiva probablemente será mucho más fácil para usted. A medida que
aprende Git, intente despejar su mente de las cosas que puede saber sobre otros VCS, como CVS, Subversion o Perforce; hacerlo lo
ayudará a evitar confusiones sutiles al usar la herramienta.
Aunque la interfaz de usuario de Git es bastante similar a estos otros VCS, Git almacena y piensa en la información de una manera muy
diferente, y comprender estas diferencias lo ayudará a evitar confundirse mientras lo usa.
Instantáneas, no diferencias
La principal diferencia entre Git y cualquier otro VCS (Subversion y sus amigos incluidos) es la forma en que Git piensa acerca de sus
datos. Conceptualmente, la mayoría de los otros sistemas almacenan información como una lista de cambios basados en archivos.
Estos otros sistemas (CVS, Subversion, Perforce, Bazaar, etc.) piensan en la información que almacenan como un conjunto de archivos
y los cambios realizados en cada archivo a lo largo del tiempo (esto se describe comúnmente como control de versión basado en delta ).
12
Machine Translated by Google
Figura 4. Almacenamiento de datos como cambios en una versión base de cada archivo
Git no piensa ni almacena sus datos de esta manera. En cambio, Git piensa en sus datos más como una serie de
instantáneas de un sistema de archivos en miniatura. Con Git, cada vez que confirma o guarda el estado de su
proyecto, Git básicamente toma una imagen de cómo se ven todos sus archivos en ese momento y almacena una
referencia a esa instantánea. Para ser eficiente, si los archivos no han cambiado, Git no vuelve a almacenar el
archivo, solo un enlace al archivo anterior idéntico que ya ha almacenado. Git piensa en sus datos más como un
flujo de instantáneas.
Figura 5. Almacenamiento de datos como instantáneas del proyecto a lo largo del tiempo
Esta es una distinción importante entre Git y casi todos los demás VCS. Hace que Git reconsidere casi todos los
aspectos del control de versiones que la mayoría de los otros sistemas copiaron de la generación anterior. Esto
hace que Git se parezca más a un mini sistema de archivos con algunas herramientas increíblemente poderosas
integradas, en lugar de simplemente un VCS. Exploraremos algunos de los beneficios que obtiene al pensar en sus
datos de esta manera cuando cubramos la bifurcación de Git en Git Branching.
La mayoría de las operaciones en Git solo necesitan archivos y recursos locales para funcionar; por lo general, no
se necesita información de otra computadora en su red. Si está acostumbrado a un CVCS donde la mayoría de las
operaciones tienen una sobrecarga de latencia de red, este aspecto de Git le hará pensar que los dioses de la
velocidad han bendecido a Git con poderes sobrenaturales. Como tiene todo el historial del proyecto en su disco
local, la mayoría de las operaciones parecen casi instantáneas.
13
Machine Translated by Google
Por ejemplo, para explorar el historial del proyecto, Git no necesita ir al servidor para obtener el historial y mostrárselo,
simplemente lo lee directamente desde su base de datos local. Esto significa que ve el historial del proyecto casi al
instante. Si desea ver los cambios introducidos entre la versión actual de un archivo y el archivo de hace un mes, Git
puede buscar el archivo de hace un mes y hacer un cálculo de diferencia local, en lugar de tener que pedirle a un
servidor remoto que lo haga. o extraiga una versión anterior del archivo del servidor remoto para hacerlo localmente.
Esto también significa que es muy poco lo que no puede hacer si está desconectado o desconectado de la VPN. Si te
subes a un avión o a un tren y quieres hacer un poco de trabajo, puedes comprometerte felizmente (con tu copia local ,
¿recuerdas?) hasta que llegues a una conexión de red para cargar. Si va a casa y no puede hacer que su cliente VPN
funcione correctamente, aún puede trabajar. En muchos otros sistemas, hacerlo es imposible o doloroso. En Perforce,
por ejemplo, no puedes hacer mucho cuando no estás conectado al servidor; en Subversion y CVS, puede editar
archivos, pero no puede enviar cambios a su base de datos (porque su base de datos está fuera de línea). Esto puede
no parecer un gran problema, pero es posible que se sorprenda de la gran diferencia que puede hacer.
Todo en Git se suma antes de que se almacene y luego se hace referencia a esa suma de verificación. Esto significa
que es imposible cambiar el contenido de cualquier archivo o directorio sin que Git lo sepa.
Esta funcionalidad está integrada en Git en los niveles más bajos y es parte integral de su filosofía. No puede perder
información en tránsito ni dañar el archivo sin que Git pueda detectarlo.
El mecanismo que usa Git para esta suma de verificación se llama hash SHA-1. Esta es una cadena de 40 caracteres
compuesta por caracteres hexadecimales (0–9 y a–f) y calculada en función del contenido de una estructura de archivo
o directorio en Git. Un hash SHA-1 se parece a esto:
24b9da6552252987aa493b52f8696cd6d3b00373
Verá estos valores hash por todas partes en Git porque los usa mucho. De hecho, Git almacena todo en su base de
datos no por nombre de archivo sino por el valor hash de su contenido.
Cuando realiza acciones en Git, casi todas solo agregan datos a la base de datos de Git. Es difícil hacer que el sistema
haga algo que no se pueda deshacer o que borre datos de alguna manera. Al igual que con cualquier VCS, puede
perder o estropear los cambios que aún no ha confirmado, pero después de confirmar una instantánea en Git, es muy
difícil perderla, especialmente si envía regularmente su base de datos a otro repositorio.
Esto hace que usar Git sea un placer porque sabemos que podemos experimentar sin el peligro de estropear gravemente
las cosas. Para obtener una visión más detallada de cómo Git almacena sus datos y cómo puede recuperar los datos
que parecen perdidos, consulte Deshacer cosas.
Preste atención ahora: esto es lo principal que debe recordar sobre Git si desea que el resto de su proceso de
aprendizaje transcurra sin problemas. Git tiene tres estados principales en los que pueden residir sus archivos:
modificado, preparado y confirmado:
14
Machine Translated by Google
• Modificado significa que ha cambiado el archivo pero aún no lo ha enviado a su base de datos.
• Preparado significa que ha marcado un archivo modificado en su versión actual para pasar a su próxima
instantánea de confirmación.
• Comprometido significa que los datos se almacenan de forma segura en su base de datos local.
Esto nos lleva a las tres secciones principales de un proyecto de Git: el árbol de trabajo, el área de preparación y el directorio de Git.
El árbol de trabajo es una comprobación única de una versión del proyecto. Estos archivos se extraen de la base de datos comprimida
en el directorio Git y se colocan en el disco para que los use o modifique.
El área de preparación es un archivo, generalmente contenido en su directorio Git, que almacena información sobre lo que se incluirá
en su próxima confirmación. Su nombre técnico en la jerga de Git es "índice", pero la frase "área de ensayo" funciona igual de bien.
El directorio de Git es donde Git almacena los metadatos y la base de datos de objetos para su proyecto. Esta es la parte más
importante de Git y es lo que se copia cuando clonas un repositorio desde otra computadora.
2. Organiza de forma selectiva solo aquellos cambios que desea que formen parte de su próxima confirmación, lo que agrega
sólo aquellos cambios en el área de preparación.
3. Realiza una confirmación, que toma los archivos tal como están en el área de preparación y almacena esa instantánea
permanentemente a su directorio Git.
Si una versión particular de un archivo está en el directorio de Git, se considera confirmada. si ha sido
15
Machine Translated by Google
modificado y se agregó al área de preparación, se organiza. Y si se modificó desde que se desprotegió pero no se ha puesto en
escena, se modifica. En Conceptos básicos de Git, aprenderá más sobre estos estados y cómo puede aprovecharlos u omitir la
parte preparada por completo.
La línea de comando
Hay muchas maneras diferentes de usar Git. Existen las herramientas de línea de comandos originales y hay muchas interfaces
gráficas de usuario de diferentes capacidades. Para este libro, usaremos Git en la línea de comando. Por un lado, la línea de
comandos es el único lugar donde puede ejecutar todos los comandos de Git: la mayoría de las GUI implementan solo un
subconjunto parcial de la funcionalidad de Git para simplificar. Si sabe cómo ejecutar la versión de línea de comandos,
probablemente también pueda descubrir cómo ejecutar la versión GUI, mientras que lo contrario no es necesariamente cierto.
Además, si bien la elección del cliente gráfico es una cuestión de gusto personal, todos los usuarios tendrán las herramientas de
línea de comandos instaladas y disponibles.
Por lo tanto, esperamos que sepa cómo abrir Terminal en macOS o Símbolo del sistema o PowerShell en Windows. Si no sabe
de lo que estamos hablando aquí, es posible que deba detenerse e investigar rápidamente para poder seguir el resto de los
ejemplos y descripciones de este libro.
Instalando Git
Antes de comenzar a usar Git, debe hacerlo disponible en su computadora. Incluso si ya está instalado, probablemente sea una
buena idea actualizar a la última versión. Puede instalarlo como un paquete o mediante otro instalador, o descargar el código
fuente y compilarlo usted mismo.
Este libro fue escrito usando Git versión 2.8.0. Aunque la mayoría de los comandos que usamos deberían
ÿ funcionar incluso en versiones antiguas de Git, es posible que algunos de ellos no funcionen o que actúen
de manera ligeramente diferente si está usando una versión anterior. Dado que Git es excelente para
preservar la compatibilidad con versiones anteriores, cualquier versión posterior a la 2.8 debería funcionar bien.
Instalación en Linux
Si desea instalar las herramientas básicas de Git en Linux a través de un instalador binario, generalmente puede hacerlo a
través de la herramienta de administración de paquetes que viene con su distribución. Si está en Fedora (o cualquier distribución
basada en RPM estrechamente relacionada, como RHEL o CentOS), puede usar dnf:
Si tiene una distribución basada en Debian, como Ubuntu, pruebe con apt:
Para obtener más opciones, hay instrucciones para instalar en varias distribuciones diferentes de Unix en el sitio web de Git, en
https://git-scm.com/download/linux.
dieciséis
Machine Translated by Google
Instalación en macOS
Hay varias formas de instalar Git en una Mac. Lo más fácil es probablemente instalar las herramientas de línea de
comandos de Xcode. En Mavericks (10.9) o superior, puede hacer esto simplemente intentando ejecutar git desde la
Terminal la primera vez.
$ git --versión
Si desea una versión más actualizada, también puede instalarla a través de un instalador binario. Se mantiene un
instalador de macOS Git y está disponible para su descarga en el sitio web de Git, en https://git-scm.com/download/
mac .
Instalación en Windows
También hay algunas formas de instalar Git en Windows. La compilación más oficial está disponible para descargar
en el sitio web de Git. Simplemente vaya a https://git-scm.com/download/win y la descarga comenzará
automáticamente. Tenga en cuenta que este es un proyecto llamado Git para Windows, que es independiente de Git
mismo; para obtener más información al respecto, vaya a https://gitforwindows.org.
Para obtener una instalación automática, puede usar el paquete Git Chocolatey. Tenga en cuenta que el paquete
Chocolatey es mantenido por la comunidad.
17
Machine Translated by Google
En cambio, algunas personas pueden encontrar útil instalar Git desde la fuente, porque obtendrá la versión más
reciente. Los instaladores binarios tienden a estar un poco atrasados, aunque como Git ha madurado en los últimos
años, esto ha hecho una diferencia menor.
Si desea instalar Git desde la fuente, debe tener las siguientes bibliotecas de las que depende Git: autotools, curl,
zlib, openssl, expat y libiconv. Por ejemplo, si está en un sistema que tiene dnf (como Fedora) o apt-get (como un
sistema basado en Debian), puede usar uno de estos comandos para instalar las dependencias mínimas para
compilar e instalar Git. binarios:
Para poder agregar la documentación en varios formatos (doc, html, info), se requieren estas dependencias
adicionales:
Si está utilizando una distribución basada en RPM (Fedora/RHEL/RHEL-derivatives), también necesita el paquete
getopt (que ya está instalado en una distribución basada en Debian):
Cuando tenga todas las dependencias necesarias, puede seguir adelante y obtener el tarball de lanzamiento
etiquetado más reciente de varios lugares. Puede obtenerlo a través del sitio kernel.org, en https://www.kernel.org/
pub/software/scm/git , o el espejo en el sitio web de GitHub, en https://github.com/git/git/releases. Es
18
Machine Translated by Google
generalmente un poco más claro cuál es la última versión en la página de GitHub, pero la página kernel.org también
tiene firmas de lanzamiento si desea verificar su descarga.
Una vez hecho esto, también puede obtener Git a través de Git mismo para obtener actualizaciones:
Ahora que tiene Git en su sistema, querrá hacer algunas cosas para personalizar su entorno Git. Debería tener que
hacer estas cosas solo una vez en cualquier computadora; se quedarán entre actualizaciones. También puede cambiarlos
en cualquier momento ejecutando los comandos nuevamente.
Git viene con una herramienta llamada git config que le permite obtener y establecer variables de configuración que
controlan todos los aspectos de cómo se ve y opera Git. Estas variables se pueden almacenar en tres lugares diferentes:
1. Archivo [ruta]/etc/gitconfig : Contiene valores aplicados a cada usuario en el sistema y todos sus repositorios. Si pasa
la opción --system a git config, lee y escribe desde este archivo específicamente. Debido a que este es un archivo
de configuración del sistema, necesitaría privilegios administrativos o de superusuario para realizar cambios en él.
2. Archivo ~/.gitconfig o ~/.config/git/config : valores específicos personalmente para usted, el usuario. Puede hacer que
Git lea y escriba en este archivo específicamente pasando la opción --global , y esto afecta a todos los repositorios
con los que trabaja en su sistema.
3. archivo de configuración en el directorio Git (es decir, .git /config) de cualquier repositorio que esté usando
actualmente: Específico para ese único repositorio. Puede obligar a Git a leer y escribir en este archivo con la opción
--local , pero de hecho, esa es la opción predeterminada. Como era de esperar, debe estar ubicado en algún lugar
de un repositorio de Git para que esta opción funcione correctamente.
Cada nivel anula los valores del nivel anterior, por lo que los valores en .git/config superan a los de [ruta]/etc/gitconfig.
En los sistemas Windows, Git busca el archivo .gitconfig en el directorio $HOME (C:\Users\$USER para la mayoría de
las personas). También sigue buscando [ruta]/etc/gitconfig, aunque es relativo a la raíz de MSys, que es donde decidas
instalar Git en tu sistema Windows cuando ejecutas el instalador. Si usa la versión 2.x o posterior de Git para Windows,
también hay un archivo de configuración de nivel de sistema en C:\Documentos y configuraciones\Todos los
usuarios\Datos de programa\Git\config en Windows XP, y en
19
Machine Translated by Google
C:\ProgramData\Git\config en Windows Vista y posteriores. Este archivo de configuración solo se puede cambiar con git config -f <archivo>
como administrador.
Tu identidad
Lo primero que debe hacer cuando instala Git es configurar su nombre de usuario y dirección de correo electrónico. Esto es importante
porque cada confirmación de Git usa esta información, y está integrada de forma inmutable en las confirmaciones que comienzas a crear:
Nuevamente, debe hacer esto solo una vez si pasa la opción --global , porque Git siempre usará esa información para cualquier cosa que
haga en ese sistema. Si desea anular esto con un nombre o dirección de correo electrónico diferente para proyectos específicos, puede
ejecutar el comando sin la opción --global cuando esté en ese proyecto.
Muchas de las herramientas GUI le ayudarán a hacer esto cuando las ejecute por primera vez.
Tu editor
Ahora que su identidad está configurada, puede configurar el editor de texto predeterminado que se usará cuando Git necesite que escriba
un mensaje. Si no está configurado, Git usa el editor predeterminado de su sistema.
Si desea utilizar un editor de texto diferente, como Emacs, puede hacer lo siguiente:
En un sistema Windows, si desea utilizar un editor de texto diferente, debe especificar la ruta completa a su archivo ejecutable. Esto puede
ser diferente dependiendo de cómo esté empaquetado su editor.
En el caso de Notepad++, un popular editor de programación, es probable que desee utilizar la versión de 32 bits, ya que en el momento
de escribir este artículo, la versión de 64 bits no es compatible con todos los complementos. Si está en un sistema Windows de 32 bits o
tiene un editor de 64 bits en un sistema de 64 bits, escribirá algo como esto:
20
Machine Translated by Google
Vim, Emacs y Notepad++ son editores de texto populares que suelen utilizar los desarrolladores en sistemas
ÿ basados en Unix como Linux y macOS o un sistema Windows. Si está utilizando otro editor o una versión
de 32 bits, busque instrucciones específicas sobre cómo configurar su editor favorito con Git en los
comandos git config core.editor.
Es posible que, si no configura su editor de esta manera, entre en un estado realmente confuso cuando Git
ÿ intente iniciarlo. Un ejemplo en un sistema Windows puede incluir una operación de Git finalizada
prematuramente durante una edición iniciada por Git.
Por defecto, Git creará una rama llamada master cuando crees un nuevo repositorio con git init.
Desde la versión 2.28 de Git en adelante, puede establecer un nombre diferente para la rama inicial.
Comprobación de su configuración
Si desea verificar sus ajustes de configuración, puede usar el comando git config --list para enumerar todos los ajustes que Git
puede encontrar en ese punto:
Es posible que vea claves más de una vez, porque Git lee la misma clave de diferentes archivos ([ruta]/etc/gitconfig y ~/.gitconfig,
por ejemplo). En este caso, Git usa el último valor para cada clave única que ve.
También puedes comprobar lo que Git cree que es el valor de una clave específica escribiendo git config <key>:
21
Machine Translated by Google
Dado que Git puede leer el mismo valor de la variable de configuración de más de un archivo, es
posible que tenga un valor inesperado para uno de estos valores y no sepa por qué. En casos como
ese, puede consultar a Git sobre el origen de ese valor, y le dirá qué archivo de configuración tuvo la
última palabra para establecer ese valor:
ÿ
$ git config --show-origin rerere.autoActualizar
archivo:/home/johndoe/.gitconfig false
Obteniendo ayuda
Si alguna vez necesita ayuda mientras usa Git, hay tres formas equivalentes de obtener la ayuda completa de la página
del manual (página de manual) para cualquiera de los comandos de Git:
Por ejemplo, puede obtener la ayuda de la página de manual para el comando git config ejecutando esto:
Estos comandos son buenos porque puedes acceder a ellos desde cualquier lugar, incluso sin conexión. Si las páginas
de manual y este libro no son suficientes y necesita ayuda en persona, puede probar los canales #git , #github o #gitlab
en el servidor IRC de Libera Chat, que se puede encontrar en https://libera. chat/. Estos canales se llenan regularmente
con cientos de personas que conocen muy bien Git y, a menudo, están dispuestas a ayudar.
Además, si no necesita la ayuda completa de la página de manual, pero solo necesita una actualización rápida de las
opciones disponibles para un comando de Git, puede solicitar la salida de "ayuda" más concisa con la opción -h , como
en :
22
Machine Translated by Google
$ git añadir -h
uso: git add [<opciones>] [--] <rutaespecificación>...
Resumen
Debes tener una comprensión básica de lo que es Git y en qué se diferencia de cualquier sistema centralizado.
sistemas de control de versiones que puede haber estado usando anteriormente. Ahora también debería tener un trabajo
versión de Git en su sistema que está configurada con su identidad personal. Ahora es el momento de aprender algunos
Conceptos básicos de Git.
23
Machine Translated by Google
Si solo puede leer un capítulo para comenzar con Git, es este. Este capítulo cubre todos los comandos básicos que necesita para
hacer la gran mayoría de las cosas que eventualmente dedicará su tiempo a hacer con Git. Al final del capítulo, debería poder
configurar e inicializar un repositorio, comenzar y detener el seguimiento de archivos y preparar y confirmar cambios. También le
mostraremos cómo configurar Git para ignorar ciertos archivos y patrones de archivo, cómo deshacer errores rápida y fácilmente,
cómo navegar por el historial de su proyecto y ver cambios entre confirmaciones, y cómo empujar y extraer desde repositorios
remotos. .
1. Puede tomar un directorio local que actualmente no está bajo control de versiones y convertirlo en un Git
repositorio, o
En cualquier caso, termina con un repositorio de Git en su máquina local, listo para trabajar.
para Linux:
$ cd /home/usuario/mi_proyecto
para macOS:
$ cd /Usuarios/usuario/mi_proyecto
para ventanas:
$ cd C:/Usuarios/usuario/mi_proyecto
y escriba:
$ git inicializar
Esto crea un nuevo subdirectorio llamado .git que contiene todos los archivos de repositorio necesarios: un esqueleto de repositorio
de Git. En este punto, todavía no se realiza un seguimiento de nada en su proyecto. Ver Git Internals para
24
Machine Translated by Google
más información sobre exactamente qué archivos están contenidos en el directorio .git que acaba de crear.
Si desea comenzar a controlar la versión de los archivos existentes (en lugar de un directorio vacío), probablemente
debería comenzar a rastrear esos archivos y realizar una confirmación inicial. Puede lograrlo con algunos comandos
de git add que especifican los archivos que desea rastrear, seguidos de una confirmación de git:
Repasaremos lo que hacen estos comandos en solo un minuto. En este punto, tiene un repositorio de Git con
archivos rastreados y una confirmación inicial.
Si desea obtener una copia de un repositorio de Git existente, por ejemplo, un proyecto al que le gustaría contribuir,
el comando que necesita es git clone. Si está familiarizado con otros VCS como Subversion, notará que el comando
es "clonar" y no "pagar". Esta es una distinción importante: en lugar de obtener solo una copia de trabajo, Git recibe
una copia completa de casi todos los datos que tiene el servidor. Cada versión de cada archivo para el historial del
proyecto se extrae de forma predeterminada cuando ejecuta git clone. De hecho, si el disco de su servidor se
corrompe, a menudo puede usar casi cualquiera de los clones en cualquier cliente para restablecer el servidor al
estado en el que se encontraba cuando fue clonado (puede perder algunos ganchos del lado del servidor y demás,
pero todos los datos versionados estarían allí; consulte Obtener Git en un servidor para obtener más detalles).
Clonas un repositorio con git clone <url>. Por ejemplo, si desea clonar la biblioteca enlazable de Git llamada libgit2,
puede hacerlo así:
Eso crea un directorio llamado libgit2, inicializa un directorio .git dentro de él, extrae todos los datos de ese repositorio
y extrae una copia de trabajo de la última versión. Si ingresa al nuevo directorio libgit2 que se acaba de crear, verá
los archivos del proyecto allí, listos para trabajar o usar.
Si desea clonar el repositorio en un directorio con un nombre diferente a libgit2, puede especificar el nuevo nombre
del directorio como argumento adicional:
Ese comando hace lo mismo que el anterior, pero el directorio de destino se llama mylibgit.
Git tiene varios protocolos de transferencia diferentes que puede usar. El ejemplo anterior usa el protocolo https:// ,
pero también puede ver git:// o user@server:path/to/repo.git, que usa el protocolo de transferencia SSH. Obtener
Git en un servidor presentará todas las opciones disponibles que el servidor puede configurar para acceder a su
repositorio de Git y las ventajas y desventajas de cada una.
25
Machine Translated by Google
Recuerde que cada archivo en su directorio de trabajo puede estar en uno de dos estados: rastreado o no rastreado .
Los archivos rastreados son archivos que estaban en la última instantánea, así como cualquier archivo recién preparado;
pueden ser sin modificar, modificados o escalonados. En resumen, los archivos rastreados son archivos que Git conoce.
Los archivos sin seguimiento son todo lo demás: cualquier archivo en su directorio de trabajo que no estaba en su última
instantánea y que no está en su área de preparación. Cuando clone un repositorio por primera vez, todos sus archivos
serán rastreados y no modificados porque Git los revisó y no ha editado nada.
A medida que edita archivos, Git los ve como modificados, porque los ha cambiado desde su última confirmación.
A medida que trabaja, prepara selectivamente estos archivos modificados y luego confirma todos esos cambios
preparados, y el ciclo se repite.
La herramienta principal que utiliza para determinar qué archivos están en qué estado es el comando git status . Si
ejecuta este comando directamente después de un clon, debería ver algo como esto:
$ git status
On branch
master Su rama está actualizada con 'origin/
master'. nada que cometer, árbol de trabajo limpio
Esto significa que tiene un directorio de trabajo limpio; en otras palabras, ninguno de sus archivos rastreados se modifica.
Git tampoco ve ningún archivo sin seguimiento, o se enumerarían aquí. Finalmente, el comando te dice en qué rama
estás y te informa que no se ha desviado de la misma
26
Machine Translated by Google
rama en el servidor. Por ahora, esa rama siempre es maestra, que es la predeterminada; no te preocupes por eso aquí.
Git Branching revisará las ramas y las referencias en detalle.
Supongamos que agrega un nuevo archivo a su proyecto, un simple archivo LÉAME . Si el archivo no existía antes y
ejecuta git status, verá su archivo sin seguimiento así:
LÉAME
no se agregó nada para confirmar, pero hay archivos sin rastrear presentes (use "git add" para rastrear)
Puede ver que su nuevo archivo README no tiene seguimiento, porque está bajo el encabezado "Archivos sin
seguimiento" en su salida de estado. Básicamente, sin seguimiento significa que Git ve un archivo que no tenía en la
instantánea anterior (confirmación) y que aún no se ha preparado; Git no comenzará a incluirlo en tus instantáneas de
confirmación hasta que le indiques explícitamente que lo haga. Hace esto para que no comience a incluir accidentalmente
archivos binarios generados u otros archivos que no tenía la intención de incluir. Desea comenzar a incluir README, así
que comencemos a rastrear el archivo.
Para comenzar a rastrear un nuevo archivo, usa el comando git add. Para comenzar a rastrear el archivo LÉAME , puede
ejecutar esto:
Si ejecuta su comando de estado nuevamente, puede ver que su archivo README ahora está rastreado y preparado
para ser confirmado:
$ git status On
branch master Su
rama está actualizada con 'origin/master'.
Cambios a confirmar: (use "git
restore --staged <archivo>..." para quitar la preparación)
Se puede decir que está organizado porque está bajo el encabezado "Cambios por confirmar". Si se compromete en este
punto, la versión del archivo en el momento en que ejecutó git add es la que estará en la siguiente instantánea histórica.
Puede recordar que cuando ejecutó git init anteriormente, luego ejecutó git add <files> , eso fue para comenzar a rastrear
archivos en su directorio. El comando git add toma un camino
27
Machine Translated by Google
nombre para un archivo o un directorio; si es un directorio, el comando agrega todos los archivos en ese directorio
recursivamente.
Cambiemos un archivo que ya fue rastreado. Si cambia un archivo previamente rastreado llamado CONTRIBUTING.md
y luego ejecuta su comando de estado de git nuevamente, obtendrá algo similar a esto:
$ git status On
branch master Su
rama está actualizada con 'origin/master'.
Cambios a confirmar: (use "git
reset HEAD <archivo>..." para quitar la preparación)
modificado: CONTRIBUYENDO.md
El archivo CONTRIBUTING.md aparece en una sección denominada "Cambios no preparados para confirmación", lo
que significa que un archivo del que se realiza un seguimiento se ha modificado en el directorio de trabajo pero aún no
está preparado. Para prepararlo, ejecuta el comando git add . git add es un comando multipropósito: lo usa para
comenzar a rastrear archivos nuevos, organizar archivos y hacer otras cosas, como marcar archivos en conflicto de
fusión como resueltos. Puede ser útil pensar en ello más como "agregar precisamente este contenido a la próxima
confirmación" en lugar de "agregar este archivo al proyecto". Ejecutemos git add ahora para preparar el archivo
CONTRIBUTING.md y luego ejecutemos git status nuevamente:
Ambos archivos están preparados y se incluirán en su próxima confirmación. En este punto, suponga que recuerda un
pequeño cambio que desea realizar en CONTRIBUTING.md antes de confirmarlo. Lo abres de nuevo y haces ese
cambio, y estás listo para comprometerte. Sin embargo, ejecutemos git status una vez más:
28
Machine Translated by Google
$ vim CONTRIBUTING.md
$ git status On branch master
Su rama está actualizada
con 'origin/master'.
Cambios a confirmar: (use "git
reset HEAD <archivo>..." para quitar la preparación)
modificado: CONTRIBUYENDO.md
¿Que demonios? Ahora CONTRIBUTING.md aparece como preparado y sin preparar. ¿Cómo es eso posible?
Resulta que Git presenta un archivo exactamente como está cuando ejecuta el comando git add . Si confirma
ahora, la versión de CONTRIBUTING.md que tenía la última vez que ejecutó el comando git add es la forma en
que se ingresará en la confirmación, no la versión del archivo como se ve en su directorio de trabajo cuando
ejecuta git commit. Si modifica un archivo después de ejecutar git add, debe ejecutar git add nuevamente para
preparar la última versión del archivo:
Estado corto
Si bien la salida de estado de git es bastante completa, también es bastante prolija. Git también tiene un indicador
de estado corto para que pueda ver sus cambios de una manera más compacta. Si ejecuta git status -s o git
status --short , obtiene un resultado mucho más simplificado del comando:
$ git estado -s
M LÉAME
MM Rakefile A
lib/git.rb M lib/
simplegit.rb ?? LICENCIA.txt
29
Machine Translated by Google
Los archivos nuevos que no se rastrean tienen un ?? junto a ellos, los archivos nuevos que se agregaron al área de preparación tienen una
A, los archivos modificados tienen una M , etc. Hay dos columnas en la salida: la columna de la izquierda indica el estado del área de
preparación y la columna de la derecha indica el estado del árbol de trabajo. Entonces, por ejemplo, en esa salida, el archivo README se
modifica en el directorio de trabajo pero aún no se prepara, mientras que el archivo lib/simplegit.rb se modifica y se prepara. El Rakefile se
modificó, preparó y luego volvió a modificar, por lo que hay cambios que están preparados y no preparados.
Ignorar archivos
A menudo, tendrás una clase de archivos que no deseas que Git agregue automáticamente o que incluso te muestre como sin seguimiento.
Por lo general, estos son archivos generados automáticamente, como archivos de registro o archivos producidos por su sistema de
compilación. En tales casos, puede crear un archivo que enumere patrones para que coincidan con el nombre .gitignore. Aquí hay un
ejemplo de archivo .gitignore :
$ gato .gitignore
*.[oa]
*~
La primera línea le dice a Git que ignore cualquier archivo que termine en ".o" o ".a": archivos de objetos y archivos que pueden ser el
producto de la construcción de su código. La segunda línea le dice a Git que ignore todos los archivos cuyos nombres terminen con una
tilde (~), que es utilizada por muchos editores de texto como Emacs para marcar archivos temporales. También puede incluir un directorio
log, tmp o pid; documentación generada automáticamente; y así. Por lo general, es una buena idea configurar un archivo .gitignore para su
nuevo repositorio antes de comenzar, de modo que no envíe accidentalmente archivos que realmente no desea en su repositorio de Git.
Las reglas para los patrones que puede poner en el archivo .gitignore son las siguientes:
• Los patrones globales estándar funcionan y se aplicarán recursivamente a lo largo de todo el proceso.
árbol.
• Puede comenzar los patrones con una barra diagonal (/) para evitar la recursividad.
• Puede finalizar los patrones con una barra diagonal (/) para especificar un directorio.
Los patrones globales son como expresiones regulares simplificadas que usan los shells. Un asterisco (*) coincide con cero o más
caracteres; [abc] coincide con cualquier carácter dentro de los corchetes (en este caso, a, b o c); un signo de interrogación (?) coincide con
un solo carácter; y los corchetes que encierran caracteres separados por un guión ([0-9]) coinciden con cualquier carácter entre ellos (en
este caso, del 0 al 9). También puede usar dos asteriscos para hacer coincidir directorios anidados; a/**/z coincidiría con a/z, a/b/z, a/b/c/z,
etc.
30
Machine Translated by Google
# pero haga un seguimiento de lib.a, aunque esté ignorando los archivos .a arriba de !lib.a
# ignorar todos los archivos .pdf en el directorio doc/ y cualquiera de sus subdirectorios doc/**/*.pdf
GitHub mantiene una lista bastante completa de buenos ejemplos de archivos .gitignore para
ÿ docenas de proyectos e idiomas en https://github.com/github/gitignore si quieres un punto de
partida para tu proyecto.
En el caso simple, un repositorio podría tener un solo archivo .gitignore en su directorio raíz,
que se aplica recursivamente a todo el repositorio. Sin embargo, también es posible tener
archivos .gitignore adicionales en subdirectorios. Las reglas de estos archivos .gitignore
ÿ anidados se aplican solo a los archivos del directorio en el que se encuentran. El repositorio
fuente del kernel de Linux tiene 206 archivos .gitignore .
Está más allá del alcance de este libro entrar en los detalles de múltiples archivos .gitignore ;
ver man gitignore para los detalles.
Si el comando de estado de git es demasiado vago para usted (quiere saber exactamente qué cambió, no solo
qué archivos se cambiaron), puede usar el comando git diff . Cubriremos git diff con más detalle más adelante,
pero probablemente lo usará más a menudo para responder estas dos preguntas: ¿Qué ha cambiado pero aún
no ha puesto en escena? ¿Y qué has puesto en escena que estás a punto de cometer? Aunque git status
responde a esas preguntas de manera muy general al enumerar los nombres de los archivos, git diff le muestra
las líneas exactas agregadas y eliminadas: el parche, por así decirlo.
Supongamos que edita y prepara el archivo README nuevamente y luego edita el archivo CONTRIBUTING.md
sin prepararlo. Si ejecuta su comando de estado de git , una vez más verá algo como esto:
31
Machine Translated by Google
$ git status On
branch master Su
rama está actualizada con 'origin/master'.
Cambios a confirmar: (use "git
reset HEAD <archivo>..." para quitar la preparación)
modificado: LÉAME
modificado: CONTRIBUYENDO.md
Para ver lo que ha cambiado pero que aún no ha preparado, escriba git diff sin otros argumentos:
Si está comenzando a trabajar en un área en particular, siéntase libre de enviar un PR que destaque su
trabajo en progreso (y tenga en cuenta en el título del PR que es
Ese comando compara lo que está en su directorio de trabajo con lo que está en su área de preparación. El
resultado le indica los cambios que ha realizado y que aún no ha realizado.
Si desea ver lo que ha organizado que se incluirá en su próxima confirmación, puede usar git diff --staged. Este
comando compara sus cambios por etapas con su última confirmación:
32
Machine Translated by Google
Es importante tener en cuenta que git diff por sí mismo no muestra todos los cambios realizados desde su última
confirmación, solo los cambios que aún no están preparados. Si ha preparado todos sus cambios, git diff no le dará
ningún resultado.
Para otro ejemplo, si prepara el archivo CONTRIBUTING.md y luego lo edita, puede usar git diff para ver los cambios
en el archivo que están preparados y los cambios que no están preparados. Si nuestro entorno se ve así:
modificado: CONTRIBUYENDO.md
modificado: CONTRIBUYENDO.md
Ahora puedes usar git diff para ver lo que aún no está preparado:
y git diff --cached para ver lo que has preparado hasta ahora (--staged y --cached son sinónimos):
33
Machine Translated by Google
Incluya una buena descripción de sus cambios cuando envíe su PR; si tenemos que leer la
diferencia completa para averiguar por qué está contribuyendo en primer lugar, es menos
probable que reciba comentarios y que su cambio se fusione. Además, divida sus cambios en
partes integrales si tu parche es +más largo que una docena de líneas.
Continuaremos usando el comando git diff de varias maneras a lo largo del resto del libro. Hay
otra forma de ver estas diferencias si prefiere un programa de visualización de diferencias
ÿ gráficas o externas. Si ejecuta git difftool en lugar de git diff, puede ver cualquiera de estas
diferencias en software como emerge, vimdiff y muchos más (incluidos los productos
comerciales). Ejecute git difftool --tool-help para ver qué hay disponible en su sistema.
$ git confirmar
34
Machine Translated by Google
# Ingrese el mensaje de confirmación para sus cambios. Las líneas que comiencen # con '#'
se ignorarán y un mensaje vacío anulará la confirmación.
# On branch master # Tu
sucursal está actualizada con 'origen/master'. #
~
~
~
Puede ver que el mensaje de confirmación predeterminado contiene la última salida del comando de estado de git comentada y
una línea vacía en la parte superior. Puede eliminar estos comentarios y escribir su mensaje de confirmación, o puede dejarlos allí
para que le ayuden a recordar lo que está confirmando.
Para un recordatorio aún más explícito de lo que ha modificado, puede pasar la opción -v a git commit. Si lo
ÿ hace, también pone la diferencia de su cambio en el editor para que pueda ver exactamente qué cambios
está confirmando.
Cuando sales del editor, Git crea tu confirmación con ese mensaje de confirmación (sin los comentarios ni las diferencias).
Alternativamente, puede escribir su mensaje de confirmación en línea con el comando de confirmación especificándolo después
de un indicador -m , como este:
¡Ahora has creado tu primer compromiso! Puede ver que la confirmación le ha dado algunos resultados sobre sí misma: en qué
rama se comprometió (maestro), qué suma de verificación SHA-1 tiene la confirmación (463dc4f), cuántos archivos se cambiaron
y estadísticas sobre las líneas agregadas y eliminadas en el cometer.
Recuerde que la confirmación registra la instantánea que configuró en su área de preparación. Todo lo que no escenificaste
todavía está allí modificado; puedes hacer otro compromiso para agregarlo a tu historial. Cada vez que realiza una confirmación,
está grabando una instantánea de su proyecto a la que puede volver o comparar más tarde.
Aunque puede ser increíblemente útil para crear compromisos exactamente como los desea, el área de preparación a veces es
un poco más compleja de lo que necesita en su flujo de trabajo. Si quieres saltarte la
35
Machine Translated by Google
área de preparación, Git proporciona un atajo simple. Agregar la opción -a al comando de confirmación de git hace que Git
organice automáticamente todos los archivos que ya están rastreados antes de realizar la confirmación, lo que le permite omitir
la parte de agregar de git :
$ git status On
branch master Su
rama está actualizada con 'origin/master'.
Cambios no preparados para
confirmación: (use "git add <archivo>..." para actualizar lo que se confirmará)
(use "git checkout -- <archivo>..." para descartar cambios en el directorio de trabajo)
modificado: CONTRIBUYENDO.md
no se agregaron cambios para confirmar (use "git add" y/o "git commit -a") $ git commit
-a -m 'Agregar nuevos puntos de referencia' [master 83e38c7] Agregar nuevos puntos
de referencia 1 archivo cambiado, 5 inserciones (+), 0 eliminaciones (-)
Observe cómo no tiene que ejecutar git add en el archivo CONTRIBUTING.md en este caso antes de comprometerse.
Eso es porque el indicador -a incluye todos los archivos modificados. Esto es conveniente, pero tenga cuidado; a veces, esta
bandera hará que incluya cambios no deseados.
Eliminación de archivos
Para eliminar un archivo de Git, debe eliminarlo de sus archivos rastreados (más precisamente, eliminarlo de su área de
preparación) y luego confirmar. El comando git rm hace eso y también elimina el archivo de su directorio de trabajo para que no
lo vea como un archivo sin seguimiento la próxima vez.
Si simplemente elimina el archivo de su directorio de trabajo, aparece en el área "Cambios no preparados para confirmación" (es
decir, no preparados) de su salida de estado de git :
$ rm PROJECTS.md
$ git status On
branch master Su
rama está actualizada con 'origin/master'.
Cambios no preparados para
confirmación: (use "git add/rm <archivo>..." para actualizar lo que se confirmará)
(use "git checkout -- <archivo>..." para descartar cambios en el directorio de trabajo)
eliminado: PROYECTOS.md
no se agregaron cambios para confirmar (use "git add" y/o "git commit -a")
36
Machine Translated by Google
$ git rm PROJECTS.md rm
'PROJECTS.md' $ git
status On branch master
Su rama está actualizada
con 'origin/master'.
Cambios a confirmar: (use "git
reset HEAD <archivo>..." para quitar la preparación)
eliminado: PROYECTOS.md
La próxima vez que confirme, el archivo desaparecerá y ya no se rastreará. Si modificó el archivo o ya lo había agregado al área de
preparación, debe forzar la eliminación con la opción -f . Esta es una función de seguridad para evitar la eliminación accidental de datos
que aún no se han registrado en una instantánea y que no se pueden recuperar de Git.
Otra cosa útil que puede hacer es mantener el archivo en su árbol de trabajo pero eliminarlo de su área de preparación. En otras palabras,
es posible que desee mantener el archivo en su disco duro pero que Git no lo rastree nunca más. Esto es particularmente útil si olvidó
agregar algo a su archivo .gitignore y accidentalmente lo preparó, como un archivo de registro grande o un montón de archivos
compilados .a . Para hacer esto, use la opción --cached :
Puede pasar archivos, directorios y patrones de archivos globales al comando git rm . Eso significa que puedes hacer cosas como:
$ git rm registro/\*.registro
Tenga en cuenta la barra invertida (\) delante del *. Esto es necesario porque Git hace su propia expansión de nombre de archivo además
de la expansión de nombre de archivo de su shell. Este comando elimina todos los archivos que tienen la extensión .log en el directorio
log/ . O bien, puede hacer algo como esto:
$ git rm \*~
Mover archivos
A diferencia de muchos otros VCS, Git no realiza un seguimiento explícito del movimiento de archivos. Si cambia el nombre de un archivo
en Git, no se almacenan metadatos en Git que indiquen que cambió el nombre del archivo. Sin embargo, Git es bastante inteligente al
darse cuenta de eso después del hecho: nos ocuparemos de detectar el movimiento de archivos un poco más tarde.
Por lo tanto, es un poco confuso que Git tenga un comando mv . Si desea cambiar el nombre de un archivo en Git, puede ejecutar algo
como:
37
Machine Translated by Google
y funciona bien De hecho, si ejecuta algo como esto y mira el estado, verá que Git lo considera un archivo renombrado:
$ mv LÉAME.md LÉAME $
git rm LÉAME.md $ git add
LÉAME
Git se da cuenta de que es un cambio de nombre implícitamente, por lo que no importa si cambia el nombre de un archivo
de esa manera o con el comando mv . La única diferencia real es que git mv es un comando en lugar de tres: es una función
de conveniencia. Más importante aún, puede usar cualquier herramienta que desee para cambiar el nombre de un archivo y
abordar el add/rm más tarde, antes de confirmar.
Después de haber creado varias confirmaciones, o si ha clonado un repositorio con un historial de confirmaciones existente,
probablemente querrá mirar hacia atrás para ver qué sucedió. La herramienta más básica y poderosa para hacer esto es el
comando git log .
Estos ejemplos usan un proyecto muy simple llamado "simplegit". Para obtener el proyecto, ejecute:
Cuando ejecutas git log en este proyecto, deberías obtener un resultado similar a este:
38
Machine Translated by Google
$ git log
compromiso ca82a6dff817ec66f44342007202690a93763949
Autor: Scott Chacon <schacon@gee-mail.com>
Fecha: lun 17 de marzo 21:52:11 2008 -0700
cometer 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Autor: Scott Chacon <schacon@gee-mail.com> Fecha:
sábado 15 de marzo 16:40:33 2008 -0700
cometer a11bef06a3f659402fe7563abf99ad00de2209e6
Autor: Scott Chacon <schacon@gee-mail.com> Fecha:
sábado 15 de marzo 10:31:28 2008 -0700
Compromiso inicial
De forma predeterminada, sin argumentos, git log enumera las confirmaciones realizadas en ese repositorio en orden
cronológico inverso; es decir, las confirmaciones más recientes aparecen primero. Como puede ver, este comando enumera
cada confirmación con su suma de verificación SHA-1, el nombre y el correo electrónico del autor, la fecha de escritura y el
mensaje de confirmación.
Hay disponible una gran cantidad y variedad de opciones para el comando git log para mostrarle exactamente lo que está
buscando. Aquí te mostraremos algunos de los más populares.
Una de las opciones más útiles es -p o --patch, que muestra la diferencia (la salida del parche ) introducida en cada
confirmación. También puede limitar la cantidad de entradas de registro que se muestran, como usar -2 para mostrar solo
las dos últimas entradas.
39
Machine Translated by Google
$ git registro -p -2
cometer ca82a6dff817ec66f44342007202690a93763949
s.plataforma = Gema::Plataforma::RUBY
ÿ
nombre de = "simplegit"
- s.versión = "0.1.0"
+ s.versión = "0.1.1"
ÿ
s.email = "schacon@gee-mail.com"
ÿ
confirmar 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -18,8 +18,3 @@ clase SimpleGit
ÿ
final
final
-
-si $0 == __ARCHIVO__
- git = SimpleGit.nuevo
- pone git.show
-final
Esta opción muestra la misma información pero con una diferencia directamente después de cada entrada. Esto es muy
útil para la revisión de código o para explorar rápidamente lo que sucedió durante una serie de confirmaciones que un
ha añadido el colaborador. También puede usar una serie de opciones de resumen con git log. Para
Por ejemplo, si desea ver algunas estadísticas abreviadas para cada confirmación, puede usar la opción --stat :
40
Machine Translated by Google
archivo de rastrillo
| 2 +- 1 archivo cambiado, 1 inserción (+), 1 borrado (-)
cometer 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Autor: Scott Chacon <schacon@gee-mail.com> Fecha:
sábado 15 de marzo 16:40:33 2008 -0700
cometer a11bef06a3f659402fe7563abf99ad00de2209e6
Autor: Scott Chacon <schacon@gee-mail.com> Fecha:
sábado 15 de marzo 10:31:28 2008 -0700
Compromiso inicial
Como puede ver, la opción --stat imprime debajo de cada entrada de confirmación una lista de archivos
modificados, cuántos archivos se cambiaron y cuántas líneas en esos archivos se agregaron y eliminaron.
También pone un resumen de la información al final.
Otra opción realmente útil es --pretty. Esta opción cambia la salida del registro a formatos distintos al
predeterminado. Hay algunos valores de opciones preconstruidos disponibles para su uso. El valor de una
sola línea para esta opción imprime cada confirmación en una sola línea, lo cual es útil si está viendo muchas
confirmaciones. Además, los valores short, full y fuller muestran la salida aproximadamente en el mismo
formato pero con menos o más información, respectivamente:
El valor de opción más interesante es el formato, que le permite especificar su propio formato de salida de
registro. Esto es especialmente útil cuando genera resultados para el análisis de la máquina, ya que especifica
el formato explícitamente, sabe que no cambiará con las actualizaciones de Git:
41
Machine Translated by Google
Especificadores útiles para git log --pretty=format enumera algunos de los especificadores más útiles que formatean
toma.
%H cometer hash
%T hachís de árbol
%PAGS
Hashes principales
%pags
Hashes principales abreviados
%anuncio
Fecha del autor (el formato respeta la opción --date=)
%Arkansas
Autor fecha, relativa
%discos compactos
fecha de confirmación
%cr
Fecha de compromiso, relativo
%s
Tema
persona que originalmente escribió el trabajo, mientras que el autor es la última persona que aplicó el
trabajo. Entonces, si envía un parche a un proyecto y uno de los miembros principales aplica el parche, ambos
obtienes crédito: tú como autor y el miembro principal como autor. Cubriremos esto
distinción un poco más en Distributed Git.
Los valores de las opciones oneline y format son particularmente útiles con otra opción de registro llamada --graph.
Esta opción agrega un pequeño y agradable gráfico ASCII que muestra su rama e historial de combinación:
42
Machine Translated by Google
Este tipo de salida se volverá más interesante a medida que avanzamos en la ramificación y la fusión en el
Siguiente capítulo.
Esas son solo algunas opciones simples de formato de salida para git log ; hay muchas más. Común
options to git log enumera las opciones que hemos cubierto hasta ahora, así como algunos otros formatos comunes
opciones que pueden ser útiles, junto con cómo cambian la salida del comando de registro.
Opción Descripción
-pags
Muestra el parche introducido con cada confirmación.
--shortstat
Muestra solo la línea de cambios/inserciones/eliminaciones del comando --stat.
--abbrev-commit Muestra solo los primeros caracteres de la suma de verificación SHA-1 en lugar de los 40.
--fecha-relativa
Mostrar la fecha en un formato relativo (por ejemplo, "hace 2 semanas") en lugar de
utilizando el formato de fecha completa.
--grafico Muestre un gráfico ASCII de la rama y combine el historial junto a la salida del registro.
--bonito Mostrar confirmaciones en un formato alternativo. Los valores de opción incluyen oneline, short,
completo, más completo y formato (donde usted especifica su propio formato).
--una línea
Abreviatura de --pretty=oneline --abbrev-commit usados juntos.
Además de las opciones de formato de salida, git log tiene varias opciones de limitación útiles; es decir,
opciones que le permiten mostrar solo un subconjunto de confirmaciones. Ya has visto una de esas opciones: el -2
opción, que muestra solo las dos últimas confirmaciones. De hecho, puede hacer -<n>, donde n es cualquier número entero para
muestra las últimas n confirmaciones. En realidad, es poco probable que lo use a menudo, porque Git canaliza por defecto todos
salida a través de un buscapersonas para que solo vea una página de salida de registro a la vez.
Sin embargo, las opciones de límite de tiempo como --since y --until son muy útiles. Por ejemplo, este
El comando obtiene la lista de confirmaciones realizadas en las últimas dos semanas:
43
Machine Translated by Google
Este comando funciona con muchos formatos: puede especificar una fecha específica como "2008-01-15" o una fecha relativa como
"hace 2 años, 1 día, 3 minutos".
También puede filtrar la lista para confirmaciones que coincidan con algunos criterios de búsqueda. La opción --author le permite filtrar
por un autor específico, y la opción --grep le permite buscar palabras clave en los mensajes de confirmación.
Puede especificar más de una instancia de los criterios de búsqueda --author y --grep , lo que limitará la salida
de la confirmación a confirmaciones que coincidan con cualquiera de los patrones --author y cualquiera de los
ÿ patrones --grep ; sin embargo, agregar la opción --all-match limita aún más la salida a solo aquellas
confirmaciones que coinciden con todos los patrones --grep .
Otro filtro realmente útil es la opción -S (coloquialmente conocida como la opción "pickaxe" de Git), que toma una cadena y muestra
solo las confirmaciones que cambiaron el número de ocurrencias de esa cadena. Por ejemplo, si quisiera encontrar la última
confirmación que agregó o eliminó una referencia a una función específica, podría llamar a:
La última opción realmente útil para pasar a git log como filtro es una ruta. Si especifica un directorio o un nombre de archivo, puede
limitar la salida del registro a las confirmaciones que introdujeron un cambio en esos archivos. Esta es siempre la última opción y
generalmente está precedida por guiones dobles (--) para separar las rutas de las opciones:
En Opciones para limitar la salida de git log , enumeraremos estas y algunas otras opciones comunes para su referencia.
Opción Descripción
-<n>
Mostrar solo las últimas n confirmaciones
--desde, --después Limite las confirmaciones a las realizadas después de la fecha especificada.
--hasta, --antes Limite las confirmaciones a las realizadas antes de la fecha especificada.
--autor
Mostrar solo confirmaciones en las que la entrada del autor coincida con la
cadena especificada.
--committer
Mostrar solo confirmaciones en las que la entrada del confirmador coincida con la
cadena especificada.
--grep Mostrar solo confirmaciones con un mensaje de confirmación que contenga la cadena
44
Machine Translated by Google
Opción Descripción
-S
Mostrar solo confirmaciones agregando o eliminando código que coincida con la cadena
Por ejemplo, si desea ver qué confirmaciones que modifican archivos de prueba en el historial del código fuente de Git fueron
confirmadas por Junio Hamano en el mes de octubre de 2008 y no son confirmaciones de combinación, puede ejecutar algo como
esto:
De las casi 40ÿ000 confirmaciones en el historial del código fuente de Git, este comando muestra las 6 que coinciden con esos criterios.
Dependiendo del flujo de trabajo utilizado en su repositorio, es posible que un porcentaje considerable de las
ÿ confirmaciones en su historial de registro sean solo confirmaciones de combinación, que normalmente no son
muy informativas. Para evitar que la visualización de confirmaciones de combinación sature su historial de
registro, simplemente agregue la opción de registro --no-merges.
Deshacer cosas
En cualquier etapa, es posible que desee deshacer algo. Aquí, revisaremos algunas herramientas básicas para deshacer los cambios
que ha realizado. Tenga cuidado, porque no siempre puede deshacer algunos de estos deshacer. Esta es una de las pocas áreas en
Git donde puede perder algo de trabajo si lo hace mal.
Uno de los deshacer comunes tiene lugar cuando se confirma demasiado pronto y posiblemente se olvida de agregar algunos archivos,
o se estropea el mensaje de confirmación. Si desea rehacer esa confirmación, realice los cambios adicionales que olvidó, organícelos
y confirme nuevamente usando la opción --amend :
Este comando toma su área de preparación y la usa para la confirmación. Si no ha realizado cambios desde su última confirmación
(por ejemplo, ejecuta este comando inmediatamente después de su confirmación anterior), su instantánea se verá exactamente igual
y todo lo que cambiará es su mensaje de confirmación.
Se activa el mismo editor de mensajes de confirmación, pero ya contiene el mensaje de su confirmación anterior. Puede editar el
mensaje como siempre, pero sobrescribe su confirmación anterior.
Como ejemplo, si se compromete y luego se da cuenta de que olvidó realizar los cambios en un archivo que deseaba
45
Machine Translated by Google
Terminas con una sola confirmación: la segunda confirmación reemplaza los resultados de la primera.
Es importante comprender que cuando está modificando su último compromiso, no lo está arreglando
sino reemplazándolo por completo con un compromiso nuevo y mejorado que elimina el compromiso
anterior y coloca el compromiso nuevo en su lugar.
Efectivamente, es como si la confirmación anterior nunca hubiera ocurrido y no aparecerá en el
ÿ historial de tu repositorio.
El valor obvio de modificar las confirmaciones es realizar pequeñas mejoras en su última confirmación,
sin saturar el historial de su repositorio con mensajes de confirmación del tipo "Oops, olvidé agregar
un archivo" o "Maldita sea, arreglando un error tipográfico en la última confirmación".
Solo modifique las confirmaciones que todavía son locales y no se han enviado a ninguna parte.
Las siguientes dos secciones demuestran cómo trabajar con su área de preparación y cambios en el directorio de trabajo.
Lo bueno es que el comando que usa para determinar el estado de esas dos áreas también le recuerda cómo deshacer
los cambios en ellas. Por ejemplo, supongamos que ha cambiado dos archivos y desea confirmarlos como dos cambios
separados, pero accidentalmente escribe git add * y prepara ambos. ¿Cómo puedes quitar el escenario a uno de los dos?
El comando de estado de git te recuerda:
Justo debajo del texto "Cambios por confirmar", dice use git reset HEAD <archivo>... para quitar la preparación. Entonces,
usemos ese consejo para eliminar el archivo CONTRIBUTING.md :
46
Machine Translated by Google
modificado: CONTRIBUYENDO.md
El comando es un poco extraño, pero funciona. El archivo CONTRIBUTING.md se modifica, pero una vez más se
deshace.
Es cierto que git reset puede ser un comando peligroso, especialmente si proporciona el
ÿ indicador --hard . Sin embargo, en el escenario descrito anteriormente, el archivo en su directorio
de trabajo no se toca, por lo que es relativamente seguro.
Por ahora, esta invocación mágica es todo lo que necesitas saber sobre el comando git reset . Entraremos en
muchos más detalles sobre lo que hace el reinicio y cómo dominarlo para hacer cosas realmente interesantes en
Reset Demystified.
¿Qué sucede si se da cuenta de que no desea conservar los cambios en el archivo CONTRIBUTING.md ? ¿Cómo
puede desmodificarlo fácilmente, revertirlo a la apariencia que tenía la última vez que se comprometió (o clonó
inicialmente, o como lo ingresó en su directorio de trabajo)? Afortunadamente, git status también te dice cómo
hacerlo. En el resultado del último ejemplo, el área no preparada se ve así:
modificado: CONTRIBUYENDO.md
Le dice bastante explícitamente cómo descartar los cambios que ha realizado. Hagamos lo que dice:
47
Machine Translated by Google
ÿ Cualquier cambio local que haya realizado en ese archivo se ha ido: Git simplemente reemplazó ese
archivo con la última versión preparada o confirmada. Nunca use este comando a menos que sepa
absolutamente que no quiere esos cambios locales no guardados.
Si desea mantener los cambios que ha realizado en ese archivo, pero aún necesita eliminarlo por ahora, repasaremos el
almacenamiento y la ramificación en Git Branching; estas son generalmente mejores formas de hacerlo.
Recuerde, cualquier cosa que se confirme en Git casi siempre se puede recuperar. Incluso las confirmaciones que estaban
en ramas que se eliminaron o las confirmaciones que se sobrescribieron con una confirmación --amend pueden
recuperarse (ver Recuperación de datos para la recuperación de datos). Sin embargo, cualquier cosa que pierda que
nunca se cometió es probable que nunca se vuelva a ver.
Volvamos sobre nuestros pasos y deshagamos las cosas con git restore en lugar de git reset.
Las siguientes dos secciones demuestran cómo trabajar con su área de preparación y cambios en el directorio de trabajo
con git restore. Lo bueno es que el comando que usa para determinar el estado de esas dos áreas también le recuerda
cómo deshacer los cambios en ellas. Por ejemplo, supongamos que ha cambiado dos archivos y desea confirmarlos como
dos cambios separados, pero accidentalmente escribe git add * y prepara ambos. ¿Cómo puedes quitar el escenario a uno
de los dos? El comando de estado de git te recuerda:
48
Machine Translated by Google
Justo debajo del texto "Cambios por confirmar", dice use git restore --staged <archivo>... para quitar la preparación.
Entonces, usemos ese consejo para eliminar el archivo CONTRIBUTING.md :
¿Qué sucede si se da cuenta de que no desea conservar los cambios en el archivo CONTRIBUTING.md ? ¿Cómo puede
desmodificarlo fácilmente, revertirlo a la apariencia que tenía la última vez que se comprometió (o clonó inicialmente, o
como lo ingresó en su directorio de trabajo)? Afortunadamente, git status también te dice cómo hacerlo. En el resultado del
último ejemplo, el área no preparada se ve así:
Le dice bastante explícitamente cómo descartar los cambios que ha realizado. Hagamos lo que dice:
Es importante comprender que git restore <file> es un comando peligroso. Cualquier cambio local que
ÿ haya realizado en ese archivo se ha ido: Git simplemente reemplazó ese archivo con la última versión
preparada o confirmada. Nunca use este comando a menos que sepa absolutamente que no quiere
esos cambios locales no guardados.
49
Machine Translated by Google
repositorios Los repositorios remotos son versiones de su proyecto que están alojadas en Internet o en alguna
red. Puede tener varios de ellos, cada uno de los cuales generalmente es de solo lectura o de lectura/escritura
para usted. Colaborar con otros implica administrar estos repositorios remotos y enviar y recibir datos cuando
necesite compartir el trabajo. Administrar repositorios remotos incluye saber cómo agregar repositorios remotos,
eliminar remotos que ya no son válidos, administrar varias sucursales remotas y definirlas como rastreadas o
no, y más. En esta sección, cubriremos algunas de estas habilidades de administración remota.
Es muy posible que pueda estar trabajando con un repositorio "remoto" que, de hecho, está
ÿ en el mismo host que usted. La palabra "remoto" no implica necesariamente que el repositorio
esté en otro lugar de la red o de Internet, solo que está en otro lugar. Trabajar con un
repositorio remoto de este tipo todavía implicaría todas las operaciones estándar de empujar,
tirar y buscar como con cualquier otro control remoto.
Para ver qué servidores remotos ha configurado, puede ejecutar el comando remoto git . Enumera los nombres
abreviados de cada identificador remoto que ha especificado. Si ha clonado su repositorio, al menos debería
ver el origen : ese es el nombre predeterminado que Git le da al servidor desde el que clonó:
También puede especificar -v, que le muestra las URL que Git ha almacenado para que se use el nombre
abreviado al leer y escribir en ese control remoto:
$ git remoto -v
origen https://github.com/schacon/ticgit (buscar) origen
https://github.com/schacon/ticgit (empujar)
Si tiene más de un control remoto, el comando los enumera a todos. Por ejemplo, un repositorio con múltiples
controles remotos para trabajar con varios colaboradores podría verse así.
50
Machine Translated by Google
$ cd grit $
git remote -v
bakkdoor https://github.com/bakkdoor/grit (buscar) bakkdoor
https://github.com/bakkdoor/grit (empujar) cho45 https://
github.com/cho45/grit
cho45/grit(buscar)
(empujar)cho45 https://github.com/
defunkt https://github.com/
defunkt/grit (buscar) defunkt https://github.com/defunkt/grit
(empujar) koke git ://github.com/koke/grit.git
(buscar) git://github.com/koke/grit.git (empujar)
git@github.com:mojombo/grit.git (buscar)
git@github.com :mojombo/grit.git (presionar)
origen
koke origen
Esto significa que podemos obtener contribuciones de cualquiera de estos usuarios con bastante facilidad. Además, es posible
que tengamos permiso para impulsar uno o más de estos, aunque no podemos decirlo aquí.
Tenga en cuenta que estos controles remotos usan una variedad de protocolos; Cubriremos más sobre esto en Obtener Git en un
servidor.
$ git origen
remoto $ git
remoto agregar pb https://github.com/paulboone/ticgit $ git remoto
-v origen https://github.com/schacon/ticgit (buscar) origen https://
github.com/schacon /ticgit (empujar) pb https://github.com/paulboone/
ticgit (buscar) pb https://github.com/paulboone/ticgit (empujar)
Ahora puede usar la cadena pb en la línea de comando en lugar de la URL completa. Por ejemplo, si desea obtener toda la
información que tiene Paul pero que aún no tiene en su repositorio, puede ejecutar git fetch pb:
$ git fetch pb
remote: Contando objetos: 43, listo. remoto:
Comprimir objetos: 100% (36/36), hecho. remoto: Total 43
(delta 10), reutilizado 31 (delta 5)
Desembalaje de objetos: 100% (43/43), hecho.
Desde https://github.com/paulboone/ticgit *
[nueva rama] -> pb/mastermaestro
* [nueva rama] -> pb/
ticgit
ticgit
51
Machine Translated by Google
Ahora se puede acceder localmente a la rama principal de Paul como pb / master ; puede fusionarla con una de sus ramas o
puede consultar una rama local en ese punto si desea inspeccionarla. Repasaremos qué son las ramas y cómo usarlas con
mucho más detalle en Git Branching.
Como acabas de ver, para obtener datos de tus proyectos remotos, puedes ejecutar:
El comando va a ese proyecto remoto y extrae todos los datos de ese proyecto remoto que aún no tiene. Después de hacer
esto, debe tener referencias a todas las sucursales desde ese control remoto, que puede fusionar o inspeccionar en cualquier
momento.
Si clona un repositorio, el comando agrega automáticamente ese repositorio remoto con el nombre "origen". Por lo tanto, git
fetch origin obtiene cualquier trabajo nuevo que se haya enviado a ese servidor desde que lo clonó (o lo obtuvo por última
vez). Es importante tener en cuenta que el comando git fetch solo descarga los datos a su repositorio local; no los fusiona
automáticamente con ninguno de sus trabajos ni modifica lo que está trabajando actualmente. Tienes que fusionarlo
manualmente en tu trabajo cuando estés listo.
Si su sucursal actual está configurada para rastrear una sucursal remota (consulte la siguiente sección y Git Branching para
obtener más información), puede usar el comando git pull para buscar automáticamente y luego fusionar esa sucursal remota
en su sucursal actual. Este puede ser un flujo de trabajo más fácil o más cómodo para usted; y, de forma predeterminada, el
comando git clone configura automáticamente su rama maestra local para rastrear la rama maestra remota (o como se llame
la rama predeterminada) en el servidor desde el que clonó.
Ejecutar git pull generalmente obtiene datos del servidor desde el que clonó originalmente e intenta fusionarlos
automáticamente con el código en el que está trabajando actualmente.
Desde la versión 2.27 de git en adelante, git pull dará una advertencia si la variable pull.rebase no está
configurada. Git seguirá advirtiéndote hasta que configures la variable.
Si desea volver a establecer la base al extraer: git config --global pull.rebase "true"
Cuando tiene su proyecto en un punto que desea compartir, debe impulsarlo aguas arriba. El comando para esto es simple:
git push <remote> <branch>. Si desea enviar su rama maestra a su servidor de origen (nuevamente, la clonación
generalmente configura ambos nombres para usted automáticamente), puede ejecutar esto para enviar cualquier confirmación
que haya hecho al servidor:
Este comando solo funciona si clonó desde un servidor al que tiene acceso de escritura y si
52
Machine Translated by Google
nadie ha empujado mientras tanto. Si usted y otra persona clonan al mismo tiempo y empujan contra la corriente
y luego empujan contra la corriente, su empuje será rechazado con razón. Tendrás que buscar su trabajo
primero e incorporarlo al tuyo antes de que se te permita presionar. Consulte Git Branching para obtener
información más detallada sobre cómo enviar contenido a servidores remotos.
Si desea ver más información sobre un control remoto en particular, puede usar el comando git remote show
<remote> . Si ejecuta este comando con un nombre abreviado en particular, como origen, obtiene algo como
esto:
Muestra la URL del repositorio remoto, así como la información de la rama de seguimiento. El comando
útilmente le dice que si está en la rama maestra y ejecuta git pull, fusionará automáticamente la rama maestra
del control remoto con la local después de que se haya obtenido. También enumera todas las referencias
remotas que ha extraído.
Ese es un ejemplo simple que es probable que encuentre. Sin embargo, cuando usas Git más intensamente,
es posible que veas mucha más información de git remote show:
53
Machine Translated by Google
Este comando muestra a qué rama se envía automáticamente cuando ejecuta git push mientras está en
ciertas ramas. También le muestra qué sucursales remotas en el servidor aún no tiene, cuáles
sucursales remotas que tiene que se han eliminado del servidor y varias sucursales locales
que pueden fusionarse automáticamente con su rama de seguimiento remoto cuando ejecutas git pull.
Puede ejecutar git remote rename para cambiar el nombre abreviado de un control remoto. Por ejemplo, si desea cambiar el nombre
pb a paul, puedes hacerlo con git remote rename:
Vale la pena mencionar que esto también cambia todos los nombres de las sucursales de seguimiento remoto. lo que solía
ser referenciado en pb/master ahora está en paul/master.
Si desea eliminar un control remoto por algún motivo: movió el servidor o ya no lo usa
un espejo en particular, o tal vez un colaborador ya no está contribuyendo; puede usar git
eliminación remota o git remoto rm:
54
Machine Translated by Google
Una vez que elimine la referencia a un control remoto de esta manera, también se eliminarán todas las ramas de seguimiento remoto
y los ajustes de configuración asociados con ese control remoto.
Etiquetado
Como la mayoría de los VCS, Git tiene la capacidad de etiquetar puntos específicos en el historial de un repositorio como importantes.
Por lo general, las personas usan esta funcionalidad para marcar puntos de lanzamiento (v1.0, v2.0 , etc.). En esta sección, aprenderá
cómo enumerar las etiquetas existentes, cómo crear y eliminar etiquetas y cuáles son los diferentes tipos de etiquetas.
Enumerar las etiquetas existentes en Git es sencillo. Simplemente escriba la etiqueta git (con opcional -l o --list):
$ git etiqueta
v1.0
v2.0
Este comando enumera las etiquetas en orden alfabético; el orden en que se muestran no tiene importancia real.
También puede buscar etiquetas que coincidan con un patrón en particular. El repositorio fuente de Git, por ejemplo, contiene más de
500 etiquetas. Si solo está interesado en ver la serie 1.8.5, puede ejecutar esto:
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2
v1.8.5.3
v1.8.5.4
v1.8.5.5
55
Machine Translated by Google
Si solo desea la lista completa de etiquetas, ejecutar el comando git tag asume implícitamente que
desea una lista y proporciona una; el uso de -l o --list en este caso es opcional.
ÿ
Sin embargo, si proporciona un patrón comodín para hacer coincidir los nombres de las etiquetas, el
uso de -l o --list es obligatorio.
Creación de etiquetas
Una etiqueta ligera es muy parecida a una rama que no cambia: es solo un puntero a una confirmación específica.
Sin embargo, las etiquetas anotadas se almacenan como objetos completos en la base de datos de Git. Son sumas de
verificación; contener el nombre del etiquetador, correo electrónico y fecha; tener un mensaje de etiquetado; y se puede
firmar y verificar con GNU Privacy Guard (GPG). En general, se recomienda que cree etiquetas anotadas para que pueda
tener toda esta información; pero si desea una etiqueta temporal o por alguna razón no desea conservar la otra información,
también hay disponibles etiquetas ligeras.
Etiquetas anotadas
Crear una etiqueta anotada en Git es simple. La forma más fácil es especificar -a cuando ejecuta el comando de etiqueta :
v1.3
v1.4
El -m especifica un mensaje de etiquetado, que se almacena con la etiqueta. Si no especifica un mensaje para una etiqueta
anotada, Git inicia su editor para que pueda escribirlo.
Puede ver los datos de la etiqueta junto con la confirmación que se etiquetó usando el comando git show :
56
Machine Translated by Google
mi versión 1.4
Eso muestra la información del etiquetador, la fecha en que se etiquetó la confirmación y el mensaje de anotación antes de mostrar la
información de la confirmación.
Etiquetas ligeras
Otra forma de etiquetar confirmaciones es con una etiqueta ligera. Esta es básicamente la suma de verificación de confirmación
almacenada en un archivo; no se guarda ninguna otra información. Para crear una etiqueta ligera, no proporcione ninguna de las
opciones -a, -s o -m , solo proporcione un nombre de etiqueta:
v1.3
v1.4
v1.4-lw
v1.5
Esta vez, si ejecuta git show en la etiqueta, no verá la información adicional de la etiqueta. El comando solo muestra el compromiso:
Etiquetado posterior
También puede etiquetar confirmaciones después de haberlas superado. Supongamos que su historial de confirmación se ve así:
57
Machine Translated by Google
Ahora, suponga que olvidó etiquetar el proyecto en v1.2, que estaba en la confirmación "Actualizar archivo de rake". Puede
agregarlo después del hecho. Para etiquetar esa confirmación, especifica la suma de comprobación de la confirmación (o parte
de ella) al final del comando:
$ git etiqueta
v0.1
v1.2
v1.3
v1.4
v1.4-lw
v1.5
versión 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8 Autor:
Magnus Chacon <mchacon@gee-mail.com> Fecha: dom 27 de
abril 20:43:35 2008 -0700
Compartir etiquetas
De forma predeterminada, el comando git push no transfiere etiquetas a servidores remotos. Tendrá que enviar etiquetas
explícitamente a un servidor compartido después de haberlas creado. Este proceso es como compartir sucursales remotas:
puede ejecutar git push origin <tagname>.
58
Machine Translated by Google
Si tiene muchas etiquetas que desea enviar a la vez, también puede usar la opción --tags para el comando git push .
Esto transferirá todas sus etiquetas al servidor remoto que aún no están allí.
Ahora, cuando alguien más clone o extraiga de su repositorio, también obtendrá todas sus etiquetas.
ÿ git push <remote> --tags enviará etiquetas ligeras y anotadas. Actualmente no hay opción para
enviar solo etiquetas ligeras, pero si usa git push <remote> --follow-tags, solo las etiquetas
anotadas se enviarán al control remoto.
Eliminación de etiquetas
Para eliminar una etiqueta en tu repositorio local, puedes usar git tag -d <tagname>. Por ejemplo, podríamos eliminar
nuestra etiqueta ligera anterior de la siguiente manera:
Tenga en cuenta que esto no elimina la etiqueta de ningún servidor remoto. Hay dos variaciones comunes para
eliminar una etiqueta de un servidor remoto.
59
Machine Translated by Google
La forma de interpretar lo anterior es leerlo como el valor nulo antes de que los dos puntos se inserten en el nombre de la etiqueta
remota, eliminándolo efectivamente.
Si desea ver las versiones de los archivos a los que apunta una etiqueta, puede hacer una comprobación de git de esa etiqueta,
aunque esto pone su repositorio en estado de "CABEZA separada", lo que tiene algunos efectos secundarios negativos:
Si desea crear una nueva rama para retener las confirmaciones que creó, puede hacerlo
(ahora o más tarde) usando -c con el comando cambiar. Ejemplo:
interruptor git -
HEAD está ahora en 99ada87... Merge pull request #89 from schacon/appendix-final
En el estado "HEAD separado", si realiza cambios y luego crea una confirmación, la etiqueta permanecerá igual, pero su nueva
confirmación no pertenecerá a ninguna rama y no se podrá acceder a ella, excepto por el hash de confirmación exacto. Por lo
tanto, si necesita realizar cambios, digamos que está arreglando un error en una versión anterior, por ejemplo, generalmente
querrá crear una rama:
Si hace esto y realiza una confirmación, su rama versión 2 será ligeramente diferente a su etiqueta v2.0.0 , ya que avanzará con
sus nuevos cambios, así que tenga cuidado.
60
Machine Translated by Google
Alias de Git
Antes de pasar al siguiente capítulo, queremos presentar una función que puede hacer que su experiencia con Git sea
más simple, fácil y familiar: los alias. En aras de la claridad, no los usaremos en ninguna otra parte de este libro, pero si
continúa usando Git con regularidad, los alias son algo que debe conocer.
Git no infiere automáticamente su comando si lo escribe parcialmente. Si no desea escribir el texto completo de cada uno
de los comandos de Git, puede configurar fácilmente un alias para cada comando usando git config. Aquí hay un par de
ejemplos que puede configurar:
Esto significa que, por ejemplo, en lugar de escribir git commit, solo necesita escribir git ci. A medida que vaya usando Git,
probablemente también usará otros comandos con frecuencia; no dude en crear nuevos alias.
Esta técnica también puede ser muy útil para crear comandos que cree que deberían existir. Por ejemplo, para corregir el
problema de usabilidad que encontró al desmontar un archivo, puede agregar su propio alias de desmontaje a Git:
Esto parece un poco más claro. También es común agregar un último comando, como este:
61
Machine Translated by Google
$ git última
confirmación 66938dae3329c7aebe598c2246a8e6af90d04646
Autor: Josh Goebel <dreamer3@example.com> Fecha:
martes 26 de agosto 19:48:51 2008 +0800
Como puede ver, Git simplemente reemplaza el nuevo comando con cualquier alias para el que lo haya creado.
Sin embargo, tal vez desee ejecutar un comando externo, en lugar de un subcomando de Git. En ese caso, inicia
el comando con un ! personaje. Esto es útil si escribe sus propias herramientas que funcionan con un repositorio
de Git. Podemos demostrarlo creando un alias de git visual para ejecutar gitk:
Resumen
En este punto, puede realizar todas las operaciones básicas de Git local: crear o clonar un repositorio, realizar
cambios, organizar y confirmar esos cambios y ver el historial de todos los cambios por los que ha pasado el
repositorio. A continuación, cubriremos la característica principal de Git: su modelo de ramificación.
62
Machine Translated by Google
Ramificación Git
Casi todos los VCS tienen algún tipo de soporte de bifurcación. La ramificación significa que te desvías de la línea principal
de desarrollo y continúas trabajando sin alterar esa línea principal. En muchas herramientas de VCS, este es un proceso
algo costoso, que a menudo requiere que cree una nueva copia de su directorio de código fuente, lo que puede llevar
mucho tiempo para proyectos grandes.
Algunas personas se refieren al modelo de bifurcación de Git como su "característica principal", y ciertamente distingue a
Git en la comunidad de VCS. ¿Por qué es tan especial? La forma en que Git ramifica es increíblemente liviana, lo que
hace que las operaciones de ramificación sean casi instantáneas y, en general, cambiar de una rama a otra con la misma
rapidez. A diferencia de muchos otros VCS, Git fomenta los flujos de trabajo que se ramifican y fusionan con frecuencia,
incluso varias veces al día. Comprender y dominar esta función le brinda una herramienta poderosa y única y puede
cambiar por completo la forma en que se desarrolla.
Para comprender realmente la forma en que Git realiza la bifurcación, debemos dar un paso atrás y examinar cómo Git
almacena sus datos.
Como recordará de ¿Qué es Git?, Git no almacena datos como una serie de conjuntos de cambios o diferencias, sino
como una serie de instantáneas.
Cuando realiza una confirmación, Git almacena un objeto de confirmación que contiene un puntero a la instantánea del
contenido que preparó. Este objeto también contiene el nombre y la dirección de correo electrónico del autor, el mensaje
que escribió y punteros a la confirmación o confirmaciones que vinieron directamente antes de esta confirmación (su padre
o padres): cero padres para la confirmación inicial, un padre para una confirmación normal y múltiples padres para una
confirmación que resulta de una fusión de dos o más ramas.
Para visualizar esto, supongamos que tiene un directorio que contiene tres archivos, los prepara todos y los confirma. La
preparación de los archivos calcula una suma de verificación para cada uno (el hash SHA-1 que mencionamos en ¿Qué
es Git?), almacena esa versión del archivo en el repositorio de Git (Git se refiere a ellos como blobs) y agrega esa suma
de verificación a la preparación . área:
Cuando crea la confirmación ejecutando git commit, Git suma cada subdirectorio (en este caso, solo el directorio raíz del
proyecto) y los almacena como un objeto de árbol en el repositorio de Git. Luego, Git crea un objeto de confirmación que
tiene los metadatos y un puntero al árbol del proyecto raíz para que pueda volver a crear esa instantánea cuando sea
necesario.
Su repositorio de Git ahora contiene cinco objetos: tres blobs (cada uno representa el contenido de uno de los tres
archivos), un árbol que enumera el contenido del directorio y especifica qué nombres de archivo se almacenan como qué
blobs, y una confirmación con el puntero a ese árbol raíz y todos los metadatos de confirmación.
63
Machine Translated by Google
Si realiza algunos cambios y confirma de nuevo, la próxima confirmación almacena un puntero a la confirmación que
vino inmediatamente antes.
Una rama en Git es simplemente un puntero móvil ligero a una de estas confirmaciones. El nombre de rama
predeterminado en Git es maestro. A medida que comienza a realizar confirmaciones, se le proporciona una rama
maestra que apunta a la última confirmación que realizó. Cada vez que confirmas, el puntero de la rama maestra
avanza automáticamente.
La rama "maestra" en Git no es una rama especial. Es exactamente como cualquier otra rama.
ÿ La única razón por la que casi todos los repositorios tienen uno es que el comando git init lo crea
de manera predeterminada y la mayoría de las personas no se molestan en cambiarlo.
64
Machine Translated by Google
¿Qué sucede cuando creas una nueva rama? Bueno, al hacerlo se crea un nuevo puntero para que te muevas. Digamos que desea
crear una nueva rama llamada testing. Haces esto con el comando git branch :
¿Cómo sabe Git en qué rama estás actualmente? Mantiene un puntero especial llamado HEAD. Tenga en cuenta que esto es muy
diferente al concepto de HEAD en otros VCS a los que puede estar acostumbrado, como Subversion o CVS. En Git, este es un
puntero a la rama local en la que se encuentra actualmente. En este caso, todavía estás en el maestro. El comando git branch solo
creó una nueva rama, no cambió a eso
sesenta y cinco
Machine Translated by Google
rama.
Puede ver esto fácilmente ejecutando un simple comando de registro de git que le muestra hacia dónde
apuntan los punteros de rama. Esta opción se llama --decorar.
Puede ver las ramas maestra y de prueba que están justo al lado de la confirmación de f30ab .
Cambio de sucursales
Para cambiar a una sucursal existente, ejecuta el comando git checkout . Pasemos a la nueva rama de
pruebas :
66
Machine Translated by Google
$ vim test.rb
$ git commit -a -m 'hizo un cambio'
Esto es interesante, porque ahora su rama de prueba ha avanzado, pero su rama maestra aún apunta
a la confirmación en la que estaba cuando ejecutó git checkout para cambiar de rama. Volvamos a la
rama principal :
67
Machine Translated by Google
Si tuviera que ejecutar git log en este momento, es posible que se pregunte a dónde fue la rama
de "prueba" que acaba de crear, ya que no aparecería en la salida.
La rama no ha desaparecido; Git simplemente no sabe que estás interesado en esa rama y está
ÿ tratando de mostrarte lo que cree que te interesa. En otras palabras, de forma predeterminada, git
log solo mostrará el historial de confirmaciones debajo de la rama que has controlado.
Ese comando hizo dos cosas. Volvió a mover el puntero HEAD para que apuntara a la rama maestra y revirtió los
archivos en su directorio de trabajo a la instantánea a la que apunta el maestro . Esto también significa que los cambios
que realice a partir de este momento se diferenciarán de una versión anterior del proyecto. Básicamente, rebobina el
trabajo que ha realizado en su rama de prueba para que pueda ir en una dirección diferente.
Es importante tener en cuenta que cuando cambias de rama en Git, los archivos en tu directorio
ÿ de trabajo cambiarán. Si cambia a una rama más antigua, su directorio de trabajo se revertirá para
que se vea como la última vez que se comprometió en esa rama. Si Git no puede hacerlo
limpiamente, no le permitirá cambiar en absoluto.
$ vim test.rb
$ git commit -a -m 'hizo otros cambios'
Ahora el historial de su proyecto ha divergido (consulte Historial divergente). Usted creó y cambió a una rama, hizo
algo de trabajo en ella y luego volvió a su rama principal e hizo otro trabajo. Ambos cambios están aislados en ramas
separadas: puede alternar entre el
68
Machine Translated by Google
ramas y combínalas cuando estés listo. E hizo todo eso con comandos simples de bifurcación, pago y confirmación .
También puede ver esto fácilmente con el comando git log . Si ejecuta git log --oneline --decorate --graph --all , imprimirá el
historial de sus confirmaciones, mostrando dónde están sus punteros de rama y cómo se ha desviado su historial.
Debido a que una rama en Git es en realidad un archivo simple que contiene la suma de verificación SHA-1 de 40 caracteres
de la confirmación a la que apunta, las ramas son baratas de crear y destruir. Crear una nueva rama es tan rápido y simple
como escribir 41 bytes en un archivo (40 caracteres y una nueva línea).
Esto contrasta marcadamente con la forma en que se bifurcan la mayoría de las herramientas VCS más antiguas, que
implica copiar todos los archivos del proyecto en un segundo directorio. Esto puede llevar varios segundos o incluso
minutos, dependiendo del tamaño del proyecto, mientras que en Git el proceso siempre es instantáneo. Además, debido a
que estamos grabando a los padres cuando nos comprometemos, encontrar una base de fusión adecuada para la fusión
se realiza automáticamente y, en general, es muy fácil de hacer. Estas características ayudan a animar a los desarrolladores
a crear y usar sucursales con frecuencia.
69
Machine Translated by Google
ÿ Es típico crear una nueva rama y querer cambiar a esa nueva rama al mismo tiempo; esto se puede hacer
en una sola operación con git checkout -b <newbranchname>.
Desde la versión 2.23 de Git en adelante, puede usar git switch en lugar de git checkout para:
ÿ • Cree una nueva rama y cambie a ella: git switch -c new-branch. La bandera -c
significa crear, también puede usar la bandera completa: --create.
2. Cree una rama para una nueva historia de usuario en la que esté trabajando.
En esta etapa, recibirá una llamada de que otro problema es crítico y necesita una revisión. Harás lo siguiente:
Ramificación básica
Primero, supongamos que está trabajando en su proyecto y ya tiene un par de confirmaciones en la rama maestra .
70
Machine Translated by Google
Ha decidido que va a trabajar en el problema 53 en cualquier sistema de seguimiento de problemas que utilice su
empresa. Para crear una nueva rama y cambiar a ella al mismo tiempo, puede ejecutar el comando git checkout con
el interruptor -b :
Trabajas en tu sitio web y haces algunas confirmaciones. Al hacerlo, la rama iss53 se mueve hacia adelante, porque
la tiene desprotegida (es decir, su CABEZA la está apuntando):
$ vim index.html $
git commit -a -m 'Crear nuevo pie de página [problema 53]'
71
Machine Translated by Google
Ahora recibe la llamada de que hay un problema con el sitio web y debe solucionarlo de inmediato. Con Git, no tiene que
implementar su solución junto con los cambios de iss53 que ha realizado, y no tiene que esforzarse mucho para revertir esos
cambios antes de que pueda aplicar su solución a lo que está en producción. Todo lo que tiene que hacer es volver a su
rama maestra .
Sin embargo, antes de hacerlo, tenga en cuenta que si su directorio de trabajo o área de preparación tiene cambios no
confirmados que entran en conflicto con la rama que está revisando, Git no le permitirá cambiar de rama. Es mejor tener un
estado de trabajo limpio cuando cambia de sucursal. Hay formas de evitar esto (es decir, ocultar y modificar la confirmación)
que veremos más adelante, en Almacenamiento y limpieza. Por ahora, supongamos que ha confirmado todos sus cambios,
por lo que puede volver a su rama principal :
En este punto, el directorio de trabajo de su proyecto es exactamente como era antes de que comenzara a trabajar en el
problema 53, y puede concentrarse en su revisión. Este es un punto importante para recordar: cuando cambias de rama, Git
restablece tu directorio de trabajo para que luzca como la última vez que te comprometiste en esa rama. Agrega, elimina y
modifica archivos automáticamente para asegurarse de que su copia de trabajo sea como se veía la rama en su última
confirmación.
A continuación, tiene que hacer una revisión. Vamos a crear una rama de revisión en la que trabajar hasta que se complete:
72
Machine Translated by Google
Puede ejecutar sus pruebas, asegurarse de que la revisión sea lo que desea y, finalmente, fusionar la rama de
revisión nuevamente en su rama maestra para implementarla en producción. Haces esto con el comando git merge :
Notarás la frase "avance rápido" en esa fusión. Debido a que la confirmación C4 a la que apunta la revisión de la
rama en la que se fusionó estaba directamente delante de la confirmación C2 en la que se encuentra, Git simplemente
mueve el puntero hacia adelante. Para expresarlo de otra manera, cuando intenta fusionar una confirmación con una
confirmación a la que se puede llegar siguiendo el historial de la primera confirmación, Git simplifica las cosas
moviendo el puntero hacia adelante porque no hay trabajo divergente para fusionar, esto se llama " avance rápido."
Su cambio ahora está en la instantánea de la confirmación a la que apunta la rama principal y puede implementar la
corrección.
73
Machine Translated by Google
Una vez implementada la solución súper importante, estará listo para volver al trabajo que estaba
haciendo antes de que lo interrumpieran. Sin embargo, primero eliminará la rama de revisión , porque
ya no la necesita: la rama maestra apunta al mismo lugar. Puede eliminarlo con la opción -d para git
branch:
Ahora puede volver a su rama de trabajo en curso en el número 53 y continuar trabajando en él.
74
Machine Translated by Google
Vale la pena señalar aquí que el trabajo que hizo en su rama de revisiones no está contenido en los archivos de su
rama iss53 . Si necesita incorporarlo, puede fusionar su rama principal en su rama iss53 ejecutando git merge master,
o puede esperar para integrar esos cambios hasta que decida volver a incorporar la rama iss53 en la principal más
tarde.
Fusión básica
Supongamos que ha decidido que el trabajo de su número 53 está completo y listo para fusionarse con su rama
principal . Para hacer eso, fusionará su rama iss53 en master, al igual que fusionó su rama de revisión anteriormente.
Todo lo que tiene que hacer es verificar la rama en la que desea fusionarse y luego ejecutar el comando git merge :
Esto se ve un poco diferente a la combinación de revisión que hizo anteriormente. En este caso, su historial de
desarrollo se ha desviado de algún punto más antiguo. Debido a que la confirmación en la rama en la que estás no
es un ancestro directo de la rama en la que te estás fusionando, Git tiene que trabajar un poco. En este caso, Git
realiza una combinación simple de tres vías, utilizando las dos instantáneas a las que apuntan las puntas de las
ramas y el ancestro común de las dos.
75
Machine Translated by Google
En lugar de simplemente mover el puntero de la rama hacia adelante, Git crea una nueva instantánea que resulta de
esta combinación de tres vías y crea automáticamente una nueva confirmación que apunta a ella. Esto se conoce como
una confirmación de combinación y es especial porque tiene más de un padre.
Ahora que su trabajo está fusionado, ya no necesita la rama iss53 . Puede cerrar el problema en su sistema de
seguimiento de problemas y eliminar la rama:
Ocasionalmente, este proceso no transcurre sin problemas. Si cambió la misma parte del mismo archivo de manera
diferente en las dos ramas que está fusionando, Git no podrá fusionarlos limpiamente. Si su solución para el problema
n.° 53 modificó la misma parte de un archivo que la rama de revisión , obtendrá un conflicto de combinación similar a
este:
76
Machine Translated by Google
Git no ha creado automáticamente una nueva confirmación de fusión. Ha pausado el proceso mientras resuelves
el conflicto. Si desea ver qué archivos no se fusionaron en algún momento después de un conflicto de fusión, puede
ejecutar git status:
$ git status On
branch master Tiene
rutas no fusionadas. (solucionar
conflictos y ejecutar "git commit")
Rutas no fusionadas:
(use "git add <file>..." para marcar la resolución)
no se agregaron cambios para confirmar (use "git add" y/o "git commit -a")
Todo lo que tenga conflictos de fusión y no se haya resuelto se muestra como no fusionado. Git agrega marcadores
estándar de resolución de conflictos a los archivos que tienen conflictos, para que pueda abrirlos manualmente y
resolver esos conflictos. Su archivo contiene una sección que se parece a esto:
<<<<<<< HEAD:index.html
<div id="footer">contacto: email.support@github.com</div>
=======
<div id="footer">
contáctenos en support@github.com </div> >>>>>>>
iss53:index.html
Esto significa que la versión en HEAD (su rama maestra , porque eso era lo que había verificado cuando ejecutó
su comando de combinación) es la parte superior de ese bloque (todo lo que está arriba de =======), mientras
que la versión en su rama iss53 se ve como todo en la parte inferior. Para resolver el conflicto, debe elegir un lado
o el otro o fusionar los contenidos usted mismo. Por ejemplo, puede resolver este conflicto reemplazando el bloque
completo con esto:
Esta resolución tiene un poco de cada sección, y las líneas <<<<<<<, ======= y >>>>>>> se han eliminado por
completo. Una vez que haya resuelto cada una de estas secciones en cada archivo en conflicto, ejecute git add
77
Machine Translated by Google
en cada archivo para marcarlo como resuelto. La preparación del archivo lo marca como resuelto en Git.
Si desea utilizar una herramienta gráfica para resolver estos problemas, puede ejecutar git mergetool, que activa una herramienta de
combinación visual adecuada y lo guía a través de los conflictos:
Si desea utilizar una herramienta de combinación que no sea la predeterminada (Git eligió opendiff en este caso porque el comando se
ejecutó en una Mac), puede ver todas las herramientas compatibles enumeradas en la parte superior después de "una de las siguientes
herramientas". Simplemente escriba el nombre de la herramienta que prefiere usar.
ÿ Si necesita herramientas más avanzadas para resolver conflictos de combinación complicados, cubrimos más
sobre la combinación en Combinación avanzada.
Después de salir de la herramienta de fusión, Git le pregunta si la fusión fue exitosa. Si le dice a la secuencia de comandos que lo fue,
prepara el archivo para marcarlo como resuelto para usted. Puede ejecutar git status nuevamente para verificar que todos los conflictos
se hayan resuelto:
$ git estado
En maestro de rama
Se solucionaron todos los conflictos, pero aún se está
fusionando. (use "git commit" para concluir la fusión)
Cambios a realizar:
modificado: index.html
Si está satisfecho con eso y verifica que todo lo que tenía conflictos se ha preparado, puede escribir git commit para finalizar la
confirmación de fusión. El mensaje de confirmación por defecto se parece a esto:
78
Machine Translated by Google
Conflictos:
index.html #
# Ingrese el mensaje de confirmación para sus cambios. Las líneas que comiencen
# con '#' se ignorarán y un mensaje vacío anulará la confirmación.
# En el maestro de la
rama # Todos los conflictos se solucionaron pero aún se
está fusionando. # # Cambios a confirmar: # modificado:
index.html
Si cree que sería útil para otras personas que analicen esta combinación en el futuro, puede modificar
este mensaje de confirmación con detalles sobre cómo resolvió la combinación y explicar por qué realizó
los cambios que realizó si estos no son obvios.
Gestión de Sucursales
Ahora que creó, fusionó y eliminó algunas sucursales, veamos algunas herramientas de administración
de sucursales que serán útiles cuando comience a usar sucursales todo el tiempo.
El comando git branch hace más que solo crear y eliminar ramas. Si lo ejecuta sin argumentos, obtiene
una lista simple de sus ramas actuales:
$ git rama
iss53
* prueba
maestra
Fíjese en el carácter * que antecede a la rama principal : indica la rama que ha retirado actualmente (es
decir, la rama a la que apunta HEAD ). Esto significa que si se compromete en este punto, la rama
maestra avanzará con su nuevo trabajo. Para ver la última confirmación en cada rama, puedes ejecutar
git branch -v:
$ git branch -v
iss53 93b412c Arreglar el problema de
*
javascript master 7a98805 Merge branch
'iss53' testing 782fd34 Agregar scott a la lista de autores en el archivo Léame
79
Machine Translated by Google
Las útiles opciones --merged y --no-merged pueden filtrar esta lista a las ramas que tiene o que aún no ha
fusionado con la rama en la que se encuentra actualmente. Para ver qué ramas ya están fusionadas con la
rama en la que te encuentras, puedes ejecutar git branch --merged:
Debido a que ya se fusionó en iss53 anteriormente, lo verá en su lista. Las ramas en esta lista sin el * delante
de ellas generalmente se pueden eliminar con git branch -d; ya has incorporado su trabajo a otra rama, así que
no vas a perder nada.
Para ver todas las ramas que contienen trabajo que aún no has fusionado, puedes ejecutar git branch --no
-merged:
Esto muestra tu otra rama. Debido a que contiene trabajo que aún no se fusionó, intentar eliminarlo con git
branch -d fallará:
Si realmente desea eliminar la rama y perder ese trabajo, puede forzarlo con -D, como señala el útil mensaje.
Siempre puede proporcionar un argumento adicional para preguntar sobre el estado de fusión
con respecto a alguna otra rama sin verificar primero esa otra rama, como en, ¿qué no se
ÿ fusionó en la rama principal ?
80
Machine Translated by Google
No cambie el nombre de las ramas que todavía están en uso por otros colaboradores. No cambie el nombre de
ÿ una rama como maestra/principal/principal sin haber leído la sección "Cambiar el nombre de la rama maestra".
Supongamos que tiene una rama que se llama bad-branch-name y desea cambiarla a un nombre de rama corregido, manteniendo
todo el historial. También desea cambiar el nombre de la sucursal en el control remoto (GitHub, GitLab, otro servidor). ¿Cómo haces
esto?
Esto reemplaza su nombre de sucursal incorrecto con el nombre de sucursal corregido, pero este cambio es solo local por ahora. Para
permitir que otros vean la rama corregida en el control remoto, presione:
Observe que está en la rama nombre-sucursal-corregido y está disponible en el control remoto. Sin embargo, la rama con el nombre
incorrecto también está presente allí, pero puede eliminarla ejecutando el siguiente comando:
Ahora el nombre de la rama incorrecta se reemplaza por completo con el nombre de la rama corregido.
Cambiar el nombre de una rama como master/main/mainline/default interrumpirá las integraciones, los servicios,
las utilidades auxiliares y los scripts de compilación/versión que utiliza su repositorio. Antes de hacer esto,
ÿ asegúrese de consultar con sus colaboradores. Además, asegúrese de realizar una búsqueda exhaustiva a
través de su repositorio y actualice cualquier referencia al nombre de la rama anterior en su código y scripts.
81
Machine Translated by Google
Ya no hay una rama maestra local , porque se le cambió el nombre a la rama principal .
Para permitir que otros vean la nueva rama principal , debe empujarla hacia el control remoto. Esto hace que la rama renombrada esté disponible
en el control remoto.
Su rama maestra local se ha ido, ya que se reemplazó con la rama principal . La rama principal está presente en el control remoto. Sin embargo,
la rama maestra anterior todavía está presente en el control remoto. Otros colaboradores seguirán usando la rama principal como base de su
Ahora tiene algunas tareas más por delante para completar la transición:
• Cualquier proyecto que dependa de este necesitará actualizar su código y/o configuración.
• Configuración de redirección en su host de repositorio para cosas como la rama predeterminada del repositorio, reglas de combinación y
Una vez que haya realizado todas estas tareas y esté seguro de que la rama principal funciona igual que la rama principal , puede eliminar la rama
principal :
trabajo comunes que esta bifurcación liviana hace posible, para que pueda decidir si desea incorporarlos en su propio ciclo de desarrollo.
82
Machine Translated by Google
Debido a que Git usa una combinación simple de tres vías, la combinación de una rama con otra varias veces durante un
período prolongado generalmente es fácil de hacer. Esto significa que puede tener varias sucursales que siempre están
abiertas y que usa para diferentes etapas de su ciclo de desarrollo; puede fusionar regularmente de algunos de ellos a otros.
Muchos desarrolladores de Git tienen un flujo de trabajo que adopta este enfoque, como tener solo código que sea
completamente estable en su rama maestra , posiblemente solo código que se haya lanzado o se lanzará. Tienen otra rama
paralela llamada desarrollar o siguiente desde la que trabajan o usan para probar la estabilidad; no siempre es necesariamente
estable, pero cada vez que llega a un estado estable, se puede fusionar en maestro.
Se usa para extraer ramas temáticas (ramas de corta duración, como la rama iss53 anterior ) cuando están listas, para
asegurarse de que pasen todas las pruebas y no introduzcan errores.
En realidad, estamos hablando de punteros que se mueven hacia arriba en la línea de confirmaciones que está realizando.
Las ramas estables están más abajo en la línea de su historial de confirmaciones, y las ramas de última generación están
más arriba en el historial.
En general, es más fácil pensar en ellos como silos de trabajo, donde los conjuntos de confirmaciones se gradúan en un silo
más estable cuando se prueban por completo.
Puede seguir haciendo esto para varios niveles de estabilidad. Algunos proyectos más grandes también tienen una rama
propuesta o pu (actualizaciones propuestas) que tiene ramas integradas que pueden no estar listas para pasar a la rama
siguiente o principal . La idea es que tus ramas estén en varios niveles de estabilidad; cuando alcanzan un nivel más estable,
se fusionan con la rama por encima de ellos. Una vez más, no es necesario tener varias sucursales de ejecución prolongada,
pero a menudo es útil, especialmente cuando se trata de proyectos muy grandes o complejos.
83
Machine Translated by Google
Ramas temáticas
Sin embargo, las ramas temáticas son útiles en proyectos de cualquier tamaño. Una rama de tema es una
rama de corta duración que crea y usa para una sola característica particular o trabajo relacionado. Esto es
algo que probablemente nunca antes haya hecho con un VCS porque generalmente es demasiado costoso
crear y fusionar sucursales. Pero en Git es común crear, trabajar, fusionar y eliminar ramas varias veces al día.
Viste esto en la última sección con las ramas iss53 y hotfix que creaste. Hizo algunas confirmaciones en
ellos y los eliminó directamente después de fusionarlos en su rama principal. Esta técnica le permite cambiar
de contexto rápida y completamente, ya que su trabajo está separado en silos donde todos los cambios en
esa rama tienen que ver con ese tema, es más fácil ver lo que sucedió durante la revisión del código y
demás. Puede mantener los cambios allí durante minutos, días o meses, y fusionarlos cuando estén listos,
independientemente del orden en que se crearon o trabajaron.
Considere un ejemplo de hacer algo de trabajo (en maestro), bifurcarse para un problema (iss91), trabajar
en él un poco, bifurcarse en la segunda rama para probar otra forma de manejar lo mismo ( iss91v2), volver
a su master branch y trabajar allí por un tiempo, y luego bifurcarse allí para hacer un trabajo que no está
seguro de que sea una buena idea (sucursal dumbidea ). Tu historial de confirmaciones se verá así:
84
Machine Translated by Google
Ahora, supongamos que decide que le gusta más la segunda solución a su problema (iss91v2); y mostraste
la rama dumbidea a tus compañeros de trabajo, y resulta ser genial. Puede desechar la rama iss91 original
(perdiendo las confirmaciones C5 y C6) y fusionar las otras dos. Su historial entonces se ve así:
Entraremos en más detalles sobre los diversos flujos de trabajo posibles para su proyecto Git en Git
distribuido, así que antes de decidir qué esquema de bifurcación usará su próximo proyecto, asegúrese de
leer ese capítulo.
Es importante recordar cuando esté haciendo todo esto que estas sucursales son completamente locales.
Cuando está ramificando y fusionando, todo se hace solo en su repositorio de Git; no hay comunicación con
el servidor.
85
Machine Translated by Google
Sucursales remotas
Las referencias remotas son referencias (punteros) en sus repositorios remotos, incluidas ramas, etiquetas, etc.
Puede obtener una lista completa de referencias remotas explícitamente con git ls-remote <remote> o git remote
show <remote> para sucursales remotas, así como más información. Sin embargo, una forma más común es
aprovechar las sucursales de seguimiento remoto.
Las sucursales de seguimiento remoto son referencias al estado de las sucursales remotas. Son referencias
locales que no puedes mover; Git los mueve por usted cada vez que realiza alguna comunicación de red, para
asegurarse de que representen con precisión el estado del repositorio remoto. Piense en ellos como marcadores,
para recordarle dónde estaban las sucursales en sus repositorios remotos la última vez que se conectó a ellos.
Los nombres de sucursales de seguimiento remoto toman la forma <remote>/<branch>. Por ejemplo, si quisiera
ver cómo se veía la rama principal en su control remoto de origen la última vez que se comunicó con él, verificaría
la rama principal/de origen . Si estaba trabajando en un problema con un socio y este envió una rama iss53 , es
posible que tenga su propia rama iss53 local , pero la rama en el servidor estaría representada por la rama de
seguimiento remoto origin/iss53.
Esto puede ser un poco confuso, así que veamos un ejemplo. Supongamos que tiene un servidor Git en su red en
git.ourcompany.com. Si clona a partir de esto, el comando de clonación de Git le asigna automáticamente el
nombre de origen , extrae todos sus datos, crea un puntero a la ubicación de su rama maestra y lo nombra como
origen/maestro localmente. Git también le brinda su propia rama maestra local que comienza en el mismo lugar
que la rama maestra de origen , por lo que tiene algo desde lo que trabajar.
"origen" no es especial
Al igual que el nombre de la rama "maestro" no tiene ningún significado especial en Git,
ÿ tampoco lo tiene "origen". Mientras que "maestro" es el nombre predeterminado para una rama
de inicio cuando ejecuta git init , que es la única razón por la que se usa ampliamente, "origen"
es el nombre predeterminado para un control remoto cuando ejecuta git clone. Si ejecuta git
clone -o booyah en su lugar, tendrá booyah/master como su rama remota predeterminada.
86
Machine Translated by Google
Si realiza algún trabajo en su rama maestra local y, mientras tanto, alguien más ingresa a git.ourcompany.com
y actualiza su rama principal , entonces sus historiales avanzan de manera diferente.
Además, mientras permanezca fuera de contacto con su servidor de origen , su puntero de origen/maestro no
moverse.
87
Machine Translated by Google
Para sincronizar su trabajo con un control remoto determinado, ejecute un comando git fetch <remote>
(en nuestro caso, git fetch origin). Este comando busca el "origen" del servidor (en este caso, es
git.ourcompany.com), obtiene cualquier dato que aún no tenga y actualiza su base de datos local,
moviendo su puntero de origen/maestro a su posición nueva y más actualizada.
88
Machine Translated by Google
Para demostrar que tiene varios servidores remotos y cómo son las sucursales remotas para esos
proyectos remotos, supongamos que tiene otro servidor Git interno que uno de sus equipos de sprint usa
solo para el desarrollo. Este servidor está en git.team1.ourcompany.com. Puede agregarlo como una
nueva referencia remota al proyecto en el que está trabajando actualmente ejecutando el comando git
remote add como vimos en Conceptos básicos de Git. Nombre este equipo remoto , que será su nombre
abreviado para toda esa URL.
89
Machine Translated by Google
Ahora, puede ejecutar git fetch teamone para obtener todo lo que el servidor remoto de teamone tiene y que usted aún no
tiene. Debido a que ese servidor tiene un subconjunto de los datos que tiene su servidor de origen en este momento, Git no
obtiene datos pero establece una rama de seguimiento remoto llamada teamone/master para apuntar a la confirmación que
teamone tiene como su rama principal .
90
Machine Translated by Google
Emprendedor
Cuando desee compartir una sucursal con el mundo, debe enviarla a un control remoto al que tenga acceso
de escritura. Sus sucursales locales no se sincronizan automáticamente con los controles remotos a los que
escribe; debe enviar explícitamente las sucursales que desea compartir. De esa forma, puede usar ramas
privadas para el trabajo que no desea compartir y subir solo las ramas temáticas en las que desea colaborar.
Si tiene una rama llamada serverfix en la que desea trabajar con otros, puede impulsarla hacia arriba de la
misma manera que impulsó su primera rama. Ejecute git push <remoto> <rama>:
Esto es un poco un atajo. Git automáticamente expande el nombre de la rama serverfix a refs /heads/
serverfix:refs/heads/serverfix, lo que significa, "Toma mi rama local serverfix y empújala para actualizar la
rama serverfix remota". Repasaremos la parte refs/heads/ en detalle en Git
91
Machine Translated by Google
Internos, pero generalmente puede dejarlo fuera. También puede hacer git push origin serverfix:serverfix, que hace lo
mismo: dice: "Tome mi serverfix y conviértalo en el serverfix del control remoto". Puede usar este formato para insertar
una sucursal local en una sucursal remota que tiene un nombre diferente. Si no desea que se llame serverfix en el
control remoto, puede ejecutar git push origin serverfix:awesomebranch para enviar su rama serverfix local a la rama
awesomebranch en el proyecto remoto.
ÿ Si no desea escribirlo cada vez que presiona, puede configurar un "caché de credenciales". Lo
más simple es mantenerlo en la memoria durante unos minutos, lo que puede configurar fácilmente
ejecutando git config --global credential.helper cache.
Para obtener más información sobre las diversas opciones de almacenamiento en caché de credenciales disponibles, consulte
Almacenamiento de credenciales.
La próxima vez que uno de sus colaboradores obtenga del servidor, obtendrá una referencia de dónde se encuentra
la versión de serverfix del servidor en el origen de la rama remota /serverfix:
Es importante tener en cuenta que cuando realiza una búsqueda que genera nuevas ramas de seguimiento remoto,
no tiene automáticamente copias editables locales de ellas. En otras palabras, en este caso, no tiene una nueva rama
serverfix , solo tiene un puntero origin/serverfix que no puede modificar.
Para fusionar este trabajo en su rama de trabajo actual, puede ejecutar git merge origin/serverfix. Si desea su propia
rama serverfix en la que pueda trabajar, puede basarla en su rama de seguimiento remoto:
Esto le brinda una sucursal local en la que puede trabajar que comienza donde está origin/serverfix .
Rastreo de sucursales
Verificar una sucursal local desde una sucursal de seguimiento remoto crea automáticamente lo que se denomina una
92
Machine Translated by Google
"rama de seguimiento" (y la rama que rastrea se llama "rama ascendente"). Las sucursales de seguimiento son
sucursales locales que tienen una relación directa con una sucursal remota. Si está en una rama de seguimiento y
escribe git pull, Git sabe automáticamente de qué servidor buscar y en qué rama fusionarse.
Cuando clona un repositorio, generalmente crea automáticamente una rama maestra que rastrea origen/maestro. Sin
embargo, puede configurar otras sucursales de seguimiento si lo desea, que rastreen las sucursales en otros controles
remotos o que no rastreen la sucursal principal . El caso simple es el ejemplo que acaba de ver, ejecutando git
checkout -b <branch> <remote>/<branch>. Esta es una operación bastante común que Git proporciona la abreviatura
--track :
De hecho, esto es tan común que incluso hay un atajo para ese atajo. Si el nombre de la sucursal que está tratando
de pagar (a) no existe y (b) coincide exactamente con un nombre en un solo control remoto, Git creará una sucursal
de seguimiento para usted:
Para configurar una sucursal local con un nombre diferente al de la sucursal remota, puede usar fácilmente la primera
versión con un nombre de sucursal local diferente:
Si ya tiene una sucursal local y desea establecerla en una sucursal remota que acaba de bajar, o si desea cambiar la
sucursal ascendente que está rastreando, puede usar la opción -u o --set-upstream-to para git branch para configurarlo
explícitamente en cualquier momento.
Cuando tiene configurada una rama de seguimiento, puede hacer referencia a su rama ascendente
ÿ con la abreviatura @{upstream} o @{u} . Entonces, si estás en la rama maestra y está rastreando
el origen/maestro, puedes decir algo como git merge @{u} en lugar de git merge origin/master si
lo deseas.
93
Machine Translated by Google
Si desea ver qué ramas de seguimiento ha configurado, puede usar la opción -vv para git branch.
Esto mostrará una lista de sus sucursales locales con más información, incluido el seguimiento de cada sucursal y si
su sucursal local está adelante, atrás o ambos.
Entonces, aquí podemos ver que nuestra rama iss53 está rastreando origin/iss53 y está "adelantada" por dos, lo que
significa que tenemos dos confirmaciones localmente que no se envían al servidor. También podemos ver que nuestra
rama maestra está rastreando el origen/maestro y está actualizada. A continuación, podemos ver que nuestra rama
serverfix está rastreando la rama server-fix-good en nuestro servidor teamone y está tres por delante y uno por detrás,
lo que significa que hay una confirmación en el servidor en el que aún no nos hemos fusionado y tres confirmaciones
localmente que no hemos empujado. Finalmente, podemos ver que nuestra rama de prueba no está rastreando
ninguna rama remota.
Es importante tener en cuenta que estos números son solo desde la última vez que los obtuvo de cada servidor.
Este comando no llega a los servidores, le informa sobre lo que ha almacenado en caché de estos servidores
localmente. Si desea obtener números totalmente actualizados por delante y por detrás, deberá obtenerlos de todos
sus controles remotos justo antes de ejecutar esto. Podrías hacerlo así:
Tracción
Si bien el comando git fetch obtendrá todos los cambios en el servidor que aún no tiene, no modificará su directorio
de trabajo en absoluto. Simplemente obtendrá los datos por usted y le permitirá fusionarlos usted mismo. Sin embargo,
hay un comando llamado git pull que es esencialmente un git fetch seguido inmediatamente por un git merge en la
mayoría de los casos. Si tiene una rama de seguimiento configurada como se muestra en la última sección, ya sea al
configurarla explícitamente o al crearla para usted mediante los comandos de clonación o pago , git pull buscará qué
servidor y rama está rastreando su rama actual, buscar desde ese servidor y luego intente fusionarse en esa rama
remota.
En general, es mejor simplemente usar los comandos fetch y merge explícitamente, ya que la magia de git pull a
menudo puede ser confusa.
Supongamos que ha terminado con una rama remota; digamos que usted y sus colaboradores han terminado con
una función y la han fusionado con la rama maestra de su control remoto (o cualquier rama en la que se encuentre
su línea de código estable). Puede eliminar una rama remota usando la opción --delete para git push. Si desea
eliminar su rama serverfix del servidor, ejecute lo siguiente:
94
Machine Translated by Google
Básicamente, todo lo que hace es eliminar el puntero del servidor. El servidor Git generalmente mantendrá los datos allí
por un tiempo hasta que se ejecute una recolección de basura, por lo que si se eliminó accidentalmente, a menudo es fácil
para recuperar.
rebase
En Git, hay dos formas principales de integrar cambios de una rama a otra: la fusión y la reorganización. En esta sección,
aprenderá qué es el rebase, cómo hacerlo, por qué es una herramienta bastante sorprendente y en qué casos no querrá
usarla.
La rebase básica
Si regresa a un ejemplo anterior de Combinación básica, puede ver que divergió su trabajo y realizó confirmaciones en
dos ramas diferentes.
La forma más fácil de integrar las ramas, como ya hemos visto, es el comando fusionar . Realiza una combinación de
tres vías entre las dos instantáneas de rama más recientes (C3 y C4) y el ancestro común más reciente de las dos (C2),
creando una nueva instantánea (y compromiso).
95
Machine Translated by Google
Sin embargo, hay otra forma: puede tomar el parche del cambio que se introdujo en C4 y volver a aplicarlo
encima de C3. En Git, esto se llama rebase. Con el comando rebase , puede tomar todos los cambios que
se confirmaron en una rama y reproducirlos en una rama diferente.
Para este ejemplo, verificaría la rama del experimento y luego la reorganizaría en la rama maestra de la
siguiente manera:
Esta operación funciona yendo al ancestro común de las dos ramas (en la que está y en la que está
rebasando), obteniendo la diferencia introducida por cada confirmación de la rama en la que está, guardando
esas diferencias en temporal archivos, restableciendo la rama actual a la misma confirmación que la rama
en la que se está reorganizando y, finalmente, aplicando cada cambio a su vez.
En este punto, puede volver a la rama maestra y realizar una fusión de avance rápido.
96
Machine Translated by Google
Ahora, la instantánea a la que apunta C4' es exactamente la misma que apuntó C5 en el ejemplo de fusión. No
hay diferencia en el producto final de la integración, pero la reorganización hace que la historia sea más limpia.
Si examina el registro de una rama reorganizada, parece una historia lineal: parece que todo el trabajo sucedió
en serie, incluso cuando originalmente sucedió en paralelo.
A menudo, hará esto para asegurarse de que sus compromisos se apliquen correctamente en una rama remota,
tal vez en un proyecto en el que intenta contribuir pero que no mantiene. En este caso, haría su trabajo en una
rama y luego volvería a basar su trabajo en origin/master cuando estuviera listo para enviar sus parches al
proyecto principal. De esa manera, el mantenedor no tiene que hacer ningún trabajo de integración, solo un
avance rápido o una aplicación limpia.
Tenga en cuenta que la instantánea a la que apunta la confirmación final con la que termina, ya sea la última de
las confirmaciones reorganizadas para una reorganización o la confirmación de fusión final después de una
fusión, es la misma instantánea: solo el historial es diferente. La reorganización reproduce los cambios de una
línea de trabajo a otra en el orden en que se introdujeron, mientras que la fusión toma los puntos finales y los fusiona.
97
Machine Translated by Google
Figura 39. Una historia con una rama de tema de otra rama de tema
Supongamos que decide que desea fusionar los cambios del lado del cliente en su línea principal para un
lanzamiento, pero desea posponer los cambios del lado del servidor hasta que se pruebe más. Puede tomar los
cambios en el cliente que no está en el servidor (C8 y C9) y reproducirlos en su rama maestra usando la opción --
onto de git rebase:
Esto básicamente dice: "Tome la rama del cliente , descubra los parches, ya que se separó de la rama del servidor ,
y reproduzca estos parches en la rama del cliente como si estuviera basado directamente en la rama maestra ".
Es un poco complejo, pero el resultado es bastante bueno.
Figura 40. Cambio de base de una rama de tema a partir de otra rama de tema
Ahora puede avanzar rápidamente su rama principal (consulte Avance rápido de su rama principal para incluir los
cambios en la rama del cliente):
98
Machine Translated by Google
Figura 41. Avance rápido de su rama principal para incluir los cambios en la rama del cliente
Supongamos que decide extraer también la rama de su servidor. Puede volver a establecer la base de la rama del
servidor en la rama maestra sin tener que verificarla primero ejecutando git rebase <basebranch> <topicbranch> , que
verifica la rama del tema (en este caso, el servidor) por usted y la reproduce en la rama base (Maestro):
Esto reproduce el trabajo de su servidor sobre su trabajo maestro , como se muestra en Reorganización de la rama de
su servidor sobre su rama maestra .
Puede eliminar las ramas del cliente y del servidor porque todo el trabajo está integrado y ya no las necesita, dejando
su historial para todo este proceso con el aspecto del historial de confirmación final:
99
Machine Translated by Google
No rebase las confirmaciones que existen fuera de su repositorio y en las que las personas pueden haber
basado el trabajo.
Si sigues esa pauta, estarás bien. Si no lo haces, la gente te odiará y tus amigos y familiares te despreciarán.
Cuando reorganizas cosas, estás abandonando compromisos existentes y creando otros nuevos que son similares
pero diferentes. Si empuja confirmaciones en algún lugar y otros las bajan y basan su trabajo en ellas, y luego
vuelve a escribir esas confirmaciones con git rebase y las vuelve a subir, sus colaboradores tendrán que volver a
fusionar su trabajo y las cosas se complicarán cuando intente tire de su trabajo de nuevo en el suyo.
Veamos un ejemplo de cómo el trabajo de rebase que ha hecho público puede causar problemas.
Suponga que clona desde un servidor central y luego trabaja con eso. Su historial de confirmación se ve así:
Ahora, otra persona hace más trabajo que incluye una combinación y envía ese trabajo al servidor central. Lo busca
y fusiona la nueva rama remota en su trabajo, haciendo que su historial se vea así:
100
Machine Translated by Google
A continuación, la persona que impulsó el trabajo fusionado decide volver atrás y cambiar la base de su
trabajo; hacen un git push --force para sobrescribir el historial en el servidor. Luego obtienes de ese servidor,
lo que reduce las nuevas confirmaciones.
Figura 46. Alguien empuja confirmaciones reorganizadas, abandonando confirmaciones en las que ha basado su trabajo
101
Machine Translated by Google
Ahora ambos están en un lío. Si haces un git pull, crearás una confirmación de combinación que incluye ambas líneas del
historial, y tu repositorio se verá así:
Figura 47. Te fusionas en el mismo trabajo nuevamente en una nueva confirmación de fusión
Si ejecuta un registro de git cuando su historial se ve así, verá dos confirmaciones que tienen el mismo autor, fecha y mensaje,
lo que será confuso. Además, si vuelve a enviar este historial al servidor, volverá a introducir todas esas confirmaciones
reorganizadas en el servidor central, lo que puede confundir aún más a las personas. Es bastante seguro asumir que el otro
desarrollador no quiere que C4 y C6 estén en la historia; es por eso que cambiaron de base en primer lugar.
Resulta que, además de la suma de verificación SHA-1 de confirmación, Git también calcula una suma de verificación que se
basa solo en el parche introducido con la confirmación. Esto se llama "parche-id".
Si extrae el trabajo que se reescribió y lo vuelve a basar sobre las nuevas confirmaciones de su socio, Git a menudo puede
descubrir con éxito qué es exclusivamente suyo y aplicarlo nuevamente sobre la nueva rama.
Por ejemplo, en el escenario anterior, si en lugar de hacer una fusión cuando estamos en Alguien empuja confirmaciones
reorganizadas, abandonando las confirmaciones en las que basó su trabajo , ejecutamos git rebase teamone/master, Git:
• Determinar qué trabajo es exclusivo de nuestra sucursal (C2, C3, C4, C6, C7)
102
Machine Translated by Google
Entonces, en lugar del resultado que vemos en Usted fusiona el mismo trabajo nuevamente en una nueva confirmación de fusión,
terminaríamos con algo más como Rebase sobre el trabajo de rebase forzado.
Esto solo funciona si C4 y C4' que hizo su socio son casi exactamente el mismo parche. De lo contrario, la rebase no podrá decir que
es un duplicado y agregará otro parche similar a C4 (que probablemente no se aplicará limpiamente, ya que los cambios ya estarían
al menos un poco allí).
También puede simplificar esto ejecutando un git pull --rebase en lugar de un git pull normal . O puede hacerlo manualmente con un
git fetch seguido de un git rebase teamone/master en este caso.
Si está utilizando git pull y desea que --rebase sea el valor predeterminado, puede establecer el valor de configuración de pull.rebase
con algo como git config --global pull.rebase true.
Si solo vuelve a basar las confirmaciones que nunca han salido de su propia computadora, estará bien. Si vuelve a basar las
confirmaciones que se han enviado, pero de las que nadie más ha basado las confirmaciones, también estará bien. Si modifica la
base de confirmaciones que ya se han publicado públicamente, y es posible que la gente haya basado su trabajo en esas
confirmaciones, es posible que tenga algunos problemas frustrantes y el desprecio de su
compañeros de equipo
Si usted o un socio lo encuentran necesario en algún momento, asegúrese de que todos sepan ejecutar git pull --rebase para tratar de
hacer que el dolor después de que suceda sea un poco más simple.
Ahora que ha visto el cambio de base y la fusión en acción, es posible que se pregunte cuál es mejor.
Antes de que podamos responder esto, retrocedamos un poco y hablemos sobre lo que significa la historia.
Un punto de vista sobre esto es que el historial de confirmaciones de su repositorio es un registro de lo que realmente sucedió. Es
un documento histórico, valioso por derecho propio, y no debe ser alterado.
103
Machine Translated by Google
Desde este ángulo, cambiar el historial de confirmaciones es casi una blasfemia; estás mintiendo sobre lo que realmente
sucedió. Entonces, ¿qué pasa si hubo una serie desordenada de confirmaciones de fusión? Así fue como sucedió, y el
repositorio debería preservarlo para la posteridad.
El punto de vista opuesto es que el historial de confirmaciones es la historia de cómo se hizo tu proyecto.
No publicarías el primer borrador de un libro, así que ¿por qué mostrar tu desordenado trabajo? Cuando esté trabajando
en un proyecto, es posible que necesite un registro de todos sus pasos en falso y caminos sin salida, pero cuando
llegue el momento de mostrar su trabajo al mundo, es posible que desee contar una historia más coherente de cómo
obtener de A a B. Las personas en este campamento usan herramientas como rebase y filter-branch para reescribir
sus confirmaciones antes de que se fusionen en la rama principal. Usan herramientas como rebase y filter-branch para
contar la historia de la mejor manera para los futuros lectores.
Ahora, a la pregunta de si es mejor fusionar o reorganizar: espero que veas que no es tan simple. Git es una herramienta
poderosa y te permite hacer muchas cosas con tu historial, pero cada equipo y cada proyecto es diferente. Ahora que
sabe cómo funcionan ambas cosas, depende de usted decidir cuál es mejor para su situación particular.
Puede obtener lo mejor de ambos mundos: rebase los cambios locales antes de presionar para limpiar su trabajo, pero
nunca rebase nada que haya empujado en alguna parte.
Resumen
Hemos cubierto ramificaciones y fusiones básicas en Git. Debería sentirse cómodo creando y cambiando a nuevas
sucursales, cambiando entre sucursales y fusionando sucursales locales. También debería poder compartir sus
sucursales empujándolas a un servidor compartido, trabajando con otros en sucursales compartidas y reorganizando
sus sucursales antes de que se compartan. A continuación, cubriremos lo que necesitará para ejecutar su propio
servidor de alojamiento de repositorio Git.
104
Machine Translated by Google
Git en el servidor
En este punto, debería poder realizar la mayoría de las tareas diarias para las que usará Git.
Sin embargo, para poder colaborar en Git, deberá tener un repositorio de Git remoto.
Aunque técnicamente puede enviar y extraer cambios de los repositorios de las personas, no se recomienda hacerlo
porque puede confundir con bastante facilidad en qué están trabajando si no tiene cuidado. Además, desea que sus
colaboradores puedan acceder al repositorio incluso si su computadora está fuera de línea; a menudo es útil tener un
repositorio común más confiable. Por lo tanto, el método preferido para colaborar con alguien es configurar un repositorio
intermedio al que ambos tengan acceso, y empujar y extraer de él.
Ejecutar un servidor Git es bastante sencillo. Primero, elige qué protocolos desea que admita su servidor. La primera
sección de este capítulo cubrirá los protocolos disponibles y las ventajas y desventajas de cada uno. Las siguientes
secciones explicarán algunas configuraciones típicas que usan esos protocolos y cómo hacer que su servidor funcione
con ellos. Por último, repasaremos algunas opciones alojadas, si no le importa alojar su código en el servidor de otra
persona y no quiere pasar por la molestia de configurar y mantener su propio servidor.
Si no tiene interés en ejecutar su propio servidor, puede saltar a la última sección del capítulo para ver algunas opciones
para configurar una cuenta alojada y luego pasar al siguiente capítulo, donde analizamos los diversos entresijos del
trabajo. en un entorno de control de código fuente distribuido.
Un repositorio remoto es generalmente un repositorio simple , un repositorio de Git que no tiene un directorio de trabajo.
Debido a que el repositorio solo se usa como un punto de colaboración, no hay razón para tener una instantánea
desprotegida en el disco; son solo los datos de Git. En los términos más simples, un repositorio simple es el contenido
del directorio .git de su proyecto y nada más.
Los Protocolos
Git puede usar cuatro protocolos distintos para transferir datos: Local, HTTP, Secure Shell (SSH) y Git. Aquí discutiremos
qué son y en qué circunstancias básicas querrías (o no querrías) usarlos.
Protocolo Local
El más básico es el protocolo Local, en el que el repositorio remoto está en otro directorio del mismo host. Esto se usa
a menudo si todos en su equipo tienen acceso a un sistema de archivos compartido como un NFS mount, o en el caso
menos probable de que todos inicien sesión en la misma computadora. Esto último no sería lo ideal, porque todas las
instancias del repositorio de código residirían en la misma computadora, lo que haría mucho más probable una pérdida
catastrófica.
Si tiene un sistema de archivos montado compartido, puede clonar, enviar y extraer de un repositorio local basado en
archivos. Para clonar un repositorio como este, o para agregar uno como remoto a un proyecto existente, use la ruta al
repositorio como URL. Por ejemplo, para clonar un repositorio local, puede ejecutar algo como esto:
105
Machine Translated by Google
Git funciona de manera ligeramente diferente si especifica explícitamente file:// al comienzo de la URL. Si solo especifica
la ruta, Git intenta usar enlaces duros o copiar directamente los archivos que necesita. Si especifica file://, Git inicia los
procesos que normalmente usa para transferir datos a través de una red, que generalmente es mucho menos eficiente.
La razón principal para especificar el prefijo file:// es si desea una copia limpia del repositorio sin referencias u objetos
extraños, generalmente después de una importación desde otro VCS o algo similar (consulte Git Internals para tareas
de mantenimiento). Usaremos la ruta normal aquí porque hacerlo casi siempre es más rápido.
Para agregar un repositorio local a un proyecto Git existente, puede ejecutar algo como esto:
Luego, puede empujar y extraer de ese control remoto a través de su nuevo nombre remoto local_proj como si lo
estuviera haciendo a través de una red.
Los profesionales
Las ventajas de los repositorios basados en archivos son que son simples y utilizan los permisos de archivos existentes
y el acceso a la red. Si ya tiene un sistema de archivos compartido al que tiene acceso todo su equipo, configurar un
repositorio es muy fácil. Coloca la copia del repositorio en algún lugar al que todos tengan acceso compartido y
establece los permisos de lectura/escritura como lo haría con cualquier otro directorio compartido.
Discutiremos cómo exportar una copia de repositorio simple para este propósito en Obtener Git en un servidor.
Esta también es una buena opción para obtener rápidamente el trabajo del repositorio de trabajo de otra persona. Si
usted y un compañero de trabajo están trabajando en el mismo proyecto y quieren que verifique algo, ejecutar un
comando como git pull /home/john/project suele ser más fácil que empujar a un servidor remoto y luego buscarlo. .
Los contras
Las desventajas de este método son que el acceso compartido generalmente es más difícil de configurar y alcanzar
desde múltiples ubicaciones que el acceso a la red básica. Si desea presionar desde su computadora portátil cuando
está en casa, debe montar el disco remoto, lo que puede ser difícil y lento en comparación con el acceso basado en la
red.
Es importante mencionar que esta no es necesariamente la opción más rápida si está utilizando algún tipo de montaje
compartido. Un repositorio local es rápido solo si tiene acceso rápido a los datos. Un repositorio en NFS suele ser más
lento que el repositorio en SSH en el mismo servidor, lo que permite que Git se ejecute en discos locales en cada
sistema.
Finalmente, este protocolo no protege el depósito contra daños accidentales. Todos los usuarios tienen acceso de shell
completo al directorio "remoto", y no hay nada que les impida cambiar o eliminar archivos internos de Git y corromper
el repositorio.
106
Machine Translated by Google
Git puede comunicarse a través de HTTP usando dos modos diferentes. Antes de Git 1.6.6, solo había una forma de
hacerlo, que era muy simple y generalmente de solo lectura. En la versión 1.6.6, se introdujo un nuevo protocolo más
inteligente que implicaba que Git podía negociar de manera inteligente la transferencia de datos de una manera similar a
como lo hace a través de SSH. En los últimos años, este nuevo protocolo HTTP se ha vuelto muy popular ya que es más
simple para el usuario y más inteligente en la forma de comunicarse. La versión más nueva a menudo se conoce como el
protocolo Smart HTTP y la forma más antigua como Dumb HTTP. Cubriremos primero el nuevo protocolo Smart HTTP.
HTTP inteligente
Smart HTTP funciona de manera muy similar a los protocolos SSH o Git, pero se ejecuta en puertos HTTPS estándar y
puede usar varios mecanismos de autenticación HTTP, lo que significa que a menudo es más fácil para el usuario que algo
como SSH, ya que puede usar cosas como autenticación de nombre de usuario/contraseña en lugar de tener para
configurar claves SSH.
Probablemente se haya convertido en la forma más popular de usar Git ahora, ya que se puede configurar para servir de
forma anónima como el protocolo git:// y también se puede impulsar con autenticación y encriptación como el protocolo
SSH. En lugar de tener que configurar diferentes URL para estas cosas, ahora puede usar una sola URL para ambos. Si
intenta enviar y el repositorio requiere autenticación (que normalmente debería), el servidor puede solicitar un nombre de
usuario y una contraseña. Lo mismo ocurre con la lectura
acceso.
De hecho, para servicios como GitHub, la URL que usa para ver el repositorio en línea (por ejemplo, https://github.com/
schacon/simplegit) es la misma URL que puede usar para clonar y, si tiene acceso, presionar.
HTTP tonto
Si el servidor no responde con un servicio inteligente Git HTTP, el cliente Git intentará recurrir al protocolo Dumb HTTP
más simple. El protocolo Dumb espera que el repositorio básico de Git se sirva como archivos normales desde el servidor
web. La belleza de Dumb HTTP es la simplicidad de configurarlo.
Básicamente, todo lo que tiene que hacer es colocar un repositorio de Git bajo la raíz de su documento HTTP y configurar
un enlace específico posterior a la actualización , y listo (consulte Git Hooks). En ese momento, cualquier persona que
pueda acceder al servidor web en el que colocó el repositorio también puede clonar su repositorio. Para permitir el acceso
de lectura a su repositorio a través de HTTP, haga algo como esto:
$ cd /var/www/htdocs/
$ git clone --bare /path/to/git_project gitproject.git $ cd
gitproject.git $ mv hooks/post-update.sample hooks/post-
update $ chmod a+x hooks/ post-actualización
Eso es todo. El enlace posterior a la actualización que viene con Git de forma predeterminada ejecuta el comando
adecuado (git update-server-info) para que la obtención y clonación de HTTP funcione correctamente. Este comando se
ejecuta cuando ingresa a este repositorio (quizás a través de SSH); luego, otras personas pueden clonar a través de algo como:
107
Machine Translated by Google
En este caso particular, estamos usando la ruta /var/www/htdocs que es común para las configuraciones de Apache, pero puede usar
cualquier servidor web estático; simplemente coloque el repositorio básico en su ruta. Los datos de Git se sirven como archivos estáticos
básicos (consulte el capítulo sobre aspectos internos de Git para obtener detalles sobre cómo se sirven exactamente).
Por lo general, elegiría ejecutar un servidor HTTP inteligente de lectura/escritura o simplemente tener los archivos accesibles como de
solo lectura de la manera tonta. Es raro ejecutar una combinación de los dos servicios.
Los profesionales
La sencillez de tener una sola URL para todos los tipos de acceso y hacer que el servidor solicite solo cuando se necesita autenticación
hace que las cosas sean muy fáciles para el usuario final. Poder autenticarse con un nombre de usuario y contraseña también es una
gran ventaja sobre SSH, ya que los usuarios no tienen que generar claves SSH localmente y cargar su clave pública en el servidor
antes de poder interactuar con ella. Para usuarios menos sofisticados, o usuarios en sistemas donde SSH es menos común, esta es
una gran ventaja en la usabilidad. También es un protocolo muy rápido y eficiente, similar al SSH.
También puede servir sus repositorios de solo lectura a través de HTTPS, lo que significa que puede cifrar la transferencia de contenido;
o puede llegar a hacer que los clientes usen certificados SSL firmados específicos.
Otra cosa buena es que HTTP y HTTPS son protocolos de uso tan común que los firewalls corporativos a menudo se configuran para
permitir el tráfico a través de sus puertos.
Los contras
Git sobre HTTPS puede ser un poco más complicado de configurar en comparación con SSH en algunos servidores. Aparte de eso,
hay muy pocas ventajas que otros protocolos tengan sobre Smart HTTP para servir a Git.
contenido.
Si está utilizando HTTP para la inserción autenticada, proporcionar sus credenciales a veces es más complicado que usar claves a
través de SSH. Sin embargo, hay varias herramientas de almacenamiento en caché de credenciales que puede usar, incluido el acceso
a Llaveros en macOS y Credential Manager en Windows, para que esto sea bastante sencillo. Lea Almacenamiento de credenciales
para ver cómo configurar el almacenamiento en caché seguro de contraseñas HTTP en su sistema.
El protocolo SSH
Un protocolo de transporte común para Git cuando el alojamiento propio se realiza a través de SSH. Esto se debe a que el acceso SSH
a los servidores ya está configurado en la mayoría de los lugares, y si no lo está, es fácil hacerlo. SSH también es un protocolo de red
autenticado y, debido a que es ubicuo, generalmente es fácil de configurar y usar.
Para clonar un repositorio Git sobre SSH, puede especificar una URL ssh:// como esta:
108
Machine Translated by Google
O puede usar la sintaxis similar a scp más corta para el protocolo SSH:
En los dos casos anteriores, si no especifica el nombre de usuario opcional, Git asume el usuario con el que está
conectado actualmente.
Los profesionales
Las ventajas de usar SSH son muchas. Primero, SSH es relativamente fácil de configurar: los demonios SSH son
comunes, muchos administradores de red tienen experiencia con ellos y muchas distribuciones de sistemas operativos
se configuran con ellos o tienen herramientas para administrarlos. Luego, el acceso a través de SSH es seguro: todas
las transferencias de datos se cifran y autentican. Por último, al igual que los protocolos HTTPS, Git y Local, SSH es
eficiente y hace que los datos sean lo más compactos posible antes de transferirlos.
Los contras
El aspecto negativo de SSH es que no admite el acceso anónimo a su repositorio de Git. Si está utilizando SSH, las
personas deben tener acceso SSH a su máquina, incluso en una capacidad de solo lectura, lo que no hace que SSH
sea propicio para proyectos de código abierto para los cuales las personas simplemente deseen clonar su repositorio
para examinarlo. Si lo usa solo dentro de su red corporativa, SSH puede ser el único protocolo con el que debe lidiar. Si
desea permitir el acceso anónimo de solo lectura a sus proyectos y también desea usar SSH, tendrá que configurar
SSH para que pueda pasar, pero algo más para que otros puedan buscar.
El Protocolo Git
Finalmente, tenemos el protocolo Git. Este es un demonio especial que viene empaquetado con Git; escucha en un
puerto dedicado (9418) que brinda un servicio similar al protocolo SSH, pero sin autenticación en absoluto. Para que un
repositorio se sirva mediante el protocolo Git, debe crear un archivo git-daemon-export-ok (el demonio no servirá un
repositorio sin ese archivo), pero aparte de eso, no hay seguridad. . O el repositorio de Git está disponible para que
todos lo clonen, o no lo está.
Esto significa que, por lo general, no hay que forzar este protocolo. Puede habilitar el acceso push pero, dada la falta
de autenticación, cualquier persona en Internet que encuentre la URL de su proyecto podría enviarlo a ese proyecto.
Baste decir que esto es raro.
Los profesionales
El protocolo Git suele ser el protocolo de transferencia de red más rápido disponible. Si está atendiendo una gran
cantidad de tráfico para un proyecto público o atendiendo un proyecto muy grande que no requiere autenticación de
usuario para el acceso de lectura, es probable que desee configurar un demonio de Git para atender su proyecto. Utiliza
el mismo mecanismo de transferencia de datos que el protocolo SSH pero sin la sobrecarga de cifrado y autenticación.
Los contras
La desventaja del protocolo Git es la falta de autenticación. Por lo general, no es deseable que el protocolo Git sea el
único acceso a su proyecto. Por lo general, lo combinará con acceso SSH o HTTPS para
109
Machine Translated by Google
los pocos desarrolladores que tienen acceso de inserción (escritura) y hacen que todos los demás usen git:// para acceso
de solo lectura. También es probablemente el protocolo más difícil de configurar. Debe ejecutar su propio demonio, que
requiere la configuración de xinetd o systemd o similar, que no siempre es un paseo por el parque. También requiere
acceso de firewall al puerto 9418, que no es un puerto estándar que siempre permiten los firewalls corporativos. Detrás de
los grandes firewalls corporativos, este oscuro puerto suele estar bloqueado.
Aquí demostraremos los comandos y los pasos necesarios para realizar instalaciones básicas y
simplificadas en un servidor basado en Linux, aunque también es posible ejecutar estos servicios en
Para configurar inicialmente cualquier servidor Git, debe exportar un repositorio existente a un nuevo repositorio básico,
un repositorio que no contiene un directorio de trabajo. Esto es generalmente fácil de hacer. Para clonar su repositorio
para crear un nuevo repositorio simple, ejecute el comando de clonación con la opción --bare . Por convención, los nombres
de directorios de repositorios desnudos terminan con el sufijo .git, así:
Ahora debería tener una copia de los datos del directorio Git en su directorio my_project.git .
Hay un par de diferencias menores en el archivo de configuración pero, para su propósito, es casi lo mismo. Toma el
repositorio de Git solo, sin un directorio de trabajo, y crea un directorio específicamente solo para él.
110
Machine Translated by Google
En este punto, otros usuarios que tengan acceso de lectura basado en SSH al directorio /srv/git en ese servidor pueden
clonar su repositorio ejecutando:
Si un usuario usa SSH en un servidor y tiene acceso de escritura al directorio /srv/git/my_project.git , también tendrá
automáticamente acceso de inserción.
Git agregará automáticamente permisos de escritura grupales a un repositorio correctamente si ejecuta el comando git init
con la opción --shared . Tenga en cuenta que al ejecutar este comando, no destruirá ninguna confirmación, referencia, etc.
en el proceso.
$ ssh usuario@git.example.com
$ cd /srv/git/my_project.git $
git init --bare --shared
Verá lo fácil que es tomar un repositorio de Git, crear una versión básica y colocarlo en un servidor al que usted y sus
colaboradores tengan acceso SSH. Ahora estás listo para colaborar en el mismo proyecto.
Es importante tener en cuenta que esto es literalmente todo lo que necesita hacer para ejecutar un servidor Git útil al que
varias personas tengan acceso: simplemente agregue cuentas compatibles con SSH en un servidor y pegue un repositorio
básico en algún lugar donde todos esos usuarios hayan leído y escrito. el acceso a los. Estás listo para ir, no se necesita
nada más.
En las próximas secciones, verá cómo expandirse a configuraciones más sofisticadas. Esta discusión incluirá no tener que
crear cuentas de usuario para cada usuario, agregar acceso público de lectura a los repositorios, configurar interfaces de
usuario web y más. Sin embargo, tenga en cuenta que para colaborar con un par de personas en un proyecto privado,
todo lo que necesita es un servidor SSH y un repositorio básico.
Configuraciones pequeñas
Si tiene un equipo pequeño o simplemente está probando Git en su organización y tiene solo unos pocos desarrolladores,
las cosas pueden ser simples para usted. Uno de los aspectos más complicados de configurar un servidor Git es la gestión
de usuarios. Si desea que algunos repositorios sean de solo lectura para ciertos usuarios y de lectura/escritura para otros,
el acceso y los permisos pueden ser un poco más difíciles de organizar.
Acceso SSH
Si tiene un servidor al que todos sus desarrolladores ya tienen acceso SSH, generalmente es más fácil configurar su
primer repositorio allí, porque casi no tiene que hacer ningún trabajo (como cubrimos en la última sección). Si desea
permisos de tipo de control de acceso más complejos en sus repositorios, puede manejarlos con los permisos normales
del sistema de archivos del sistema operativo de su servidor.
111
Machine Translated by Google
Si desea colocar sus repositorios en un servidor que no tiene cuentas para todos los miembros de su equipo a
quienes desea otorgar acceso de escritura, debe configurar el acceso SSH para ellos. Suponemos que si tiene
un servidor con el que hacer esto, ya tiene instalado un servidor SSH, y así es como está accediendo al servidor.
Hay algunas maneras en las que puede otorgar acceso a todos los miembros de su equipo. El primero es
configurar cuentas para todos, lo cual es sencillo pero puede ser engorroso. Es posible que no desee ejecutar
adduser (o la posible alternativa useradd) y tenga que establecer contraseñas temporales para cada nuevo usuario.
Un segundo método es crear una sola cuenta de usuario 'git' en la máquina, pedirle a cada usuario que tenga
acceso de escritura que le envíe una clave pública SSH y agregar esa clave al archivo ~/.ssh/authorized_keys
de ese nuevo cuenta 'git'. En ese momento, todos podrán acceder a esa máquina a través de la cuenta 'git'. Esto
no afecta los datos de confirmación de ninguna manera: el usuario de SSH con el que te conectas no afecta las
confirmaciones que has registrado.
Otra forma de hacerlo es hacer que su servidor SSH se autentique desde un servidor LDAP o alguna otra fuente
de autenticación centralizada que ya haya configurado. Siempre que cada usuario pueda obtener acceso de shell
en la máquina, cualquier mecanismo de autenticación SSH que se le ocurra debería funcionar.
$ cd ~/.ssh $
lsauthorized_keys2
Está buscando un par de archivos con un nombre similar a id_dsa o id_rsa y un archivo coincidente con una
extensión .pub . El archivo .pub es su clave pública y el otro archivo es la clave privada correspondiente. Si no
tiene estos archivos (o ni siquiera tiene un directorio .ssh ), puede crearlos ejecutando un programa llamado ssh-
keygen, que se proporciona con el paquete SSH en sistemas Linux/macOS y viene con Git para Windows:
112
Machine Translated by Google
$ ssh-keygen -o
Generación de un par de claves rsa públicas/privadas.
Introduzca el archivo en el que guardar la clave (/home/schacon/.ssh/id_rsa): Directorio
creado '/home/schacon/.ssh'.
Ingrese la frase de contraseña (vacío para no tener frase de
contraseña): Ingrese la misma frase de contraseña
nuevamente: Su identificación ha sido guardada en /home/schacon/.ssh/id_rsa.
Su clave pública se ha guardado en /home/schacon/.ssh/id_rsa.pub.
La huella digital clave es:
d0:82:24:8e:d7:f1:bb:9b:33:53:96:93:49:da:9b:e3 schacon@mylaptop.local
Primero confirma dónde desea guardar la clave (.ssh/id_rsa), y luego solicita dos veces una frase de contraseña, que
puede dejar vacía si no desea escribir una contraseña cuando use la clave.
Sin embargo, si usa una contraseña, asegúrese de agregar la opción -o ; guarda la clave privada en un formato que es
más resistente al descifrado de contraseñas por fuerza bruta que el formato predeterminado. También puede usar la
herramienta ssh-agent para evitar tener que ingresar la contraseña cada vez.
Ahora, cada usuario que haga esto debe enviarle su clave pública a usted o a quien esté administrando el servidor Git
(suponiendo que esté utilizando una configuración de servidor SSH que requiere claves públicas). Todo lo que tienen
que hacer es copiar el contenido del archivo .pub y enviarlo por correo electrónico. Las claves públicas se ven así:
Para obtener un tutorial más detallado sobre cómo crear una clave SSH en varios sistemas operativos, consulte la guía
de GitHub sobre claves SSH en https://docs.github.com/en/github/authenticating-to-github/generating-a-new ssh-key-and-
adding-it-to-the-ssh-agent.
Primero, crea una cuenta de usuario de git y un directorio .ssh para ese usuario.
113
Machine Translated by Google
A continuación, debe agregar algunas claves públicas SSH del desarrollador al archivo authorized_keys para el usuario de git .
Supongamos que tiene algunas claves públicas de confianza y las ha guardado en archivos temporales. Nuevamente, las
claves públicas se ven así:
Simplemente los agrega al archivo authorized_keys del usuario de git en su directorio .ssh :
Ahora, puede configurar un repositorio vacío para ellos ejecutando git init con la opción --bare , que inicializa el repositorio sin
un directorio de trabajo:
$ cd /srv/git $
mkdir project.git $ cd
project.git $ git init --bare
Repositorio Git vacío
inicializado en /srv/git/project.git/
Luego, John, Josie o Jessica pueden insertar la primera versión de su proyecto en ese repositorio agregándolo como un control
remoto y empujando hacia arriba una rama. Tenga en cuenta que alguien debe instalarse en la máquina y crear un repositorio
simple cada vez que desee agregar un proyecto. Usemos gitserver como el nombre de host del servidor en el que configuró
su usuario y repositorio de git . Si lo está ejecutando internamente y configura DNS para que gitserver apunte a ese servidor,
entonces puede usar los comandos prácticamente como están (suponiendo que myproject es un proyecto existente con
archivos):
114
Machine Translated by Google
# en la computadora
de John $ cd myproject
$ git init $ git add . $
git commit -m 'Commit
inicial' $ git remote add origin
git@gitserver:/srv/git/project.git $ git push origin master
En este punto, los demás pueden clonarlo y volver a subir los cambios con la misma facilidad:
Con este método, puede poner en funcionamiento rápidamente un servidor Git de lectura/escritura para un puñado de
desarrolladores.
Debe tener en cuenta que actualmente todos estos usuarios también pueden iniciar sesión en el servidor y obtener un shell
como usuario de git . Si desea restringir eso, deberá cambiar el shell a otra cosa en el archivo /etc/passwd .
Puede restringir fácilmente la cuenta de usuario de git a solo actividades relacionadas con Git con una herramienta de shell
limitada llamada git-shell que viene con Git. Si configura esto como el shell de inicio de sesión de la cuenta de usuario de git ,
entonces esa cuenta no puede tener acceso de shell normal a su servidor. Para usar esto, especifique git-shell en lugar de
bash o csh para el shell de inicio de sesión de esa cuenta. Para hacerlo, primero debe agregar la ruta completa del comando
git-shell a /etc/shells si aún no está allí:
Ahora puede editar el shell para un usuario usando chsh <nombre de usuario> -s <shell>:
Ahora, el usuario de git aún puede usar la conexión SSH para enviar y recibir repositorios de Git, pero no puede instalarse en
la máquina. Si lo intenta, verá un rechazo de inicio de sesión como este:
$ ssh git@gitserver
fatal: el shell interactivo de git no está habilitado.
sugerencia: ~/git-shell-commands debe existir y tener acceso de lectura y ejecución.
Conexión a gitserver cerrada.
115
Machine Translated by Google
En este punto, los usuarios aún pueden usar el reenvío de puertos SSH para acceder a cualquier host al que pueda
acceder el servidor git. Si desea evitar eso, puede editar el archivo authorized_keys y anteponer las siguientes
opciones a cada clave que desee restringir:
sin reenvío de puertos, sin reenvío X11, sin reenvío de agentes, sin pty
sin reenvío de puerto, sin reenvío X11, sin reenvío de agente, sin pty ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQDEwENNMomTboYI+LJieaAY16qiXiH3wuvENhBG...
Ahora los comandos de red de Git seguirán funcionando bien, pero los usuarios no podrán obtener un shell. Como
indica el resultado, también puede configurar un directorio en el directorio de inicio del usuario de git que personaliza
un poco el comando git-shell . Por ejemplo, puede restringir los comandos de Git que aceptará el servidor o puede
personalizar el mensaje que ven los usuarios si intentan acceder a SSH de esa manera. Ejecute git help shell para
obtener más información sobre cómo personalizar el shell.
Git demonio
A continuación, configuraremos un demonio que sirva repositorios mediante el protocolo "Git". Esta es una opción
común para un acceso rápido y no autenticado a sus datos de Git. Recuerde que dado que este no es un servicio
autenticado, todo lo que sirva a través de este protocolo es público dentro de su red.
Si está ejecutando esto en un servidor fuera de su firewall, debe usarse solo para proyectos que son públicamente
visibles para el mundo. Si el servidor en el que lo está ejecutando está dentro de su firewall, puede usarlo para
proyectos a los que una gran cantidad de personas o computadoras (integración continua o servidores de
compilación) tienen acceso de solo lectura, cuando no desea tener para agregar una clave SSH para cada uno.
En cualquier caso, el protocolo Git es relativamente fácil de configurar. Básicamente, debe ejecutar este comando
de manera demonizada:
La opción --reuseaddr permite que el servidor se reinicie sin esperar a que se agoten las conexiones antiguas,
mientras que la opción --base-path permite clonar proyectos sin especificar la ruta completa, y la ruta al final le dice
al demonio Git dónde busque repositorios para exportar. Si está ejecutando un firewall, también deberá perforar un
agujero en el puerto 9418 en el cuadro en el que está configurando esto.
116
Machine Translated by Google
Puede demonizar este proceso de varias maneras, según el sistema operativo que esté ejecutando.
Dado que systemd es el sistema de inicio más común entre las distribuciones modernas de Linux, puede usarlo para ese
propósito. Simplemente coloque un archivo en /etc/systemd/system/git-daemon.service con estos contenidos:
[Unidad]
Descripción=Iniciar Git Daemon
[Servicio]
ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/srv/git/ /srv/git/
Reiniciar=siempre
Reiniciar segundo = 500 ms
Salida estándar=syslog
StandardError=syslog
SyslogIdentifier=git-daemon
Usuario=git
Grupo=git
[Instalar en pc]
WantedBy=multi-usuario.objetivo
Es posible que haya notado que el demonio Git se inicia aquí con git como grupo y como usuario. Modifíquelo para que
se ajuste a sus necesidades y asegúrese de que el usuario proporcionado exista en el sistema. Además, verifique que el
binario de Git esté realmente ubicado en /usr/bin/git y cambie la ruta si es necesario.
Finalmente, ejecutará systemctl enable git-daemon para iniciar automáticamente el servicio en el arranque, y puede
iniciar y detener el servicio con, respectivamente, systemctl start git-daemon y systemctl stop git daemon.
En otros sistemas, es posible que desee usar xinetd, un script en su sistema sysvinit , o algo más, siempre que obtenga
ese comando demonizado y observado de alguna manera.
A continuación, debe decirle a Git a qué repositorios debe permitir el acceso no autenticado basado en el servidor de Git.
Puede hacer esto en cada repositorio creando un archivo llamado git-daemon-export-ok.
La presencia de ese archivo le dice a Git que está bien servir este proyecto sin autenticación.
HTTP inteligente
Ahora tenemos acceso autenticado a través de SSH y acceso no autenticado a través de git://, pero también hay un
protocolo que puede hacer ambas cosas al mismo tiempo. Configurar Smart HTTP es básicamente solo
117
Machine Translated by Google
habilitando un script CGI que se proporciona con Git llamado git-http-backend en el servidor. Este CGI leerá la ruta y
los encabezados enviados por git fetch o git push a una URL HTTP y determinará si el cliente puede comunicarse a
través de HTTP (lo cual es cierto para cualquier cliente desde la versión 1.6.6). Si el CGI ve que el cliente es inteligente,
se comunicará inteligentemente con él; de lo contrario, volverá al comportamiento tonto (por lo que es compatible con
versiones anteriores para lecturas con clientes más antiguos).
Veamos una configuración muy básica. Configuraremos esto con Apache como el servidor CGI. Si no tiene la
configuración de Apache, puede hacerlo en una caja de Linux con algo como esto:
Esto también habilita los módulos mod_cgi, mod_alias y mod_env , que son necesarios para que esto funcione
correctamente.
También deberá configurar el grupo de usuarios de Unix de los directorios /srv/git en www-data para que su servidor
web pueda leer y escribir acceso a los repositorios, porque la instancia de Apache que ejecuta el script CGI será (por
defecto) ejecutándose como ese usuario:
A continuación, debemos agregar algunas cosas a la configuración de Apache para ejecutar git-http-backend como
controlador de todo lo que ingrese a la ruta /git de su servidor web.
Si omite la variable de entorno GIT_HTTP_EXPORT_ALL , Git solo servirá a los clientes no autenticados los repositorios
con el archivo git-daemon-export-ok en ellos, tal como lo hizo el demonio de Git.
Finalmente, querrá decirle a Apache que permita las solicitudes a git-http-backend y que haga que las escrituras se
autentiquen de alguna manera, posiblemente con un bloque Auth como este:
<Archivos "git-http-backend">
AuthType Basic AuthName "Git
Access"
AuthUserFile /srv/git/.htpasswd Requerir
expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~
m#/git-receive-pack$#)
Requerir usuario válido </
Files>
Eso requerirá que cree un archivo .htpasswd que contenga las contraseñas de todos los usuarios válidos. Aquí hay un
ejemplo de cómo agregar un usuario "schacon" al archivo:
118
Machine Translated by Google
Hay muchas formas de que Apache autentique a los usuarios, tendrá que elegir e implementar una de ellas. Este
es solo el ejemplo más simple que se nos ocurrió. Es casi seguro que también querrá configurar esto a través de
SSL para que todos estos datos estén encriptados.
GitWeb
Ahora que tiene acceso básico de lectura/escritura y de solo lectura a su proyecto, es posible que desee
configurar un visualizador simple basado en la web. Git viene con un script CGI llamado GitWeb que a veces se
usa para esto.
119
Machine Translated by Google
Si desea verificar cómo se vería GitWeb para su proyecto, Git viene con un comando para iniciar una
instancia temporal si tiene un servidor web liviano en su sistema como lighttpd o webrick. En las máquinas
Linux, a menudo se instala lighttpd , por lo que puede ejecutarlo escribiendo git instaweb en el directorio de
su proyecto. Si está ejecutando una Mac, Leopard viene preinstalado con Ruby, por lo que webrick puede
ser su mejor opción. Para iniciar instaweb con un controlador que no sea lighttpd, puede ejecutarlo con la
opción --httpd .
Eso inicia un servidor HTTPD en el puerto 1234 y luego inicia automáticamente un navegador web que se
abre en esa página. Es bastante fácil de tu parte. Cuando haya terminado y desee apagar el servidor, puede
ejecutar el mismo comando con la opción --stop :
Si desea ejecutar la interfaz web en un servidor todo el tiempo para su equipo o para un proyecto de código
abierto que está alojando, deberá configurar el script CGI para que lo sirva su servidor web normal.
Algunas distribuciones de Linux tienen un paquete gitweb que puede instalar a través de apt o dnf, por lo
que es posible que desee probarlo primero. Veremos cómo instalar GitWeb manualmente muy rápidamente.
Primero, debe obtener el código fuente de Git, que viene con GitWeb, y generar el script CGI personalizado:
Tenga en cuenta que debe indicarle al comando dónde encontrar sus repositorios de Git con la variable
GITWEB_PROJECTROOT . Ahora, debe hacer que Apache use CGI para ese script, para lo cual puede
agregar un VirtualHost:
120
Machine Translated by Google
ordenar permitir,
ÿ
denegar Permitir
ÿ
Una vez más, GitWeb se puede servir con cualquier servidor web compatible con CGI o Perl; si prefiere usar otra cosa, no
debería ser difícil de configurar. En este punto, debería poder visitar http://gitserver/ para ver sus repositorios en línea.
GitLab
Sin embargo, GitWeb es bastante simplista. Si está buscando un servidor Git moderno y con todas las funciones, existen
varias soluciones de código abierto que puede instalar en su lugar. Como GitLab es uno de los más populares, cubriremos
su instalación y uso como ejemplo. Esto es más difícil que la opción GitWeb y requerirá más mantenimiento, pero es una
opción con todas las funciones.
Instalación
GitLab es una aplicación web respaldada por una base de datos, por lo que su instalación es más complicada que la de
otros servidores Git. Afortunadamente, este proceso está bien documentado y respaldado. GitLab recomienda
encarecidamente instalar GitLab en su servidor a través del paquete oficial Omnibus GitLab.
• Proveedor de nube como AWS, Google Cloud Platform, Azure, OpenShift y Digital Ocean.
Para obtener más información, lea el archivo Léame de GitLab Community Edition (CE).
Administración
Se accede a la interfaz de administración de GitLab a través de la web. Simplemente dirija su navegador al nombre de
host o la dirección IP donde está instalado GitLab e inicie sesión como usuario administrador. El nombre de usuario
predeterminado es admin@local.host y la contraseña predeterminada es 5iveL!fe (que debe cambiar de inmediato). Una
vez que haya iniciado sesión, haga clic en el icono "Área de administración" en el menú en la parte superior derecha.
121
Machine Translated by Google
Usuarios
Todos los que usen su servidor GitLab deben tener una cuenta de usuario. Las cuentas de usuario son bastante simples,
contienen principalmente información personal adjunta a los datos de inicio de sesión. Cada cuenta de usuario tiene un espacio
de nombres, que es una agrupación lógica de proyectos que pertenecen a ese usuario. Si el usuario jane tuviera un proyecto
llamado proyecto, la URL de ese proyecto sería http://servidor/jane/proyecto.
Puede eliminar una cuenta de usuario de dos maneras: "Bloquear" a un usuario evita que inicie sesión en la instancia de GitLab,
pero todos los datos en el espacio de nombres de ese usuario se conservarán, y las confirmaciones firmadas con la dirección
de correo electrónico de ese usuario seguirán vinculándose a su perfil
"Destruir" a un usuario, por otro lado, lo elimina por completo de la base de datos y del sistema de archivos.
Se eliminarán todos los proyectos y datos en su espacio de nombres, y también se eliminarán todos los grupos que posean.
Obviamente, esta es una acción mucho más permanente y destructiva, y rara vez la necesitarás.
Grupos
Un grupo de GitLab es una colección de proyectos, junto con datos sobre cómo los usuarios pueden acceder a esos proyectos.
Cada grupo tiene un espacio de nombres de proyecto (de la misma manera que lo hacen los usuarios), por lo que si la
capacitación del grupo tiene materiales del proyecto, su URL sería http://servidor/capacitación/materiales.
122
Machine Translated by Google
Cada grupo está asociado con una cantidad de usuarios, cada uno de los cuales tiene un nivel de permisos para los proyectos del grupo y
el grupo mismo. Estos van desde "Invitado" (solo problemas y chat) hasta "Propietario" (control total del grupo, sus miembros y sus
proyectos). Los tipos de permisos son demasiado numerosos para enumerarlos aquí, pero GitLab tiene un enlace útil en la pantalla de
administración.
Proyectos
Un proyecto de GitLab corresponde aproximadamente a un solo repositorio de Git. Cada proyecto pertenece a un solo espacio de nombres,
ya sea un usuario o un grupo. Si el proyecto pertenece a un usuario, el propietario del proyecto tiene control directo sobre quién tiene
acceso al proyecto; si el proyecto pertenece a un grupo, los permisos de nivel de usuario del grupo tendrán efecto.
Cada proyecto tiene un nivel de visibilidad, que controla quién tiene acceso de lectura a las páginas y al repositorio de ese proyecto. Si un
proyecto es privado, el propietario del proyecto debe otorgar acceso de forma explícita a usuarios específicos.
Un proyecto interno es visible para cualquier usuario que haya iniciado sesión y un proyecto público es visible para cualquier persona.
Tenga en cuenta que esto controla tanto el acceso a git fetch como el acceso a la interfaz de usuario web para ese proyecto.
Manos
GitLab incluye soporte para ganchos, tanto a nivel de proyecto como de sistema. Para cualquiera de estos, el servidor de GitLab realizará
un HTTP POST con algún JSON descriptivo cada vez que ocurran eventos relevantes.
Esta es una excelente manera de conectar sus repositorios de Git y su instancia de GitLab con el resto de su automatización de desarrollo,
como servidores de CI, salas de chat o herramientas de implementación.
Uso básico
Lo primero que querrá hacer con GitLab es crear un nuevo proyecto. Puede hacerlo haciendo clic en el icono "+" en la barra de herramientas.
Se le pedirá el nombre del proyecto, a qué espacio de nombres debe pertenecer y cuál debe ser su nivel de visibilidad. La mayor parte de
lo que especifica aquí no es permanente y se puede cambiar más tarde a través de la interfaz de configuración. Haz clic en "Crear proyecto"
y listo.
123
Machine Translated by Google
Una vez que exista el proyecto, probablemente querrá conectarlo con un repositorio Git local. Se puede acceder a cada proyecto a
través de HTTPS o SSH, cualquiera de los cuales se puede usar para configurar un control remoto de Git. Las URL están visibles en
la parte superior de la página de inicio del proyecto. Para un repositorio local existente, este comando creará un gitlab remoto con
nombre en la ubicación alojada:
Si no tiene una copia local del repositorio, simplemente puede hacer esto:
La interfaz de usuario web proporciona acceso a varias vistas útiles del propio repositorio. La página de inicio de cada proyecto
muestra la actividad reciente, y los enlaces en la parte superior lo llevarán a las vistas de los archivos del proyecto y al registro de
confirmación.
Trabajando juntos
La forma más sencilla de trabajar juntos en un proyecto de GitLab es otorgar a cada usuario acceso push directo al repositorio de Git.
Puede agregar un usuario a un proyecto yendo a la sección "Miembros" de la configuración de ese proyecto y asociando el nuevo
usuario con un nivel de acceso (los diferentes niveles de acceso se discuten un poco en Grupos). Al darle a un usuario un nivel de
acceso de "Desarrollador" o superior, ese usuario puede enviar confirmaciones y bifurcaciones directamente al repositorio.
Otra forma de colaboración más desacoplada es mediante el uso de solicitudes de combinación. Esta característica permite que
cualquier usuario que pueda ver un proyecto contribuya a él de forma controlada. Los usuarios con acceso directo pueden
simplemente crear una rama, enviar confirmaciones a ella y abrir una solicitud de fusión desde su rama hacia la maestra o cualquier
otra rama. Los usuarios que no tienen permisos de inserción para un repositorio pueden "bifurcarlo" para crear su propia copia, enviar
confirmaciones a su copia y abrir una solicitud de fusión desde su bifurcación de regreso al proyecto principal. Este modelo le permite
al propietario tener el control total de lo que ingresa al repositorio y cuándo, al tiempo que permite contribuciones de usuarios que no
son de confianza.
Fusionar solicitudes y problemas son las principales unidades de discusión de larga duración en GitLab. Cada solicitud de combinación
permite una discusión línea por línea del cambio propuesto (que admite un tipo de revisión de código ligero), así como un hilo de
discusión general. Ambos pueden asignarse a usuarios u organizarse en hitos.
Esta sección se enfoca principalmente en las funciones de GitLab relacionadas con Git, pero como un proyecto maduro, proporciona
muchas otras funciones para ayudar a su equipo a trabajar en conjunto, como wikis de proyectos y herramientas de mantenimiento
del sistema. Un beneficio de GitLab es que, una vez que el servidor está configurado y funcionando, rara vez necesitará modificar un
archivo de configuración o acceder al servidor a través de SSH; la mayor parte de la administración y el uso general se pueden
realizar a través de la interfaz del navegador.
124
Machine Translated by Google
una serie de ventajas: un sitio de alojamiento es generalmente rápido de configurar y fácil de iniciar proyectos,
y no requiere mantenimiento ni supervisión del servidor. Incluso si configura y ejecuta su propio servidor
internamente, es posible que desee utilizar un sitio de alojamiento público para su código fuente abierto; por lo
general, es más fácil para la comunidad de código abierto encontrarlo y ayudarlo.
En estos días, tiene una gran cantidad de opciones de alojamiento para elegir, cada una con diferentes ventajas
y desventajas. Para ver una lista actualizada, consulte la página de GitHosting en el wiki principal de Git en
https://git.wiki.kernel.org/index.php/GitHosting.
Cubriremos el uso de GitHub en detalle en GitHub, ya que es el host de Git más grande que existe y es posible
que deba interactuar con proyectos alojados en él en cualquier caso, pero hay docenas más para elegir si no
desea configurar su propio servidor Git.
Resumen
Tiene varias opciones para poner en marcha un repositorio Git remoto para que pueda colaborar con otros o
compartir su trabajo.
Ejecutar su propio servidor le brinda mucho control y le permite ejecutar el servidor dentro de su propio firewall,
pero dicho servidor generalmente requiere una buena cantidad de su tiempo para configurarlo y mantenerlo. Si
coloca sus datos en un servidor alojado, es fácil de configurar y mantener; sin embargo, debe poder mantener
su código en los servidores de otra persona, y algunas organizaciones no lo permiten.
Debería ser bastante sencillo determinar qué solución o combinación de soluciones es adecuada para usted y
su organización.
125
Machine Translated by Google
Git distribuido
Ahora que tiene un repositorio Git remoto configurado como punto focal para que todos los desarrolladores compartan
su código, y está familiarizado con los comandos básicos de Git en un flujo de trabajo local, verá cómo utilizar algunos
de los flujos de trabajo distribuidos. que Git te ofrece.
En este capítulo, verá cómo trabajar con Git en un entorno distribuido como colaborador e integrador. Es decir,
aprenderá cómo contribuir con código con éxito a un proyecto y hacerlo lo más fácil posible para usted y el mantenedor
del proyecto, y también cómo mantener un proyecto con éxito con la contribución de varios desarrolladores.
A diferencia de los sistemas de control de versiones centralizados (CVCS), la naturaleza distribuida de Git le permite
ser mucho más flexible en la forma en que los desarrolladores colaboran en los proyectos. En los sistemas
centralizados, cada desarrollador es un nodo que trabaja más o menos por igual con un concentrador central. En Git,
sin embargo, cada desarrollador es potencialmente tanto un nodo como un concentrador; es decir, cada desarrollador
puede aportar código a otros repositorios y mantener un repositorio público en el que otros puedan basar su trabajo y
al que puedan contribuir. Esto presenta una amplia gama de posibilidades de flujo de trabajo para su proyecto y/o su
equipo, por lo que cubriremos algunos paradigmas comunes que aprovechan esta flexibilidad. Repasaremos las
fortalezas y posibles debilidades de cada diseño; puede elegir uno solo para usar, o puede mezclar y combinar
características de cada uno.
En los sistemas centralizados, generalmente existe un único modelo de colaboración: el flujo de trabajo centralizado.
Un concentrador central, o repositorio, puede aceptar código y todos sincronizan su trabajo con él. Varios
desarrolladores son nodos (consumidores de ese centro) y se sincronizan con esa ubicación centralizada.
Esto significa que si dos desarrolladores clonan desde el concentrador y ambos realizan cambios, el primer
desarrollador que inserte sus cambios nuevamente puede hacerlo sin problemas. El segundo desarrollador debe fusionarse en el
126
Machine Translated by Google
el trabajo del primero antes de subir los cambios, para no sobrescribir los cambios del primer desarrollador.
Este concepto es tan cierto en Git como en Subversion (o cualquier CVCS), y este modelo funciona perfectamente bien
en Git.
Si ya se siente cómodo con un flujo de trabajo centralizado en su empresa o equipo, puede continuar usando fácilmente
ese flujo de trabajo con Git. Simplemente configure un único repositorio y proporcione a todos los miembros de su equipo
acceso push; Git no permitirá que los usuarios se sobrescriban entre sí.
Digamos que John y Jessica comienzan a trabajar al mismo tiempo. John termina su cambio y lo envía al servidor. Luego,
Jessica intenta impulsar sus cambios, pero el servidor los rechaza. Se le dice que está tratando de impulsar cambios que
no son de avance rápido y que no podrá hacerlo hasta que busque y fusione. Este flujo de trabajo es atractivo para
muchas personas porque es un paradigma con el que muchos están familiarizados y se sienten cómodos.
Esto tampoco se limita a equipos pequeños. Con el modelo de ramificación de Git, es posible que cientos de
desarrolladores trabajen con éxito en un solo proyecto a través de docenas de sucursales simultáneamente.
Debido a que Git le permite tener varios repositorios remotos, es posible tener un flujo de trabajo en el que cada
desarrollador tenga acceso de escritura a su propio repositorio público y acceso de lectura a los demás.
Este escenario a menudo incluye un repositorio canónico que representa el proyecto "oficial". Para contribuir a ese
proyecto, crea su propio clon público del proyecto y le envía sus cambios. Luego, puede enviar una solicitud al mantenedor
del proyecto principal para obtener sus cambios. Luego, el mantenedor puede agregar su repositorio como un control
remoto, probar sus cambios localmente, fusionarlos en su rama y enviarlos de vuelta a su repositorio. El proceso funciona
de la siguiente manera (consulte Flujo de trabajo del administrador de integración):
4. El colaborador envía un correo electrónico al mantenedor pidiéndole que realice los cambios.
127
Machine Translated by Google
Este es un flujo de trabajo muy común con herramientas basadas en hub como GitHub o GitLab, donde es fácil
bifurcar un proyecto e insertar sus cambios en su bifurcación para que todos los vean. Una de las principales ventajas
de este enfoque es que puede continuar trabajando y el mantenedor del repositorio principal puede obtener sus
cambios en cualquier momento. Los colaboradores no tienen que esperar a que el proyecto incorpore sus cambios:
cada parte puede trabajar a su propio ritmo.
Esta es una variante de un flujo de trabajo de múltiples repositorios. Generalmente es utilizado por grandes proyectos
con cientos de colaboradores; un ejemplo famoso es el kernel de Linux. Varios administradores de integración están
a cargo de ciertas partes del repositorio; se llaman tenientes. Todos los lugartenientes tienen un gerente de
integración conocido como el dictador benévolo. El dictador benévolo empuja desde su directorio a un repositorio de
referencia del que todos los colaboradores deben extraer. El proceso funciona así (ver Flujo de trabajo del dictador
benévolo):
1. Los desarrolladores regulares trabajan en su rama de tema y vuelven a basar su trabajo sobre el maestro. los
rama maestra es la del repositorio de referencia a la que empuja el dictador.
2. Los tenientes fusionan las ramas temáticas de los desarrolladores en su rama principal .
3. El dictador fusiona las ramas maestras de los tenientes en la rama maestra del dictador .
4. Finalmente, el dictador empuja esa rama maestra al repositorio de referencia para que los otros desarrolladores
puedan volver a basarse en ella.
Este tipo de flujo de trabajo no es común, pero puede ser útil en proyectos muy grandes o en entornos muy
jerárquicos. Permite que el líder del proyecto (el dictador) delegue gran parte del trabajo y recopile grandes
subconjuntos de código en múltiples puntos antes de integrarlos.
128
Machine Translated by Google
Martin Fowler ha elaborado una guía "Patrones para gestionar ramas de código fuente".
Esta guía cubre todos los flujos de trabajo comunes de Git y explica cómo y cuándo usarlos. También
ÿ hay una sección que compara frecuencias de integración altas y bajas.
https://martinfowler.com/articles/branching-patterns.html
Estos son algunos flujos de trabajo de uso común que son posibles con un sistema distribuido como Git, pero puede ver
que son posibles muchas variaciones para adaptarse a su flujo de trabajo particular del mundo real. Ahora que puede
(con suerte) determinar qué combinación de flujo de trabajo puede funcionar para usted, cubriremos algunos ejemplos
más específicos de cómo lograr los roles principales que conforman los diferentes flujos. En la siguiente sección,
aprenderá sobre algunos patrones comunes para contribuir a un proyecto.
Contribuir a un proyecto
La principal dificultad para describir cómo contribuir a un proyecto son las numerosas variaciones sobre cómo hacerlo.
Debido a que Git es muy flexible, las personas pueden trabajar juntas y lo hacen de muchas maneras, y es problemático
describir cómo debe contribuir: cada proyecto es un poco diferente. Algunas de las variables involucradas son el recuento
de colaboradores activos, el flujo de trabajo elegido, su acceso de confirmación y posiblemente el método de contribución
externa.
La primera variable es el recuento de colaboradores activos: ¿cuántos usuarios están contribuyendo activamente con
código para este proyecto y con qué frecuencia? En muchos casos, tendrá dos o tres desarrolladores con algunas
confirmaciones por día, o posiblemente menos para proyectos algo inactivos. Para empresas o proyectos más grandes,
la cantidad de desarrolladores podría ser de miles, con cientos o miles de confirmaciones cada día. Esto es importante
porque con más y más desarrolladores, te encuentras con más problemas para asegurarte de que tu código se aplique
limpiamente o se pueda fusionar fácilmente. Los cambios que envíe pueden volverse obsoletos o romperse gravemente
debido al trabajo que se fusionó mientras estaba trabajando o mientras sus cambios esperaban ser aprobados o
aplicados. ¿Cómo puede mantener su código constantemente actualizado y sus compromisos válidos?
La siguiente variable es el flujo de trabajo en uso para el proyecto. ¿Está centralizado y cada desarrollador tiene el mismo
acceso de escritura a la línea de código principal? ¿El proyecto tiene un mantenedor o administrador de integración que
verifica todos los parches? ¿Todos los parches son revisados y aprobados por pares? ¿Estás involucrado en ese
proceso? ¿Existe un sistema de lugartenientes y tiene que enviarles su trabajo primero?
La siguiente variable es su acceso de confirmación. El flujo de trabajo requerido para contribuir a un proyecto es muy
diferente si tiene acceso de escritura al proyecto que si no lo tiene. Si no tiene acceso de escritura, ¿cómo prefiere el
proyecto aceptar el trabajo contribuido? ¿Incluso tiene una política? ¿Cuánto trabajo estás contribuyendo a la vez? ¿Con
qué frecuencia contribuyes?
Todas estas preguntas pueden afectar la forma en que contribuye de manera efectiva a un proyecto y qué flujos de
trabajo son los preferidos o están disponibles para usted. Cubriremos aspectos de cada uno de estos en una serie de
casos de uso, pasando de lo simple a lo más complejo; debería poder construir los flujos de trabajo específicos que
necesita en la práctica a partir de estos ejemplos.
129
Machine Translated by Google
Directrices de compromiso
Antes de comenzar a ver los casos de uso específicos, aquí hay una nota rápida sobre los mensajes de confirmación.
Tener una buena guía para crear compromisos y cumplirla hace que trabajar con Git y colaborar con otros sea mucho más
fácil. El proyecto Git proporciona un documento que presenta una serie de buenos consejos para crear compromisos desde
los cuales enviar parches; puede leerlo en el código fuente de Git en el archivo Documentation/SubmittingPatches .
En primer lugar, sus envíos no deben contener errores de espacio en blanco. Git proporciona una manera fácil de verificar
esto: antes de comprometerse, ejecute git diff --check, que identifica posibles errores de espacios en blanco y los enumera
por usted.
Si ejecuta ese comando antes de comprometerse, puede saber si está a punto de cometer problemas de espacios en
blanco que pueden molestar a otros desarrolladores.
A continuación, intente hacer que cada confirmación sea un conjunto de cambios lógicamente separado. Si puede, intente
hacer que sus cambios sean digeribles: no programe un fin de semana completo en cinco problemas diferentes y luego
envíelos todos como una confirmación masiva el lunes. Incluso si no se compromete durante el fin de semana, use el área
de preparación el lunes para dividir su trabajo en al menos una confirmación por problema, con un mensaje útil por confirmación.
Si algunos de los cambios modifican el mismo archivo, intente usar git add --patch para organizar parcialmente los archivos
(cubierto en detalle en Puesta en escena interactiva). La instantánea del proyecto en la punta de la rama es idéntica ya sea
que realice una confirmación o cinco, siempre que todos los cambios se agreguen en algún momento, así que intente
facilitar las cosas a sus compañeros desarrolladores cuando tengan que revisar sus cambios.
Este enfoque también facilita extraer o revertir uno de los conjuntos de cambios si lo necesita más adelante.
Reescribir el historial describe una serie de trucos útiles de Git para reescribir el historial y organizar archivos de forma
interactiva: use estas herramientas para ayudar a crear un historial limpio y comprensible antes de enviar el trabajo a otra
persona.
Lo último a tener en cuenta es el mensaje de confirmación. Adquirir el hábito de crear mensajes de compromiso de calidad
hace que usar y colaborar con Git sea mucho más fácil. Como regla general, su
130
Machine Translated by Google
los mensajes deben comenzar con una sola línea que no tenga más de 50 caracteres y que describa el conjunto de
cambios de manera concisa, seguida de una línea en blanco, seguida de una explicación más detallada. El proyecto Git
requiere que la explicación más detallada incluya su motivación para el cambio y contraste su implementación con el
comportamiento anterior; esta es una buena guía a seguir. Escribe tu mensaje de confirmación en imperativo: "Corregir
error" y no "Corregir error" o "Corregir error". Aquí hay una plantilla que puede seguir, que hemos adaptado ligeramente
de una escrita originalmente por Tim Pope:
Si todos sus mensajes de confirmación siguen este modelo, las cosas serán mucho más fáciles para usted y los
desarrolladores con los que colabora. El proyecto Git tiene mensajes de confirmación bien formateados: intente ejecutar
git log --no-merges allí para ver cómo se ve un historial de confirmación de proyecto bien formateado.
En aras de la brevedad, muchos de los ejemplos de este libro no tienen mensajes de confirmación
ÿ bien formateados como este; en su lugar, simplemente usamos la opción -m para git commit.
La configuración más sencilla que probablemente encontrará es un proyecto privado con uno o dos desarrolladores más.
"Privado", en este contexto, significa código cerrado, no accesible para el mundo exterior. Usted y los demás
desarrolladores tienen acceso push al repositorio.
En este entorno, puede seguir un flujo de trabajo similar al que podría hacer al usar Subversion u otro sistema
centralizado. Todavía obtienes las ventajas de cosas como fuera de línea
131
Machine Translated by Google
confirmación y bifurcación y fusión mucho más simples, pero el flujo de trabajo puede ser muy similar; la principal
diferencia es que las fusiones ocurren en el lado del cliente en lugar de en el servidor en el momento de la
confirmación. Veamos cómo se vería cuando dos desarrolladores comiencen a trabajar juntos con un repositorio compartido.
El primer desarrollador, John, clona el repositorio, realiza un cambio y se compromete localmente. Los mensajes
de protocolo se han reemplazado con … en estos ejemplos para acortarlos un poco.
# John's Machine
$ git clone john@githost:simplegit.git
Clonación en 'simplegit'...
...
$ cd simplegit/ $
vim lib/simplegit.rb $ git
commit -am 'Eliminar valor predeterminado no
válido' [master 738ee87] Eliminar valor predeterminado
no válido 1 archivos cambiados, 1 inserciones (+), 1 eliminaciones (-)
# Jessica's Machine
$ git clone jessica@githost:simplegit.git
Clonación en 'simplegit'...
...
$ cd simplegit/ $
vim TODO $ git
commit -am 'Agregar tarea de
reinicio' [master fbff5bc] Agregar tarea
de reinicio 1 archivos cambiados, 1 inserciones (+), 0 eliminaciones (-)
# La máquina de
Jessica $ git push origin master
...
Para jessica@githost:simplegit.git
1edee6b..fbff5bc maestro -> maestro
La última línea del resultado anterior muestra un mensaje de retorno útil de la operación de inserción. El formato
básico es <oldref>..<newref> fromref ÿ toref, donde oldref significa la referencia anterior, newref significa la nueva
referencia, fromref es el nombre de la referencia local que se envía y toref es el nombre de la referencia remota
que se envía. actualizado. Verá un resultado similar a este a continuación en las discusiones, por lo que tener una
idea básica del significado ayudará a comprender los diversos estados de los repositorios.
Hay más detalles disponibles en la documentación de git-push.
Continuando con este ejemplo, poco después, John realiza algunos cambios, los envía a su repositorio local e
intenta enviarlos al mismo servidor:
132
Machine Translated by Google
# John's Machine
$ git push origin master
To john@githost:simplegit.git !
[rechazado] error maestromaestro
-> (no avance rápido): no se
pudo enviar algunas referencias a 'john@githost:simplegit.git'
En este caso, el impulso de John falla debido al impulso anterior de Jessica de sus cambios. Esto es especialmente
importante de entender si está acostumbrado a Subversion, porque notará que los dos desarrolladores no editaron
el mismo archivo. Aunque Subversion realiza automáticamente dicha fusión en el servidor si se editan diferentes
archivos, con Git, primero debe fusionar las confirmaciones localmente. En otras palabras, John primero debe
obtener los cambios anteriores de Jessica y fusionarlos en su repositorio local antes de que se le permita presionar.
Como primer paso, John obtiene el trabajo de Jessica (esto solo obtiene el trabajo anterior de Jessica, aún no lo
fusiona con el trabajo de John):
Ahora John puede fusionar el trabajo de Jessica que obtuvo en su propio trabajo local:
133
Machine Translated by Google
Siempre que la fusión local se realice sin problemas, el historial actualizado de John ahora se verá así:
En este punto, es posible que John quiera probar este nuevo código para asegurarse de que ninguno de los trabajos de Jessica
afecte a ninguno de los suyos y, siempre que todo parezca estar bien, finalmente puede impulsar el nuevo trabajo combinado hasta el final.
servidor:
134
Machine Translated by Google
Mientras tanto, Jessica creó una nueva rama de tema llamada problema 54 e hizo tres compromisos con esa
rama. Todavía no ha obtenido los cambios de John, por lo que su historial de confirmaciones se ve así:
De repente, Jessica se entera de que John ha enviado un nuevo trabajo al servidor y quiere echarle un vistazo,
para poder obtener todo el contenido nuevo del servidor que aún no tiene:
# Máquina de Jessica
$ git fetch origen
...
De jessica@githost:simplegit
fbff5bc..72bbc59 maestro -> origen/maestro
Eso reduce el trabajo que John ha impulsado mientras tanto. La historia de Jessica ahora se ve así:
Jessica cree que su rama temática está lista, pero quiere saber qué parte del trabajo buscado de John tiene que
fusionar con su trabajo para poder impulsar. Ella ejecuta git log para averiguar:
La sintaxis issue54..origin/master es un filtro de registro que le pide a Git que muestre solo las confirmaciones
que están en la última rama (en este caso origen/maestro) que no están en la primera rama (en este caso
135
Machine Translated by Google
Del resultado anterior, podemos ver que hay una única confirmación que John ha realizado y que Jessica no se ha
fusionado con su trabajo local. Si fusiona origin/master, esa es la única confirmación que modificará su trabajo local.
Ahora, Jessica puede fusionar su trabajo de tema en su rama maestra , fusionar el trabajo de John (origen/maestro)
en su rama maestra y luego regresar al servidor nuevamente.
Primero (después de haber comprometido todo el trabajo en su rama temática de número 54), Jessica vuelve a su
rama maestra en preparación para integrar todo este trabajo:
Jessica puede fusionar origin/master o issue54 primero; ambos están en sentido ascendente, por lo que el orden no
importa. La instantánea final debe ser idéntica sin importar el orden que elija; sólo la historia será diferente. Ella elige
fusionar la rama de problema 54 primero:
No se producen problemas; como puede ver, fue una simple combinación de avance rápido. Jessica ahora completa
el proceso de fusión local al fusionar el trabajo obtenido anteriormente de John que se encuentra en la rama de origen/
maestro :
136
Machine Translated by Google
Ahora se puede acceder al origen/maestro desde la rama maestra de Jessica , por lo que debería poder empujar
con éxito (suponiendo que John no haya empujado aún más cambios mientras tanto):
Cada desarrollador se comprometió varias veces y fusionó el trabajo de los demás con éxito.
Figura 63. Historial de Jessica después de devolver todos los cambios al servidor
Ese es uno de los flujos de trabajo más simples. Trabajas durante un tiempo (generalmente en una rama temática)
y fusionas ese trabajo en tu rama principal cuando está listo para integrarse. Cuando desee compartir ese trabajo,
obtenga y fusione su maestro desde origen/maestro si ha cambiado, y finalmente empuje a la rama maestra en el
servidor. La secuencia general es algo como esto:
137
Machine Translated by Google
Figura 64. Secuencia general de eventos para un flujo de trabajo Git simple de múltiples desarrolladores
En el siguiente escenario, observará los roles de colaborador en un grupo privado más grande. Aprenderá
a trabajar en un entorno en el que grupos pequeños colaboran en funciones, después de lo cual otra parte
integra esas contribuciones basadas en el equipo.
138
Machine Translated by Google
Digamos que John y Jessica están trabajando juntos en una función (llamémosla "función A"), mientras que Jessica
y un tercer desarrollador, Josie, están trabajando en una segunda (por ejemplo, "función B"). En este caso, la
empresa está utilizando un tipo de flujo de trabajo de administrador de integración donde el trabajo de los grupos
individuales está integrado solo por ciertos ingenieros, y la rama principal del repositorio principal puede ser
actualizada solo por esos ingenieros . En este escenario, todo el trabajo se realiza en sucursales basadas en
equipos y los integradores lo reúnen más tarde.
Sigamos el flujo de trabajo de Jessica mientras trabaja en sus dos características, colaborando en paralelo
con dos desarrolladores diferentes en este entorno. Suponiendo que ya clonó su repositorio, decide
trabajar primero en la función A. Ella crea una nueva rama para la característica y trabaja en
allí:
# Jessica's Machine $
git checkout -b featureA Cambiado
a una nueva rama 'featureA' $ vim lib/
simplegit.rb $ git commit -am 'Agregar límite
a la función de registro' [featureA 3300904] Agregar límite
a la función de registro 1 archivos cambiados, 1
inserciones (+), 1 eliminaciones (-)
En este punto, necesita compartir su trabajo con John, por lo que envía sus confirmaciones de rama de
característicaA al servidor. Jessica no tiene acceso de inserción a la rama maestra , solo los integradores
lo tienen, por lo que tiene que empujar a otra rama para colaborar con John:
Jessica le envía un correo electrónico a John para decirle que ha enviado un trabajo a una rama llamada
funciónA y que él puede verlo ahora. Mientras espera los comentarios de John, Jessica decide comenzar a
trabajar en la función B con Josie. Para comenzar, inicia una nueva rama de función, basándose en la rama
maestra del servidor :
# La máquina de Jessica
$ git fetch origin $ git
checkout -b featureB origin/master
Cambiado a una nueva rama 'featureB'
139
Machine Translated by Google
$ vim lib/simplegit.rb $
git commit -am 'Hacer que la función ls-tree sea
recursiva' [featureB e5b0fdc] Hacer que la función ls-tree
sea recursiva 1 archivos cambiados, 1 inserciones (+), 1
eliminaciones (-) $ vim lib/simplegit .rb $ git commit -am
'Add ls-files' [featureB 8512791] Add ls-files 1 archivos
cambiados, 5 inserciones (+), 0 eliminaciones (-)
Está lista para impulsar su trabajo, pero recibe un correo electrónico de Josie que le informa que una rama con
un trabajo inicial de "característica B" ya se envió al servidor como la rama de FeatureBee . Jessica necesita
fusionar esos cambios con los suyos propios antes de poder enviar su trabajo al servidor. Jessica primero
obtiene los cambios de Josie con git fetch:
Suponiendo que Jessica todavía está en su rama FeatureB desprotegida , ahora puede fusionar el trabajo de
Josie en esa rama con git merge:
140
Machine Translated by Google
En este punto, Jessica quiere enviar todo este trabajo combinado de "función B" de vuelta al servidor, pero no quiere
simplemente enviar su propia rama de función B. Más bien, dado que Josie ya ha iniciado una rama de FeatureBee
upstream , Jessica quiere empujar a esa rama, lo que hace con:
Esto se llama refspec. Consulte The Refspec para obtener una discusión más detallada sobre las refspecs de Git y las
diferentes cosas que puede hacer con ellas. Observe también la bandera -u ; esto es la abreviatura de --set-upstream,
que configura las ramas para empujar y tirar más fácilmente más adelante.
De repente, Jessica recibe un correo electrónico de John, quien le dice que ha enviado algunos cambios a la rama de
funciónA en la que están colaborando, y le pide a Jessica que los revise. Nuevamente, Jessica ejecuta un simple git
fetch para obtener todo el contenido nuevo del servidor, incluido (por supuesto) el último trabajo de John:
Jessica puede mostrar el registro del nuevo trabajo de John comparando el contenido de la rama FeatureA recién
recuperada con su copia local de la misma rama:
Si a Jessica le gusta lo que ve, puede fusionar el nuevo trabajo de John en su rama local FeatureA con:
Finalmente, es posible que Jessica desee realizar un par de cambios menores en todo ese contenido fusionado, por lo
que es libre de realizar esos cambios, enviarlos a su rama local de funciónA y enviar el resultado final al servidor:
141
Machine Translated by Google
En algún momento, Jessica, Josie y John informan a los integradores que las sucursales featureA y featureBee en el
servidor están listas para integrarse en la línea principal. Después de que los integradores fusionen estas ramas en la
línea principal, una búsqueda traerá la nueva confirmación de fusión, haciendo que el historial se vea así:
142
Machine Translated by Google
Figura 67. La historia de Jessica después de fusionar sus dos ramas temáticas
Muchos grupos cambian a Git debido a esta capacidad de tener varios equipos trabajando en paralelo, fusionando
las diferentes líneas de trabajo al final del proceso. La capacidad de los subgrupos más pequeños de un equipo
para colaborar a través de sucursales remotas sin tener que involucrar o obstaculizar necesariamente a todo el
equipo es un gran beneficio de Git. La secuencia para el flujo de trabajo que vio aquí es algo como esto:
143
Machine Translated by Google
Contribuir a proyectos públicos es un poco diferente. Debido a que no tiene los permisos para actualizar
directamente las ramas en el proyecto, debe hacer llegar el trabajo a los mantenedores de alguna otra manera.
Este primer ejemplo describe la contribución a través de bifurcaciones en hosts de Git que admiten bifurcaciones
fáciles. Muchos sitios de hospedaje admiten esto (incluidos GitHub, BitBucket, repo.or.cz y otros), y muchos
mantenedores de proyectos esperan este estilo de contribución. La siguiente sección se ocupa de los proyectos
que prefieren aceptar parches aportados por correo electrónico.
Primero, probablemente querrá clonar el repositorio principal, crear una rama de tema para el parche o parche
144
Machine Translated by Google
series con las que planea contribuir y haga su trabajo allí. La secuencia se ve básicamente así:
Es posible que desee usar rebase -i para reducir su trabajo a una sola confirmación, o reorganizar
ÿ el trabajo en las confirmaciones para que el parche sea más fácil de revisar para el mantenedor;
consulte Reescritura del historial para obtener más información sobre la reorganización interactiva.
Cuando el trabajo de su rama esté terminado y esté listo para devolverlo a los mantenedores, vaya a la página del
proyecto original y haga clic en el botón "Bifurcación", creando su propia bifurcación del proyecto con capacidad de escritura.
Luego debe agregar esta URL del repositorio como un nuevo control remoto de su repositorio local; en este ejemplo,
llamémoslo myfork:
A continuación, debe enviar su nuevo trabajo a este repositorio. Es más fácil enviar la rama de tema en la que está
trabajando a su repositorio bifurcado, en lugar de fusionar ese trabajo en su rama principal y enviarlo. La razón es que
si su trabajo no se acepta o se selecciona, no tiene que rebobinar su rama maestra (la operación de selección de Git se
trata con más detalle en Flujos de trabajo de cambio de base y selección). Si los mantenedores fusionan, modifican la
base o seleccionan su trabajo, eventualmente lo recuperará extrayéndolo de su repositorio de todos modos.
Una vez que su trabajo ha sido enviado a su bifurcación del repositorio, debe notificar a los mantenedores del proyecto
original que tiene trabajo que le gustaría que fusionaran. Esto a menudo se denomina solicitud de extracción y, por lo
general, genera dicha solicitud a través del sitio web (GitHub tiene su propio mecanismo de "Solicitud de extracción"
que revisaremos en GitHub ) o puede ejecutar el comando git request-pull y enviar un correo electrónico la salida
posterior al mantenedor del proyecto manualmente.
El comando git request-pull toma la rama base en la que desea que se extraiga su rama de tema y la URL del repositorio
de Git de la que desea que se extraigan, y produce un resumen de todos los cambios que solicita que se extraigan. Por
ejemplo, si Jessica quiere enviar a John una solicitud de extracción y ha realizado dos confirmaciones en la rama de
tema que acaba de enviar, puede ejecutar esto:
145
Machine Translated by Google
git://githost/simplegit.git característicaA
lib/simplegit.rb | 1 10 ++++++++++-
archivos cambiados, 9 inserciones (+), 1 eliminaciones (-)
Esta salida se puede enviar al mantenedor: les dice de dónde se ramificó el trabajo, resume las
confirmaciones e identifica de dónde se extraerá el nuevo trabajo.
En un proyecto del que no eres el mantenedor, por lo general es más fácil tener una rama como maestro
que siempre realice un seguimiento del origen/maestro y hacer tu trabajo en ramas temáticas que puedes
descartar fácilmente si son rechazadas. Tener temas de trabajo aislados en ramas de temas también facilita
la reorganización de su trabajo si la punta del repositorio principal se ha movido mientras tanto y sus
compromisos ya no se aplican correctamente. Por ejemplo, si deseas enviar un segundo tema de trabajo al
proyecto, no continúes trabajando en la rama del tema que acabas de subir; empieza de nuevo desde la
rama maestra del repositorio principal:
$ git commit $
git push myfork featureB $ git
request-pull origin/master myfork ... solicitud
generada por correo electrónico para el mantenedor ... $ git fetch
origin
Ahora, cada uno de sus temas está contenido dentro de un silo, similar a una cola de parches, que puede
reescribir, reorganizar y modificar sin que los temas interfieran o dependan entre sí, así:
146
Machine Translated by Google
Digamos que el mantenedor del proyecto ha extraído un montón de otros parches y ha probado su primera
rama, pero ya no se fusiona limpiamente. En este caso, puede intentar volver a establecer la base de esa rama
sobre el origen/maestro, resolver los conflictos para el mantenedor y luego volver a enviar sus cambios:
Esto reescribe su historial para que ahora se vea como el historial de confirmación después del trabajo de la característica A.
Debido a que modificó la base de la rama, debe especificar -f en su comando push para poder reemplazar la
rama featureA en el servidor con una confirmación que no es un descendiente de ella. Una alternativa sería
enviar este nuevo trabajo a una rama diferente en el servidor (quizás llamada featureAv2).
Veamos otro escenario posible: el mantenedor ha analizado el trabajo en su segunda rama y le gusta el
concepto, pero le gustaría que cambiara un detalle de implementación. También aprovechará esta oportunidad
para mover el trabajo para que se base en la rama maestra actual del proyecto. Comienza una nueva rama
basada en la rama de origen/maestra actual , aplasta los cambios de la característica B allí, resuelve cualquier
conflicto, realiza el cambio de implementación y luego lo empuja como una nueva rama:
147
Machine Translated by Google
La opción --squash toma todo el trabajo en la rama fusionada y lo comprime en un conjunto de cambios que produce el
estado del repositorio como si hubiera ocurrido una fusión real, sin realizar una confirmación de fusión. Esto significa que su
confirmación futura tendrá solo un padre y le permitirá introducir todos los cambios desde otra rama y luego realizar más
cambios antes de registrar la nueva confirmación.
Además, la opción --no-commit puede ser útil para retrasar la confirmación de fusión en el caso del proceso de fusión
predeterminado.
En este punto, puede notificar al mantenedor que realizó los cambios solicitados y que pueden encontrar esos cambios en
su rama featureBv2 .
Muchos proyectos tienen procedimientos establecidos para aceptar parches; deberá verificar las reglas específicas para
cada proyecto, ya que serán diferentes. Dado que hay varios proyectos más antiguos y más grandes que aceptan parches
a través de una lista de correo de desarrolladores, veremos un ejemplo de eso ahora.
El flujo de trabajo es similar al caso de uso anterior: crea ramas de temas para cada serie de parches en la que trabaja. La
diferencia es cómo los envías al proyecto. En lugar de bifurcar el proyecto e impulsar su propia versión escribible, genera
versiones de correo electrónico de cada serie de confirmación y las envía por correo electrónico a la lista de correo del
desarrollador:
Ahora tiene dos confirmaciones que desea enviar a la lista de correo. Utiliza git format-patch para generar los archivos con
formato mbox que puede enviar por correo electrónico a la lista; convierte cada confirmación en un
148
Machine Translated by Google
mensaje de correo electrónico con la primera línea del mensaje de confirmación como asunto y el resto del mensaje más el parche
que introduce la confirmación como cuerpo. Lo bueno de esto es que aplicar un parche desde un correo electrónico generado con
format-patch conserva toda la información de confirmación correctamente.
El comando format-patch imprime los nombres de los archivos de parche que crea. El interruptor -M le dice a Git que busque cambios
de nombre. Los archivos terminan luciendo así:
---
lib/simplegit.rb | 1 2 +-
archivos cambiados, 1 inserciones (+), 1 eliminaciones (-)
2.1.0
También puede editar estos archivos de parche para agregar más información para la lista de correo electrónico que no desea que
aparezca en el mensaje de confirmación. Si agrega texto entre la línea --- y el comienzo del parche (la línea diff --git ), los
desarrolladores pueden leerlo, pero el proceso de parcheo ignora ese contenido.
Para enviar esto por correo electrónico a una lista de correo, puede pegar el archivo en su programa de correo electrónico o enviarlo
a través de un programa de línea de comandos. Pegar el texto a menudo causa problemas de formato, especialmente con clientes
"más inteligentes" que no conservan las líneas nuevas y otros espacios en blanco de manera adecuada. Afortunadamente, Git
proporciona una herramienta para ayudarlo a enviar parches formateados correctamente a través de IMAP, lo que puede ser más
fácil para usted. Demostraremos cómo enviar un parche a través de Gmail, que resulta ser el agente de correo electrónico que mejor conocemos;
149
Machine Translated by Google
puede leer instrucciones detalladas para varios programas de correo al final del archivo Documentation/SubmittingPatches
mencionado anteriormente en el código fuente de Git.
Primero, debe configurar la sección imap en su archivo ~/.gitconfig . Puede establecer cada valor por separado con una serie
de comandos de configuración de git , o puede agregarlos manualmente, pero al final su archivo de configuración debería
verse así:
[imap]
carpeta = "[Gmail]/Borradores"
host = imaps://imap.gmail.com
usuario = usuario@gmail.com
contraseña = YX]8g76G_2^sFbd
puerto = 993 sslverify = falso
Si su servidor IMAP no usa SSL, las dos últimas líneas probablemente no sean necesarias y el valor de host será imap:// en
lugar de imaps://. Cuando esté configurado, puede usar git imap-send para colocar la serie de parches en la carpeta Borradores
del servidor IMAP especificado:
En este punto, debería poder ir a su carpeta Borradores, cambiar el campo Para a la lista de correo a la que está enviando el
parche, posiblemente CC al mantenedor o persona responsable de esa sección, y enviarlo.
También puede enviar los parches a través de un servidor SMTP. Como antes, puede configurar cada valor por separado con
una serie de comandos de configuración de git , o puede agregarlos manualmente en la sección de envío de correo electrónico
en su archivo ~/.gitconfig :
[enviar
correo electrónico]
smtpencryption = tls smtpserver =
smtp.gmail.com smtpuser =
usuario@gmail.com smtpserverport = 587
Una vez hecho esto, puede usar git send-email para enviar sus parches:
150
Machine Translated by Google
Luego, Git escupe un montón de información de registro que se parece a esto para cada parche que está enviando:
resultado: correcto
ÿ Para obtener ayuda sobre cómo configurar su sistema y correo electrónico, más consejos y trucos, y una
sandbox para enviar un parche de prueba por correo electrónico, vaya a git-send-email.io.
Resumen
En esta sección, cubrimos múltiples flujos de trabajo y hablamos sobre las diferencias entre trabajar como parte de un pequeño equipo en
proyectos de código cerrado y contribuir a un gran proyecto público. Sabe verificar si hay errores de espacio en blanco antes de confirmar, y
puede escribir un excelente mensaje de confirmación. Aprendió cómo formatear parches y enviarlos por correo electrónico a una lista de correo
de desarrolladores. El manejo de las fusiones también se cubrió en el contexto de los diferentes flujos de trabajo. Ahora está bien preparado
A continuación, verás cómo trabajar la otra cara de la moneda: mantener un proyecto Git. Aprenderá a ser un dictador benévolo o un
administrador de integración.
Mantenimiento de un proyecto
Además de saber cómo contribuir de manera efectiva a un proyecto, es probable que necesite saber cómo mantener uno. Esto puede consistir
en aceptar y aplicar parches generados a través de format-patch y enviados por correo electrónico, o integrar cambios en sucursales remotas
151
Machine Translated by Google
a tu proyecto. Ya sea que mantenga un repositorio canónico o quiera ayudar verificando o aprobando
parches, necesita saber cómo aceptar el trabajo de la manera más clara para otros colaboradores y
sostenible para usted a largo plazo.
Cuando está pensando en integrar un nuevo trabajo, generalmente es una buena idea probarlo en una
rama temática , una rama temporal creada específicamente para probar ese nuevo trabajo. De esta manera,
es fácil modificar un parche individualmente y dejarlo si no funciona hasta que tenga tiempo de volver a él.
Si crea un nombre de rama simple basado en el tema del trabajo que va a probar, como ruby_client o algo
descriptivo similar, puede recordarlo fácilmente si tiene que abandonarlo por un tiempo y regresar más
tarde. El mantenedor del proyecto Git tiende a nombrar estas ramas también, como sc/ruby_client, donde
sc es la abreviatura de la persona que contribuyó con el trabajo. Como recordará, puede crear la rama
basada en su rama maestra de esta manera:
Ahora está listo para agregar el trabajo contribuido que recibió en esta rama temática y determinar si desea
fusionarlo con sus ramas a largo plazo.
Si recibe un parche por correo electrónico que necesita integrar en su proyecto, debe aplicar el parche en
su rama temática para evaluarlo. Hay dos formas de aplicar un parche enviado por correo electrónico: con
git apply o con git am.
Si recibió el parche de alguien que lo generó con git diff o alguna variación del comando Unix diff (que no
se recomienda; consulte la siguiente sección), puede aplicarlo con el comando git apply . Suponiendo que
guardó el parche en /tmp/patch-ruby-client.patch, puede aplicar el parche de esta manera:
Esto modifica los archivos en su directorio de trabajo. Es casi idéntico a ejecutar un comando patch -p1
para aplicar el parche, aunque es más paranoico y acepta menos coincidencias aproximadas que patch.
También maneja la adición, eliminación y cambio de nombre de archivos si se describen en el formato git
diff , que parche no funcionará. Finalmente, git apply es un modelo de "aplicar todo o cancelar todo" en el
que se aplica todo o nada, mientras que patch puede aplicar parches parcialmente, dejando su directorio
de trabajo en un estado extraño. git apply es en general mucho más conservador que patch. No creará una
confirmación para usted: después de ejecutarlo, debe organizar y confirmar los cambios introducidos manualmente.
152
Machine Translated by Google
También puede usar git apply para ver si un parche se aplica limpiamente antes de intentar aplicarlo realmente; puede ejecutar git
apply -- verifique con el parche:
Si no hay salida, entonces el parche debería aplicarse limpiamente. Este comando también sale con un estado distinto de cero si
falla la verificación, por lo que puede usarlo en secuencias de comandos si lo desea.
Si el colaborador es un usuario de Git y fue lo suficientemente bueno como para usar el comando format-patch para generar su
parche, entonces su trabajo es más fácil porque el parche contiene información del autor y un mensaje de confirmación para usted.
Si puede, anime a sus colaboradores a usar format-patch en lugar de diff para generar parches para usted. Solo debería tener que
usar git apply para parches heredados y cosas por el estilo.
Para aplicar un parche generado por format-patch, usa git am (el comando se llama am porque se usa para "aplicar una serie de
parches desde un buzón"). Técnicamente, git am está diseñado para leer un archivo mbox, que es un formato simple de texto sin
formato para almacenar uno o más mensajes de correo electrónico en un archivo de texto. Se ve algo como esto:
Este es el comienzo de la salida del comando git format-patch que viste en la sección anterior; también representa un formato de
correo electrónico mbox válido. Si alguien le envió el parche por correo electrónico correctamente usando git send-email y lo
descarga en un formato mbox, entonces puede apuntar git am a ese archivo mbox y comenzará a aplicar todos los parches que
vea. Si ejecuta un cliente de correo que puede guardar varios correos electrónicos en formato mbox, puede guardar toda la serie
de parches en un archivo y luego usar git am para aplicarlos uno a la vez.
Sin embargo, si alguien subió un archivo de parche generado a través de git format-patch a un sistema de emisión de boletos o algo
similar, puede guardar el archivo localmente y luego pasar ese archivo guardado en su disco a git am para aplicarlo:
Puede ver que se aplicó limpiamente y creó automáticamente la nueva confirmación para usted. La información del autor se toma
de los encabezados Desde y Fecha del correo electrónico , y el mensaje de confirmación es
153
Machine Translated by Google
tomado del Asunto y el cuerpo (antes del parche) del correo electrónico. Por ejemplo, si este parche se aplicó desde el ejemplo
de mbox anterior, la confirmación generada se vería así:
La información de Confirmación indica la persona que aplicó el parche y la hora en que se aplicó. La información del autor es
la persona que creó originalmente el parche y cuándo se creó originalmente.
Pero es posible que el parche no se aplique limpiamente. Tal vez su rama principal se haya alejado demasiado de la rama a
partir de la cual se creó el parche, o el parche depende de otro parche que aún no ha aplicado. En ese caso, el proceso de git
am fallará y te preguntará qué quieres hacer:
Este comando coloca marcadores de conflicto en cualquier archivo con el que tenga problemas, de forma similar a una
operación de fusión o reorganización en conflicto. Resuelve este problema de la misma manera: edite el archivo para resolver
el conflicto, prepare el nuevo archivo y luego ejecute git am --resolved para continuar con el siguiente parche:
$ (arreglar el archivo)
$ git add ticgit.gemspec $ git
am --resolved Aplicación: vea
si esto ayuda a la gema
Si desea que Git intente resolver el conflicto de manera un poco más inteligente, puede pasarle una opción -3 , lo que hace
que Git intente una combinación de tres vías. Esta opción no está activada de forma predeterminada porque no funciona si la
confirmación del parche en la que se basa no está en su repositorio. Si tiene ese compromiso, si el parche se basó en un
compromiso público, entonces la opción -3 generalmente es mucho más inteligente para aplicar un parche en conflicto:
154
Machine Translated by Google
En este caso, sin la opción -3 , el parche se habría considerado como un conflicto. Dado que se utilizó la opción
-3 , el parche se aplicó limpiamente.
Si está aplicando varios parches desde un mbox, también puede ejecutar el comando am en modo interactivo,
que se detiene en cada parche que encuentra y le pregunta si desea aplicarlo:
$ git am -3 -i mbox
El cuerpo de confirmación es:
--------------------------
Esto es bueno si tiene varios parches guardados, porque puede ver el parche primero si no recuerda cuál es, o
no aplicar el parche si ya lo ha hecho.
Cuando todos los parches para su tema se aplican y confirman en su rama, puede elegir si desea integrarlos en
una rama de mayor duración y cómo hacerlo.
Si su contribución provino de un usuario de Git que configuró su propio repositorio, introdujo una serie de cambios
en él y luego le envió la URL al repositorio y el nombre de la rama remota en la que se encuentran los cambios,
puede agregarlos como un remoto y hacer fusiones localmente.
Por ejemplo, si Jessica le envía un correo electrónico diciendo que tiene una gran función nueva en la rama de
cliente de ruby de su repositorio, puede probarla agregando el control remoto y revisando esa rama localmente:
Si ella te vuelve a enviar un correo electrónico más tarde con otra sucursal que contenga otra gran característica,
puedes buscar y pagar directamente porque ya tienes la configuración remota.
Esto es más útil si está trabajando con una persona constantemente. Si alguien solo tiene un parche para
contribuir de vez en cuando, entonces aceptarlo por correo electrónico puede llevar menos tiempo que requerir
que todos ejecuten su propio servidor y tener que agregar y eliminar controles remotos continuamente para
obtener algunos parches. También es poco probable que desee tener cientos de controles remotos, cada uno para alguien q
155
Machine Translated by Google
contribuye sólo un parche o dos. Sin embargo, los scripts y los servicios alojados pueden hacer que esto sea más fácil;
depende en gran medida de cómo se desarrolle y cómo se desarrollen sus colaboradores.
La otra ventaja de este enfoque es que también obtienes el historial de las confirmaciones. Aunque puede tener
problemas legítimos de fusión, sabe en qué parte de su historial se basa su trabajo; una combinación de tres vías
adecuada es la predeterminada en lugar de tener que proporcionar un -3 y esperar que el parche se haya generado a
partir de una confirmación pública a la que tiene acceso.
Si no está trabajando con una persona de manera constante, pero aún desea obtener información de ella de esta manera,
puede proporcionar la URL del repositorio remoto al comando git pull . Esto realiza una extracción única y no guarda la
URL como una referencia remota:
Suele ser útil obtener una revisión de todas las confirmaciones que están en esta rama pero que no están en tu rama
maestra . Puede excluir confirmaciones en la rama principal agregando la opción --not antes del nombre de la rama. Esto
hace lo mismo que el formato master..contrib que usamos anteriormente. Por ejemplo, si su colaborador le envía dos
parches y crea una rama llamada contrib y aplica esos parches allí, puede ejecutar esto:
cometer 7482e0d16d04bea79d0dba8988cc78df655f16a0
Autor: Scott Chacon <schacon@gmail.com>
Fecha: lun 22 oct 19:38:36 2008 -0700
Para ver qué cambios introduce cada confirmación, recuerda que puedes pasar la opción -p a git log y agregará la
diferencia introducida en cada confirmación.
Para ver una diferencia completa de lo que sucedería si fusionara esta rama temática con otra rama, es posible que deba
usar un truco extraño para obtener los resultados correctos. Usted puede pensar en ejecutar esto:
156
Machine Translated by Google
Este comando le da una diferencia, pero puede ser engañoso. Si su rama maestra ha avanzado desde que creó la
rama de tema a partir de ella, entonces obtendrá resultados aparentemente extraños. Esto sucede porque Git
compara directamente las instantáneas de la última confirmación de la rama de tema en la que se encuentra y la
instantánea de la última confirmación de la rama principal . Por ejemplo, si agregó una línea en un archivo en la
rama maestra , una comparación directa de las instantáneas parecerá que la rama del tema eliminará esa línea.
Si el maestro es un antepasado directo de su rama temática, esto no es un problema; pero si las dos historias han
divergido, la diferencia parecerá que está agregando todas las cosas nuevas en su rama de tema y eliminando todo
lo que es único en la rama principal .
Lo que realmente desea ver son los cambios agregados a la rama del tema: el trabajo que presentará si fusiona
esta rama con la principal. Lo hace haciendo que Git compare la última confirmación en su rama de tema con el
primer ancestro común que tiene con la rama maestra .
Técnicamente, puede hacerlo determinando explícitamente el ancestro común y luego ejecutando su diferencia en
él:
o, más concisamente:
Sin embargo, ninguno de ellos es particularmente conveniente, por lo que Git proporciona otra abreviatura para
hacer lo mismo: la sintaxis de triple punto. En el contexto del comando git diff , puedes poner tres puntos después
de otra rama para hacer una diferencia entre la última confirmación de la rama en la que estás y su ancestro común
con otra rama:
Este comando le muestra solo el trabajo que ha introducido su rama de tema actual desde su ancestro común con
el maestro. Esa es una sintaxis muy útil para recordar.
Cuando todo el trabajo en su rama temática esté listo para integrarse en una rama más principal, la pregunta es
cómo hacerlo. Además, ¿qué flujo de trabajo general desea utilizar para mantener su proyecto? Tiene varias
opciones, por lo que cubriremos algunas de ellas.
157
Machine Translated by Google
Un flujo de trabajo básico es simplemente fusionar todo ese trabajo directamente en su rama principal . En este escenario,
tiene una rama maestra que contiene código básicamente estable. Cuando tiene trabajo en una rama de tema que cree que
ha completado, o trabajo que alguien más ha contribuido y ha verificado, lo fusiona con su rama maestra, elimina esa rama
de tema recién fusionada y repite.
Por ejemplo, si tenemos un repositorio con trabajo en dos ramas llamadas ruby_client y php_client que se parece a History
con varias ramas de temas, y fusionamos ruby_client seguido de php_client, su historial terminará luciendo como After a topic
branch merge.
Ese es probablemente el flujo de trabajo más simple, pero posiblemente puede ser problemático si se trata de proyectos más
grandes o más estables en los que desea tener mucho cuidado con lo que presenta.
Si tiene un proyecto más importante, es posible que desee utilizar un ciclo de combinación de dos fases. En este escenario,
tiene dos ramas de ejecución prolongada, maestra y de desarrollo, en las que determina que la maestra se actualiza solo
cuando se corta una versión muy estable y todo el código nuevo se integra en la rama de desarrollo . Regularmente empuja
estas dos ramas al repositorio público. Cada vez que tiene una nueva rama de tema para fusionar (antes de fusionar una
rama de tema), la fusiona en desarrollar (después de fusionar una rama de tema); luego, cuando etiqueta un lanzamiento,
avanza rápidamente el maestro a donde sea que esté ahora
158
Machine Translated by Google
De esta manera, cuando las personas clonen el repositorio de su proyecto, pueden consultar master para compilar la última versión estable y mantenerse al
día fácilmente, o pueden consultar el desarrollo, que es el contenido más avanzado. También puede extender este concepto al tener una rama de integración
donde
159
Machine Translated by Google
todo el trabajo se fusiona. Luego, cuando el código base en esa rama es estable y pasa las pruebas, lo fusiona en una
rama de desarrollo ; y cuando eso ha demostrado ser estable por un tiempo, avanza rápidamente su rama principal .
El proyecto Git tiene cuatro ramas de ejecución prolongada: master, next y seen (anteriormente 'pu', actualizaciones
propuestas) para trabajos nuevos y maint para backports de mantenimiento. Cuando los contribuyentes introducen un
nuevo trabajo, se recopila en ramas temáticas en el repositorio del mantenedor de una manera similar a la que hemos
descrito (consulte Administrar una serie compleja de ramas temáticas aportadas en paralelo). En este punto, los temas se
evalúan para determinar si son seguros y están listos para el consumo o si necesitan más trabajo. Si son seguros, se
fusionan con el siguiente y esa rama se empuja hacia arriba para que todos puedan probar los temas integrados juntos.
Figura 77. Gestión de una serie compleja de ramas temáticas aportadas en paralelo
Si los temas aún necesitan trabajo, se fusionan en visto en su lugar. Cuando se determina que son totalmente estables,
los temas se vuelven a fusionar en maestro. Las ramas siguientes y vistas se reconstruyen a partir del maestro. Esto
significa que el maestro casi siempre avanza, el siguiente se vuelve a basar ocasionalmente y lo visto se vuelve a basar
aún más a menudo:
160
Machine Translated by Google
Figura 78. Fusión de ramas de temas aportados en ramas de integración a largo plazo
Cuando una rama de tema finalmente se fusiona con la principal, se elimina del repositorio. El proyecto Git también
tiene una rama de mantenimiento que se bifurca de la última versión para proporcionar parches respaldados en caso
de que se requiera una versión de mantenimiento. Por lo tanto, cuando clonas el repositorio de Git, tienes cuatro
ramas que puedes consultar para evaluar el proyecto en diferentes etapas de desarrollo, dependiendo de qué tan
vanguardista quieras ser o cómo quieras contribuir; y el mantenedor tiene un flujo de trabajo estructurado para
ayudarlos a examinar nuevas contribuciones. El flujo de trabajo del proyecto Git está especializado. Para comprender
esto claramente, puede consultar la guía del administrador de Git.
Otros mantenedores prefieren cambiar la base o seleccionar el trabajo contribuido sobre su rama maestra , en lugar
de fusionarlo, para mantener un historial mayormente lineal. Cuando tiene trabajo en una rama de tema y ha
determinado que desea integrarla, se mueve a esa rama y ejecuta el comando rebase para reconstruir los cambios
sobre su rama maestra actual (o de desarrollo, etc.). Si eso funciona bien, puede avanzar rápidamente su rama
maestra y terminará con un historial de proyecto lineal.
La otra forma de mover el trabajo introducido de una rama a otra es seleccionarlo. Una selección de cereza en Git es
como una nueva base para una sola confirmación. Toma el parche que se introdujo en una confirmación e intenta
volver a aplicarlo en la rama en la que se encuentra actualmente. Esto es útil si tiene varios compromisos en una rama
de tema y desea integrar solo uno de ellos, o si solo tiene un compromiso en una rama de tema y prefiere seleccionarlo
en lugar de ejecutar rebase. Por ejemplo, suponga que tiene un proyecto que se ve así:
161
Machine Translated by Google
Esto extrae el mismo cambio introducido en e43a6, pero obtiene un nuevo valor SHA-1 de confirmación,
porque la fecha aplicada es diferente. Ahora su historial se ve así:
Figura 80. Historial después de elegir una confirmación en una rama de tema
Ahora puede eliminar su rama de tema y eliminar las confirmaciones que no deseaba incluir.
162
Machine Translated by Google
regañar
Si está realizando muchas fusiones y cambios de base, o si está manteniendo una rama de tema de larga duración, Git tiene
una característica llamada "rerere" que puede ayudar.
Rerere significa "reutilizar resolución grabada", es una forma de atajar la resolución manual de conflictos. Cuando rerere está
habilitado, Git mantendrá un conjunto de imágenes previas y posteriores a las fusiones exitosas, y si nota que hay un conflicto
que se parece exactamente a uno que ya solucionó, solo usará la solución de la última vez. , sin molestarte con eso.
Esta característica viene en dos partes: un ajuste de configuración y un comando. La opción de configuración es rerere.enabled,
y es lo suficientemente útil como para ponerla en su configuración global:
Ahora, cada vez que realice una combinación que resuelva conflictos, la resolución se registrará en el caché en caso de que
la necesite en el futuro.
Si lo necesita, puede interactuar con el caché rerere usando el comando git rerere . Cuando se invoca solo, Git verifica su
base de datos de resoluciones e intenta encontrar una coincidencia con cualquier conflicto de combinación actual y resolverlo
(aunque esto se hace automáticamente si rerere.enabled se establece en verdadero). También hay subcomandos para ver
qué se grabará, para borrar una resolución específica del caché y para borrar todo el caché. Cubriremos rerere con más
detalle en Rerere.
Cuando haya decidido cortar un lanzamiento, probablemente querrá asignar una etiqueta para poder volver a crear ese
lanzamiento en cualquier momento en el futuro. Puede crear una nueva etiqueta como se describe en Conceptos básicos de
Git. Si decide firmar la etiqueta como mantenedor, el etiquetado puede verse así:
Si firma sus etiquetas, es posible que tenga el problema de distribuir la clave PGP pública utilizada para firmar sus etiquetas.
El mantenedor del proyecto Git ha resuelto este problema al incluir su clave pública como un blob en el repositorio y luego
agregar una etiqueta que apunta directamente a ese contenido. Para hacer esto, puede averiguar qué clave desea ejecutando
gpg --list-keys:
$ gpg --list-keys /
Users/schacon/.gnupg/pubring.gpg
---------------------------------
163
Machine Translated by Google
Luego, puede importar directamente la clave a la base de datos de Git exportándola y canalizándola a través de git hash-
object, que escribe un nuevo blob con esos contenidos en Git y le devuelve el SHA-1 del blob:
Ahora que tiene el contenido de su clave en Git, puede crear una etiqueta que apunte directamente a ella especificando
el nuevo valor SHA-1 que le dio el comando hash-object :
Si ejecuta git push --tags, la etiquetamaintainer -pgp-pub se compartirá con todos. Si alguien quiere verificar una etiqueta,
puede importar directamente su clave PGP sacando el blob directamente de la base de datos e importándolo a GPG:
Pueden usar esa clave para verificar todas sus etiquetas firmadas. Además, si incluye instrucciones en el mensaje de la
etiqueta, ejecutar git show <tag> le permitirá brindarle al usuario final instrucciones más específicas sobre la verificación
de la etiqueta.
Debido a que Git no tiene números que aumentan monótonamente como 'v123' o el equivalente para cada confirmación,
si desea tener un nombre legible por humanos para acompañar una confirmación, puede ejecutar git describe en esa
confirmación. En respuesta, Git genera una cadena que consiste en el nombre de la etiqueta más reciente anterior a
esa confirmación, seguida por la cantidad de confirmaciones desde esa etiqueta, seguida finalmente por un valor SHA-1
parcial de la confirmación que se describe (precedido por la letra "g" que significa Git):
De esta manera, puede exportar una instantánea o compilarla y nombrarla algo comprensible para las personas. De
hecho, si construyes Git a partir del código fuente clonado del repositorio de Git, git --version te da algo parecido a esto.
Si está describiendo una confirmación que ha etiquetado directamente, simplemente le proporciona el nombre de la
etiqueta.
De forma predeterminada, el comando git describe requiere etiquetas anotadas (etiquetas creadas con el indicador -a o
-s ); si también desea aprovechar las etiquetas ligeras (sin anotaciones), agregue la opción --tags al comando. También
puede usar esta cadena como destino de un comando git checkout o git show , aunque se basa en el valor SHA-1
abreviado al final, por lo que es posible que no sea válido para siempre. Por ejemplo, el kernel de Linux saltó
recientemente de 8 a 10 caracteres para garantizar la exclusividad del objeto SHA-1, por lo que se invalidaron los
nombres de salida de git describe más antiguos.
164
Machine Translated by Google
Preparando un lanzamiento
Ahora desea lanzar una compilación. Una de las cosas que querrá hacer es crear un archivo de los
última instantánea de su código para aquellas pobres almas que no usan Git. El comando para hacer esto es git
archivo:
Si alguien abre ese tarball, obtiene la última instantánea de su proyecto en un directorio de proyectos .
También puede crear un archivo zip de la misma manera, pero pasando la opción --format=zip a
archivo git:
Ahora tiene un buen tarball y un archivo zip de la versión de su proyecto que puede cargar en su
sitio web o correo electrónico a las personas.
El registro breve
Es hora de enviar un correo electrónico a su lista de correo de personas que quieren saber qué está pasando en su proyecto. A
buena manera de obtener rápidamente una especie de registro de cambios de lo que se ha agregado a su proyecto desde su
último lanzamiento o correo electrónico es usar el comando git shortlog . Resume todos los compromisos en el
rango que le das; por ejemplo, lo siguiente le brinda un resumen de todas las confirmaciones desde su último
versión, si su última versión se llamó v1.0.1:
Añadir Grit::Commit#to_patch
ÿ
Obtiene un resumen limpio de todas las confirmaciones desde v1.0.1, agrupadas por autor, que puede enviar por correo electrónico a
tu lista.
165
Machine Translated by Google
Resumen
Debería sentirse bastante cómodo contribuyendo a un proyecto en Git, así como manteniendo su
propio proyecto o integrando las contribuciones de otros usuarios. ¡Felicitaciones por ser un
desarrollador de Git efectivo! En el próximo capítulo, aprenderá a usar el servicio de hospedaje de
Git más grande y popular, GitHub.
166
Machine Translated by Google
GitHub
GitHub es el host individual más grande para los repositorios de Git y es el punto central de colaboración para millones de
desarrolladores y proyectos. Un gran porcentaje de todos los repositorios de Git están alojados en GitHub, y muchos
proyectos de código abierto lo utilizan para el alojamiento de Git, el seguimiento de problemas, la revisión de código y otras cosas.
Entonces, si bien no es una parte directa del proyecto de código abierto de Git, existe una buena posibilidad de que desee
o necesite interactuar con GitHub en algún momento mientras usa Git profesionalmente.
Este capítulo trata sobre el uso efectivo de GitHub. Cubriremos registrarse y administrar una cuenta, crear y usar repositorios
Git, flujos de trabajo comunes para contribuir a proyectos y aceptar contribuciones a los suyos, la interfaz programática de
GitHub y muchos pequeños consejos para hacer su vida más fácil en general.
Si no está interesado en usar GitHub para hospedar sus propios proyectos o para colaborar con otros proyectos que están
hospedados en GitHub, puede saltar con seguridad a Git Tools.
Cambio de interfaces
Es importante tener en cuenta que, al igual que muchos sitios web activos, los elementos de la interfaz
ÿ de usuario en estas capturas de pantalla cambiarán con el tiempo. Con suerte, la idea general de lo
que estamos tratando de lograr aquí seguirá ahí, pero si desea versiones más actualizadas de estas
pantallas, las versiones en línea de este libro pueden tener capturas de pantalla más nuevas.
167
Machine Translated by Google
Lo siguiente que verá es la página de precios de los planes actualizados, pero es seguro ignorar esto por ahora.
GitHub te enviará un correo electrónico para verificar la dirección que proporcionaste. Adelante, haz esto; es bastante
importante (como veremos más adelante).
GitHub proporciona casi toda su funcionalidad con cuentas gratuitas, excepto algunas funciones
avanzadas.
ÿ Los planes pagos de GitHub incluyen herramientas y funciones avanzadas, así como límites más altos
para los servicios gratuitos, pero no los cubriremos en este libro. Para obtener más información sobre los
planes disponibles y su comparación, visite https://github.com/pricing .
Al hacer clic en el logotipo de Octocat en la parte superior izquierda de la pantalla, accederá a la página del panel de control.
Ahora está listo para usar GitHub.
Acceso SSH
A partir de ahora, puede conectarse con los repositorios de Git utilizando el protocolo https:// , autenticándose con el nombre
de usuario y la contraseña que acaba de configurar. Sin embargo, para simplemente clonar proyectos públicos, ni siquiera
necesita registrarse: la cuenta que acabamos de crear entra en juego cuando bifurcamos proyectos y empujamos a nuestras
bifurcaciones un poco más tarde.
Si desea utilizar controles remotos SSH, deberá configurar una clave pública. Si aún no tienes uno,
168
Machine Translated by Google
consulte Generación de su clave pública SSH. Abra la configuración de su cuenta usando el enlace en la parte superior derecha
de la ventana:
Desde allí, haga clic en el botón "Agregar una clave SSH", asigne un nombre a su clave, pegue el contenido de su archivo de
clave pública ~/.ssh/id_rsa.pub (o como lo haya llamado) en el área de texto y haga clic en “Añadir clave”.
Asegúrese de nombrar su clave SSH algo que pueda recordar. Puede nombrar cada una de sus claves
ÿ (por ejemplo, "Mi computadora portátil" o "Cuenta de trabajo") para que, si necesita revocar una clave
más tarde, pueda saber fácilmente cuál está buscando.
Tu avatar
A continuación, si lo desea, puede reemplazar el avatar que se genera para usted con una imagen de su elección. Primero
vaya a la pestaña "Perfil" (encima de la pestaña Claves SSH) y haga clic en "Cargar nueva imagen".
169
Machine Translated by Google
Elegiremos una copia del logotipo de Git que está en nuestro disco duro y luego tendremos la oportunidad de recortarlo.
Ahora, en cualquier lugar donde interactúes en el sitio, las personas verán tu avatar junto a tu nombre de usuario.
Si ha cargado un avatar en el popular servicio Gravatar (a menudo utilizado para cuentas de Wordpress), ese avatar se
utilizará de forma predeterminada y no es necesario que realice este paso.
170
Machine Translated by Google
La forma en que GitHub asigna sus compromisos de Git a su usuario es por dirección de correo electrónico. Si usa varias
direcciones de correo electrónico en sus confirmaciones y desea que GitHub las vincule correctamente, debe agregar todas las
direcciones de correo electrónico que ha usado en la sección Correos electrónicos de la sección de administración.
En Agregar direcciones de correo electrónico podemos ver algunos de los diferentes estados que son posibles. La dirección
superior se verifica y se configura como la dirección principal, lo que significa que es donde recibirá notificaciones y recibos. La
segunda dirección se verifica y, por lo tanto, se puede configurar como la principal si desea cambiarla.
La dirección final no está verificada, lo que significa que no puede convertirla en su dirección principal. Si GitHub ve alguno de
estos en mensajes de confirmación en cualquier repositorio del sitio, se vinculará a su usuario
ahora.
Puede encontrar la configuración de autenticación de dos factores en la pestaña Seguridad de la configuración de su cuenta.
171
Machine Translated by Google
Si hace clic en el botón "Configurar autenticación de dos factores", lo llevará a una página de configuración donde
puede optar por usar una aplicación de teléfono para generar su código secundario (una "contraseña de un solo uso
basada en el tiempo"), o puede hacer que GitHub le envíe un código por SMS cada vez que necesite iniciar sesión.
Después de elegir el método que prefiere y seguir las instrucciones para configurar 2FA, su cuenta estará un poco más
segura y tendrá que proporcionar un código además de su contraseña cada vez que inicie sesión en GitHub.
Contribuir a un proyecto
Ahora que nuestra cuenta está configurada, analicemos algunos detalles que podrían ser útiles para ayudarlo a
contribuir a un proyecto existente.
Proyectos de bifurcación
Si desea contribuir a un proyecto existente al que no tiene acceso push, puede "bifurcar" el proyecto. Cuando "bifurcas"
un proyecto, GitHub hará una copia del proyecto que es completamente tuya; vive en su espacio de nombres y puede
enviarlo.
Históricamente, el término "bifurcación" ha tenido un contexto algo negativo, lo que significa que
alguien tomó un proyecto de código abierto en una dirección diferente, a veces creando un proyecto
ÿ competitivo y dividiendo a los contribuyentes. En GitHub, una "bifurcación" es simplemente el
mismo proyecto en su propio espacio de nombres, lo que le permite realizar cambios en un proyecto
públicamente como una forma de contribuir de una manera más abierta.
De esta manera, los proyectos no tienen que preocuparse por agregar usuarios como colaboradores para darles acceso
push. Las personas pueden bifurcar un proyecto, empujarlo y contribuir con sus cambios al repositorio original creando
lo que se llama una solicitud de extracción, que trataremos a continuación. Esto abre un hilo de discusión con revisión
de código, y el propietario y el colaborador pueden comunicarse
172
Machine Translated by Google
sobre el cambio hasta que el propietario esté satisfecho con él, momento en el cual el propietario puede fusionarlo.
Para bifurcar un proyecto, visite la página del proyecto y haga clic en el botón "Bifurcar" en la parte superior derecha de la página.
Después de unos segundos, accederá a la página de su nuevo proyecto, con su propia copia del código que se puede escribir.
El flujo de GitHub
GitHub está diseñado en torno a un flujo de trabajo de colaboración particular, centrado en solicitudes de incorporación de cambios. Este flujo
funciona ya sea que esté colaborando con un equipo muy unido en un único repositorio compartido, o una empresa distribuida globalmente o
una red de extraños que contribuyen a un proyecto a través de docenas de bifurcaciones. Se centra en el flujo de trabajo de Ramas de temas
1. Bifurcar el proyecto.
Este es básicamente el flujo de trabajo del Administrador de integración cubierto en el Flujo de trabajo del Administrador de integración, pero en
lugar de usar el correo electrónico para comunicarse y revisar los cambios, los equipos usan las herramientas basadas en la web de GitHub.
Veamos un ejemplo de cómo proponer un cambio en un proyecto de código abierto alojado en GitHub usando este flujo.
Puede usar la herramienta CLI oficial de GitHub en lugar de la interfaz web de GitHub para la mayoría de las cosas. La
ÿ herramienta se puede utilizar en sistemas Windows, MacOS y Linux. Ir a la página de inicio de la CLI de GitHub para las
Tony está buscando un código para ejecutar en su microcontrolador programable Arduino y encontró un gran archivo de programa en GitHub en
https://github.com/schacon/blink.
173
Machine Translated by Google
El único problema es que la velocidad de parpadeo es demasiado rápida. Creemos que es mucho mejor esperar 3 segundos
en lugar de 1 entre cada cambio de estado. Así que mejoremos el programa y enviémoslo de vuelta al proyecto como un
cambio propuesto.
Primero, hacemos clic en el botón 'Fork' como se mencionó anteriormente para obtener nuestra propia copia del proyecto.
Nuestro nombre de usuario aquí es "tonychacon", por lo que nuestra copia de este proyecto está en https://github.com/
tonychacon/blink y ahí es donde podemos editarlo. Lo clonaremos localmente, crearemos una rama de tema, cambiaremos el
código y finalmente enviaremos ese cambio nuevamente a GitHub.
174
Machine Translated by Google
$ cd
parpadear $ git checkout -b parpadeo lento ÿ
Cambiado a una nueva rama 'parpadeo lento'
Ahora, si volvemos a nuestra bifurcación en GitHub, podemos ver que GitHub notó que pusimos una nueva
175
Machine Translated by Google
el tema se ramifica y nos presenta un gran botón verde para ver nuestros cambios y abrir una solicitud de
extracción para el proyecto original.
Si hacemos clic en ese botón verde, veremos una pantalla que nos pide que le demos un título y una
descripción a nuestra solicitud de extracción. Casi siempre vale la pena esforzarse un poco en esto, ya que
una buena descripción ayuda al propietario del proyecto original a determinar qué estaba tratando de hacer,
si los cambios propuestos son correctos y si aceptar los cambios mejoraría el proyecto original.
También vemos una lista de las confirmaciones en nuestra rama de tema que están "por delante" de la rama
maestra (en este caso, solo una) y una diferencia unificada de todos los cambios que se realizarán si el
proyecto fusiona esta rama. dueño.
176
Machine Translated by Google
Cuando presione el botón 'Crear solicitud de extracción' en esta pantalla, el propietario del proyecto que bifurcó recibirá una notificación
de que alguien está sugiriendo un cambio y lo vinculará a una página que tiene toda esta información.
Aunque las solicitudes de extracción se usan comúnmente para proyectos públicos como este cuando el
colaborador tiene un cambio completo listo para realizar, también se usa a menudo en proyectos internos al
ÿ comienzo del ciclo de desarrollo. Dado que puede seguir empujando a la rama del tema incluso después de
abrir la solicitud de extracción, a menudo se abre temprano y se usa como una forma de iterar en el trabajo como
equipo dentro de un contexto, en lugar de abrirse al final del proceso.
En este punto, el propietario del proyecto puede ver el cambio sugerido y fusionarlo, rechazarlo o comentarlo. Digamos que le gusta la
idea, pero preferiría un tiempo un poco más largo para que la luz esté apagada que encendida.
177
Machine Translated by Google
Donde esta conversación puede tener lugar por correo electrónico en los flujos de trabajo presentados en Git distribuido, en
GitHub esto sucede en línea. El propietario del proyecto puede revisar la diferencia unificada y dejar un comentario haciendo
clic en cualquiera de las líneas.
Figura 92. Comentar una línea de código específica en una solicitud de extracción
Una vez que el mantenedor hace este comentario, la persona que abrió la solicitud de extracción (y, de hecho, cualquier otra
persona que vea el repositorio) recibirá una notificación. Veremos cómo personalizar esto más adelante, pero si tuviera
activadas las notificaciones por correo electrónico, Tony recibiría un correo electrónico como este:
Cualquiera también puede dejar comentarios generales sobre la solicitud de extracción. En la página de discusión de Solicitud
de extracción podemos ver un ejemplo del propietario del proyecto comentando una línea de código y luego dejando un
comentario general en la sección de discusión. Puede ver que los comentarios del código también se incorporan a la
conversación.
178
Machine Translated by Google
Ahora el contribuyente puede ver lo que debe hacer para que se acepte su cambio. Por suerte, esto es muy
sencillo. Donde por correo electrónico puede que tenga que volver a lanzar su serie y volver a enviarla a la lista de
correo, con GitHub simplemente se compromete con la rama del tema nuevamente y presiona, lo que actualizará
automáticamente la solicitud de extracción. En la solicitud de extracción final , también puede ver que el comentario
del código anterior se ha colapsado en la solicitud de extracción actualizada, ya que se hizo en una línea que se
modificó desde entonces.
Agregar confirmaciones a una solicitud de extracción existente no activa una notificación, por lo que una vez que
Tony ha enviado sus correcciones, decide dejar un comentario para informar al propietario del proyecto que realizó
el cambio solicitado.
179
Machine Translated by Google
Una cosa interesante a tener en cuenta es que si hace clic en la pestaña "Archivos modificados" en esta solicitud de
extracción, obtendrá la diferencia "unificada", es decir, la diferencia agregada total que se introduciría en su rama
principal si este tema branch se fusionó. En términos de git diff , básicamente muestra automáticamente tu git diff
master…<branch> para la rama en la que se basa esta solicitud de extracción. Consulte Determinar qué se introduce
para obtener más información sobre este tipo de diferencia.
La otra cosa que notará es que GitHub verifica si la solicitud de extracción se fusiona limpiamente y proporciona un
botón para realizar la fusión por usted en el servidor. Este botón solo aparece si tiene acceso de escritura al
repositorio y es posible una combinación trivial. Si hace clic en él, GitHub realizará una combinación de "no avance
rápido", lo que significa que incluso si la combinación podría ser un avance rápido, aún creará una confirmación de
combinación.
180
Machine Translated by Google
Este es el flujo de trabajo básico que utilizan la mayoría de los proyectos de GitHub. Se crean ramas de temas, se abren solicitudes
de extracción en ellas, se produce una discusión, posiblemente se realiza más trabajo en la rama y, finalmente, la solicitud se cierra o
se fusiona.
No solo horquillas
Es importante tener en cuenta que también puede abrir una solicitud de extracción entre dos sucursales en el
ÿ mismo repositorio. Si está trabajando en una función con alguien y ambos tienen acceso de escritura al proyecto,
puede enviar una rama de tema al repositorio y abrir una solicitud de extracción en la rama principal de ese
mismo proyecto para iniciar la revisión del código y proceso de discusión. No es necesario bifurcar.
Ahora que hemos cubierto los conceptos básicos de contribuir a un proyecto en GitHub, cubramos algunos consejos y trucos
interesantes sobre las solicitudes de incorporación de cambios para que pueda ser más efectivo al usarlas.
Es importante comprender que muchos proyectos realmente no piensan en las solicitudes de incorporación de cambios como colas de
parches perfectos que deben aplicarse limpiamente en orden, ya que la mayoría de los proyectos basados en listas de correo piensan
en contribuciones de series de parches. La mayoría de los proyectos de GitHub piensan en las ramas de solicitud de extracción como
conversaciones iterativas en torno a un cambio propuesto, que culmina en una diferencia unificada que se aplica mediante la fusión.
Esta es una distinción importante, porque generalmente se sugiere el cambio antes de que se considere que el código es perfecto, lo
que es mucho más raro con las contribuciones de series de parches basadas en listas de correo. Esto permite una conversación más
temprana con los mantenedores para que llegar a la solución adecuada sea más un esfuerzo de la comunidad. Cuando se propone
código con una solicitud de extracción y los mantenedores o la comunidad sugieren un cambio, la serie de parches generalmente no
se vuelve a implementar, sino que la diferencia se envía como una nueva confirmación a la rama, lo que hace que la conversación
avance con el contexto de la obra anterior intacta.
Por ejemplo, si regresa y mira de nuevo la solicitud de extracción final, notará que el colaborador no volvió a basar su compromiso y
envió otra solicitud de extracción. En su lugar, agregaron nuevas confirmaciones y las empujaron a la rama existente. De esta manera,
si regresa y observa esta solicitud de extracción en el futuro, puede encontrar fácilmente todo el contexto de por qué se tomaron las
decisiones. Al presionar el botón "Combinar" en el sitio, se crea a propósito una confirmación de combinación que hace referencia a la
solicitud de extracción para que sea fácil regresar e investigar la conversación original si es necesario.
Si su solicitud de extracción se vuelve obsoleta o no se fusiona limpiamente, querrá arreglarla para que el mantenedor pueda fusionarla
fácilmente. GitHub probará esto por ti y te informará en la parte inferior de cada solicitud de extracción si la fusión es trivial o no.
181
Machine Translated by Google
Si ve algo como que la solicitud de extracción no se fusiona limpiamente, querrá arreglar su rama para que se vuelva verde y
el mantenedor no tenga que hacer trabajo extra.
Tienes dos opciones principales para hacer esto. Puede cambiar la base de su rama encima de la rama de destino
(normalmente la rama maestra del repositorio que bifurcó), o puede fusionar la rama de destino en su rama.
La mayoría de los desarrolladores en GitHub elegirán hacer lo último, por las mismas razones que acabamos de mencionar
en la sección anterior. Lo que importa es el historial y la fusión final, por lo que el rebase no le brinda mucho más que un
historial ligeramente más limpio y, a cambio, es mucho más difícil y propenso a errores.
Si desea fusionarse en la rama de destino para hacer que su Solicitud de extracción se pueda fusionar, agregaría el repositorio
original como un nuevo control remoto, buscaría en él, fusionaría la rama principal de ese repositorio en su rama de tema,
solucionaría cualquier problema y finalmente lo impulsaría. copia de seguridad en la misma sucursal en la que abrió la solicitud
de extracción.
Por ejemplo, digamos que en el ejemplo de "tonychacon" que estábamos usando antes, el autor original hizo un cambio que
crearía un conflicto en la solicitud de extracción. Vayamos a través de esos pasos.
182
Machine Translated by Google
Una vez que haga eso, la solicitud de extracción se actualizará automáticamente y se volverá a verificar para ver si se fusiona
limpiamente.
183
Machine Translated by Google
Una de las mejores cosas de Git es que puedes hacer eso continuamente. Si tiene un proyecto de larga duración, puede
fusionarse fácilmente desde la rama de destino una y otra vez y solo tiene que lidiar con los conflictos que surgieron desde la
última vez que se fusionó, lo que hace que el proceso sea muy manejable.
Si absolutamente desea cambiar la base de la rama para limpiarla, sin duda puede hacerlo, pero se recomienda enfáticamente
no forzar el empuje sobre la rama en la que ya está abierta la solicitud de extracción. Si otras personas lo han eliminado y han
trabajado más en él, se encontrará con todos los problemas descritos en The Perils of Rebasing. En su lugar, inserte la rama
reorganizada en una nueva rama en GitHub y abra una nueva solicitud de extracción que haga referencia a la anterior, luego
cierre la original.
Referencias
Su próxima pregunta puede ser "¿Cómo hago referencia a la solicitud de extracción anterior?". Resulta que hay muchas, muchas
formas de hacer referencia a otras cosas en casi cualquier lugar donde puedas escribir en GitHub.
Comencemos con cómo hacer una referencia cruzada de otra solicitud de extracción o un problema. A todas las solicitudes de
extracción y problemas se les asignan números y son únicos dentro del proyecto. Por ejemplo, no puede tener Solicitud de
extracción n.° 3 y Problema n.° 3. Si desea hacer referencia a cualquier Solicitud de extracción o Problema de cualquier otro,
simplemente puede poner #<num> en cualquier comentario o descripción. También puede ser más específico si la solicitud de
emisión o extracción se encuentra en otro lugar; escribe nombredeusuario#<num> si te refieres a un problema o solicitud de
extracción en una bifurcación del repositorio en el que te encuentras, o nombre de usuario/repo#<num> para hacer referencia a
algo en otro repositorio.
Veamos un ejemplo. Digamos que modificamos la base de la rama en el ejemplo anterior, creamos una nueva solicitud de
extracción para ella y ahora queremos hacer referencia a la solicitud de extracción antigua a partir de la nueva. También
queremos hacer referencia a un problema en la bifurcación del repositorio y un problema en un proyecto completamente diferente.
Podemos completar la descripción al igual que las referencias cruzadas en una solicitud de extracción.
184
Machine Translated by Google
Cuando enviemos esta solicitud de extracción, veremos todo eso representado como referencias cruzadas representadas en una
solicitud de extracción.
Tenga en cuenta que la URL completa de GitHub que pusimos allí se acortó a solo la información necesaria.
Ahora, si Tony regresa y cierra la solicitud de extracción original, podemos ver que al mencionarla en la nueva, GitHub ha creado
automáticamente un evento de seguimiento en la línea de tiempo de la solicitud de extracción. Esto significa que cualquier persona
que visite esta Solicitud de extracción y vea que está cerrada puede vincularse fácilmente a la que la reemplazó. El enlace se parecerá
a Enlace de regreso a la nueva solicitud de extracción en la línea de tiempo cerrada de la solicitud de extracción.
185
Machine Translated by Google
Figura 100. Vínculo de regreso a la nueva solicitud de extracción en la línea de tiempo cerrada de la solicitud de extracción
Además de los números de emisión, también puede hacer referencia a una confirmación específica de SHA-1. Tienes que
especificar un SHA-1 completo de 40 caracteres, pero si GitHub lo ve en un comentario, se vinculará directamente a la
confirmación. Nuevamente, puede hacer referencia a confirmaciones en bifurcaciones u otros repositorios de la misma manera
que lo hizo con los problemas.
Vincular a otros problemas es solo el comienzo de cosas interesantes que puede hacer con casi cualquier cuadro de texto en
GitHub. En las descripciones, comentarios, comentarios de código y más de problemas y solicitudes de extracción, puede usar
lo que se denomina "rebaja con sabor de GitHub". Markdown es como escribir en texto sin formato pero que se representa de
forma rica.
Consulte Un ejemplo de Markdown con sabor de GitHub tal como está escrito y representado para ver un ejemplo de cómo se
pueden escribir comentarios o texto y luego representar mediante Markdown.
Figura 101. Un ejemplo de GitHub Flavored Markdown tal como está escrito y representado
El sabor GitHub de Markdown agrega más cosas que puede hacer más allá de la sintaxis básica de Markdown.
Todos estos pueden ser realmente útiles al crear comentarios o descripciones útiles de solicitudes de extracción o problemas.
186
Machine Translated by Google
Listas de tareas
La primera función Markdown específica de GitHub realmente útil, especialmente para usar en solicitudes de extracción, es la Lista de tareas. Una
lista de tareas es una lista de casillas de verificación de cosas que desea hacer. Ponerlos en un problema o solicitud de extracción normalmente indica
cosas que desea hacer antes de considerar que el elemento está completo.
Si incluimos esto en la descripción de nuestra Solicitud de extracción o Problema, lo veremos representado como Listas de tareas representadas en
un comentario de Markdown.
Esto se usa a menudo en las solicitudes de extracción para indicar todo lo que le gustaría hacer en la rama antes de que la solicitud de extracción esté
lista para fusionarse. La parte realmente interesante es que simplemente puede hacer clic en las casillas de verificación para actualizar el comentario;
Además, GitHub buscará listas de tareas en sus problemas y solicitudes de extracción y las mostrará como metadatos en las páginas que las
enumeran. Por ejemplo, si tiene una solicitud de extracción con tareas y mira la página de descripción general de todas las solicitudes de extracción,
puede ver qué tan avanzado está. Esto ayuda a las personas a dividir las solicitudes de extracción en subtareas y ayuda a otras personas a realizar
Puede ver un ejemplo de esto en el resumen de la lista de tareas en la lista de solicitud de extracción.
Estos son increíblemente útiles cuando abre una solicitud de extracción antes y la usa para realizar un seguimiento de su progreso a través de la
implementación de la función.
187
Machine Translated by Google
Fragmentos de código
También puede agregar fragmentos de código a los comentarios. Esto es especialmente útil si desea presentar algo que
podría intentar hacer antes de implementarlo como una confirmación en su rama.
Esto también se usa a menudo para agregar un código de ejemplo de lo que no funciona o lo que podría implementar esta solicitud
de extracción.
```java
for(int i=0 ; yo < 5 ; i++)
"
{ System.out.println("i is : } + yo);
```
Si agrega un nombre de idioma como lo hicimos allí con 'java', GitHub también intentará resaltar la sintaxis del fragmento. En
el caso del ejemplo anterior, terminaría renderizándose como el ejemplo de código delimitado renderizado.
citando
Si está respondiendo a una pequeña parte de un comentario largo, puede citar selectivamente el otro comentario precediendo
las líneas con el carácter > . De hecho, esto es tan común y tan útil que existe un atajo de teclado para ello. Si resalta el texto
en un comentario al que desea responder directamente y presiona la tecla r , citará ese texto en el cuadro de comentarios
por usted.
188
Machine Translated by Google
emoticonos
Finalmente, también puedes usar emoji en tus comentarios. En realidad, esto se usa bastante en los
comentarios que ve en muchos problemas de GitHub y solicitudes de extracción. Incluso hay un asistente
de emoji en GitHub. Si está escribiendo un comentario y comienza con un carácter : , un autocompletador
lo ayudará a encontrar lo que está buscando.
Los emojis toman la forma de :<nombre>: en cualquier parte del comentario. Por ejemplo, podrías escribir
algo como esto:
189
Machine Translated by Google
:aplausos::tada::panda_face:
No es que esto sea increíblemente útil, pero agrega un elemento de diversión y emoción a un medio en el que de otro modo
sería difícil transmitir emoción.
En realidad, hay una gran cantidad de servicios web que utilizan caracteres emoji en estos días. Puede
encontrar una gran hoja de referencia para encontrar emoji que exprese lo que quiere decir en:
ÿ
https://www.webfx.com/tools/emoji-cheat-sheet/
Imágenes
Esto no es técnicamente un Markdown con sabor a GitHub, pero es increíblemente útil. Además de agregar enlaces de imágenes
de Markdown a los comentarios, que pueden ser difíciles de encontrar e incrustar URL, GitHub le permite arrastrar y soltar
imágenes en áreas de texto para incrustarlas.
190
Machine Translated by Google
Si observa Arrastrar y soltar imágenes para cargarlas e incrustarlas automáticamente, puede ver una pequeña
sugerencia de "Análisis como Markdown" sobre el área de texto. Al hacer clic en eso, obtendrá una hoja de trucos
completa de todo lo que puede hacer con Markdown en GitHub.
Una vez que haya bifurcado un repositorio de GitHub, su repositorio (su "bifurcación") existe independientemente
del original. En particular, cuando el repositorio original tiene nuevas confirmaciones, GitHub te informa mediante
un mensaje como:
Pero su repositorio de GitHub nunca será actualizado automáticamente por GitHub; esto es algo que debe hacer
usted mismo. Afortunadamente, esto es muy fácil de hacer.
Una posibilidad de hacer esto no requiere configuración. Por ejemplo, si bifurcó desde https://github.com/progit/
progit2.git, puede mantener su rama maestra actualizada de esta manera:
191
Machine Translated by Google
Esto funciona, pero es un poco tedioso tener que deletrear la URL de búsqueda cada vez. Puede automatizar este trabajo con
un poco de configuración:
Una vez hecho esto, el flujo de trabajo se vuelve mucho más simple:
Este enfoque puede ser útil, pero no está exento de inconvenientes. Git felizmente hará este trabajo por ti en silencio, pero no
te avisará si haces una confirmación para dominar, extraer de progit y luego enviar al origen ; todas esas operaciones son
válidas con esta configuración. Por lo tanto, deberá tener cuidado de nunca comprometerse directamente con el maestro, ya
que esa rama pertenece efectivamente al repositorio ascendente.
Mantenimiento de un proyecto
Ahora que nos sentimos cómodos contribuyendo a un proyecto, veamos el otro lado: crear, mantener y administrar su propio
proyecto.
Vamos a crear un nuevo repositorio para compartir el código de nuestro proyecto. Comience haciendo clic en el botón "Nuevo
repositorio" en el lado derecho del tablero, o desde el botón + en la barra de herramientas superior al lado de su nombre de
usuario como se ve en el menú desplegable "Nuevo repositorio".
192
Machine Translated by Google
193
Machine Translated by Google
Todo lo que realmente tiene que hacer aquí es proporcionar un nombre de proyecto; el resto de los campos son completamente
opcionales. Por ahora, simplemente haga clic en el botón "Crear repositorio" y listo: tiene un nuevo repositorio en GitHub, llamado
<usuario>/<nombre_del_proyecto>.
Dado que aún no tiene ningún código allí, GitHub le mostrará instrucciones sobre cómo crear un nuevo repositorio de Git o conectar
un proyecto de Git existente. No profundizaremos en esto aquí; si necesita un repaso, consulte Conceptos básicos de Git.
Ahora que su proyecto está alojado en GitHub, puede proporcionar la URL a cualquier persona con la que desee compartir su
proyecto. Se puede acceder a cada proyecto en GitHub a través de HTTPS como https://github.com/<user>/<project_name>,
través de SSH como git@github.com:<user>/
ya
<project_name>.
Git puede buscar y enviar a estas dos URL, pero tienen un control de acceso basado en las credenciales del usuario que se conecta
a ellas.
A menudo, es preferible compartir la URL basada en HTTPS para un proyecto público, ya que el usuario no
necesita tener una cuenta de GitHub para acceder a ella para la clonación. Los usuarios deberán tener una
ÿ cuenta y una clave SSH cargada para acceder a su proyecto si les proporciona la URL de SSH. El HTTPS
también es exactamente la misma URL que pegarían en un navegador para ver el proyecto allí.
Agregar colaboradores
Si está trabajando con otras personas a las que desea otorgar acceso de confirmación, debe agregarlas como "colaboradores". Si
Ben, Jeff y Louise se registran para obtener cuentas en GitHub y desea otorgarles acceso automático a su repositorio, puede
agregarlos a su proyecto. Si lo hace, les dará acceso "push", lo que significa que tienen acceso de lectura y escritura al proyecto y al
repositorio de Git.
194
Machine Translated by Google
Luego seleccione "Colaboradores" en el menú del lado izquierdo. Luego, simplemente escriba un nombre de usuario
en el cuadro y haga clic en "Agregar colaborador". Puedes repetir esto tantas veces como quieras para otorgar acceso
a todos los que quieras. Si necesita revocar el acceso, simplemente haga clic en la "X" en el lado derecho de su
fila.
Ahora que tiene un proyecto con algo de código y tal vez incluso algunos colaboradores que también tienen acceso
push, repasemos qué hacer cuando usted mismo recibe una solicitud de extracción.
Las solicitudes de extracción pueden provenir de una rama en una bifurcación de su repositorio o pueden provenir de
otra rama en el mismo repositorio. La única diferencia es que los que están en una bifurcación a menudo son de
personas a las que no puedes enviar a su rama y ellos no pueden enviar a la tuya, mientras que con las solicitudes de
extracción internas generalmente ambas partes pueden acceder a la rama.
195
Machine Translated by Google
Para estos ejemplos, supongamos que usted es "tonychacon" y ha creado un nuevo proyecto de código Arduino llamado
"fade".
Alguien viene, hace un cambio en su código y le envía una solicitud de extracción. Debería recibir un correo electrónico
notificándole sobre la nueva solicitud de extracción y debería parecerse a una notificación por correo electrónico de una
nueva solicitud de extracción.
Figura 114. Notificación por correo electrónico de una nueva solicitud de extracción
Hay algunas cosas a tener en cuenta sobre este correo electrónico. Le dará un pequeño diffstat: una lista de archivos que
han cambiado en la solicitud de extracción y cuánto. Le da un enlace a la solicitud de extracción en GitHub. También le
brinda algunas URL que puede usar desde la línea de comandos.
Si observa la línea que dice git pull <url> parche-1, esta es una forma sencilla de fusionarse en una rama remota sin tener
que agregar un control remoto. Repasamos esto rápidamente en Verificación de sucursales remotas. Si lo desea, puede
crear y cambiar a una rama de tema y luego ejecutar este comando para fusionar los cambios de Solicitud de extracción.
Las otras URL interesantes son las URL .diff y .patch , que, como puede suponer, proporcionan versiones unificadas de
diferencias y parches de la solicitud de incorporación de cambios. Técnicamente, podría fusionarse en el trabajo de solicitud
de extracción con algo como esto:
196
Machine Translated by Google
Como cubrimos en The GitHub Flow, ahora puede tener una conversación con la persona que abrió la solicitud de extracción.
Puede comentar líneas específicas de código, comentar confirmaciones completas o comentar toda la solicitud de extracción
en sí misma, utilizando GitHub Flavored Markdown en todas partes.
Cada vez que alguien más comenta sobre la solicitud de extracción, seguirás recibiendo notificaciones por correo electrónico
para que sepas que hay actividad. Cada uno tendrá un enlace a la solicitud de extracción donde se está realizando la
actividad y también puede responder directamente al correo electrónico para comentar en el hilo de la solicitud de extracción.
Una vez que el código está en el lugar que le gusta y desea fusionarlo, puede extraer el código y fusionarlo localmente, ya
sea con la sintaxis de git pull <url> <branch> que vimos anteriormente, o agregando la bifurcación como un control remoto
y buscar y fusionar.
Si la combinación es trivial, también puede presionar el botón "Combinar" en el sitio de GitHub. Esto hará una fusión de "no
avance rápido", creando una confirmación de fusión incluso si fuera posible una fusión de avance rápido. Esto significa que
pase lo que pase, cada vez que presiona el botón de combinación, se crea una confirmación de combinación. Como puede
ver en el botón Fusionar y las instrucciones para fusionar una solicitud de extracción manualmente, GitHub le brinda toda
esta información si hace clic en el enlace de sugerencia.
197
Machine Translated by Google
Figura 116. Botón Fusionar e instrucciones para fusionar una solicitud de extracción manualmente
Si decide que no desea fusionarlo, también puede simplemente cerrar la solicitud de extracción y se notificará a la
persona que la abrió.
Si está lidiando con muchas solicitudes de extracción y no quiere agregar un montón de controles remotos o hacer
extracciones únicas cada vez, hay un buen truco que GitHub le permite hacer. Este es un truco un poco avanzado y
repasaremos los detalles un poco más en The Refspec, pero puede ser bastante útil.
GitHub en realidad anuncia las ramas de solicitud de extracción para un repositorio como una especie de pseudo-
ramas en el servidor. De forma predeterminada, no los obtiene cuando clona, pero están ocultos y puede acceder a
ellos con bastante facilidad.
Para demostrar esto, vamos a utilizar un comando de bajo nivel (a menudo denominado comando de "plomería", sobre
el cual leeremos más en Plomería y porcelana) llamado ls-remote. Este comando generalmente no se usa en las
operaciones diarias de Git, pero es útil para mostrarnos qué referencias están presentes en el servidor.
Si ejecutamos este comando contra el repositorio "parpadeo" que estábamos usando anteriormente, obtendremos una
lista de todas las ramas y etiquetas y otras referencias en el repositorio.
198
Machine Translated by Google
Por supuesto, si está en su repositorio y ejecuta git ls-remote origin o cualquier control remoto que desee verificar, le
mostrará algo similar a esto.
Si el repositorio está en GitHub y tiene solicitudes de extracción abiertas, obtendrá estas referencias que tienen el prefijo
refs/pull/. Estas son básicamente ramas, pero dado que no están bajo referencias/cabezas/ no las obtienes normalmente
cuando clonas o obtienes del servidor; el proceso de obtención las ignora normalmente.
Hay dos referencias por solicitud de extracción: la que termina en /head apunta exactamente a la misma confirmación
que la última confirmación en la rama de solicitud de extracción. Entonces, si alguien abre una solicitud de extracción en
nuestro repositorio y su rama se llama corrección de errores y apunta a confirmar a5a775, entonces en nuestro
repositorio no tendremos una rama de corrección de errores (ya que está en su bifurcación), pero tendremos pull/<pr#>/
head que apunta a a5a775. Esto significa que podemos extraer fácilmente todas las ramas de solicitud de extracción de
una sola vez sin tener que agregar un montón de controles remotos.
Esto le dice a Git: "Conéctese al control remoto de origen y descargue la referencia llamada refs/pull/958/head". Git
obedece felizmente y descarga todo lo que necesita para construir esa referencia, y pone un puntero a la confirmación
que desea en .git/FETCH_HEAD. Puedes seguir eso con git merge FETCH_HEAD en una rama en la que quieras
probarlo, pero ese mensaje de confirmación de combinación parece un poco raro. Además, si está revisando muchas
solicitudes de extracción, esto se vuelve tedioso.
También hay una manera de obtener todas las solicitudes de extracción y mantenerlas actualizadas cada vez que se
conecta al control remoto. Abra .git/config en su editor favorito y busque el control remoto de origen . Debería verse un
poco como esto:
Esa línea que comienza con fetch = es una "refspec". Es una forma de asignar nombres en el control remoto con nombres
en su directorio local .git . Este en particular le dice a Git, "las cosas en el control remoto que son
199
Machine Translated by Google
bajo refs/heads debe ir a mi repositorio local bajo refs/remotes/origin". Puede modificar esta sección para agregar otra refspec:
Esa última línea le dice a Git: "Todas las referencias que parecen refs/pull/123/head deben almacenarse localmente como refs/
remotes/origin/pr/123". Ahora, si guardas ese archivo y haces un git fetch:
$ git fetch # …
* [nueva
referencia] * refs/pull/1/cabeza -> origen/pr/1 refs/pull/
[nueva referencia] 2/cabeza -> origen/pr/2 refs/pull/4/cabeza
* [nueva -> origen/pr/4
referencia] # …
Ahora todas las solicitudes de extracción remotas se representan localmente con referencias que actúan de manera muy similar a
las ramas de seguimiento; son de solo lectura y se actualizan cuando haces una recuperación. Esto hace que sea muy fácil probar
el código de una solicitud de extracción localmente:
Los ojos de águila entre ustedes notarían la cabeza en el extremo de la parte remota de la refspec.
También hay una refs/pull/#/merge ref en el lado de GitHub, que representa la confirmación que resultaría si presiona el botón
"merge" en el sitio. Esto puede permitirle probar la combinación incluso antes de presionar el botón.
No solo puede abrir solicitudes de extracción dirigidas a la rama principal o principal , sino que también puede abrir una solicitud de
extracción dirigida a cualquier sucursal de la red. De hecho, incluso puede apuntar a otra solicitud de extracción.
Si ve una solicitud de extracción que se está moviendo en la dirección correcta y tiene una idea para un cambio que depende de ella
o no está seguro de que sea una buena idea, o simplemente no tiene acceso de inserción a la rama de destino, puede abrir una
solicitud de extracción directamente en él.
Cuando va a abrir una Solicitud de extracción, hay un cuadro en la parte superior de la página que especifica a qué rama está
solicitando extraer y de cuál está solicitando extraer. Si presiona el botón "Editar" a la derecha de ese cuadro, puede cambiar no solo
las ramas sino también qué bifurcación.
200
Machine Translated by Google
Aquí puede especificar con bastante facilidad fusionar su nueva rama en otra solicitud de extracción u otra bifurcación del proyecto.
Menciones y Notificaciones
GitHub también tiene un sistema de notificaciones bastante bueno incorporado que puede ser útil cuando tiene preguntas o necesita
comentarios de personas o equipos específicos.
En cualquier comentario puede comenzar a escribir un carácter @ y comenzará a autocompletarse con los nombres y nombres de
usuario de las personas que son colaboradores o contribuyentes en el proyecto.
También puede mencionar a un usuario que no está en ese menú desplegable, pero a menudo el autocompletador puede hacerlo
más rápido.
Una vez que publique un comentario con una mención de usuario, ese usuario será notificado. Esto significa que esta puede ser una
forma realmente efectiva de atraer a las personas a las conversaciones en lugar de hacer que voten. Muy a menudo, en las solicitudes
de extracción en GitHub, las personas atraerán a otras personas de sus equipos o de su empresa para revisar un problema o una
solicitud de extracción.
201
Machine Translated by Google
La página de notificaciones
Cuando mencionamos "notificaciones" aquí con respecto a GitHub, nos referimos a una forma específica en la
que GitHub intenta ponerse en contacto con usted cuando ocurren eventos y hay algunas formas diferentes de
configurarlos. Si va a la pestaña "Centro de notificaciones" desde la página de configuración, puede ver algunas
de las opciones que tiene.
202
Machine Translated by Google
Las dos opciones son recibir notificaciones por "Correo electrónico" y por "Web" y puede elegir una, ninguna o
ambas para cuando participa activamente en las cosas y para la actividad en los repositorios que está viendo.
Notificaciones web
Las notificaciones web solo existen en GitHub y solo puede consultarlas en GitHub. Si tiene esta opción
seleccionada en sus preferencias y se activa una notificación para usted, verá un pequeño punto azul sobre el
ícono de notificaciones en la parte superior de su pantalla como se ve en el Centro de notificaciones.
Si hace clic en eso, verá una lista de todos los elementos sobre los que ha sido notificado, agrupados por
proyecto. Puede filtrar las notificaciones de un proyecto específico haciendo clic en su nombre en la barra lateral
izquierda. También puede reconocer la notificación haciendo clic en el icono de marca de verificación junto a cualquier
203
Machine Translated by Google
notificación, o reconozca todas las notificaciones en un proyecto haciendo clic en la marca de verificación en la parte superior del grupo.
También hay un botón de silencio junto a cada marca de verificación en el que puede hacer clic para no recibir más notificaciones sobre
ese elemento.
Todas estas herramientas son muy útiles para manejar un gran número de notificaciones. Muchos usuarios avanzados de GitHub
simplemente desactivarán las notificaciones por correo electrónico por completo y administrarán todas sus notificaciones a través de esta
pantalla.
Las notificaciones por correo electrónico son la otra forma en que puede manejar las notificaciones a través de GitHub. Si tiene esto
activado, recibirá correos electrónicos para cada notificación. Vimos ejemplos de esto en Comentarios enviados como notificaciones por
correo electrónico y Notificación por correo electrónico de una nueva Solicitud de extracción. Los correos electrónicos también se enhebrarán
correctamente, lo cual es bueno si está utilizando un cliente de correo electrónico de enhebrado.
También hay una buena cantidad de metadatos incrustados en los encabezados de los correos electrónicos que le envía GitHub, lo que
Por ejemplo, si observamos los encabezados de correo electrónico reales enviados a Tony en el correo electrónico que se muestra en la
notificación por correo electrónico de una nueva solicitud de extracción, veremos lo siguiente entre la información enviada:
Hay un par de cosas interesantes aquí. Si desea resaltar o redirigir correos electrónicos a este proyecto en particular o incluso a una
solicitud de extracción, la información en Message-ID le brinda todos los datos en formato <usuario>/<proyecto>/<tipo>/<id> . Si esto fuera
un problema, por ejemplo, el campo <tipo> habría sido "problemas" en lugar de "extracción".
Los campos List-Post y List-Unsubscribe significan que si tiene un cliente de correo que los entiende, puede publicar fácilmente en la lista o
"Cancelar suscripción" del hilo. Eso sería esencialmente lo mismo que hacer clic en el botón "silenciar" en la versión web de la notificación
o "Cancelar suscripción" en la página de Problema o Solicitud de extracción.
También vale la pena señalar que si tiene habilitadas las notificaciones web y de correo electrónico y lee la versión de correo electrónico de
la notificación, la versión web también se marcará como leída si tiene imágenes permitidas en su cliente de correo.
Archivos especiales
Hay un par de archivos especiales que GitHub notará si están presentes en tu repositorio.
204
Machine Translated by Google
LÉAME
El primero es el archivo README , que puede tener casi cualquier formato que GitHub reconozca como prosa. Por
ejemplo, podría ser README, README.md, README.asciidoc, etc. Si GitHub ve un archivo README en su fuente, lo
mostrará en la página de inicio del proyecto.
Muchos equipos usan este archivo para almacenar toda la información relevante del proyecto para alguien que podría ser
nuevo en el repositorio o proyecto. Esto generalmente incluye cosas como:
Dado que GitHub procesará este archivo, puede incrustar imágenes o enlaces en él para una mayor facilidad de
comprensión.
CONTRIBUYENDO
El otro archivo especial que reconoce GitHub es el archivo CONTRIBUTING . Si tiene un archivo llamado CONTRIBUCIÓN
con cualquier extensión de archivo, GitHub mostrará Abriendo una solicitud de extracción cuando exista un archivo
CONTRIBUCIÓN cuando alguien comience a abrir una solicitud de extracción.
Figura 122. Apertura de una solicitud de extracción cuando existe un archivo CONTRIBUYENTE
La idea aquí es que puede especificar cosas específicas que desea o no desea en una solicitud de extracción enviada a
su proyecto. De esta manera, las personas pueden leer las pautas antes de abrir la solicitud de extracción.
Administración de proyecto
En general, no hay muchas cosas administrativas que pueda hacer con un solo proyecto, pero hay un par de elementos
que pueden ser de interés.
205
Machine Translated by Google
Si está utilizando una rama que no sea "maestra" como su rama predeterminada en la que desea que las personas abran
solicitudes de extracción o vean de forma predeterminada, puede cambiar eso en la página de configuración de su repositorio
en la pestaña "Opciones".
Simplemente cambie la rama predeterminada en el menú desplegable y esa será la predeterminada para todas las operaciones
principales a partir de ese momento, incluida la rama que se verifica de forma predeterminada cuando alguien clona el repositorio.
Transferencia de un proyecto
Si desea transferir un proyecto a otro usuario u organización en GitHub, hay una opción "Transferir propiedad" en la parte inferior
de la misma pestaña "Opciones" de la página de configuración de su repositorio que le permite hacer esto.
Esto es útil si está abandonando un proyecto y alguien quiere hacerse cargo de él, o si su proyecto se está haciendo más grande
y quiere trasladarlo a una organización.
Esto no solo mueve el repositorio junto con todos sus observadores y estrellas a otro lugar, sino que también configura una
redirección desde su URL al nuevo lugar. También redirigirá los clones y las recuperaciones de Git, no solo las solicitudes web.
206
Machine Translated by Google
Una organización es bastante fácil de crear; simplemente haga clic en el icono "+" en la parte superior derecha de cualquier
página de GitHub y seleccione "Nueva organización" en el menú.
Primero deberá nombrar su organización y proporcionar una dirección de correo electrónico para un punto de contacto
principal para el grupo. Luego puede invitar a otros usuarios a ser copropietarios de la cuenta si lo desea.
Siga estos pasos y pronto será el propietario de una nueva organización. Al igual que las cuentas personales, las
organizaciones son gratuitas si todo lo que planea almacenar allí será de código abierto.
Como propietario de una organización, cuando bifurca un repositorio, tendrá la opción de bifurcarlo al espacio de nombres
de su organización. Cuando crea nuevos repositorios, puede crearlos en su cuenta personal o en cualquiera de las
organizaciones de las que es propietario. También "observa" automáticamente cualquier nuevo repositorio creado en estas
organizaciones.
Al igual que en Tu avatar, puedes cargar un avatar para tu organización para personalizarlo un poco. También, al igual que
las cuentas personales, tiene una página de inicio para la organización que enumera todos sus repositorios y puede ser
vista por otras personas.
Ahora cubramos algunas de las cosas que son un poco diferentes con una cuenta organizacional.
equipos
Las organizaciones están asociadas con personas individuales por medio de equipos, que son simplemente una agrupación
de cuentas de usuarios individuales y repositorios dentro de la organización y qué tipo de acceso tienen esas personas en
esos repositorios.
207
Machine Translated by Google
Por ejemplo, supongamos que su empresa tiene tres repositorios: frontend, backend y deploymentscripts. Le
gustaría que sus desarrolladores de HTML/CSS/JavaScript tuvieran acceso al frontend y tal vez al backend, y que
su gente de operaciones tuviera acceso al backend y los scripts de implementación. Los equipos lo hacen fácil,
sin tener que administrar a los colaboradores de cada repositorio individual.
La página Organización le muestra un panel simple de todos los repositorios, usuarios y equipos que están bajo
esta organización.
Para administrar sus equipos, puede hacer clic en la barra lateral de equipos en el lado derecho de la página en la
página de la organización. Esto lo llevará a una página que puede usar para agregar miembros al equipo, agregar
repositorios al equipo o administrar la configuración y los niveles de control de acceso para el equipo. Cada equipo
puede tener acceso de solo lectura, lectura/escritura o administrativo a los repositorios. Puede cambiar ese nivel
haciendo clic en el botón "Configuración" en la página El equipo.
208
Machine Translated by Google
Cuando invite a alguien a un equipo, recibirá un correo electrónico informándole que ha sido invitado.
Además, las @menciones del equipo (como @acmecorp/frontend) funcionan de la misma manera que con los usuarios
individuales, excepto que todos los miembros del equipo se suscriben al hilo. Esto es útil si desea la atención de alguien
en un equipo, pero no sabe exactamente a quién preguntar.
Un usuario puede pertenecer a cualquier cantidad de equipos, así que no se limite solo a los equipos de control de acceso.
Los equipos de interés especial como ux, css o refactoring son útiles para ciertos tipos de preguntas, y otros como legales
y daltónicos para un tipo completamente diferente.
Registro de auditoría
Las organizaciones también brindan a los propietarios acceso a toda la información sobre lo que sucedió en la organización.
Puede ir a la pestaña 'Registro de auditoría' y ver qué eventos han ocurrido a nivel de organización, quién los realizó y en
qué parte del mundo se realizaron.
209
Machine Translated by Google
También puede filtrar hacia tipos específicos de eventos, lugares específicos o personas específicas.
Scripting GitHub
Así que ahora hemos cubierto todas las principales funciones y flujos de trabajo de GitHub, pero cualquier grupo o
proyecto grande tendrá personalizaciones que quizás deseen realizar o servicios externos que quizás deseen integrar.
Afortunadamente para nosotros, GitHub es bastante pirateable de muchas maneras. En esta sección, cubriremos cómo
usar el sistema de enlaces de GitHub y su API para hacer que GitHub funcione como queremos.
Servicios y Hooks
La sección Hooks and Services de la administración del repositorio de GitHub es la forma más fácil de tener
210
Machine Translated by Google
Servicios
Primero vamos a echar un vistazo a los Servicios. Tanto las integraciones de Hooks como de Servicios se pueden
encontrar en la sección Configuración de su repositorio, donde anteriormente vimos agregar Colaboradores y cambiar
la rama predeterminada de su proyecto. En la pestaña "Webhooks and Services" verá algo como la sección de
configuración de Servicios y Hooks.
Hay docenas de servicios entre los que puede elegir, la mayoría de ellos integraciones en otros sistemas comerciales
y de código abierto. La mayoría de ellos son para servicios de integración continua, rastreadores de errores y problemas,
sistemas de salas de chat y sistemas de documentación. Veremos cómo configurar uno muy simple, el gancho de
correo electrónico. Si elige "correo electrónico" en el menú desplegable "Agregar servicio", obtendrá una pantalla de
configuración como la configuración del servicio de correo electrónico.
211
Machine Translated by Google
En este caso, si presionamos el botón "Agregar servicio", la dirección de correo electrónico que especificamos recibirá un
correo electrónico cada vez que alguien ingrese al repositorio. Los servicios pueden escuchar muchos tipos diferentes de
eventos, pero la mayoría solo escucha eventos push y luego hace algo con esos datos.
Si hay un sistema que está utilizando que le gustaría integrar con GitHub, debe consultar aquí para ver si hay una
integración de servicio existente disponible. Por ejemplo, si está utilizando Jenkins para ejecutar pruebas en su base de
código, puede habilitar la integración del servicio incorporado de Jenkins para iniciar una ejecución de prueba cada vez
que alguien ingresa a su repositorio.
Manos
Si necesita algo más específico o desea integrarse con un servicio o sitio que no está incluido en esta lista, puede usar
el sistema de ganchos más genérico. Los ganchos de repositorio de GitHub son bastante simples. Especificas una URL
y GitHub publicará una carga HTTP en esa URL en cualquier evento que desees.
En general, la forma en que esto funciona es que puede configurar un pequeño servicio web para escuchar una carga útil
de enlace de GitHub y luego hacer algo con los datos cuando se reciben.
Para habilitar un gancho, haga clic en el botón "Agregar webhook" en la sección de configuración de Servicios y ganchos.
Esto lo llevará a una página que se parece a la configuración de Webhook.
La configuración de un enlace web es bastante simple. En la mayoría de los casos, simplemente ingrese una URL y una
clave secreta y presione "Agregar webhook". Hay algunas opciones para los eventos para los que desea que GitHub le
envíe una carga útil: el valor predeterminado es obtener solo una carga útil para el evento de inserción , cuando alguien
inserta código nuevo en cualquier rama de su repositorio.
212
Machine Translated by Google
Veamos un pequeño ejemplo de un servicio web que puede configurar para manejar un enlace web. Usaremos el marco web Ruby
Sinatra ya que es bastante conciso y debería poder ver fácilmente lo que estamos haciendo.
Digamos que queremos recibir un correo electrónico si una persona específica ingresa a una rama específica de nuestro proyecto
modificando un archivo específico. Podríamos hacerlo bastante fácilmente con un código como este:
requieren 'sinatra'
requieren 'json'
requieren 'correo'
'tchacon@example.com'
ÿ
para 'tchacon@example.com'
ÿ
"ALARMA" final
final
final
Aquí tomamos la carga JSON que nos entrega GitHub y buscamos quién la empujó, a qué rama empujaron y qué archivos se tocaron
en todas las confirmaciones que se empujaron. Luego lo verificamos con nuestros criterios y enviamos un correo electrónico si
coincide.
Para desarrollar y probar algo como esto, tiene una buena consola de desarrollador en la misma pantalla donde configuró la conexión.
Puede ver las últimas entregas que GitHub ha intentado realizar para ese webhook. Para cada enlace, puede profundizar en cuándo
se entregó, si fue exitoso y el cuerpo y los encabezados tanto de la solicitud como de la respuesta. Esto hace que sea increíblemente
fácil probar y depurar sus ganchos.
213
Machine Translated by Google
La otra gran característica de esto es que puede volver a entregar cualquiera de las cargas útiles para probar su servicio
fácilmente.
Para obtener más información sobre cómo escribir webhooks y todos los diferentes tipos de eventos que puede escuchar,
vaya a la documentación del desarrollador de GitHub en https://developer.github.com/webhooks/.
La API de GitHub
Los servicios y ganchos le brindan una forma de recibir notificaciones automáticas sobre eventos que ocurren en sus
repositorios, pero ¿qué sucede si necesita más información sobre estos eventos? ¿Qué sucede si necesita automatizar algo
como agregar colaboradores o etiquetar problemas?
Aquí es donde la API de GitHub resulta útil. GitHub tiene toneladas de puntos finales de API para hacer casi
214
Machine Translated by Google
cualquier cosa que pueda hacer en el sitio web de forma automatizada. En esta sección, aprenderemos cómo
autenticarse y conectarse a la API, cómo comentar un problema y cómo cambiar el estado de una solicitud de
extracción a través de la API.
Uso básico
Lo más básico que puede hacer es una simple solicitud GET en un punto final que no requiere autenticación. Esto
podría ser un usuario o información de solo lectura en un proyecto de código abierto. Por ejemplo, si queremos saber
más sobre un usuario llamado “schacon”, podemos ejecutar algo como esto:
Hay toneladas de puntos finales como este para obtener información sobre organizaciones, proyectos, problemas,
compromisos, casi cualquier cosa que pueda ver públicamente en GitHub. Incluso puede usar la API para representar
Markdown arbitrariamente o encontrar una plantilla .gitignore .
*.oreja
215
Machine Translated by Google
Sin embargo, si desea realizar una acción en el sitio web, como comentar un problema o una solicitud de
extracción, o si desea ver o interactuar con contenido privado, deberá autenticarse.
Hay varias formas de autenticarse. Puede usar la autenticación básica con solo su nombre de usuario y contraseña,
pero generalmente es una mejor idea usar un token de acceso personal. Puede generar esto desde la pestaña
"Aplicaciones" de su página de configuración.
Figura 133. Genere su token de acceso desde la pestaña "Aplicaciones" de su página de configuración
Le preguntará qué ámbitos desea para este token y una descripción. Asegúrese de usar una buena descripción
para que se sienta cómodo eliminando el token cuando ya no se use su secuencia de comandos o aplicación.
GitHub solo le mostrará el token una vez, así que asegúrese de copiarlo. Ahora puede usar esto para autenticarse
en su secuencia de comandos en lugar de usar un nombre de usuario y una contraseña. Esto es bueno porque
puede limitar el alcance de lo que quiere hacer y el token es revocable.
Esto también tiene la ventaja adicional de aumentar su límite de tasa. Sin autenticación, estará limitado a 60
solicitudes por hora. Si te autenticas puedes realizar hasta 5.000 solicitudes por hora.
Entonces, usémoslo para hacer un comentario sobre uno de nuestros problemas. Digamos que queremos dejar
un comentario sobre un tema específico, el número 6. Para hacerlo, tenemos que hacer una solicitud HTTP POST
a repos/<user>/<repo>/issues/<num>/comments con el token que acabamos de generar como encabezado de
Autorización.
216
Machine Translated by Google
https://api.github.com/repos/schacon/blink/issues/6 /comentarios
{ "id": 58322100,
"html_url": "https://github.com/schacon/blink/issues/6#issuecomment-58322100",
...
"usuario":
{ "iniciar sesión":
"tonychacon", "id": 7874698,
"avatar_url": "https://avatars.githubusercontent.com/u/7874698?v=2", "tipo":
"Usuario" , }, "created_at": "2014-10-08T07:48:19Z", "updated_at":
"2014-10-08T07:48:19Z", "body": "Un nuevo comentario, :+1:" }
Ahora, si va a ese problema, puede ver el comentario que acabamos de publicar con éxito como en Un comentario
publicado desde la API de GitHub.
Puede usar la API para hacer casi cualquier cosa que pueda hacer en el sitio web: crear y establecer hitos, asignar
personas a problemas y solicitudes de extracción, crear y cambiar etiquetas, acceder a datos de confirmación,
crear nuevas confirmaciones y ramas, abrir, cerrar o fusionar Pull Requests, crear y editar equipos, comentar
líneas de código en un Pull Request, buscar en el sitio y así sucesivamente.
Hay un último ejemplo que veremos, ya que es realmente útil si está trabajando con solicitudes de extracción.
Cada confirmación puede tener uno o más estados asociados y hay una API para agregar y consultar ese estado.
La mayoría de los servicios de prueba e integración continua utilizan esta API para reaccionar a las inserciones
probando el código que se envió y luego informan si esa confirmación ha superado todas las pruebas. También
puede usar esto para verificar si el mensaje de compromiso tiene el formato correcto, si el remitente siguió todas
las pautas de su contribución, si el compromiso se firmó de manera válida, cualquier cantidad de cosas.
Supongamos que configura un webhook en su repositorio que accede a un pequeño servicio web que busca una
cadena Firmado por en el mensaje de confirmación.
217
Machine Translated by Google
requiere 'httpparty'
requieren 'sinatra'
requiere 'json'
estado = 'éxito'
ÿ
estado = 'fracaso'
ÿ
estado = {
ÿ
:encabezados => {
ÿ
Esperemos que esto sea bastante simple de seguir. En este controlador de gancho web, revisamos cada confirmación que
se acaba de enviar, buscamos la cadena 'Firmado por' en el mensaje de confirmación y finalmente PUBLICAMOS
a través de HTTP al punto final de la API /repos/<user>/<repo>/statuses/<commit_sha> con el estado.
En este caso, puede enviar un estado ('éxito', 'fracaso', 'error'), una descripción de lo que sucedió, un objetivo
URL a la que el usuario puede ir para obtener más información y un "contexto" en caso de que haya varios estados para
un solo compromiso. Por ejemplo, un servicio de prueba puede proporcionar un estado y un servicio de validación como
esto también puede proporcionar un estado: el campo "contexto" es cómo se diferencian.
218
Machine Translated by Google
Si alguien abre una nueva solicitud de extracción en GitHub y este enlace está configurado, es posible que vea algo como el estado
de confirmación a través de la API.
Ahora puede ver una pequeña marca de verificación verde junto a la confirmación que tiene una cadena de "Firmado por" en el
mensaje y una cruz roja en la que el autor olvidó firmar. También puede ver que la solicitud de extracción toma el estado de la última
confirmación en la rama y le advierte si falla.
Esto es realmente útil si está utilizando esta API para obtener resultados de prueba, de modo que no fusione accidentalmente algo
donde la última confirmación está fallando en las pruebas.
octokit
Aunque hemos estado haciendo casi todo a través de curl y solicitudes HTTP simples en estos ejemplos, existen varias bibliotecas
de código abierto que hacen que esta API esté disponible de una manera más idiomática.
En el momento de escribir este artículo, los lenguajes admitidos incluyen Go, Objective-C, Ruby y .NET. Echa un vistazo a https://
github.com/octokit para obtener más información sobre estos, ya que manejan gran parte del HTTP por usted.
Con suerte, estas herramientas pueden ayudarlo a personalizar y modificar GitHub para que funcione mejor para sus flujos de
trabajo específicos. Para obtener documentación completa sobre toda la API, así como guías para tareas comunes, consulte https://
developer.github.com.
Resumen
Ahora eres un usuario de GitHub. Sabes cómo crear una cuenta, administrar una organización, crear y enviar repositorios, contribuir
a los proyectos de otras personas y aceptar contribuciones de otros. En el próximo capítulo, aprenderá herramientas y consejos más
potentes para lidiar con situaciones complejas, lo que realmente lo convertirá en un maestro de Git.
219
Machine Translated by Google
Herramientas Git
A estas alturas, ha aprendido la mayoría de los comandos y flujos de trabajo diarios que necesita para administrar o mantener un
repositorio de Git para su control de código fuente. Ha realizado las tareas básicas de seguimiento y confirmación de archivos, y ha
aprovechado el poder del área de ensayo y la bifurcación y fusión de temas ligeros.
Ahora explorará una serie de cosas muy poderosas que Git puede hacer que no necesariamente usará en el día a día, pero que puede
necesitar en algún momento.
Selección de revisión
Git te permite hacer referencia a una sola confirmación, un conjunto de confirmaciones o un rango de confirmaciones de varias maneras.
No son necesariamente obvios, pero es útil conocerlos.
Revisiones individuales
Obviamente, puede referirse a cualquier confirmación individual por su hash SHA-1 completo de 40 caracteres, pero también hay formas
más amigables para los humanos de referirse a las confirmaciones. Esta sección describe las diversas formas en que puede hacer
referencia a cualquier confirmación.
Corto SHA-1
Git es lo suficientemente inteligente como para averiguar a qué compromiso te refieres si proporcionas los primeros caracteres del hash
SHA-1, siempre que ese hash parcial tenga al menos cuatro caracteres y no sea ambiguo; es decir, ningún otro objeto en la base de
datos de objetos puede tener un hash que comience con el mismo prefijo.
Por ejemplo, para examinar una confirmación específica donde sabe que agregó cierta funcionalidad, primero puede ejecutar el comando
git log para ubicar la confirmación:
220
Machine Translated by Google
$ git registro
compromiso 734713bc047d87bf7eac9674765ae793478c50d3
1c002dd... 35cfb2b...
Autor: Scott Chacon <schacon@gmail.com> Fecha: Jue
11 de diciembre 15:08:43 2008 -0800
En este caso, digamos que está interesado en la confirmación cuyo hash comienza con 1c002dd…. Puede inspeccionar
esa confirmación con cualquiera de las siguientes variaciones de git show (suponiendo que las versiones más cortas no
sean ambiguas):
Git puede encontrar una abreviatura corta y única para sus valores SHA-1. Si pasa --abbrev-commit al comando git log ,
la salida usará valores más cortos pero los mantendrá únicos; por defecto usa siete caracteres, pero los hace más
largos si es necesario para mantener el SHA-1 sin ambigüedades:
Generalmente, de ocho a diez caracteres son más que suficientes para ser únicos dentro de un proyecto. Por ejemplo,
a partir de febrero de 2019, el kernel de Linux (que es un proyecto bastante grande) tiene más de 875ÿ000
confirmaciones y casi siete millones de objetos en su base de datos de objetos, sin dos objetos cuyos SHA-1 sean
idénticos en los primeros 12 caracteres.
221
Machine Translated by Google
Muchas personas se preocupan en algún momento de que, por casualidad aleatoria, tengan
dos objetos distintos en su repositorio que tengan el mismo valor SHA-1. ¿Entonces que?
Si confirma un objeto que tiene el mismo valor SHA-1 que un objeto diferente anterior en su
repositorio, Git verá el objeto anterior que ya está en su base de datos Git, supondrá que ya
estaba escrito y simplemente lo reutilizará. Si intenta verificar ese objeto nuevamente en algún
momento, siempre obtendrá los datos del primer objeto.
Sin embargo, debe tener en cuenta lo ridículamente improbable que es este escenario. El
resumen SHA-1 es de 20 bytes o 160 bits. La cantidad de objetos con hash aleatorio
necesarios para garantizar una probabilidad del 50% de una sola colisión es de
aproximadamente 280 (la fórmula para determinar la probabilidad de colisión es p = (n(n-1)/2)
* (1/2^160)). 280 es 1,2 x 1024 o 1 millón de billones de billones. Eso es 1200 veces el número
ÿ de granos de arena en la tierra.
Aquí hay un ejemplo para darle una idea de lo que se necesitaría para obtener una colisión
SHA-1. Si los 6.500 millones de humanos en la Tierra estuvieran programando, y cada
segundo, cada uno produjera un código que fuera el equivalente de toda la historia del kernel
de Linux (6.5 millones de objetos Git) y lo insertara en un enorme repositorio Git, tomaría
aproximadamente 2 años. hasta que ese repositorio contenía suficientes objetos para tener un
50% de probabilidad de una sola colisión de objetos SHA-1. Por lo tanto, una colisión orgánica
SHA-1 es menos probable que todos los miembros de su equipo de programación sean
atacados y asesinados por lobos en incidentes no relacionados en la misma noche.
Si le dedica varios miles de dólares de potencia informática, es posible sintetizar dos archivos
con el mismo hash, como se demuestra en https://shattered.io/ en febrero de 2017. Git está
avanzando hacia el uso de SHA256 como el algoritmo hash predeterminado, que es mucho
más resistente a los ataques de colisión y tiene un código para ayudar a mitigar este ataque
(aunque no puede eliminarlo por completo).
Referencias de sucursales
Una forma sencilla de referirse a una confirmación en particular es si es la confirmación en la punta de una rama;
en ese caso, simplemente puede usar el nombre de la rama en cualquier comando de Git que espere una
referencia a una confirmación. Por ejemplo, si desea examinar el último objeto de confirmación en una rama, los
siguientes comandos son equivalentes, asumiendo que la rama topic1 apunta a la confirmación ca82a6d…:
Si desea ver a qué SHA-1 específico apunta una rama, o si desea ver a qué se reduce cualquiera de estos
ejemplos en términos de SHA-1, puede usar una herramienta de plomería de Git llamada rev-parse. Puede ver
Git Internals para obtener más información sobre las herramientas de plomería; básicamente, rev-parse existe para
222
Machine Translated by Google
operaciones de nivel inferior y no está diseñado para ser utilizado en las operaciones diarias. Sin embargo, a veces puede
ser útil cuando necesita ver lo que realmente está sucediendo. Aquí puede ejecutar rev-parse en su sucursal.
Una de las cosas que hace Git en segundo plano mientras trabaja es mantener un "registro de referencia", un registro de
dónde han estado sus referencias HEAD y branch durante los últimos meses.
$ git reflog
734713b HEAD@{0}: confirmación: corrige el manejo de referencias, agrega gc auto,
actualiza las pruebas d921970 HEAD@{1}: fusiona phedders/rdocs: fusión realizada por la estrategia
'recursiva'. 1c002dd HEAD@{2}: confirmación: agrega algo de culpa y fusiona cosas 1c36188
HEAD@{3}: rebase -i (squash): actualización de HEAD 95df984 HEAD@{4}: confirmación: # Esta es
una combinación de dos confirmaciones. 1c36188 HEAD@{5}: rebase -i (squash): actualizando
HEAD 7e05da5 HEAD@{6}: rebase -i (pick): actualizando HEAD
Cada vez que se actualiza la sugerencia de su sucursal por cualquier motivo, Git almacena esa información para usted en
este historial temporal. También puede usar sus datos de reflog para hacer referencia a confirmaciones anteriores. Por
ejemplo, si desea ver el quinto valor anterior de HEAD de su repositorio, puede usar la referencia @{5} que ve en la salida
de reflog:
$ mostrar HEAD@{5}
También puede usar esta sintaxis para ver dónde estaba una rama hace un tiempo específico. Por ejemplo, para ver dónde
estaba ayer su rama maestra , puede escribir:
Eso le mostraría dónde estaba ayer la punta de su rama maestra . Esta técnica solo funciona para los datos que aún están
en su registro de referencia, por lo que no puede usarla para buscar confirmaciones de más de unos pocos meses.
Para ver la información de reflog formateada como la salida de registro de git , puede ejecutar git log -g:
223
Machine Translated by Google
Es importante tener en cuenta que la información de reflog es estrictamente local: es un registro solo de lo que ha hecho en su
repositorio. Las referencias no serán las mismas en la copia del repositorio de otra persona; Además, inmediatamente después
de clonar inicialmente un repositorio, tendrá un registro de referencia vacío, ya que aún no se ha producido ninguna actividad en
su repositorio. Ejecutar git show HEAD@{2.months.ago} le mostrará la confirmación coincidente solo si clonó el proyecto hace al
menos dos meses; si lo clonó más recientemente, verá solo su primera confirmación local.
Si tiene experiencia en UNIX o Linux, puede pensar en el reflog como la versión de Git del historial de shell,
ÿ que enfatiza que lo que hay allí es claramente relevante solo para usted y su "sesión", y no tiene nada que
ver con nadie más que pueda estar trabajando en la misma máquina.
Al usar PowerShell, las llaves como { y } son caracteres especiales y se deben escapar. Puede escapar de
`
ellos con un acento grave o poner la referencia de confirmación entre comillas:
ÿ
$ mostrar HEAD@{0} $ # no trabajará
Referencias de ascendencia
La otra forma principal de especificar una confirmación es a través de su ascendencia. Si coloca un ^ (signo de intercalación) al
final de una referencia, Git lo resuelve para que signifique el padre de esa confirmación. Supongamos que miras el historial de tu
proyecto:
224
Machine Translated by Google
Luego, puede ver la confirmación anterior especificando HEAD^, que significa "el padre de HEAD":
ÿ # NO funcionará en Windows
$ git muestra CABEZA^
$ git muestra CABEZA^^ # OK
$ git muestra "CABEZA^" # OK
También puede especificar un número después de ^ para identificar qué padre desea; por ejemplo, d921970^2
significa "el segundo padre de d921970". Esta sintaxis es útil solo para confirmaciones de fusión, que tienen
más de un padre: el primer padre de una confirmación de fusión es de la rama en la que estaba cuando se
fusionó (con frecuencia maestro), mientras que el segundo padre de una confirmación de fusión es de la rama
que se fusionó (digamos, tema):
225
Machine Translated by Google
La otra especificación principal de ascendencia es la ~ (tilde). Esto también se refiere al primer padre, por lo que HEAD~ y HEAD^
son equivalentes. La diferencia se hace evidente cuando especifica un número. HEAD~2 significa "el primer padre del primer padre"
o "el abuelo": atraviesa los primeros padres la cantidad de veces que especifique. Por ejemplo, en el historial mencionado
anteriormente, HEAD~3 sería:
Ignorar *.gem
Esto también se puede escribir HEAD~~~, que nuevamente es el primer padre del primer padre del primer padre:
$ mostrar HEAD~~~
cometer 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Autor: Tom Preston-Werner <tom@mojombo.com>
Fecha: Vie 7 de noviembre 13:47:59 2008 -0500
Ignorar *.gem
También puede combinar estas sintaxis: puede obtener el segundo elemento principal de la referencia anterior (suponiendo que se
trate de una confirmación de combinación) utilizando HEAD~3^2, y así sucesivamente.
Rangos de confirmación
Ahora que puede especificar confirmaciones individuales, veamos cómo especificar rangos de confirmaciones. Esto es particularmente
útil para administrar sus sucursales: si tiene muchas sucursales, puede usar especificaciones de rango para responder preguntas
como "¿Qué trabajo hay en esta sucursal que aún no he fusionado con mi sucursal principal?"
226
Machine Translated by Google
punto doble
La especificación de rango más común es la sintaxis de doble punto. Básicamente, esto le pide a Git que resuelva un rango de
confirmaciones a las que se puede acceder desde una confirmación pero no desde otra. Por ejemplo, supongamos que tiene un
historial de confirmaciones que se parece a un historial de ejemplo para la selección de rango.
Supongamos que desea ver qué hay en su rama experimental que aún no se ha fusionado con su rama maestra . Puede pedirle
a Git que le muestre un registro de solo esas confirmaciones con maestro ... experimento, lo que significa "todas las
confirmaciones accesibles desde el experimento que no son accesibles desde el maestro". En aras de la brevedad y la claridad
en estos ejemplos, las letras de los objetos de confirmación del diagrama se utilizan en lugar de la salida del registro real en el
orden en que se mostrarían:
Si, por otro lado, desea ver lo contrario (todas las confirmaciones en el maestro que no están en el experimento ), puede invertir
los nombres de las ramas. experiment..master le muestra todo en el maestro no accesible desde el experimento:
mi
Esto es útil si desea mantener actualizada la rama del experimento y obtener una vista previa de lo que está a punto de fusionar.
Otro uso frecuente de esta sintaxis es ver lo que está a punto de enviar a un control remoto:
Este comando le muestra cualquier confirmación en su rama actual que no esté en la rama maestra en su control remoto de
origen . Si ejecuta un git push y su rama actual está rastreando origin/master, las confirmaciones enumeradas por git log origin/
master..HEAD son las confirmaciones que se transferirán al servidor. También puede omitir un lado de la sintaxis para que Git
asuma HEAD. Por ejemplo, puede obtener los mismos resultados que en el ejemplo anterior escribiendo git log origin/master..
— Git sustituye HEAD si falta un lado.
227
Machine Translated by Google
Puntos Múltiples
La sintaxis de doble punto es útil como abreviatura, pero tal vez desee especificar más de dos ramas para indicar su revisión,
como ver qué confirmaciones hay en cualquiera de varias ramas que no están en la rama en la que se encuentra actualmente.
Git te permite hacer esto usando el carácter ^ o --not antes de cualquier referencia desde la que no quieras ver confirmaciones
accesibles. Por lo tanto, los siguientes tres comandos son equivalentes:
Esto es bueno porque con esta sintaxis puede especificar más de dos referencias en su consulta, lo que no puede hacer con la
sintaxis de doble punto. Por ejemplo, si desea ver todas las confirmaciones a las que se puede acceder desde refA o refB pero
no desde refC, puede usar cualquiera de las siguientes opciones:
Esto lo convierte en un sistema de consulta de revisión muy poderoso que debería ayudarlo a descubrir qué hay en sus sucursales.
punto triple
La última sintaxis principal de selección de rango es la sintaxis de triple punto, que especifica todas las confirmaciones a las que
puede acceder cualquiera de las dos referencias, pero no ambas. Vuelva a consultar el historial de confirmación de ejemplo en
Historial de ejemplo para la selección de rango. Si desea ver lo que hay en el maestro o el experimento, pero no en las referencias
comunes, puede ejecutar:
D
C
Nuevamente, esto le brinda una salida de registro normal , pero le muestra solo la información de confirmación para esas cuatro
confirmaciones, que aparecen en el orden de fecha de confirmación tradicional.
Un interruptor común para usar con el comando de registro en este caso es --left-right, que le muestra en qué lado del rango se
encuentra cada confirmación. Esto ayuda a que la salida sea más útil:
> re
>C
228
Machine Translated by Google
Con estas herramientas, puede hacer que Git sepa mucho más fácilmente qué compromiso o compromisos desea
inspeccionar.
En esta sección, verás algunos comandos interactivos de Git que pueden ayudarte a crear tus confirmaciones.
para incluir solo ciertas combinaciones y partes de archivos. Estas herramientas son útiles si modifica un
una gran cantidad de archivos, luego decida que desea que esos cambios se dividan en varios
confirmaciones enfocadas en lugar de una gran confirmación desordenada. De esta manera, puede asegurarse de que sus compromisos sean
conjuntos de cambios separados lógicamente y pueden ser revisados fácilmente por los desarrolladores que trabajan con usted.
Si ejecuta git add con la opción -i o --interactive , Git ingresa a un modo de shell interactivo,
$ git añadir -i
ÿ
Puede ver que este comando le muestra una vista muy diferente de su área de preparación de lo que está
probablemente solía: básicamente, la misma información que obtienes con el estado de git pero un poco más breve
e informativo. Enumera los cambios que ha preparado a la izquierda y los cambios sin preparar a la derecha.
Después de esto, viene una sección de "Comandos", que le permite hacer una serie de cosas como puesta en escena y
anular archivos, organizar partes de archivos, agregar archivos sin seguimiento y mostrar diferencias de lo que ha sido
escenificado.
Si escribe u o 2 (para actualizar) en el indicador Qué ahora> , se le preguntará qué archivos desea actualizar.
escenario:
sin cambios 2:
sin3:cambios
sin +1/-1 índice.html
cambios +5/-1 lib/simplegit.rb
Actualizar>>
Para organizar los archivos TODO e index.html , puede escribir los números:
229
Machine Translated by Google
Actualizar>> 1,2
ÿ
El * al lado de cada archivo significa que el archivo está seleccionado para ser preparado. Si presiona Enter después de escribir nada
Actualizar>>
2 caminos actualizados
Ahora puede ver que los archivos TODO e index.html están preparados y el archivo simplegit.rb todavía está
sin escenificar Si desea desorganizar el archivo TODO en este punto, use la opción r o 3 (para revertir):
Mirando de nuevo tu estado de Git, puedes ver que has desmontado el archivo TODO :
230
Machine Translated by Google
Para ver la diferencia de lo que ha organizado, puede usar el comando d o 6 (para diferencia). Te muestra una lista
de sus archivos preparados, y puede seleccionar aquellos para los que le gustaría ver la diferencia preparada. Esta
es muy parecido a especificar git diff --cached en la línea de comando:
<p id="fuera">...</p>
<script tipo="texto/javascript">
Con estos comandos básicos, puede usar el modo de agregar interactivo para tratar con su área de preparación un
poco más fácilmente.
También es posible que Git organice ciertas partes de los archivos y no el resto. Por ejemplo, si haces dos
cambios en su archivo simplegit.rb y desea organizar uno de ellos y no el otro, hacerlo es muy
fácil en Git. Desde el mismo indicador interactivo explicado en la sección anterior, escriba p o 5 (para
parche). Git te preguntará qué archivos te gustaría organizar parcialmente; entonces, para cada sección del
archivos seleccionados, mostrará fragmentos de la diferencia del archivo y le preguntará si desea organizarlos, uno por
una:
231
Machine Translated by Google
Tienes muchas opciones en este punto. ¿ Escribiendo ? muestra una lista de lo que puede hacer:
Por lo general, escribirá y o n si desea preparar cada trozo, pero también puede ser útil colocarlos todos en ciertos archivos u omitir
una decisión de trozo hasta más tarde. Si prepara una parte del archivo y deja otra parte sin preparar, su salida de estado se verá así:
El estado del archivo simplegit.rb es interesante. Te muestra que un par de líneas están escenificadas y otras no. Has preparado
parcialmente este archivo. En este punto, puede salir del script de adición interactivo y ejecutar git commit para confirmar los archivos
parcialmente preparados.
Tampoco es necesario que esté en el modo de adición interactiva para realizar la puesta en escena del archivo parcial; puede iniciar el
232
Machine Translated by Google
misma secuencia de comandos usando git add -p o git add --patch en la línea de comando.
Además, puede usar el modo parche para restablecer parcialmente archivos con el comando git reset --patch , para verificar
partes de archivos con el comando git checkout --patch y para guardar partes de archivos con el comando git stash save --
patch . Entraremos en más detalles sobre cada uno de estos a medida que lleguemos a usos más avanzados de estos
comandos.
Almacenamiento y limpieza
A menudo, cuando ha estado trabajando en parte de su proyecto, las cosas están en un estado desordenado y desea
cambiar de rama por un tiempo para trabajar en otra cosa. El problema es que no desea hacer una confirmación de trabajo
a medio hacer solo para poder volver a este punto más tarde. La respuesta a este problema es el comando git stash .
Stashing toma el estado sucio de su directorio de trabajo, es decir, sus archivos rastreados modificados y cambios
preparados, y lo guarda en una pila de cambios sin terminar que puede volver a aplicar en cualquier momento (incluso en
una rama diferente).
git stash save no desaparecerá pronto, así que no te preocupes por si desaparece repentinamente.
Pero es posible que desee comenzar a migrar a la alternativa de inserción para la nueva funcionalidad .
Esconder tu trabajo
Para demostrar el ocultamiento, ingresará a su proyecto y comenzará a trabajar en un par de archivos y posiblemente
realizará uno de los cambios. Si ejecuta git status, puede ver su estado sucio:
$ git status
Cambios a confirmar: (use
"git reset HEAD <archivo>..." para quitar la etapa)
modificado: index.html
modificado: lib/simplegit.rb
Ahora quiere cambiar de rama, pero no quiere comprometer lo que ha estado trabajando todavía,
233
Machine Translated by Google
así que guardarás los cambios. Para insertar un nuevo alijo en su pila, ejecute git stash o git stash push:
$ git alijo
Directorio de trabajo guardado y estado del índice \
"WIP en maestro: 049d078 Crear archivo de índice"
HEAD está ahora en 049d078 Crear archivo de índice
(Para restaurarlos, escriba "git stash apply")
$ git estado
# En el maestro de la
En este punto, puede cambiar de sucursal y trabajar en otro lugar; sus cambios se almacenan en su pila. Para ver
qué alijos has almacenado, puedes usar git stash list:
En este caso, se guardaron dos escondites anteriormente, por lo que tiene acceso a tres obras escondidas diferentes.
Puede volver a aplicar el que acaba de guardar utilizando el comando que se muestra en la salida de ayuda del
comando de almacenamiento original: git stash apply. Si desea aplicar uno de los stashes más antiguos, puede
especificarlo nombrándolo, así: git stash apply stash@{2}. Si no especifica un alijo, Git asume el alijo más reciente e
intenta aplicarlo:
no se agregaron cambios para confirmar (use "git add" y/o "git commit -a")
Puede ver que Git vuelve a modificar los archivos que revirtió cuando guardó el alijo. En este caso, tenía un directorio
de trabajo limpio cuando intentó aplicar el alijo e intentó aplicarlo en la misma rama desde la que lo guardó. No es
necesario tener un directorio de trabajo limpio y aplicarlo en la misma rama para aplicar con éxito un alijo. Puede
guardar un alijo en una rama, cambiar a otra rama más tarde e intentar volver a aplicar los cambios. También puede
tener archivos modificados y no confirmados en su directorio de trabajo cuando aplica un alijo: Git le brinda conflictos
de combinación en todo caso.
234
Machine Translated by Google
ya no se aplica limpiamente.
Los cambios en sus archivos se volvieron a aplicar, pero el archivo que preparó antes no se volvió a preparar.
Para hacer eso, debe ejecutar el comando git stash apply con una opción --index para indicarle al comando que
intente volver a aplicar los cambios por etapas. Si hubiera ejecutado eso en su lugar, habría vuelto a su posición
original:
modificado: index.html
modificado: lib/simplegit.rb
La opción de aplicar solo intenta aplicar el trabajo guardado: continúa teniéndolo en su pila. Para eliminarlo,
puede ejecutar git stash drop con el nombre del alijo que desea eliminar:
También puede ejecutar git stash pop para aplicar el alijo y luego soltarlo inmediatamente de su pila.
Almacenamiento creativo
Hay algunas variantes ocultas que también pueden ser útiles. La primera opción que es bastante popular es la
opción --keep-index del comando git stash . Esto le dice a Git que no solo incluya todo el contenido en etapas en
el alijo que se está creando, sino que lo deje simultáneamente en el índice.
235
Machine Translated by Google
$ git status -s M
index.html
M lib/simplegit.rb
$ git status -s M
index.html
Otra cosa común que puede querer hacer con el almacenamiento oculto es esconder los archivos sin rastrear, así
como los rastreados. De forma predeterminada, git stash solo almacenará archivos rastreados modificados y
preparados. Si especifica --include-untracked o -u, Git incluirá archivos sin seguimiento en el alijo que se está creando.
Sin embargo, incluir archivos sin seguimiento en el alijo no incluirá archivos explícitamente ignorados ; para incluir
adicionalmente archivos ignorados, use --all (o simplemente -a).
$ git status -s M
index.html M lib/
simplegit.rb ?? nuevo-
archivo.txt
$ git alijo -u
Directorio de trabajo guardado y WIP de estado de índice en maestro: 1b65b17 agregó el archivo de índice
HEAD ahora está en 1b65b17 agregó el archivo de índice
$ git estado -s $
Finalmente, si especifica el indicador --patch , Git no ocultará todo lo que se modifique, sino que le preguntará de
forma interactiva cuáles de los cambios desea ocultar y cuáles desea mantener en su directorio de trabajo.
236
Machine Translated by Google
+
+ def mostrar (árbol = 'maestro')
+ comando("mostrar git #{treeish}") fin
+
final
test
Stash this hunk [y,n,q,a,d,/,e,?]? y
Directorio de trabajo guardado y WIP de estado de índice en maestro: 1b65b17 agregó el archivo de índice
Si oculta algún trabajo, déjelo allí por un tiempo y continúe en la rama desde la que escondió el trabajo,
es posible que tenga problemas para volver a aplicar el trabajo. Si la aplicación intenta modificar un
archivo que ya modificó, obtendrá un conflicto de fusión y tendrá que intentar resolverlo. Si desea una
forma más fácil de probar los cambios ocultos nuevamente, puede ejecutar git stash branch <nuevo
nombre de la rama>, que crea una nueva rama para usted con el nombre de la rama seleccionada,
comprueba la confirmación en la que estaba cuando escondió su trabajo, vuelve a aplicar su trabajo allí
y luego suelta el alijo si se aplica con éxito:
modificado: index.html
modificado: lib/simplegit.rb
237
Machine Translated by Google
Este es un buen atajo para recuperar fácilmente el trabajo guardado y trabajar en él en una nueva rama.
Algunas razones comunes para limpiar su directorio de trabajo pueden ser eliminar el cruft generado por fusiones o
herramientas externas o eliminar artefactos de compilación para ejecutar una compilación limpia.
Deberá tener mucho cuidado con este comando, ya que está diseñado para eliminar archivos de su directorio de trabajo que
no se rastrean. Si cambia de opinión, a menudo no es posible recuperar el contenido de esos archivos. Una opción más
segura es ejecutar git stash --all para eliminar todo pero guardarlo en un alijo.
Suponiendo que desea eliminar archivos cruft o limpiar su directorio de trabajo, puede hacerlo con git clean. Para eliminar
todos los archivos no rastreados en su directorio de trabajo, puede ejecutar git clean -f -d, que elimina cualquier archivo y
también cualquier subdirectorio que quede vacío como resultado. El -f significa 'forzar' o "realmente hacer esto", y es
obligatorio si la variable de configuración de Git clean.requireForce no se establece explícitamente en false.
Si alguna vez quiere ver lo que haría, puede ejecutar el comando con la opción --dry-run (o -n) , que significa "haga una
prueba y dígame qué habría eliminado".
$ git clean -d -n
Quitaría test.o
Quitaría tmp/
De forma predeterminada, el comando git clean solo eliminará los archivos sin seguimiento que no se ignoren. Cualquier
archivo que coincida con un patrón en su .gitignore u otros archivos ignorados no se eliminará. Si también desea eliminar
esos archivos, como eliminar todos los archivos .o generados a partir de una compilación para que pueda hacer una
compilación completamente limpia, puede agregar -x al comando de limpieza.
$ git status -s M
lib/simplegit.rb ??
construir.TMP
?? tmp/
$ git clean -n -d
Eliminaría build.TMP
Quitaría tmp/
$ git clean -n -d -x
Eliminaría build.TMP
Quitaría test.o
Quitaría tmp/
Si no sabe qué va a hacer el comando git clean , siempre ejecútelo con -n primero para duplicar
238
Machine Translated by Google
verifique antes de cambiar el -n a -f y hacerlo de verdad. La otra forma en que puede tener cuidado con el proceso es
ejecutarlo con el indicador -i o "interactivo".
$ git clean -x -i
Eliminaría los siguientes elementos:
build.TMP test.o *** Comandos ***
6: ayuda 5: salir
¿Y ahora qué?
De esta manera, puede recorrer cada archivo individualmente o especificar patrones para eliminar de forma interactiva.
Existe una situación peculiar en la que es posible que deba ser más contundente al pedirle a Git que
limpie su directorio de trabajo. Si se encuentra en un directorio de trabajo en el que ha copiado o
ÿ clonado otros repositorios de Git (quizás como submódulos), incluso git clean -fd se negará a eliminar
esos directorios. En casos como ese, debe agregar una segunda opción -f para enfatizar.
Firmar su trabajo
Git es criptográficamente seguro, pero no es infalible. Si acepta el trabajo de otros en Internet y desea verificar que las
confirmaciones provienen realmente de una fuente confiable, Git tiene algunas formas de firmar y verificar el trabajo con
GPG.
GPG Introducción
En primer lugar, si desea firmar algo, debe configurar GPG e instalar su clave personal.
Si no tiene una clave instalada, puede generar una con gpg --gen-key.
$ gpg --gen-clave
Una vez que tenga una clave privada para iniciar sesión, puede configurar Git para que la use para firmar cosas configurando la
configuración de configuración de user.signingkey .
239
Machine Translated by Google
Ahora Git usará su clave de forma predeterminada para firmar etiquetas y confirmaciones si lo desea.
Etiquetas de firma
Si tiene una clave privada GPG configurada, ahora puede usarla para firmar nuevas etiquetas. Todo lo que tienes que hacer es usar -s
en lugar de -a:
Si ejecuta git show en esa etiqueta, puede ver su firma GPG adjunta:
iQEcBAABAgAGBQJTZbQlAAoJEF0+sviABDDrZbQH/09PfE51KPVPlanr6q1v4/Ut
LQxfojUWiLQdg2ESJItkcuweYg + kc3HCyFejeDIBw9dpXt00rY26p05qrpnG + 85b hM1 /
PswpPLuBSr + oCIDj5GMC2r2iEKsfv2fJbNW8iWAXVLoWZRF8B0MfqX / YTMbm
ecorc4iXzQu7tupRihslbNkfvfciMnSDeSvzCpWAHl7h8Wj6hhqePmLm9lAYqnKp
8S5B/1SSQuEAjRZgI4IexpZoeKGVDptPHxLLS38fozsyi0QyDyzEgJxcJQVMXxVi
RUysgqjcpT8+iQM1PblGfHR4XAhuOqN5Fx06PSaFZhqvWFezJ28/CLyX5q+oIVk=
=EFTF
-----FINALIZAR FIRMA DE PGP-----
Verificación de etiquetas
Para verificar una etiqueta firmada, usa git tag -v <tag-name>. Este comando usa GPG para verificar la firma. Necesita la clave pública
del firmante en su conjunto de claves para que esto funcione correctamente:
240
Machine Translated by Google
GIT 1.4.2.1
Correcciones menores desde 1.4.2, incluidos git-mv y git-http con alternativas. gpg: Firma
realizada el miércoles 13 de septiembre 02:08:25 PDT de 2006 usando la clave DSA ID F3119B9A
gpg: Buena firma de "Junio C Hamano <junkio@cox.net>" también conocido como "[imagen jpeg de
gpg: tamaño 1513]"
Huella digital de clave principal: 3565 2A26 2040 E066 C9A7 4A7D C0C6 D9A4 F311 9B9A
gpg: Firma realizada el miércoles 13 de septiembre 02:08:25 PDT de 2006 con el ID de clave DSA
F3119B9A gpg: No se puede verificar la firma: clave pública no encontrada error: no se pudo
verificar la etiqueta 'v1.4.2.1'
Confirmaciones de firma
En las versiones más recientes de Git (v1.7.9 y superiores), ahora también puede firmar confirmaciones individuales. Si está
interesado en firmar confirmaciones directamente en lugar de solo las etiquetas, todo lo que necesita hacer es agregar una -S
a su comando de confirmación de git .
Para ver y verificar estas firmas, también hay una opción --show-signature para git log.
241
Machine Translated by Google
compromiso firmado
Además, puede configurar git log para verificar las firmas que encuentre y enumerarlas en su salida con el %G? formato.
Aquí podemos ver que solo la última confirmación está firmada y es válida y las confirmaciones anteriores no lo son.
En Git 1.8.3 y versiones posteriores, se puede indicar a git merge y git pull que inspeccionen y rechacen al fusionar
una confirmación que no lleva una firma GPG confiable con el comando --verify-signatures .
Si usa esta opción al fusionar una rama y contiene confirmaciones que no están firmadas ni son válidas, la fusión no
funcionará.
Si la fusión contiene solo confirmaciones firmadas válidas, el comando de fusión le mostrará todas las firmas que ha
verificado y luego avanzará con la fusión.
También puede usar la opción -S con el comando git merge para firmar la confirmación de combinación resultante. El
siguiente ejemplo verifica que cada compromiso en la rama que se fusionará esté firmado y, además, firma el
compromiso de fusión resultante.
242
Machine Translated by Google
buscando
Con una base de código de casi cualquier tamaño, a menudo necesitará encontrar dónde se llama o define una
función, o mostrar el historial de un método. Git proporciona un par de herramientas útiles para revisar el código y las
confirmaciones almacenadas en su base de datos de forma rápida y sencilla. Revisaremos algunos de ellos.
GitGrep
Git viene con un comando llamado grep que le permite buscar fácilmente a través de cualquier árbol confirmado, el
directorio de trabajo o incluso el índice de una cadena o expresión regular. Para los ejemplos que siguen, buscaremos
en el código fuente de Git.
De forma predeterminada, git grep buscará en los archivos de su directorio de trabajo. Como primera variación, puede
usar cualquiera de las opciones -n o --line-number para imprimir los números de línea donde Git ha encontrado
coincidencias:
243
Machine Translated by Google
if (gmtime_r(&now, &now_tm)) if
(gmtime_r(&time, tm)) { date.c:758: /
* gmtime_r() in match_digit() puede haberlo aplastado
compat-util.h:1138: */ git- tm *git_gmtime_r(const time_t *,
estructura
estructura tm *); git-compat-util.h:1140:#define gmtime_r git_gmtime_r
Además de la búsqueda básica que se muestra arriba, git grep admite una gran cantidad de otras opciones
interesantes.
Por ejemplo, en lugar de imprimir todas las coincidencias, puede pedirle a git grep que resuma la salida
mostrándole solo qué archivos contenían la cadena de búsqueda y cuántas coincidencias había en cada archivo
con la opción -c o --count :
git-compat-util.h:2
Si está interesado en el contexto de una cadena de búsqueda, puede mostrar el método o función adjunto para
cada cadena coincidente con cualquiera de las opciones -p o --show-function :
Como puede ver, la rutina gmtime_r se llama desde las funciones match_multi_number y match_digit en el
archivo date.c (la tercera coincidencia mostrada representa solo la cadena que aparece en un comentario).
También puede buscar combinaciones complejas de cadenas con el indicador --and , lo que garantiza que se
produzcan varias coincidencias en la misma línea de texto. Por ejemplo, busquemos cualquier línea que defina
una constante cuyo nombre contenga cualquiera de las subcadenas "LINK" o "BUF_MAX", específicamente en
una versión anterior del código base de Git representado por la etiqueta v1.8.0 (agregaremos la --romper y
244
Machine Translated by Google
v1.8.0: caché.h
73:#definir S_IFGITLINK 0160000
74:#definir S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
v1.8.0:entorno.c
54:#definir OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
v1.8.0:strbuf.c
326: #define STRBUF_MAXLINK (2*PATH_MAX)
v1.8.0:enlaces
simbólicos.c 53:#define FL_SYMLINK (1 << 2)
v1.8.0:zlib.c 30:/
* #define ZLIB_BUF_MAX ((uInt)-1) */ 31:#define
ZLIB_BUF_MAX ((uInt) 1024 * 1024 * 1024) /* 1GB */
El comando git grep tiene algunas ventajas sobre los comandos de búsqueda normales como grep y ack.
La primera es que es muy rápido, la segunda es que puedes buscar en cualquier árbol de Git, no solo en el
directorio de trabajo. Como vimos en el ejemplo anterior, buscamos términos en una versión anterior del código
fuente de Git, no en la versión que estaba actualmente desprotegida.
Tal vez no esté buscando dónde existe un término, sino cuándo existió o se introdujo. El comando git log tiene
varias herramientas poderosas para encontrar confirmaciones específicas por el contenido de sus mensajes o
incluso el contenido de la diferencia que introducen.
Si, por ejemplo, queremos averiguar cuándo se introdujo originalmente la constante ZLIB_BUF_MAX , podemos
usar la opción -S (coloquialmente conocida como la opción "pickaxe" de Git) para decirle a Git que nos muestre
solo las confirmaciones que cambiaron el número. de ocurrencias de esa cadena.
Si observamos la diferencia de esos compromisos, podemos ver que en ef49a7a se introdujo la constante y en
e01503b se modificó.
Si necesita ser más específico, puede proporcionar una expresión regular para buscar con la opción -G .
245
Machine Translated by Google
Otra búsqueda de registro bastante avanzada que es increíblemente útil es la búsqueda de historial de línea.
Simplemente ejecute git log con la opción -L y le mostrará el historial de una función o línea de código en su
base de código.
Por ejemplo, si quisiéramos ver todos los cambios realizados en la función git_deflate_bound en el archivo
zlib.c , podríamos ejecutar git log -L :git_deflate_bound:zlib.c. Esto intentará descubrir cuáles son los límites de
esa función y luego revisará el historial y nos mostrará cada cambio que se realizó en la función como una serie
de parches que se remontan a cuando se creó la función por primera vez.
-
return deflateBound(strm, tamaño);
+ return deflateBound(&strm->z, tamaño);
}
commit 225a6f1068f71723a910e8565db4e252b3ca21fa
Autor: Junio C Hamano <gitster@pobox.com> Fecha:
Vie Jun 10 11:18:17 2011 -0700
@@ -81,0 +85,5
@@ +largo sin firmar git_deflate_bound(z_streamp strm, tamaño largo sin
firmar) +{
+ return deflateBound(strm, tamaño);
+}
+
Si Git no puede averiguar cómo hacer coincidir una función o método en su lenguaje de programación, también
puede proporcionarle una expresión regular (o regex). Por ejemplo, esto habría hecho lo mismo que el ejemplo
anterior: git log -L '/unsigned long git_deflate_bound/',/^}/:zlib.c. También puede darle un rango de líneas o un
solo número de línea y obtendrá el mismo tipo de salida.
246
Machine Translated by Google
Reescribiendo la historia
Muchas veces, al trabajar con Git, es posible que desee revisar su historial de confirmación local. Una de las mejores
cosas de Git es que te permite tomar decisiones en el último momento posible. Puede decidir qué archivos van en qué
confirmaciones justo antes de confirmar con el área de preparación, puede decidir que no tenía la intención de trabajar
en algo todavía con git stash, y puede reescribir las confirmaciones que ya sucedieron para que parezcan sucedió de
una manera diferente. Esto puede implicar cambiar el orden de las confirmaciones, cambiar mensajes o modificar
archivos en una confirmación, agrupar o dividir confirmaciones, o eliminar confirmaciones por completo, todo antes de
compartir su trabajo con otros.
En esta sección, verá cómo realizar estas tareas para que pueda hacer que su historial de confirmaciones tenga el
aspecto que desea antes de compartirlo con otros.
Una de las reglas cardinales de Git es que, dado que gran parte del trabajo es local dentro de su
clon, tiene mucha libertad para reescribir su historia localmente. Sin embargo, una vez que empujas
ÿ tu trabajo, es una historia completamente diferente, y debes considerar el trabajo empujado como
definitivo a menos que tengas una buena razón para cambiarlo. En resumen, debe evitar presionar
su trabajo hasta que esté satisfecho con él y listo para compartirlo con el resto del mundo.
El comando anterior carga el mensaje de confirmación anterior en una sesión de editor, donde puede realizar cambios
en el mensaje, guardar esos cambios y salir. Cuando guarda y cierra el editor, el editor escribe una nueva confirmación
que contiene ese mensaje de confirmación actualizado y lo convierte en su nueva última confirmación.
Si, por otro lado, desea cambiar el contenido real de su última confirmación, el proceso funciona básicamente de la
misma manera: primero haga los cambios que cree que olvidó, organice esos cambios y la subsiguiente confirmación
de git --amend reemplaza eso última confirmación con su nueva confirmación mejorada.
Debe tener cuidado con esta técnica porque la modificación cambia el SHA-1 de la confirmación. Es como una
reorganización muy pequeña: no modifiques tu última confirmación si ya la has enviado.
247
Machine Translated by Google
ÿ Por otro lado, si sus enmiendas son suficientemente triviales (corregir un error tipográfico tonto
o agregar un archivo que olvidó preparar) de modo que el mensaje de confirmación anterior
esté bien, simplemente puede hacer los cambios, prepararlos y evitar el editor innecesario.
sesión íntegramente con:
Para modificar una confirmación que está más atrás en su historial, debe pasar a herramientas más complejas. Git
no tiene una herramienta de historial de modificación, pero puede usar la herramienta de reorganización para
reorganizar una serie de confirmaciones en el HEAD en el que se basaron originalmente en lugar de moverlas a
otra. Con la herramienta de reorganización interactiva, puede detenerse después de cada confirmación que desee
modificar y cambiar el mensaje, agregar archivos o hacer lo que desee. Puede ejecutar rebase de forma interactiva
agregando la opción -i a git rebase. Debe indicar cuánto tiempo atrás desea reescribir las confirmaciones diciéndole
al comando en qué confirmación se debe reorganizar.
Por ejemplo, si desea cambiar los últimos tres mensajes de confirmación, o cualquiera de los mensajes de
confirmación en ese grupo, proporcione como argumento a git rebase -i el padre de la última confirmación que
desea editar, que es HEAD~2 ^ o CABEZA~3. Puede ser más fácil recordar el ~3 porque está tratando de editar
las últimas tres confirmaciones, pero tenga en cuenta que en realidad está designando hace cuatro confirmaciones,
el padre de la última confirmación que desea editar:
Recuerde nuevamente que este es un comando de reorganización: cada confirmación en el rango HEAD~3..HEAD
con un mensaje modificado y todos sus descendientes serán reescritos. No incluya ninguna confirmación que ya
haya enviado a un servidor central; hacerlo confundirá a otros desarrolladores al proporcionar una versión alternativa
del mismo cambio.
Ejecutar este comando le brinda una lista de confirmaciones en su editor de texto que se parece a esto:
248
Machine Translated by Google
Es importante tener en cuenta que estas confirmaciones se enumeran en el orden opuesto al que normalmente las ve con
el comando de registro . Si ejecuta un registro, verá algo como esto:
Observe el orden inverso. La reorganización interactiva le brinda un script que se ejecutará. Comenzará en la confirmación
que especifique en la línea de comando (HEAD~3) y reproducirá los cambios introducidos en cada una de estas
confirmaciones de arriba a abajo. Enumera el más antiguo en la parte superior, en lugar del más nuevo, porque ese es el
primero que se reproducirá.
Debe editar el script para que se detenga en la confirmación que desea editar. Para hacerlo, cambie la palabra "elegir" a la
palabra "editar" para cada una de las confirmaciones después de las cuales desea que el script se detenga. Por ejemplo,
para modificar solo el tercer mensaje de confirmación, cambie el archivo para que se vea así:
249
Machine Translated by Google
Cuando guarda y sale del editor, Git lo rebobina hasta la última confirmación en esa lista y lo deja en la línea de
comando con el siguiente mensaje:
Este comando aplicará las otras dos confirmaciones automáticamente, y luego habrá terminado. Si cambia la selección
para editar en más líneas, puede repetir estos pasos para cada confirmación que cambie para editar. Cada vez, Git se
detendrá, le permitirá modificar la confirmación y continuar cuando haya terminado.
Reordenación de confirmaciones
También puede usar rebases interactivos para reordenar o eliminar confirmaciones por completo. Si desea eliminar el
compromiso "Agregar archivo cat" y cambiar el orden en que se introducen los otros dos compromisos, puede cambiar
el script de rebase de esto:
a esto:
250
Machine Translated by Google
Cuando guarda y sale del editor, Git rebobina su rama al padre de estas confirmaciones, aplica 310154e y
luego f7f3f6d, y luego se detiene. Efectivamente, cambia el orden de esas confirmaciones y elimina la
confirmación "Agregar archivo cat" por completo.
Compromisos de aplastamiento
También es posible tomar una serie de confirmaciones y agruparlas en una única confirmación con la
herramienta de reorganización interactiva. El script pone instrucciones útiles en el mensaje de rebase:
#
# Comandos:
# Estas líneas se pueden reordenar; se ejecutan de arriba hacia abajo. # # Si elimina una línea aquí,
ESE COMPROMISO SE PERDERÁ. #
# Sin embargo, si elimina todo, la reorganización se anulará. # # Tenga en cuenta que las
confirmaciones vacías están comentadas
Si, en lugar de "seleccionar" o "editar", especifica "aplastar", Git aplica tanto ese cambio como el cambio
directamente anterior y hace que fusione los mensajes de confirmación. Entonces, si desea hacer una sola
confirmación de estas tres confirmaciones, haga que el script se vea así:
Cuando guarda y sale del editor, Git aplica los tres cambios y luego lo vuelve a colocar en el editor para
fusionar los tres mensajes de confirmación:
251
Machine Translated by Google
Cuando guardas eso, tienes una única confirmación que introduce los cambios de las tres confirmaciones anteriores.
Dividir una confirmación deshace una confirmación y luego realiza una etapa parcial y confirma tantas veces como
confirmaciones desee terminar. Por ejemplo, suponga que desea dividir la confirmación del medio de sus tres
confirmaciones. En lugar de "Actualizar el formato LÉAME y agregar culpa", desea dividirlo en dos confirmaciones:
"Actualizar el formato LÉAME" para el primero y "Agregar culpa" para el segundo. Puede hacerlo en el script rebase -i
cambiando la instrucción en la confirmación que desea dividir para "editar":
Luego, cuando el script lo lleva a la línea de comando, restablece ese compromiso, toma los cambios que se han
restablecido y crea múltiples compromisos a partir de ellos. Cuando guardas y sales del editor, Git rebobina hasta el padre
de la primera confirmación de tu lista, aplica la primera confirmación (f7f3f6d), aplica la segunda (310154e) y te lleva a la
consola. Allí, puede hacer un restablecimiento mixto de esa confirmación con git reset HEAD^, que efectivamente deshace
esa confirmación y deja los archivos modificados sin preparar. Ahora puede organizar y confirmar archivos hasta que
tenga varias confirmaciones y ejecutar git rebase --continúe cuando haya terminado:
252
Machine Translated by Google
Esto cambia los SHA-1 de las tres confirmaciones más recientes en su lista, así que asegúrese de que no aparezca
ninguna confirmación modificada en esa lista que ya haya enviado a un repositorio compartido. Observe que la última
confirmación (f7f3f6d) de la lista no ha cambiado. A pesar de que esta confirmación se muestra en el script, debido a
que se marcó como "elegir" y se aplicó antes de cualquier cambio de reorganización, Git deja la confirmación sin
modificar.
Eliminación de un compromiso
Si desea deshacerse de una confirmación, puede eliminarla usando el script rebase -i . En la lista de confirmaciones,
coloque la palabra "soltar" antes de la confirmación que desea eliminar (o simplemente elimine esa línea del script de
rebase):
Debido a la forma en que Git crea los objetos de confirmación, eliminar o modificar una confirmación provocará la
reescritura de todas las confirmaciones que le siguen. Cuanto más retroceda en el historial de su repositorio, más
confirmaciones deberán recrearse. Esto puede causar muchos conflictos de combinación si tiene muchas confirmaciones
más adelante en la secuencia que dependen de la que acaba de eliminar.
Si llega a la mitad de una rebase como esta y decide que no es una buena idea, siempre puede detenerse.
Escribe git rebase --abort, y tu repositorio volverá al estado en el que estaba antes de que comenzaras el rebase.
Si termina una reorganización y decide que no es lo que desea, puede usar git reflog para recuperar una versión anterior
de su rama. Consulte Recuperación de datos para obtener más información sobre el comando reflog .
253
Machine Translated by Google
Esto ocurre con bastante frecuencia. Alguien accidentalmente envía un archivo binario enorme con un agregado
., una contraseña
de git desconsiderado y desea eliminarlo
y desea que de todas partes.
su proyecto Talcódigo
sea de vez accidentalmente envió es
abierto. filter-branch un la
archivo que contenía
herramienta que
probablemente quieras usar para borrar todo tu historial. Para eliminar un archivo llamado contraseñas.txt de
todo su historial, puede usar la opción --tree-filter para filtrar la rama:
La opción --tree-filter ejecuta el comando especificado después de cada pago del proyecto y luego vuelve a
confirmar los resultados. En este caso, elimina un archivo llamado contraseñas.txt de cada instantánea, ya sea
que exista o no. Si desea eliminar todos los archivos de respaldo del editor comprometidos accidentalmente,
puede ejecutar algo como git filter-branch --tree-filter 'rm -f *~' HEAD.
Podrás ver a Git reescribiendo árboles y confirmaciones y luego mover el puntero de rama al final. Por lo general,
es una buena idea hacer esto en una rama de prueba y luego reiniciar la rama maestra después de haber
determinado que el resultado es lo que realmente desea. Para ejecutar filter-branch en todas sus sucursales,
puede pasar --all al comando.
Suponga que ha realizado una importación desde otro sistema de control de código fuente y tiene subdirectorios
que no tienen sentido (troncal, etiquetas, etc.). Si desea que el subdirectorio troncal sea la nueva raíz del proyecto
para cada confirmación, filter-branch también puede ayudarlo a hacerlo:
Ahora su nueva raíz del proyecto es lo que estaba en el subdirectorio troncal cada vez. Git también eliminará
automáticamente las confirmaciones que no afectaron al subdirectorio.
Otro caso común es que olvidó ejecutar git config para configurar su nombre y dirección de correo electrónico
antes de comenzar a trabajar, o tal vez desee abrir un proyecto en el trabajo y cambiar todas las direcciones de
correo electrónico de su trabajo a su dirección personal. En cualquier caso, también puede cambiar las direcciones
de correo electrónico en varias confirmaciones en un lote con filter-branch . Debe tener cuidado de cambiar sólo el
254
Machine Translated by Google
direcciones de correo electrónico que son suyas, por lo que usa --commit-filter:
'
$ git filter-branch --commit-filter if
ÿ
[ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
ÿ
luego
ÿ
GIT_AUTHOR_NAME="Scott Chacón";
ÿ
GIT_AUTHOR_EMAIL="schacon@ejemplo.com";
ÿ
demás
Fi' CABEZA
Esto pasa y reescribe cada compromiso para tener su nueva dirección. Porque las confirmaciones contienen
los valores SHA-1 de sus padres, este comando cambia cada confirmación SHA-1 en su historial, no
solo aquellos que tienen la dirección de correo electrónico correspondiente.
Restablecer Desmitificado
Antes de pasar a herramientas más especializadas, hablemos de los comandos de restablecimiento y pago de Git.
Estos comandos son dos de las partes más confusas de Git cuando los encuentras por primera vez. Ellos
hacer tantas cosas que parece inútil entenderlas realmente y emplearlas adecuadamente.
Para ello, recomendamos una simple metáfora.
Árbol Papel
La cabeza
HEAD es el puntero a la referencia de rama actual, que a su vez es un puntero a la última confirmación
hecho en esa rama. Eso significa que HEAD será el padre de la próxima confirmación que se cree. Es
por lo general, lo más sencillo es pensar en HEAD como la instantánea de tu última confirmación en esa rama.
De hecho, es bastante fácil ver cómo se ve esa instantánea. Aquí hay un ejemplo de obtener el real
lista de directorios y sumas de verificación SHA-1 para cada archivo en la instantánea HEAD:
255
Machine Translated by Google
Compromiso inicial
Los comandos cat-file y ls-tree de Git son comandos de "plomería" que se usan para cosas de nivel inferior y no se usan
realmente en el trabajo diario, pero nos ayudan a ver qué está pasando aquí.
El índice
El índice es su próxima confirmación propuesta. También nos hemos estado refiriendo a este concepto como el "Área de
preparación" de Git, ya que esto es lo que Git mira cuando ejecutas git commit.
Git completa este índice con una lista de todos los contenidos de los archivos que se desprotegieron por última vez en su
directorio de trabajo y cómo se veían cuando se desprotegieron originalmente. Luego reemplaza algunos de esos archivos
con nuevas versiones de ellos, y git commit lo convierte en el árbol para una nueva confirmación.
Nuevamente, aquí estamos usando git ls-files, que es más un comando detrás de escena que le muestra cómo se ve su índice
actualmente.
El índice no es técnicamente una estructura de árbol, en realidad se implementa como un manifiesto aplanado, pero para
nuestros propósitos es lo suficientemente parecido.
El directorio de trabajo
Finalmente, tiene su directorio de trabajo (también conocido comúnmente como el "árbol de trabajo"). Los otros dos árboles
almacenan su contenido de manera eficiente pero inconveniente, dentro de la carpeta .git .
El directorio de trabajo los desempaqueta en archivos reales, lo que hace que sea mucho más fácil editarlos. Piense en el
directorio de trabajo como una caja de arena, donde puede probar los cambios antes de enviarlos a su área de ensayo (índice)
y luego al historial.
256
Machine Translated by Google
$ árbol
.
ÿÿÿ LÉAME
ÿÿÿ Rakefile ÿÿÿ
lib
ÿÿÿ
ÿ
simplegit.rb
1 directorio, 3 archivos
El flujo de trabajo
El flujo de trabajo típico de Git es registrar instantáneas de su proyecto en estados sucesivamente mejores, mediante
la manipulación de estos tres árboles.
Visualicemos este proceso: supongamos que ingresa a un nuevo directorio con un solo archivo. Llamaremos a esto
v1 del archivo, y lo indicaremos en azul. Ahora ejecutamos git init, que creará un repositorio Git con una referencia
HEAD que apunta a la rama maestra no nacida.
257
Machine Translated by Google
Ahora queremos confirmar este archivo, por lo que usamos git add para tomar contenido en el directorio de trabajo
y copiarlo en el índice.
258
Machine Translated by Google
Luego ejecutamos git commit, que toma el contenido del índice y lo guarda como una instantánea permanente,
crea un objeto de confirmación que apunta a esa instantánea y actualiza el maestro para que apunte a esa
confirmación.
259
Machine Translated by Google
Si ejecutamos git status, no veremos cambios, porque los tres árboles son iguales.
Ahora queremos hacer un cambio en ese archivo y confirmarlo. Pasaremos por el mismo proceso; primero,
cambiamos el archivo en nuestro directorio de trabajo. Llamemos a esto v2 del archivo, e indíquelo en rojo.
260
Machine Translated by Google
Si ejecutamos git status en este momento, veremos el archivo en rojo como "Cambios no preparados para confirmación",
porque esa entrada difiere entre el índice y el directorio de trabajo. A continuación, ejecutamos git add en él para colocarlo
en nuestro índice.
261
Machine Translated by Google
En este punto, si ejecutamos git status, veremos el archivo en verde debajo de "Cambios por confirmar" porque el
índice y HEAD difieren, es decir, nuestra próxima confirmación propuesta ahora es diferente de nuestra última
confirmación. Finalmente, ejecutamos git commit para finalizar la confirmación.
262
Machine Translated by Google
Ahora , el estado de git no nos dará ningún resultado, porque los tres árboles vuelven a ser iguales.
Cambiar de rama o clonar pasa por un proceso similar. Cuando revisa una rama, cambia HEAD para apuntar a la nueva
referencia de rama, completa su índice con la instantánea de esa confirmación y luego copia el contenido del índice en
su directorio de trabajo.
Para los propósitos de estos ejemplos, digamos que modificamos file.txt nuevamente y lo confirmamos por tercera vez.
Así que ahora nuestra historia se ve así:
263
Machine Translated by Google
Ahora analicemos exactamente qué hace el restablecimiento cuando lo llama. Manipula directamente estos tres árboles
de una manera simple y predecible. Realiza hasta tres operaciones básicas.
Lo primero que hará el reinicio es mover lo que apunta HEAD. Esto no es lo mismo que cambiar HEAD (que es lo que
hace el proceso de pago ); reset mueve la rama a la que apunta HEAD. Esto significa que si HEAD está configurado en
la rama maestra (es decir, actualmente está en la rama maestra ), la ejecución de git reset 9e5e6a4 comenzará haciendo
que el punto maestro sea 9e5e6a4.
264
Machine Translated by Google
No importa qué forma de reinicio con un compromiso invoques, esto es lo primero que siempre intentará hacer.
Con reset --soft, simplemente se detendrá allí.
Ahora tómese un segundo para mirar ese diagrama y darse cuenta de lo que sucedió: esencialmente deshizo
el último comando de confirmación de git . Cuando ejecutas git commit, Git crea un nuevo commit y mueve la
rama a la que apunta HEAD. Cuando restablece de nuevo a HEAD~ (el padre de HEAD), está moviendo la
rama de regreso a donde estaba, sin cambiar el índice o el directorio de trabajo. Ahora puede actualizar el
índice y ejecutar git commit nuevamente para lograr lo que hubiera hecho git commit --amend (consulte Cambio
de la última confirmación).
Tenga en cuenta que si ejecuta git status ahora, verá en verde la diferencia entre el índice y el nuevo HEAD.
Lo siguiente que hará el reinicio es actualizar el índice con el contenido de cualquier instantánea a la que
ahora apunta HEAD.
265
Machine Translated by Google
Si especifica la opción --mixed , el restablecimiento se detendrá en este punto. Este también es el valor predeterminado, por lo
que si no especifica ninguna opción (simplemente reinicie HEAD~ en este caso), aquí es donde se detendrá el comando.
Ahora tómese otro segundo para mirar ese diagrama y darse cuenta de lo que sucedió: todavía deshizo su última confirmación,
pero también quitó todo. Regresó a antes de ejecutar todos sus comandos git add y git commit .
Lo tercero que hará el reinicio es hacer que el directorio de trabajo se vea como el índice. Si usa la opción --hard , continuará
hasta esta etapa.
266
Machine Translated by Google
Así que pensemos en lo que acaba de pasar. Deshiciste tu última confirmación, los comandos git add y git commit , y todo el trabajo que hiciste en
tu directorio de trabajo.
Es importante tener en cuenta que esta marca (--hard) es la única forma de hacer que el comando de reinicio sea peligroso y uno de los pocos
casos en los que Git realmente destruirá los datos. Cualquier otra invocación de reinicio se puede deshacer con bastante facilidad, pero la opción --
hard no, ya que sobrescribe a la fuerza los archivos en el directorio de trabajo. En este caso particular, todavía tenemos la versión v3 de nuestro
archivo en una confirmación en nuestra base de datos de Git, y podríamos recuperarla mirando nuestro reflog, pero si no la hubiéramos confirmado,
Resumen
El comando de reinicio sobrescribe estos tres árboles en un orden específico y se detiene cuando se lo indica:
2. Haga que el índice se vea como HEAD (deténgase aquí a menos que --hard).
267
Machine Translated by Google
Eso cubre el comportamiento del reinicio en su forma básica, pero también puede proporcionarle un camino para
actuar. Si especifica una ruta, el restablecimiento omitirá el paso 1 y limitará el resto de sus acciones a un archivo o
conjunto de archivos específico. En realidad, esto tiene sentido: HEAD es solo un puntero, y no puede señalar parte
de una confirmación y parte de otra. Pero el índice y el directorio de trabajo se pueden actualizar parcialmente, por
lo que el restablecimiento continúa con los pasos 2 y 3.
Entonces, supongamos que ejecutamos git reset file.txt. Este formulario (ya que no especificó un compromiso
SHA-1 o rama, y no especificó --soft o --hard) es una abreviatura de git reset --mixed HEAD file.txt, que hará lo
siguiente:
Esto tiene el efecto práctico de desorganizar el archivo. Si miramos el diagrama de ese comando y pensamos en lo
que hace git add , son exactamente opuestos.
268
Machine Translated by Google
Esta es la razón por la que la salida del comando git status sugiere que ejecute esto para eliminar un archivo (consulte Desactivar un
archivo almacenado para obtener más información al respecto).
Podríamos fácilmente no dejar que Git asuma que queremos decir "extraer los datos de HEAD" especificando un compromiso específico
para extraer esa versión del archivo. Simplemente ejecutaríamos algo como git reset eb43bf file.txt.
269
Machine Translated by Google
Esto efectivamente hace lo mismo que si hubiéramos revertido el contenido del archivo a v1 en el directorio de
trabajo, ejecutado git add y luego revertido a v3 nuevamente (sin realmente seguir todos esos pasos). Si
ejecutamos git commit ahora, registrará un cambio que revertirá ese archivo a v1, aunque en realidad nunca lo
volvimos a tener en nuestro directorio de trabajo.
También es interesante notar que, al igual que git add, el comando de reinicio aceptará una opción --patch para
eliminar el contenido pieza por pieza. Por lo tanto, puede eliminar o revertir contenido de forma selectiva.
aplastamiento
Veamos cómo hacer algo interesante con este nuevo poder: aplastar confirmaciones.
Digamos que tiene una serie de confirmaciones con mensajes como "ups", "WIP" y "olvidé este archivo". Puede
usar el reinicio para agruparlos rápida y fácilmente en una sola confirmación que lo haga lucir realmente inteligente.
Squashing Commits muestra otra forma de hacer esto, pero en este ejemplo es más sencillo usar reset.
Digamos que tiene un proyecto donde la primera confirmación tiene un archivo, la segunda confirmación agregó
un nuevo archivo y cambió el primero, y la tercera confirmación cambió el primer archivo nuevamente. El segundo
compromiso fue un trabajo en progreso y desea aplastarlo.
270
Machine Translated by Google
Puede ejecutar git reset --soft HEAD~2 para mover la rama HEAD a una confirmación anterior (la confirmación
más reciente que desea conservar):
271
Machine Translated by Google
272
Machine Translated by Google
Ahora puede ver que su historial accesible, el historial que enviaría, ahora parece que tuvo una confirmación
con el archivo-a.txt v1, luego una segunda que modificó el archivo-a.txt a v3 y agregó el archivo b.txt. La
confirmación con la versión v2 del archivo ya no está en el historial.
Echale un vistazo
Finalmente, puede preguntarse cuál es la diferencia entre pagar y restablecer . Al igual que restablecer, el
proceso de pago manipula los tres árboles, y es un poco diferente dependiendo de si le da al comando una
ruta de archivo o no.
273
Machine Translated by Google
sin caminos
Ejecutar git checkout [branch] es bastante similar a ejecutar git reset --hard [branch] en el sentido de que actualiza los tres
árboles para que se vea como [branch], pero hay dos diferencias importantes.
Primero, a diferencia de reset --hard, checkout es seguro para el directorio de trabajo; verificará para asegurarse de que
no está eliminando los archivos que tienen cambios. En realidad, es un poco más inteligente que eso: intenta hacer una
combinación trivial en el directorio de trabajo, por lo que se actualizarán todos los archivos que no haya cambiado. reset --
hard, por otro lado, simplemente reemplazará todo en todos los ámbitos sin verificar.
La segunda diferencia importante es cómo el proceso de pago actualiza HEAD. Mientras que el restablecimiento moverá
la rama a la que apunta HEAD, el checkout moverá HEAD para que apunte a otra rama.
Por ejemplo, supongamos que tenemos ramas maestras y de desarrollo que apuntan a diferentes compromisos, y
actualmente estamos en desarrollo (entonces HEAD lo señala). Si ejecutamos git reset master, el desarrollo ahora
apuntará a la misma confirmación que hace master . Si, en cambio, ejecutamos git checkout master, el desarrollo no se
mueve, HEAD sí lo hace. HEAD ahora apuntará al maestro.
Entonces, en ambos casos estamos moviendo HEAD al punto de cometer A, pero la forma en que lo hacemos es muy
diferente. reset moverá los puntos HEAD de la rama, checkout mueve HEAD mismo.
con caminos
La otra forma de ejecutar el pago es con una ruta de archivo que, al igual que el restablecimiento, no mueve HEAD. Es
como el archivo git reset [branch] en el sentido de que actualiza el índice con ese archivo en ese compromiso, pero también
274
Machine Translated by Google
sobrescribe el archivo en el directorio de trabajo. Sería exactamente como git reset --hard [branch] file
(si el reinicio le permitiera ejecutar eso), no es seguro para el directorio de trabajo y no mueve HEAD.
Además, al igual que git reset y git add, el proceso de pago aceptará una opción --patch para permitirle seleccionar
revertir el contenido del archivo trozo a trozo.
Resumen
Esperemos que ahora entienda y se sienta más cómodo con el comando de reinicio , pero
probablemente todavía esté un poco confundido acerca de cómo difiere exactamente del proceso de pago y posiblemente no podría
recuerda todas las reglas de las diferentes invocaciones.
Aquí hay una hoja de trucos para saber qué comandos afectan a qué árboles. La columna "HEAD" dice "REF" si
ese comando mueve la referencia (rama) a la que apunta HEAD, y "HEAD" si mueve HEAD
sí mismo. Preste especial atención al 'WD Safe?' columna: si dice NO, tómese un segundo para pensar antes
ejecutando ese comando.
Nivel de compromiso
Nivel de archivo
Fusión avanzada
La fusión en Git suele ser bastante fácil. Dado que Git facilita la fusión de otra rama múltiple
veces, significa que puede tener una rama de larga duración pero puede mantenerla actualizada a medida que avanza,
resolver pequeños conflictos a menudo, en lugar de ser sorprendido por un gran conflicto al final de la
serie.
Sin embargo, a veces ocurren conflictos complicados. A diferencia de otros sistemas de control de versiones, Git no
No intente ser demasiado inteligente sobre la resolución de conflictos de fusión. La filosofía de Git es ser inteligente sobre
determinar cuándo una resolución de fusión es inequívoca, pero si hay un conflicto, no intenta ser
ingenioso para resolverlo automáticamente. Por lo tanto, si espera demasiado para fusionar dos ramas que
divergen rápidamente, puede encontrarse con algunos problemas.
En esta sección, repasaremos cuáles podrían ser algunos de esos problemas y qué herramientas te brinda Git para ayudarte.
manejar estas situaciones más difíciles. También cubriremos algunos de los diferentes tipos no estándar de
fusiones que puede hacer, así como ver cómo revertir las fusiones que ha hecho.
275
Machine Translated by Google
Fusionar conflictos
Si bien cubrimos algunos conceptos básicos sobre la resolución de conflictos de fusión en Conflictos de fusión básicos,
para conflictos más complejos, Git proporciona algunas herramientas para ayudarlo a descubrir qué está sucediendo y
cómo manejar mejor el conflicto.
En primer lugar, si es posible, intente asegurarse de que su directorio de trabajo esté limpio antes de realizar una
combinación que pueda tener conflictos. Si tiene trabajo en curso, confírmelo en una rama temporal o guárdelo. Esto hace
que puedas deshacer cualquier cosa que intentes aquí. Si tiene cambios sin guardar en su directorio de trabajo cuando
intenta una combinación, algunos de estos consejos pueden ayudarlo a conservar ese trabajo.
Veamos un ejemplo muy simple. Tenemos un archivo Ruby súper simple que imprime 'hola mundo'.
#! /usr/bin/env rubí
def hola
pone 'hola mundo' al
final
Hola()
En nuestro repositorio, creamos una nueva rama llamada espacio en blanco y procedemos a cambiar todos los finales de
línea de Unix a finales de línea de DOS, esencialmente cambiando cada línea del archivo, pero solo con espacios en
blanco. Luego cambiamos la línea “hola mundo” por “hola mundo”.
276
Machine Translated by Google
$ unix2dos hello.rb
unix2dos: convirtiendo el archivo hello.rb a formato DOS ...
$ git commit -am 'Convertir hello.rb a DOS' [espacio en
blanco 3270f76] Convertir hello.rb a DOS 1 archivo
cambiado, 7 inserciones (+) , 7 eliminaciones (-)
$ vim hola.rb $
git diff -b diff --
git a/hola.rb b/hola.rb índice
ac51efd..e85207e 100755
--- a/hola.rb
+++ b/hola.rb
@@ -1,7 +1,7
@@ #! /usr/bin/env rubí
def hola -
pone 'hola mundo' +
pone 'hola mundo'^M fin
Hola()
277
Machine Translated by Google
$ vim hola.rb $
git diff diff --git a/
hola.rb b/hola.rb index ac51efd..36c06c8
100755 --- a/hola.rb +++ b/hola.rb @@
-1,5 +1,6 @@ #! /usr/bin/env rubí
Ahora tratamos de fusionar nuestra rama de espacios en blanco y obtendremos conflictos debido a los cambios en los espacios
en blanco.
Ahora tenemos algunas opciones. Primero, veamos cómo salir de esta situación. Si tal vez no esperabas conflictos y no quieres
lidiar con la situación todavía, simplemente puedes salir de la fusión con git merge --abort.
La opción git merge --abort intenta volver a su estado antes de ejecutar la combinación. Los únicos casos en los que es posible
que no pueda hacer esto a la perfección serían si tuviera cambios no guardados y no confirmados en su directorio de trabajo
cuando lo ejecutó; de lo contrario, debería funcionar bien.
278
Machine Translated by Google
Si por alguna razón solo desea comenzar de nuevo, también puede ejecutar git reset --hard HEAD, y su repositorio volverá al último
estado comprometido. Recuerde que cualquier trabajo no comprometido se perderá, así que asegúrese de no querer ninguno de sus
cambios.
En este caso específico, los conflictos están relacionados con espacios en blanco. Sabemos esto porque el caso es simple, pero
también es bastante fácil darse cuenta en casos reales cuando se observa el conflicto porque cada línea se elimina de un lado y se
vuelve a agregar en el otro. De forma predeterminada, Git ve todas estas líneas como modificadas, por lo que no puede fusionar los
archivos.
Sin embargo, la estrategia de combinación predeterminada puede admitir argumentos, y algunos de ellos tratan de ignorar correctamente
los cambios de espacios en blanco. Si ve que tiene muchos problemas de espacios en blanco en una combinación, simplemente puede
anularla y volver a hacerlo, esta vez con -Xignore-all-space o -Xignore-space-change. La primera opción ignora completamente los
espacios en blanco al comparar líneas, la segunda trata las secuencias de uno o más espacios en blanco como equivalentes.
Dado que en este caso, los cambios reales en el archivo no estaban en conflicto, una vez que ignoramos los cambios en los espacios
en blanco, todo se fusiona perfectamente.
Este es un salvavidas si tiene a alguien en su equipo a quien le gusta volver a formatear todo de vez en cuando, desde espacios a
pestañas o viceversa.
Aunque Git maneja bastante bien el preprocesamiento de espacios en blanco, hay otros tipos de cambios que tal vez Git no pueda
manejar automáticamente, pero son correcciones programables. Como ejemplo, supongamos que Git no puede manejar el cambio de
espacio en blanco y necesitamos hacerlo a mano.
Lo que realmente tenemos que hacer es ejecutar el archivo que estamos tratando de fusionar a través de un programa dos2unix antes
de intentar la fusión de archivos real. Entonces, ¿cómo haríamos eso?
Primero, entramos en el estado de conflicto de fusión. Luego queremos obtener copias de mi versión del archivo, su versión (de la rama
en la que nos estamos fusionando) y la versión común (desde donde ambos lados se bifurcaron). Luego, queremos arreglar su lado o
el nuestro y volver a intentar la fusión nuevamente solo para este único archivo.
Obtener las tres versiones de archivo es bastante fácil. Git almacena todas estas versiones en el índice bajo "etapas", cada una de las
cuales tiene números asociados. La etapa 1 es el ancestro común, la etapa 2 es su versión y la etapa 3 es de MERGE_HEAD, la
versión que está fusionando ("la de ellos").
Puede extraer una copia de cada una de estas versiones del archivo en conflicto con el comando git show y una sintaxis especial.
279
Machine Translated by Google
Si desea obtener un poco más de núcleo duro, también puede usar el comando ls-files -u plumbing para obtener los
SHA-1 reales de los blobs de Git para cada uno de estos archivos.
$ GIT LS-Files -U
100755 AC51EFDC3DF4F4FD328D1A02AD05331D8E2C9111 1 HELLO.RB
100755 36C06C8752C78D2AFF89571132F3BF7841A7B5C3 2 HELLO.RB
100755 E85207E04DFDD5EB0A1E9OBBBC67FD837C44A1CD 3 HELLO.RB
Ahora que tenemos el contenido de las tres etapas en nuestro directorio de trabajo, podemos corregir el suyo manualmente
para solucionar el problema de los espacios en blanco y volver a fusionar el archivo con el poco conocido comando git
merge-file que hace precisamente eso.
$ dos2unix hello.theirs.rb
dos2unix: convirtiendo el archivo hello.theirs.rb a formato Unix ...
$ git merge-file -p \
hola.nuestro.rb hola.común.rb hola.los suyos.rb > hola.rb
Hola()
En este punto, hemos fusionado muy bien el archivo. De hecho, esto funciona mejor que la opción de ignorar el cambio
de espacio porque en realidad corrige los cambios de espacio en blanco antes de fusionarlos en lugar de simplemente
ignorarlos. En la fusión ignorar-cambio de espacio , en realidad terminamos con unas pocas líneas con terminaciones de
línea de DOS, haciendo que las cosas se mezclen.
Si desea tener una idea antes de finalizar este compromiso sobre lo que realmente cambió entre un lado y el otro, puede
pedirle a git diff que compare lo que hay en su directorio de trabajo que
280
Machine Translated by Google
está a punto de comprometerse como resultado de la fusión en cualquiera de estas etapas. Vamos a repasarlos todos.
Para comparar su resultado con lo que tenía en su rama antes de la fusión, en otras palabras, para ver qué introdujo la
fusión, puede ejecutar git diff --ours:
Hola()
Entonces, aquí podemos ver fácilmente que lo que sucedió en nuestra rama, lo que en realidad estamos introduciendo
en este archivo con esta fusión, es cambiar esa línea única.
Si queremos ver cómo el resultado de la fusión difiere de lo que estaba de su lado, puede ejecutar git diff --theirs. En este
ejemplo y en el siguiente, tenemos que usar -b para quitar el espacio en blanco porque lo estamos comparando con lo
que está en Git, no con nuestro archivo limpio hello.theirs.rb .
Finalmente, puedes ver cómo el archivo ha cambiado desde ambos lados con git diff --base.
281
Machine Translated by Google
Hola()
En este punto, podemos usar el comando git clean para borrar los archivos adicionales que creamos para hacer la
combinación manual pero que ya no necesitamos.
$ git clean -f
Eliminando hello.common.rb
Eliminando hello.ours.rb
Eliminando hello.theirs.rb
Comprobación de conflictos
Tal vez no estemos contentos con la resolución en este punto por alguna razón, o tal vez la edición manual de uno o
ambos lados todavía no funcionó bien y necesitamos más contexto.
Cambiemos un poco el ejemplo. Para este ejemplo, tenemos dos ramas de mayor duración que tienen algunas
confirmaciones pero crean un conflicto de contenido legítimo cuando se fusionan.
Ahora tenemos tres confirmaciones únicas que viven solo en la rama maestra y otras tres que viven en la rama mundo . Si
intentamos fusionar la rama mundo , tenemos un conflicto.
282
Machine Translated by Google
Nos gustaría ver cuál es el conflicto de fusión. Si abrimos el archivo, veremos algo como esto:
#! /usr/bin/env rubí
definitivamente hola
<<<<<<< CABEZA
Hola()
Ambos lados de la combinación agregaron contenido a este archivo, pero algunas de las confirmaciones modificaron el
archivo en el mismo lugar que causó este conflicto.
Exploremos un par de herramientas que ahora tiene a su disposición para determinar cómo surgió este conflicto. Tal vez no
sea obvio cómo exactamente debe solucionar este conflicto. Necesitas mas
contexto.
Una herramienta útil es git checkout con la opción --conflict . Esto volverá a verificar el archivo nuevamente y reemplazará los
marcadores de conflicto de combinación. Esto puede ser útil si desea restablecer los marcadores e intentar resolverlos
nuevamente.
Puede pasar --conflict ya sea diff3 o merge (que es el predeterminado). Si lo pasa diff3, Git usará una versión ligeramente
diferente de los marcadores de conflicto, no solo brindándole las versiones "nuestra" y "suya", sino también la versión "base"
en línea para brindarle más contexto.
283
Machine Translated by Google
#! /usr/bin/env rubí
definitivamente hola
<<<<<<< nuestro
=======
Hola()
Si le gusta este formato, puede configurarlo como predeterminado para futuros conflictos de combinación configurando la
configuración merge.conflictstyle en diff3.
El comando git checkout también puede tomar las opciones --ours y --theirs , lo que puede ser una forma realmente rápida de
elegir un lado o el otro sin fusionar cosas en absoluto.
Esto puede ser particularmente útil para conflictos de archivos binarios donde simplemente puede elegir un lado, o donde solo
desea fusionar ciertos archivos desde otra rama: puede fusionar y luego extraer ciertos archivos de un lado u otro antes de
confirmar .
Combinar registro
Otra herramienta útil para resolver conflictos de fusión es git log. Esto puede ayudarlo a obtener contexto sobre lo que pudo
haber contribuido a los conflictos. Revisar un poco de historia para recordar por qué dos líneas de desarrollo tocaban la misma
área de código puede ser realmente útil a veces.
Para obtener una lista completa de todas las confirmaciones únicas que se incluyeron en cualquiera de las ramas involucradas
en esta fusión, podemos usar la sintaxis de "punto triple" que aprendimos en Punto triple.
Esa es una buena lista de los seis compromisos totales involucrados, así como también en qué línea de desarrollo estaba
cada compromiso.
Sin embargo, podemos simplificar aún más esto para darnos un contexto mucho más específico. Si añadimos el --merge
284
Machine Translated by Google
opción para git log, solo mostrará las confirmaciones en cualquier lado de la combinación que toque un archivo que actualmente
está en conflicto.
Si ejecuta eso con la opción -p en su lugar, obtiene solo las diferencias con el archivo que terminó en conflicto.
Esto puede ser realmente útil para brindarle rápidamente el contexto que necesita para ayudarlo a comprender por qué algo
entra en conflicto y cómo resolverlo de manera más inteligente.
Dado que Git organiza cualquier resultado de fusión que tenga éxito, cuando ejecuta git diff mientras se encuentra en un estado
de fusión en conflicto, solo obtiene lo que todavía está en conflicto. Esto puede ser útil para ver lo que aún tiene que resolver.
Cuando ejecuta git diff directamente después de un conflicto de combinación, le dará información en un formato de salida de
diferencia bastante único.
definitivamente hola
++<<<<<<<
CABEZA + pone 'hola mundo'
++=======
+ pone 'hola mundo' +
+>>>>>>> mundo
final
Hola()
El formato se llama "Diferencia combinada" y le brinda dos columnas de datos al lado de cada línea. La primera columna le
muestra si esa línea es diferente (agregada o eliminada) entre la rama "nuestra" y el archivo en su directorio de trabajo y la
segunda columna hace lo mismo entre la rama "suya" y la copia de su directorio de trabajo.
Entonces, en ese ejemplo, puede ver que las líneas <<<<<<< y >>>>>>> están en la copia de trabajo pero no estaban en ninguno
de los lados de la fusión. Esto tiene sentido porque la herramienta de combinación los colocó allí para nuestro contexto, pero se
espera que los eliminemos.
Si resolvemos el conflicto y volvemos a ejecutar git diff , veremos lo mismo, pero es un poco más
285
Machine Translated by Google
útil.
$ vim hola.rb $
git diff diff --cc
hola.rb index
0399cd5,59727f0..0000000 --- a/
hola.rb +++ b/hola.rb @@@ -1,7
-1,7 + 1,7 @@@ #! /usr/bin/env
rubí
def hola -
pone 'hola mundo' -
pone 'hola mundo' ++
pone 'hola mundo' end
Hola()
Esto nos muestra que “hola mundo” estaba en nuestro lado pero no en la copia de trabajo, que “hola mundo”
estaba en su lado pero no en la copia de trabajo y finalmente que “hola mundo” no estaba en ninguno de los
lados pero ahora está en la copia de trabajo. Esto puede ser útil para revisar antes de confirmar la resolución.
También puede obtener esto del registro de git para cualquier combinación para ver cómo se resolvió algo después del hecho. Git
generará este formato si ejecuta git show en una confirmación de combinación, o si agrega una opción --cc a un registro de git -p
(que de forma predeterminada solo muestra parches para confirmaciones que no son de combinación).
286
Machine Translated by Google
Conflictos:
ÿ
hola.rb
def hola -
pone 'hola mundo' - pone
'hola mundo' ++ pone 'hola
mundo' end
Hola()
Deshacer fusiones
Ahora que sabe cómo crear una confirmación de combinación, probablemente haga algunos por error. Una de las mejores
cosas de trabajar con Git es que está bien cometer errores, porque es posible (y en muchos casos fácil) corregirlos.
Las confirmaciones de fusión no son diferentes. Digamos que comenzó a trabajar en una rama de tema, la fusionó
accidentalmente con la principal y ahora su historial de confirmaciones se ve así:
287
Machine Translated by Google
Hay dos formas de abordar este problema, dependiendo de cuál sea el resultado deseado.
Si la confirmación de combinación no deseada solo existe en su repositorio local, la mejor y más fácil solución es mover las ramas
para que apunten a donde usted quiere. En la mayoría de los casos, si sigue el errante git merge con git reset --hard HEAD~, esto
restablecerá los punteros de rama para que se vean así:
Cubrimos el restablecimiento en Restablecer desmitificado, por lo que no debería ser demasiado difícil averiguar qué está pasando
aquí. Aquí hay un repaso rápido: restablecer --hard generalmente pasa por tres pasos:
1. Mueva los puntos HEAD de la rama. En este caso, queremos mover el maestro a donde estaba antes de la confirmación de
fusión (C6).
288
Machine Translated by Google
La desventaja de este enfoque es que está reescribiendo el historial, lo que puede ser problemático con un repositorio
compartido. Consulte The Perils of Rebasing para obtener más información sobre lo que puede suceder; la versión corta
es que si otras personas tienen las confirmaciones que estás reescribiendo, probablemente deberías evitar reiniciar. Este
enfoque tampoco funcionará si se han creado otras confirmaciones desde la fusión; mover los árbitros efectivamente
perdería esos cambios.
Invertir el compromiso
Si mover los punteros de rama no funciona para usted, Git le da la opción de hacer una nueva confirmación que deshace
todos los cambios de uno existente. Git llama a esta operación "revertir" y, en este escenario particular, la invocaría así:
El indicador -m 1 indica qué padre es la "línea principal" y debe mantenerse. Cuando invoca una combinación en HEAD
(tema de fusión de git), la nueva confirmación tiene dos padres: el primero es HEAD (C6) y el segundo es la punta de la
rama que se está fusionando (C4). En este caso, queremos deshacer todos los cambios introducidos al fusionar en el
padre #2 (C4), manteniendo todo el contenido del padre #1 (C6).
La nueva confirmación ^M tiene exactamente el mismo contenido que C6, por lo que a partir de aquí es como si la fusión
nunca hubiera ocurrido, excepto que las confirmaciones ahora no fusionadas todavía están en el historial de HEAD . Git se
confundirá si intenta fusionar el tema en el maestro nuevamente:
No hay nada en el tema que no esté accesible desde el maestro. Lo que es peor, si agrega trabajo al tema y lo fusiona
nuevamente, Git solo traerá los cambios desde la fusión revertida:
289
Machine Translated by Google
La mejor manera de evitar esto es anular la fusión original, ya que ahora desea incorporar los cambios que se
revirtieron y luego crear una nueva confirmación de fusión:
$ git revert ^M
[master 09f0126] Revert "Revertir "Fusionar rama 'tema'""
$ git merge topic
En este ejemplo, M y ^M se cancelan. ^^M se fusiona efectivamente en los cambios de C3 y C4, y C8 se fusiona en
los cambios de C7, por lo que ahora el tema está totalmente fusionado.
En primer lugar, hay otra cosa útil que podemos hacer con el modo de fusión "recursivo" normal.
Ya hemos visto las opciones ignore-all-space e ignore-space-change que se pasan con una -X , pero también
podemos decirle a Git que favorezca un lado o el otro cuando vea un conflicto.
De manera predeterminada, cuando Git ve un conflicto entre dos ramas que se fusionan, agregará marcadores de
conflicto de fusión en su código y marcará el archivo como en conflicto y le permitirá resolverlo. Si prefiere que Git
simplemente elija un lado específico e ignore el otro lado en lugar de dejarlo manualmente
290
Machine Translated by Google
Si Git ve esto, no agregará marcadores de conflicto. Cualquier diferencia que sea fusionable, se fusionará.
Cualquier diferencia que entre en conflicto, simplemente elegirá el lado que especifique en su totalidad, incluidos los archivos
binarios.
Si volvemos al ejemplo de "hola mundo" que estábamos usando antes, podemos ver que la fusión en nuestra rama genera
conflictos.
En ese caso, en lugar de obtener marcadores de conflicto en el archivo con "hola mundo" en un lado y "hola mundo" en el otro,
simplemente elegirá "hola mundo". Sin embargo, todos los demás cambios que no están en conflicto en esa rama se fusionan
correctamente.
Esta opción también se puede pasar al comando git merge-file que vimos anteriormente ejecutando algo como git merge-file --
ours para fusiones de archivos individuales.
Si desea hacer algo como esto, pero Git no intenta siquiera fusionar los cambios desde el otro lado, hay una opción más
draconiana, que es la estrategia de fusión "nuestra". Esto es diferente de la opción de combinación recursiva "nuestra" .
Esto básicamente hará una fusión falsa. Registrará una nueva confirmación de fusión con ambas ramas como padres, pero ni
siquiera mirará la rama en la que se está fusionando. Simplemente registrará como resultado de la fusión el código exacto en
su rama actual.
Puede ver que no hay diferencia entre la rama en la que estábamos y el resultado de la fusión.
291
Machine Translated by Google
Esto a menudo puede ser útil para engañar básicamente a Git para que piense que una rama ya está fusionada cuando
haciendo una fusión más adelante. Por ejemplo, digamos que se bifurcó de una rama de lanzamiento y ha hecho algunos
trabaje en él que querrá volver a fusionar en su rama principal en algún momento. Mientras tanto
algunas correcciones de errores en el maestro deben ser respaldadas en su rama de lanzamiento . Puedes fusionar la corrección de errores.
bifurcarse en la rama de lanzamiento y también fusionarse -s nuestra la misma rama en su rama maestra
(a pesar de que la solución ya está allí), de modo que cuando vuelva a fusionar la rama de lanzamiento , hay
no hay conflictos de la corrección de errores.
Fusión de subárboles
La idea de la combinación de subárboles es que tiene dos proyectos, y uno de los proyectos se asigna a un
subdirectorio del otro. Cuando especifica una fusión de subárbol, Git suele ser lo suficientemente inteligente como para
descubra que uno es un subárbol del otro y fusione adecuadamente.
Primero, agregaremos la aplicación Rack a nuestro proyecto. Agregaremos el proyecto Rack como referencia remota
en nuestro propio proyecto y luego verifíquelo en su propia rama:
Ahora tenemos la raíz del proyecto Rack en nuestra rama rack_branch y nuestro propio proyecto en el
rama maestra . Si revisa uno y luego el otro, puede ver que tienen un proyecto diferente
raíces:
$ ls
AUTORES PROBLEMAS CONOCIDOS Rakefile ejemplo de liberación
maestro
Cambiado a rama "maestro"
$ ls
LÉAME
292
Machine Translated by Google
Este es un concepto extraño. No todas las ramas en su repositorio tienen que ser ramas del mismo proyecto. No es
común, porque rara vez es útil, pero es bastante fácil tener ramas que contengan historias completamente diferentes.
En este caso, queremos llevar el proyecto Rack a nuestro proyecto maestro como un subdirectorio. Podemos hacer eso
en Git con git read-tree. Aprenderá más sobre read-tree y sus amigos en Git Internals, pero por ahora sepa que lee el
árbol raíz de una rama en su área de ensayo actual y directorio de trabajo. Acabamos de volver a su rama principal y
llevamos la rama rack_branch al subdirectorio rack de nuestra rama principal de nuestro proyecto principal:
Cuando nos comprometemos, parece que tenemos todos los archivos de Rack en ese subdirectorio, como si los
hubiéramos copiado desde un tarball. Lo que se pone interesante es que podemos fusionar cambios de una de las ramas
a la otra con bastante facilidad. Por lo tanto, si el proyecto Rack se actualiza, podemos incorporar cambios ascendentes
cambiando a esa rama y extrayendo:
Luego, podemos fusionar esos cambios nuevamente en nuestra rama principal . Para extraer los cambios y completar
previamente el mensaje de confirmación, use la opción --squash , así como la opción -Xsubtree de la estrategia de
combinación recursiva . La estrategia recursiva es la predeterminada aquí, pero la incluimos para mayor claridad.
Todos los cambios del proyecto Rack se fusionan y están listos para confirmarse localmente. También puede hacer lo
contrario: realizar cambios en el subdirectorio rack de su rama maestra y luego fusionarlos en su rama rack_branch más
tarde para enviarlos a los mantenedores o empujarlos hacia arriba.
Esto nos brinda una manera de tener un flujo de trabajo algo similar al flujo de trabajo del submódulo sin usar submódulos
(que trataremos en Submódulos). Podemos mantener ramas con otros proyectos relacionados en nuestro repositorio y
fusionarlas en subárboles en nuestro proyecto de vez en cuando. Es bueno de alguna manera, por ejemplo, todo el
código está comprometido en un solo lugar. Sin embargo, tiene otros inconvenientes en el sentido de que es un poco
más complejo y más fácil cometer errores al reintegrar cambios o empujar accidentalmente una rama a un repositorio no
relacionado.
Otra cosa un poco extraña es que para obtener una diferencia entre lo que tiene en su subdirectorio rack y el código en
su rama rack_branch , para ver si necesita fusionarlos, no puede usar el comando diff normal. En su lugar, debe ejecutar
git diff-tree con la rama que desea comparar
para:
293
Machine Translated by Google
O bien, para comparar lo que hay en el subdirectorio de su bastidor con lo que era la rama maestra en el servidor la
última vez que buscó, puede ejecutar:
regañar
La funcionalidad de git rerere es una característica un poco oculta. El nombre significa "reutilizar resolución grabada" y,
como su nombre lo indica, le permite pedirle a Git que recuerde cómo resolvió un conflicto de fragmentos para que la
próxima vez que vea el mismo conflicto, Git pueda resolverlo automáticamente. .
Hay una serie de escenarios en los que esta funcionalidad puede ser realmente útil. Uno de los ejemplos que se
mencionan en la documentación es cuando desea asegurarse de que una rama de tema de larga duración finalmente se
fusionará limpiamente, pero no desea tener un montón de confirmaciones de combinación intermedias que saturan su
historial de confirmaciones. Con rerere habilitado, puede intentar la combinación ocasional, resolver los conflictos y luego
salir de la combinación. Si hace esto continuamente, entonces la combinación final debería ser fácil porque rerere puede
hacer todo por usted automáticamente.
Esta misma táctica se puede usar si desea mantener una rama reorganizada para no tener que lidiar con los mismos
conflictos de reorganización cada vez que lo hace. O si desea tomar una rama que fusionó y solucionó un montón de
conflictos y luego decide reorganizarla, es probable que no tenga que volver a hacer todos los mismos conflictos.
Otra aplicación de rerere es cuando fusionas un montón de ramas de temas en evolución en una cabeza comprobable de
vez en cuando, como suele hacer el proyecto Git. Si las pruebas fallan, puede rebobinar las fusiones y volver a hacerlas
sin la rama de tema que hizo que las pruebas fallaran sin tener que volver a resolver los conflictos.
Para habilitar la funcionalidad rerere , simplemente tiene que ejecutar esta configuración:
También puede activarlo creando el directorio .git/rr-cache en un repositorio específico, pero la configuración es más clara
y habilita esa característica globalmente para usted.
Ahora veamos un ejemplo sencillo, similar al anterior. Digamos que tenemos un archivo llamado hello.rb que se parece a
esto:
#! /usr/bin/env rubí
def hola
pone 'hola mundo' al
final
294
Machine Translated by Google
En una rama cambiamos la palabra “hola” por “hola”, luego en otra rama cambiamos el “mundo” por “mundo”, igual
que antes.
Debería notar la nueva línea Preimagen grabada para ARCHIVO allí. De lo contrario, debería verse exactamente
como un conflicto de fusión normal. En este punto, rerere nos puede decir algunas cosas. Normalmente, puede
ejecutar git status en este punto para ver qué es lo que está en conflicto:
$ git estado
# En el maestro de rama
# Rutas no fusionadas:
# (usar "git reset HEAD <archivo>..." para eliminar) # (usar "git
add <archivo>..." para marcar la resolución) #
Sin embargo, git rerere también le dirá para qué ha registrado el estado previo a la fusión con git rerere
estado:
295
Machine Translated by Google
Y git rerere diff mostrará el estado actual de la resolución: con qué comenzó a resolver y en qué lo resolvió.
definitivamente hola
-<<<<<<<
- pone 'hola mundo'
-=======
+<<<<<<< CABEZA
Además (y esto no está realmente relacionado con rerere), puede usar git ls-files -u para ver los archivos en conflicto
y las versiones anterior, izquierda y derecha:
$ GIT LS-Files -U
100644 39804C942A9C1F2C03DC7C5EBCD7F3E3A6B97519 1 HELLO.RB
100644 A440DB6E8D1FD76AD438A49025A9AD9CE746F581 2 HELLO.RB
100644 54336BE847C3758Ab6048764196074443848474 3 hola.rb
Ahora puede resolverlo para que solo diga 'hola mundo' y puede ejecutar git rerere diff nuevamente para ver qué
recordará rerere:
definitivamente hola
-<<<<<<<
- pone 'hola mundo'
-=======
296
Machine Translated by Google
Eso básicamente dice que cuando Git ve un conflicto de fragmentos en un archivo hello.rb que tiene "hola mundo" en un lado y
"hola mundo" en el otro, lo resolverá como "hola mundo".
Ahora, deshagamos esa fusión y luego volvamos a basarla en la parte superior de nuestra rama principal . Podemos mover nuestra
rama hacia atrás usando git reset como vimos en Reset Demystified.
297
Machine Translated by Google
Ahora, obtuvimos el mismo conflicto de combinación que esperábamos, pero eche un vistazo al ARCHIVO
resuelto usando la línea de resolución anterior. Si miramos el archivo, veremos que ya se resolvió, no hay
marcadores de conflicto de combinación en él.
#! /usr/bin/env rubí
def hola
pone 'hola mundo' final
298
Machine Translated by Google
También puede recrear el estado del archivo en conflicto con git checkout:
definitivamente hola
<<<<<<< nuestro
Vimos un ejemplo de esto en Combinación avanzada. Sin embargo, por ahora, volvamos a resolverlo simplemente ejecutando
git rerere nuevamente:
$ git rerere
Resuelto 'hello.rb' usando la resolución anterior. $ gato hola.rb #! /
usr/bin/env rubí
def hola
Hemos vuelto a resolver el archivo automáticamente usando la resolución en caché rerere . Ahora puede agregar y continuar la
reorganización para completarla.
299
Machine Translated by Google
Por lo tanto, si realiza muchas fusiones, o desea mantener una rama de tema actualizada con su rama maestra sin un montón
de fusiones, o cambia de base con frecuencia, puede activar rerere para ayudarlo un poco.
Anotación de archivo
Si rastrea un error en su código y desea saber cuándo se introdujo y por qué, la anotación de archivos suele ser su mejor
herramienta. Te muestra qué confirmación fue la última en modificar cada línea de cualquier archivo. Entonces, si ve que un
método en su código tiene errores, puede anotar el archivo con la culpa de git para determinar qué confirmación fue
responsable de la introducción de esa línea.
El siguiente ejemplo usa git culp para determinar qué compromiso y quién fue el responsable de las líneas en el Makefile del
kernel de Linux de nivel superior y, además, usa la opción -L para restringir la salida de la anotación a las líneas 69 a 82 de
ese archivo:
Observe que el primer campo es el SHA-1 parcial de la confirmación que modificó por última vez esa línea. Los siguientes dos
campos son valores extraídos de ese compromiso: el nombre del autor y la fecha de creación de ese
commit, para que pueda ver fácilmente quién modificó esa línea y cuándo. Después de eso viene el número de línea y el
contenido del archivo. También tenga en cuenta las líneas de confirmación ^1da177e4c3f4 , donde el prefijo ^ designa las
líneas que se introdujeron en la confirmación inicial del repositorio y se han mantenido sin cambios desde entonces. Esto es
un poco confuso, porque ahora has visto al menos tres formas diferentes en que Git usa
300
Machine Translated by Google
Otro aspecto interesante de Git es que no realiza un seguimiento de los cambios de nombre de archivos de forma explícita. Graba las instantáneas
y luego trata de averiguar qué fue renombrado implícitamente, después del hecho. uno de los interesantes
Las características de esto es que también puede pedirle que descubra todo tipo de movimiento de código. Si pasas -C
para culpar a Git, Git analiza el archivo que está anotando e intenta averiguar dónde están los fragmentos de código.
dentro de él originalmente provinieron si fueron copiados de otro lugar. Por ejemplo, digamos que eres
refactorizar un archivo llamado GITServerHandler.m en varios archivos, uno de los cuales es GITPackUpload.m. Por
culpando a GITPackUpload.m con la opción -C , puede ver de dónde vinieron originalmente las secciones del código
desde:
Esto es realmente útil. Normalmente, obtienes como confirmación original la confirmación donde copiaste el
código terminado, porque esa es la primera vez que toca esas líneas en este archivo. Git te dice el original
confirme donde escribió esas líneas, incluso si fue en otro archivo.
Búsqueda binaria
Supongamos que acaba de enviar una versión de su código a un entorno de producción, está obteniendo un error
informes sobre algo que no estaba sucediendo en su entorno de desarrollo, y no puede
imagina por qué el código está haciendo eso. Vuelves a tu código y resulta que puedes reproducir
el problema, pero no puede averiguar qué es lo que va mal. Puede bisecar el código para averiguarlo. Primero tú
ejecute git bisect start para que las cosas funcionen, y luego use git bisect bad para decirle al sistema que el
El compromiso actual en el que estás está roto. Luego, debe decir a bisect cuando fue el último buen estado conocido,
usando git bisect good <good_commit>:
301
Machine Translated by Google
Git descubrió que hubo alrededor de 12 confirmaciones entre la confirmación que marcó como la última buena
confirmación (v1.0) y la mala versión actual, y revisó la del medio por usted. En este punto, puede ejecutar su prueba
para ver si el problema existe a partir de este compromiso. Si es así, entonces se introdujo en algún momento antes de
esta confirmación intermedia; si no es así, entonces el problema se introdujo en algún momento después de la
confirmación intermedia. Resulta que no hay ningún problema aquí, y le dices a Git que al escribir git bisect good y
continúa tu viaje:
Ahora estás en otra confirmación, a mitad de camino entre la que acabas de probar y tu confirmación incorrecta. Ejecutas
tu prueba nuevamente y descubres que este compromiso está roto, así que le dices a Git que with git bisect bad:
$ bisecar mal
Bisección: Quedan 1 revisiones para probar después de
esto [f71ce38690acf49c1f3c9bea38e09d82a5ce6014] Eliminar tabla de excepciones
Esta confirmación está bien, y ahora Git tiene toda la información que necesita para determinar dónde se introdujo el
problema. Le informa el SHA-1 de la primera confirmación incorrecta y muestra parte de la información de confirmación
y qué archivos se modificaron en esa confirmación para que pueda averiguar qué sucedió que pudo haber introducido
este error:
Configuración M
Cuando haya terminado, debe ejecutar git bisect reset para restablecer su HEAD a donde estaba antes de comenzar, o
terminará en un estado extraño:
302
Machine Translated by Google
Esta es una herramienta poderosa que puede ayudarlo a verificar cientos de confirmaciones en busca de un error
introducido en minutos. De hecho, si tiene un script que saldrá 0 si el proyecto es bueno o no 0 si el proyecto es malo,
puede automatizar completamente git bisect. En primer lugar, vuelve a indicarle el alcance de la bisectriz al proporcionar
las confirmaciones buenas y malas conocidas. Puede hacer esto enumerándolos con el comando de inicio de bisección si
lo desea, enumerando primero la confirmación mala conocida y la confirmación buena conocida en segundo lugar:
Al hacerlo, automáticamente se ejecuta test-error.sh en cada confirmación extraída hasta que Git encuentra la primera
confirmación rota. También puede ejecutar algo como hacer o hacer pruebas o lo que sea que tenga que ejecute pruebas
automatizadas para usted.
Submódulos
A menudo sucede que mientras trabaja en un proyecto, necesita usar otro proyecto dentro de él.
Tal vez sea una biblioteca desarrollada por un tercero o que esté desarrollando por separado y utilizando en varios
proyectos principales. Surge un problema común en estos escenarios: desea poder tratar los dos proyectos por separado
y aún así poder usar uno desde el otro.
Aquí hay un ejemplo. Suponga que está desarrollando un sitio web y creando fuentes Atom. En lugar de escribir su propio
código generador de Atom, decide usar una biblioteca. Es probable que deba incluir este código de una biblioteca
compartida, como una instalación de CPAN o una gema de Ruby, o copiar el código fuente en su propio árbol de proyectos.
El problema de incluir la biblioteca es que es difícil personalizar la biblioteca de alguna manera y, a menudo, es más difícil
implementarla, porque debe asegurarse de que cada cliente tenga esa biblioteca disponible. El problema de copiar el
código en su propio proyecto es que los cambios personalizados que realice son difíciles de fusionar cuando los cambios
anteriores estén disponibles.
Git aborda este problema utilizando submódulos. Los submódulos le permiten mantener un repositorio de Git como un
subdirectorio de otro repositorio de Git. Esto le permite clonar otro repositorio en su proyecto y mantener sus confirmaciones
separadas.
Comencemos agregando un repositorio Git existente como un submódulo del repositorio en el que estamos trabajando.
Para agregar un nuevo submódulo, use el comando git submodule add con la URL absoluta o relativa del proyecto que le
gustaría comenzar a rastrear. En este ejemplo, agregaremos una biblioteca llamada "DbConnector".
303
Machine Translated by Google
De forma predeterminada, los submódulos agregarán el subproyecto a un directorio con el mismo nombre que
el repositorio, en este caso, "DbConnector". Puede agregar una ruta diferente al final del comando si desea
que vaya a otro lugar.
$ git status On
branch master Su
rama está actualizada con 'origin/master'.
Primero debería notar el nuevo archivo .gitmodules . Este es un archivo de configuración que almacena la
asignación entre la URL del proyecto y el subdirectorio local en el que lo extrajo:
[submódulo "DbConnector"]
ruta = DbConnector url =
https://github.com/chaconinc/DbConnector
Si tiene varios submódulos, tendrá varias entradas en este archivo. Es importante tener en cuenta que este
archivo está controlado por versión con sus otros archivos, como su archivo .gitignore . Es empujado y tirado
con el resto de su proyecto. Así es como otras personas que clonan este proyecto saben de dónde obtener los
proyectos de submódulos.
Dado que la URL en el archivo .gitmodules es lo que otras personas intentarán clonar/
recuperar primero, asegúrese de usar una URL a la que puedan acceder si es posible. Por
ÿ ejemplo, si usa una URL diferente para empujar a la que otros usarían para extraer, use la
que otros tienen acceso. Puede sobrescribir este valor localmente con git config
submodule.DbConnector.url PRIVATE_URL para su propio uso. Cuando corresponda, una
URL relativa puede ser útil.
La otra lista en la salida de estado de git es la entrada de la carpeta del proyecto. Si ejecuta git diff en eso, verá
algo interesante:
304
Machine Translated by Google
Aunque DbConnector es un subdirectorio en su directorio de trabajo, Git lo ve como un submódulo y no rastrea su contenido
cuando no está en ese directorio. En cambio, Git lo ve como una confirmación particular de ese repositorio.
Si desea una salida diferencial un poco más agradable, puede pasar la opción --submodule a git diff.
+
+
Observe el modo 160000 para la entrada DbConnector . Ese es un modo especial en Git que básicamente significa que está
registrando una confirmación como una entrada de directorio en lugar de un subdirectorio o un archivo.
Aquí clonaremos un proyecto con un submódulo en él. Cuando clona un proyecto de este tipo, de forma predeterminada obtiene
los directorios que contienen submódulos, pero ninguno de los archivos dentro de ellos todavía:
305
Machine Translated by Google
El directorio DbConnector está ahí, pero vacío. Debe ejecutar dos comandos: git submodule init para inicializar su archivo de
configuración local y git submodule update para obtener todos los datos de ese proyecto y verifique la confirmación adecuada que
figura en su superproyecto:
Ahora su subdirectorio DbConnector está en el estado exacto en el que se encontraba cuando se comprometió anteriormente.
Sin embargo, hay otra manera de hacer esto que es un poco más simple. Si pasa --recurse-submodules al comando git clone ,
automáticamente inicializará y actualizará cada submódulo en el repositorio, incluidos los submódulos anidados si alguno de los
submódulos en el repositorio tiene submódulos.
306
Machine Translated by Google
Clonación en 'DbConnector'...
remoto: Contar objetos: 11, hecho. remoto:
Comprimir objetos: 100% (10/10), hecho. remoto: Total 11
(delta 0), reutilizado 11 (delta 0)
Desembalaje de objetos: 100% (11/11), hecho.
Comprobando conectividad... hecho.
Ruta del submódulo 'DbConnector': desprotegido 'c3f01dc8862123d317dd46284b05b6892c7b29bc'
Si ya clonó el proyecto y olvidó --recurse-submodules, puede combinar los pasos de actualización de git submodule init y
git submodule ejecutando git submodule update --init. También para inicializar, buscar y verificar cualquier submódulo
anidado, puede usar la infalible actualización del submódulo git --init --recursive.
El modelo más simple de usar submódulos en un proyecto sería si simplemente estuviera consumiendo un subproyecto y
quisiera obtener actualizaciones de él de vez en cuando, pero en realidad no estuviera modificando nada en su pago.
Veamos un ejemplo simple allí.
Si desea verificar si hay trabajo nuevo en un submódulo, puede ingresar al directorio y ejecutar git fetch y git merge en la
rama ascendente para actualizar el código local.
$ git fetch
Desde https://github.com/chaconinc/DbConnector
c3f01dc..d0354fc maestro -> origin/master $ git merge
origin/master
Actualizando c3f01dc..d0354fc Avance rápido de scripts/
connect.sh | | src/db.c 1 + 2 archivos cambiados, 2
inserciones (+)
1+
Ahora, si regresa al proyecto principal y ejecuta git diff --submodule , puede ver que el submódulo se actualizó y obtener
una lista de confirmaciones que se le agregaron. Si no quieres escribir
307
Machine Translated by Google
--submodule cada vez que ejecuta git diff, puede configurarlo como el formato predeterminado configurando el valor
de configuración de diff.submodule en "log".
Si se compromete en este punto, bloqueará el submódulo para que tenga el nuevo código cuando otras personas
actualicen.
También hay una manera más fácil de hacer esto, si prefiere no buscar y fusionar manualmente en el subdirectorio.
Si ejecuta git submodule update --remote, Git irá a sus submódulos y buscará y actualizará por usted.
Este comando supondrá de manera predeterminada que desea actualizar el pago a la rama principal del repositorio
de submódulos. Sin embargo, puede configurar esto en algo diferente si lo desea. Por ejemplo, si desea que el
submódulo DbConnector rastree la rama "estable" de ese repositorio, puede configurarlo en su archivo .gitmodules
(para que todos los demás también lo rastreen) o simplemente en su archivo local .git/config . Configurémoslo en el
archivo .gitmodules :
Si omite -f .gitmodules , solo hará el cambio por usted, pero probablemente tenga más sentido rastrear esa información
con el repositorio para que todos los demás también lo hagan.
Cuando ejecutamos git status en este punto, Git nos mostrará que tenemos "nuevas confirmaciones" en el submódulo.
308
Machine Translated by Google
$ git status On
branch master Su
rama está actualizada con 'origin/master'.
modificado: .gitmodules
modificado: DbConnector (nuevas confirmaciones)
no se agregaron cambios para confirmar (use "git add" y/o "git commit -a")
$ git status On
branch master Su
rama está actualizada con 'origin/master'.
modificado: .gitmodules
modificado: DbConnector (nuevas confirmaciones)
En este punto, si ejecuta git diff , podemos ver que hemos modificado nuestro archivo .gitmodules y también
que hay una serie de confirmaciones que hemos extraído y que están listas para confirmar en nuestro proyecto
de submódulo.
309
Machine Translated by Google
$ git diferencia
diff --git a/.gitmodules b/.gitmodules
índice 6fc0b3d..fd1cc29 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submódulo "DbConnector"]
ÿ
ruta = conector Db
ÿ
URL = https://github.com/chaconinc/DbConnector
+ rama = estable
Submódulo DbConnector c3f01dc..c87d55d:
ÿ
Esto es genial, ya que podemos ver el registro de compromisos que estamos a punto de comprometer en nuestro
submódulo. Una vez confirmado, también puede ver esta información después del hecho cuando ejecuta git
registro -p.
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submódulo "DbConnector"]
ÿ
ruta = conector Db
ÿ
URL = https://github.com/chaconinc/DbConnector
+ rama = estable
Submódulo DbConnector c3f01dc..c87d55d:
ÿ
Por defecto, Git intentará actualizar todos sus submódulos cuando ejecute la actualización de submódulos de git
--remoto. Si tiene muchos de ellos, es posible que desee pasar el nombre del submódulo que desea
310
Machine Translated by Google
Pongámonos ahora en la piel de su colaborador, que tiene su propio clon local del repositorio de MainProject.
Simplemente ejecutar git pull para obtener los cambios recién confirmados no es suficiente:
$ git pull De
https://github.com/chaconinc/MainProject fb9093c..0a24cfc
maestro -> origen/maestro Obteniendo submódulo
DbConnector De
https://github.com/chaconinc/DbConnector -> origen/estable
c3f01dc..c87d55d estable Actualización de fb9093c..0a24cfc
Avance rápido
$ git status On
branch master Su rama
está actualizada con 'origin/master'.
Cambios no preparados para
confirmación: (use "git add <archivo>..." para actualizar lo que se confirmará) (use
"git checkout -- <archivo>..." para descartar cambios en el directorio de trabajo)
no se agregaron cambios para confirmar (use "git add" y/o "git commit -a")
De forma predeterminada, el comando git pull recupera de forma recursiva los cambios de los submódulos, como
podemos ver en el resultado del primer comando anterior. Sin embargo, no actualiza los submódulos. Esto se muestra
en la salida del comando git status , que muestra que el submódulo está "modificado" y tiene "nuevas confirmaciones".
Además, los corchetes que muestran las nuevas confirmaciones apuntan a la izquierda (<), lo que indica que estas
confirmaciones se registran en MainProject pero no están presentes en la comprobación local de DbConnector. Para
finalizar la actualización, debe ejecutar la actualización del submódulo git:
311
Machine Translated by Google
$ git status
On branch master
Su rama está actualizada con 'origin/master'. nada que
cometer, árbol de trabajo limpio
Tenga en cuenta que para estar seguro, debe ejecutar la actualización del submódulo git con el indicador --init en
caso de que MainProject confirme que acaba de agregar nuevos submódulos, y con el indicador --recursive si
algún submódulo tiene submódulos anidados.
Si desea automatizar este proceso, puede agregar el indicador --recurse-submodules al comando git pull (desde
Git 2.14). Esto hará que Git ejecute la actualización del submódulo de git justo después de la extracción, poniendo
los submódulos en el estado correcto. Además, si desea que Git siempre extraiga con --recurse -submodules,
puede establecer la opción de configuración submodule.recurse en verdadero (esto funciona para git pull desde
Git 2.15). Esta opción hará que Git use el indicador --recurse-submodules para todos los comandos que lo admitan
(excepto clonar).
Hay una situación especial que puede ocurrir al extraer actualizaciones de superproyectos: podría ser que el
repositorio ascendente haya cambiado la URL del submódulo en el archivo .gitmodules en una de las
confirmaciones que extrae. Esto puede suceder, por ejemplo, si el proyecto del submódulo cambia su plataforma
de alojamiento. En ese caso, es posible que git pull --recurse-submodules, o git submodule update, falle si el
superproyecto hace referencia a una confirmación de submódulo que no se encuentra en el submódulo remoto
configurado localmente en su repositorio. Para remediar esta situación, se requiere el comando de sincronización
del submódulo git :
Trabajar en un submódulo
Es muy probable que si usa submódulos, lo haga porque realmente desea trabajar en el código del submódulo al
mismo tiempo que trabaja en el código del proyecto principal (o en varios submódulos) . De lo contrario,
probablemente estaría utilizando un sistema de gestión de dependencias más simple (como Maven o Rubygems).
Así que ahora veamos un ejemplo de hacer cambios en el submódulo al mismo tiempo que el proyecto principal y
confirmar y publicar esos cambios al mismo tiempo.
Hasta ahora, cuando ejecutamos el comando de actualización del submódulo git para obtener cambios de los
repositorios del submódulo, Git obtendría los cambios y actualizaría los archivos en el subdirectorio, pero dejaría
el sub-repositorio en lo que se llama un estado de "CABEZA separada". Esto significa que no hay una rama de
trabajo local (como el maestro, por ejemplo) que rastrea los cambios. Sin cambios de seguimiento de rama de trabajo, eso
312
Machine Translated by Google
significa que incluso si realiza cambios en el submódulo, es muy posible que esos cambios se pierdan la próxima vez que
ejecute la actualización del submódulo de git. Debe realizar algunos pasos adicionales si desea realizar un seguimiento de
los cambios en un submódulo.
Para configurar su submódulo para que sea más fácil de ingresar y piratear, debe hacer dos cosas. Debe ingresar a cada
submódulo y verificar una rama para trabajar. Luego, debe decirle a Git qué hacer si ha realizado cambios y luego
actualizar el submódulo de git: el control remoto extrae el nuevo trabajo desde arriba. Las opciones son que puede
fusionarlos en su trabajo local, o puede intentar reorganizar su trabajo local además de los nuevos cambios.
$ cd DbConnector/
$ git pago estable
Cambiado a la rama 'estable'
Intentemos actualizar nuestro submódulo con la opción "combinar". Para especificarlo manualmente, simplemente
podemos agregar la opción --merge a nuestra llamada de actualización . Aquí veremos que hubo un cambio en el servidor
para este submódulo y se fusionó.
$ cd ..
$ git submodule update --remote --merge remote:
Contando objetos: 4, listo. remoto: Comprimir
objetos: 100% (2/2), listo. remoto: Total 4 (delta 2),
reutilizado 4 (delta 2)
Desembalaje de objetos: 100% (4/4), hecho.
Desde https://github.com/chaconinc/DbConnector
c87d55d..92c7337 estable -> origen/estable Actualizando
c87d55d..92c7337
Avance rápido src/main.c | 1 + 1 archivo cambiado, 1
inserción (+)
Si vamos al directorio DbConnector, tenemos los nuevos cambios ya fusionados en nuestra rama estable local. Ahora
veamos qué sucede cuando hacemos nuestro propio cambio local en la biblioteca y alguien más envía otro cambio al
mismo tiempo.
$ cd DbConnector/
$ vim src/db.c $ git
commit -am 'Unicode support' [stable
f906e16] Unicode support 1 archivo
cambiado, 1 inserción (+)
Ahora, si actualizamos nuestro submódulo, podemos ver qué sucede cuando hemos realizado un cambio local y aguas
arriba también tiene un cambio que debemos incorporar.
313
Machine Translated by Google
$ cd .. $
git submodule update --remote --rebase Primero,
rebobinando el cabezal para reproducir su trabajo encima...
Aplicando: compatibilidad con
Unicode Ruta del submódulo 'DbConnector': rebasado en '5d60ef9bbebf5a0c1c1050f242ceeb54ad58da94'
Si olvida --rebase o --merge, Git simplemente actualizará el submódulo a lo que sea que esté en el servidor y
restablecerá su proyecto a un estado HEAD separado.
Si esto sucede, no se preocupe, simplemente puede volver al directorio y verificar su rama nuevamente (que
aún contendrá su trabajo) y fusionar o reorganizar origin/stable (o cualquier rama remota que desee)
manualmente.
Si no ha confirmado sus cambios en su submódulo y ejecuta una actualización de submódulo que causaría
problemas, Git buscará los cambios pero no sobrescribirá el trabajo no guardado en su directorio de submódulo.
Cancelación
No se puede realizar el pago 'c75e92a2b3855c9e5b66f915308390d9db204aca' en la ruta del submódulo
'DbConnector'
Si realizó cambios que entran en conflicto con algo que cambió anteriormente, Git le informará cuando ejecute
la actualización.
314
Machine Translated by Google
Ahora tenemos algunos cambios en nuestro directorio de submódulos. Algunas de estas fueron traídas desde arriba por
nuestras actualizaciones y otras se hicieron localmente y aún no están disponibles para nadie más, ya que aún no las hemos
enviado.
$ git diff
Submódulo DbConnector c87d55d..82d2ad3:
ÿ
Si nos comprometemos en el proyecto principal y lo impulsamos sin impulsar también los cambios del submódulo, otras
personas que intenten verificar nuestros cambios tendrán problemas, ya que no tendrán forma de obtener los cambios del
submódulo de los que dependen. . Esos cambios solo existirán en nuestra copia local.
Para asegurarse de que esto no suceda, puede pedirle a Git que verifique que todos sus submódulos se hayan enviado
correctamente antes de enviar el proyecto principal. El comando git push toma el argumento --recurse -submodules que se
puede configurar como "verificar" o "bajo demanda". La opción "verificar" hará que la inserción simplemente falle si alguno de
los cambios de submódulos confirmados no se ha aplicado.
o cd a la ruta y uso
empujar git
Como puede ver, también nos brinda algunos consejos útiles sobre lo que podríamos querer hacer a continuación. La opción
simple es ingresar a cada submódulo y presionar manualmente los controles remotos para asegurarse de que estén disponibles
externamente y luego intentar presionar nuevamente. Si desea que el comportamiento de verificación ocurra para todas las
inserciones, puede hacer que este comportamiento sea el predeterminado haciendo git config push.recurseSubmodules check.
La otra opción es usar el valor "bajo demanda", que intentará hacer esto por usted.
315
Machine Translated by Google
Como puede ver allí, Git ingresó al módulo DbConnector y lo empujó antes de empujar el proyecto principal. Si la inserción de
ese submódulo falla por alguna razón, la inserción del proyecto principal también fallará. Puede hacer que este comportamiento
sea el predeterminado haciendo git config push.recurseSubmodules a pedido.
Si cambia la referencia de un submódulo al mismo tiempo que otra persona, es posible que tenga algunos problemas. Es
decir, si los historiales de los submódulos han divergido y están comprometidos con ramas divergentes en un superproyecto,
puede que le cueste un poco arreglarlo.
Si una de las confirmaciones es un ancestro directo de la otra (una combinación de avance rápido), entonces Git simplemente
elegirá la última para la combinación, por lo que funciona bien.
Sin embargo, Git no intentará ni siquiera una fusión trivial por ti. Si el submódulo se compromete a divergir y necesita
fusionarse, obtendrá algo similar a esto:
$ git pull
remote: Contando objetos: 2, listo. remoto:
Comprimir objetos: 100% (1/1), listo. remoto: Total 2 (delta
1), reutilizado 2 (delta 1)
Desembalaje de objetos: 100% (2/2), hecho.
Desde https://github.com/chaconinc/MainProject
9a377d1..eb974f8 maestro -> origen/maestro
Obtención de la advertencia de DbConnector
del submódulo: no se pudo fusionar el submódulo DbConnector (no se encontraron las siguientes confirmaciones de fusión)
CONFLICTO de DbConnector
de fusión automática (submódulo): conflicto de fusión en
DbConnector Fusión automática fallida; solucione los conflictos y luego confirme el resultado.
Entonces, básicamente, lo que sucedió aquí es que Git descubrió que las dos ramas registran puntos en la historia del
submódulo que son divergentes y deben fusionarse. Lo explica como "combinar
316
Machine Translated by Google
siguientes confirmaciones no encontradas”, lo cual es confuso, pero explicaremos por qué en un momento.
Para resolver el problema, debe averiguar en qué estado debe estar el submódulo. Extrañamente, Git realmente no le
brinda mucha información para ayudar aquí, ni siquiera los SHA-1 de las confirmaciones de ambos lados de la historia.
Afortunadamente, es fácil de averiguar. Si ejecuta git diff , puede obtener los SHA-1 de las confirmaciones registradas en
ambas ramas que intentaba fusionar.
Entonces, en este caso, eb41d76 es la confirmación en nuestro submódulo que teníamos y c771610 es la confirmación
que tenía upstream. Si vamos a nuestro directorio de submódulos, ya debería estar en eb41d76 ya que la combinación no
lo habría tocado. Si por alguna razón no lo es, simplemente puede crear y pagar una rama que apunte a ella.
Lo importante es el SHA-1 de la confirmación del otro lado. Esto es lo que tendrás que fusionar y resolver. Puede
simplemente probar la combinación con el SHA-1 directamente, o puede crear una rama para él y luego intentar combinarla.
Le sugerimos lo último, aunque solo sea para hacer un mensaje de confirmación de combinación más agradable.
Entonces, iremos a nuestro directorio de submódulos, crearemos una rama llamada "try-merge" basada en ese segundo
SHA-1 de git diff y fusionaremos manualmente.
$ cd ConectorBD
Tenemos un conflicto de combinación real aquí, por lo que si lo resolvemos y lo confirmamos, simplemente podemos
actualizar el proyecto principal con el resultado.
317
Machine Translated by Google
$ cd .. ÿ $ git
diff ÿ diff --cc
DbConnector
eb41d76 índice, c771610..0000000 ---
a / dbconnector +++ b / dbconnector
@@@ -1,1 -1,1 +1,1 @@@ -
Subproyecto cometer
eb41d764bccf88be77aced643c13a7fa86714135 -Subproject cometer
c77161012afbbe1f58b5053316ead08f4b7e6d1d ++ Subproyecto cometer
9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a $ git agregar DbConnector ÿ
Curiosamente, hay otro caso que maneja Git. Si existe una confirmación de fusión en el directorio del submódulo que contiene
ambas confirmaciones en su historial, Git te la sugerirá como una posible solución. Ve que en algún momento del proyecto del
submódulo, alguien fusionó las ramas que contenían estos dos compromisos, por lo que tal vez querrá ese.
Esta es la razón por la cual el mensaje de error de antes era "combinar después de las confirmaciones no encontradas", porque
no podía hacer esto. Es confuso porque ¿quién esperaría que intentara hacer esto?
Si encuentra una sola confirmación de fusión aceptable, verá algo como esto:
318
Machine Translated by Google
El comando sugerido que proporciona Git actualizará el índice como si hubiera ejecutado git add (que borra el
conflicto), luego confirme. Aunque probablemente no deberías hacer esto. Puede ir fácilmente al directorio de
submódulos, ver cuál es la diferencia, avanzar rápidamente a este compromiso, probarlo correctamente y luego
confirmarlo.
$ cd DbConnector/ $
git merge 9fd905e
Actualización eb41d76..9fd905e
Avance rápido
$ cd .. $
git add DbConnector $ git
commit -am 'Avance rápido a un submódulo secundario común'
Esto logra lo mismo, pero al menos de esta manera puede verificar que funciona y que tiene el código en el
directorio de su submódulo cuando haya terminado.
Hay algunas cosas que puede hacer para que trabajar con submódulos sea un poco más fácil.
Submódulo Foreach
Hay un comando de submódulo foreach para ejecutar algún comando arbitrario en cada submódulo. Esto puede
ser realmente útil si tiene varios submódulos en el mismo proyecto.
Por ejemplo, supongamos que queremos iniciar una nueva función o corregir un error y tenemos trabajo en varios
submódulos. Podemos guardar fácilmente todo el trabajo en todos nuestros submódulos.
319
Machine Translated by Google
Luego podemos crear una nueva rama y cambiar a ella en todos nuestros submódulos.
Entiendes la idea. Una cosa realmente útil que puede hacer es producir una buena diferencia unificada de lo que se cambia en su
proyecto principal y también en todos sus subproyectos.
320
Machine Translated by Google
commit_pager_choice();
+ url = url_decode(url_orig);
+
ÿ
/* construir alias_argv */
ÿ
Aquí podemos ver que estamos definiendo una función en un submódulo y llamándola en el proyecto principal.
Obviamente, este es un ejemplo simplificado, pero espero que le dé una idea de cómo puede ser útil.
Alias útiles
Es posible que desee configurar algunos alias para algunos de estos comandos, ya que pueden ser bastante largos
y no puede establecer opciones de configuración para la mayoría de ellos para que sean predeterminados. Cubrimos
la configuración de alias de Git en Git Aliases, pero aquí hay un ejemplo de lo que puede configurar si planea trabajar
mucho con submódulos en Git.
$ git config alias.sdiff '!'"git diff && git submodule foreach 'git diff'" $ git config alias.spush 'push --
recurse-submodules=on-demand' $ git config alias.supdate 'actualización de submódulo -- remoto --
merge'
De esta manera, simplemente puede ejecutar git update cuando desee actualizar sus submódulos, o git spush
321
Machine Translated by Google
Cambio de ramas
Por ejemplo, cambiar ramas con submódulos en ellas también puede ser complicado con versiones de
Git anteriores a Git 2.13. Si crea una nueva rama, agrega un submódulo allí y luego vuelve a cambiar a
una rama sin ese submódulo, todavía tiene el directorio del submódulo como un directorio sin seguimiento:
$ advertencia de git
checkout master: no se puede rmdir CryptoLibrary: el directorio no está vacío
Cambiado a la rama 'maestro'
Su rama está actualizada con 'origen/maestro'.
$ git estado
En maestro de rama
Su rama está actualizada con 'origen/maestro'.
Archivos sin
seguimiento: (use "git add <archivo>..." para incluir en lo que se confirmará)
Criptobiblioteca/
no se agregó nada para confirmar, pero hay archivos sin rastrear presentes (use "git add" para rastrear)
Eliminar el directorio no es difícil, pero puede ser un poco confuso tenerlo allí. Si lo elimina y luego vuelve
a cambiar a la rama que tiene ese submódulo, deberá ejecutar la actualización del submódulo --init para
volver a llenarlo.
322
Machine Translated by Google
$ git clean-ffdx
Eliminando CryptoLibrary/
$ ls biblioteca criptográfica/
$ ls biblioteca criptográfica/
Makefile incluye guiones origen
Una vez más, no es realmente muy difícil, pero puede ser un poco confuso.
Las versiones más recientes de Git (Git >= 2.13) simplifican todo esto al agregar el indicador --recurse-submodules al
comando git checkout , que se encarga de colocar los submódulos en el estado correcto para la rama a la que estamos
cambiando.
$ git status On
branch master Su
rama está actualizada con 'origin/master'.
Usar el indicador --recurse-submodules de git checkout también puede ser útil cuando trabaja en varias ramas en el
superproyecto, cada una con su submódulo apuntando a diferentes confirmaciones. De hecho, si cambia entre ramas que
registran el submódulo en diferentes confirmaciones, al ejecutar git
323
Machine Translated by Google
estado, el submódulo aparecerá como "modificado" e indicará "nuevas confirmaciones". Esto se debe a que, de forma
predeterminada, el estado del submódulo no se transfiere al cambiar de rama.
Esto puede ser muy confuso, por lo que es una buena idea hacer siempre git checkout --recurse-submodules cuando
tu proyecto tenga submódulos. Para las versiones anteriores de Git que no tienen el indicador --recurse-submodules ,
después de pagar puedes usar la actualización del submódulo de git --init --recursive para poner los submódulos en
el estado correcto.
Afortunadamente, puedes decirle a Git (>=2.14) que siempre use el indicador --recurse-submodules configurando la
opción de configuración submodule.recurse: git config submodule.recurse true. Como se señaló anteriormente, esto
también hará que Git recurra a submódulos para cada comando que tenga la opción --recurse-submodules (excepto
git clone).
La otra advertencia principal con la que se encuentra mucha gente implica cambiar de subdirectorios a submódulos.
Si ha estado rastreando archivos en su proyecto y desea moverlos a un submódulo, debe tener cuidado o Git se
enojará con usted. Suponga que tiene archivos en un subdirectorio de su proyecto y desea cambiarlo a un submódulo.
Si elimina el subdirectorio y luego ejecuta la adición de submódulo, Git le grita:
$ rm -Rf CryptoLibrary/
$ git submodule add https://github.com/chaconinc/CryptoLibrary
'CryptoLibrary' ya existe en el índice
$ git rm -r CryptoLibrary $
git submodule add https://github.com/chaconinc/CryptoLibrary
Clonación en 'CryptoLibrary'... remoto: Contar objetos: 11, listo.
remoto: Comprimir objetos: 100% (10/10), listo. remoto: Total 11
(delta 0), reutilizado 11 (delta 0)
Ahora supongamos que hiciste eso en una sucursal. Si intenta volver a una rama donde esos archivos todavía están
en el árbol real en lugar de un submódulo, obtendrá este error:
...
Muévalos o elimínelos antes de poder cambiar de rama.
Abortando
324
Machine Translated by Google
Puede forzarlo a cambiar con checkout -f, pero tenga cuidado de no tener cambios sin guardar allí, ya que podrían
sobrescribirse con ese comando.
Luego, cuando vuelve a cambiar, obtiene un directorio CryptoLibrary vacío por alguna razón y es posible que la actualización
del submódulo de git tampoco lo solucione. Es posible que deba ingresar al directorio de su submódulo y ejecutar un pago de
git. para recuperar todos sus archivos. Puede ejecutar esto en un script foreach de submódulo para ejecutarlo para múltiples
submódulos.
Es importante tener en cuenta que los submódulos en estos días mantienen todos sus datos de Git en el directorio .git del
proyecto principal , por lo que, a diferencia de versiones mucho más antiguas de Git, destruir un directorio de submódulos no
perderá ninguna confirmación o rama que tenía.
Con estas herramientas, los submódulos pueden ser un método bastante simple y efectivo para desarrollar varios proyectos
relacionados pero aún separados simultáneamente.
Agrupación
Aunque hemos cubierto las formas comunes de transferir datos de Git a través de una red (HTTP, SSH, etc.), en realidad hay
una forma más de hacerlo que no se usa comúnmente pero que puede ser bastante útil.
Git es capaz de "agrupar" sus datos en un solo archivo. Esto puede ser útil en varios escenarios. Tal vez su red no funcione y
quiera enviar cambios a sus compañeros de trabajo. Tal vez esté trabajando en algún lugar fuera del sitio y no tenga acceso
a la red local por razones de seguridad. Tal vez su tarjeta inalámbrica/ethernet se acaba de romper. Tal vez no tenga acceso
a un servidor compartido por el momento, quiera enviar actualizaciones por correo electrónico a alguien y no quiera transferir
40 confirmaciones a través de un parche de formato.
Aquí es donde el comando git bundle puede ser útil. El comando bundle empaquetará todo lo que normalmente se enviaría
por cable con un comando git push en un archivo binario que puede enviar por correo electrónico a alguien o colocar en una
unidad flash, luego desagregarlo en otro repositorio.
Veamos un ejemplo sencillo. Digamos que tienes un repositorio con dos confirmaciones:
325
Machine Translated by Google
$ git registro
compromiso 9a466c572fe88b195efd356c3f2bbeccdb504102
Autor: Scott Chacon <schacon@gmail.com> Fecha:
miércoles 10 de marzo 07:34:10 2010 -0800
Segunda confirmación
cometer b1ec3248f39900d2a406049d762aa68e9641be25
Autor: Scott Chacon <schacon@gmail.com> Fecha: miércoles
10 de marzo 07:34:01 2010 -0800
Primera confirmación
Si desea enviar ese repositorio a alguien y no tiene acceso a un repositorio para enviarlo, o simplemente no desea configurar
uno, puede agruparlo con git bundle create.
Ahora tiene un archivo llamado repo.bundle que tiene todos los datos necesarios para volver a crear la rama principal del
repositorio. Con el comando de paquete , debe enumerar cada referencia o rango específico de confirmaciones que desea incluir.
Si tiene la intención de que esto se clone en otro lugar, debe agregar HEAD como referencia, así como lo hemos hecho aquí.
Puede enviar por correo electrónico este archivo repo.bundle a otra persona, o ponerlo en una unidad USB y recorrerlo.
Por otro lado, digamos que le enviaron este archivo repo.bundle y desea trabajar en el proyecto. Puede clonar desde el archivo
binario a un directorio, como lo haría desde una URL.
Si no incluye HEAD en las referencias, también debe especificar -b master o cualquier rama que esté incluida porque, de lo
contrario, no sabrá qué rama verificar.
Ahora supongamos que realiza tres confirmaciones y desea enviar las nuevas confirmaciones a través de un paquete en una memoria
USB o correo electrónico.
326
Machine Translated by Google
Primero, debemos determinar el rango de confirmaciones que queremos incluir en el paquete. A diferencia de los
protocolos de red que determinan el conjunto mínimo de datos para transferir a través de la red, tendremos que
resolver esto manualmente. Ahora, podría hacer lo mismo y agrupar todo el repositorio, lo que funcionará, pero es
mejor simplemente agrupar la diferencia: solo las tres confirmaciones que acabamos de hacer localmente.
Para hacer eso, tendrás que calcular la diferencia. Como describimos en Rangos de confirmaciones, puede especificar
un rango de confirmaciones de varias formas. Para obtener las tres confirmaciones que tenemos en nuestra rama
maestra que no estaban en la rama que clonamos originalmente, podemos usar algo como origin/master..master o
master ^origin/master. Puede probar eso con el comando de registro .
Así que ahora que tenemos la lista de compromisos que queremos incluir en el paquete, agrupémoslos. Hacemos eso
con el comando git bundle create , dándole un nombre de archivo que queremos que sea nuestro paquete y el rango
de confirmaciones que queremos incluir en él.
Ahora tenemos un archivo commits.bundle en nuestro directorio. Si tomamos eso y se lo enviamos a nuestro socio,
ella puede importarlo al repositorio original, incluso si se ha hecho más trabajo allí mientras tanto.
Cuando obtiene el paquete, puede inspeccionarlo para ver qué contiene antes de importarlo a su repositorio. El primer
comando es el comando de verificación del paquete que se asegurará de que el archivo sea realmente un paquete Git
válido y que tenga todos los ancestros necesarios para reconstituirlo correctamente.
327
Machine Translated by Google
Si el empaquetador hubiera creado un paquete de solo las dos últimas confirmaciones que había hecho, en lugar de
las tres, el repositorio original no podría importarlo, ya que le falta el historial de requisitos. El comando de verificación
se habría visto así:
Sin embargo, nuestro primer paquete es válido, por lo que podemos obtener confirmaciones de él. Si desea ver qué
ramas hay en el paquete que se pueden importar, también hay un comando para enumerar solo las cabezas:
El subcomando de verificación también le indicará las cabezas. El punto es ver qué se puede extraer, de modo que
pueda usar los comandos fetch o pull para importar confirmaciones de este paquete. Aquí buscaremos la rama maestra
del paquete en una rama llamada other-master en nuestro repositorio:
Ahora podemos ver que tenemos las confirmaciones importadas en la rama de otro maestro , así como cualquier
confirmación que hayamos hecho mientras tanto en nuestra propia rama maestra .
Por lo tanto, git bundle puede ser realmente útil para compartir o realizar operaciones de tipo red cuando no tiene la red
adecuada o el repositorio compartido para hacerlo.
328
Machine Translated by Google
Reemplazar
Como hemos enfatizado antes, los objetos en la base de datos de objetos de Git no se pueden cambiar, pero Git
proporciona una forma interesante de pretender reemplazar objetos en su base de datos con otros objetos.
El comando replace te permite especificar un objeto en Git y decir "cada vez que te refieras a este objeto, finge que es
un objeto diferente ". Esto suele ser útil para reemplazar una confirmación en su historial con otra sin tener que
reconstruir todo el historial con, por ejemplo, git filter-branch.
Por ejemplo, supongamos que tiene un historial de código enorme y desea dividir su repositorio en un historial breve
para los nuevos desarrolladores y un historial mucho más extenso para las personas interesadas en la minería de datos.
Puede injertar un historial en el otro "reemplazando" la primera confirmación en la nueva línea con la última confirmación
en la anterior. Esto es bueno porque significa que en realidad no tienes que volver a escribir cada compromiso en el
nuevo historial, como normalmente tendrías que hacer para unirlos (porque el parentesco afecta a los SHA-1).
Probemos esto. Tomemos un repositorio existente, divídalo en dos repositorios, uno reciente y otro histórico, y luego
veremos cómo podemos recombinarlos sin modificar los valores SHA-1 de los repositorios recientes a través de replace.
Queremos dividir esto en dos líneas de la historia. Una línea va desde el compromiso uno hasta el compromiso cuatro:
ese será el histórico. La segunda línea será solo los compromisos cuatro y cinco, esa será la historia reciente.
329
Machine Translated by Google
Bueno, crear la historia histórica es fácil, podemos simplemente poner una rama en la historia y luego
empujar esa rama a la rama maestra de un nuevo repositorio remoto.
330
Machine Translated by Google
Ahora podemos enviar la nueva rama de historial a la rama maestra de nuestro nuevo repositorio:
OK, entonces nuestra historia está publicada. Ahora, la parte más difícil es truncar nuestra historia reciente para que sea
331
Machine Translated by Google
menor. Necesitamos una superposición para poder reemplazar un compromiso en uno con un compromiso equivalente en
el otro, por lo que vamos a truncar esto solo para confirmar cuatro y cinco (así que comete cuatro superposiciones).
En este caso, es útil crear una confirmación base que tenga instrucciones sobre cómo expandir el historial, para que otros
desarrolladores sepan qué hacer si alcanzan la primera confirmación en el historial truncado y necesitan más. Entonces, lo
que vamos a hacer es crear un objeto de confirmación inicial como nuestro punto base con instrucciones, luego reorganizar
las confirmaciones restantes (cuatro y cinco) encima de él.
Para hacer eso, debemos elegir un punto para dividir, que para nosotros es el tercer compromiso, que es 9c68fdc en
lenguaje SHA. Entonces, nuestro compromiso base se basará en ese árbol. Podemos crear nuestra confirmación base
usando el comando commit-tree , que simplemente toma un árbol y nos devolverá un objeto de confirmación SHA-1
completamente nuevo y sin padres.
ÿ directamente, sino que son utilizados por otros comandos de Git para realizar trabajos más pequeños.
En ocasiones, cuando estamos haciendo cosas más extrañas como esta, nos permiten hacer cosas
de muy bajo nivel, pero no están diseñadas para el uso diario. Puede leer más sobre los comandos de
plomería en Plomería y Porcelana.
332
Machine Translated by Google
Bien, ahora que tenemos una confirmación base, podemos reorganizar el resto de nuestro historial además de eso
con git rebase --onto. El argumento --onto será el SHA-1 que acabamos de obtener del árbol de confirmación y el
punto de rebase será la tercera confirmación (el padre de la primera confirmación que queremos mantener, 9c68fdc):
333
Machine Translated by Google
Bien, ahora hemos reescrito nuestro historial reciente sobre un compromiso base descartable que ahora
tiene instrucciones sobre cómo reconstituir el historial completo si quisiéramos. Podemos enviar ese nuevo
historial a un nuevo proyecto y ahora, cuando las personas clonen ese repositorio, solo verán las dos
confirmaciones más recientes y luego una confirmación base con instrucciones.
Ahora cambiemos los roles a alguien que clone el proyecto por primera vez y que quiera el historial completo.
Para obtener los datos del historial después de clonar este repositorio truncado, habría que agregar un
segundo control remoto para el repositorio histórico y buscar:
334
Machine Translated by Google
-> proyecto-historia/maestro
Ahora el colaborador tendría sus confirmaciones recientes en la rama maestra y las confirmaciones históricas en la
rama proyecto-historial/maestra .
Para combinarlos, simplemente puede llamar a git replace con el compromiso que desea reemplazar y luego el
compromiso con el que desea reemplazarlo. Así que queremos reemplazar la "cuarta" confirmación en la rama
maestra con la "cuarta" confirmación en la rama proyecto-historial/maestra :
¿Guay, verdad? Sin tener que cambiar todos los SHA-1 en sentido ascendente, pudimos reemplazar una confirmación
en nuestro historial con una confirmación completamente diferente y todas las herramientas normales (bisectar,
culpar, etc.) funcionarán como esperábamos.
335
Machine Translated by Google
Curiosamente, todavía muestra 81a708d como SHA-1, aunque en realidad está usando los datos de confirmación
c6e1e95 con los que lo reemplazamos. Incluso si ejecuta un comando como cat-file, le mostrará los datos reemplazados:
cuarto compromiso
Recuerde que el padre real de 81a708d fue nuestra confirmación de marcador de posición (622e88e), no 9c68fdce
como se indica aquí.
336
Machine Translated by Google
$ Git para-cada-ref
e146b5f14e79d4935160c0e83fb9ebe526b8da0d comprometen refs / heads / master
c6e1e95051d41771a649f3145423f8809d1a74d4 cometer árbitros / mandos a distancia / historia /
maestro e146b5f14e79d4935160c0e83fb9ebe526b8da0d cometer árbitros / mandos a distancia /
origen / HEAD e146b5f14e79d4935160c0e83fb9ebe526b8da0d cometer árbitros / mandos a distancia /
origin / master c6e1e95051d41771a649f3145423f8809d1a74d4 comprometerse
referencias/reemplazar/81a708dd0e167a3f691541c7a6463343bc457040
Esto significa que es fácil compartir nuestro reemplazo con otros, porque podemos enviarlo a nuestro servidor y otras personas
pueden descargarlo fácilmente. Esto no es tan útil en el escenario de injerto de historia que hemos visto aquí (ya que todos
estarían descargando ambas historias de todos modos, así que ¿por qué separarlas?) pero puede ser útil en otras circunstancias.
Almacenamiento de Credenciales
Si usa el transporte SSH para conectarse a controles remotos, es posible que tenga una clave sin una frase de contraseña, lo que
le permite transferir datos de forma segura sin tener que escribir su nombre de usuario y contraseña. Sin embargo, esto no es
posible con los protocolos HTTP: cada conexión necesita un nombre de usuario y una contraseña. Esto se vuelve aún más difícil
para los sistemas con autenticación de dos factores, donde el token que usa para una contraseña se genera aleatoriamente y no
se puede pronunciar.
Afortunadamente, Git tiene un sistema de credenciales que puede ayudar con esto. Git tiene algunas opciones proporcionadas en
el cuadro:
• El valor predeterminado es no almacenar en caché en absoluto. Cada conexión le pedirá su nombre de usuario y
clave.
• El modo "caché" mantiene las credenciales en la memoria durante un cierto período de tiempo. Ninguna de las contraseñas
se almacena nunca en el disco y se eliminan de la memoria caché después de 15 minutos.
• El modo de "almacenamiento" guarda las credenciales en un archivo de texto sin formato en el disco y nunca caducan. Esto
significa que hasta que cambie su contraseña para el host de Git, no tendrá que volver a escribir sus credenciales. La
desventaja de este enfoque es que sus contraseñas se almacenan en texto claro en un archivo sin formato en su directorio
de inicio.
• Si usa una Mac, Git viene con un modo "osxkeychain", que almacena en caché las credenciales en el llavero seguro que está
adjunto a su cuenta del sistema. Este método almacena las credenciales en el disco y nunca caducan, pero están encriptadas
con el mismo sistema que almacena los certificados HTTPS y los autocompletados de Safari.
• Si usa Windows, macOS o Linux, puede instalar un asistente llamado "Git Credential
Gerente". Esto utiliza almacenes de datos nativos de la plataforma para controlar la información confidencial.
Algunos de estos ayudantes tienen opciones. El asistente de "almacenamiento" puede tomar un argumento --file <ruta> , que
personaliza dónde se guarda el archivo de texto sin formato (el valor predeterminado es ~/.git-credentials). El ayudante de "caché"
337
Machine Translated by Google
acepta la opción --timeout <segundos> , que cambia la cantidad de tiempo que su daemon se mantiene en ejecución (el
valor predeterminado es "900" o 15 minutos). Aquí hay un ejemplo de cómo configuraría el asistente de "almacenamiento"
con un nombre de archivo personalizado:
Git incluso te permite configurar varios ayudantes. Al buscar credenciales para un host en particular, Git las consultará en
orden y se detendrá después de proporcionar la primera respuesta. Al guardar las credenciales, Git enviará el nombre de
usuario y la contraseña a todos los ayudantes de la lista y podrán elegir qué hacer con ellos. Así es como se vería
un .gitconfig si tuviera un archivo de credenciales en una memoria USB, pero quisiera usar el caché en memoria para
ahorrar algo de escritura si la unidad no está conectada:
[credencial]
ayudante = almacenar --file /mnt/thumbdrive/.git-credentials ayudante =
caché --tiempo de espera 30000
Bajo el capó
¿Como funciona todo esto? El comando raíz de Git para el sistema auxiliar de credenciales es git credential, que toma un
comando como argumento y luego más entradas a través de stdin.
Esto podría ser más fácil de entender con un ejemplo. Digamos que se configuró un asistente de credenciales y el asistente
almacenó las credenciales para mygithost. Aquí hay una sesión que usa el comando "llenar", que se invoca cuando Git
intenta encontrar credenciales para un host:
nombre de
usuario=bob contraseña=s3cre7
ÿ Git-credential está esperando la entrada en stdin. Le proporcionamos las cosas que sabemos: la
338
Machine Translated by Google
ÿ Una línea en blanco indica que la entrada está completa y el sistema de credenciales debe responder con
lo que sabe
ÿ Git-credential luego se hace cargo y escribe en stdout con los bits de información que encontró.
ÿ Si no se encuentran las credenciales, Git le pide al usuario el nombre de usuario y la contraseña, y proporciona
devuélvalos a la salida estándar de invocación (aquí están conectados a la misma consola).
El sistema de credenciales en realidad está invocando un programa que está separado de Git; cuál y cómo depende del valor de
configuración de credential.helper . Hay varias formas que puede tomar:
Foo
Ejecuta git-credential-foo
Entonces, los ayudantes descritos anteriormente en realidad se denominan git-credential-cache, git-credential-store, etc., y
podemos configurarlos para tomar argumentos de línea de comandos. La forma general para esto es "git-credential-foo [args]
<acción>". El protocolo stdin/stdout es el mismo que git-credential, pero usan un conjunto de acciones ligeramente diferente:
• store es una solicitud para guardar un conjunto de credenciales en la memoria de este ayudante.
• borrar purgar las credenciales de las propiedades dadas de la memoria de este ayudante.
Para las acciones de almacenar y borrar , no se requiere respuesta (Git lo ignora de todos modos). Sin embargo, para la acción
de obtener , Git está muy interesado en lo que el ayudante tiene que decir. Si el ayudante no sabe nada útil, simplemente puede
salir sin resultados, pero si lo sabe, debe aumentar la información proporcionada con la información que ha almacenado. La
salida se trata como una serie de sentencias de asignación; cualquier cosa proporcionada reemplazará lo que Git ya sabe.
Aquí está el mismo ejemplo anterior, pero omitiendo git-credential y yendo directamente a git credential-store:
nombre de usuario =
339
Machine Translated by Google
ÿ Aquí le decimos a git-credential-store que guarde algunas credenciales: el nombre de usuario "bob" y el
la contraseña "s3cre7" se utilizará cuando https://mygithost se accede.
ÿ Ahora recuperaremos esas credenciales. Proporcionamos las partes de la conexión que ya conocemos.
(https://migithost), y una línea vacía.
https://bob:s3cre7@mygithost
Es solo una serie de líneas, cada una de las cuales contiene una URL decorada con credenciales. Los ayudantes de osxkeychain
y wincred usan el formato nativo de sus almacenes de respaldo, mientras que el caché usa su propio formato en memoria (que
ningún otro proceso puede leer).
Dado que git-credential-store y friends son programas separados de Git, no es un gran salto darse cuenta de que cualquier
programa puede ser un asistente de credenciales de Git. Los ayudantes proporcionados por Git cubren muchos casos de uso
comunes, pero no todos. Por ejemplo, supongamos que su equipo tiene algunas credenciales que se comparten con todo el
equipo, quizás para la implementación. Estos se almacenan en un directorio compartido, pero no desea copiarlos en su propio
almacén de credenciales, ya que cambian con frecuencia. Ninguno de los ayudantes existentes cubre este caso; veamos qué se
necesitaría para escribir el nuestro. Hay varias características clave que este programa debe tener:
1. La única acción a la que debemos prestar atención es obtener; almacenar y borrar son operaciones de escritura, por lo que
simplemente salga limpiamente cuando se reciban.
2. El formato de archivo del archivo de credenciales compartidas es el mismo que usa git-credential-store.
3. La ubicación de ese archivo es bastante estándar, pero debemos permitir que el usuario pase una ruta personalizada
por si acaso.
Una vez más, escribiremos esta extensión en Ruby, pero cualquier idioma funcionará siempre que Git pueda ejecutar el producto
terminado. Aquí está el código fuente completo de nuestro nuevo asistente de credenciales:
340
Machine Translated by Google
#!/usr/bin/env rubí
requiere 'optparse'
final
fin.analizar!
conocido = {} ÿ
while línea = STDIN.se
''
rompe si línea.strip == k,v =
línea.strip.split '=', 2 conocido[k] = v final
File.readlines(path).each do |fileline| ÿ
prot,usuario,contraseña,host = fileline.scan(/^(.*?):\/\/(.*?):(.*?)@(.*)$/).primero si prot ==
conocido['protocolo'] y host == conocido['host'] y usuario == conocido['nombre de usuario'] luego
de usuario=#{usuario}" pone
ÿ
"contraseña=#{contraseña}"
ÿ
exit(0)
final
final
ÿ Aquí analizamos las opciones de la línea de comandos, lo que permite al usuario especificar el archivo de entrada. El valor
predeterminado es ~/.git-credentials.
ÿ Este programa solo responde si la acción es obtener y existe el archivo de almacenamiento de respaldo.
ÿ Este ciclo lee desde stdin hasta que se alcanza la primera línea en blanco. Las entradas se almacenan en el conocido
hash para referencia posterior.
ÿ Este bucle lee el contenido del archivo de almacenamiento y busca coincidencias. Si el protocolo, el host y el nombre de usuario
de conocido coinciden con esta línea, el programa imprime los resultados en la salida estándar y sale.
Guardaremos nuestro asistente como git-credential-read-only, lo pondremos en algún lugar de nuestra RUTA y lo marcaremos como
ejecutable. Así es como se ve una sesión interactiva:
341
Machine Translated by Google
protocolo = https
host = mygithost
nombre de usuario
Dado que su nombre comienza con "git-", podemos usar la sintaxis simple para el valor de configuración:
Como puede ver, extender este sistema es bastante sencillo y puede resolver algunos problemas comunes para
usted y su equipo.
Resumen
Ha visto una serie de herramientas avanzadas que le permiten manipular sus confirmaciones y el área de preparación
con mayor precisión. Cuando observe problemas, debería poder averiguar fácilmente qué compromiso los introdujo,
cuándo y por quién. Si desea utilizar subproyectos en su proyecto, ha aprendido a adaptarse a esas necesidades.
En este punto, debería poder hacer la mayoría de las cosas en Git que necesitará en la línea de comando día a día
y sentirse cómodo haciéndolo.
342
Machine Translated by Google
Personalizando Git
Hasta ahora, hemos cubierto los conceptos básicos de cómo funciona Git y cómo usarlo, y hemos presentado una serie de
herramientas que proporciona Git para ayudarlo a usarlo de manera fácil y eficiente. En este capítulo, veremos cómo puede hacer
que Git funcione de una manera más personalizada, introduciendo varias opciones de configuración importantes y el sistema de
ganchos. Con estas herramientas, es fácil hacer que Git funcione exactamente como usted, su empresa o su grupo lo necesitan.
Configuración Git
Como leyó brevemente en Primeros pasos, puede especificar los ajustes de configuración de Git con el comando git config . Una
de las primeras cosas que hizo fue configurar su nombre y dirección de correo electrónico:
Ahora aprenderá algunas de las opciones más interesantes que puede configurar de esta manera para personalizar su uso de Git.
Primero, una revisión rápida: Git usa una serie de archivos de configuración para determinar el comportamiento no predeterminado
que puede desear. El primer lugar en el que Git busca estos valores es en el archivo [ruta]/etc/gitconfig de todo el sistema, que
contiene configuraciones que se aplican a cada usuario en el sistema y todos sus repositorios. Si pasa la opción --system a git
config, lee y escribe desde este archivo específicamente.
El siguiente lugar que busca Git es el archivo ~/.gitconfig (o ~/.config/git/config) , que es específico para cada usuario. Puede
hacer que Git lea y escriba en este archivo pasando la opción --global .
Finalmente, Git busca valores de configuración en el archivo de configuración en el directorio de Git (.git/config) de cualquier
repositorio que esté usando actualmente. Estos valores son específicos de ese único repositorio y representan pasar la opción --
local a git config. Si no especifica con qué nivel desea trabajar, este es el valor predeterminado.
Cada uno de estos "niveles" (sistema, global, local) sobrescribe los valores en el nivel anterior, por lo que los valores en .git/config
superan a los de [ruta]/etc/gitconfig, por ejemplo.
Los archivos de configuración de Git son texto sin formato, por lo que también puede establecer estos
ÿ valores editando manualmente el archivo e insertando la sintaxis correcta. Sin embargo, generalmente es
más fácil ejecutar el comando git config .
Las opciones de configuración reconocidas por Git se dividen en dos categorías: del lado del cliente y del lado del servidor. La
mayoría de las opciones son del lado del cliente, configurando sus preferencias personales de trabajo. Se admiten muchas ,
muchas opciones de configuración, pero una gran parte de ellas son útiles solo en ciertos casos extremos; Cubriremos solo las
opciones más comunes y útiles aquí. Si desea ver una lista de todas las opciones que reconoce su versión de Git, puede ejecutar:
343
Machine Translated by Google
$ hombre git-config
Este comando enumera todas las opciones disponibles con bastante detalle. También puede encontrar este material de referencia
en https://git-scm.com/docs/git-config.
core.editor
De manera predeterminada, Git usa lo que haya configurado como su editor de texto predeterminado a través de una de las variables
de entorno de shell VISUAL o EDITOR, o recurre al editor vi para crear y editar sus mensajes de confirmación y etiquetado. Para
cambiar ese valor predeterminado a otra cosa, puede usar la configuración core.editor :
Ahora, sin importar cuál esté configurado como su editor de shell predeterminado, Git activará Emacs para editar mensajes.
commit.plantilla
Si establece esto en la ruta de un archivo en su sistema, Git usará ese archivo como el mensaje inicial predeterminado cuando
confirme. El valor de crear una plantilla de confirmación personalizada es que puede usarla para recordarse a sí mismo (o a otros) el
formato y el estilo adecuados al crear un mensaje de confirmación.
[Boleto: X]
Tenga en cuenta cómo esta plantilla de compromiso le recuerda al autor de confirmación que debe mantener la línea de asunto
breve (por el bien de git log --oneline output), para agregar más detalles debajo de eso y para referirse a un problema o número de
ticket de seguimiento de errores, si existe.
Para decirle a Git que lo use como el mensaje predeterminado que aparece en su editor cuando ejecuta git commit, establezca el
valor de configuración de commit.template :
Luego, su editor se abrirá a algo como esto para su mensaje de confirmación de marcador de posición cuando confirme:
344
Machine Translated by Google
[Boleto: X]
# Ingrese el mensaje de confirmación para sus cambios. Las líneas que comiencen #
con '#' se ignorarán y un mensaje vacío anulará la confirmación.
# En el maestro de rama
# Cambios que se confirmarán: #
(use "git reset HEAD <archivo>..." para quitar la preparación)
# # modificado: lib/test.rb #
~
~
Si su equipo tiene una política de mensajes de confirmación, colocar una plantilla para esa política en su sistema y configurar Git
para que la use de forma predeterminada puede ayudar a aumentar las posibilidades de que esa política se siga con regularidad.
core.pager
Esta configuración determina qué buscapersonas se usa cuando las páginas de Git se generan, como log y diff. Puede configurarlo
en más o en su buscapersonas favorito (de manera predeterminada, es menos), o puede desactivarlo configurándolo en una cadena
en blanco:
''
$ git config --global core.pager
Si ejecuta eso, Git paginará la salida completa de todos los comandos, sin importar cuánto tiempo sean.
usuario.signingkey
Si está creando etiquetas anotadas firmadas (como se explica en Cómo firmar su trabajo), configurar su clave de firma GPG como un
ajuste de configuración facilita las cosas. Configure su ID de clave así:
Ahora, puede firmar etiquetas sin tener que especificar su clave cada vez con el comando de etiqueta git :
core.excluyearchivo
Puede poner patrones en el archivo .gitignore de su proyecto para que Git no los vea como archivos sin seguimiento o
345
Machine Translated by Google
intente organizarlos cuando ejecute git add en ellos, como se explica en Ignorar archivos.
Pero a veces desea ignorar ciertos archivos para todos los repositorios con los que trabaja. Si su computadora ejecuta macOS,
probablemente esté familiarizado con los archivos .DS_Store . Si su editor preferido es Emacs o Vim, conoce los nombres de
archivo que terminan con ~ o .swp.
Esta configuración le permite escribir una especie de archivo .gitignore global . Si crea un archivo ~/.gitignore_global con estos
contenidos:
*~
.*.swp .DS_Store
…y ejecutas git config --global core.excludesfile ~/.gitignore_global, Git nunca más te molestará con esos archivos.
ayuda.autocorrección
Git trata de averiguar a qué te referías, pero aún se niega a hacerlo. Si establece help.autocorrect en 1, Git ejecutará este
comando por usted:
Tenga en cuenta que el negocio de "0.1 segundos". help.autocorrect es en realidad un número entero que representa décimas
de segundo. Entonces, si lo configura en 50, Git le dará 5 segundos para cambiar de opinión antes de ejecutar el comando
autocorregido.
Colores en Git
Git es totalmente compatible con la salida de terminal en color, lo que ayuda en gran medida a analizar visualmente la salida del
comando de forma rápida y sencilla. Varias opciones pueden ayudarlo a configurar el color según sus preferencias.
color.ui
Git colorea automáticamente la mayor parte de su salida, pero hay un cambio maestro si no te gusta este comportamiento. Para
desactivar todas las salidas de terminal de color de Git, haga lo siguiente:
346
Machine Translated by Google
La configuración predeterminada es automática, que colorea la salida cuando va directamente a una terminal, pero omite los
códigos de control de color cuando la salida se redirige a una tubería o un archivo.
También puede configurarlo para que siempre ignore la diferencia entre terminales y tuberías. Rara vez querrás esto; en la
mayoría de los escenarios, si desea códigos de color en su salida redirigida, puede pasar un indicador --color al comando Git para
forzarlo a usar códigos de color. La configuración predeterminada es casi siempre lo que desea.
color.*
Si desea ser más específico acerca de qué comandos están coloreados y cómo, Git proporciona configuraciones de color
específicas para los verbos. Cada uno de estos se puede configurar como verdadero, falso o siempre:
color.rama
color.diff
color.interactivo
color.estado
Además, cada uno de estos tiene subconfiguraciones que puede usar para establecer colores específicos para partes de la salida,
si desea anular cada color. Por ejemplo, para configurar la metainformación en su salida de diff en primer plano azul, fondo negro
y texto en negrita, puede ejecutar:
Puede establecer el color en cualquiera de los siguientes valores: normal, negro, rojo, verde, amarillo, azul, magenta, cian o
blanco. Si desea un atributo como negrita en el ejemplo anterior, puede elegir entre negrita, tenue, ul (subrayado), parpadeo y
reverso (intercambiar primer plano y fondo).
Aunque Git tiene una implementación interna de diff, que es lo que hemos estado mostrando en este libro, puede configurar una
herramienta externa en su lugar. También puede configurar una herramienta gráfica de resolución de conflictos de combinación
en lugar de tener que resolver los conflictos manualmente. Demostraremos cómo configurar Perforce Visual Merge Tool (P4Merge)
para hacer sus diferencias y fusionar resoluciones, porque es una buena herramienta gráfica y es gratis.
Si desea probar esto, P4Merge funciona en todas las plataformas principales, por lo que debería poder hacerlo.
Usaremos nombres de rutas en los ejemplos que funcionan en sistemas macOS y Linux; para Windows, deberá cambiar /usr/local/
bin a una ruta ejecutable en su entorno.
Para comenzar, descargue P4Merge de Perforce. A continuación, configurará secuencias de comandos de envoltura externas
para ejecutar sus comandos. Usaremos la ruta de macOS para el ejecutable; en otros sistemas, será donde esté instalado su
binario p4merge . Configure un script contenedor de combinación llamado extMerge que llama a su binario con todos los
argumentos proporcionados:
347
Machine Translated by Google
El contenedor diff verifica para asegurarse de que se proporcionen siete argumentos y pasa dos de ellos a su secuencia de
comandos de combinación. De forma predeterminada, Git pasa los siguientes argumentos al programa diff:
ruta archivo antiguo hexadecimal antiguo modo antiguo archivo nuevo hexadecimal nuevo modo nuevo
Debido a que solo desea los argumentos del archivo antiguo y del archivo nuevo , utiliza el script contenedor para pasar los que
necesita.
Ahora puede configurar su archivo de configuración para usar sus herramientas personalizadas de resolución de combinación y
diferencias. Esto requiere una serie de configuraciones personalizadas: merge.tool para decirle a Git qué estrategia usar,
mergetool.<tool>.cmd para especificar cómo ejecutar el comando, mergetool.<tool>.trustExitCode para decirle a Git si el código de
salida de ese programa indica una resolución de fusión exitosa o no, y diff.external para decirle a Git qué comando ejecutar para
diffs. Entonces, puede ejecutar cuatro comandos de configuración:
[combinar]
herramienta = extMerge
[mergetool "extMerge"] cmd = extMerge "$BASE" "$LOCAL"
"$REMOTE" "$MERGED" trustExitCode = false
[dif]
externo = extDiff
348
Machine Translated by Google
En lugar de obtener la salida diff en la línea de comando, Git activa P4Merge, que se parece a esto:
Si intenta fusionar dos ramas y posteriormente tiene conflictos de fusión, puede ejecutar el comando git mergetool; inicia P4Merge para permitirle
Lo bueno de esta configuración de contenedor es que puede cambiar sus herramientas de diferenciación y combinación fácilmente. Por ejemplo,
para cambiar sus herramientas extDiff y extMerge para ejecutar la herramienta KDiff3, todo lo que tiene que hacer es editar su archivo extMerge :
Ahora, Git utilizará la herramienta KDiff3 para la visualización de diferencias y la resolución de conflictos de fusión.
Git viene preestablecido para usar una serie de otras herramientas de resolución de combinación sin tener que configurar la configuración de
cmd. Para ver una lista de las herramientas que admite, intente esto:
349
Machine Translated by Google
surgir
ÿ
gvimdiff
ÿ
gvimdiff2
ÿ
abierto
ÿ
p4merge
ÿ
vimdiff
ÿ
vimdiff2
araxis
ÿ
bc3
ÿ
comparar código
ÿ
caminante delta
ÿ
difuminar
ÿ
difuso
ÿ
emerger
ÿ
kdiff3
ÿ
fusionar
tkdif
ÿ
tortuga emerge
ÿ
xxdif
Si no está interesado en usar KDiff3 para diferenciar, sino que quiere usarlo solo para la resolución de fusión,
y el comando kdiff3 está en su camino, entonces puede ejecutar:
Si ejecuta esto en lugar de configurar los archivos extMerge y extDiff , Git usará KDiff3 para fusionar
resolución y la herramienta Git diff normal para diffs.
Los problemas de formato y espacios en blanco son algunos de los problemas más sutiles y frustrantes que muchos
encuentran los desarrolladores cuando colaboran, especialmente entre plataformas. Es muy fácil para parches o
otro trabajo colaborado para introducir cambios sutiles en los espacios en blanco porque los editores introducen silenciosamente
y si sus archivos alguna vez tocan un sistema Windows, sus finales de línea podrían ser reemplazados. Git tiene un
pocas opciones de configuración para ayudar con estos problemas.
core.autocrlf
Si está programando en Windows y trabaja con personas que no lo son (o viceversa), podrá
probablemente se encuentre con problemas de final de línea en algún momento. Esto se debe a que Windows usa un carácter de
retorno de carro y un carácter de avance de línea para las nuevas líneas en sus archivos, mientras que macOS y Linux
350
Machine Translated by Google
los sistemas utilizan sólo el carácter de avance de línea. Este es un hecho sutil pero increíblemente molesto del trabajo multiplataforma;
muchos editores en Windows reemplazan silenciosamente los finales de línea de estilo LF existentes con CRLF, o insertan ambos caracteres
Git puede manejar esto convirtiendo automáticamente los finales de línea CRLF en LF cuando agrega un archivo al índice, y viceversa cuando
extrae el código en su sistema de archivos. Puede activar esta funcionalidad con la configuración core.autocrlf . Si está en una máquina con
Windows, configúrelo en verdadero : esto convierte las terminaciones LF en CRLF cuando revisa el código:
Si está en un sistema Linux o macOS que usa finales de línea LF, entonces no quiere que Git los convierta automáticamente cuando extrae
archivos; sin embargo, si se introduce accidentalmente un archivo con terminaciones CRLF, es posible que desee que Git lo arregle. Puede
decirle a Git que convierta CRLF a LF en la confirmación, pero no al revés configurando core.autocrlf para ingresar:
Esta configuración debería dejarte terminaciones CRLF en las cajas de Windows, pero terminaciones LF en los sistemas macOS y Linux y en
el repositorio.
Si es un programador de Windows que realiza un proyecto solo para Windows, puede desactivar esta función y registrar los retornos de carro
core.espacio en blanco
Git viene predeterminado para detectar y solucionar algunos problemas de espacios en blanco. Puede buscar seis problemas principales de
espacios en blanco: tres están habilitados de forma predeterminada y se pueden desactivar, y tres están deshabilitados de forma predeterminada
pero se pueden activar.
Los tres que están activados por defecto son blank-at-eol, que busca espacios al final de una línea; blank-at-eof, que detecta líneas en blanco
al final de un archivo; y space-before-tab, que busca espacios antes de las tabulaciones al principio de una línea.
Los tres que están deshabilitados de forma predeterminada pero que se pueden activar son sangría sin tabulación, que busca líneas que
comienzan con espacios en lugar de tabulaciones (y se controla mediante la opción de ancho de tabulación ); sangría de tabulación, que busca
tabulaciones en la parte de sangría de una línea; y cr-at-eol, que le dice a Git que los retornos de carro al final de las líneas están bien.
Puede decirle a Git cuál de estos desea habilitar configurando core.whitespace en los valores que desea activar o desactivar, separados por
comas. Puede deshabilitar una opción anteponiendo un - delante de su nombre, o usar el valor predeterminado dejándolo completamente fuera
de la cadena de configuración. Por ejemplo, si desea que se configure todo menos el espacio antes de la pestaña , puede hacer esto (con el
espacio final como una abreviatura para cubrir tanto el espacio en blanco en eol como en blanco en eof):
351
Machine Translated by Google
Git detectará estos problemas cuando ejecute un comando git diff e intente colorearlos para que pueda solucionarlos antes de
comprometerse. También usará estos valores para ayudarlo cuando aplique parches con git apply. Cuando esté aplicando
parches, puede pedirle a Git que le avise si está aplicando parches con los problemas de espacios en blanco especificados:
O puede hacer que Git intente solucionar el problema automáticamente antes de aplicar el parche:
Estas opciones también se aplican al comando git rebase . Si cometió problemas de espacios en blanco, pero aún no los ha
actualizado, puede ejecutar git rebase --whitespace=fix para que Git solucione automáticamente los problemas de espacios en
blanco mientras reescribe los parches.
No hay tantas opciones de configuración disponibles para el lado del servidor de Git, pero hay algunas interesantes de las que
quizás desee tomar nota.
recibir.fsckObjects
Git es capaz de asegurarse de que cada objeto recibido durante una inserción aún coincida con su suma de verificación SHA-1
y apunte a objetos válidos. Sin embargo, no hace esto por defecto; es una operación bastante costosa y podría ralentizar la
operación, especialmente en grandes repositorios o envíos. Si desea que Git verifique la coherencia de los objetos en cada
inserción, puede forzarlo a que lo haga configurando receive.fsckObjects en
cierto:
Ahora, Git verificará la integridad de su repositorio antes de que se acepte cada envío para asegurarse de que los clientes
defectuosos (o maliciosos) no introduzcan datos corruptos.
recibir.denyNonFastForwards
Si cambia la base de las confirmaciones que ya envió y luego intenta enviarlas de nuevo, o si intenta enviar una confirmación a
una rama remota que no contiene la confirmación que la rama remota
352
Machine Translated by Google
apunta actualmente, se le negará. En general, esta es una buena política; pero en el caso de la rebase, puede determinar que sabe lo
que está haciendo y puede forzar la actualización de la rama remota con un indicador -f en su comando push.
Para decirle a Git que rechace las inserciones forzadas, configure receive.denyNonFastForwards:
La otra forma en que puede hacer esto es a través de ganchos de recepción del lado del servidor, que cubriremos en un momento.
Ese enfoque le permite hacer cosas más complejas, como negar avances no rápidos a un determinado subconjunto de usuarios.
recibir.denyDeletes
Una de las soluciones a la política denyNonFastForwards es que el usuario elimine la rama y luego la vuelva a insertar con la nueva
referencia. Para evitar esto, establezca receive.denyDeletes en verdadero:
Esto niega cualquier eliminación de ramas o etiquetas; ningún usuario puede hacerlo. Para eliminar sucursales remotas, debe eliminar
los archivos ref del servidor manualmente. También hay formas más interesantes de hacer esto por usuario a través de ACL, como
aprenderá en Ejemplo de política aplicada por Git.
Atributos Git
Algunas de estas configuraciones también se pueden especificar para una ruta, de modo que Git aplique esas configuraciones solo
para un subdirectorio o subconjunto de archivos. Estas configuraciones específicas de la ruta se denominan atributos de Git y se
establecen en un archivo .gitattributes en uno de sus directorios (normalmente la raíz de su proyecto) o en el archivo .git/info/attributes
si no desea el archivo de atributos. comprometidos con tu proyecto.
Con los atributos, puede hacer cosas como especificar estrategias de combinación separadas para archivos o directorios individuales
en su proyecto, decirle a Git cómo diferenciar archivos que no son de texto o hacer que Git filtre el contenido antes de ingresarlo o
sacarlo de Git. En esta sección, aprenderá sobre algunos de los atributos que puede establecer en sus rutas en su proyecto de Git y
verá algunos ejemplos del uso de esta función en la práctica.
Archivos binarios
Un buen truco para el que puede usar los atributos de Git es decirle a Git qué archivos son binarios (en caso de que no pueda
descifrarlo) y darle a Git instrucciones especiales sobre cómo manejar esos archivos. Por ejemplo, algunos archivos de texto pueden
ser generados por una máquina y no diferibles, mientras que algunos archivos binarios sí pueden ser diferidos. Verás cómo decirle a
Git cuál es cuál.
Algunos archivos parecen archivos de texto, pero para todos los efectos deben tratarse como datos binarios. Por ejemplo, los proyectos
de Xcode en macOS contienen un archivo que termina en .pbxproj, que es básicamente un conjunto de datos JSON (formato de datos
de JavaScript de texto sin formato) escrito en el disco por el IDE, que registra la configuración de compilación, etc. Aunque técnicamente
es un archivo de texto (porque todo es UTF-8), no desea tratar
353
Machine Translated by Google
como tal porque es realmente una base de datos liviana: no puede fusionar los contenidos si dos personas lo cambian, y las diferencias
generalmente no son útiles. El archivo está destinado a ser consumido por una máquina. En esencia, desea tratarlo como un archivo
binario.
Para decirle a Git que trate todos los archivos pbxproj como datos binarios, agregue la siguiente línea a su archivo .gitattributes :
*.pbxproj binario
Ahora, Git no intentará convertir ni solucionar problemas de CRLF; ni intentará calcular o imprimir una diferencia para los cambios en
este archivo cuando ejecute git show o git diff en su proyecto.
También puede usar la funcionalidad de atributos de Git para diferenciar archivos binarios de manera efectiva. Para ello, dígale a Git
cómo convertir sus datos binarios a un formato de texto que se pueda comparar a través de la diferencia normal.
Primero, usará esta técnica para resolver uno de los problemas más molestos conocidos por la humanidad: el control de versiones de
documentos de Microsoft Word. Todo el mundo sabe que Word es el editor más horrible que existe, pero, curiosamente, todo el mundo
todavía lo usa. Si desea controlar las versiones de los documentos de Word, puede pegarlos en un repositorio de Git y confirmarlos de
vez en cuando; pero de que sirve eso Si ejecuta git diff normalmente, solo verá algo como esto:
No puede comparar directamente dos versiones a menos que las revise y las escanee manualmente, ¿verdad?
Resulta que puedes hacer esto bastante bien usando los atributos de Git. Ponga la siguiente línea en su archivo .gitattributes :
*.docx diff=palabra
Esto le dice a Git que cualquier archivo que coincida con este patrón (.docx) debe usar el filtro de "palabra" cuando intenta ver una
diferencia que contiene cambios. ¿Qué es el filtro de “palabra”? Tienes que configurarlo. Aquí configurará Git para usar el programa
docx2txt para convertir documentos de Word en archivos de texto legibles, que luego diferenciará correctamente.
Primero, deberá instalar docx2txt; puede descargarlo desde https://sourceforge.net/projects/docx2txt . Siga las instrucciones en el archivo
INSTALL para colocarlo en algún lugar donde su shell pueda encontrarlo. A continuación, escribirá un script contenedor para convertir la
salida al formato que espera Git. Cree un archivo que esté en algún lugar de su ruta llamado docx2txt y agregue estos contenidos:
#!/bin/bash
docx2txt.pl "$1" -
354
Machine Translated by Google
No olvides hacer chmod a+x en ese archivo. Finalmente, puedes configurar Git para usar este script:
Ahora Git sabe que si intenta hacer una diferencia entre dos instantáneas y alguno de los archivos termina en .docx, debe
ejecutar esos archivos a través del filtro de "palabra", que se define como el programa docx2txt . Esto efectivamente crea
buenas versiones basadas en texto de sus archivos de Word antes de intentar diferenciarlos.
He aquí un ejemplo: el capítulo 1 de este libro se convirtió a formato Word y se comprometió en un repositorio de Git. Luego
se agregó un nuevo párrafo. Esto es lo que muestra git diff :
Git nos dice de manera exitosa y sucinta que agregamos la cadena "Pruebas: 1, 2, 3", lo cual es correcto.
No es perfecto (los cambios de formato no se mostrarían aquí), pero sin duda funciona.
Otro problema interesante que puede resolver de esta manera consiste en diferenciar archivos de imagen. Una forma de
hacer esto es pasar archivos de imagen a través de un filtro que extrae su información EXIF: metadatos que se registran.
355
Machine Translated by Google
con la mayoría de los formatos de imagen. Si descarga e instala el programa exiftool , puede usarlo para
convierta sus imágenes en texto sobre los metadatos, por lo que al menos la diferencia le mostrará un texto
representación de cualquier cambio que haya ocurrido. Ponga la siguiente línea en su archivo .gitattributes :
*.png diferencia=exif
Si reemplaza una imagen en su proyecto y ejecuta git diff, verá algo como esto:
Puede ver fácilmente que el tamaño del archivo y las dimensiones de la imagen han cambiado.
Los desarrolladores acostumbrados a esos sistemas a menudo solicitan la expansión de palabras clave de estilo SVN o CVS. los
El problema principal con esto en Git es que no puedes modificar un archivo con información sobre la confirmación.
después de que te hayas comprometido, porque Git primero hace una suma de verificación del archivo. Sin embargo, puede inyectar texto en un archivo
cuando esté desprotegido y elimínelo nuevamente antes de agregarlo a una confirmación. Los atributos de Git te ofrecen
Primero, puede inyectar la suma de verificación SHA-1 de un blob en un campo $Id$ en el archivo automáticamente. Si usted
establece este atributo en un archivo o conjunto de archivos, luego, la próxima vez que revise esa rama, Git lo hará
reemplace ese campo con el SHA-1 del blob. Es importante notar que no es el SHA-1 del
commit, sino del propio blob. Ponga la siguiente línea en su archivo .gitattributes :
356
Machine Translated by Google
*.txt identificación
La próxima vez que revise este archivo, Git inyecta el SHA-1 del blob:
$ rm test.txt $
git checkout -- test.txt $ cat
test.txt $Id:
42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $
Sin embargo, ese resultado es de uso limitado. Si usó la sustitución de palabras clave en CVS o Subversion, puede incluir una
marca de fecha: el SHA-1 no es tan útil porque es bastante aleatorio y no puede saber si un SHA-1 es más antiguo o más nuevo
que otro. con solo mirarlos.
Resulta que puede escribir sus propios filtros para hacer sustituciones en los archivos al confirmar/pagar.
Estos se denominan filtros "limpios" y "difuminados". En el archivo .gitattributes , puede configurar un filtro para rutas particulares
y luego configurar secuencias de comandos que procesarán los archivos justo antes de que se desprotejan ("difuminar", consulte
El filtro "difuminado" se ejecuta al finalizar la compra) y justo antes de que están preparados ("limpiar", consulte El filtro "limpio"
se ejecuta cuando los archivos están preparados). Estos filtros se pueden configurar para hacer todo tipo de cosas divertidas.
357
Machine Translated by Google
El mensaje de confirmación original para esta característica brinda un ejemplo simple de cómo ejecutar todo su
código fuente C a través del programa de sangría antes de confirmar. Puede configurarlo configurando el atributo de
filtro en su archivo .gitattributes para filtrar archivos \*.c con el filtro "sangría":
*.c filtro=sangría
En este caso, cuando envíe archivos que coincidan con *.c, Git los ejecutará a través del programa de sangría antes
de prepararlos y luego los ejecutará a través del programa cat antes de volver a registrarlos en el disco. El programa
cat esencialmente no hace nada: escupe los mismos datos que vienen. Esta combinación filtra efectivamente todos
los archivos de código fuente C a través de la sangría antes de confirmar.
Otro ejemplo interesante es la expansión de la palabra clave $Date$ , estilo RCS. Para hacer esto correctamente,
necesita un pequeño script que tome un nombre de archivo, calcule la última fecha de confirmación para este
proyecto e inserte la fecha en el archivo. Aquí hay un pequeño script de Ruby que hace eso:
Todo lo que hace el script es obtener la fecha de confirmación más reciente del comando git log , pegarla en cualquier
cadena $Date$ que vea en stdin e imprimir los resultados; debería ser fácil de hacer en cualquier idioma en el que
se sienta más cómodo. Puede nombrar este archivo expand_date y ponerlo en su ruta. Ahora, necesitas
358
Machine Translated by Google
configure un filtro en Git ( llámelo dater ) y dígale que use su filtro expand_date para borrar los archivos al finalizar la
compra. Usarás una expresión de Perl para limpiar eso en la confirmación:
Este fragmento de código de Perl elimina todo lo que ve en una cadena $Date$ , para volver al punto de partida. Ahora
que su filtro está listo, puede probarlo configurando un atributo Git para ese archivo que involucra el nuevo filtro y
creando un archivo con su palabra clave $Date$ :
fecha*.txt filtro=fecha
Si confirma esos cambios y revisa el archivo nuevamente, verá la palabra clave correctamente sustituida:
Puede ver cuán poderosa puede ser esta técnica para aplicaciones personalizadas. Sin embargo, debe tener cuidado,
porque el archivo .gitattributes se confirma y pasa con el proyecto, pero el controlador (en este caso, dater) no lo está,
por lo que no funcionará en todas partes. Cuando diseñe estos filtros, deberían poder fallar correctamente y hacer que
el proyecto siga funcionando correctamente.
Exportando tu repositorio
Los datos de atributos de Git también le permiten hacer algunas cosas interesantes al exportar un archivo de su
proyecto.
exportar-ignorar
Puede decirle a Git que no exporte ciertos archivos o directorios al generar un archivo. Si hay un subdirectorio o
archivo que no desea incluir en su archivo de almacenamiento pero que sí desea registrar en su proyecto, puede
determinar esos archivos a través del atributo exportar-ignorar .
Por ejemplo, digamos que tiene algunos archivos de prueba en un subdirectorio test/ y no tiene sentido incluirlos en la
exportación tarball de su proyecto. Puede agregar la siguiente línea a su archivo de atributos de Git:
probar/exportar-ignorar
359
Machine Translated by Google
Ahora, cuando ejecuta git archive para crear un tarball de su proyecto, ese directorio no se incluirá en el archivo.
exportar-sust
Al exportar archivos para su implementación, puede aplicar el formato de git log y el procesamiento de expansión de palabras
clave a partes seleccionadas de archivos marcados con el atributo `export-subst.
Por ejemplo, si desea incluir un archivo llamado LAST_COMMIT en su proyecto y tener metadatos sobre la última confirmación
inyectada automáticamente cuando se ejecuta el archivo git , puede, por ejemplo, configurar sus archivos .gitattributes y
LAST_COMMIT de esta manera:
Cuando ejecuta git archive, el contenido del archivo archivado se verá así:
Las sustituciones pueden incluir, por ejemplo, el mensaje de confirmación y cualquier nota de git, y el registro de git puede
hacer un ajuste de texto simple:
'
El archivo resultante es adecuado para el trabajo de implementación, pero como cualquier archivo exportado, no es adecuado
para trabajos de desarrollo posteriores.
360
Machine Translated by Google
fusionar estrategias
También puede usar los atributos de Git para decirle a Git que use diferentes estrategias de combinación para archivos específicos
en su proyecto. Una opción muy útil es decirle a Git que no intente fusionar archivos específicos cuando tengan conflictos, sino
que use su lado de la fusión sobre el de otra persona.
Esto es útil si una rama en su proyecto se ha separado o está especializada, pero desea poder fusionar los cambios nuevamente
y desea ignorar ciertos archivos. Supongamos que tiene un archivo de configuración de la base de datos llamado base de
datos.xml que es diferente en dos ramas y desea fusionarse en su otra rama sin estropear el archivo de la base de datos. Puede
configurar un atributo como este:
Si se fusiona en la otra rama, en lugar de tener conflictos de fusión con el archivo base de datos.xml, verá algo como esto:
Ganchos Git
Como muchos otros sistemas de control de versiones, Git tiene una forma de activar secuencias de comandos personalizadas
cuando ocurren ciertas acciones importantes. Hay dos grupos de estos ganchos: del lado del cliente y del lado del servidor. Los
enlaces del lado del cliente se activan mediante operaciones como la confirmación y la fusión, mientras que los enlaces del lado
del servidor se ejecutan en operaciones de red, como la recepción de confirmaciones enviadas. Puede usar estos ganchos por
todo tipo de razones.
Instalar un gancho
Todos los ganchos se almacenan en el subdirectorio de ganchos del directorio Git. En la mayoría de los proyectos, eso es .git/
hooks. Cuando inicializa un nuevo repositorio con git init, Git llena el directorio de ganchos con un montón de scripts de ejemplo,
muchos de los cuales son útiles por sí mismos; pero también documentan los valores de entrada de cada script. Todos los
ejemplos están escritos como scripts de shell, con algo de Perl incorporado, pero cualquier script ejecutable con el nombre
adecuado funcionará bien; puede escribirlos en Ruby o Python o en cualquier idioma con el que esté familiarizado. Si desea
utilizar los scripts de enlace incluidos, tendrá que cambiarles el nombre; todos sus nombres de archivo terminan con .sample.
Para habilitar un script de enlace, coloque un archivo en el subdirectorio de enlaces de su directorio .git que tenga el nombre
adecuado (sin ninguna extensión) y sea ejecutable. A partir de ese momento, debe ser
361
Machine Translated by Google
Hay muchos ganchos del lado del cliente. Esta sección los divide en ganchos de flujo de trabajo de confirmación, scripts de flujo de trabajo de correo
Es importante tener en cuenta que los ganchos del lado del cliente no se copian cuando clona un repositorio. Si su intención
ÿ con estos scripts es hacer cumplir una política, probablemente querrá hacerlo en el lado del servidor; consulte el ejemplo en
Los primeros cuatro ganchos tienen que ver con el proceso de confirmación.
El enlace previo a la confirmación se ejecuta primero, incluso antes de escribir un mensaje de confirmación. Se usa para inspeccionar la instantánea
que está a punto de ser confirmada, para ver si olvidó algo, para asegurarse de que se ejecuten las pruebas o para examinar cualquier cosa que
necesite inspeccionar en el código. Salir de este gancho con un valor distinto de cero aborta la confirmación, aunque puede omitirla con git commit --
no-verify. Puede hacer cosas como verificar el estilo del código (ejecutar lint o algo equivalente), buscar espacios en blanco al final (el enlace
predeterminado hace exactamente esto) o buscar la documentación adecuada sobre nuevos métodos.
El gancho prepare-commit-msg se ejecuta antes de que se active el editor de mensajes de confirmación, pero después de que se cree el mensaje
predeterminado. Te permite editar el mensaje predeterminado antes de que el autor de la confirmación lo vea.
Este enlace toma algunos parámetros: la ruta al archivo que contiene el mensaje de confirmación hasta el momento, el tipo de confirmación y la
confirmación SHA-1 si se trata de una confirmación modificada. Este enlace generalmente no es útil para confirmaciones normales; más bien, es
bueno para confirmaciones en las que el mensaje predeterminado se genera automáticamente, como mensajes de confirmación con plantilla,
confirmaciones de combinación, confirmaciones aplastadas y confirmaciones modificadas. Puede usarlo junto con una plantilla de confirmación para
El enlace commit-msg toma un parámetro, que nuevamente es la ruta a un archivo temporal que contiene el mensaje de confirmación escrito por el
desarrollador. Si este script sale distinto de cero, Git cancela el proceso de confirmación, por lo que puede usarlo para validar el estado de su proyecto
o el mensaje de confirmación antes de permitir que se realice una confirmación. En la última sección de este capítulo, demostraremos el uso de este
enlace para verificar que su mensaje de confirmación cumpla con un patrón requerido.
Una vez que se completa todo el proceso de confirmación, se ejecuta el gancho posterior a la confirmación . No requiere ningún parámetro, pero
puede obtener fácilmente la última confirmación ejecutando git log -1 HEAD. Generalmente, este script se usa para notificaciones o algo similar.
Puede configurar tres enlaces del lado del cliente para un flujo de trabajo basado en correo electrónico. Todos son invocados por el comando git am ,
por lo que si no está usando ese comando en su flujo de trabajo, puede pasar con seguridad a la siguiente sección. Si está tomando parches por
correo electrónico preparados por git format-patch, entonces algunos de estos pueden serle útiles.
El primer enlace que se ejecuta es applypatch-msg. Toma un solo argumento: el nombre del temporal
362
Machine Translated by Google
archivo que contiene el mensaje de confirmación propuesto. Git aborta el parche si este script sale distinto de cero.
Puede usar esto para asegurarse de que un mensaje de confirmación tenga el formato correcto o para normalizar el mensaje haciendo
que el script lo edite en su lugar.
El siguiente enlace que se ejecuta al aplicar parches a través de git am es pre-applypatch. De forma un tanto confusa, se ejecuta después
de que se aplica el parche pero antes de que se realice una confirmación, por lo que puede usarlo para inspeccionar la instantánea antes
de realizar la confirmación. Puede ejecutar pruebas o inspeccionar el árbol de trabajo con este script. Si falta algo o las pruebas no pasan,
salir de cero cancela el script git am sin confirmar el parche.
El último enlace que se ejecuta durante una operación de git am es post-applypatch, que se ejecuta después de realizar la confirmación.
Puede usarlo para notificar a un grupo o al autor del parche que sacó que lo ha hecho.
No puede detener el proceso de aplicación de parches con este script.
El enlace de pre-rebase se ejecuta antes de que rebase cualquier cosa y puede detener el proceso al salir de un valor distinto de cero.
Puede usar este gancho para no permitir el rebase de cualquier confirmación que ya se haya enviado. El ejemplo de gancho previo a la
reorganización que instala Git hace esto, aunque hace algunas suposiciones que pueden no coincidir con su flujo de trabajo.
El enlace posterior a la reescritura se ejecuta mediante comandos que reemplazan las confirmaciones, como git commit --amend y git
rebase (aunque no mediante git filter-branch). Su único argumento es qué comando activó la reescritura y recibe una lista de reescrituras
en stdin. Este gancho tiene muchos de los mismos usos que los ganchos posteriores a la compra y posteriores a la fusión .
Después de ejecutar un pago de Git con éxito, se ejecuta el gancho posterior al pago ; puede usarlo para configurar su directorio de
trabajo correctamente para el entorno de su proyecto. Esto puede significar mover archivos binarios grandes que no desea controlar la
fuente, documentación de generación automática, o algo por el estilo.
El enlace posterior a la combinación se ejecuta después de un comando de combinación exitoso. Puede usarlo para restaurar datos en
el árbol de trabajo que Git no puede rastrear, como datos de permisos. Este enlace también puede validar la presencia de archivos
externos al control de Git que puede querer copiar cuando cambie el árbol de trabajo.
El gancho previo al envío se ejecuta durante el envío de git, después de que se hayan actualizado las referencias remotas pero antes de
que se hayan transferido los objetos. Recibe el nombre y la ubicación del control remoto como parámetros, y una lista de referencias a
actualizar a través de stdin. Puede usarlo para validar un conjunto de actualizaciones de referencia antes de que se produzca una
inserción (un código de salida distinto de cero anulará la inserción).
Ocasionalmente, Git realiza la recolección de elementos no utilizados como parte de su funcionamiento normal, al invocar git gc --auto.
El gancho pre-auto-gc se invoca justo antes de que se lleve a cabo la recolección de elementos no utilizados y se puede usar para
notificarle que esto está sucediendo o para cancelar la recolección si ahora no es un buen momento.
Además de los enlaces del lado del cliente, puede usar un par de enlaces del lado del servidor importantes como administrador del
sistema para aplicar casi cualquier tipo de política para su proyecto. Estos scripts se ejecutan antes y después de las inserciones en el
servidor. Los ganchos previos pueden salir distintos de cero en cualquier momento para rechazar el empuje, así como
363
Machine Translated by Google
imprimir un mensaje de error al cliente; puede configurar una política de inserción tan compleja como desee.
pre-recibir
La primera secuencia de comandos que se ejecuta cuando se maneja una inserción de un cliente es la recepción previa. Toma una
lista de referencias que se envían desde stdin; si sale distinto de cero, no se acepta ninguno de ellos. Puede usar este enlace para
hacer cosas como asegurarse de que ninguna de las referencias actualizadas no sea de avance rápido, o para controlar el acceso a
todas las referencias y archivos que están modificando con el empuje.
actualizar
La secuencia de comandos de actualización es muy similar a la secuencia de comandos previa a la recepción , excepto que se ejecuta
una vez para cada rama que el pusher intenta actualizar. Si el empujador está tratando de empujar a varias ramas, la recepción previa
se ejecuta solo una vez, mientras que la actualización se ejecuta una vez por rama a la que están empujando. En lugar de leer desde
la entrada estándar, este script toma tres argumentos: el nombre de la referencia (rama), el SHA-1 al que apuntaba la referencia antes
de la inserción y el SHA-1 que el usuario está tratando de insertar. Si el script de actualización sale distinto de cero, solo se rechaza
esa referencia; otras referencias aún se pueden actualizar.
post-recepción
El enlace posterior a la recepción se ejecuta después de que se completa todo el proceso y se puede usar para actualizar otros
servicios o notificar a los usuarios. Toma los mismos datos estándar que el gancho de pre-recepción . Los ejemplos incluyen enviar
una lista por correo electrónico, notificar a un servidor de integración continua o actualizar un sistema de seguimiento de tickets; incluso
puede analizar los mensajes de confirmación para ver si es necesario abrir, modificar o cerrar algún ticket.
Esta secuencia de comandos no puede detener el proceso de inserción, pero el cliente no se desconecta hasta que se completa, así
que tenga cuidado si intenta hacer algo que pueda llevar mucho tiempo.
Los scripts que mostraremos están escritos en Ruby; en parte por nuestra inercia intelectual, pero también porque Ruby es fácil de
leer, incluso si no necesariamente puedes escribirlo. Sin embargo, cualquier idioma funcionará: todas las secuencias de comandos de
enlace de muestra distribuidas con Git están en Perl o Bash, por lo que también puede ver muchos ejemplos de enlaces en esos
idiomas al mirar las muestras.
Todo el trabajo del lado del servidor irá al archivo de actualización en su directorio de ganchos . El enlace de actualización se ejecuta
una vez por cada rama que se empuja y toma tres argumentos:
364
Machine Translated by Google
También tiene acceso al usuario que realiza la inserción si la inserción se ejecuta a través de SSH. Si ha permitido que todos se
conecten con un solo usuario (como "git") a través de la autenticación de clave pública, es posible que deba darle a ese usuario un
contenedor de shell que determine qué usuario se está conectando en función de la clave pública y establecer un entorno. variable
en consecuencia. Aquí supondremos que el usuario que se conecta está en la variable de entorno $USER , por lo que su secuencia
de comandos de actualización comienza reuniendo toda la información que necesita:
#!/usr/bin/env rubí
$refname = ARGV[0]
$oldrev = ARGV[1]
$newrev = ARGV[2]
$usuario = ENV['USUARIO']
Sí, esas son variables globales. No juzgues, es más fácil demostrarlo de esta manera.
Su primer desafío es hacer cumplir que cada mensaje de confirmación se adhiera a un formato particular. Solo para tener un objetivo,
suponga que cada mensaje debe incluir una cadena que se parezca a "ref: 1234" porque desea que cada compromiso se vincule a
un elemento de trabajo en su sistema de tickets. Debe observar cada confirmación que se envía hacia arriba, ver si esa cadena está
en el mensaje de confirmación y, si la cadena está ausente en alguna de las confirmaciones, salir con un valor distinto de cero para
que se rechace la inserción.
Puede obtener una lista de los valores SHA-1 de todas las confirmaciones que se envían tomando los valores $newrev y $oldrev y
pasándolos a un comando de plomería de Git llamado git rev-list. Este es básicamente el comando git log , pero de manera
predeterminada, solo imprime los valores SHA-1 y ninguna otra información. Entonces, para obtener una lista de todos los SHA-1 de
confirmación introducidos entre un SHA-1 de confirmación y otro, puede ejecutar algo como esto:
Puede tomar esa salida, recorrer cada uno de esos SHA-1 confirmados, capturar el mensaje y probar ese mensaje con una expresión
regular que busca un patrón.
Debe descubrir cómo obtener el mensaje de confirmación de cada una de estas confirmaciones para probar. Para obtener el
365
Machine Translated by Google
datos de confirmación sin procesar, puede usar otro comando de plomería llamado git cat-file. Repasaremos todos estos comandos de
plomería en detalle en Git Internals; pero por ahora, esto es lo que da ese comando
usted:
Una forma sencilla de obtener el mensaje de confirmación de una confirmación cuando tiene el valor SHA-1 es ir a la primera línea en
blanco y tomar todo lo que sigue. Puede hacerlo con el comando sed en los sistemas Unix:
Puede usar ese conjuro para obtener el mensaje de confirmación de cada confirmación que se intenta enviar y salir si ve algo que no
coincide. Para salir de la secuencia de comandos y rechazar la inserción, salga de un valor distinto de cero. Todo el método se ve así:
final
final final
comprobar_mensaje_formato
Poner eso en su secuencia de comandos de actualización rechazará las actualizaciones que contienen confirmaciones que tienen mensajes
que no se adhieren a su regla.
Suponga que desea agregar un mecanismo que utiliza una lista de control de acceso (ACL) que especifica qué usuarios pueden enviar
cambios a qué partes de sus proyectos. Algunas personas tienen acceso completo y otras solo pueden enviar cambios a ciertos
subdirectorios o archivos específicos. Para hacer cumplir esto, escribirá esas reglas en un archivo llamado acl que se encuentra en su
repositorio Git básico en el servidor. Tendras
366
Machine Translated by Google
el gancho de actualización mira esas reglas, ve qué archivos se están introduciendo para todas las confirmaciones
que se envían y determina si el usuario que realiza el envío tiene acceso para actualizar todos esos archivos.
Lo primero que harás es escribir tu ACL. Aquí utilizará un formato muy parecido al mecanismo CVS ACL: utiliza una
serie de líneas, donde el primer campo es disponible o no disponible, el siguiente campo es una lista delimitada por
comas de los usuarios a los que se aplica la regla y el último campo es la ruta a la que se aplica la regla (en blanco
significa acceso abierto). Todos estos campos están delimitados por un carácter de barra vertical (|) .
En este caso, tiene un par de administradores, algunos escritores de documentación con acceso al directorio doc y
un desarrollador que solo tiene acceso a los directorios lib y tests , y su archivo ACL se ve así:
aproveche|nickh,pjhyett,defunkt,tpw
aproveche|usinclair,cdickens,ebronte|doc
aproveche|schacon|lib aproveche|schacon|
pruebas
Comienza leyendo estos datos en una estructura que puedes usar. En este caso, para simplificar el ejemplo, solo
aplicará las directivas de disponibilidad . Aquí hay un método que le brinda una matriz asociativa donde la clave es el
nombre de usuario y el valor es una matriz de rutas en las que el usuario ha escrito
acceso:
def get_acl_access_data(acl_file) #
leer datos ACL
''
acl_file = File.read(acl_file).split("\n").reject { |line| línea == acceso = {} }
acl_file.each hacer |línea| disponibilidad, usuarios, ruta = línea.split('|') siguiente
a menos que disponibilidad == 'disponibilidad' usuarios.split(',').each do |
usuario| acceso[usuario] ||= [] acceso[usuario] << ruta fin fin
acceso
final
En el archivo ACL que vio anteriormente, este método get_acl_access_data devuelve una estructura de datos que
se ve así:
367
Machine Translated by Google
{"defunkt"=>[nil],
"tpw"=>[nil],
"nickh"=>[nil],
"pjhyett"=>[nil],
"schacon"=>["lib", "tests" ],
"cdickens"=>["doc"],
"usinclair"=>["doc"],
"ebronte"=>["doc"]}
Ahora que tiene los permisos ordenados, debe determinar qué rutas han modificado las confirmaciones que
se están enviando, para que pueda asegurarse de que el usuario que está enviando tenga acceso a todas ellas.
Puede ver con bastante facilidad qué archivos se han modificado en una sola confirmación con la opción --
name-only del comando git log (mencionado brevemente en Git Basics):
LÉAME
lib/prueba.rb
Si usa la estructura ACL devuelta por el método get_acl_access_data y la compara con los archivos
enumerados en cada una de las confirmaciones, puede determinar si el usuario tiene acceso para enviar todas
sus confirmaciones:
368
Machine Translated by Google
siguiente si ruta.tamaño == 0
ÿ
tiene_archivo_acceso = falso
ÿ
acceso[$usuario].each do |access_path|
ÿ
tiene_archivo_acceso = verdadero
ÿ
final
ÿ
final
ÿ
si !tiene_archivo_acceso
ÿ
salida 1
ÿ
final
final
final
final
verificar_directorio_permisos
Obtiene una lista de nuevas confirmaciones que se envían a su servidor con git rev-list. Entonces, para cada uno de esos
confirma, encuentra qué archivos se modifican y se asegura de que el usuario que está presionando tenga acceso a todos
las rutas que se modifican.
Ahora sus usuarios no pueden enviar confirmaciones con mensajes mal formados o con archivos modificados fuera
de sus caminos designados.
Probarlo
Si ejecuta chmod u+x .git/hooks/update, que es el archivo en el que debería haber puesto todo esto
código, y luego intenta enviar una confirmación con un mensaje no conforme, obtiene algo como esto:
369
Machine Translated by Google
Hay un par de cosas interesantes aquí. Primero, ves esto donde el gancho comienza a correr.
Aplicación de políticas...
(refs/heads/master) (fb8c72) (c56860)
Recuerde que lo imprimió al principio de su secuencia de comandos de actualización. Cualquier cosa que su secuencia de
comandos haga eco en la salida estándar se transferirá al cliente.
Usted imprimió la primera línea, las otras dos fueron Git diciéndole que la secuencia de comandos de actualización salió de un
valor distinto de cero y eso es lo que está rechazando su impulso. Por último, tienes esto:
Para git@gitserver:project.git !
[remoto rechazado] maestro -> maestro (gancho rechazado) error:
no se pudo enviar algunas referencias a 'git@gitserver:project.git'
Verá un mensaje de rechazo remoto para cada referencia que su enlace rechazó, y le indica que se rechazó específicamente
debido a una falla en el enlace.
Además, si alguien intenta editar un archivo al que no tiene acceso y envía una confirmación que lo contiene, verá algo similar.
Por ejemplo, si un autor de documentación intenta enviar una confirmación modificando algo en el directorio lib , verá:
370
Machine Translated by Google
De ahora en adelante, siempre que el script de actualización esté allí y sea ejecutable, su repositorio nunca tendrá
un mensaje de confirmación sin su patrón y sus usuarios estarán en un espacio aislado.
La desventaja de este enfoque es el lloriqueo que inevitablemente resultará cuando se rechacen los envíos de
confirmación de los usuarios. Que su trabajo cuidadosamente elaborado sea rechazado en el último minuto puede
ser extremadamente frustrante y confuso; y además, tendrán que editar su historial para corregirlo, lo que no siempre
es para los débiles de corazón.
La respuesta a este dilema es proporcionar algunos ganchos del lado del cliente que los usuarios pueden ejecutar
para notificarles cuando están haciendo algo que es probable que el servidor rechace. De esa manera, pueden
corregir cualquier problema antes de comprometerse y antes de que esos problemas se vuelvan más difíciles de
solucionar. Debido a que los ganchos no se transfieren con un clon de un proyecto, debe distribuir estos scripts de
alguna otra manera y luego hacer que sus usuarios los copien en su directorio .git/hooks y hacerlos ejecutables.
Puede distribuir estos ganchos dentro del proyecto o en un proyecto separado, pero Git no los configurará
automáticamente.
Para comenzar, debe verificar su mensaje de confirmación justo antes de que se registre cada confirmación, para
que sepa que el servidor no rechazará sus cambios debido a mensajes de confirmación mal formateados. Para
hacer esto, puede agregar el enlace commit-msg . Si tiene que leer el mensaje del archivo pasado como primer
argumento y compararlo con el patrón, puede obligar a Git a cancelar la confirmación si no hay ninguna coincidencia:
#!/usr/bin/env ruby
archivo_mensaje = ARGV[0]
mensaje = Archivo.leer(archivo_mensaje)
if !$regex.match(message) pone
"[POLICY] Su mensaje no tiene el formato correcto" exit 1
final
Si ese script está en su lugar (en .git/hooks/commit-msg) y es ejecutable, y confirma con un mensaje que no tiene el
formato correcto, verá esto:
No se completó ninguna confirmación en esa instancia. Sin embargo, si su mensaje contiene el patrón adecuado,
Git le permite confirmar:
371
Machine Translated by Google
A continuación, desea asegurarse de que no está modificando archivos que están fuera del alcance de su ACL. Si el
directorio .git de su proyecto contiene una copia del archivo ACL que usó anteriormente, entonces el siguiente script
de confirmación previa aplicará esas restricciones por usted:
#!/usr/bin/env rubí
$usuario = ENV['USUARIO']
# solo permite que ciertos usuarios modifiquen ciertos subdirectorios en un proyecto def
check_directory_perms access = get_acl_access_data('.git/acl')
has_file_access = final
verdadero
if !has_file_access pone
ÿ
final
final
final
verificar_directorio_permisos
Este es aproximadamente el mismo script que la parte del lado del servidor, pero con dos diferencias importantes.
Primero, el archivo ACL está en un lugar diferente, porque este script se ejecuta desde su directorio de trabajo, no
desde su directorio .git . Tienes que cambiar la ruta al archivo ACL de esto:
acceso = get_acl_access_data('acl')
a esto:
acceso = get_acl_access_data('.git/acl')
La otra diferencia importante es la forma en que obtiene una lista de los archivos que se han modificado.
Debido a que el método del lado del servidor mira el registro de confirmaciones y, en este punto, la confirmación aún
no se ha registrado, en su lugar, debe obtener su lista de archivos del área de preparación. En lugar de:
372
Machine Translated by Google
Pero esas son las únicas dos diferencias; de lo contrario, el script funciona de la misma manera. Una advertencia es que
espera que se ejecute localmente como el mismo usuario que presiona en la máquina remota. Si eso es diferente, debe
configurar la variable $user manualmente.
Otra cosa que podemos hacer aquí es asegurarnos de que el usuario no inserte referencias que no sean de avance rápido.
Para obtener una referencia que no sea un avance rápido, debe volver a establecer una base más allá de una confirmación
que ya ha enviado o intentar enviar una rama local diferente a la misma rama remota.
Aquí hay un ejemplo de secuencia de comandos previa a la reorganización que verifica eso. Obtiene una lista de todas las
confirmaciones que está a punto de reescribir y verifica si existen en alguna de sus referencias remotas. Si ve uno al que
se puede acceder desde una de sus referencias remotas, aborta la reorganización.
#!/usr/bin/env rubí
base_branch = ARGV[0]
if ARGV[1] topic_branch
= ARGV[1] else topic_branch
= "HEAD" end
final final
final
Este script usa una sintaxis que no se trató en Selección de revisión. Obtiene una lista de confirmaciones que ya se han
subido al ejecutar esto:
373
Machine Translated by Google
La sintaxis SHA^@ se resuelve en todos los padres de esa confirmación. Está buscando cualquier compromiso al que se
pueda acceder desde el último compromiso en el control remoto y que no sea accesible desde ningún padre de ninguno
de los SHA-1 que está tratando de subir, lo que significa que es un avance rápido.
El principal inconveniente de este enfoque es que puede ser muy lento y, a menudo, innecesario: si no intenta forzar la
inserción con -f, el servidor le advertirá y no aceptará la inserción. Sin embargo, es un ejercicio interesante y, en teoría,
puede ayudarlo a evitar una reorganización que luego tendrá que regresar y corregir.
Resumen
Hemos cubierto la mayoría de las principales formas en que puede personalizar su cliente y servidor Git para que se
ajuste mejor a su flujo de trabajo y proyectos. Aprendió sobre todo tipo de opciones de configuración, atributos basados
en archivos y enlaces de eventos, y creó un servidor de aplicación de políticas de ejemplo. Ahora debería poder hacer
que Git se ajuste a casi cualquier flujo de trabajo que pueda soñar.
374
Machine Translated by Google
En algún momento, es posible que desee convertir su proyecto existente a Git. La segunda parte de este capítulo cubre
cómo migrar su proyecto a Git desde varios sistemas específicos, así como un método que funcionará si no existe una
herramienta de importación preconstruida.
Git y subversión
Una gran fracción de los proyectos de desarrollo de código abierto y una buena cantidad de proyectos corporativos
utilizan Subversion para administrar su código fuente. Ha existido durante más de una década, y durante la mayor parte
de ese tiempo fue la elección de facto de VCS para proyectos de código abierto. También es muy similar en muchos
aspectos a CVS, que antes de eso era el chico grande del mundo del control de código fuente.
Una de las grandes características de Git es un puente bidireccional a Subversion llamado git svn. Esta herramienta le
permite usar Git como un cliente válido para un servidor Subversion, por lo que puede usar todas las funciones locales
de Git y luego enviar a un servidor Subversion como si estuviera usando Subversion localmente. Esto significa que puede
hacer bifurcaciones y fusiones locales, usar el área de preparación, usar rebase y selección selectiva, etc., mientras sus
colaboradores continúan trabajando en sus formas oscuras y antiguas. Es una buena manera de colar a Git en el entorno
corporativo y ayudar a sus compañeros desarrolladores a ser más eficientes mientras presiona para que se cambie la
infraestructura para admitir completamente a Git. El puente Subversion es la droga de entrada al mundo DVCS.
git svn
El comando base en Git para todos los comandos puente de Subversion es git svn. Se requieren bastantes comandos,
por lo que mostraremos los más comunes mientras revisamos algunos flujos de trabajo simples.
Es importante tener en cuenta que cuando usa git svn, está interactuando con Subversion, que es un sistema que
funciona de manera muy diferente a Git. Si bien puede realizar bifurcaciones y fusiones locales, generalmente es mejor
mantener su historial lo más lineal posible reorganizando su trabajo y evitando hacer cosas como interactuar
simultáneamente con un repositorio remoto de Git.
No reescriba su historial e intente empujar de nuevo, y no empuje a un repositorio de Git paralelo para colaborar con
otros desarrolladores de Git al mismo tiempo. Subversion solo puede tener un único historial lineal, y confundirlo es muy
fácil. Si está trabajando con un equipo, y algunos usan SVN y otros usan Git, asegúrese de que todos estén usando el
servidor SVN para colaborar; hacerlo hará que
375
Machine Translated by Google
Configuración
Para demostrar esta funcionalidad, necesita un repositorio SVN típico al que tenga acceso de escritura.
Si desea copiar estos ejemplos, tendrá que hacer una copia grabable de un repositorio de prueba SVN.
Para hacerlo fácilmente, puede usar una herramienta llamada svnsync que viene con Subversion.
$ mkdir /tmp/prueba-svn $
svnadmin create /tmp/prueba-svn
Luego, habilite a todos los usuarios para que cambien los revprops; la manera fácil es agregar un script previo al cambio de revprop
que siempre sale en 0:
Ahora puede sincronizar este proyecto con su máquina local llamando a svnsync init con los repositorios hacia y desde.
Esto configura las propiedades para ejecutar la sincronización. A continuación, puede clonar el código ejecutando:
Aunque esta operación puede tardar solo unos minutos, si intenta copiar el repositorio original a otro repositorio remoto en
lugar de uno local, el proceso tardará casi una hora, aunque haya menos de 100 confirmaciones. Subversion tiene que clonar
una revisión a la vez y luego devolverla a otro repositorio; es ridículamente ineficiente, pero es la única manera fácil de hacerlo.
Empezando
Ahora que tiene un repositorio de Subversion al que tiene acceso de escritura, puede realizar un flujo de trabajo típico.
Comenzará con el comando git svn clone , que importa un Subversion completo
376
Machine Translated by Google
repositorio en un repositorio Git local. Recuerde que si está importando desde un repositorio de Subversion
alojado real, debe reemplazar el archivo:///tmp/test-svn aquí con la URL de su repositorio de Subversion:
$ git svn clone file:///tmp/test-svn -T trunk -b branch -t tags Repositorio Git vacío
inicializado en /private/tmp/progit/test-svn/.git/ r1 =
dcbfb5891860124cc2e8cc616cded42624897125 (refs/remotes/ origen/tronco)
A m4/acx_pthread.m4 A m4/
stl_hash.m4 A java/src/test/
java/com/google/protobuf/UnknownFieldSetTest.java A java/src/test/java/com/google/
protobuf/WireFormatTest.java
…
Esto ejecuta el equivalente a dos comandos: git svn init seguido de git svn fetch , en la URL que proporcione.
Esto puede tomar un tiempo. Si, por ejemplo, el proyecto de prueba tiene solo alrededor de 75 confirmaciones
y el código base no es tan grande, Git debe verificar cada versión, una a la vez, y confirmarlas
individualmente. Para un proyecto con cientos o miles de confirmaciones, esto puede tardar literalmente
horas o incluso días en finalizar.
La parte -T trunk -b branch -t tags le dice a Git que este repositorio de Subversion sigue las convenciones
básicas de bifurcación y etiquetado. Si nombra su tronco, ramas o etiquetas de manera diferente, puede
cambiar estas opciones. Debido a que esto es tan común, puede reemplazar esta parte completa con -s, lo
que significa diseño estándar e implica todas esas opciones. El siguiente comando es equivalente:
En este punto, debe tener un repositorio Git válido que haya importado sus ramas y etiquetas:
$ git branch -a
* master remotes/
origin/my-calc-branch remotes/origin/
tags/2.0.2 remotes/origin/tags/
release-2.0.1 remotes/origin/tags/
release-2.0.2 remotes/origin/ tags/
release-2.0.2rc1 remotos/origen/troncal
377
Machine Translated by Google
Tenga en cuenta cómo esta herramienta gestiona las etiquetas de Subversion como referencias remotas. Echemos un vistazo más de cerca
$ Git show-ref
árbitros bfd2d79303166789fc73af4046651a4b35c12f0b
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs / heads / master
0fb585761df569eaecd8146c71e58d70147460a2 árbitros / mandos a distancia / origen / my-calc-branch /
mandos a distancia / origen / etiquetas / 2.0.2 285c2b2e36e467dd4d91c8e3c0c0e1750b3fe8ca árbitros /
mandos a distancia / origen / etiquetas / versión 2.0.1-cbda99cb45d9abcb9793db1d4f70ae562a969f1e refs/
controles remotos/origin/tags/release-2.0.2 a9f074aa89e826d6f9d30808ce5ae3ffe711feda refs/remotos/origin/
tags/release-2.0.2rc1 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/remotos/origen/troncal
Git no hace esto cuando clona desde un servidor Git; así es como se ve un repositorio con etiquetas después de un clon nuevo:
$ Espectáculo-ref
git c3dcbe8488c6240392e8a5d7553bbffcb0f94ef0 árbitros / mandos a distancia / origen /
árbitros 32ef1d1c7cc8c603ab78416262cc421b80a8c2df maestro / mandos a distancia / origen /
rama-1 75f703a3580a9b81ead89fe1138e6da858c5ba18 árbitros / mandos a distancia / origen /
rama-2 23f8588dde934e8f33c263c6d8359b2ae095f863 árbitros / etiquetas / v0.1.0
7064938bd5e7ef47bfd79a685a62c1e2649e2ce7 árbitros / etiquetas / v0.2.0
6dcb09b5b57875f334f61aebed695e2e4193db5e referencias/etiquetas/v1.0.0
Git obtiene las etiquetas directamente en refs/tags, en lugar de tratarlas como ramas remotas.
Ahora que tiene un directorio de trabajo, puede trabajar un poco en el proyecto y enviar sus confirmaciones hacia arriba, utilizando Git de
manera efectiva como un cliente SVN. Si edita uno de los archivos y lo confirma, tiene una confirmación que existe en Git localmente que no
$ git commit -am 'Agregar instrucciones git-svn al LÉAME' [master 4af61fd] Agregar
instrucciones git-svn al archivo LÉAME 1 cambiado, 5 inserciones (+)
A continuación, debe impulsar su cambio en sentido ascendente. Observe cómo esto cambia la forma en que trabaja con Subversion: puede
realizar varias confirmaciones fuera de línea y luego enviarlas todas a la vez al servidor de Subversion. Para enviar a un servidor de Subversion,
378
Machine Translated by Google
Esto toma todas las confirmaciones que ha realizado además del código del servidor de Subversion, realiza una
confirmación de Subversion para cada una y luego vuelve a escribir su confirmación de Git local para incluir un
identificador único. Esto es importante porque significa que todas las sumas de verificación SHA-1 para sus confirmaciones
cambian. En parte por esta razón, trabajar con versiones remotas basadas en Git de sus proyectos al mismo tiempo que
un servidor Subversion no es una buena idea. Si observa la última confirmación, puede ver el nuevo git-svn-id que se
agregó:
$ git registro -1
compromiso 95e0222ba6399739834380eb10afcd73e0670bc5
Autor: ben <ben@0b684db3-b064-4277-89d1-21af03df0a68>
Fecha: Jue 24 de julio 03:08:36 2014 +0000
Tenga en cuenta que la suma de verificación SHA-1 que originalmente comenzó con 4af61fd cuando se comprometió
ahora comienza con 95e0222. Si desea enviar tanto a un servidor Git como a un servidor Subversion, primero debe
enviar (dcommit) al servidor Subversion, porque esa acción cambia sus datos de confirmación.
Si está trabajando con otros desarrolladores, en algún momento uno de ustedes presionará y luego el otro intentará
impulsar un cambio que entra en conflicto. Ese cambio será rechazado hasta que se fusione en su trabajo. En git svn, se
ve así:
379
Machine Translated by Google
Para resolver esta situación, puede ejecutar git svn rebase, que extrae cualquier cambio en el servidor que aún no tiene y
vuelve a basar cualquier trabajo que tenga sobre lo que está en el servidor:
Ahora, todo su trabajo está por encima de lo que está en el servidor de Subversion, por lo que puede dcommit con éxito:
380
Machine Translated by Google
Tenga en cuenta que, a diferencia de Git, que requiere que fusione el trabajo ascendente que aún no tiene
localmente antes de poder empujar, git svn lo obliga a hacerlo solo si los cambios entran en conflicto (muy
parecido a cómo funciona Subversion). Si alguien más envía un cambio a un archivo y luego usted envía un
cambio a otro archivo, su dcommit funcionará bien:
d8450bab8a77228a644b7dc0e95977ffc61adff7 (refs/remotes/origin/trunk)
M configure.ac r87 =
f3653ea40cb4e26b6281cec102e35dcba1fe17c4 (refs/controles remotos/origen/troncal)
W: a0253d06732169107aa020390d9fefd2b1d92806 y árbitros / mandos a distancia / origen / tronco son diferentes,
usando rebase:: 100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18
e757b59a9439312d80d5d43bb65d4a7d0389ed6d M autogen.sh En primer lugar, la cabeza de rebobinado para
Es importante recordar esto, porque el resultado es un estado de proyecto que no existía en ninguna de sus
computadoras cuando presionó. Si los cambios son incompatibles pero no entran en conflicto, es posible que
tenga problemas que sean difíciles de diagnosticar. Esto es diferente a usar un servidor Git: en Git, puede probar
completamente el estado en su sistema cliente antes de publicarlo, mientras que en SVN, nunca puede estar
seguro de que los estados inmediatamente antes y después de la confirmación sean idénticos.
También debe ejecutar este comando para obtener cambios del servidor de Subversion, incluso si no está listo
para comprometerse. Puede ejecutar git svn fetch para obtener los nuevos datos, pero git svn rebase realiza la
búsqueda y luego actualiza sus confirmaciones locales.
Ejecutar git svn rebase de vez en cuando asegura que su código esté siempre actualizado. Sin embargo, debe
asegurarse de que su directorio de trabajo esté limpio cuando ejecute esto. Si tiene cambios locales, debe ocultar
su trabajo o confirmarlo temporalmente antes de ejecutar git svn rebase ; de lo contrario, el comando se detendrá
si ve que el rebase dará como resultado un conflicto de fusión.
Cuando se sienta cómodo con un flujo de trabajo de Git, es probable que cree ramas de temas, trabaje en ellas y
luego las combine . en una sola rama cada vez en lugar de fusionar ramas. La razón para preferir el cambio de
base es que Subversion tiene un historial lineal y no se ocupa de las fusiones como lo hace Git, por lo que git svn
sigue solo al primer padre cuando convierte las instantáneas en confirmaciones de Subversion.
381
Machine Translated by Google
Suponga que su historial se parece a lo siguiente: creó una rama de experimento , realizó dos confirmaciones y luego
las fusionó nuevamente en el maestro. Cuando dcommit, verá un resultado como este:
Ejecutar dcommit en una rama con historial fusionado funciona bien, excepto que cuando observa el historial de su
proyecto Git, no ha reescrito ninguna de las confirmaciones que realizó en la rama del experimento ; en cambio,
todos esos cambios aparecen en la versión SVN del confirmación de fusión única.
Cuando alguien más clona ese trabajo, todo lo que ven es la confirmación de combinación con todo el trabajo
comprimido en él, como si hubieras ejecutado git merge --squash; no ven los datos de confirmación sobre de dónde
provienen o cuándo se confirmaron.
Ramificación de subversión
La bifurcación en Subversion no es lo mismo que la bifurcación en Git; si puede evitar usarlo mucho, probablemente
sea lo mejor. Sin embargo, puede crear y confirmar sucursales en Subversion usando git svn.
Para crear una nueva rama en Subversion, ejecute git svn branch [nueva-rama]:
Esto hace el equivalente al comando svn copy trunk branch/opera en Subversion y opera en el servidor de Subversion.
Es importante tener en cuenta que no te registra en ese
382
Machine Translated by Google
rama; si confirma en este punto, ese compromiso irá al tronco en el servidor, no a Opera.
Git determina a qué rama van sus dcommits buscando la punta de cualquiera de sus ramas de Subversion en su
historial; debe tener solo una, y debe ser la última con un git-svn-id en su historial de ramas actual.
Si desea trabajar en más de una rama simultáneamente, puede configurar ramas locales para que se descommit a
ramas específicas de Subversion iniciándolas en la confirmación de Subversion importada para esa rama. Si desea
una sucursal de ópera en la que pueda trabajar por separado, puede ejecutar:
Ahora, si desea fusionar su rama Opera en Trunk (su rama maestra ), puede hacerlo con una fusión normal de git.
Pero debe proporcionar un mensaje de confirmación descriptivo (a través de -m), o la fusión dirá "Fusionar rama
opera" en lugar de algo útil.
Recuerde que aunque está utilizando git merge para realizar esta operación, y la combinación probablemente será
mucho más fácil de lo que sería en Subversion (porque Git detectará automáticamente la base de combinación
adecuada para usted), esta no es una combinación normal de Git cometer. Tiene que devolver estos datos a un
servidor de Subversion que no pueda manejar una confirmación que rastree más de un padre; entonces, después
de subirlo, se verá como una sola confirmación que aplastó todo el trabajo de otra rama bajo una sola confirmación.
Después de fusionar una rama con otra, no puede regresar fácilmente y continuar trabajando en esa rama, como
normalmente puede hacerlo en Git. El comando dcommit que ejecuta borra cualquier información que diga en qué
rama se fusionó, por lo que los cálculos posteriores de la base de fusión serán incorrectos: el dcommit hace que su
resultado de git merge parezca que ejecutó git merge --squash.
Desafortunadamente, no hay una buena manera de evitar esta situación: Subversion no puede almacenar esta
información, por lo que siempre estará paralizado por sus limitaciones mientras lo usa como su servidor. Para evitar
problemas, debe eliminar la sucursal local (en este caso, Opera) después de fusionarla con la troncal.
Comandos de subversión
El conjunto de herramientas git svn proporciona una serie de comandos para ayudar a facilitar la transición a Git al
proporcionar una funcionalidad similar a la que tenía en Subversion. Aquí hay algunos comandos que le brindan lo
que solía hacer Subversion.
Si está acostumbrado a Subversion y desea ver su historial en estilo de salida SVN, puede ejecutar git svn log para
ver su historial de confirmaciones en formato SVN:
383
Machine Translated by Google
cambio autógeno
-------------------------------------------------- ----------------------
-------------------------------------------------- ----------------------
Debe saber dos cosas importantes sobre git svn log. En primer lugar, funciona sin conexión, a diferencia del
comando real svn log , que solicita los datos al servidor de Subversion. En segundo lugar, solo muestra las
confirmaciones que se han confirmado en el servidor de Subversion. Las confirmaciones locales de Git que no
ha cancelado no aparecen; tampoco las confirmaciones que las personas hayan realizado en el servidor de
Subversion mientras tanto. Es más como el último estado conocido de las confirmaciones en el servidor de Subversion.
Anotación SVN
Al igual que el comando git svn log simula el comando svn log fuera de línea, puede obtener el equivalente de
svn annotate ejecutando git svn reproche [ARCHIVO]. La salida se ve así:
Nuevamente, no muestra las confirmaciones que realizó localmente en Git o que se han enviado a Subversion
mientras tanto.
También puede obtener el mismo tipo de información que le brinda svn info ejecutando git svn info:
384
Machine Translated by Google
Esto es como culpar e iniciar sesión , ya que se ejecuta sin conexión y está actualizado solo desde la última vez que se comunicó
con el servidor de Subversion.
Si clona un repositorio de Subversion que tiene las propiedades svn:ignore configuradas en cualquier lugar, probablemente querrá
configurar los archivos .gitignore correspondientes para no enviar accidentalmente archivos que no debería. git svn tiene dos
comandos para ayudar con este problema. El primero es git svn create-ignore, que crea automáticamente los archivos .gitignore
correspondientes para que su próxima confirmación pueda incluirlos.
El segundo comando es git svn show-ignore, que imprime en la salida estándar las líneas que necesita colocar en un
archivo .gitignore para que pueda redirigir la salida al archivo de exclusión de su proyecto:
De esa manera, no ensucia el proyecto con archivos .gitignore . Esta es una buena opción si es el único usuario de Git en un
equipo de Subversion y sus compañeros de equipo no quieren archivos .gitignore en el proyecto.
Resumen de Git-Svn
Las herramientas de git svn son útiles si está atascado con un servidor Subversion o si se encuentra en un entorno de desarrollo
que requiere ejecutar un servidor Subversion. Sin embargo, debe considerarlo paralizado Git, o encontrará problemas en la
traducción que pueden confundirlo a usted y a sus colaboradores. Para no meterse en problemas, trate de seguir estas pautas:
• Mantenga un historial de Git lineal que no contenga confirmaciones de combinación realizadas por git merge. Rebase cualquier
el trabajo que realiza fuera de su sucursal principal de vuelta a ella; no lo fusiones.
• No configure ni colabore en un servidor Git separado. Posiblemente tenga uno para acelerar los clones para los nuevos
desarrolladores, pero no presione nada que no tenga una entrada git-svn-id . Incluso es posible que desee agregar un gancho
de pre-recepción que verifique cada mensaje de confirmación en busca de un git-svn-id y rechace las inserciones que
contienen confirmaciones sin él.
Si sigue esas pautas, trabajar con un servidor Subversion puede ser más llevadero. Sin embargo, si es posible migrar a un servidor
Git real, hacerlo puede beneficiar mucho más a su equipo.
385
Machine Translated by Google
Git y Mercurial
El universo DVCS es más grande que solo Git. De hecho, hay muchos otros sistemas en este espacio, cada uno con su propio
punto de vista sobre cómo realizar correctamente el control de versiones distribuidas. Aparte de Git, el más popular es Mercurial, y
los dos son muy similares en muchos aspectos.
La buena noticia, si prefiere el comportamiento del lado del cliente de Git pero está trabajando con un proyecto cuyo código fuente
se controla con Mercurial, es que hay una manera de usar Git como cliente para un repositorio alojado en Mercurial. Dado que la
forma en que Git se comunica con los repositorios del servidor es a través de controles remotos, no debería sorprender que este
puente se implemente como un asistente remoto. El nombre del proyecto es git-remote-hg y se puede encontrar en https://
github.com/felipec/git-remote-hg.
git-remote-hg
Primero, debe instalar git-remote-hg. Básicamente, esto implica dejar caer su archivo en algún lugar de su ruta, así:
$ curl -o ~/bin/git-remote-hg \
https://raw.githubusercontent.com/felipec/git-remote-hg/master/git-remote-hg $
chmod +x ~/bin/git-remote -hg
…asumiendo que ~/bin está en su $PATH. Git-remote-hg tiene otra dependencia: la biblioteca mercurial para Python. Si tiene
Python instalado, esto es tan simple como:
Lo último que necesitará es el cliente Mercurial. Vaya a https://www.mercurial-scm.org/ e instálalo si aún no lo has hecho.
Ahora estás listo para rockear. Todo lo que necesita es un repositorio de Mercurial al que pueda ingresar. Afortunadamente, todos
los repositorios de Mercurial pueden actuar de esta manera, así que solo usaremos el repositorio "hola mundo" que todos usan
para aprender Mercurial:
Empezando
Ahora que tenemos un repositorio adecuado del "lado del servidor", podemos pasar por un flujo de trabajo típico. Como verá, estos
dos sistemas son lo suficientemente similares como para que no haya mucha fricción.
386
Machine Translated by Google
Notará que trabajar con un repositorio de Mercurial usa el comando estándar de clonación de git . Esto se debe a que git-
remote-hg está funcionando a un nivel bastante bajo, usando un mecanismo similar a cómo se implementa el protocolo HTTP/
S de Git (ayudantes remotos). Dado que tanto Git como Mercurial están diseñados para que cada cliente tenga una copia
completa del historial del repositorio, este comando crea una copia completa, que incluye todo el historial del proyecto, y lo
hace con bastante rapidez.
El comando log muestra dos confirmaciones, la última de las cuales es señalada por una gran cantidad de referencias. Resulta
que algunos de estos no están realmente allí. Echemos un vistazo a lo que realmente hay en el directorio .git :
$ árbol. ÿÿ notas
ÿ ÿÿÿ hg ÿÿÿ
controles
remotos ÿ ÿÿÿ
origen ÿ ÿÿÿ
etiquetas HEAD
ÿÿÿ
9 directorios, 5 archivos
Git-remote-hg está tratando de hacer las cosas más idiomáticamente al estilo de Git, pero bajo el capó está administrando el
mapeo conceptual entre dos sistemas ligeramente diferentes. El directorio refs/hg es donde se almacenan las referencias
remotas reales. Por ejemplo, refs/hg/origin/branches/default es un archivo de referencia de Git que contiene el SHA-1 que
comienza con "ac7955c", que es la confirmación a la que apunta el maestro . Entonces, el directorio refs/hg es como un falso
refs/remotes/origin, pero tiene la distinción adicional entre marcadores y ramas.
El archivo notes/hg es el punto de partida de cómo git-remote-hg asigna hashes de confirmación de Git a ID de conjuntos de
cambios de Mercurial. Exploremos un poco:
387
Machine Translated by Google
$ gato billetes/
hg d4c10386...
Entonces , refs/notes/hg apunta a un árbol, que en la base de datos de objetos de Git es una lista de otros objetos con nombres. git ls-tree
genera el modo, el tipo, el hash del objeto y el nombre de archivo de los elementos dentro de un árbol. Una vez que profundizamos en uno
de los elementos del árbol, encontramos que dentro hay un blob llamado "ac9117f" (el hash SHA-1 de la confirmación apuntada por el
maestro), con contenido "0a04b98" (que es la ID del Conjunto de cambios de Mercurial en la punta de la rama predeterminada ).
La buena noticia es que, en general, no tenemos que preocuparnos por todo esto. El flujo de trabajo típico no será muy diferente de trabajar
con un control remoto de Git.
Hay una cosa más a la que debemos prestar atención antes de continuar: ignora. Mercurial y Git usan un mecanismo muy similar para
esto, pero es probable que no desee enviar un archivo .gitignore a un repositorio de Mercurial. Afortunadamente, Git tiene una forma de
ignorar archivos que son locales en un repositorio en disco, y el formato Mercurial es compatible con Git, por lo que solo tiene que copiarlo:
$ cp .hgignore .git/info/exclude
El archivo .git/info/exclude actúa como un .gitignore, pero no está incluido en las confirmaciones.
flujo de trabajo
Supongamos que hemos trabajado y realizado algunas confirmaciones en la rama maestra , y está listo para enviarlo al repositorio remoto.
Así es como se ve nuestro repositorio en este momento:
388
Machine Translated by Google
Nuestra rama maestra está dos confirmaciones por delante de origen/maestro, pero esas dos confirmaciones solo existen
en nuestra máquina local. Veamos si alguien más ha estado haciendo un trabajo importante al mismo tiempo:
$ git fetch
From hg::/tmp/hello
ac7955c..df85e87 maestro -> origen/maestro
ac7955c..df85e87 sucursales/predeterminado -> origen/sucursales/
predeterminado $ git log --oneline --graph --decorate --all * 7b07969 (refs/
notas/hg) Notas por defecto * d4c1038 Notas por maestro * df85e87
(origen/maestro, origen/sucursales/predeterminado, origen/HEAD, refs/hg/
origen/sucursales/predeterminado, refs/hg/origen/ marcadores/maestro)
Añadir algo de documentación | * ba04a2a (HEAD, maestro) Actualizar makefile | *
d25d16f Adiós |/ * ac7955c Crear un archivo MAKE * 65bb417 Crear un programa
estándar 'hola, mundo'
Como usamos el indicador --all , vemos las referencias de "notas" que git-remote-hg usa internamente, pero podemos
ignorarlas. El resto es lo que esperábamos; origin/master ha avanzado una confirmación y nuestro historial ahora se ha
separado. A diferencia de los otros sistemas con los que trabajamos en este capítulo, Mercurial es capaz de manejar
fusiones, por lo que no vamos a hacer nada complicado.
Perfecto. Realizamos las pruebas y todo pasa, así que estamos listos para compartir nuestro trabajo con el resto del equipo:
$ git push
To hg::/tmp/hello
df85e87..0c64627 maestro -> maestro
389
Machine Translated by Google
¡Eso es todo! Si echa un vistazo al repositorio de Mercurial, verá que esto hizo lo que esperábamos:
|
o 1 82e55d328c8c 2005-08-26 01:21 -0700mpm
Crear un archivo MAKE
||
El conjunto de cambios con el número 2 fue realizado por Mercurial, y los conjuntos de cambios con el número 3 y 4 fueron
hecho por git-remote-hg, empujando confirmaciones hechas con Git.
Ramas y marcadores
Git tiene solo un tipo de rama: una referencia que se mueve cuando se realizan confirmaciones. En Mercurial, este
tipo de referencia se llama "marcador" y se comporta de la misma manera que una rama de Git.
El concepto de Mercurial de una "sucursal" es más pesado. La rama en la que se realiza un conjunto de cambios es
registrado con el conjunto de cambios, lo que significa que siempre estará en el historial del repositorio. Aquí hay un
ejemplo de una confirmación que se realizó en la rama de desarrollo :
$ hg registro -l 1
conjunto de cambios: 6:8f65e5e02793
rama: desarrollar
etiqueta: propina
Tenga en cuenta la línea que comienza con "rama". Git realmente no puede replicar esto (y no necesita hacerlo; ambos
tipos de rama se pueden representar como una referencia de Git), pero git-remote-hg necesita comprender el
diferencia, porque a Mercurial le importa.
Crear marcadores de Mercurial es tan fácil como crear ramas de Git. En el lado de Git:
390
Machine Translated by Google
$ hg marcadores
característicaA 5:bd5ac26f11f9
$ hg registro --estilo compacto -G
@ 6[consejo] 8f65e5e02793 2014-08-14 20:06 -0700 ben
| Más documentación
|
o 5[característicaA]:4,2 bd5ac26f11f9 2014-08-14 20:02 -0700 ben
|\ | Combinar rama de seguimiento remoto 'origen/maestro'
|
||
|
o 1 82e55d328c8c 2005-08-26 01:21 -0700mpm
Crear un archivo MAKE
||
Tenga en cuenta la nueva etiqueta [featureA] en la revisión 5. Estos actúan exactamente como las ramas de Git en el lado de Git, con
una excepción: no puede eliminar un marcador del lado de Git (esta es una limitación de los ayudantes remotos).
También puede trabajar en una rama Mercurial de "peso pesado": simplemente coloque una rama en las ramas
espacio de nombres:
391
Machine Translated by Google
$ hg sucursales
desarrollo 7:a4529d07aad4
permanente 6:8f65e5e02793
predeterminado 5:bd5ac26f11f9 (inactivo)
$ hg log -G
o conjunto de cambios: 7:a4529d07aad4
| rama: permanente
| etiqueta: consejo
| padre: 5:bd5ac26f11f9
| usuario: Ben Straub <ben@straub.cc>
| fecha: | jue 14 de agosto 20:21:09 2014 -0700
resumen: | Un cambio permanente
Desde el lado de Git, trabajar con cualquiera de estos estilos de rama es lo mismo: solo paga, confirma,
buscar, fusionar, tirar y empujar como lo haría normalmente. Una cosa que debes saber es que Mercurial
no admite reescribir el historial, solo agregarlo. Así es como se ve nuestro repositorio de Mercurial
después de un rebase interactivo y un empuje forzado:
392
Machine Translated by Google
||
|| ||
|
o 1 82e55d328c8c 2005-08-26 01:21 -0700mpm
Crear un archivo MAKE
||
Se han creado los conjuntos de cambios 8, 9 y 10 y pertenecen a la rama permanente , pero el antiguo
los conjuntos de cambios todavía están allí. Esto puede ser muy confuso para sus compañeros de equipo que usan Mercurial,
así que trata de evitarlo.
Resumen Mercurial
Git y Mercurial son lo suficientemente similares como para que trabajar a través del límite sea bastante sencillo. Si usted
evite cambiar el historial que ha quedado en su máquina (como generalmente se recomienda), es posible que ni siquiera
tenga en cuenta que el otro extremo es Mercurial.
Git y Bazar
Entre los DVCS, otro famoso es Bazaar. Bazaar es gratuito y de código abierto, y forma parte de la
Proyecto GNU. Se comporta de manera muy diferente a Git. A veces, para hacer lo mismo que con Git,
tiene que usar una palabra clave diferente, y algunas palabras clave que son comunes no tienen el mismo
393
Machine Translated by Google
sentido. En particular, la gestión de sucursales es muy diferente y puede causar confusión, especialmente cuando alguien
viene del universo de Git. Sin embargo, es posible trabajar en un repositorio de Bazaar desde uno de Git.
Hay muchos proyectos que te permiten usar Git como cliente de Bazaar. Aquí usaremos el proyecto de Felipe Contreras
que puedes encontrar en https://github.com/felipec/git-remote-bzr. Para instalarlo solo debes descargar el archivo git-
remote-bzr en una carpeta contenida en tu $PATH:
Es simple de usar. Basta con clonar un repositorio de Bazaar con el prefijo bzr::. Dado que tanto Git como Bazaar realizan
clones completos en su máquina, es posible adjuntar un clon de Git a su clon local de Bazaar, pero no se recomienda.
Es mucho más fácil adjuntar su clon de Git directamente al mismo lugar al que se adjunta su clon de Bazaar: el repositorio
central.
Supongamos que trabajó con un repositorio remoto que se encuentra en la dirección bzr+ssh://
developer@mybazaarserver:myproject. Luego debes clonarlo de la siguiente manera:
En este punto, se crea su repositorio Git pero no se compacta para un uso óptimo del disco. Por eso también deberías
limpiar y compactar tu repositorio Git, especialmente si es grande:
$ git gc --agresivo
Sucursales de bazar
Bazaar solo te permite clonar ramas, pero un repositorio puede contener varias ramas y git remote-bzr puede clonar
ambas. Por ejemplo, para clonar una rama:
El segundo comando clona todas las ramas contenidas en el repositorio de emacs; sin embargo, es
394
Machine Translated by Google
Algunos repositorios remotos no te permiten listar sus ramas, en cuyo caso tienes que especificarlas manualmente,
y aunque podrías especificar la configuración en el comando de clonación, puede que te resulte más fácil:
Dado que está trabajando en un proyecto administrado con Bazaar, no debe crear un archivo .gitignore porque puede
configurarlo accidentalmente bajo el control de versiones y molestar a las otras personas que trabajan con Bazaar.
La solución es crear el archivo .git/info/exclude ya sea como un enlace simbólico o como un archivo normal. Más
adelante veremos cómo resolver esta cuestión.
Bazaar usa el mismo modelo que Git para ignorar archivos, pero también tiene dos características que no tienen un
equivalente en Git. La descripción completa se puede encontrar en la documentación. las dos caracteristicas
están:
1. "!!" le permite ignorar ciertos patrones de archivo incluso si se especifican con un "!" regla.
2. "RE:" al comienzo de una línea le permite especificar una expresión regular de Python (Solo Git
permite globos de concha).
1. Si el archivo .bzrigore no contiene ninguno de estos dos prefijos específicos, simplemente puede
haga un enlace simbólico a él en el repositorio: ln -s .bzrignore .git/info/exclude.
2. De lo contrario, debe crear el archivo .git/info/exclude y adaptarlo para ignorar exactamente el mismo
archivos en .bzrigore.
Cualquiera que sea el caso, deberá permanecer atento a cualquier cambio de .bzrignore para asegurarse de que el
archivo .git/info/exclude siempre refleje .bzrignore. De hecho, si el archivo .bzrignore cambiara y contuviera una o
más líneas que comenzaran con "!!" o "RE:", Git no puede interpretar estas líneas, tendrá que adaptar su archivo .git/
info/exclude para ignorar los mismos archivos que los ignorados con .bzrignore. Además, si el archivo .git/info/exclude
era un enlace simbólico, primero deberá eliminar el enlace simbólico, copiar .bzrignore a .git/info/exclude y luego
adaptar este último.
Sin embargo, tenga cuidado con su creación porque con Git es imposible volver a incluir un archivo si se excluye un
directorio principal de ese archivo.
Para obtener los cambios del control remoto, extraiga los cambios como de costumbre, utilizando los comandos de Git. Suponiendo que
395
Machine Translated by Google
que sus cambios están en la rama maestra , fusiona o vuelve a basar su trabajo en la rama de origen/maestra :
Debido a que Bazaar también tiene el concepto de confirmaciones de combinación, no habrá ningún problema si presiona una
confirmación de combinación. Para que pueda trabajar en una rama, fusionar los cambios en el maestro e impulsar su trabajo.
Luego, crea sus ramas, prueba y confirma su trabajo como de costumbre. Finalmente envías tu trabajo al repositorio de Bazaar:
Advertencias
El marco de ayuda remota de Git tiene algunas limitaciones que se aplican. En particular, estos comandos no funcionan:
• git push origin :branch-to-delete (Bazaar no puede aceptar eliminaciones de ref de esta manera)
Resumen
Dado que los modelos de Git y Bazaar son similares, no hay mucha resistencia cuando se trabaja cruzando el límite. Siempre
y cuando esté atento a las limitaciones y esté siempre consciente de que el repositorio remoto no es nativo de Git, estará bien.
Perforce es un sistema de control de versiones muy popular en entornos corporativos. Ha existido desde 1995, lo que lo
convierte en el sistema más antiguo cubierto en este capítulo. Como tal, está diseñado con las limitaciones de su época; asume
que siempre está conectado a un único servidor central y que solo se guarda una versión en el disco local. Sin duda, sus
características y restricciones se adaptan bien a varios problemas específicos, pero hay muchos proyectos que usan Perforce
donde Git realmente funcionaría mejor.
Hay dos opciones si desea mezclar su uso de Perforce y Git. El primero que cubriremos es el puente "Git Fusion" de los
creadores de Perforce, que le permite exponer subárboles de su depósito de Perforce como repositorios Git de lectura y
escritura. El segundo es git-p4, un puente del lado del cliente que le permite usar Git como cliente de Perforce, sin necesidad
de reconfigurar el servidor de Perforce.
Fusión Git
Perforce proporciona un producto llamado Git Fusion (disponible en http://www.perforce.com/git-fusion), que sincroniza un
servidor Perforce con repositorios Git en el lado del servidor.
396
Machine Translated by Google
Configuración
Para nuestros ejemplos, utilizaremos el método de instalación más sencillo para Git Fusion, que consiste en descargar
una máquina virtual que ejecuta el demonio Perforce y Git Fusion. Puede obtener la imagen de la máquina virtual
desde http://www.perforce.com/downloads/Perforce/20-User, y una vez que termine de descargarse, impórtelo a su
software de virtualización favorito (usaremos VirtualBox).
Al iniciar la máquina por primera vez, le pide que personalice la contraseña para tres usuarios de Linux (root, perforce
y git) y proporcione un nombre de instancia, que se puede usar para distinguir esta instalación de otras en la misma
red. Cuando todo se haya completado, verás esto:
Debe tomar nota de la dirección IP que se muestra aquí, la usaremos más adelante. A continuación, crearemos un
usuario de Perforce. Seleccione la opción "Iniciar sesión" en la parte inferior y presione enter (o SSH a la máquina), e
inicie sesión como root. Luego use estos comandos para crear un usuario:
397
Machine Translated by Google
El primero abrirá un editor VI para personalizar el usuario, pero puede aceptar los valores predeterminados
escribiendo :wq y presionando Intro. El segundo le pedirá que ingrese una contraseña dos veces. Eso es todo lo que
necesitamos hacer con un indicador de shell, así que salga de la sesión.
Lo siguiente que deberá hacer para seguir adelante es decirle a Git que no verifique los certificados SSL. La imagen
de Git Fusion viene con un certificado, pero es para un dominio que no coincidirá con la dirección IP de su máquina
virtual, por lo que Git rechazará la conexión HTTPS. Si va a ser una instalación permanente, consulte el manual de
Perforce Git Fusion para instalar un certificado diferente; para nuestros propósitos de ejemplo, esto será suficiente:
$ exportar GIT_SSL_NO_VERIFY=verdadero
La imagen de la máquina virtual viene equipada con un proyecto de muestra que puede clonar. Aquí estamos clonando
a través de HTTPS, con el usuario john que creamos anteriormente; Git solicita credenciales para esta conexión, pero
el caché de credenciales nos permitirá omitir este paso para cualquier solicitud posterior.
Configuración de fusión
Una vez que haya instalado Git Fusion, querrá modificar la configuración. En realidad, esto es bastante fácil de hacer
con su cliente Perforce favorito; simplemente asigne el directorio //.git-fusion en el servidor Perforce a su espacio de
trabajo. La estructura del archivo se ve así:
398
Machine Translated by Google
$ árbol
.
ÿÿÿ objetos ÿ
ÿÿÿ repositorios ÿ ÿ
ÿÿÿ [...] ÿ ÿÿÿ árboles ÿ
ÿÿÿ [...] ÿ ÿÿÿ p4gf_config
ÿÿÿ repositorios ÿ ÿÿÿ ÿ
Talkhouse ÿ ÿ p4gf_config
ÿÿÿ
usuarios
ÿÿÿ
ÿ
p4gf_mapa de usuario
El directorio de objetos es utilizado internamente por Git Fusion para asignar objetos de Perforce a Git y
viceversa, no tendrá que meterse con nada allí. Hay un archivo p4gf_config global en este directorio, así
como uno para cada repositorio: estos son los archivos de configuración que determinan cómo se comporta
Git Fusion. Echemos un vistazo al archivo en la raíz:
[repo-creación] juego
de caracteres = utf8
[git-to-perforce]
change-owner = autor
enable-git-branch-creation = sí enable-
swarm-reviews = sí enable-git-merge-
commits = sí enable-git-submodules =
sí verificación previa-commit = ninguno
ignorar -autor-permisos = sin verificación
de permiso de lectura = ninguno git-
merge-evitación-después-de-cambiar-
num = 12107
[forzosamente a git]
http-url = ninguno
ssh-url = ninguno
[@features]
imports = Falso
chunked-push = Falso
matrix2 = Falso paralelo-
push = Falso
[autenticación]
email-case-sensitivity = no
399
Machine Translated by Google
No entraremos en los significados de estas banderas aquí, pero tenga en cuenta que este es solo un archivo de texto con formato
INI, muy parecido a lo que Git usa para la configuración. Este archivo especifica las opciones globales, que luego pueden anularse
mediante archivos de configuración específicos del repositorio, como repos/Talkhouse/p4gf_config. Si abre este archivo, verá una
sección [@repo] con algunas configuraciones que son diferentes de los valores predeterminados globales.
También verá secciones que se ven así:
[Talkhouse-master]
git-branch-name = vista
maestra = //depot/Talkhouse/main-dev/... ...
Este es un mapeo entre una rama de Perforce y una rama de Git. La sección puede tener el nombre que desee, siempre que el
nombre sea único. git-branch-name le permite convertir una ruta de depósito que sería engorrosa en Git a un nombre más amigable.
La configuración de vista controla cómo se mapean los archivos de Perforce en el repositorio de Git, usando la sintaxis de mapeo
de vista estándar. Se puede especificar más de una asignación, como en este ejemplo:
[mapeo de múltiples
proyectos] git-branch-name
= master view = //depot/project1/main/... project1/...
ÿ
De esta manera, si su mapeo de espacio de trabajo normal incluye cambios en la estructura de los directorios, puede replicar eso
con un repositorio de Git.
El último archivo del que hablaremos es users/p4gf_usermap, que asigna usuarios de Perforce a usuarios de Git, y que es posible
que ni siquiera necesite. Al convertir un conjunto de cambios de Perforce a una confirmación de Git, el comportamiento
predeterminado de Git Fusion es buscar el usuario de Perforce y usar la dirección de correo electrónico y el nombre completo
almacenados allí para el campo autor/autor en Git. Al convertir de otra manera, el valor predeterminado es buscar el usuario de
Perforce con la dirección de correo electrónico almacenada en el campo de autor de la confirmación de Git y enviar el conjunto de
cambios como ese usuario (con la aplicación de permisos). En la mayoría de los casos, este comportamiento funcionará bien, pero
considere el siguiente archivo de mapeo:
Cada línea tiene el formato <usuario> <correo electrónico> "<nombre completo>" y crea una sola asignación de usuario. Las dos
primeras líneas asignan dos direcciones de correo electrónico distintas a la misma cuenta de usuario de Perforce. Esto es útil si
creó confirmaciones de Git en varias direcciones de correo electrónico diferentes (o cambió las direcciones de correo electrónico),
pero desea que se asignen al mismo usuario de Perforce. Al crear una confirmación de Git a partir de un conjunto de cambios de
Perforce, la primera línea que coincide con el usuario de Perforce se usa para la información de autoría de Git.
Las últimas dos líneas enmascaran los nombres reales y las direcciones de correo electrónico de Bob y Joe de las confirmaciones
de Git que se crean. Esto es bueno si desea abrir un proyecto interno, pero no desea publicar su directorio de empleados en todo
el mundo. Tenga en cuenta que las direcciones de correo electrónico y los nombres completos deben
400
Machine Translated by Google
ser único, a menos que desee que todos los compromisos de Git se atribuyan a un solo autor ficticio.
flujo de trabajo
Perforce Git Fusion es un puente bidireccional entre Perforce y el control de versiones de Git. Echemos un vistazo a cómo se
siente trabajar desde el lado de Git. Asumiremos que hemos mapeado en el proyecto "Jam" usando un archivo de
configuración como se muestra arriba, que podemos clonar así:
La primera vez que haga esto, puede llevar algo de tiempo. Lo que sucede es que Git Fusion está convirtiendo todos los
conjuntos de cambios aplicables en el historial de Perforce en confirmaciones de Git. Esto sucede localmente en el servidor,
por lo que es relativamente rápido, pero si tiene mucho historial, aún puede llevar algo de tiempo. Las recuperaciones
posteriores realizan una conversión incremental, por lo que se sentirá más como la velocidad nativa de Git.
Como puede ver, nuestro repositorio se ve exactamente como cualquier otro repositorio de Git con el que pueda trabajar.
Hay tres ramas, y Git ha creado una rama maestra local que realiza un seguimiento del origen/maestro. Trabajemos un poco
y creemos un par de confirmaciones nuevas:
401
Machine Translated by Google
#...
$ git log --oneline --decorate --graph --all * cfd46ab
(HEAD, maestro) Agregar documentación para la nueva función *
a730d77 Espacio en blanco * d254865 (origen/maestro, origen/HEAD)
Actualizar a la última versión de metrowerks en Beos: el Intel uno. * bd2f54a Se corrigió la fuga
del identificador NT de Jam. [...]
Tenemos dos nuevos compromisos. Ahora vamos a comprobar si alguien más ha estado trabajando:
$ git fetch
remote: Contando objetos: 5, listo.
remoto: Comprimir objetos: 100% (3/3), hecho. remoto:
Total 3 (delta 2), reutilizado 0 (delta 0)
Desembalaje de objetos: 100% (3/3), hecho.
Desde https://10.0.1.254/Jam
d254865..6afeb15 maestro -> origen/maestro $ git log --
oneline --decorate --graph --all * 6afeb15 (origen/maestro,
origen/HEAD) Actualizar copyright | * cfd46ab (HEAD, maestro)
Agregar documentación para la nueva función | * a730d77 Espacio en
blanco |/ * d254865 Actualice a los últimos metrowerks en Beos, el de
Intel. * bd2f54a Se corrigió la fuga del identificador NT de Jam. [...]
¡Parece que alguien lo estaba! No lo sabría desde esta vista, pero la confirmación 6afeb15 en realidad se creó usando un cliente
Perforce. Simplemente parece otra confirmación desde el punto de vista de Git, que es exactamente el punto. Veamos cómo el
servidor Perforce maneja una confirmación de fusión:
402
Machine Translated by Google
Git cree que funcionó. Echemos un vistazo al historial del archivo README desde el punto de vista de Perforce,
utilizando la función de gráfico de revisión de p4v:
Si nunca ha visto esta vista antes, puede parecer confuso, pero muestra los mismos conceptos que un visor gráfico
para el historial de Git. Estamos mirando el historial del archivo README , por lo que el árbol de directorios en la
parte superior izquierda solo muestra ese archivo tal como aparece en varias ramas. En la parte superior derecha,
tenemos un gráfico visual de cómo se relacionan las diferentes revisiones del archivo, y la vista general de este gráfico está en
403
Machine Translated by Google
abajo a la derecha. El resto de la vista corresponde a la vista de detalles de la revisión seleccionada (2 en este caso).
Una cosa a tener en cuenta es que el gráfico se ve exactamente como el del historial de Git. Perforce no tenía una rama
con nombre para almacenar las confirmaciones 1 y 2 , por lo que creó una rama "anónima" en el directorio .git-fusion
para contenerla. Esto también sucederá con las ramas de Git con nombre que no se correspondan con una rama de
Perforce con nombre (y luego puede asignarlas a una rama de Perforce usando el archivo de configuración).
La mayor parte de esto sucede detrás de escena, pero el resultado final es que una persona en un equipo puede usar
Git, otra puede usar Perforce, y ninguno de ellos sabrá sobre la elección del otro.
Resumen de Git-Fusion
Si tiene (o puede obtener) acceso a su servidor Perforce, Git Fusion es una excelente manera de hacer que Git y Perforce
se comuniquen entre sí. Hay un poco de configuración involucrada, pero la curva de aprendizaje no es muy pronunciada.
Esta es una de las pocas secciones de este capítulo donde no aparecerán advertencias sobre el uso de toda la potencia
de Git. Eso no quiere decir que Perforce estará contento con todo lo que le des, si intentas reescribir el historial que ya
se ha empujado, Git Fusion lo rechazará, pero Git Fusion se esfuerza mucho por sentirse nativo. Incluso puede usar
submódulos de Git (aunque se verán extraños para los usuarios de Perforce) y fusionar ramas (esto se registrará como
una integración en el lado de Perforce).
Si no puede convencer al administrador de su servidor para que configure Git Fusion, todavía hay una manera de usar
estas herramientas juntas.
Git-p4
Git-p4 es un puente bidireccional entre Git y Perforce. Se ejecuta completamente dentro de su repositorio de Git, por lo
que no necesitará ningún tipo de acceso al servidor de Perforce (aparte de las credenciales de usuario, por supuesto).
Git-p4 no es una solución tan flexible ni completa como Git Fusion, pero le permite hacer la mayor parte de lo que le
gustaría hacer sin invadir el entorno del servidor.
Necesitará la herramienta p4 en algún lugar de su RUTA para trabajar con git-p4. A partir de este
ÿ escrito, está disponible gratuitamente en http://www.perforce.com/downloads/Perforce/20-User .
Configuración
Por ejemplo, ejecutaremos el servidor Perforce desde Git Fusion OVA como se muestra arriba, pero omitiremos el
servidor Git Fusion e iremos directamente al control de versiones de Perforce.
Para usar el cliente de línea de comandos p4 (del que depende git-p4), deberá configurar un par de variables de entorno:
$ exportar P4PORT=10.0.1.254:1666
$ exportar P4USER=juan
Empezando
404
Machine Translated by Google
Esto crea lo que en términos de Git es un clon "superficial"; solo la última revisión de Perforce se importa a Git; recuerda, Perforce no está
diseñado para dar todas las revisiones a todos los usuarios. Esto es suficiente para usar Git como cliente de Perforce, pero para otros
propósitos no es suficiente.
Una vez que está terminado, tenemos un repositorio Git completamente funcional:
$ cd myproject
$ git log --oneline --all --graph --decorate *
70eaf78 (HEAD, p4/master, p4/HEAD, master) Importación inicial de //depot/www/live/ desde
el estado en la revisión # cabeza
Tenga en cuenta que hay un control remoto "p4" para el servidor Perforce, pero todo lo demás parece un clon estándar. En realidad, eso
es un poco engañoso; en realidad no hay un control remoto allí.
$ git remoto -v
No existen controles remotos en este repositorio. Git-p4 ha creado algunas referencias para representar el estado del servidor, y se ven
como referencias remotas para el registro de git, pero Git no las administra y no puede enviarlas.
flujo de trabajo
Bien, hagamos un poco de trabajo. Supongamos que ha progresado en una característica muy importante y está listo para mostrársela al
resto de su equipo.
Hicimos dos confirmaciones nuevas que estamos listos para enviar al servidor de Perforce. Veamos si alguien más estuvo trabajando hoy:
405
Machine Translated by Google
$ git p4 sincronizar
git p4 sincronizar
Realizando una importación incremental en refs/remotes/p4/master git branch
Rutas de depósito: //depot/www/live/
Destino de importación: refs/remotes/p4/master
Importando revisión 12142 (100%) $
git log --oneline --all --graph --decorate * 75cd059 (p4/
master, p4/HEAD) Actualizar copyright | * 018467c
(HEAD, master) Cambiar título de página | * c0fb617
Enlace de actualización |/ * 70eaf78 Importación inicial
de //depot/www/live/ desde el estado en la revisión #head
Parece que lo fueron, y master y p4/master han divergido. El sistema de bifurcación de Perforce no se parece
en nada al de Git, por lo que enviar confirmaciones de combinación no tiene ningún sentido. Git-p4 recomienda
que rebase sus confirmaciones, e incluso viene con un atajo para hacerlo:
$ git p4 rebase
Realizando una importación incremental en refs/remotes/p4/master git branch
Rutas de depósito: //depot/www/live/ ¡No hay cambios para importar!
Probablemente lo sepa por el resultado, pero git p4 rebase es un atajo para git p4 sync seguido de git rebase
p4/master. Es un poco más inteligente que eso, especialmente cuando se trabaja con varias ramas, pero esta
es una buena aproximación.
Ahora nuestra historia vuelve a ser lineal y estamos listos para contribuir con nuestros cambios a Perforce. El
comando de envío de git p4 intentará crear una nueva revisión de Perforce para cada confirmación de Git entre
p4/master y master. Ejecutarlo nos lleva a nuestro editor favorito, y el contenido del archivo se parece a esto:
406
Machine Translated by Google
Cambio: nuevo
Cliente: john_bens-mbp_8487
Usuario: juan
Estado: nuevo
Descripción:
Actualizar enlace
Archivos:
//depósito/www/live/index.html # editar
</td>
Este es principalmente el mismo contenido que vería al ejecutar p4 enviar, excepto las cosas al final que
git-p4 ha incluido útilmente. Git-p4 intenta respetar la configuración de Git y Perforce individualmente cuando
407
Machine Translated by Google
tiene que proporcionar un nombre para una confirmación o conjunto de cambios, pero en algunos casos desea anularlo.
Por ejemplo, si la confirmación de Git que está importando fue escrita por un colaborador que no tiene una cuenta de
usuario de Perforce, es posible que desee que el conjunto de cambios resultante parezca que lo escribió él (y no usted).
Git-p4 ha importado útilmente el mensaje de la confirmación de Git como el contenido de este conjunto de cambios de
Perforce, por lo que todo lo que tenemos que hacer es guardar y salir, dos veces (una para cada confirmación). La salida
de shell resultante se verá así:
$ git p4 enviar
Perforce checkout para ruta de depósito //depot/www/live/ ubicado en /Users/ben/john_bens mbp_8487/
john_bens-mbp_8487/depot/www/live/ Sincronizando p4 checkout... - archivo(s) up- hasta la fecha.
...
Aplicando el enlace de actualización
dbac45b //depot/www/live/index.html#4 - abierto para editar
Cambio 12143 creado con 1 archivo(s) abierto(s).
Enviando cambio 12143.
Bloqueando 1 archivos...
editar //depot/www/live/index.html#5
Cambio 12143 enviado.
Aplicando 905ec6a Cambiar título de
página //depot/www/live/index.html#5 - abierto para editar
Cambio 12144 creado con 1 archivo(s) abierto(s).
Enviando cambio 12144.
Bloqueando 1 archivos...
editar //depot/www/live/index.html#6
Cambio 12144 enviado.
¡Todas las confirmaciones aplicadas!
El resultado es como si acabáramos de hacer un git push, que es la analogía más cercana a lo que realmente sucedió.
Tenga en cuenta que durante este proceso, cada confirmación de Git se convierte en un conjunto de cambios de Perforce;
si desea agruparlos en un solo conjunto de cambios, puede hacerlo con una reorganización interactiva antes de ejecutar
git p4 submit. También tenga en cuenta que los hashes SHA-1 de todas las confirmaciones que se enviaron como
conjuntos de cambios han cambiado; esto se debe a que git-p4 agrega una línea al final de cada confirmación que convierte:
408
Machine Translated by Google
$ git registro -1
compromiso 775a46f630d8b46535fc9983cf3ebe6b9aa53145
Autor: John Doe <john@example.com> Fecha:
dom 31 de agosto 10:31:44 2014 -0800
¿Qué sucede si intentas enviar una confirmación de fusión? Hagamos un intento. Esta es la situación en la que
nos hemos metido:
La historia de Git y Perforce diverge después de 775a46f. El lado de Git tiene dos confirmaciones, luego una
confirmación de fusión con el encabezado de Perforce, luego otra confirmación. Vamos a intentar enviarlos
además de un solo conjunto de cambios en el lado de Perforce. Veamos qué pasaría si intentáramos enviar ahora:
$ git p4 enviar -n
Forzar el pago de la ruta del depósito //depot/www/live/ ubicado en /Users/ben/john_bens mbp_8487/john_bens-
mbp_8487/depot/www/live/
Sincronizaría el pago de p4 en /Users/ben/john_bens-mbp_8487/john_bens mbp_8487/depot/www/
live/
Aplicaría
b4959b6 Marca comercial
cbacd0a Bordes de la tabla: sí, por favor 3be6fd8
Dirección de correo electrónico correcta
El indicador -n es la abreviatura de --dry-run, que intenta informar lo que sucedería si el comando de envío se
ejecutara de verdad. En este caso, parece que estaríamos creando tres conjuntos de cambios de Perforce, que
corresponden a las tres confirmaciones no fusionadas que aún no existen en el servidor de Perforce. Eso suena
exactamente como lo que queremos, veamos cómo resulta:
409
Machine Translated by Google
* Corrección de gramática
c4689fc * 775a46f Cambiar título de
página * 05f1ade Enlace de
actualización * 75cd059 Actualizar
copyright * 70eaf78 Importación inicial de //depot/www/live/ desde el estado en revisión #head
Nuestra historia se volvió lineal, como si nos hubiéramos reorganizado antes de enviar (que de hecho es exactamente lo que
sucedió). Esto significa que puede ser libre de crear, trabajar, descartar y fusionar ramas en el lado de Git sin temor a que su
historial de alguna manera se vuelva incompatible con Perforce. Si puede reorganizarlo, puede contribuirlo a un servidor Perforce.
Derivación
Si su proyecto Perforce tiene múltiples ramas, no está de suerte; git-p4 puede manejar eso de una manera que lo hace sentir como
Git. Digamos que su depósito de Perforce se presenta así:
//deposito
ÿÿÿ
ÿ
proyecto
ÿÿÿ principal ÿÿÿ dev
ÿ
Y supongamos que tiene una rama de desarrollo , que tiene una especificación de vista que se ve así:
//depósito/proyecto/principal/... //depósito/proyecto/dev/...
410
Machine Translated by Google
Tenga en cuenta el especificador "@all" en la ruta del almacén; eso le dice a git-p4 que clone no solo el último conjunto de
cambios para ese subárbol, sino todos los conjuntos de cambios que alguna vez hayan tocado esos caminos. Esto se acerca más
al concepto de clon de Git, pero si está trabajando en un proyecto con una larga historia, podría llevar un tiempo.
El indicador --detect-branches le dice a git-p4 que use las especificaciones de rama de Perforce para mapear las ramas a las referencias de Git.
Si estas asignaciones no están presentes en el servidor de Perforce (que es una forma perfectamente válida de usar Perforce),
puede decirle a git-p4 cuáles son las asignaciones de rama y obtendrá el mismo resultado:
Establecer la variable de configuración git-p4.branchList en main:dev le dice a git-p4 que "main" y "dev" son ambas ramas, y la
segunda es hija de la primera.
Si ahora hacemos git checkout -b dev p4/project/dev y hacemos algunas confirmaciones, git-p4 es lo suficientemente inteligente
como para apuntar a la rama correcta cuando hacemos git p4 submit. Desafortunadamente, git-p4 no puede mezclar clones
superficiales y múltiples ramas; si tiene un proyecto enorme y quiere trabajar en más de una rama, tendrá que clonar git p4 una
vez para cada rama a la que desee enviar.
Para crear o integrar sucursales, deberá utilizar un cliente Perforce. Git-p4 solo puede sincronizar y enviar a ramas existentes, y
solo puede hacerlo con un conjunto de cambios lineal a la vez. Si fusiona dos ramas en Git e intenta enviar el nuevo conjunto de
cambios, todo lo que se registrará será un montón de cambios en los archivos; se perderán los metadatos sobre qué sucursales
están involucradas en la integración.
Git-p4 hace posible usar un flujo de trabajo Git con un servidor Perforce, y es bastante bueno en eso.
Sin embargo, es importante recordar que Perforce está a cargo de la fuente y solo está usando Git para trabajar localmente. Solo
tenga mucho cuidado al compartir confirmaciones de Git; si tienes un control remoto que otro
411
Machine Translated by Google
la gente usa, no envíe ninguna confirmación que aún no se haya enviado al servidor de Perforce.
Si desea combinar libremente el uso de Perforce y Git como clientes para el control de código fuente, y puede convencer al
administrador del servidor para que lo instale, Git Fusion convierte el uso de Git en un cliente de control de versiones de primera
clase para un servidor Perforce.
Migrar a Git
Si tiene un código base existente en otro VCS pero ha decidido comenzar a usar Git, debe migrar su proyecto de una forma u
otra. Esta sección repasa algunos importadores para sistemas comunes y luego demuestra cómo desarrollar su propio importador
personalizado. Aprenderá cómo importar datos de varios de los sistemas SCM más grandes utilizados profesionalmente, porque
constituyen la mayoría de los usuarios que están cambiando y porque las herramientas de alta calidad para ellos son fáciles de
conseguir.
Subversión
Si leyó la sección anterior sobre el uso de git svn, puede usar fácilmente esas instrucciones para git svn clonar un repositorio;
luego, deje de usar el servidor Subversion, empuje a un nuevo servidor Git y comience a usarlo. Si desea el historial, puede
lograrlo tan rápido como extraiga los datos del servidor de Subversion (lo que puede llevar un tiempo).
Sin embargo, la importación no es perfecta; y debido a que tomará tanto tiempo, es mejor que lo hagas bien. El primer problema
es la información del autor. En Subversion, cada persona que se compromete tiene un usuario en el sistema que se registra en
la información de confirmación. Los ejemplos de la sección anterior muestran schacon en algunos lugares, como la salida de
culpa y el registro de git svn. Si desea asignar esto a mejores datos de autor de Git, necesita una asignación de los usuarios de
Subversion a los autores de Git. Cree un archivo llamado users.txt que tenga esta asignación en un formato como este:
Para obtener una lista de los nombres de autor que usa SVN, puede ejecutar esto:
Eso genera la salida del registro en formato XML, luego conserva solo las líneas con la información del autor, descarta los
duplicados y elimina las etiquetas XML. Obviamente, esto solo funciona en una máquina con grep, sort y perl instalados. Luego,
redirija esa salida a su archivo users.txt para que pueda agregar los datos de usuario de Git equivalentes junto a cada entrada.
Si está intentando esto en una máquina con Windows, este es el punto en el que tendrá problemas.
412
Machine Translated by Google
Puede proporcionar este archivo a git svn para ayudarlo a mapear los datos del autor con mayor precisión.
También puede decirle a git svn que no incluya los metadatos que Subversion normalmente importa, pasando --
no-metadata al comando clonar o init . Los metadatos incluyen un git-svn-id dentro de cada mensaje de
confirmación que generará Git durante la importación. Esto puede inflar su registro de Git y puede hacerlo un poco confuso.
Debe conservar los metadatos cuando desee duplicar las confirmaciones realizadas en el
ÿ repositorio de Git en el repositorio SVN original. Si no desea la sincronización en su registro de
confirmación, no dude en omitir el parámetro --no-metadata .
Ahora debería tener una mejor importación de Subversion en su directorio my_project . En lugar de confirmaciones
que se ven así:
cometer 37efa680e8473b615de980fa935944215428a35a
Autor: schacon <schacon@4c93b258-373f-11de-be05-5f7a86268029>
Fecha: dom 3 mayo 00:12:22 2009 +0000
se ven así:
cometer 03a8785f44c8ea5cdb0e8834b7c8e6c469be2ff2
Autor: Scott Chacon <schacon@geemail.com> Fecha:
domingo 3 de mayo 00:12:22 2009 +0000
No solo el campo Autor se ve mucho mejor, sino que el git-svn-id ya no está allí.
También debe hacer un poco de limpieza posterior a la importación. Por un lado, deberías limpiar las extrañas
referencias que git svn configuró. Primero moverá las etiquetas para que sean etiquetas reales en lugar de
extrañas ramas remotas, y luego moverá el resto de las ramas para que sean locales.
Para mover las etiquetas para que sean etiquetas Git adecuadas, ejecute:
$ para t en $(git for-each-ref --format='%(refname:short)' refs/remotes/tags); haz git tag ${t/tags\//} $t &&
git branch -D -r $t; hecho
413
Machine Translated by Google
Esto toma las referencias que eran ramas remotas que comenzaron con refs/remotes/tags/ y las convierte en etiquetas reales
(ligeras).
A continuación, mueva el resto de las referencias bajo refs/remotes para que sean sucursales locales:
Puede suceder que vea algunas ramas adicionales con el sufijo @xxx (donde xxx es un número), mientras que en Subversion solo
ve una rama. Esta es en realidad una característica de Subversion llamada "peg-revisions", que es algo para lo que Git simplemente
no tiene una contraparte sintáctica. Por lo tanto, git svn simplemente agrega el número de versión de svn al nombre de la rama de
la misma manera que lo hubieras escrito en svn para abordar la revisión de clavija de esa rama. Si ya no le importan las revisiones
de clavijas, simplemente elimínelas:
$ para p en $(git for-each-ref --format='%(refname:short)' | grep @); haz git branch -D $p; hecho
Ahora todas las ramas antiguas son ramas Git reales y todas las etiquetas antiguas son etiquetas Git reales.
Hay una última cosa que limpiar. Desafortunadamente, git svn crea una rama adicional llamada troncal, que se asigna a la rama
predeterminada de Subversion, pero la referencia troncal apunta al mismo lugar que la maestra.
Dado que master es más idiomáticamente Git, aquí se explica cómo eliminar la rama adicional:
Lo último que debe hacer es agregar su nuevo servidor Git como un control remoto y presionarlo. Aquí hay un ejemplo de cómo
agregar su servidor como un control remoto:
Como desea que todas sus ramas y etiquetas suban, ahora puede ejecutar esto:
Todas sus ramas y etiquetas deben estar en su nuevo servidor Git en una importación agradable y limpia.
Mercurial
Dado que Mercurial y Git tienen modelos bastante similares para representar versiones, y dado que Git es un poco más flexible,
convertir un repositorio de Mercurial a Git es bastante sencillo, usando una herramienta llamada "hg-fast-export", que necesitará un
copia de:
414
Machine Translated by Google
El primer paso en la conversión es obtener un clon completo del repositorio de Mercurial que desea convertir:
El siguiente paso es crear un archivo de asignación de autor. Mercurial es un poco más indulgente que Git por lo que pondrá
en el campo de autor para los conjuntos de cambios, por lo que este es un buen momento para limpiar la casa. Generar esto
es un comando de una línea en un shell bash :
$ cd /tmp/hg-repo $
registro de hg | usuario grep: | ordenar | único | sed 's/usuario: *//' > ../autores
Esto tomará unos segundos, dependiendo de la duración del historial de su proyecto, y luego el archivo /tmp/authors se verá
así:
Beto
bob@localhost
bob <bob@company.com>
bob jones <bob <AT> empresa <DOT> com>
Bob Jones <bob@company.com> Joe Smith
<joe@company.com>
En este ejemplo, la misma persona (Bob) ha creado conjuntos de cambios con cuatro nombres diferentes, uno de los cuales
parece correcto y el otro no sería válido para una confirmación de Git. Hg fast-export nos permite arreglar esto convirtiendo
cada línea en una regla: "<input>"="<output>", asignando una <input> a una <output>. Dentro de las cadenas <input> y
<output> , se admiten todas las secuencias de escape entendidas por la codificación python string_escape . Si el archivo de
asignación de autor no contiene una <entrada> coincidente, ese autor se enviará a Git sin modificar. Si todos los nombres de
usuario se ven bien, no necesitaremos este archivo en absoluto. En este ejemplo, queremos que nuestro archivo se vea así:
El mismo tipo de archivo de mapeo se puede usar para cambiar el nombre de ramas y etiquetas cuando Git no permite el
nombre de Mercurial.
El siguiente paso es crear nuestro nuevo repositorio Git y ejecutar el script de exportación:
415
Machine Translated by Google
El indicador -r le dice a hg-fast-export dónde encontrar el repositorio de Mercurial que queremos convertir, y el
indicador -A le indica dónde encontrar el archivo de mapeo de autor (los archivos de mapeo de ramas y etiquetas se
especifican mediante -B y - banderas T respectivamente). El script analiza los conjuntos de cambios de Mercurial y
los convierte en un script para la función de "importación rápida" de Git (que discutiremos en detalle más adelante).
Esto toma un poco (aunque es mucho más rápido de lo que sería a través de la red) y el resultado es bastante detallado:
416
Machine Translated by Google
estadísticas de git-fast-import:
-------------------------------------------------- -------------------
intentos)
ÿ
intentos)
ÿ
intentos)
ÿ
intentos)
Total sucursales: 109 2 cargas )
ÿ
átomos: (1952)
2235 KiB
ÿ
=
pack_report: getpagesize() 4096
paquete_informe: core.packedGitWindowSize = 1073741824
informe_paquete: core.packedGitLimit = 8589934592
= 90430
pack_report: pack_used_ctr
= 46771
pack_report: pack_mmap_calls
= 1/1
pack_report: pack_open_windows
pack_report: pack_mapped = 340852700 / 340852700
-------------------------------------------------- -------------------
417
Machine Translated by Google
Eso es prácticamente todo lo que hay que hacer. Todas las etiquetas de Mercurial se han convertido en etiquetas de Git,
y las ramas y marcadores de Mercurial se han convertido en ramas de Git. Ahora está listo para llevar el repositorio a su
nuevo hogar del lado del servidor:
Bazar
Bazaar es una herramienta de DVCS muy parecida a Git y, como resultado, es bastante sencillo convertir un repositorio
de Bazaar en uno de Git. Para lograr esto, deberá importar el complemento bzr-fastimport .
El procedimiento para instalar el complemento fastimport es diferente en los sistemas operativos tipo UNIX y en Windows.
En el primer caso, lo más sencillo es instalar el paquete bzr-fastimport que instalará todas las dependencias requeridas.
Para que este complemento funcione, también necesitará el módulo Python fastimport . Puede verificar si está presente
o no e instalarlo con los siguientes comandos:
418
Machine Translated by Google
En el segundo caso (en Windows), bzr-fastimport se instala automáticamente con la versión independiente
y la instalación predeterminada (deje todas las casillas marcadas). Así que en este caso no tienes nada que
hacer.
En este punto, la forma de importar un repositorio de Bazaar difiere según tengas una sola sucursal o estés
trabajando con un repositorio que tiene varias sucursales.
Ahora haga cd en el directorio que contiene su repositorio de Bazaar e inicialice el repositorio de Git:
Ahora, simplemente puede exportar su repositorio Bazaar y convertirlo en un repositorio Git usando el
siguiente comando:
Según el tamaño del proyecto, su repositorio de Git se crea en un lapso de unos segundos a unos minutos.
También puede importar un repositorio de Bazaar que contenga sucursales. Supongamos que tiene dos
ramas: una representa la rama principal (myProject.trunk), la otra es la rama de trabajo (myProject.work).
$ ls
miProyecto.trunk miProyecto.trabajo
419
Machine Translated by Google
Ahora git branch te muestra la rama maestra así como la rama de trabajo . Verifique los registros para
asegurarse de que estén completos y elimine los archivos Marks.bzr y Marks.git .
Cualquiera que sea la cantidad de sucursales que tenía y el método de importación que utilizó, su área de
preparación no está sincronizada con HEAD, y con la importación de varias sucursales, su directorio de trabajo
tampoco está sincronizado. Esta situación se resuelve fácilmente con el siguiente comando:
Ahora echemos un vistazo a los archivos para ignorar. Lo primero que debe hacer es cambiar el nombre
de .bzrignore a .gitignore. Si el archivo .bzrignore contiene una o varias líneas que comienzan con "!!" o "RE:",
tendrá que modificarlo y tal vez crear varios archivos .gitignore para ignorar exactamente los mismos archivos
que Bazaar estaba ignorando.
Finalmente, deberá crear un compromiso que contenga esta modificación para la migración:
420
Machine Translated by Google
Forzosamente
El siguiente sistema desde el que verá la importación es Perforce. Como discutimos anteriormente, hay dos formas de
permitir que Git y Perforce se comuniquen entre sí: git-p4 y Perforce Git Fusion.
Git Fusion hace que este proceso sea bastante sencillo. Simplemente configure los ajustes de su proyecto, las
asignaciones de usuarios y las ramas mediante un archivo de configuración (como se explica en Git Fusion) y clone el
repositorio. Git Fusion lo deja con lo que parece ser un repositorio Git nativo, que luego está listo para enviarse a un
host Git nativo si lo desea. Incluso podría usar Perforce como su host Git si lo desea.
Git-p4
Git-p4 también puede actuar como una herramienta de importación. Como ejemplo, importaremos el proyecto Jam
desde Perforce Public Depot. Para configurar su cliente, debe exportar la variable de entorno P4PORT para que
apunte al depósito de Perforce:
$ exportar P4PORT=public.perforce.com:1666
Para seguir, necesitará un depósito de Perforce para conectarse. Usaremos el depósito público
ÿ en public.perforce.com para nuestros ejemplos, pero puede usar cualquier depósito al que tenga
acceso.
Ejecute el comando git p4 clone para importar el proyecto Jam desde el servidor de Perforce, proporcionando la ruta
del almacén y del proyecto y la ruta en la que desea importar el proyecto:
Este proyecto en particular tiene solo una rama, pero si tiene ramas que están configuradas con vistas de ramas (o
solo un conjunto de directorios), puede usar el indicador --detect-branches para clonar git p4 para importar todas las
ramas del proyecto también . Consulte Ramificación para obtener más detalles sobre esto.
En este punto ya casi has terminado. Si va al directorio p4import y ejecuta git log, puede ver su trabajo importado:
421
Machine Translated by Google
$ git log -2
confirmar e5da1c909e5db3036475419f6379f2c73710c4e6
Autor: giles <giles@giles@perforce.com> Fecha:
miércoles 8 de febrero 03:13:27 2012 -0800
cometer aa21359a0a135dda85c50a7f7cf249e4f7b8fd98
Autor: kwirth <kwirth@perforce.com> Fecha: martes 7 de
julio 01:35:51 2009 -0800
Puedes ver que git-p4 ha dejado un identificador en cada mensaje de confirmación. Está bien mantener ese identificador
allí, en caso de que necesite hacer referencia al número de cambio de Perforce más adelante. Sin embargo, si desea
eliminar el identificador, ahora es el momento de hacerlo, antes de comenzar a trabajar en el nuevo repositorio.
Puede usar git filter-branch para eliminar las cadenas de identificación en masa:
Si ejecuta git log, puede ver que todas las sumas de verificación SHA-1 para las confirmaciones han cambiado, pero
las cadenas git-p4 ya no están en los mensajes de confirmación:
$ git log -2
commit b17341801ed838d97f7800a54a6f9b95750839b7
Autor: giles <giles@giles@perforce.com> Fecha:
miércoles 8 de febrero 03:13:27 2012 -0800
confirmar 3e68c2e26cd89cb983eb52c024ecdfba1d6b3fff
Autor: kwirth <kwirth@perforce.com> Fecha:
martes 7 de julio 01:35:51 2009 -0800
Un importador personalizado
Si su sistema no es uno de los anteriores, debe buscar un importador en línea: los importadores de calidad son
422
Machine Translated by Google
disponible para muchos otros sistemas, incluyendo CVS, Clear Case, Visual Source Safe, incluso un directorio de
archivos. Si ninguna de estas herramientas funciona para usted, tiene una herramienta más oscura o necesita un
proceso de importación más personalizado, debe usar git fast-import. Este comando lee instrucciones simples de
stdin para escribir datos Git específicos. Es mucho más fácil crear objetos de Git de esta manera que ejecutar los
comandos de Git sin formato o intentar escribir los objetos sin formato (consulte Git Internals para obtener más
información). De esta manera, puede escribir un script de importación que lea la información necesaria del sistema
desde el que está importando e imprima instrucciones sencillas en la salida estándar. Luego puede ejecutar este
programa y canalizar su salida a través de git fast-import.
Para demostrarlo rápidamente, escribirá un importador simple. Supongamos que trabaja en actual, hace una copia
de seguridad de su proyecto copiando ocasionalmente el directorio en un directorio de copia de seguridad
back_YYYY_MM_DD con marca de tiempo , y desea importarlo a Git. Su estructura de directorios se ve así:
$ ls /opt/import_from
back_2014_01_02
back_2014_01_04
back_2014_01_14
back_2014_02_03 actual
Para importar un directorio de Git, debe revisar cómo Git almacena sus datos. Como recordará, Git es
fundamentalmente una lista vinculada de objetos de confirmación que apuntan a una instantánea del contenido.
Todo lo que tiene que hacer es decirle a la importación rápida cuáles son las instantáneas de contenido, qué puntos
de datos de confirmación les asignan y el orden en que aparecen. Su estrategia será revisar las instantáneas una
a la vez y crear confirmaciones con el contenido de cada directorio, vinculando cada confirmación con la anterior.
Como hicimos en Ejemplo de política aplicada por Git, escribiremos esto en Ruby, porque es con lo que
generalmente trabajamos y tiende a ser fácil de leer. Puede escribir este ejemplo con bastante facilidad en cualquier
cosa con la que esté familiarizado: solo necesita imprimir la información adecuada en la salida estándar. Y, si está
ejecutando en Windows, esto significa que deberá tener especial cuidado de no introducir retornos de carro al final
de sus líneas: git fast-import es muy particular sobre solo querer saltos de línea (LF) no la línea de retorno de carro
feeds (CRLF) que usa Windows.
Para comenzar, cambiará al directorio de destino e identificará cada subdirectorio, cada uno de los cuales es una
instantánea que desea importar como una confirmación. Cambiará a cada subdirectorio e imprimirá los comandos
necesarios para exportarlo. Su ciclo principal básico se ve así:
423
Machine Translated by Google
última_marca = cero
end
Ejecuta print_export dentro de cada directorio, que toma el manifiesto y la marca de la instantánea anterior y devuelve el
manifiesto y la marca de esta; de esa manera, puede vincularlos correctamente.
“Mark” es el término de importación rápida para un identificador que le das a una confirmación; a medida que crea
compromisos, asigna a cada uno una marca que puede usar para vincularlo desde otros compromisos. Entonces, lo
primero que debe hacer en su método print_export es generar una marca del nombre del directorio:
marca = convert_dir_to_mark(dir)
Hará esto creando una matriz de directorios y usando el valor del índice como marca, porque una marca debe ser un
número entero. Su método se ve así:
$marcas = []
def convert_dir_to_mark(dir) if !
$marcas.incluir?(dir) $marcas << dir
end ($marcas.index(dir) + 1).to_s end
Ahora que tiene una representación entera de su compromiso, necesita una fecha para los metadatos del compromiso.
Debido a que la fecha se expresa en el nombre del directorio, la analizará. La siguiente línea en su archivo print_export es:
fecha = convert_dir_to_date(dir)
424
Machine Translated by Google
Eso devuelve un valor entero para la fecha de cada directorio. La última metainformación que necesita para cada
confirmación son los datos del confirmador, que codifica en una variable global:
Ahora está listo para comenzar a imprimir los datos de confirmación para su importador. La información inicial
indica que está definiendo un objeto de confirmación y en qué rama está, seguida de la marca que ha generado,
la información del confirmador y el mensaje de confirmación, y luego la confirmación anterior, si corresponde.
El código se ve así:
# imprime la información de
importación puts 'commit refs/heads/
master' puts 'mark :' + mark puts
"committer #{$author} #{date} -0700"
'
export_data('imported from + dir) puts
última_marca
'from :' +
si última_marca
Codifica la zona horaria (-0700) porque hacerlo es fácil. Si está importando desde otro sistema, debe especificar la
zona horaria como un desplazamiento. El mensaje de confirmación debe expresarse en un formato especial:
datos (tamaño)\n(contenido)
El formato consta de la palabra datos, el tamaño de los datos a leer, una nueva línea y finalmente los datos.
Debido a que necesita usar el mismo formato para especificar el contenido del archivo más adelante, cree un
método auxiliar, export_data:
def exportar_datos(cadena)
imprimir "datos #{cadena.tamaño}\n#{cadena}"
end
Todo lo que queda es especificar el contenido del archivo para cada instantánea. Esto es fácil, porque tiene cada
uno en un directorio: puede imprimir el comando deleteall seguido del contenido de cada archivo en el directorio.
Luego, Git registrará cada instantánea de manera adecuada:
425
Machine Translated by Google
Nota: Debido a que muchos sistemas piensan en sus revisiones como cambios de una confirmación a otra, la importación
rápida también puede tomar comandos con cada confirmación para especificar qué archivos se agregaron, eliminaron o
modificaron y cuáles son los nuevos contenidos. Podría calcular las diferencias entre las instantáneas y proporcionar solo
estos datos, pero hacerlo es más complejo: también puede proporcionar a Git todos los datos y dejar que lo resuelva. Si
esto se adapta mejor a sus datos, consulte la página del manual de importación rápida para obtener detalles sobre cómo
proporcionar sus datos de esta manera.
El formato para enumerar el contenido del nuevo archivo o especificar un archivo modificado con el nuevo contenido es el
siguiente:
Aquí, 644 es el modo (si tiene archivos ejecutables, debe detectar y especificar 755 en su lugar), y en línea dice que
enumerará el contenido inmediatamente después de esta línea. Su método inline_data se ve así:
Reutiliza el método export_data que definiste anteriormente, porque es igual a la forma en que especificaste los datos de
tu mensaje de confirmación.
Lo último que debe hacer es devolver la marca actual para que pueda pasar a la siguiente iteración:
marca de retorno
Si está ejecutando en Windows, deberá asegurarse de agregar un paso adicional. Como se mencionó
anteriormente, Windows usa CRLF para caracteres de nueva línea, mientras que git fast-import solo
espera LF. Para solucionar este problema y hacer feliz la importación rápida de git , debe decirle a
$salida estándar.binmode
426
Machine Translated by Google
#!/usr/bin/env rubí
$stdout.binmode
$autor = "John Doe <john@example.com>"
$marcas =
[] def convertir_dir_a_marca(dir)
if !$marcas.incluir?(dir) $marcas
ÿ
<< dir
end
($marcas.index(dir)+1).to_s end
devuelve Time.now().to_i
else
ÿ
def exportar_datos(cadena)
imprimir "datos #{cadena.tamaño}\n#{cadena}"
end
File.file?(file) inline_data(file)
ÿ
final
427
Machine Translated by Google
marca
final
final
final final
datos 28
# Hola
Este es mi Léame.
commit refs/heads/master mark :2
committer John Doe
<john@example.com> 1388822400 -0700 data 29
#!/bin/env rubí
pone "Hola"
M 644 en línea LÉAME.md (...)
Para ejecutar el importador, canalice esta salida a través de git fast-import mientras se encuentra en el directorio de Git al
que desea importar. Puede crear un nuevo directorio y luego ejecutar git init en él como punto de partida, y luego ejecutar
su secuencia de comandos:
428
Machine Translated by Google
$ git inicializar
Repositorio Git vacío inicializado en /opt/import_to/.git/
$ ruby import.rb /opt/import_from | Importación rápida de Git
estadísticas de git-fast-import:
-------------------------------------------------- -------------------
intentos)
ÿ
intentos)
ÿ
átomos: (2
2110 KiB
ÿ
=
pack_report: getpagesize() 4096
paquete_informe: core.packedGitWindowSize = 1073741824
informe_paquete: core.packedGitLimit = 8589934592
= 10
pack_report: pack_used_ctr
= 5
pack_report: pack_mmap_calls
= 2/ 2
pack_report: pack_open_windows
= 1457 / 1457
pack_report: pack_mapped
-------------------------------------------------- -------------------
Como puede ver, cuando se completa con éxito, le brinda un montón de estadísticas sobre lo que
logrado. En este caso, importó 13 objetos en total para 4 confirmaciones en 1 rama. Ahora usted puede
ejecuta git log para ver tu nuevo historial:
$ git registro -2
cometer 3caa046d4aac682a55867132ccdfbe0d3fdee498
importado de actual
confirmar 4afc2b945d0d3c8cd00556fbe2e8224569dc9def
importado de back_2014_02_03
429
Machine Translated by Google
Ahí lo tienes: un repositorio Git agradable y limpio. Es importante tener en cuenta que nada está desprotegido:
al principio no tiene ningún archivo en su directorio de trabajo. Para obtenerlos, debe restablecer su rama a
donde está el maestro ahora:
$ ls
$ git reset --hard master
HEAD ahora está en 3caa046 importado de $ ls
actual README.md main.rb
Puede hacer mucho más con la herramienta de importación rápida : manejar diferentes modos, datos binarios,
múltiples ramas y fusiones, etiquetas, indicadores de progreso y más. Hay varios ejemplos de escenarios más
complejos disponibles en el directorio contrib/fast-import del código fuente de Git.
Resumen
Debería sentirse cómodo usando Git como cliente para otros sistemas de control de versiones, o importando
casi cualquier repositorio existente a Git sin perder datos. En el próximo capítulo, cubriremos las partes internas
sin procesar de Git para que pueda crear cada byte, si es necesario.
430
Machine Translated by Google
Internos de Git
Es posible que haya saltado a este capítulo desde un capítulo mucho más temprano, o que haya llegado hasta aquí
después de leer secuencialmente el libro completo hasta este punto; en cualquier caso, aquí es donde repasaremos el
funcionamiento interno y la implementación de Git. Descubrimos que comprender esta información era fundamentalmente
importante para apreciar cuán útil y poderoso es Git, pero otros nos han argumentado que puede ser confuso e
innecesariamente complejo para los principiantes. Por lo tanto, hemos hecho de esta discusión el último capítulo del
libro para que pueda leerlo temprano o más tarde en su proceso de aprendizaje. Te dejamos a ti decidir.
Ahora que estás aquí, comencemos. Primero, si aún no está claro, Git es fundamentalmente un sistema de archivos de
contenido direccionable con una interfaz de usuario de VCS escrita encima. Aprenderá más sobre lo que esto significa
en un momento.
En los primeros días de Git (principalmente antes de 1.5), la interfaz de usuario era mucho más compleja porque
enfatizaba este sistema de archivos en lugar de un VCS pulido. En los últimos años, la interfaz de usuario se ha refinado
hasta que es tan limpia y fácil de usar como cualquier otro sistema; sin embargo, persiste el estereotipo sobre la primera
interfaz de usuario de Git que era compleja y difícil de aprender.
La capa del sistema de archivos direccionable por contenido es asombrosamente genial, así que lo cubriremos primero
en este capítulo; luego, aprenderá sobre los mecanismos de transporte y las tareas de mantenimiento del repositorio
con las que eventualmente tendrá que lidiar.
Fontanería y Porcelanato
Este libro cubre principalmente cómo usar Git con más o menos 30 subcomandos, como pago, sucursal, control remoto,
etc. Pero debido a que Git fue inicialmente un conjunto de herramientas para un sistema de control de versiones en
lugar de un VCS completo y fácil de usar, tiene una serie de subcomandos que realizan trabajos de bajo nivel y fueron
diseñados para encadenarse al estilo UNIX o llamarse desde scripts. Estos comandos generalmente se denominan
comandos de "plomería" de Git, mientras que los comandos más fáciles de usar se denominan comandos de "porcelana".
Como ya habrá notado, los primeros nueve capítulos de este libro tratan casi exclusivamente de los comandos de
porcelana. Pero en este capítulo, se ocupará principalmente de los comandos de plomería de nivel inferior, porque le
dan acceso al funcionamiento interno de Git y ayudan a demostrar cómo y por qué Git hace lo que hace. Muchos de
estos comandos no están pensados para usarse manualmente en la línea de comandos, sino como bloques de
construcción para nuevas herramientas y scripts personalizados.
Cuando ejecuta git init en un directorio nuevo o existente, Git crea el directorio .git , que es donde se encuentra casi todo
lo que Git almacena y manipula. Si desea hacer una copia de seguridad o clonar su repositorio, copiar este único
directorio en otro lugar le brinda casi todo lo que necesita. Todo este capítulo trata básicamente de lo que puede ver en
este directorio. Este es el aspecto típico de un directorio .git recién inicializado :
431
Machine Translated by Google
$ ls -F1
descripción
de configuración
HEAD
ganchos/
info/ objetos/ refs/
Dependiendo de su versión de Git, es posible que vea algún contenido adicional allí, pero este es un repositorio nuevo de git
init : es lo que ve de manera predeterminada. El archivo de descripción solo lo usa el programa GitWeb, así que no se preocupe.
El archivo de configuración contiene las opciones de configuración específicas de su proyecto, y el directorio de información
mantiene un archivo de exclusión global para los patrones ignorados que no desea rastrear en un archivo .gitignore . El directorio
de ganchos contiene los scripts de gancho del lado del cliente o del servidor, que se analizan en detalle en Git Hooks.
Esto deja cuatro entradas importantes: el HEAD y los archivos de índice (aún por crear) , y los directorios de objetos y
referencias . Estas son las partes principales de Git. El directorio de objetos almacena todo el contenido de su base de datos, el
directorio de refs almacena punteros en objetos de confirmación en esos datos (ramas, etiquetas, controles remotos y más), el
archivo HEAD apunta a la rama que actualmente ha verificado y el archivo de índice es donde Git almacena la información del
área de ensayo. Ahora verá cada una de estas secciones en detalle para ver cómo funciona Git.
Objetos Git
Git es un sistema de archivos direccionable por contenido. Genial. ¿Que significa eso? Significa que en el núcleo de Git hay un
simple almacén de datos de clave-valor. Lo que esto significa es que puede insertar cualquier tipo de contenido en un repositorio
de Git, para lo cual Git le devolverá una clave única que puede usar más adelante para recuperar ese
contenido.
Como demostración, veamos el comando de plomería git hash-object, que toma algunos datos, los almacena en su directorio .git/
objects (la base de datos de objetos) y le devuelve la clave única que ahora se refiere a ese objeto de datos.
Primero, inicializas un nuevo repositorio de Git y verificas que (como era de esperar) no hay nada en el directorio de objetos :
Git ha inicializado el directorio de objetos y ha creado subdirectorios de paquete e información en él, pero hay
432
Machine Translated by Google
no hay archivos regulares. Ahora, usemos git hash-object para crear un nuevo objeto de datos y almacenarlo manualmente en
su nueva base de datos de Git:
En su forma más simple, git hash-object tomaría el contenido que le entregó y simplemente devolvería la clave única que se
usaría para almacenarlo en su base de datos de Git. La opción -w luego le dice al comando que no solo devuelva la clave, sino
que escriba ese objeto en la base de datos. Finalmente, la opción --stdin le dice a git hash-object que obtenga el contenido para
ser procesado desde stdin; de lo contrario, el comando esperaría un argumento de nombre de archivo al final del comando que
contiene el contenido que se utilizará.
El resultado del comando anterior es un hash de suma de comprobación de 40 caracteres. Este es el hash SHA-1: una suma de
verificación del contenido que está almacenando más un encabezado, del que aprenderá en un momento. Ahora puedes ver
cómo Git ha almacenado tus datos:
Si vuelve a examinar su directorio de objetos , puede ver que ahora contiene un archivo para ese nuevo contenido. Así es como
Git almacena el contenido inicialmente: como un solo archivo por pieza de contenido, nombrado con la suma de verificación
SHA-1 del contenido y su encabezado. El subdirectorio se nombra con los primeros 2 caracteres del SHA-1 y el nombre del
archivo son los 38 caracteres restantes.
Una vez que tenga contenido en su base de datos de objetos, puede examinar ese contenido con el comando git cat-file . Este
comando es una especie de navaja suiza para inspeccionar objetos de Git. Pasar -p al archivo cat le indica al comando que
primero averigüe el tipo de contenido y luego lo muestre de manera adecuada:
Ahora, puede agregar contenido a Git y volver a extraerlo. También puede hacer esto con el contenido de los archivos.
Por ejemplo, puede hacer un control de versión simple en un archivo. Primero, cree un nuevo archivo y guarde su contenido en
su base de datos:
433
Machine Translated by Google
Su base de datos de objetos ahora contiene ambas versiones de este nuevo archivo (así como el primer contenido
que almacenó allí):
En este punto, puede eliminar su copia local de ese archivo test.txt , luego usar Git para recuperar, desde la base de
datos de objetos, la primera versión que guardó:
o la segunda versión:
Pero recordar la clave SHA-1 para cada versión de su archivo no es práctico; además, no está almacenando el nombre
del archivo en su sistema, solo el contenido. Este tipo de objeto se denomina blob. Puede hacer que Git le diga el tipo
de objeto de cualquier objeto en Git, dada su clave SHA-1, con git cat-file -t:
Objetos de árbol
El siguiente tipo de objeto de Git que examinaremos es el árbol, que resuelve el problema de almacenar el nombre del
archivo y también le permite almacenar un grupo de archivos juntos. Git almacena contenido de manera similar a un
sistema de archivos UNIX, pero un poco simplificado. Todo el contenido se almacena como objetos de árbol y blob,
con árboles correspondientes a entradas de directorio de UNIX y blobs correspondientes más o menos a inodos o
contenido de archivos. Un solo objeto de árbol contiene una o más entradas, cada una de las cuales es el hash SHA-1
de un blob o subárbol con su modo, tipo y nombre de archivo asociados. Por ejemplo, supongamos que tiene un
proyecto en el que el árbol más reciente se ve así:
99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 de rake
434
Machine Translated by Google
rama maestra . Tenga en cuenta que el subdirectorio lib no es un blob sino un puntero a otro árbol:
Según el shell que utilice, es posible que encuentre errores al utilizar la sintaxis master^{tree} .
En CMD en Windows, el carácter ^ se usa para escapar, por lo que debe duplicarlo para
ÿ evitar esto: git cat-file -p master^^{tree}. Al usar PowerShell, los parámetros que usan {}
caracteres deben citarse para evitar que el parámetro se analice incorrectamente: git cat-file
-p 'master^{tree}'.
Si usa ZSH, el carácter ^ se usa para englobar, por lo que debe incluir la expresión completa
entre comillas: git cat-file -p "master^{tree}".
Puede crear fácilmente su propio árbol. Git normalmente crea un árbol tomando el estado de su área de
preparación o índice y escribiendo una serie de objetos de árbol a partir de él. Por lo tanto, para crear un objeto
de árbol, primero debe configurar un índice organizando algunos archivos. Para crear un índice con una sola
entrada, la primera versión de su archivo test.txt , puede usar el comando de plomería git update-index. usas esto
435
Machine Translated by Google
comando para agregar artificialmente la versión anterior del archivo test.txt a una nueva área de ensayo. Debe pasarle la opción --
add porque el archivo aún no existe en su área de preparación (todavía no tiene configurada un área de preparación) y --cacheinfo
porque el archivo que está agregando no está en su directorio pero está en su base de datos. Luego, especifica el modo, SHA-1 y
el nombre del archivo:
En este caso, está especificando un modo de 100644, lo que significa que es un archivo normal. Otras opciones son 100755, lo
que significa que es un archivo ejecutable; y 120000, que especifica un enlace simbólico. El modo se toma de los modos UNIX
normales pero es mucho menos flexible: estos tres modos son los únicos que son válidos para archivos (blobs) en Git (aunque se
usan otros modos para directorios y submódulos).
Ahora, puede usar git write-tree para escribir el área de preparación en un objeto de árbol. No se necesita la opción -w : llamar a
este comando crea automáticamente un objeto de árbol a partir del estado del índice si ese árbol aún no existe:
$ git escribir-árbol
d8329fc1cc938780ffdd9f94e0d364e0ea74f579
$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579 100644 blob
83baae61804e65cc73a7201a7252750c76066a30 prueba.txt
También puede verificar que este es un objeto de árbol usando el mismo comando git cat-file que vio anteriormente:
Ahora creará un nuevo árbol con la segunda versión de test.txt y también un nuevo archivo:
Su área de preparación ahora tiene la nueva versión de test.txt , así como el nuevo archivo new.txt. Escriba ese árbol (registrando
el estado del área de preparación o el índice de un objeto de árbol) y vea cómo se ve:
$ git write-tree
0155eb4229851634a0f03eb265b69f5a2d56f341 $ git
cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341 100644 blob
fa49b077972391ad58037051e4e2a3 nuevo.txt
100644 gota 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a prueba.txt
436
Machine Translated by Google
Tenga en cuenta que este árbol tiene ambas entradas de archivo y también que test.txt SHA-1 es la "versión 2" SHA-1
de antes (1f7a7a). Solo por diversión, agregará el primer árbol como un subdirectorio en este. Puede leer árboles en su área de
preparación llamando a git read-tree. En este caso, puede leer un árbol existente en su área de preparación como un subárbol
usando la opción --prefix con este comando:
Si creó un directorio de trabajo a partir del nuevo árbol que acaba de escribir, obtendría los dos archivos en el nivel superior del
directorio de trabajo y un subdirectorio llamado bak que contenía la primera versión del archivo test.txt . Puede pensar en los datos
que contiene Git para estas estructuras de la siguiente manera:
Confirmar objetos
Si ha hecho todo lo anterior, ahora tiene tres árboles que representan las diferentes instantáneas de su proyecto que desea rastrear,
pero el problema anterior persiste: debe recordar los tres valores SHA-1 para recuperar las instantáneas. . Tampoco tienes
información sobre quién guardó
437
Machine Translated by Google
las instantáneas, cuándo se guardaron o por qué se guardaron. Esta es la información básica que el objeto de confirmación
almacena para usted.
Para crear un objeto de confirmación, llame a commit-tree y especifique un solo árbol SHA-1 y qué objetos de confirmación,
si los hay, lo precedieron directamente. Comienza con el primer árbol que escribiste:
Obtendrá un valor hash diferente debido a la hora de creación y los datos de autor diferentes. Además,
aunque en principio cualquier objeto de confirmación puede reproducirse con precisión dados esos
ÿ datos, los detalles históricos de la construcción de este libro significan que los hashes de confirmación
impresos pueden no corresponder a las confirmaciones dadas. Reemplace los hashes de confirmación
y etiquetas con sus propias sumas de verificación más adelante en este capítulo.
Primera confirmación
El formato de un objeto de confirmación es simple: especifica el árbol de nivel superior para la instantánea del proyecto en
ese punto; el padre confirma, si lo hay (el objeto de confirmación descrito anteriormente no tiene ningún padre); la información
del autor/autor (que usa su nombre de usuario y los ajustes de configuración de correo electrónico de usuario y una marca
de tiempo); una línea en blanco y luego el mensaje de confirmación.
A continuación, escribirá los otros dos objetos de confirmación, cada uno de los cuales hará referencia a la confirmación
anterior:
Cada uno de los tres objetos de confirmación apunta a uno de los tres árboles de instantáneas que creó. Por extraño que
parezca, ahora tiene un historial de Git real que puede ver con el comando de registro de git , si lo ejecuta en la última
confirmación SHA-1:
438
Machine Translated by Google
Tercer compromiso
bak/prueba.txt | 1 1+
archivo cambiado, 1 inserción (+)
Segunda confirmación
nuevo.txt | 1 +
prueba.txt | 2 +- 2
archivos cambiados, 2 inserciones (+), 1 borrado (-)
confirmar fdf4fc3344e67ab068f836878b6c4951e3b15f3d
Autor: Scott Chacon <schacon@gmail.com> Fecha:
viernes 22 de mayo 18:09:34 2009 -0700
Primera confirmación
prueba.txt | 1 + 1
archivo cambiado, 1 inserción (+)
Asombroso. Acaba de realizar las operaciones de bajo nivel para crear un historial de Git sin usar ninguno de los
comandos de front-end. Esto es esencialmente lo que hace Git cuando ejecuta los comandos git add y git
commit : almacena blobs para los archivos que han cambiado, actualiza el índice, escribe árboles y escribe
objetos de confirmación que hacen referencia a los árboles de nivel superior y las confirmaciones que vino
inmediatamente antes que ellos. Estos tres objetos principales de Git (el blob, el árbol y la confirmación) se
almacenan inicialmente como archivos separados en su directorio .git/objects . Aquí están todos los objetos en
el directorio de ejemplo ahora, comentados con lo que almacenan:
439
Machine Translated by Google
Si sigue todos los punteros internos, obtendrá un gráfico de objetos como este:
Almacenamiento de objetos
Mencionamos anteriormente que hay un encabezado almacenado con cada objeto que envías a tu base de datos
de objetos de Git. Tomemos un minuto para ver cómo Git almacena sus objetos. Verá cómo almacenar un objeto
blob, en este caso, la cadena "¿qué pasa, doctor?" — de forma interactiva en el lenguaje de programación Ruby.
$ irb
>> content = "¿qué pasa, doctor?"
=> "¿Qué pasa, doctor?"
Git primero construye un encabezado que comienza identificando el tipo de objeto, en este caso, un blob. A esa
primera parte del encabezado, Git agrega un espacio seguido del tamaño en bytes del contenido, y agrega un byte
nulo final:
440
Machine Translated by Google
Git concatena el encabezado y el contenido original y luego calcula la suma de verificación SHA-1 de
ese nuevo contenido. Puede calcular el valor SHA-1 de una cadena en Ruby al incluir la biblioteca de
resumen SHA1 con el comando require y luego llamar a Digest::SHA1.hexdigest() con la cadena:
Comparemos eso con la salida de git hash-object. Aquí usamos echo -n para evitar agregar una nueva
línea a la entrada.
Git comprime el nuevo contenido con zlib, lo que puede hacer en Ruby con la biblioteca zlib. Primero,
debe solicitar la biblioteca y luego ejecutar Zlib::Deflate.deflate() en el contenido:
Finalmente, escribirá su contenido desinflado de zlib en un objeto en el disco. Determinará la ruta del
objeto que desea escribir (los primeros dos caracteres del valor SHA-1 son el nombre del subdirectorio
y los últimos 38 caracteres son el nombre del archivo dentro de ese directorio). En Ruby, puede usar la
función FileUtils.mkdir_p() para crear el subdirectorio si no existe. Luego, abra el archivo con File.open()
y escriba el contenido previamente comprimido con zlib en el archivo con una llamada write() en el
identificador de archivo resultante:
441
Machine Translated by Google
---
---
Todos los objetos de Git se almacenan de la misma manera, solo que con diferentes tipos: en lugar del blob de cadena, el
encabezado comenzará con confirmación o árbol. Además, aunque el contenido del blob puede ser casi cualquier cosa, el
contenido del árbol y la confirmación tienen un formato muy específico.
Referencias Git
Si estuviera interesado en ver el historial de su repositorio al que se puede acceder desde la confirmación, digamos,
1a410e, podría ejecutar algo como git log 1a410e para mostrar ese historial, pero aún tendría que recordar que 1a410e es
la confirmación que desea usar como el punto de partida de esa historia. En cambio, sería más fácil si tuviera un archivo
en el que pudiera almacenar ese valor SHA-1 con un nombre simple para poder usar ese nombre simple en lugar del valor
SHA-1 sin procesar.
En Git, estos nombres simples se denominan "referencias" o "refs"; puede encontrar los archivos que contienen esos
valores SHA-1 en el directorio .git/refs . En el proyecto actual, este directorio no contiene archivos, pero contiene una
estructura simple:
Para crear una nueva referencia que te ayude a recordar dónde está tu última confirmación, técnicamente puedes hacer
algo tan simple como esto:
Ahora, puede usar la referencia principal que acaba de crear en lugar del valor SHA-1 en sus comandos de Git:
No se recomienda que edite directamente los archivos de referencia; en su lugar, Git proporciona el comando más seguro
git update-ref para hacer esto si desea actualizar una referencia:
442
Machine Translated by Google
Eso es básicamente lo que es una rama en Git: un simple puntero o referencia al encabezado de una línea de trabajo.
Para volver a crear una rama en la segunda confirmación, puede hacer esto:
Figura 150. Objetos de directorio de Git con referencias de cabecera de rama incluidas
Cuando ejecuta comandos como git branch <branch>, Git básicamente ejecuta ese comando update-ref para agregar el
SHA-1 de la última confirmación de la rama en la que se encuentra en cualquier referencia nueva que desee
crear.
La cabeza
La pregunta ahora es, cuando ejecutas git branch <branch>, ¿cómo sabe Git el SHA-1 de la última confirmación? La
respuesta es el archivo HEAD.
Por lo general, el archivo HEAD es una referencia simbólica a la rama en la que se encuentra actualmente. Por referencia
simbólica, queremos decir que, a diferencia de una referencia normal, contiene un puntero a otra referencia.
443
Machine Translated by Google
Sin embargo, en algunos casos excepcionales, el archivo HEAD puede contener el valor SHA-1 de un objeto git. Esto sucede cuando revisa
una etiqueta, una confirmación o una rama remota, lo que pone su repositorio en "separado".
CABEZA" estado.
$ gato .git/HEAD
ref: refs/heads/master
Si ejecuta la prueba de pago de git, Git actualiza el archivo para que se vea así:
Cuando ejecuta git commit, crea el objeto de confirmación, especificando que el padre de ese objeto de confirmación sea cualquier valor
SHA-1 al que apunte la referencia en HEAD.
También puede editar manualmente este archivo, pero nuevamente existe un comando más seguro para hacerlo: git simbólico-ref.
Puedes leer el valor de tu HEAD a través de este comando:
$ gitsimbolic-ref HEAD
refs/heads/master
Etiquetas
Acabamos de hablar sobre los tres tipos de objetos principales de Git (blobs, árboles y confirmaciones), pero hay un cuarto. El objeto de
etiqueta es muy parecido a un objeto de confirmación: contiene un etiquetador, una fecha, un mensaje y un puntero. La principal diferencia
es que un objeto de etiqueta generalmente apunta a una confirmación en lugar de a un árbol. Es como una referencia a una rama, pero
nunca se mueve; siempre apunta a la misma confirmación pero le da un nombre más amigable.
Como se discutió en Conceptos básicos de Git, hay dos tipos de etiquetas: anotadas y ligeras. Puede hacer una etiqueta ligera ejecutando
algo como esto:
444
Machine Translated by Google
Eso es todo lo que es una etiqueta ligera: una referencia que nunca se mueve. Sin embargo, una etiqueta anotada es más
compleja. Si crea una etiqueta anotada, Git crea un objeto de etiqueta y luego escribe una referencia para señalarlo en
lugar de apuntar directamente a la confirmación. Puede ver esto creando una etiqueta anotada (usando la opción -a ):
$ gato .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
Etiqueta de prueba
Observe que la entrada del objeto apunta al valor SHA-1 de confirmación que etiquetó. También tenga en cuenta que no
necesita apuntar a una confirmación; puede etiquetar cualquier objeto de Git. En el código fuente de Git, por ejemplo, el
mantenedor agregó su clave pública GPG como un objeto blob y luego lo etiquetó. Puede ver la clave pública ejecutando
esto en un clon del repositorio de Git:
El repositorio del kernel de Linux también tiene un objeto de etiqueta que no apunta a confirmación: la primera etiqueta
creada apunta al árbol inicial de la importación del código fuente.
Controles remotos
El tercer tipo de referencia que verá es una referencia remota. Si agrega un control remoto y lo presiona, Git almacena el
valor que envió por última vez a ese control remoto para cada rama en el directorio refs/remotes .
Por ejemplo, puede agregar un origen remoto llamado y enviarle su rama maestra :
445
Machine Translated by Google
Luego, puede ver cuál era la rama maestra en el control remoto de origen la última vez que se comunicó con el servidor,
revisando el archivo refs/remotes/origin/master :
$ gato .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
Las referencias remotas se diferencian de las ramas (referencias de referencias/cabeceras ) principalmente en que se
consideran de solo lectura. Puede hacer git checkout a uno, pero Git no hará referencia simbólica a HEAD a uno, por lo
que nunca lo actualizará con un comando de confirmación . Git los administra como marcadores del último estado
conocido de dónde estaban esas sucursales en esos servidores.
Paquetes de archivos
Si siguió todas las instrucciones del ejemplo de la sección anterior, ahora debería tener un repositorio Git de prueba con
11 objetos: cuatro blobs, tres árboles, tres confirmaciones y una etiqueta:
Git comprime el contenido de estos archivos con zlib, y no está almacenando mucho, por lo que todos estos archivos en
conjunto ocupan solo 925 bytes. Ahora agregará contenido más considerable al repositorio para demostrar una
característica interesante de Git. Para demostrarlo, agregaremos el archivo repo.rb de la biblioteca Grit; se trata de un
archivo de código fuente de 22K:
446
Machine Translated by Google
Si observa el árbol resultante, puede ver el valor SHA-1 que se calculó para su nuevo objeto de blob repo.rb :
Luego puede usar git cat-file para ver qué tan grande es ese objeto:
El blob ahora es un blob diferente, lo que significa que aunque agregó solo una línea al final de un archivo de 400
líneas, Git almacenó ese contenido nuevo como un objeto completamente nuevo:
447
Machine Translated by Google
Tiene dos objetos de 22K casi idénticos en su disco (cada uno comprimido a aproximadamente 7K).
¿No sería bueno si Git pudiera almacenar uno de ellos en su totalidad, pero luego el segundo objeto solo como el delta
entre él y el primero?
Resulta que puede. El formato inicial en el que Git guarda objetos en el disco se denomina formato de objeto "suelto".
Sin embargo, ocasionalmente Git empaqueta varios de estos objetos en un solo archivo binario llamado "packfile" para
ahorrar espacio y ser más eficiente. Git hace esto si tiene demasiados objetos sueltos, si ejecuta el comando git gc
manualmente o si lo envía a un servidor remoto. Para ver qué sucede, puedes pedirle manualmente a Git que empaque
los objetos llamando al comando git gc :
$ git gc
Contando objetos: 18, listo.
Compresión delta usando hasta 8 hilos.
Comprimir objetos: 100% (14/14), hecho.
Objetos de escritura: 100% (18/18), hecho.
Total 18 (delta 3), reutilizado 0 (delta 0)
Si busca en su directorio de objetos , encontrará que la mayoría de sus objetos se han ido y ha aparecido un nuevo par
de archivos:
Los objetos que quedan son los blobs a los que no apunta ninguna confirmación; en este caso, el "¿qué pasa, doctor?"
y los blobs de ejemplo de "contenido de prueba" que creó anteriormente. Debido a que nunca los agregó a ninguna
confirmación, se consideran colgantes y no están empaquetados en su nuevo archivo de paquete.
Los otros archivos son su nuevo archivo de paquete y un índice. El archivo de paquete es un archivo único que contiene
el contenido de todos los objetos que se eliminaron de su sistema de archivos. El índice es un archivo que contiene
compensaciones en ese archivo de paquete para que pueda buscar rápidamente un objeto específico. Lo bueno es que,
aunque los objetos en el disco antes de ejecutar el comando gc tenían un tamaño aproximado de 15 KB, el nuevo archivo
de paquete solo tiene 7 KB. Ha reducido el uso de su disco a la mitad empaquetando sus objetos.
¿Cómo hace esto Git? Cuando Git empaqueta objetos, busca archivos que tengan nombres y tamaños similares, y
almacena solo los deltas de una versión del archivo a la siguiente. Puede consultar el archivo del paquete y ver qué hizo
Git para ahorrar espacio. El comando de plomería git verificar-paquete le permite ver lo que se empaquetó:
448
Machine Translated by Google
Aquí, el blob 033b4 , que si recuerda fue la primera versión de su archivo repo.rb , hace referencia al blob b042a , que fue la segunda
versión del archivo. La tercera columna en la salida es el tamaño del objeto en el paquete, por lo que puede ver que b042a ocupa 22K
del archivo, pero que 033b4 solo ocupa 9 bytes. Lo que también es interesante es que la segunda versión del archivo es la que se
almacena intacta, mientras que la versión original se almacena como un delta; esto se debe a que es más probable que necesite un
acceso más rápido a la versión más reciente del archivo. .
Lo realmente bueno de esto es que se puede volver a empaquetar en cualquier momento. Ocasionalmente, Git volverá a empaquetar
su base de datos automáticamente, siempre tratando de ahorrar más espacio, pero también puede volver a empaquetar manualmente
en cualquier momento ejecutando git gc a mano.
La especificación de referencia
A lo largo de este libro, hemos utilizado asignaciones simples de sucursales remotas a referencias locales, pero pueden ser más
complejas. Suponga que estaba siguiendo las dos últimas secciones y había creado un pequeño repositorio Git local y ahora deseaba
agregarle un control remoto :
Ejecutar el comando anterior agrega una sección al archivo .git/config de su repositorio , especificando el
449
Machine Translated by Google
nombre del remoto (origen), la URL del repositorio remoto y la especificación de referencia que se usará para obtener:
["origen" remoto]
url = https://github.com/schacon/simplegit-progit fetch =
+refs/heads/*:refs/remotes/origin/*
El formato de refspec es, primero, un + opcional, seguido de <src>:<dst>, donde <src> es el patrón para las referencias en el lado
remoto y <dst> es donde esas referencias se rastrearán localmente. El + le dice a Git que actualice la referencia incluso si no es
un avance rápido.
En el caso predeterminado que se escribe automáticamente mediante un comando git remote add origin , Git obtiene todas las
referencias en refs/heads/ en el servidor y las escribe en refs/remotes/origin/ localmente. Entonces, si hay una rama maestra en
el servidor, puede acceder al registro de esa rama localmente a través de cualquiera de los siguientes:
Todos son equivalentes, porque Git expande cada uno de ellos a refs/remotes/origin/master.
Si, en cambio, desea que Git despliegue solo la rama maestra cada vez, y no todas las demás ramas en el servidor remoto, puede
cambiar la línea de búsqueda para que se refiera solo a esa rama:
buscar = +refs/heads/master:refs/remotos/origen/master
Esta es solo la especificación de referencia predeterminada para git fetch para ese control remoto. Si desea realizar una
recuperación única, también puede especificar la especificación de referencia específica en la línea de comando. Para llevar la
rama maestra en el control remoto a origin/mymaster localmente, puede ejecutar:
También puede especificar múltiples refspecs. En la línea de comando, puede desplegar varias ramas así:
topic:refs/remotes/origin/topic From
git@github.com:schacon/simplegit ! [rechazado] maestro *
[nueva rama] tema -> origen/mymaster (no avance rápido)
-> origen/tema
En este caso, se rechazó la extracción de la rama maestra porque no figuraba como una referencia de avance rápido.
Puede anular eso especificando el + delante de refspec.
450
Machine Translated by Google
También puede especificar múltiples refspecs para buscar en su archivo de configuración. Si desea obtener siempre las ramas
principal y experimental del control remoto de origen , agregue dos líneas:
["origen" remoto]
url = https://github.com/schacon/simplegit-progit fetch =
+refs/heads/master:refs/remotes/origin/master fetch = +refs/
heads/experiment:refs/remotes/ origen/experimento
Desde Git 2.6.0, puede usar globos parciales en el patrón para hacer coincidir varias ramas, así que esto funciona:
buscar = +refs/heads/qa*:refs/remotes/origin/qa*
Aún mejor, puede usar espacios de nombres (o directorios) para lograr lo mismo con más estructura.
Si tiene un equipo de control de calidad que impulsa una serie de sucursales y desea obtener la sucursal maestra y cualquiera de las
sucursales del equipo de control de calidad, pero nada más, puede usar una sección de configuración como esta:
["origen" remoto]
url = https://github.com/schacon/simplegit-progit fetch =
+refs/heads/master:refs/remotes/origin/master fetch = +refs/
heads/qa/*:refs/ controles remotos/origen/qa/*
Si tiene un proceso de flujo de trabajo complejo que tiene un equipo de control de calidad que impulsa sucursales, desarrolladores
que impulsan sucursales y equipos de integración que impulsan y colaboran en sucursales remotas, puede asignarles nombres
fácilmente de esta manera.
Empujando Refspecs
Es bueno que pueda obtener referencias de espacios de nombres de esa manera, pero, en primer lugar, ¿cómo hace el equipo de
control de calidad para que sus sucursales entren en un espacio de nombres qa/ ? Lo logras usando refspecs para empujar.
Si el equipo de control de calidad quiere enviar su rama maestra a qa/master en el servidor remoto, puede ejecutar:
Si quieren que Git lo haga automáticamente cada vez que ejecuten git push origin, pueden agregar un valor push a su archivo de
configuración:
["origen" remoto]
url = https://github.com/schacon/simplegit-progit fetch =
+refs/heads/*:refs/remotes/origin/* push = refs/heads/
master:refs/heads/qa /Maestro
Nuevamente, esto hará que un origen de git push envíe la rama maestra local a la rama maestra/qa remota de forma predeterminada.
451
Machine Translated by Google
Eliminación de referencias
También puede usar refspec para eliminar referencias del servidor remoto ejecutando algo como esto:
Debido a que refspec es <src>:<dst>, al omitir la parte <src> , esto básicamente dice que haga que el tema se ramifique en el
nada remoto, lo que lo eliminará.
Protocolos de transferencia
Git puede transferir datos entre dos repositorios de dos formas principales: el protocolo "tonto" y el protocolo "inteligente". Esta
sección cubrirá rápidamente cómo funcionan estos dos protocolos principales.
El protocolo tonto
Si está configurando un repositorio para que se sirva solo de lectura a través de HTTP, es probable que se use el protocolo
tonto. Este protocolo se llama "tonto" porque no requiere código específico de Git en el lado del servidor durante el proceso de
transporte; el proceso de obtención es una serie de solicitudes HTTP GET , donde el cliente puede asumir el diseño del
repositorio de Git en el servidor.
El protocolo tonto rara vez se usa en estos días. Es difícil asegurarlo o hacerlo privado, por lo que la
ÿ mayoría de los hosts de Git (tanto en la nube como en las instalaciones) se negarán a usarlo.
En general, se recomienda utilizar el protocolo inteligente, que describimos un poco más adelante.
Lo primero que hace este comando es desplegar el archivo info/refs . Este archivo está escrito por el comando de actualización
de información del servidor , por lo que debe habilitarlo como un enlace posterior a la recepción para que el transporte HTTP
funcione correctamente:
=> OBTENER
información/refs ca82a6dff817ec66f44342007202690a93763949árbitros/jefes/maestro
452
Machine Translated by Google
Ahora tiene una lista de las referencias remotas y SHA-1. A continuación, busque cuál es la referencia HEAD para saber qué
verificar cuando haya terminado:
ref: refs/cabezas/maestro
Debe verificar la rama maestra cuando haya completado el proceso. En este punto, está listo para comenzar el proceso de
caminar. Debido a que su punto de partida es el objeto de confirmación ca82a6 que vio en el archivo info/refs , comienza por
obtener eso:
Obtiene un objeto de vuelta: ese objeto está en formato suelto en el servidor y lo obtuvo a través de una solicitud HTTP GET
estática. Puede descomprimirlo con zlib, quitar el encabezado y ver el contenido de la confirmación:
A continuación, tiene dos objetos más para recuperar: cfda3b, que es el árbol de contenido al que apunta la confirmación que
acabamos de recuperar; y 085bb3, que es la confirmación principal:
Vaya, parece que ese objeto de árbol no está en formato suelto en el servidor, por lo que obtiene una respuesta 404. Hay un
par de razones para esto: el objeto podría estar en un repositorio alternativo o podría estar en un archivo de paquete en este
repositorio. Git verifica primero las alternativas enumeradas:
Si vuelve con una lista de direcciones URL alternativas, Git comprueba si hay archivos sueltos y paquetes de archivos; esto es
453
Machine Translated by Google
un buen mecanismo para proyectos que son bifurcaciones entre sí para compartir objetos en el disco. Sin embargo, debido
a que no se enumeran alternativas en este caso, su objeto debe estar en un archivo de paquete. Para ver qué archivos de
paquete están disponibles en este servidor, debe obtener el archivo de objetos/información/paquetes , que contiene una
lista de ellos (también generado por update-server-info):
Solo hay un archivo de paquete en el servidor, por lo que su objeto obviamente está allí, pero verificará el archivo de índice
para asegurarse. Esto también es útil si tiene varios archivos de paquete en el servidor, para que pueda ver qué archivo
de paquete contiene el objeto que necesita:
Ahora que tiene el índice del archivo de paquete, puede ver si su objeto está en él, porque el índice enumera los SHA-1
de los objetos contenidos en el archivo de paquete y las compensaciones de esos objetos. Tu objeto está ahí, así que
continúa y obtén el archivo de paquete completo:
Tiene su objeto de árbol, por lo que continúa recorriendo sus compromisos. También están todos dentro del archivo de
paquete que acaba de descargar, por lo que no tiene que hacer más solicitudes a su servidor. Git extrae una copia de
trabajo de la rama maestra a la que apuntaba la referencia HEAD que descargaste al principio.
El protocolo inteligente
El protocolo tonto es simple pero un poco ineficiente y no puede manejar la escritura de datos del cliente al servidor. El
protocolo inteligente es un método más común para transferir datos, pero requiere un proceso en el extremo remoto que
sea inteligente sobre Git: puede leer datos locales, descubrir qué tiene y necesita el cliente y generar un archivo de paquete
personalizado para ello. Hay dos conjuntos de procesos para transferir datos: un par para cargar datos y un par para
descargar datos.
Cargando datos
Para cargar datos en un proceso remoto, Git utiliza los procesos send-pack y receive-pack . El proceso de envío del
paquete se ejecuta en el cliente y se conecta a un proceso de recepción del paquete en el lado remoto.
SSH
Por ejemplo, supongamos que ejecuta git push origin master en su proyecto y origin se define como una URL que usa el
protocolo SSH. Git activa el proceso de paquete de envío , que inicia una conexión a través de SSH a su servidor. Intenta
ejecutar un comando en el servidor remoto a través de una llamada SSH que se parece a esto:
454
Machine Translated by Google
El comando git-receive-pack responde inmediatamente con una línea por cada referencia que tiene actualmente; en este
caso, solo la rama principal y su SHA-1. La primera línea también tiene una lista de las capacidades del servidor (aquí, report-
status, delete-refs y algunas otras, incluido el identificador del cliente).
Los datos se transmiten en fragmentos. Cada fragmento comienza con un valor hexadecimal de 4 caracteres que especifica
la longitud del fragmento (incluidos los 4 bytes de la propia longitud). Los fragmentos suelen contener una sola línea de
datos y un avance de línea final. Su primer fragmento comienza con 00a5, que es hexadecimal para 165, lo que significa
que el fragmento tiene una longitud de 165 bytes. El siguiente fragmento es 0000, lo que significa que el servidor ha
terminado con su lista de referencias.
Ahora que conoce el estado del servidor, su proceso de paquete de envío determina qué confirmaciones tiene que el
servidor no tiene. Para cada referencia que este impulso actualizará, el proceso de envío y paquete le dice al proceso de
recepción del paquete esa información. Por ejemplo, si está actualizando la rama maestra y agregando una rama
experimental , la respuesta del paquete de envío puede verse así:
0076ca82a6dff817ec66f44342007202690a93763949 15027957951b64cf874c3557a0f3547bd83b3ff6
\ refs / heads / master-informe de estado 006c0000000000000000000000000000000000000000
cdfdb42577e2506715f8cfeacdbabc092bf63e8d \ refs / heads / experimento 0000
Git envía una línea para cada referencia que estás actualizando con la longitud de la línea, el SHA-1 antiguo, el SHA-1
nuevo y la referencia que se está actualizando. La primera línea también tiene las capacidades del cliente. El valor SHA-1
de todos los '0' significa que no había nada antes, porque está agregando la referencia del experimento. Si estuviera
eliminando una referencia, vería lo contrario: todos los '0' en el lado derecho.
A continuación, el cliente envía un archivo de paquete de todos los objetos que el servidor aún no tiene. Finalmente, el
servidor responde con una indicación de éxito (o fracaso):
000e desempaquetar ok
HTTP(S)
Este proceso es prácticamente el mismo en HTTP, aunque el protocolo de enlace es un poco diferente. La conexión se
inicia con esta petición:
455
Machine Translated by Google
Ese es el final del primer intercambio cliente-servidor. Luego, el cliente realiza otra solicitud, esta vez una POST, con
los datos que proporciona send-pack .
La solicitud POST incluye la salida del paquete de envío y el archivo del paquete como su carga útil. Luego, el servidor
indica el éxito o el fracaso con su respuesta HTTP.
Tenga en cuenta que el protocolo HTTP puede envolver aún más estos datos dentro de una codificación de transferencia fragmentada.
Descarga de datos
Cuando descarga datos, están involucrados los procesos fetch-pack y upload-pack . El cliente inicia un proceso de
paquete de búsqueda que se conecta a un proceso de paquete de carga en el lado remoto para negociar qué datos se
transferirán hacia abajo.
SSH
Si está realizando la búsqueda a través de SSH, fetch-pack ejecuta algo como esto:
Esto es muy similar a lo que responde el paquete de recepción , pero las capacidades son diferentes. Además,
devuelve a qué apunta HEAD (symref=HEAD:refs/heads/master) para que el cliente sepa qué verificar si se trata de un
clon.
En este punto, el proceso fetch-pack mira qué objetos tiene y responde con los objetos que necesita enviando "quiero"
y luego el SHA-1 que quiere. Envía todos los objetos que ya tiene con “have” y luego el SHA-1. Al final de esta lista,
escribe "hecho" para iniciar el proceso de carga del paquete para comenzar a enviar el paquete de datos que necesita:
456
Machine Translated by Google
HTTP(S)
El protocolo de enlace para una operación de búsqueda requiere dos solicitudes HTTP. El primero es un GET al mismo
punto final utilizado en el protocolo tonto:
Esto es muy similar a invocar git-upload-pack a través de una conexión SSH, pero el segundo intercambio se realiza como
una solicitud separada:
Nuevamente, este es el mismo formato que el anterior. La respuesta a esta solicitud indica éxito o fracaso e incluye el
archivo del paquete.
Resumen de protocolos
Esta sección contiene una descripción general muy básica de los protocolos de transferencia. El protocolo incluye muchas
otras características, como multi_ack o capacidades de banda lateral , pero cubrirlas está fuera del alcance de este libro.
Hemos tratado de darle una idea del vaivén general entre el cliente y el servidor; si necesita más conocimientos que estos,
probablemente querrá echar un vistazo al código fuente de Git.
Mantenimiento
De vez en cuando, Git ejecuta automáticamente un comando llamado "auto gc". La mayoría de las veces, este comando no
hace nada. Sin embargo, si hay demasiados objetos sueltos (objetos que no están en un archivo de paquete) o demasiados
457
Machine Translated by Google
packfiles, Git lanza un comando git gc completo . El "gc" significa recolección de basura, y el comando hace una serie de cosas:
reúne todos los objetos sueltos y los coloca en archivos de paquete, consolida los archivos de paquete en un archivo de paquete
grande y elimina los objetos que no son accesibles desde cualquier lugar. cometer y tienen unos meses de edad.
$ git gc --auto
Nuevamente, esto generalmente no hace nada. Debe tener alrededor de 7000 objetos sueltos o más de 50 archivos de paquete
para que Git inicie un comando gc real. Puede modificar estos límites con los ajustes de configuración gc.auto y gc.autopacklimit ,
respectivamente.
La otra cosa que hará gc es empaquetar sus referencias en un solo archivo. Supongamos que su repositorio contiene las
siguientes ramas y etiquetas:
Si ejecuta git gc, ya no tendrá estos archivos en el directorio refs . Git los moverá por el bien de la eficiencia a un archivo
llamado .git/packed-refs que se ve así:
Si actualiza una referencia, Git no edita este archivo, sino que escribe un nuevo archivo en refs/heads. Para obtener el SHA-1
apropiado para una referencia dada, Git busca esa referencia en el directorio de referencias y luego verifica el archivo de
referencias empaquetadas como respaldo. Entonces, si no puede encontrar una referencia en el directorio de referencias ,
probablemente esté en su archivo de referencias empaquetadas .
Observe la última línea del archivo, que comienza con ^. Esto significa que la etiqueta directamente arriba es una etiqueta anotada
y esa línea es la confirmación a la que apunta la etiqueta anotada.
Recuperación de datos
En algún momento de su viaje Git, puede perder accidentalmente una confirmación. En general, esto sucede porque fuerza la
eliminación de una rama que tenía trabajo y resulta que, después de todo, quería la rama; o restablece una rama, abandonando
así las confirmaciones de las que quería algo.
Suponiendo que esto suceda, ¿cómo puede recuperar sus confirmaciones?
458
Machine Translated by Google
Aquí hay un ejemplo que restablece por completo la rama maestra en su repositorio de prueba a una confirmación anterior
y luego recupera las confirmaciones perdidas. Primero, revisemos dónde está su repositorio en este punto:
Efectivamente, ha perdido las dos confirmaciones principales: no tiene una rama desde la que se pueda acceder a esas
confirmaciones. Debe encontrar la última confirmación SHA-1 y luego agregar una rama que apunte a ella. El truco es
encontrar la última confirmación SHA-1: no es como si la hubieras memorizado, ¿verdad?
A menudo, la forma más rápida es usar una herramienta llamada git reflog. Mientras trabaja, Git registra en silencio cuál es
su HEAD cada vez que lo cambia. Cada vez que confirmas o cambias de rama, el reflog se actualiza. El registro de
referencia también se actualiza mediante el comando git update-ref , que es otra razón para usarlo en lugar de simplemente
escribir el valor SHA-1 en sus archivos de referencia, como explicamos en Referencias de Git. Puedes ver dónde has estado
en cualquier momento ejecutando git reflog:
$ git reflog
1a410ef HEAD@{0}: restablecer: pasar a 1a410ef ab1afef
HEAD@{1}: confirmar: modificar un poco repo.rb 484a592
HEAD@{2}: confirmar: crear repo.rb
Aquí podemos ver los dos compromisos que hemos revisado, sin embargo, no hay mucha información aquí. Para ver la
misma información de una manera mucho más útil, podemos ejecutar git log -g, que le dará una salida de registro normal
para su reflog.
459
Machine Translated by Google
$ git log -g
commit 1a410efbd13591db07496601ebc7a059dd55cfe9
Reflog: HEAD@{0} (Scott Chacon <schacon@gmail.com>)
Reflog mensaje: actualización HEAD
Autor: Scott Chacon <schacon@gmail.com> Fecha:
viernes 22 de mayo 18:22:37 2009 -0700
Tercer compromiso
confirmar ab1afef80fac8e34258ff41fc1b867c702daa24b
Reflog: HEAD@{1} (Scott Chacon <schacon@gmail.com>)
Reflog mensaje: actualización HEAD
Autor: Scott Chacon <schacon@gmail.com> Fecha:
viernes 22 de mayo 18:15:24 2009 -0700
Parece que la confirmación inferior es la que perdiste, por lo que puedes recuperarla creando una nueva rama en esa
confirmación. Por ejemplo, puede iniciar una rama llamada recovery -branch en ese compromiso (ab1afef):
Genial: ahora tienes una rama llamada recovery-branch que es donde solía estar tu rama maestra , lo que hace que las dos
primeras confirmaciones sean accesibles nuevamente. A continuación, suponga que su pérdida no estaba en el registro de
referencia por alguna razón; puede simular eso eliminando la rama de recuperación y eliminando el registro de referencia.
Ahora los dos primeros compromisos no son accesibles por nada:
Debido a que los datos de reflog se guardan en el directorio .git/logs/ , efectivamente no tiene reflog. ¿Cómo puedes recuperar
ese compromiso en este punto? Una forma es usar la utilidad git fsck , que verifica la integridad de su base de datos. Si lo
ejecuta con la opción --full , le muestra todos los objetos que no están señalados por otro objeto:
460
Machine Translated by Google
En este caso, puede ver su compromiso faltante después de la cadena "compromiso pendiente". Puede recuperarlo
de la misma manera, agregando una rama que apunte a ese SHA-1.
Eliminación de objetos
Hay muchas cosas geniales sobre Git, pero una característica que puede causar problemas es el hecho de que un
clon de git descarga el historial completo del proyecto, incluidas todas las versiones de cada archivo. Esto está bien si
todo es código fuente, porque Git está altamente optimizado para comprimir esos datos de manera eficiente.
Sin embargo, si alguien en algún momento de la historia de su proyecto agregó un solo archivo enorme, todos los
clones de todos los tiempos se verán obligados a descargar ese archivo grande, incluso si se eliminó del proyecto en
la próxima confirmación. Debido a que es accesible desde la historia, siempre estará allí.
Esto puede ser un gran problema cuando está convirtiendo repositorios de Subversion o Perforce en Git.
Debido a que no descargas todo el historial en esos sistemas, este tipo de adición tiene pocas consecuencias. Si
realizó una importación desde otro sistema o encuentra que su repositorio es mucho más grande de lo que debería
ser, así es como puede encontrar y eliminar objetos grandes.
Tenga cuidado: esta técnica es destructiva para su historial de confirmaciones. Reescribe cada objeto de
confirmación desde el árbol más antiguo que debe modificar para eliminar una referencia de archivo grande. Si hace
esto inmediatamente después de una importación, antes de que alguien haya comenzado a basar su trabajo en la
confirmación, está bien; de lo contrario, debe notificar a todos los colaboradores que deben volver a basar su trabajo
en sus nuevas confirmaciones.
Para demostrarlo, agregará un archivo grande a su repositorio de prueba, lo eliminará en la próxima confirmación, lo
encontrará y lo eliminará permanentemente del repositorio. Primero, agregue un objeto grande a su historial:
$ curl -L https://www.kernel.org/pub/software/scm/git/git-2.1.0.tar.gz > git.tgz $ git add git.tgz $ git commit -m 'Agregar
git tarball ' [master 7b30847] Agregar git tarball 1 archivo cambiado, 0 inserciones (+), 0 eliminaciones (-) modo de
creación 100644 git.tgz
461
Machine Translated by Google
$ git rm git.tgz rm
'git.tgz' $ git commit
-m 'Oops - remove large tarball' [master dadf725] Ups -
remove large tarball 1 archivo cambiado, 0 inserciones
(+), 0 eliminaciones (-) modo de eliminación 100644 git.tgz
$ git gc
Contando objetos: 17, listo.
Compresión delta usando hasta 8 hilos.
Comprimir objetos: 100% (13/13), listo.
Objetos de escritura: 100% (17/17), hecho.
Total 17 (delta 1), reutilizado 10 (delta 0)
Puede ejecutar el comando contar objetos para ver rápidamente cuánto espacio está utilizando:
$ git cuenta-objetos -v
cuenta: 7 tamaño: 32
en paquete:
17 paquetes:
1 tamaño-paquete:
4868 ciruelas pasas:
0 basura: 0 tamaño-
basura: 0
La entrada del paquete de tamaño es el tamaño de sus archivos de paquete en kilobytes, por lo que está usando casi
5 MB. Antes de la última confirmación, estabas usando cerca de 2K; claramente, eliminar el archivo de la confirmación
anterior no lo eliminó de tu historial. Cada vez que alguien clone este repositorio, tendrá que clonar los 5 MB solo para
obtener este pequeño proyecto, porque accidentalmente agregó un archivo grande. Deshagámonos de eso.
Primero tienes que encontrarlo. En este caso, ya sabes qué archivo es. Pero supongamos que no lo hizo; ¿Cómo
identificaría qué archivo o archivos ocupaban tanto espacio? Si ejecuta git gc, todos los objetos están en un archivo
de paquete; puede identificar los objetos grandes ejecutando otro comando de plomería llamado gitcheck-pack y
ordenando el tercer campo en la salida, que es el tamaño del archivo. También puede canalizarlo a través del
comando tail porque solo le interesan los últimos archivos más grandes:
462
Machine Translated by Google
El objeto grande está en la parte inferior: 5 MB. Para averiguar qué archivo es, utilizará el comando rev-list , que
utilizó brevemente en Forzar un formato de mensaje de compromiso específico. Si pasa --objects a rev-list, enumera
todos los SHA-1 confirmados y también los SHA-1 de blob con las rutas de archivo asociadas a ellos. Puedes usar
esto para encontrar el nombre de tu blob:
Ahora, debe eliminar este archivo de todos los árboles en su pasado. Puede ver fácilmente qué confirmaciones
modificaron este archivo:
Debe volver a escribir todas las confirmaciones posteriores a 7b30847 para eliminar por completo este archivo de
su historial de Git. Para hacerlo, usa filter-branch, que usó en Rewrite History:
La opción --index-filter es similar a la opción --tree-filter utilizada en Reescribir el historial, excepto que en lugar de
pasar un comando que modifica los archivos desprotegidos en el disco, está modificando su área de ensayo o índice
cada vez.
En lugar de eliminar un archivo específico con algo como rm file, debe eliminarlo con git rm --cached ; debe eliminarlo
del índice, no del disco. La razón para hacerlo de esta manera es la velocidad, ya que Git no tiene que verificar cada
revisión en el disco antes de ejecutar el filtro, el proceso puede ser mucho, mucho más rápido. Puede realizar la
misma tarea con --tree-filter si lo desea. La opción --ignore-unmatch de git rm le indica que no se produzca un error
si el patrón que está tratando de eliminar no está allí. Finalmente, le pide a filter-branch que reescriba su historial
solo desde la confirmación 7b30847 , porque sabe que ahí es donde comenzó este problema. De lo contrario,
comenzará desde el principio y tardará más tiempo innecesariamente.
Su historial ya no contiene una referencia a ese archivo. Sin embargo, su reflog y un nuevo conjunto de referencias
que Git agregó cuando hizo la rama de filtro en .git/refs/original todavía lo hacen, por lo que debe eliminarlos y luego
volver a empaquetar la base de datos. Debes deshacerte de cualquier cosa que apunte a esas confirmaciones
antiguas antes de volver a empaquetar:
463
Machine Translated by Google
$ rm -Rf .git/refs/original $ rm
-Rf .git/logs/ $ git gc Contar
objetos: 15, listo.
$ git count-objects -v
count: 11 size: 4904 in-
pack: 15 packs: 1 size-
pack: 8 prune-packable:
0 basura: 0 size-garbage:
0
El tamaño del repositorio empaquetado se ha reducido a 8K, que es mucho mejor que 5 MB. Puede ver en
el valor de tamaño que el objeto grande todavía está en sus objetos sueltos, por lo que no se ha ido; pero
no se transferirá en un push o clon posterior, que es lo importante. Si realmente quisiera, podría eliminar el
objeto por completo ejecutando git prune con la opción --expire :
tamaño: 0
en paquete: 15
paquetes: 1
tamaño-paquete:
8 ciruela-empaquetable:
0 basura: 0 tamaño-
basura: 0
Variables de entorno
Git siempre se ejecuta dentro de un shell bash y utiliza una serie de variables de entorno del shell para
determinar cómo se comporta. Ocasionalmente, resulta útil saber cuáles son y cómo se pueden usar para
hacer que Git se comporte de la manera que deseas. Esta no es una lista exhaustiva de todas las variables
de entorno a las que presta atención Git, pero cubriremos las más útiles.
464
Machine Translated by Google
Comportamiento global
Parte del comportamiento general de Git como programa de computadora depende de las variables de entorno.
GIT_EXEC_PATH determina dónde busca Git sus subprogramas (como git-commit, git-diff y otros). Puede verificar la
configuración actual ejecutando git --exec-path.
HOME generalmente no se considera personalizable (muchas otras cosas dependen de él), pero es donde Git busca el
archivo de configuración global. Si desea una instalación de Git verdaderamente portátil, completa con una configuración
global, puede anular HOME en el perfil de shell de Git portátil.
PREFIX es similar, pero para la configuración de todo el sistema. Git busca este archivo en $PREFIX/etc/gitconfig.
GIT_CONFIG_NOSYSTEM, si está configurado, deshabilita el uso del archivo de configuración de todo el sistema. Esto es útil
si la configuración de su sistema está interfiriendo con sus comandos, pero no tiene acceso para cambiarla o eliminarla.
GIT_PAGER controla el programa utilizado para mostrar la salida de varias páginas en la línea de comandos. Si esto no está
configurado, PAGER se utilizará como respaldo.
GIT_EDITOR es el editor que Git lanzará cuando el usuario necesite editar algún texto (un mensaje de confirmación, por
ejemplo). Si no está configurado, se utilizará EDITOR .
Ubicaciones de repositorio
Git usa varias variables de entorno para determinar cómo interactúa con el repositorio actual.
GIT_DIR es la ubicación de la carpeta .git . Si esto no se especifica, Git sube por el árbol de directorios hasta llegar a ~ o /,
buscando un directorio .git en cada paso.
GIT_WORK_TREE es la ubicación de la raíz del directorio de trabajo para un repositorio no vacío. Si se especifica --git -dir o
GIT_DIR pero no se especifica --work-tree, GIT_WORK_TREE o core.worktree , el directorio de trabajo actual se considera el
nivel superior de su árbol de trabajo.
GIT_OBJECT_DIRECTORY se puede usar para especificar la ubicación del directorio que normalmente reside en .git/objects.
GIT_ALTERNATE_OBJECT_DIRECTORIES es una lista separada por dos puntos (formateada como /dir/one:/dir/two:…)
que le dice a Git dónde buscar objetos si no están en GIT_OBJECT_DIRECTORY. Si tiene muchos proyectos con archivos
grandes que tienen exactamente el mismo contenido, esto puede usarse para evitar almacenar demasiadas copias de ellos.
465
Machine Translated by Google
especificaciones de ruta
Una "especificación de ruta" se refiere a cómo especifica las rutas a las cosas en Git, incluido el uso de comodines. Estos se usan en el
archivo .gitignore , pero también en la línea de comandos (git add *.c).
GIT_GLOB_PATHSPECS se establece en 1, los caracteres comodín actúan como comodines (que es el valor predeterminado); si
GIT_NOGLOB_PATHSPECS se establece en 1, los caracteres comodín solo coinciden entre sí, lo que significa que algo como *.c solo
coincidiría con un archivo llamado "\*.c", en lugar de cualquier archivo cuyo nombre termine con .c. Puede anular esto en casos individuales
iniciando pathspec con :(glob) o :(literal), como en :(glob)\*.c.
GIT_LITERAL_PATHSPECS deshabilita los dos comportamientos anteriores; no funcionará ningún carácter comodín, y los prefijos de
GIT_ICASE_PATHSPECS establece que todas las especificaciones de ruta funcionen sin distinguir entre mayúsculas y minúsculas.
cometer
La creación final de un objeto de confirmación de Git generalmente la realiza git-commit-tree, que usa estas variables de entorno como su
principal fuente de información, recurriendo a los valores de configuración solo si estos no están presentes.
EMAIL es la dirección de correo electrónico alternativa en caso de que el valor de configuración de user.email no esté establecido. Si esto no
está configurado, Git recurre al usuario del sistema y los nombres de host.
Redes
Git usa la biblioteca curl para realizar operaciones de red a través de HTTP, por lo que GIT_CURL_VERBOSE le dice a Git que emita todos
los mensajes generados por esa biblioteca. Esto es similar a hacer curl -v en la línea de comandos.
GIT_SSL_NO_VERIFY le dice a Git que no verifique los certificados SSL. Esto a veces puede ser necesario si está utilizando un certificado
autofirmado para servir repositorios Git a través de HTTPS, o si está configurando un servidor Git pero aún no ha instalado un certificado
completo.
Si la velocidad de datos de una operación HTTP es inferior a GIT_HTTP_LOW_SPEED_LIMIT bytes por segundo durante más de
GIT_HTTP_LOW_SPEED_TIME segundos, Git cancelará esa operación. Estos valores anulan los valores de configuración de
http.lowSpeedLimit y http.lowSpeedTime .
466
Machine Translated by Google
GIT_HTTP_USER_AGENT establece la cadena de agente de usuario utilizada por Git cuando se comunica a través de HTTP. El valor
predeterminado es un valor como git/2.0.0.
Diferenciar y fusionar
GIT_DIFF_OPTS es un nombre poco apropiado. Los únicos valores válidos son -u<n> o --unified=<n>, que controla la cantidad de
líneas de contexto que se muestran en un comando git diff .
GIT_EXTERNAL_DIFF se utiliza como anulación del valor de configuración diff.external . Si está configurado, Git invocará este
programa cuando se invoque git diff .
GIT_DIFF_PATH_COUNTER y GIT_DIFF_PATH_TOTAL son útiles desde dentro del programa especificado por GIT_EXTERNAL_DIFF
o diff.external. El primero representa qué archivo de una serie se está diferenciando (empezando por 1), y el último es el número total
de archivos en el lote.
GIT_MERGE_VERBOSITY controla la salida de la estrategia de combinación recursiva. Los valores permitidos son los siguientes:
El valor predeterminado es 2.
depuración
¿Quieres saber realmente qué está haciendo Git? Git tiene un conjunto bastante completo de seguimientos incrustados, y todo lo que
necesita hacer es activarlos. Los posibles valores de estas variables son los siguientes:
• Una ruta absoluta que comience con / : la salida de seguimiento se escribirá en ese archivo.
GIT_TRACE controla las trazas generales, que no encajan en ninguna categoría específica. Esto incluye la expansión de alias y la
delegación a otros subprogramas.
467
Machine Translated by Google
GIT_TRACE_PACK_ACCESS controla el seguimiento del acceso al archivo de paquete. El primer campo es el archivo de paquete que se está
accedido, el segundo es el desplazamiento dentro de ese archivo:
GIT_TRACE_PERFORMANCE controla el registro de datos de rendimiento. La salida muestra cuánto tiempo cada
468
Machine Translated by Google
$ GIT_TRACE_PERFORMANCE=verdadero git gc
20:18:19.499676 trace.c:414 'pack- rendimiento: 0.374835000 s: comando git: 'git'
refs' '--all' '--prune'
20:18:19.845585 trace.c:414 'reflog' rendimiento: 0.343020000 s: comando git: 'git'
'expire' '--all'
Contando objetos: 170994, hecho.
Compresión delta usando hasta 8 hilos.
Comprimir objetos: 100 % (43413/43413), listo.
Objetos de escritura: 100% (170994/170994), hecho.
Total 170994 (delta 126176), reutilizado 170524 (delta 125706)
20:18:23.567927 trace.c:414 'pack- rendimiento: 3.715349000 s: comando git: 'git'
objects' '--keep-true-parents' '--honor-pack-keep' '--non-empty' '--all' '--
reflog' '--unpack-unreachable=2.weeks.ago' '--local' '--delta-base-offset'
'.git/objetos/paquete/.tmp-49190-paquete'
20:18:23.584728 trace.c:414 rendimiento: 0.000910000 s: comando git: 'git'
'empaquetado con ciruela pasa'
20:18:23.605218 trace.c:414 rendimiento: 0.017972000 s: comando git: 'git'
'actualizar información del servidor'
20:18:23.606342 trace.c:414 rendimiento: 3.756312000 s: comando git: 'git'
'reempacar' '-d' '-l' '-A' '--unpack-unreachable=2.weeks.ago'
Comprobando conectividad: 170994, hecho.
20:18:25.225424 trace.c:414 'prune' rendimiento: 1.616423000 s: comando git: 'git'
'--expire' '2.weeks.ago'
20:18:25.232403 trace.c:414 'rerere' rendimiento: 0.001051000 s: comando git: 'git'
'gc'
20:18:25.233159 rastreo.c:414 'gc' rendimiento: 6.112217000 s: comando git: 'git'
GIT_TRACE_SETUP muestra información sobre lo que Git está descubriendo sobre el repositorio y
entorno con el que está interactuando.
Diverso
GIT_SSH, si se especifica, es un programa que se invoca en lugar de ssh cuando Git intenta conectarse a un SSH
anfitrión. Se invoca como $GIT_SSH [nombre de usuario@]host [-p <puerto>] <comando>. Tenga en cuenta que este no es el
forma más fácil de personalizar cómo se invoca ssh ; no admitirá parámetros de línea de comandos adicionales, por lo que
tendría que escribir un script de contenedor y configurar GIT_SSH para señalarlo. Probablemente sea más fácil simplemente usar el
~/.ssh/config archivo para eso.
469
Machine Translated by Google
GIT_ASKPASS es una anulación del valor de configuración de core.askpass . Este es el programa que se invoca cada vez que Git
necesita solicitar las credenciales al usuario, que puede esperar un mensaje de texto como argumento de la línea de comando y
debe devolver la respuesta en la salida estándar (consulte Almacenamiento de credenciales para obtener más información sobre
este subsistema).
GIT_NAMESPACE controla el acceso a las referencias de espacios de nombres y es equivalente a la marca --namespace . Esto
es principalmente útil en el lado del servidor, donde es posible que desee almacenar varias bifurcaciones de un solo repositorio en
un repositorio, manteniendo solo las referencias separadas.
GIT_FLUSH se puede usar para obligar a Git a usar E/S sin búfer al escribir de forma incremental en la salida estándar. Un valor
de 1 hace que Git se vacíe con más frecuencia, un valor de 0 hace que toda la salida se almacene en búfer. El valor predeterminado
(si esta variable no está configurada) es elegir un esquema de almacenamiento en búfer adecuado según la actividad y el modo de
salida.
GIT_REFLOG_ACTION le permite especificar el texto descriptivo escrito en el reflog. Aquí hay un ejemplo:
Resumen
En este punto, debería tener una comprensión bastante buena de lo que hace Git en segundo plano y, hasta cierto punto, cómo se
implementa. Este capítulo ha cubierto varios comandos de plomería, comandos que son de menor nivel y más simples que los
comandos de porcelana que aprendió en el resto del libro. Comprender cómo funciona Git en un nivel inferior debería facilitar la
comprensión de por qué está haciendo lo que está haciendo y también escribir sus propias herramientas y scripts de ayuda para
que su flujo de trabajo específico funcione para usted.
Git como un sistema de archivos direccionable por contenido es una herramienta muy poderosa que puede usar fácilmente como
algo más que un VCS. Esperamos que pueda usar su nuevo conocimiento de las funciones internas de Git para implementar su
propia aplicación genial de esta tecnología y sentirse más cómodo usando Git de formas más avanzadas.
470
Machine Translated by Google
Interfaces gráficas
El entorno nativo de Git está en la terminal. Las nuevas funciones aparecen allí primero, y solo en la línea de comando está
completamente a su disposición todo el poder de Git. Pero el texto sin formato no es la mejor opción para todas las tareas; a
veces lo que necesita es una representación visual, y algunos usuarios se sienten mucho más cómodos con una interfaz de
apuntar y hacer clic.
Es importante tener en cuenta que las diferentes interfaces se adaptan a los diferentes flujos de trabajo. Algunos clientes
exponen solo un subconjunto cuidadosamente seleccionado de la funcionalidad de Git, para admitir una forma específica de
trabajo que el autor considera efectiva. Visto desde este punto de vista, ninguna de estas herramientas puede llamarse "mejor"
que las demás, simplemente son más adecuadas para su propósito previsto. También tenga en cuenta que no hay nada que
estos clientes gráficos puedan hacer que el cliente de línea de comandos no pueda hacer; la línea de comandos sigue siendo
donde tendrá más poder y control cuando trabaje con sus repositorios.
gitk y git-gui
Cuando instalas Git, también obtienes sus herramientas visuales, gitk y git-gui.
gitk es un visor de historial gráfico. Piense en ello como un poderoso shell de GUI sobre git log y git grep.
Esta es la herramienta que debe usar cuando intenta encontrar algo que sucedió en el pasado o visualizar el historial de su
proyecto.
Gitk es más fácil de invocar desde la línea de comandos. Simplemente cd en un repositorio de Git y escriba:
Gitk acepta muchas opciones de línea de comandos, la mayoría de las cuales se pasan a la acción de registro de git
subyacente . Probablemente uno de los más útiles es el indicador --all , que le dice a gitk que muestre confirmaciones
accesibles desde cualquier referencia, no solo HEAD. La interfaz de Gitk se ve así:
471
Machine Translated by Google
En la parte superior hay algo que se parece un poco a la salida de git log --graph; cada punto representa una
confirmación, las líneas representan las relaciones principales y las referencias se muestran como cuadros de colores.
El punto amarillo representa HEAD y el punto rojo representa los cambios que aún no se han confirmado. En la parte
inferior hay una vista de la confirmación seleccionada; los comentarios y el parche a la izquierda, y una vista de resumen
a la derecha. En el medio hay una colección de controles utilizados para buscar en el historial.
git-gui, por otro lado, es principalmente una herramienta para crear compromisos. También es más fácil invocarlo desde
la línea de comandos:
472
Machine Translated by Google
A la izquierda está el índice; los cambios no organizados están en la parte superior, los cambios organizados en la parte inferior. Puede
mover archivos completos entre los dos estados haciendo clic en sus iconos, o puede seleccionar un archivo para verlo haciendo clic en su
nombre.
En la parte superior derecha está la vista de diferencias, que muestra los cambios del archivo seleccionado actualmente. Puede organizar
fragmentos individuales (o líneas individuales) haciendo clic con el botón derecho en esta área.
En la parte inferior derecha está el área de mensajes y acciones. Escriba su mensaje en el cuadro de texto y haga clic en "Confirmar" para
hacer algo similar a git commit. También puede optar por modificar la última confirmación eligiendo el botón de opción "Modificar", que
actualizará el área "Cambios por etapas" con el contenido de la última confirmación. Luego, simplemente puede realizar o cancelar algunos
cambios, modificar el mensaje de confirmación y hacer clic en "Confirmar" nuevamente para reemplazar la confirmación anterior por una
nueva.
gitk y git-gui son ejemplos de herramientas orientadas a tareas. Cada uno de ellos está diseñado para un propósito específico (ver el historial
y crear confirmaciones, respectivamente) y omite las funciones que no son necesarias para esa tarea.
GitHub ha creado dos clientes Git orientados al flujo de trabajo: uno para Windows y otro para macOS. Estos clientes son un buen ejemplo
de herramientas orientadas al flujo de trabajo: en lugar de exponer toda la funcionalidad de Git, se centran en un conjunto seleccionado de
funciones de uso común que funcionan bien juntas. Se ven así:
473
Machine Translated by Google
Están diseñados para verse y funcionar de manera muy similar, por lo que los trataremos como un solo producto en este
capítulo. No vamos a hacer un resumen detallado de estas herramientas (tienen su propia documentación), pero es
necesario un recorrido rápido por la vista de "cambios" (que es donde pasará la mayor parte de su tiempo).
• A la izquierda está la lista de repositorios que el cliente está rastreando; puede agregar un repositorio (ya sea por
clonar o adjuntar localmente) haciendo clic en el ícono "+" en la parte superior de esta área.
• En el centro hay un área de entrada de confirmación, que le permite ingresar un mensaje de confirmación y seleccionar
qué archivos deben incluirse. En Windows, el historial de confirmaciones se muestra directamente debajo de esto; en
474
Machine Translated by Google
• A la derecha hay una vista de diferencias, que muestra lo que ha cambiado en su directorio de trabajo, o qué cambios se incluyeron
en la confirmación seleccionada.
• Lo último que debe notar es el botón "Sincronizar" en la parte superior derecha, que es la forma principal en que
interactuar a través de la red.
No necesita una cuenta de GitHub para usar estas herramientas. Si bien están diseñados para resaltar el servicio
ÿ de GitHub y el flujo de trabajo recomendado, trabajarán felizmente con cualquier repositorio y realizarán
operaciones de red con cualquier host de Git.
Instalación
GitHub para Windows se puede descargar desde https://windows.github.com, y GitHub para macOS desde https://mac.github.com.
Cuando las aplicaciones se ejecutan por primera vez, lo guían a través de toda la configuración de Git por primera vez, como configurar
su nombre y dirección de correo electrónico, y ambos configuran valores predeterminados para muchas opciones de configuración
comunes, como cachés de credenciales y comportamiento CRLF.
Ambos son "siempre verdes": las actualizaciones se descargan e instalan en segundo plano mientras las aplicaciones están abiertas.
Esto incluye una versión integrada de Git, lo que significa que probablemente no tendrá que preocuparse por actualizarlo manualmente
nuevamente. En Windows, el cliente incluye un acceso directo para iniciar PowerShell con Posh-git, del que hablaremos más adelante
en este capítulo.
El siguiente paso es darle a la herramienta algunos repositorios para trabajar. El cliente le muestra una lista de los repositorios a los que
tiene acceso en GitHub y puede clonarlos en un solo paso. Si ya tiene un repositorio local, simplemente arrastre su directorio desde el
Finder o el Explorador de Windows a la ventana del cliente de GitHub y se incluirá en la lista de repositorios de la izquierda.
Una vez que esté instalado y configurado, puede usar el cliente de GitHub para muchas tareas comunes de Git. El flujo de trabajo
previsto para esta herramienta a veces se denomina "Flujo de GitHub". Cubrimos esto con más detalle.
en The GitHub Flow, pero la esencia general es que (a) se comprometerá con una rama, y (b) se sincronizará con un repositorio remoto
con bastante regularidad.
La gestión de sucursales es una de las áreas donde las dos herramientas divergen. En macOS, hay un botón en la parte superior de la
ventana para crear una nueva rama:
En Windows, esto se hace escribiendo el nombre de la nueva sucursal en el widget de cambio de sucursal:
475
Machine Translated by Google
Una vez que se crea su rama, hacer nuevas confirmaciones es bastante sencillo. Realice algunos cambios en su directorio
de trabajo, y cuando cambie a la ventana del cliente de GitHub, le mostrará qué archivos cambiaron. Ingrese un mensaje
de confirmación, seleccione los archivos que desea incluir y haga clic en el botón "Confirmar" (ctrl-enter o ÿ-enter).
La forma principal de interactuar con otros repositorios a través de la red es a través de la función "Sincronizar".
Git internamente tiene operaciones separadas para empujar, buscar, fusionar y reorganizar, pero los clientes de GitHub
las agrupan todas en una función de varios pasos. Esto es lo que sucede cuando haces clic en el botón Sincronizar:
1. git pull --rebase. Si esto falla debido a un conflicto de fusión, recurra a git pull --no-rebase.
2. empujar git.
Esta es la secuencia más común de comandos de red cuando se trabaja con este estilo, por lo que agruparlos en un solo
comando ahorra mucho tiempo.
Resumen
Estas herramientas son muy adecuadas para el flujo de trabajo para el que están diseñadas. Tanto los desarrolladores
como los que no son desarrolladores pueden colaborar en un proyecto en cuestión de minutos, y muchas de las mejores
prácticas para este tipo de flujo de trabajo están integradas en las herramientas. Sin embargo, si su flujo de trabajo es
diferente o desea tener más control sobre cómo y cuándo se realizan las operaciones de red, le recomendamos que utilice
otro cliente o la línea de comandos.
Otras GUI
Hay una serie de otros clientes gráficos de Git, y van desde herramientas especializadas de un solo propósito hasta
aplicaciones que intentan exponer todo lo que Git puede hacer. El sitio web oficial de Git tiene una lista seleccionada de
los clientes más populares en https://git-scm.com/downloads/guis. Una lista más completa está disponible en el sitio wiki
de Git, en https://git.wiki.kernel.org/index.php/Interfaces,_frontends,_and_tools#Graphical_Interfaces .
476
Machine Translated by Google
• Ver diferencias.
• … ¡y más!
Visual Studio Code tiene soporte para git incorporado. Deberá tener instalada la versión 2.0.0 (o posterior) de git.
• La barra de estado de Git (abajo a la izquierda) muestra la rama actual, los indicadores sucios, entrantes y salientes.
confirmaciones salientes.
ÿ Inicializar un repositorio.
ÿ Clonar un repositorio.
ÿ Ver diferencias.
477
Machine Translated by Google
Solicitudes de extracción.
La integración se basa en el cliente git de la línea de comandos y requiere que se instale uno. La documentación oficial está disponible en
https://www.jetbrains.com/help/idea/using-git-integration.html.
• La barra lateral mostrará el estado de git de los archivos y carpetas con una insignia/icono.
• Los archivos y carpetas que están en su archivo .gitignore se desvanecerán en la barra lateral.
• En la barra de estado, puede ver la rama actual de git y cuántas modificaciones tiene
hecha.
• Todos los cambios en un archivo ahora son visibles a través de marcadores en el medianil.
• Puede usar parte de la funcionalidad del cliente git de Sublime Merge desde Sublime Text. Esta
Git en bash
Si es un usuario de Bash, puede aprovechar algunas de las funciones de su shell para que su experiencia con Git sea mucho más
amigable. En realidad, Git incluye complementos para varios shells, pero no está activado de forma predeterminada.
Primero, debe obtener una copia del archivo de finalización del código fuente de la versión de Git que está utilizando. Verifique su versión
escribiendo git version, luego use git checkout tags/vX.YZ, donde vX.YZ corresponde a la versión de Git que está usando. Copie el archivo
contrib/completion/git-completion.bash en algún lugar a mano, como su directorio de inicio, y agréguelo a su .bashrc:
. ~/git-completion.bash
478
Machine Translated by Google
$ git cheque<tab>
… y Bash se autocompletará para finalizar la compra. Esto funciona con todos los subcomandos de Git,
parámetros de la línea de comandos y controles remotos y nombres de referencia cuando corresponda.
También es útil personalizar su indicador para mostrar información sobre el Git del directorio actual
repositorio. Esto puede ser tan simple o complejo como desee, pero generalmente hay algunas piezas clave
de la información que la mayoría de la gente quiere, como la sucursal actual y el estado del trabajo
directorio. Para agregarlos a su aviso, simplemente copie el archivo contrib/completion/git-prompt.sh de
Repositorio fuente de Git a su directorio de inicio, agregue algo como esto a su .bashrc:
. ~/git-prompt.sh
exportar GIT_PS1_SHOWDIRTYSTATE=1
exportar PS1='\w$(__git_ps1 " (%s)")\$ '
Ambos scripts vienen con documentación útil; eche un vistazo a los contenidos de git finish.bash y git-prompt.sh para obtener más
información.
Git en Zsh
Zsh también incluye una biblioteca de finalización de pestañas para Git. Para usarlo, simplemente ejecute autoload -Uz compinit &&
compinit en su .zshrc. La interfaz de Zsh es un poco más poderosa que la de Bash:
$ git che<tab>
verificar-atributo -- mostrar información de gitattributes
check-ref-format: asegúrese de que un nombre de referencia esté bien formado
índice de -- rama de pago o caminos al árbol de trabajo
pago -- copiar archivos del índice al directorio de trabajo
pico de -- encontrar confirmaciones no fusionadas aguas arriba
cereza -- aplicar cambios introducidos por algunas confirmaciones existentes
479
Machine Translated by Google
Las fichas completadas ambiguas no solo se enumeran; tienen descripciones útiles, y puede navegar gráficamente
por la lista presionando repetidamente la pestaña. Esto funciona con los comandos de Git, sus argumentos y los
nombres de las cosas dentro del repositorio (como referencias y controles remotos), así como los nombres de archivo
y todas las demás cosas que Zsh sabe cómo completar con tabulación.
Zsh viene con un marco para obtener información de los sistemas de control de versiones, llamado vcs_info.
Para incluir el nombre de la rama en el indicador del lado derecho, agregue estas líneas a su archivo ~/.zshrc :
Esto da como resultado una visualización de la rama actual en el lado derecho de la ventana del terminal, siempre
que su shell esté dentro de un repositorio de Git. El lado izquierdo también es compatible, por supuesto; simplemente
descomente la asignación a PROMPT. Se parece un poco a esto:
Para obtener más información sobre vcs_info, consulte su documentación en la página del manual de zshcontrib(1) ,
o en línea en http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#Version-Control Information.
En lugar de vcs_info, es posible que prefiera el script de personalización de solicitud que se incluye con Git, llamado
git-prompt.sh; consulte https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh por
480
Machine Translated by Google
Zsh es lo suficientemente poderoso como para que haya marcos completos dedicados a mejorarlo. Uno de ellos
se llama "oh-my-zsh" y se puede encontrar en https://github.com/robbyrussell/oh-my-zsh. El sistema de
complementos de oh-my-zsh viene con un poderoso git tab-completion, y tiene una variedad de "temas" de
solicitud, muchos de los cuales muestran datos de control de versiones. Un ejemplo de un tema oh-my-zsh es
solo un ejemplo de lo que se puede hacer con este sistema.
Git en PowerShell
El terminal de línea de comandos heredado en Windows (cmd.exe) no es realmente capaz de una experiencia
Git personalizada, pero si está usando PowerShell, está de suerte. Esto también funciona si está ejecutando
PowerShell Core en Linux o macOS. Un paquete llamado posh-git (https://github.com/dahlbyk/posh git)
proporciona poderosas funciones de finalización de pestañas, así como un aviso mejorado para ayudarlo a
mantenerse al tanto del estado de su repositorio. Se parece a esto:
Instalación
Antes de que pueda ejecutar secuencias de comandos de PowerShell en su máquina, debe configurar su
ExecutionPolicy local en RemoteSigned (básicamente, cualquier cosa excepto Indefinido y Restringido). Si tu escoges
481
Machine Translated by Google
AllSigned en lugar de RemoteSigned, también los scripts locales (los suyos) deben estar firmados digitalmente para
poder ejecutarse. Con RemoteSigned, solo los scripts que tienen el ZoneIdentifier establecido en Internet (fueron
descargados de la web) deben firmarse, otros no. Si es administrador y desea configurarlo para todos los usuarios
en esa máquina, use -Scope LocalMachine. Si es un usuario normal, sin derechos administrativos, puede usar -Scope
CurrentUser para configurarlo solo para usted.
Para establecer el valor de ExecutionPolicy en RemoteSigned para todos los usuarios, use el siguiente comando:
Galería de PowerShell
Si tiene al menos PowerShell 5 o PowerShell 4 con PackageManagement instalado, puede usar el administrador de
paquetes para instalar posh-git por usted.
Si desea instalar posh-git para todos los usuarios, use -Scope AllUsers en su lugar y ejecute el comando desde una
consola de PowerShell con privilegios elevados. Si el segundo comando falla con un error como Módulo
'PowerShellGet' no se instaló mediante Install-Module, primero deberá ejecutar otro comando:
A continuación, puede volver atrás e intentarlo de nuevo. Esto sucede porque los módulos que se envían con
Windows PowerShell están firmados con un certificado de publicación diferente.
Para incluir información de git en su solicitud, se debe importar el módulo posh-git. Para que se importe Posh Git
cada vez que se inicia PowerShell, ejecute el comando Add-PoshGitToProfile que agregará la declaración de
importación en su secuencia de comandos $profile . Este script se ejecuta cada vez que abre una nueva consola de
PowerShell. Tenga en cuenta que hay varios scripts de $profile . P.ej. uno para la consola y otro separado para el
ISE.
482
Machine Translated by Google
De la fuente
Esto agregará la línea adecuada a su archivo profile.ps1 y posh-git estará activo la próxima vez que abra
PowerShell.
Para obtener una descripción de la información de resumen del estado de Git que se muestra en el aviso,
consulte: https://github.com/dahlbyk/posh-git/blob/master/README.md#git-status-summary-information Para
obtener más detalles sobre cómo personalizar su solicitud de posh-git, consulte: https://github.com/dahlbyk/posh-
git/blob/master/README.md#customization-variables .
Resumen
Aprendió cómo aprovechar el poder de Git desde el interior de las herramientas que usa durante su trabajo diario
y también cómo acceder a los repositorios de Git desde sus propios programas.
483
Machine Translated by Google
Si necesita integrar Git con su aplicación, básicamente tiene dos opciones: generar un shell y llamar al programa de línea
de comandos de git , o incrustar una biblioteca de Git en su aplicación. Aquí cubriremos la integración de la línea de
comandos y varias de las bibliotecas Git integrables más populares.
Una opción es generar un proceso de shell y usar la herramienta de línea de comandos de Git para hacer el trabajo. Esto
tiene la ventaja de ser canónico y todas las características de Git son compatibles. Esto también resulta bastante fácil,
ya que la mayoría de los entornos de tiempo de ejecución tienen una función relativamente simple para invocar un
proceso con argumentos de línea de comandos. Sin embargo, este enfoque tiene algunas desventajas.
Una es que toda la salida está en texto sin formato. Esto significa que tendrá que analizar el formato de salida que
cambia ocasionalmente de Git para leer el progreso y la información de resultados, lo que puede ser ineficiente y
propenso a errores.
Otro es la falta de recuperación de errores. Si un repositorio está dañado de alguna manera, o si el usuario tiene un valor
de configuración incorrecto, Git simplemente se negará a realizar muchas operaciones.
Otro más es la gestión de procesos. Git requiere que mantengas un entorno de shell en un proceso separado, lo que
puede agregar una complejidad no deseada. Tratar de coordinar muchos de estos procesos (especialmente cuando se
accede potencialmente al mismo repositorio desde varios procesos) puede ser todo un desafío.
libgit2
Otra opción a tu disposición es usar Libgit2. Libgit2 es una implementación de Git sin dependencias, con un enfoque en
tener una buena API para usar dentro de otros programas. Puede encontrarlo en https://libgit2.org.
484
Machine Translated by Google
// Abrir un repositorio
git_repository *repo; int
error = git_repository_open(&repo, "/ruta/al/repositorio");
// Limpiar
git_commit_free(commit);
git_repository_free(repositorio);
El primer par de líneas abre un repositorio de Git. El tipo git_repository representa un identificador de un repositorio con un
caché en la memoria. Este es el método más simple, para cuando conoce la ruta exacta al directorio de trabajo o carpeta .git
de un repositorio. También está el git_repository_open_ext que incluye opciones para buscar, git_clone y amigos para hacer
un clon local de un repositorio remoto y git_repository_init para crear un repositorio completamente nuevo.
El segundo fragmento de código usa la sintaxis rev-parse (consulte Referencias de sucursales para obtener más información
sobre esto) para obtener la confirmación a la que finalmente apunta HEAD. El tipo devuelto es un puntero git_object , que
representa algo que existe en la base de datos de objetos de Git para un repositorio. git_object es en realidad un tipo
"principal" para varios tipos diferentes de objetos; el diseño de la memoria para cada uno de los tipos "secundarios" es el
mismo que para git_object, por lo que puede enviar con seguridad al correcto. En este caso, git_object_type(commit)
devolvería GIT_OBJ_COMMIT, por lo que es seguro convertirlo en un puntero de git_commit .
El siguiente fragmento muestra cómo acceder a las propiedades de la confirmación. La última línea aquí usa un tipo git_oid ;
esta es la representación de Libgit2 para un hash SHA-1.
• Si declara un puntero y pasa una referencia a él en una llamada de Libgit2, esa llamada probablemente
devolver un código de error entero. Un valor 0 indica éxito; cualquier cosa menos es un error.
• Si Libgit2 devuelve un puntero const de una llamada, no tiene que liberarlo, pero dejará de ser válido
cuando el objeto al que pertenece es liberado.
Eso último significa que no es muy probable que esté escribiendo C cuando use Libgit2. Afortunadamente, hay varios
enlaces específicos del idioma disponibles que facilitan bastante el trabajo con los repositorios de Git desde su idioma y
entorno específicos. Echemos un vistazo al ejemplo anterior escrito con los enlaces de Ruby para Libgit2, que se denominan
Rugged y se pueden encontrar en
485
Machine Translated by Google
https://github.com/libgit2/rugged.
repo = Rugged::Repository.new('ruta/al/repositorio')
commit = repo.head.target puts commit.message puts
"#{commit.author[:name]} <#{commit.author[:email] }>"
árbol = cometer.árbol
Como puede ver, el código está mucho menos desordenado. En primer lugar, Rugged usa excepciones; puede generar
cosas como ConfigError u ObjectError para indicar condiciones de error. En segundo lugar, no hay una liberación explícita de
recursos, ya que Ruby se recolecta como basura. Echemos un vistazo a un ejemplo un poco más complicado: crear un
compromiso desde cero
index = repo.index
index.read_tree(repo.head.target.tree)
index.add(:path => 'newfile.txt', :oid => blob_id) ÿ
sig =
{ :email => "bob@example.com", :name
=> "Usuario Bob", :time =>
Time.now, }
ÿ Rellene el índice con el árbol de confirmación principal y agregue el nuevo archivo en la ruta newfile.txt.
ÿ El mensaje de confirmación.
ÿ Al crear una confirmación, debe especificar los padres de la nueva confirmación. Esto usa la punta de
HEAD para el padre soltero.
ÿ Rugged (y Libgit2) pueden actualizar opcionalmente una referencia al realizar una confirmación.
ÿ El valor devuelto es el hash SHA-1 de un nuevo objeto de confirmación, que luego puede usar para obtener un
Objeto de compromiso .
486
Machine Translated by Google
El código de Ruby es agradable y limpio, pero dado que Libgit2 está haciendo el trabajo pesado, este código también se ejecutará bastante
Funcionalidad avanzada
Libgit2 tiene un par de capacidades que están fuera del alcance del núcleo de Git. Un ejemplo es la capacidad de conexión: Libgit2 le permite
proporcionar "backends" personalizados para varios tipos de operaciones, por lo que puede almacenar cosas de una manera diferente a como
lo hace Git estándar. Libgit2 permite backends personalizados para la configuración, el almacenamiento de referencias y la base de datos de
Echemos un vistazo a cómo funciona esto. El siguiente código se tomó prestado del conjunto de ejemplos de back-end proporcionados por el
git_odb *odb;
int error = git_odb_new(&odb); ÿ
git_odb_backend *mi_backend;
error = git_odb_backend_mine(&my_backend, /*…*/); ÿ
git_repository *
repositorio; error = git_repository_open(&repo, "alguna
ruta"); error = git_repository_set_odb(repositorio, odb); ÿ
Tenga en cuenta que los errores se capturan, pero no se controlan. Esperamos que su código sea mejor que el nuestro.
ÿ Inicialice una "frontend" de base de datos de objetos vacía (ODB), que actuará como un contenedor para el
ÿ Abra un repositorio y configúrelo para usar nuestro ODB para buscar objetos.
Pero, ¿qué es esto de git_odb_backend_mine ? Bueno, ese es el constructor para su propia implementación de ODB, y puede hacer lo que
quiera allí, siempre que complete la estructura git_odb_backend correctamente. Así es como podría verse:
487
Machine Translated by Google
estructura typedef
{ git_odb_backend padre;
backend->contexto_personalizado = …;
devolver GIT_ÉXITO; }
La restricción más sutil aquí es que el primer miembro de my_backend_struct debe ser una estructura
`git_odb_backend; esto asegura que el diseño de la memoria sea lo que el código Libgit2 espera que sea. El
resto es arbitrario; esta estructura puede ser tan grande o pequeña como necesites que sea.
La función de inicialización asigna algo de memoria para la estructura, configura el contexto personalizado y
luego completa los miembros de la estructura principal que admite. Eche un vistazo al archivo include/git2/sys/
odb_backend.h en el código fuente de Libgit2 para obtener un conjunto completo de firmas de llamada; su caso
de uso particular ayudará a determinar cuál de estos querrá admitir.
Otras encuadernaciones
Libgit2 tiene enlaces para muchos idiomas. Aquí mostramos un pequeño ejemplo utilizando algunos de los
paquetes de enlaces más completos a partir de este escrito; existen bibliotecas para muchos otros lenguajes,
incluidos C++, Go, Node.js, Erlang y JVM, todos en diversas etapas de madurez. La colección oficial de enlaces
se puede encontrar navegando por los repositorios en https://github.com/libgit2. El código que escribiremos
devolverá el mensaje de confirmación de la confirmación señalada eventualmente por HEAD (algo así como git
log -1).
LibGit2Sharp
488
Machine Translated by Google
new Repository(@"C:\path\to\repo").Head.Tip.Message;
Para las aplicaciones de escritorio de Windows, incluso hay un paquete NuGet que lo ayudará a comenzar rápidamente.
objetivo-git
Si su aplicación se ejecuta en una plataforma Apple, es probable que esté utilizando Objective-C como lenguaje de
implementación. Objetivo-Git (https://github.com/libgit2/objective-git) es el nombre de los enlaces Libgit2 para ese entorno.
El programa de ejemplo se ve así:
GTRepositorio *repo =
[[GTRepository alloc] initWithURL:[NSURL fileURLWithPath: @"/path/to/repo"] error:NULL];
Objective-git es totalmente interoperable con Swift, así que no temas si te has olvidado de Objective-C.
pygit2
Los enlaces para Libgit2 en Python se denominan Pygit2 y se pueden encontrar en https://www.pygit2.org.
Nuestro programa de ejemplo:
.mensaje
Otras lecturas
Por supuesto, un tratamiento completo de las capacidades de Libgit2 está fuera del alcance de este libro. Si desea
obtener más información sobre Libgit2, hay documentación de API en https://libgit2.github.com/libgit2, y un conjunto de
guías en https://libgit2.github.com/docs. Para los otros enlaces, consulte el LÉAME y las pruebas incluidas; a menudo hay
pequeños tutoriales y consejos para leer más allí.
JGit
Si desea utilizar Git desde un programa Java, hay una biblioteca de Git con todas las funciones llamada JGit.
JGit es una implementación relativamente completa de Git escrita de forma nativa en Java y se usa ampliamente en la
comunidad de Java. El proyecto JGit está bajo el paraguas de Eclipse, y su hogar se puede encontrar en https://
www.eclipse.org/jgit/.
Preparándose
Hay varias formas de conectar su proyecto con JGit y comenzar a escribir código en él.
Probablemente lo más fácil sea usar Maven: la integración se logra agregando lo siguiente
489
Machine Translated by Google
<dependencia>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>3.5.0.201409260305-r</version> </
dependency>
Lo más probable es que la versión haya avanzado para cuando lea esto; consulte https://mvnrepository.com/artifact/org.eclipse.jgit/
por automáticamente
org.eclipse.jgit información del repositorio. Una vez realizado este paso, Maven adquirirá y utilizará actualizado las bibliotecas
que necesitará.
JGit
Si prefiere administrar las dependencias binarias usted mismo, los binarios JGit preconstruidos están disponibles en https://www.eclipse.org/
jgit/download. Puede incorporarlos a su proyecto ejecutando un comando como este:
Plomería
JGit tiene dos niveles básicos de API: plomería y porcelana. La terminología para estos proviene de Git mismo, y JGit se divide
aproximadamente en los mismos tipos de áreas: las API de porcelana son una interfaz fácil de usar para acciones comunes a nivel de
usuario (el tipo de cosas que un usuario normal usaría la herramienta de línea de comandos de Git para ), mientras que las API de
plomería son para interactuar directamente con objetos de repositorio de bajo nivel.
El punto de partida para la mayoría de las sesiones de JGit es la clase Repository , y lo primero que querrá hacer es crear una instancia
de ella. Para un repositorio basado en un sistema de archivos (sí, JGit permite otros modelos de almacenamiento), esto se logra usando
FileRepositoryBuilder:
El constructor tiene una API fluida para proporcionar todo lo que necesita para encontrar un repositorio de Git, ya sea que su programa
sepa exactamente dónde se encuentra o no. Puede usar variables de entorno (.readEnvironment()), comenzar desde un lugar en el
directorio de trabajo y buscar (.setWorkTree(…).findGitDir()), o simplemente abrir un directorio .git conocido como se indicó anteriormente.
Una vez que tenga una instancia de repositorio , puede hacer todo tipo de cosas con ella. Aquí hay una muestra rápida:
490
Machine Translated by Google
// Obtener una
referencia Ref master = repo.getRef("master");
// Rev-parse
ObjectId obj = repo.resolve("HEAD^{tree}");
//
Configuración Configuración cfg =
repo.getConfig(); Nombre de cadena = cfg.getString("usuario", nulo, "nombre");
Están sucediendo muchas cosas aquí, así que repasemos una sección a la vez.
La primera línea obtiene un puntero a la referencia maestra . JGit toma automáticamente la referencia maestra real ,
que se encuentra en refs/heads/master, y devuelve un objeto que le permite obtener información sobre la referencia.
Puede obtener el nombre (.getName()) y el objeto de destino de una referencia directa (.getObjectId()) o la referencia a
la que apunta una referencia simbólica (.getTarget()). Los objetos de referencia también se utilizan para representar
objetos y referencias de etiqueta, por lo que puede preguntar si la etiqueta está "pelada", lo que significa que apunta al
destino final de una cadena (potencialmente larga) de objetos de etiqueta.
La segunda línea obtiene el destino de la referencia maestra , que se devuelve como una instancia de ObjectId.
ObjectId representa el hash SHA-1 de un objeto, que puede o no existir en la base de datos de objetos de Git. La tercera
línea es similar, pero muestra cómo JGit maneja la sintaxis rev-parse (para obtener más información, consulte
Referencias de sucursales); puede pasar cualquier especificador de objeto que Git entienda, y JGit devolverá un ObjectId
válido para ese objeto o nulo.
Las siguientes dos líneas muestran cómo cargar el contenido sin procesar de un objeto. En este ejemplo, llamamos a
ObjectLoader.copyTo() para transmitir el contenido del objeto directamente a la salida estándar, pero ObjectLoader
también tiene métodos para leer el tipo y el tamaño de un objeto, así como devolverlo como una matriz de bytes. Para
objetos grandes (donde .isLarge() devuelve verdadero), puede llamar a .openStream() para obtener un objeto similar a
InputStream que pueda leer los datos del objeto sin procesar sin extraerlo todo a la memoria a la vez.
Las siguientes líneas muestran lo que se necesita para crear una nueva rama. Creamos una instancia RefUpdate,
491
Machine Translated by Google
configure algunos parámetros y llame a .update() para activar el cambio. Inmediatamente después de esto está el
código para eliminar esa misma rama. Tenga en cuenta que se requiere .setForceUpdate(true) para que esto
funcione; de lo contrario, la llamada .delete() devolverá REJECTED y no pasará nada.
El último ejemplo muestra cómo obtener el valor de nombre de usuario de los archivos de configuración de Git. Esta
instancia de Config usa el repositorio que abrimos anteriormente para la configuración local, pero detectará
automáticamente los archivos de configuración global y del sistema y también leerá los valores de ellos.
Esta es solo una pequeña muestra de la API de plomería completa; hay muchos más métodos y clases disponibles.
Tampoco se muestra aquí la forma en que JGit maneja los errores, que es mediante el uso de excepciones. Las API
de JGit a veces arrojan excepciones estándar de Java (como IOException), pero también se proporcionan una gran
cantidad de tipos de excepción específicos de JGit (como NoRemoteRepositoryException, CorruptObjectException y
NoMergeBaseException).
Porcelana
Las API de plomería son bastante completas, pero puede ser engorroso unirlas para lograr objetivos comunes, como
agregar un archivo al índice o realizar una nueva confirmación. JGit proporciona un conjunto de API de nivel superior
para ayudar con esto, y el punto de entrada a estas API es la clase Git :
repositorio de
repositorio; // construir repositorio...
Git git = nuevo Git (repositorio);
La clase Git tiene un buen conjunto de métodos de estilo constructor de alto nivel que se pueden usar para construir
un comportamiento bastante complejo. Echemos un vistazo a un ejemplo: hacer algo como git ls-remote:
" "
-> + ref.getObjectId().nombre());
Este es un patrón común con la clase Git; los métodos devuelven un objeto de comando que le permite encadenar
llamadas a métodos para establecer parámetros, que se ejecutan cuando llama a .call(). En este caso, le estamos
pidiendo etiquetas al control remoto de origen , pero no cabezas. Observe también el uso de un objeto
CredentialsProvider para la autenticación.
Muchos otros comandos están disponibles a través de la clase Git, incluidos, entre otros , agregar, culpar, confirmar,
limpiar, empujar, reorganizar, revertir y restablecer.
492
Machine Translated by Google
Otras lecturas
Esta es solo una pequeña muestra de las capacidades completas de JGit. Si está interesado y desea obtener más información,
aquí es donde puede buscar información e inspiración:
• El libro de cocina JGit en https://github.com/centic9/jgit-cookbook tiene muchos ejemplos de cómo hacer tareas específicas
con JGit.
go-git
En caso de que desee integrar Git en un servicio escrito en Golang, también existe una implementación de biblioteca Go pura.
Esta implementación no tiene dependencias nativas y, por lo tanto, no es propensa a errores de administración de memoria
manual. También es transparente para las herramientas de análisis de rendimiento estándar de Golang, como CPU, perfiladores
de memoria, detectores de carrera, etc.
go-git se centra en la extensibilidad, la compatibilidad y es compatible con la mayoría de las API de fontanería, que se
documenta en https://github.com/go-git/go-git/blob/master/COMPATIBILITY.md.
importar "github.com/go-git/go-git/v5"
Tan pronto como tenga una instancia de Repositorio , puede acceder a la información y realizar mutaciones en ella:
// recupera el historial de
confirmación, err := commit.History()
493
Machine Translated by Google
Funcionalidad avanzada
go-git tiene algunas características avanzadas notables, una de las cuales es un sistema de almacenamiento conectable, que es
similar a los backends de Libgit2. La implementación predeterminada es el almacenamiento en memoria, que es muy rápido.
Otra característica es una abstracción flexible del sistema de archivos. Usando https://pkg.go.dev/github.com/go-git/go billy/v5?
tab=doc#Filesystem es fácil almacenar todos los archivos de forma diferente, es decir, empaquetándolos en un solo archivo en
el disco o manteniéndolos todos en la memoria.
Otro caso de uso avanzado incluye un cliente HTTP ajustable, como el que se encuentra en https://github.com/go-git/go-git/blob/
master/_examples/custom_http/main.go.
customClient :=
&http.Client{ Transport: &http.Transport{ // acepta cualquier certificado (puede ser útil para
realizar pruebas)
ÿ
Otras lecturas
Un tratamiento completo de las capacidades de go-git está fuera del alcance de este libro. Si desea obtener más información
sobre go-git, hay documentación de API en https://pkg.go.dev/github.com/go-git/go-git/v5, y un conjunto de ejemplos de uso en
https://github.com/go-git/go-git/tree/master/_examples.
Dulwich
También hay una implementación pura de Python Git: Dulwich. El proyecto está alojado en https://www.dulwich.io/ Su objetivo
es proporcionar una interfaz para los repositorios de git (tanto locales como remotos)
494
Machine Translated by Google
eso no llama a git directamente, sino que usa Python puro. Sin embargo, tiene extensiones C opcionales que mejoran
significativamente el rendimiento.
Dulwich sigue el diseño de git y separa dos niveles básicos de API: plomería y porcelana.
Aquí hay un ejemplo del uso de la API de nivel inferior para acceder al mensaje de confirmación de la última confirmación:
'57fbe010446356833a6ad1600059d80b1e731e15'
c = r[r.cabeza()]
C
# <Compromiso 015fc1267258458901a94d228e39f0a378370466>
c.message
# 'Agregar nota sobre la codificación.\n'
Para imprimir un registro de compromiso usando la API de porcelana de alto nivel, se puede usar:
Otras lecturas
La documentación de la API, el tutorial y muchos ejemplos de cómo realizar tareas específicas con Dulwich están disponibles
en el sitio web oficial https://www.dulwich.io.
495
Machine Translated by Google
En este apéndice, repasaremos todos los comandos de Git que abordamos a lo largo del libro, agrupados aproximadamente según
su uso. Hablaremos sobre lo que hace cada comando en general y luego indicaremos en qué parte del libro puede encontrarnos
usándolo.
Puede abreviar opciones largas. Por ejemplo, puede escribir git commit --a, que actúa como si hubiera escrito
ÿ git commit --amend. Esto solo funciona cuando las letras después de -- son únicas para una opción. Utilice la
opción completa al escribir guiones.
Instalación y configuración
Hay dos comandos que se usan bastante, desde las primeras invocaciones de Git hasta los ajustes y referencias comunes todos los
días, los comandos config y help .
configuración de git
Git tiene una forma predeterminada de hacer cientos de cosas. Para muchas de estas cosas, puede decirle a Git que las haga de
forma predeterminada de una manera diferente, o establecer sus preferencias. Esto implica todo, desde decirle a Git cuál es su
nombre hasta preferencias específicas de color de terminal o qué editor usa. Hay varios archivos de los que este comando leerá y
escribirá para que pueda establecer valores globalmente o en repositorios específicos.
El comando git config se ha utilizado en casi todos los capítulos del libro.
En la primera configuración de Git , lo usamos para especificar nuestro nombre, dirección de correo electrónico y preferencia de
editor incluso antes de comenzar a usar Git.
En Git Aliases , mostramos cómo puede usarlo para crear comandos abreviados que se expanden a secuencias de opciones largas
para que no tenga que escribirlos cada vez.
En Rebasing lo usamos para hacer que --rebase sea el predeterminado cuando ejecutas git pull.
En Credential Storage lo usamos para configurar un almacén predeterminado para sus contraseñas HTTP.
En Expansión de palabras clave mostramos cómo configurar filtros de limpieza y difuminado en el contenido que entra y sale de Git.
496
Machine Translated by Google
BBEdit (Mac, con comando git config --global core.editor "bbedit -w"
herramientas de línea)
Sublime Text (Windows de 64 bits) git config --global core.editor "'C:\Archivos de programa\Sublime
Texto 3\sublime_text.exe' -w" (También vea la nota a continuación)
Edición de texto (macOS) git config --global core.editor "abrir --wait-apps --new -e"
Panel de texto (Windows de 64 bits) git config --global core.editor "'C:\Archivos de programa\TextPad
5\TextPad.exe' -m (También vea la nota a continuación)
código VSC)
497
Machine Translated by Google
ayuda
El comando de ayuda de git se usa para mostrarle toda la documentación enviada con Git sobre cualquier comando. Si
bien brindamos una descripción general aproximada de la mayoría de los más populares en este apéndice, para obtener
una lista completa de todas las opciones e indicadores posibles para cada comando, siempre puede ejecutar git help
<comando>.
Presentamos el comando de ayuda de git en Obtención de ayuda y le mostramos cómo usarlo para encontrar más
información sobre el shell de git en Configuración del servidor.
iniciar git
Para tomar un directorio y convertirlo en un nuevo repositorio de Git para que pueda comenzar a controlarlo, simplemente
puede ejecutar git init.
Primero presentamos esto en Obtención de un repositorio Git, donde mostramos la creación de un nuevo repositorio para
comenzar a trabajar.
Hablamos brevemente sobre cómo puede cambiar el nombre de sucursal predeterminado de "maestro" en sucursales
remotas.
Usamos este comando para crear un repositorio básico vacío para un servidor en Colocación del repositorio básico en
un servidor.
Finalmente, analizamos algunos de los detalles de lo que realmente hace detrás de escena en Plomería y porcelana.
clonar
El comando git clone es en realidad una especie de envoltorio alrededor de varios otros comandos. Crea un nuevo
directorio, entra en él y ejecuta git init para convertirlo en un repositorio Git vacío, agrega un control remoto (git remote
add) a la URL que le pasas (de forma predeterminada con el nombre de origen), ejecuta un git fetch desde ese control
remoto repository y luego verifica la última confirmación en su directorio de trabajo con git checkout.
El comando git clone se usa en docenas de lugares a lo largo del libro, pero solo mencionaremos algunos lugares
interesantes.
Básicamente se presenta y explica en Clonación de un repositorio existente, donde analizamos algunos ejemplos.
En Obtención de Git en un servidor , analizamos el uso de la opción --bare para crear una copia de un repositorio de Git
sin un directorio de trabajo.
498
Machine Translated by Google
Finalmente, en Clonación de un proyecto con submódulos aprendemos la opción --recurse-submodules para simplificar un poco la
clonación de un repositorio con submódulos.
Aunque se usa en muchos otros lugares a lo largo del libro, estos son los que son algo únicos o donde se usa de maneras un poco
diferentes.
Instantáneas básicas
Para el flujo de trabajo básico de preparar contenido y enviarlo a su historial, solo hay unos pocos comandos básicos.
añadir
El comando git add agrega contenido del directorio de trabajo al área de preparación (o "índice") para la próxima confirmación. Cuando
se ejecuta el comando git commit , de forma predeterminada solo mira esta área de preparación, por lo que git add se usa para crear
exactamente cómo le gustaría que se viera su próxima instantánea de confirmación.
Este comando es increíblemente importante en Git y se menciona o se usa docenas de veces en este libro. Cubriremos rápidamente
algunos de los usos únicos que se pueden encontrar.
Mencionamos cómo usarlo para resolver conflictos de combinación en Conflictos básicos de combinación.
Repasamos su uso para organizar de forma interactiva solo partes específicas de un archivo modificado en la puesta en escena interactiva.
Finalmente, lo emulamos a un nivel bajo en Tree Objects, para que pueda tener una idea de lo que está haciendo detrás de escena.
estado de Git
El comando de estado de git le mostrará los diferentes estados de los archivos en su directorio de trabajo y área de ensayo. Qué archivos
están modificados y sin preparar y cuáles están preparados pero aún no confirmados. En su forma normal, también le mostrará algunos
consejos básicos sobre cómo mover archivos entre estas etapas.
Primero cubrimos el estado en Verificación del estado de sus archivos, tanto en su forma básica como simplificada.
Si bien lo usamos a lo largo del libro, prácticamente todo lo que puede hacer con el comando git status se cubre allí.
diferencia de git
El comando git diff se usa cuando desea ver las diferencias entre dos árboles cualesquiera. Esta podría ser la diferencia entre su entorno
de trabajo y su área de preparación (git diff por sí mismo), entre su área de preparación y su última confirmación (git diff --staged), o entre
dos confirmaciones (git diff master branchB).
Primero observamos los usos básicos de git diff en Visualización de los cambios preparados y no preparados, donde mostramos cómo
ver qué cambios están preparados y cuáles aún no.
Lo usamos para buscar posibles problemas de espacios en blanco antes de confirmar con la opción --check en
499
Machine Translated by Google
Directrices de compromiso.
Vemos cómo verificar las diferencias entre ramas de manera más efectiva con la sintaxis git diff A…B en Determinar lo que se
introduce.
Lo usamos para filtrar las diferencias de espacios en blanco con -b y cómo comparar diferentes etapas de archivos en conflicto con
--theirs, --ours y --base en Advanced Merging.
Finalmente, lo usamos para comparar efectivamente los cambios de submódulos con --submodule en Comenzar con submódulos.
El comando git difftool simplemente inicia una herramienta externa para mostrarle la diferencia entre dos árboles en caso de que
quiera usar algo que no sea el comando git diff incorporado.
git cometer
El comando git commit toma todo el contenido del archivo que se ha preparado con git add y registra una nueva instantánea
permanente en la base de datos y luego mueve el puntero de la rama actual hacia ella.
En primer lugar, cubrimos los aspectos básicos de la confirmación en Confirmar los cambios. Allí también demostramos cómo usar
el indicador -a para omitir el paso de agregar git en los flujos de trabajo diarios y cómo usar el indicador -m para pasar un mensaje
de confirmación en la línea de comando en lugar de iniciar un editor.
En Deshacer cosas , cubrimos el uso de la opción --amend para rehacer la confirmación más reciente.
En Branches in a Nutshell, entramos en muchos más detalles sobre lo que hace git commit y por qué lo hace así.
Finalmente, echamos un vistazo a lo que hace el comando git commit en segundo plano y cómo se implementa realmente en
Commit Objects.
reiniciar
El comando git reset se usa principalmente para deshacer cosas, como puede ver por el verbo. Se mueve alrededor del puntero
HEAD y opcionalmente cambia el índice o el área de preparación y también puede cambiar opcionalmente el directorio de trabajo si
usa --hard. Esta última opción hace posible que este comando pierda su trabajo si se usa incorrectamente, así que asegúrese de
entenderlo antes de usarlo.
Primero cubrimos de manera efectiva el uso más simple de git reset en Unstaging a Staged File, donde lo usamos para eliminar un
archivo en el que habíamos ejecutado git add on.
Luego lo cubrimos con bastante detalle en Reset Demystified, que está enteramente dedicado a explicar este comando.
500
Machine Translated by Google
Usamos git reset --hard para abortar una fusión en Aborting a Merge, donde también usamos git merge --abort, que es una
especie de envoltorio para el comando git reset .
git rm
El comando git rm se usa para eliminar archivos del área de preparación y el directorio de trabajo de Git. Es similar a git add en
el sentido de que organiza la eliminación de un archivo para la próxima confirmación.
Cubrimos el comando git rm con cierto detalle en Eliminación de archivos, incluida la eliminación recursiva de archivos y solo la
eliminación de archivos del área de ensayo, pero dejándolos en el directorio de trabajo con --cached.
El único otro uso diferente de git rm en el libro es en Eliminación de objetos , donde usamos y explicamos brevemente --ignore-
unmatch al ejecutar git filter-branch, que simplemente hace que no se produzca un error cuando el archivo que estamos tratando
de eliminar no no existe Esto puede ser útil para propósitos de secuencias de comandos.
git mv
El comando git mv es un comando práctico para mover un archivo y luego ejecutar git add en el archivo nuevo y git rm en el
archivo anterior.
limpiar
El comando git clean se usa para eliminar archivos no deseados de su directorio de trabajo. Esto podría incluir la eliminación de
artefactos de compilación temporales o la combinación de archivos en conflicto.
Cubrimos muchas de las opciones y escenarios en los que podría usar el comando de limpieza en Limpieza de su directorio de
trabajo.
Ramificación y fusión
Solo hay un puñado de comandos que implementan la mayor parte de la funcionalidad de bifurcación y fusión en Git.
rama git
El comando git branch es en realidad algo así como una herramienta de administración de sucursales. Puede enumerar las
sucursales que tiene, crear una nueva sucursal, eliminar sucursales y cambiar el nombre de las sucursales.
La mayor parte de Git Branching está dedicada al comando branch y se usa a lo largo de todo el capítulo. Primero lo presentamos
en Creación de una nueva sucursal y revisamos la mayoría de sus otras funciones (listado y eliminación) en Administración de
sucursales.
En Ramas de seguimiento , usamos la opción git branch -u para configurar una rama de seguimiento.
501
Machine Translated by Google
pago git
El comando git checkout se usa para cambiar de rama y ver el contenido en su directorio de trabajo.
Primero encontramos el comando en Switching Branches junto con el comando git branch .
Vemos cómo usarlo para comenzar a rastrear sucursales con el indicador --track en Seguimiento de sucursales.
Entramos en detalles más detallados sobre su relación con git reset en Reset Demystified.
combinación de git
La herramienta de fusión de git se usa para fusionar una o más ramas en la rama que ha retirado. Luego avanzará la rama actual al
resultado de la fusión.
El comando git merge se introdujo por primera vez en Basic Branching. Aunque se usa en varios lugares del libro, hay muy pocas
variaciones del comando fusionar ; generalmente, simplemente git merge <branch> con el nombre de la única rama que desea fusionar.
Cubrimos cómo hacer una combinación aplastada (donde Git combina el trabajo pero finge que es solo una nueva confirmación sin
registrar el historial de la rama en la que se está fusionando) al final de Forked Public Project.
Hablamos mucho sobre el proceso y el comando de combinación, incluido el comando -Xignore-space-change y el indicador --abort
para cancelar una combinación problemática en Advanced Merging.
Aprendimos cómo verificar las firmas antes de fusionarlas si su proyecto utiliza GPG en Signing Commits.
El comando git mergetool simplemente inicia un asistente de combinación externo en caso de que tenga problemas con una
combinación en Git.
Lo mencionamos rápidamente en Conflictos básicos de combinación y detallamos cómo implementar su propia herramienta de
combinación externa en Herramientas de comparación y combinación externa.
registro de git
El comando git log se usa para mostrar el historial registrado accesible de un proyecto desde la instantánea de confirmación más
reciente hacia atrás. De forma predeterminada, solo mostrará el historial de la rama en la que se encuentra actualmente, pero se le
pueden asignar cabezas o ramas diferentes o incluso múltiples desde las que atravesar.
También se usa a menudo para mostrar las diferencias entre dos o más ramas en el nivel de confirmación.
502
Machine Translated by Google
Este comando se usa en casi todos los capítulos del libro para demostrar la historia de un proyecto.
Presentamos el comando y lo cubrimos con cierta profundidad en Visualización del historial de confirmaciones. Allí miramos la
opción -p y --stat para tener una idea de lo que se introdujo en cada confirmación y las opciones --pretty y --oneline para ver el
historial de manera más concisa, junto con algunas opciones simples de filtrado de fecha y autor.
En la creación de una nueva rama , lo usamos con la opción --decorate para visualizar fácilmente dónde se encuentran nuestros
punteros de rama y también usamos la opción --graph para ver cómo se ven las historias divergentes.
En Private Small Team y Commit Ranges cubrimos la sintaxis branchA..branchB para usar el comando git log para ver qué
confirmaciones son únicas para una rama en relación con otra rama. En Commit Ranges analizamos esto de manera bastante
extensa.
En Merge Log y Triple Dot cubrimos el uso del formato branchA…branchB y la sintaxis --left-right para ver qué hay en una rama o
en la otra pero no en ambas. En Merge Log también vemos cómo usar la opción --merge para ayudar con la depuración de conflictos
de fusión, así como el uso de la opción --cc para ver los conflictos de confirmación de fusión en su historial.
En RefLog Shortnames , usamos la opción -g para ver el registro de referencia de Git a través de esta herramienta en lugar de
realizar un cruce de ramas.
En Búsqueda , analizamos el uso de las opciones -S y -L para realizar búsquedas bastante sofisticadas de algo que sucedió
históricamente en el código, como ver el historial de una función.
En Firma de confirmaciones , vemos cómo usar --show-signature para agregar una cadena de validación a cada confirmación en la
salida del registro de git en función de si se firmó de forma válida o no.
alijo de git
El comando git stash se usa para almacenar temporalmente el trabajo no confirmado para limpiar su directorio de trabajo sin tener
que confirmar el trabajo no terminado en una rama.
etiqueta git
El comando git tag se usa para dar un marcador permanente a un punto específico en el historial del código.
Generalmente esto se usa para cosas como lanzamientos.
Este comando se presenta y cubre en detalle en Etiquetado y lo usamos en la práctica en Etiquetado de sus lanzamientos.
También cubrimos cómo crear una etiqueta firmada por GPG con el indicador -s y cómo verificar una con el indicador -v en Cómo
firmar su trabajo.
503
Machine Translated by Google
en otros lugares, hay un puñado de comandos que se ocupan de los repositorios remotos.
buscar
El comando git fetch se comunica con un repositorio remoto y recupera toda la información que está en ese repositorio que
no está en el actual y la almacena en su base de datos local.
Primero observamos este comando en Obtención y extracción de sus controles remotos y continuamos viendo ejemplos
de su uso en sucursales remotas.
Lo usamos para obtener una sola referencia específica que está fuera del espacio predeterminado en Refs de solicitud de
extracción y vemos cómo obtener de un paquete en Agrupación.
Configuramos refspecs altamente personalizadas para hacer que git fetch haga algo un poco diferente al predeterminado
en The Refspec.
tirar de git
El comando git pull es básicamente una combinación de los comandos git fetch y git merge , donde Git buscará desde el
control remoto que especifique e inmediatamente intentará fusionarlo en la rama en la que se encuentra.
Lo presentamos rápidamente en Obtención y extracción de sus controles remotos y le mostramos cómo ver lo que se
fusionará si lo ejecuta en Inspección de un control remoto.
También vemos cómo usarlo para ayudar con las dificultades de rebase en Rebase When You Rebase.
Mostramos cómo usarlo con una URL para obtener cambios de una sola vez en Verificación de sucursales remotas.
Finalmente, mencionamos rápidamente que puede usar la opción --verify-signatures para verificar que las confirmaciones
que está extrayendo han sido firmadas con GPG en Confirmaciones de firma.
empujar git
El comando git push se usa para comunicarse con otro repositorio, calcular qué tiene su base de datos local que no tiene
la remota y luego empuja la diferencia al otro repositorio.
Requiere acceso de escritura al otro repositorio y, por lo tanto, normalmente se autentica de alguna manera.
En primer lugar, analizamos el comando git push en Pushing to Your Remotes. Aquí cubrimos los conceptos básicos de
enviar una rama a un repositorio remoto. En Empujar profundizamos un poco más en empujar ramas específicas y en
Rastrear ramas vemos cómo configurar ramas de seguimiento para empujar automáticamente. En Eliminación de sucursales
remotas , usamos el indicador --delete para eliminar una sucursal en el servidor con git push.
A lo largo de Contributing to a Project , vemos varios ejemplos del uso de git push para compartir el trabajo en sucursales
a través de múltiples controles remotos.
504
Machine Translated by Google
Vemos cómo usarlo para compartir etiquetas que haya creado con la opción --tags en Compartir etiquetas.
En Publicación de cambios de submódulos , usamos la opción --recurse-submodules para verificar que todo el trabajo de nuestros submódulos se
haya publicado antes de enviar el superproyecto, lo que puede ser realmente útil cuando se usan submódulos.
En Otros ganchos de clientes , hablamos brevemente sobre el gancho previo a la inserción , que es un script que podemos configurar para que
se ejecute antes de que se complete una inserción para verificar que se le debe permitir la inserción.
Finalmente, en Pushing Refspecs , analizamos la inserción con una refspec completa en lugar de los atajos generales que se usan normalmente.
Esto puede ayudarlo a ser muy específico sobre qué trabajo desea compartir.
git remoto
El comando git remote es una herramienta de administración para su registro de repositorios remotos. Le permite guardar direcciones URL largas
como identificadores cortos, como "origen", para que no tenga que escribirlos todo el tiempo. Puede tener varios de estos y el comando remoto git
Este comando se cubre en detalle en Trabajar con controles remotos, incluidos enumerarlos, agregarlos, eliminarlos y cambiarles el nombre.
También se usa en casi todos los capítulos posteriores del libro, pero siempre en el formato estándar de git remote add <name> <url> .
archivo git
El comando git archive se usa para crear un archivo de almacenamiento de una instantánea específica del proyecto.
Usamos git archive para crear un tarball de un proyecto para compartir en Preparación de un lanzamiento.
submódulo git
El comando git submodule se usa para administrar repositorios externos dentro de repositorios normales.
Esto podría ser para bibliotecas u otros tipos de recursos compartidos. El comando del submódulo tiene varios subcomandos (agregar, actualizar,
Inspección y Comparación
mostrar
El comando git show puede mostrar un objeto Git de una manera simple y legible por humanos. Normalmente usaría esto para mostrar la
Más tarde lo usamos un poco en Selección de revisión para mostrar las confirmaciones a las que se resuelven nuestras diversas selecciones de
revisión.
505
Machine Translated by Google
Una de las cosas más interesantes que hacemos con git show es en la fusión manual de archivos para extraer contenidos de archivos
específicos de varias etapas durante un conflicto de fusión.
bitácora de git
El comando git shortlog se usa para resumir la salida de git log. Tomará muchas de las mismas opciones que el comando git log , pero en
lugar de enumerar todas las confirmaciones, presentará un resumen de las confirmaciones agrupadas por autor.
Mostramos cómo usarlo para crear un buen registro de cambios en The Shortlog.
describir
El comando git describe se usa para tomar cualquier cosa que se resuelva en una confirmación y produce una cadena que es algo legible
por humanos y no cambiará. Es una forma de obtener una descripción de una confirmación que es tan inequívoca como una confirmación
SHA-1 pero más comprensible.
Usamos git describe en Generar un número de compilación y preparar un lanzamiento para obtener una cadena para nombrar nuestro
archivo de lanzamiento después.
depuración
Git tiene un par de comandos que se usan para ayudar a depurar un problema en su código. Esto va desde averiguar dónde se introdujo
algo hasta descubrir quién lo introdujo.
git bisecar
La herramienta git bisect es una herramienta de depuración increíblemente útil que se usa para encontrar qué compromiso específico fue
el primero en introducir un error o problema al realizar una búsqueda binaria automática.
culpa
El comando git culpe anota las líneas de cualquier archivo con el que la confirmación fue la última en introducir un cambio en cada línea
del archivo y qué persona fue la autora de esa confirmación. Esto es útil para encontrar a la persona a la que pedir más información sobre
una sección específica de su código.
git grep
El comando git grep puede ayudarlo a encontrar cualquier cadena o expresión regular en cualquiera de los archivos en su código fuente,
incluso en versiones anteriores de su proyecto.
506
Machine Translated by Google
Parchar
Algunos comandos en Git se centran en el concepto de pensar en las confirmaciones en términos de los cambios que introducen, como
si la serie de confirmaciones fuera una serie de parches. Estos comandos lo ayudan a administrar sus sucursales de esta manera.
El comando git cherry-pick se usa para tomar el cambio introducido en una sola confirmación de Git e intentar volver a introducirlo como
una nueva confirmación en la rama en la que se encuentra actualmente. Esto puede ser útil para tomar solo una o dos confirmaciones de
una rama individualmente en lugar de fusionarse en la rama que toma todos los cambios.
La selección selectiva se describe y demuestra en Flujos de trabajo de cambio de base y selección selectiva.
git rebase
El comando git rebase es básicamente una selección automatizada. Determina una serie de compromisos y luego los selecciona uno por
uno en el mismo orden en otro lugar.
El cambio de base se cubre en detalle en Rebase, incluida la cobertura de los problemas de colaboración relacionados con el cambio de
base de sucursales que ya son públicas.
Lo usamos en la práctica durante un ejemplo de dividir su historial en dos repositorios separados en Reemplazar, usando también el
indicador --onto .
También lo usamos en un modo de secuencias de comandos interactivas con la opción -i en Cambio de varios mensajes de confirmación.
git revertir
El comando git revert es esencialmente una selección de git inversa. Crea una nueva confirmación que aplica exactamente lo contrario
del cambio introducido en la confirmación a la que se dirige, esencialmente deshaciéndola o revirtiéndola.
Correo electrónico
Muchos proyectos de Git, incluido el propio Git, se mantienen completamente en listas de correo. Git tiene una serie de herramientas
integradas que ayudan a facilitar este proceso, desde generar parches que puede enviar fácilmente por correo electrónico hasta aplicar
esos parches desde un buzón de correo electrónico.
Aplicar
El comando git apply aplica un parche creado con el comando git diff o incluso GNU diff. Es similar a lo que podría hacer el comando
patch con algunas pequeñas diferencias.
507
Machine Translated by Google
Demostramos su uso y las circunstancias en las que puede hacerlo en Aplicación de parches desde el correo electrónico.
git soy
El comando git am se usa para aplicar parches desde una bandeja de entrada de correo electrónico, específicamente una que
tiene formato mbox. Esto es útil para recibir parches por correo electrónico y aplicarlos fácilmente a su proyecto.
Cubrimos el uso y el flujo de trabajo en torno a git am en Aplicar un parche con am , incluido el uso de las opciones --resolved,
-i y -3 .
También hay una serie de ganchos que puede usar para ayudar con el flujo de trabajo en torno a git am y todos están cubiertos
en Enlaces de flujo de trabajo de correo electrónico.
También lo usamos para aplicar cambios en las solicitudes de extracción de GitHub con formato de parche en las notificaciones por correo electrónico.
El comando git format-patch se usa para generar una serie de parches en formato mbox que puedes usar para enviar a una
lista de correo correctamente formateada.
Pasamos por un ejemplo de contribución a un proyecto utilizando la herramienta de parche de formato git en Proyecto público
por correo electrónico.
git imap-enviar
El comando git imap-send carga un buzón generado con git format-patch en una carpeta de borradores IMAP.
Pasamos por un ejemplo de contribución a un proyecto mediante el envío de parches con la herramienta git imap-send en
Public Project over Email.
El comando git send-email se usa para enviar parches generados con git format-patch por correo electrónico.
Pasamos por un ejemplo de contribución a un proyecto mediante el envío de parches con la herramienta git send-email en
Public Project over Email.
El comando git request-pull simplemente se usa para generar un cuerpo de mensaje de ejemplo para enviar por correo
electrónico a alguien. Si tiene una sucursal en un servidor público y quiere que alguien sepa cómo integrar esos cambios sin
enviar los parches por correo electrónico, puede ejecutar este comando y enviar el resultado a la persona que desea que
introduzca los cambios.
Demostramos cómo usar git request-pull para generar un mensaje de extracción en Forked Public Project.
508
Machine Translated by Google
Sistemas Externos
Git viene con algunos comandos para integrarse con otros sistemas de control de versiones.
git svn
El comando git svn se utiliza para comunicarse con el sistema de control de versiones de Subversion como cliente. Esto
significa que puede usar Git para pagar y comprometerse con un servidor de Subversion.
Para otros sistemas de control de versiones o importar desde casi cualquier formato, puede usar git fast import para asignar
rápidamente el otro formato a algo que Git pueda registrar fácilmente.
Administración
Si está administrando un repositorio de Git o necesita arreglar algo a lo grande, Git proporciona una serie de comandos
administrativos para ayudarlo.
git gc
El comando git gc ejecuta la "recolección de basura" en su repositorio, elimina archivos innecesarios en su base de datos y
empaqueta los archivos restantes en un formato más eficiente.
Este comando normalmente se ejecuta en segundo plano para usted, aunque puede ejecutarlo manualmente si lo desea.
Repasamos algunos ejemplos de esto en Mantenimiento.
git fsck
El comando git fsck se usa para verificar la base de datos interna en busca de problemas o inconsistencias.
Solo usamos esto rápidamente una vez en Recuperación de datos para buscar objetos colgantes.
git reflog
El comando git reflog revisa un registro de dónde han estado todos los jefes de sus sucursales mientras trabaja para encontrar
confirmaciones que puede haber perdido al reescribir los historiales.
Cubrimos este comando principalmente en RefLog Shortnames, donde mostramos el uso normal y cómo usar git log -g para
ver la misma información con la salida de git log .
También pasamos por un ejemplo práctico de recuperación de una rama perdida en Recuperación de datos.
509
Machine Translated by Google
El comando git filter-branch se usa para reescribir muchas confirmaciones de acuerdo con ciertos patrones, como
eliminar un archivo de todas partes o filtrar todo el repositorio a un solo subdirectorio para extraer un proyecto.
En Eliminar un archivo de cada confirmación , explicamos el comando y exploramos varias opciones diferentes,
como --commit-filter, --subdirectory-filter y --tree-filter.
Comandos de plomería
También hubo una gran cantidad de comandos de plomería de nivel inferior que encontramos en el libro.
El primero que encontramos es ls-remote en Pull Request Refs , que usamos para ver las referencias sin procesar
en el servidor.
Usamos ls-files en Manual File Re-merging, Rerere y The Index para tener una visión más cruda de cómo se ve
su área de preparación.
También mencionamos rev-parse en Branch References para tomar casi cualquier cadena y convertirla en un
objeto SHA-1.
Sin embargo, la mayoría de los comandos de plomería de bajo nivel que cubrimos están en Git Internals, que es
más o menos en lo que se enfoca el capítulo. Tratamos de evitar su uso durante la mayor parte del resto del libro.
510
Machine Translated by Google
Índice
@ pequeño equipo privado, 131
93
D
apache, 118
mi
Apple, 489
editor
archivo, 359
atributos, 353 cambiar predeterminado, 34
correo electrónico, 150 aplicar
autocorrección, 346
parches desde, 152 excluye, 345, 432
B
fiesta, 478
F
Bazar, 418
archivos
archivos binarios, 353
moviendo, 37
BitKeeper, 12
sucursales, 63 quitando, 36
creación, 65 eliminación
GRAMO
remota, 94 diferenciación,
Git como cliente, 375
156 de ejecución
comandos de git agregar,
prolongada, 83
27, 27, 28 am, 153
administración, 79 fusión,
aplicar, 152 archivar,
75 remota, 155, 86
165 sucursal, 65, 79
conmutación, 66 tema,
pagar, 66 seleccionar,
152, 84 seguimiento, 92
161 clonar, 25
upstream, 92 números de
construcción, 164
desnudo,
C 110 confirmar, 34,
511
Machine Translated by Google
fetch, 52 H
fetch-pack, 456 ganchos, 361
filter-branch, 422 post-actualización, 107
format-patch, 148
gitk, 471 gui, 471 I
help, 116, 22 http- ignorar archivos, 30
backend, 118 init, Importación
25, 27 bare, 111, 114 de Bazaar, 418 de
Mercurial, 414 de otros,
422 de Perforce, 421
instaweb, 120 de Subversion, 412
log, 38 merge,
73 squash, 147 trabajo integrador, 157
mergetool, Interoperación con otros VCS
78 p4, 404, 421 mercurial, 386
pull, 52 push, 52, Forzosamente, 396
58, 91 rebase, Subversión, 375
96 receive-pack, CRI, 22
454 remote, 50,
51, 53, 54 request- j
pull , 145 rerere, 163 Java, 489
paquete de envío, 454 jgit, 489
bitácora, 165 show, 57
show-ref, 378 estado, k
libgit2, 484
finales de línea, 350
Linus Torvalds, 12
Linux, 12
instalación, 16
GitHub, 167 filtrado de registros,
API, 214 45 formateo de registros, 41
Flujo, 173
METRO
organizaciones, 207
512
Machine Translated by Google
O T
PowerShell, 481
PAGS
instalación, 17
R
flujos de trabajo, 126
reorganización, centralizado, 126
95 peligros de, dictador y lugartenientes, 128
100 frente a fusión, administrador de integración, 127
103 referencias fusión, 158 fusión (grande), 160
remoto, 86 reorganización y selección selectiva,
liberación, 165 161
rerere, 163
X
Rubí, 485
código x, 17
S
Z
servir repositorios, 105 protocolo
git, 116 zsh, 479
GitLab, 121
Git Web, 119
HTTP, 117
SSH, 111
SHA-1, 14
avisos de shell
bash, 478
PowerShell, 481
zsh, 479
Claves SSH, 112
con GitHub, 168
omisión del área de
ensayo, 35
Subversión, 12, 127, 375, 412, 9
513