La afirmación de que "la ramificación es gratuita en git" es una simplificación de los hechos porque no es "gratuita" per se. Mirando debajo del capó, una afirmación más correcta sería decir que la ramificación es redonkulosamente barata , porque las ramas son básicamente referencias a compromisos . Defino "baratura" aquí como menos gastos generales más barato.
Analicemos por qué Git es tan "barato" al examinar qué tipos de gastos generales tiene:
¿Cómo se implementan las ramas en git?
El repositorio de git, en .git
su mayoría , consiste en directorios con archivos que contienen metadatos que usa git. Cada vez que crea una rama en git, por ejemplo git branch {name_of_branch}
, suceden algunas cosas:
- Se crea una referencia a la sucursal local en:
.git/refs/heads/{name_of_branch}
- Se crea un registro de historial para la sucursal local en:
.git/logs/refs/heads/{name_of_branch}
Eso es básicamente todo, se crean un par de archivos de texto. Si abre la referencia como un archivo de texto, el contenido será el id-sha del commit al que apunta la rama. Tenga en cuenta que la ramificación no requiere que realice ninguna confirmación, ya que son otro tipo de objeto. Ambas ramas y commits son "ciudadanos de primera clase" en términos de git y una forma es pensar en la relación de branch-to-commit como una agregación en lugar de una composición. Si elimina una rama, las confirmaciones seguirán existiendo como "colgantes". Si eliminó accidentalmente una rama, siempre puede intentar encontrar la confirmación con git-lost-found
o git-fsck --lost-found
y crear una rama en el sha-id que encuentre colgando (y siempre que git aún no haya realizado ninguna recolección de basura).
Entonces, ¿cómo hace git un seguimiento de en qué rama estás trabajando? La respuesta es con el .git/HEAD
archivo, que se parece a esto si estás en la master
rama.
ref: refs/heads/master
Cambiar ramas simplemente cambia la referencia en el .git/HEAD
archivo, y luego procede a cambiar el contenido de su espacio de trabajo con los definidos en la confirmación.
¿Cómo se compara esto en otros sistemas de control de versiones?
En Subversion , las ramas son directorios virtuales en el repositorio . Entonces, la forma más fácil de ramificarse es hacerlo de forma remota, con una sola línea svn copy {trunk-url} {branch-url} -m "Branched it!"
. Lo que SVN hará es lo siguiente:
- Copie el directorio de origen, por ejemplo
trunk
, a un directorio de destino,
- Confirme los cambios para finalizar la acción de copia.
Deberá realizar esta acción de forma remota en el servidor, ya que realizar esa copia localmente es una operación de tiempo lineal, con archivos que se copian y enlazan. Esta es una operación muy lenta , mientras que hacerlo en el servidor es una operación de tiempo constante. Tenga en cuenta que incluso cuando se realiza la bifurcación en el servidor, la subversión requiere una confirmación cuando se bifurca mientras que git no, lo cual es una diferencia clave. Ese es un tipo de sobrecarga que hace que SVN sea marginalmente menos barato que Git.
El comando para cambiar ramas en SVN , es decir svn switch
, es realmente el svn update
disfraz. Gracias al concepto de directorio virtual, el comando es un poco más flexible en svn que en git. Los subdirectorios en su espacio de trabajo se pueden cambiar para reflejar otra url del repositorio. Lo más parecido sería usarlo, git-submodule
pero usarlo es semánticamente bastante diferente de la ramificación. Desafortunadamente, esta es también una decisión de diseño que hace que el cambio sea un poco más lento en SVN que en Git, ya que tiene que verificar cada directorio de espacio de trabajo en qué url remota está reflejando. En mi experiencia, Git es más rápido para cambiar de rama que SVN.
La ramificación de SVN tiene un costo ya que copia archivos y siempre debe estar disponible públicamente. En git, como se explicó anteriormente, las ramas son "solo referencias" y pueden mantenerse en su repositorio local y publicarse a su discreción. Sin embargo, en mi experiencia, SVN sigue siendo notablemente más barato y más eficiente que, por ejemplo, ClearCase.
Es un fastidio que SVN no esté descentralizado. Puede tener múltiples repositorios reflejados en algún repositorio de origen, pero no es posible sincronizar cambios diferentes en múltiples repositorios SVN, ya que SVN no tiene identificadores únicos para confirmaciones (git ha identificado identificadores basados en el contenido de la confirmación). Sin embargo, la razón por la que personalmente comencé a usar git sobre SVN es porque iniciar un repositorio es notablemente más fácil y más barato en git . Conceptualmente en términos de gestión de configuración de software, cada copia divergente de un proyecto (clon, fork, espacio de trabajo o lo que sea) es una "rama", y dada esta terminología, crear una nueva copia en SVN no es tan barato como Git, donde este último tiene ramas "incorporadas".
Como otro ejemplo, en Mercurial , la ramificación comenzó un poco diferente como un DVCS y la creación / destrucción de ramas con nombre requirió confirmaciones separadas. Los desarrolladores de Mercurial implementados más tarde en los marcadores de desarrollo para imitar el mismo modelo de ramificación de git, aunque heads
se llaman tips
y en su lugar branches
están bookmarks
en terminología mercurial.