No sé exactamente cómo lo hace GitHub, pero aquí hay una manera posible. Requiere cierto conocimiento de la forma en que git almacena sus datos.
La respuesta corta es que los repos pueden compartir la base de datos objects
pero cada uno tiene sus propias referencias.
Incluso podemos simularlo localmente para una prueba de concepto.
En el anuario de un acuerdo de recompra desnudo (o en el .git/
subdirectorio si no es desnudo) hay tres cosas que son el mínimo para un acuerdo de recompra a trabajar:
- la
objects/
subdirectorio, que almacena todos los objetos (commits, trees, blobs ...). Se almacenan individualmente como archivos con nombres iguales al hash del objeto o en los archivos .pack
.
- subdirectorio
refs/
, que almacena archivos simples como refs/heads/master
cuyo contenido es el hash del objeto al que hace referencia.
- el archivo
HEAD
, que dice cuál es la confirmación actual. Su valor es un hash puro (que corresponde a un cabeza separada, es decir, no estamos en ninguna rama con nombre) o un enlace de texto a un ref donde se puede encontrar el hash real (por ejemplo ref: refs/heads/master
), eso significa que estamos en rama master
)
Supongamos que alguien crea su cesión temporal original (no se bifurcan) orig
en Github.
Para simular, localmente hacemos
$ git init --bare github_orig
Nos imaginamos que lo anterior ocurre en los servidores de Github. Ahora hay un repositorio github vacío. A continuación, nos imaginamos que a partir de nuestra propia PC clonamos el repositorio GitHub:
$ git clone github_orig local_orig
Por supuesto, en la vida real en lugar de github_orig
usaremos https://github...
. Ahora hemos clonado el repositorio de github en local_orig
.
$ cd local_orig/
$ echo zzz > file
$ git add file
$ git commit -m initial
$ git push
$ cd ..
Después object
dir este github_orig
's contendrá nuestra empujado cometer objeto, un objeto blob para file
y un objeto árbol. El archivo refs/heads/master
contendrá el hash de confirmación.
Ahora imaginemos qué podría estar pasando cuando alguien presione el botón Fork
. Vamos a crear un repositorio git, pero a mano:
$ mkdir github_fork
$ cd github_fork/
$ cp ../github_orig/HEAD .
$ cp -r ../github_orig/refs .
$ ln -s ../github_orig/objects
$ cd ..
en cuenta que nos copiamos HEAD
y refs
pero hacer un enlace simbólico para objects
. Como podemos ver, hacer una horquilla es muy barata. Incluso si tenemos decenas de ramas, cada una de ellas es simplemente un archivo en el directorio refs/heads
que contiene un hash hexadecimal simple (40 bytes). Para objects
solo vinculamos al directorio de objetos original, ¡no copiamos nada!
Ahora simulamos que el usuario que realiza la tenedor, los clones del repo bifurcada localmente:
$ git clone github_fork local_fork
$ cd local_fork
$ # ls
.git/ file
podemos ver que hemos clonado con éxito a pesar de que el repositorio que clonar no tiene sus propios objects
pero los enlaces a la del repositorio original.
Ahora el usuario de horquilla puede hacer ramas, confirmaciones y luego empujarlas al github_fork
. Los objetos se insertarán en el directorio objects
, que es el mismo para github_orig
. Pero refs
y HEAD
se modificarán y ya no coincidirán con los del github_orig
.
Por lo tanto, la conclusión es que todos los repos que pertenecen al mismo árbol de bifurcación comparten un fondo común de objetos , mientras que cada repositorio contiene sus propias referencias. Cualquiera que empuje commits a su propio repositorio bifurcado modifica sus propias referencias pero coloca los objetos en un grupo compartido.
Por supuesto, para ser realmente utilizable algunas cosas más hay que tener cuidado de - lo más importante es el colector git basura debe no ser invocada a menos que la cesión temporal en el que se invoca en cuenta el conocimiento de todos referencias - no sólo su propio. De lo contrario, podría descartar objetos en el grupo compartido que no son accesibles desde sus referencias pero que podrían ser accesibles desde otros reposs refs.
Es posible que github utilice algún tipo de optimización, como enlaces duros, mientras crea la horquilla, pero para todos los fines prácticos, es solo una clonación en el propio servidor github. –
@NoufalIbrahim: Claro. Definitivamente es posible que se esfuercen por hacer una optimización interna para ahorrar espacio en el disco hasta que un tenedor realmente comprometa una revisión del archivo. Pero eso sería transparente para los usuarios realmente. Buen punto sin embargo. – jdi
@NoufalIbrahim: Aunque como lo pienso más, podría ser una situación complicada, porque como sabemos, cuando el repositorio de subida recibe nuevas confirmaciones, no tiene ningún efecto sobre las horquillas. Ellos son responsables de buscar aguas abajo de forma individual. – jdi