Descargo de responsabilidad: uso Git, sigo el desarrollo de Git en la lista de correo de git e incluso contribuyo un poco a Git (principalmente gitweb). Conozco Mercurial de la documentación y algunos de la discusión en el canal #revctrl IRC en FreeNode.
Gracias a todas las personas en el canal #mercurial IRC que brindaron ayuda sobre Mercurial para este artículo.
Resumen
Aquí sería bueno tener alguna sintaxis para la tabla, algo así como en la extensión PHPMarkdown / MultiMarkdown / Maruku de Markdown
- Estructura del repositorio: Mercurial no permite fusiones de pulpos (con más de dos padres), ni etiquetar objetos sin compromiso.
- Etiquetas: Mercurial utiliza
.hgtags
archivos versionados con reglas especiales para etiquetas por repositorio, y también tiene soporte para etiquetas locales en .hg/localtags
; en Git, las etiquetas son referencias que residen en el refs/tags/
espacio de nombres y, de forma predeterminada, se siguen automáticamente al buscar y requieren un empuje explícito.
- Sucursales: en Mercurial, el flujo de trabajo básico se basa en cabezas anónimas ; Git usa ramas con nombre ligero y tiene un tipo especial de ramas (ramas de seguimiento remoto ) que siguen a las ramas en el repositorio remoto.
- Nomenclatura y rangos de revisión : Mercurial proporciona números de revisión , locales al repositorio, y basa las revisiones relativas (contando desde la punta, es decir, la rama actual) y rangos de revisión en esta numeración local ; Git proporciona una forma de referirse a la revisión en relación con la punta de la rama, y los rangos de revisión son topológicos (basados en el gráfico de revisiones)
- Mercurial usa el seguimiento de cambio de nombre , mientras que Git usa la detección de cambio de nombre para tratar los cambios de nombre de archivo
- Red: Mercurial admite los protocolos "inteligentes" SSH y HTTP, y el protocolo HTTP estático; El Git moderno admite los protocolos "inteligentes" SSH, HTTP y GIT, y el protocolo "tonto" HTTP (S). Ambos tienen soporte para archivos de paquetes para el transporte fuera de línea.
- Mercurial usa extensiones (complementos) y API establecida; Git tiene capacidad de escritura y formatos establecidos.
Hay algunas cosas que difieren de Mercurial de Git, pero hay otras cosas que las hacen similares. Ambos proyectos toman prestadas ideas el uno del otro. Por ejemplo, el hg bisect
comando en Mercurial (anteriormente extensión bisecta ) se inspiró en el git bisect
comando en Git, mientras que la idea de git bundle
se inspiró en hg bundle
.
Estructura del repositorio, almacenando revisiones
En Git hay cuatro tipos de objetos en su base de datos de objetos: objetos blob que contienen el contenido de un archivo, objetos de árbol jerárquico que almacenan la estructura del directorio, incluidos los nombres de archivo y las partes relevantes de los permisos de archivo (permiso ejecutable para archivos, que es un enlace simbólico) , confirme el objeto que contiene información de autoría, apunte a la instantánea del estado del repositorio en la revisión representada por una confirmación (a través de un objeto de árbol del directorio superior del proyecto) y referencias a cero o más confirmaciones principales, y etiquete objetos que hagan referencia a otros objetos y puedan ser firmado con PGP / GPG.
Git utiliza dos formas de almacenar objetos: formato suelto , donde cada objeto se almacena en un archivo separado (esos archivos se escriben una vez, y nunca se modifican), y formato empaquetado donde muchos objetos se almacenan comprimidos delta en un solo archivo. El hecho de que la referencia a un nuevo objeto se escribe (atómicamente, usando el truco de crear + renombrar) proporciona la atomicidad de las operaciones después de escribir un objeto.
Los repositorios de Git requieren mantenimiento periódico git gc
(para reducir el espacio en disco y mejorar el rendimiento), aunque actualmente Git lo hace automáticamente. (Este método proporciona una mejor compresión de los repositorios).
Mercurial (por lo que yo entiendo) almacena el historial de un archivo en un registro de archivos (juntos, creo, con metadatos adicionales como seguimiento de cambio de nombre y algo de información auxiliar); utiliza una estructura plana llamada manifiesto para almacenar la estructura del directorio y una estructura llamada registro de cambios que almacena información sobre los conjuntos de cambios (revisiones), incluido el mensaje de confirmación y cero, uno o dos padres.
Mercurial utiliza el diario de transacciones para proporcionar la atomicidad de las operaciones y se basa en truncar los archivos para limpiarlos después de una operación fallida o interrumpida. Los Revlogs son solo para agregar.
Al observar la estructura del repositorio en Git versus Mercurial, se puede ver que Git es más como una base de datos de objetos (o un sistema de archivos con contenido de contenido), y Mercurial más como una base de datos relacional tradicional de campo fijo.
Diferencias:
en Git, los objetos del árbol forman una estructura jerárquica ; en el archivo de manifiesto Mercurial es una estructura plana . En Git blob object, almacene una versión del contenido de un archivo; en Mercurial Filelog almacena el historial completo de un solo archivo (si no tenemos en cuenta aquí ninguna complicación con los cambios de nombre). Esto significa que hay diferentes áreas de operaciones donde Git sería más rápido que Mercurial, todas las demás cosas se consideran iguales (como fusiones o mostrar el historial de un proyecto) y áreas donde Mercurial sería más rápido que Git (como aplicar parches o mostrar historial de un solo archivo).Este problema puede no ser importante para el usuario final.
Debido a la estructura de registro fijo de la estructura de registro de cambios de Mercurial , los compromisos en Mercurial solo pueden tener hasta dos padres ; commits en Git puede tener más de dos padres (llamada "fusión de pulpo"). Si bien puede (en teoría) reemplazar la fusión de pulpo por una serie de fusiones de dos padres, esto podría causar complicaciones al convertir entre repositorios Mercurial y Git.
Hasta donde sé, Mercurial no tiene el equivalente de etiquetas anotadas (objetos de etiqueta) de Git. Un caso especial de etiquetas anotadas son etiquetas firmadas (con firma PGP / GPG); el equivalente en Mercurial se puede hacer usando GpgExtension , cuya extensión se distribuye junto con Mercurial. No puede etiquetar objetos sin compromiso en Mercurial como puede hacerlo en Git, pero eso no es muy importante, creo (algunos repositorios de git usan blob etiquetado para distribuir la clave PGP pública para verificar etiquetas firmadas).
Referencias: ramas y etiquetas
En Git, las referencias (ramas, ramas y etiquetas de seguimiento remoto) residen fuera del DAG de las confirmaciones (como deberían). Las referencias en el refs/heads/
espacio de nombres ( ramas locales ) apuntan a commits, y generalmente se actualizan con "git commit"; apuntan a la punta (cabeza) de la rama, por eso ese nombre. Las referencias en el refs/remotes/<remotename>/
espacio de nombres ( ramas de seguimiento remoto ) apuntan a comprometerse, siguen ramas en el repositorio remoto <remotename>
y se actualizan mediante "git fetch" o equivalente. Las referencias en el refs/tags/
espacio de nombres ( etiquetas ) generalmente apuntan a commits (etiquetas livianas) u objetos de etiqueta (etiquetas anotadas y firmadas), y no están destinados a cambiar.
Etiquetas
En Mercurial puede dar un nombre persistente a la revisión usando la etiqueta ; Las etiquetas se almacenan de manera similar a los patrones de ignorar. Significa que las etiquetas visibles globalmente se almacenan en un .hgtags
archivo controlado por revisión en su repositorio. Eso tiene dos consecuencias: primero, Mercurial tiene que usar reglas especiales para este archivo para obtener la lista actual de todas las etiquetas y actualizar dicho archivo (por ejemplo, lee la revisión más reciente del archivo, no la versión actualmente desprotegida); segundo, debe realizar cambios en este archivo para que la nueva etiqueta sea visible para otros usuarios / otros repositorios (por lo que yo entiendo).
Mercurial también admite etiquetas locales , almacenadas hg/localtags
, que no son visibles para otros (y, por supuesto, no son transferibles)
En Git, las etiquetas son referencias nominales fijas (constantes) a otros objetos (generalmente objetos de etiqueta, que a su vez apuntan a confirmaciones) almacenados en el refs/tags/
espacio de nombres. De forma predeterminada, cuando se busca o empuja un conjunto de revisiones, git busca o empuja automáticamente etiquetas que apuntan a las revisiones que se buscan o empujan. Sin embargo, puede controlar hasta cierto punto qué etiquetas se obtienen o se envían.
Git trata las etiquetas livianas (apuntando directamente a commits) y las etiquetas anotadas (apuntando a objetos de etiqueta, que contienen mensajes de etiqueta que opcionalmente incluyen la firma PGP, que a su vez apuntan a commit) de manera ligeramente diferente, por ejemplo, por defecto, considera solo las etiquetas anotadas cuando describe se compromete a usar "git describe".
Git no tiene un equivalente estricto de etiquetas locales en Mercurial. Sin embargo, las mejores prácticas de git recomiendan configurar un repositorio desnudo público separado, en el que empuje los cambios listos, y desde el que otros clonan y obtienen. Esto significa que las etiquetas (y ramas) que no inserta son privadas para su repositorio. Por otro lado, también puede usar un espacio de nombres que no sea heads
, remotes
o tags
, por ejemplo, local-tags
para etiquetas locales.
Opinión personal: en mi opinión, las etiquetas deben residir fuera del gráfico de revisión, ya que son externas (son punteros en el gráfico de revisiones). Las etiquetas deben ser no versionadas, pero transferibles. La elección de Mercurial de utilizar un mecanismo similar al de ignorar archivos significa que debe tratarse .hgtags
especialmente (el archivo en árbol es transferible, pero ordinario está versionado) o tiene etiquetas que son locales solamente ( .hg/localtags
no está versionado, pero intransferible).
Ramas
En Git, la rama local (punta de rama o encabezado de rama) es una referencia con nombre a una confirmación, donde se pueden desarrollar nuevas confirmaciones. Branch también puede significar una línea activa de desarrollo, es decir, todos los commits accesibles desde la punta de la branch. Las sucursales locales residen en el refs/heads/
espacio de nombres, por lo que, por ejemplo, el nombre completo de la sucursal 'maestra' es 'refs / heads / master'.
La rama actual en Git (es decir, la rama desprotegida y la rama donde irá la nueva confirmación) es la rama a la que hace referencia la referencia HEAD. Uno puede tener HEAD apuntando directamente a un commit, en lugar de ser una referencia simbólica; Esta situación de estar en una rama anónima sin nombre se llama HEAD separada ("git branch" muestra que estás en '(sin rama)').
En Mercurial hay sucursales anónimas (jefes de sucursal), y uno puede usar marcadores (a través de la extensión de marcador ). Dichas ramas de marcadores son puramente locales, y esos nombres eran (hasta la versión 1.6) no transferibles usando Mercurial. Puede usar rsync o scp para copiar el .hg/bookmarks
archivo a un repositorio remoto. También puede usar hg id -r <bookmark> <url>
para obtener la identificación de revisión de una sugerencia actual de un marcador.
Desde 1.6 los marcadores se pueden empujar / tirar. La página BookmarksExtension tiene una sección sobre Trabajar con repositorios remotos . Hay una diferencia en que en Mercurial los nombres de marcadores son globales , mientras que la definición de 'remoto' en Git describe también el mapeo de los nombres de las ramas de los nombres en el repositorio remoto a los nombres de las ramas locales de seguimiento remoto; por ejemplo, el refs/heads/*:refs/remotes/origin/*
mapeo significa que uno puede encontrar el estado de la rama 'maestra' ('refs / heads / master') en el repositorio remoto en la rama de seguimiento remoto 'origen / maestro' ('refs / remotes / origin / master').
Mercurial también se denomina ramas con nombre , donde el nombre de la rama está incrustado en una confirmación (en un conjunto de cambios). Dicho nombre es global (transferido al buscar). Esos nombres de rama se registran permanentemente como parte de los metadatos del conjunto de cambios. Con Mercurial moderno puede cerrar la "rama con nombre" y dejar de grabar el nombre de la rama. En este mecanismo, las puntas de las ramas se calculan sobre la marcha.
En mi opinión, las "ramas con nombre" de Mercurial deberían llamarse etiquetas de compromiso , porque es lo que son. Hay situaciones en las que la "rama con nombre" puede tener múltiples sugerencias (múltiples confirmaciones sin hijos) y también puede consistir en varias partes disjuntas del gráfico de revisiones.
No hay equivalente de esas "ramas incrustadas" de Mercurial en Git; Además, la filosofía de Git es que si bien se puede decir que la rama incluye alguna confirmación, no significa que una confirmación pertenezca a alguna rama.
Tenga en cuenta que la documentación de Mercurial todavía propone utilizar clones separados (repositorios separados) al menos para ramas de larga duración (rama única por flujo de trabajo de repositorio), también conocido como ramificación por clonación .
Ramas en empujar
Mercurial por defecto empuja todas las cabezas . Si desea empujar una sola rama ( cabeza simple ), debe especificar la revisión de la punta de la rama que desea empujar. Puede especificar la sugerencia de la rama por su número de revisión (local al repositorio), por identificador de revisión, por nombre de marcador (local al repositorio, no se transfiere) o por el nombre de la rama incrustada (rama nombrada).
Por lo que yo entiendo, si empuja un rango de revisiones que contienen confirmaciones marcadas como en alguna "rama con nombre" en el lenguaje Mercurial, tendrá esta "rama con nombre" en el repositorio al que empuja. Esto significa que los nombres de tales ramas incrustadas ("ramas con nombre") son globales (con respecto a los clones de un repositorio / proyecto dado).
Por defecto (sujeto a la push.default
variable de configuración) "git push" o "git push < remote >" Git empujaría ramas coincidentes , es decir, solo aquellas ramas locales que ya tienen su equivalente presente en el repositorio remoto en el que ingresas. Puede usar la --all
opción to git-push ("git push --all") para empujar todas las ramas , puede usar "git push < remote > < branch >" para empujar una rama determinada , y puede usar "git push < remoto > CABEZA "para empujar la rama actual .
Todo lo anterior supone que Git no está configurado qué ramas empujar a través de remote.<remotename>.push
variables de configuración.
Ramas en busca
Nota: aquí utilizo la terminología de Git donde "buscar" significa descargar cambios desde el repositorio remoto sin integrar esos cambios con el trabajo local. Esto es lo que hace " git fetch
" y " hg pull
".
Si lo entiendo correctamente, Mercurial busca de forma predeterminada todas las cabezas del repositorio remoto, pero puede especificar la rama para obtener a través de " hg pull --rev <rev> <url>
" o " hg pull <url>#<rev>
" para obtener una sola rama . Puede especificar <rev> utilizando el identificador de revisión, el nombre de "rama con nombre" (rama incrustada en el registro de cambios) o el nombre del marcador. Sin embargo, el nombre del marcador (al menos actualmente) no se transfiere. Todas las revisiones de "ramas con nombre" que reciba pertenecen para ser transferidas. "hg pull" almacena las puntas de las ramas que obtuvo como cabezas anónimas y sin nombre.
En Git por defecto (para 'origen' remoto creado por "git clone", y para controles remotos creados usando "git remote add") " git fetch
" (o " git fetch <remote>
") obtiene todas las ramas del repositorio remoto (desde el refs/heads/
espacio de nombres), y las almacena en refs/remotes/
espacio de nombres Esto significa, por ejemplo, que la rama llamada 'maestro' (nombre completo: 'refs / heads / master') en el 'origen' remoto se almacenaría (guardaría) como la rama de seguimiento remoto 'origen / maestro' (nombre completo: 'refs / controles remotos / origen / maestro ').
Puede obtener una sola rama en Git utilizando git fetch <remote> <branch>
: Git almacenaría las ramas solicitadas en FETCH_HEAD, que es algo similar a las cabezas sin nombre de Mercurial.
Esos son solo ejemplos de casos predeterminados de poderosa sintaxis Git de refspec : con refspecs puede especificar y / o configurar qué ramas desea obtener y dónde almacenarlas. Por ejemplo, el caso predeterminado "buscar todas las ramas" está representado por '+ refs / heads / *: refs / remotes / origin / *' comodín refspec, y "buscar una sola rama" es la abreviatura de 'refs / heads / <branch>:' . Las Refspecs se utilizan para asignar nombres de ramas (referencias) en el repositorio remoto a nombres de referencias locales. Pero no necesita saber (mucho) sobre las especificaciones técnicas para poder trabajar eficazmente con Git (gracias principalmente al comando "git remote").
Opinión personal: Personalmente, creo que las "ramas con nombre" (con los nombres de las ramas incrustados en los metadatos del conjunto de cambios) en Mercurial son diseños equivocados con su espacio de nombres global, especialmente para un sistema de control de versiones distribuido . Por ejemplo, tomemos un caso en el que tanto Alice como Bob tienen "rama nombrada" llamada 'for-joe' en sus repositorios, ramas que no tienen nada en común. Sin embargo, en el repositorio de Joe esas dos ramas serían maltratadas como una sola rama. Entonces, de alguna manera, se te ocurrió una convención que protege contra los enfrentamientos de nombres de sucursales. Esto no es problema con Git, donde en el repositorio de Joe la rama 'for-joe' de Alice sería 'alice / for-joe', y de Bob sería 'bob / for-joe'.
Las "sucursales de marcadores" de Mercurial carecen actualmente de un mecanismo de distribución central.
Diferencias:
Esta área es una de las principales diferencias entre Mercurial y Git, como dijeron James Woodyatt y Steve Losh en sus respuestas. Mercurial, por defecto, utiliza líneas de código anónimas y ligeras, que en su terminología se llaman "cabezas". Git usa ramas con nombre livianas, con mapeo inyectivo para mapear nombres de ramas en repositorio remoto a nombres de ramas de seguimiento remoto. Git "lo obliga" a nombrar ramas (bueno, con la excepción de una sola rama sin nombre, situación llamada HEAD separada), pero creo que esto funciona mejor con flujos de trabajo con muchas ramas, como el flujo de trabajo de ramas temáticas, lo que significa múltiples ramas en un solo paradigma de repositorio.
Nombrando revisiones
En Git hay muchas formas de nombrar revisiones (descritas, por ejemplo, en la página de manual de git rev-parse ):
- El nombre completo del objeto SHA1 (cadena hexadecimal de 40 bytes) o una subcadena de este tipo que es única dentro del repositorio
- Un nombre de referencia simbólico, por ejemplo, 'maestro' (que se refiere a la rama 'maestro'), o 'v1.5.0' (que se refiere a la etiqueta), o 'origen / siguiente' (que se refiere a la rama de seguimiento remoto)
- Un sufijo
^
para el parámetro de revisión significa el primer padre de un objeto de compromiso, ^n
significa el enésimo padre de un compromiso de fusión. Un sufijo ~n
para el parámetro de revisión significa enésimo antecesor de una confirmación en línea recta de primer padre. Esos sufijos se pueden combinar para formar un especificador de revisión siguiendo la ruta desde una referencia simbólica, por ejemplo, 'pu ~ 3 ^ 2 ~ 3'
- Salida de "git describe", es decir, una etiqueta más cercana, opcionalmente seguida de un guión y una serie de confirmaciones, seguidas de un guión, una 'g' y un nombre de objeto abreviado, por ejemplo 'v1.6.5.1-75- g5bf8097 '.
También hay especificadores de revisión que involucran reflog, no mencionados aquí. En Git, cada objeto, ya sea commit, tag, tree o blob, tiene su identificador SHA-1; hay una sintaxis especial como, por ejemplo, 'next: Documentation' o 'next: README' para referirse al árbol (directorio) o blob (contenido del archivo) en la revisión especificada.
Mercurial también tiene muchas formas de nombrar conjuntos de cambios (descritos, por ejemplo, en la página de manual de hg ):
- Un entero simple se trata como un número de revisión. Hay que recordar que los números de revisión son locales para el repositorio dado ; en otro repositorio pueden ser diferentes.
- Los enteros negativos se tratan como desplazamientos secuenciales desde la punta, con -1 que denota la punta, -2 que denota la revisión anterior a la punta, y así sucesivamente. También son locales para el repositorio.
- Un identificador de revisión único (cadena hexadecimal de 40 dígitos) o su prefijo único.
- Un nombre de etiqueta (nombre simbólico asociado con la revisión dada), o un nombre de marcador (con extensión: nombre simbólico asociado con la cabeza dada, local al repositorio), o una "rama con nombre" (etiqueta de compromiso; la revisión dada por "rama con nombre" es punta (confirmación sin hijos) de todas las confirmaciones con una etiqueta de confirmación dada, con el número de revisión más grande si hay más de una sugerencia)
- El nombre reservado "tip" es una etiqueta especial que siempre identifica la revisión más reciente.
- El nombre reservado "nulo" indica la revisión nula.
- El nombre reservado "." indica el directorio de trabajo principal.
Diferencias
Como puede ver al comparar las listas anteriores, Mercurial ofrece números de revisión, locales al repositorio, mientras que Git no. Por otro lado, Mercurial ofrece compensaciones relativas solo desde 'punta' (rama actual), que son locales al repositorio (al menos sin ParentrevspecExtension ), mientras que Git permite especificar cualquier confirmación de seguimiento desde cualquier punta.
La revisión más reciente se llama HEAD en Git y "tip" en Mercurial; no hay revisión nula en Git. Tanto Mercurial como Git pueden tener muchas raíces (pueden tener más de una confirmación sin padres; esto generalmente es el resultado de la unión de proyectos anteriormente separados).
Ver también: Muchos tipos diferentes de artículo de especificadores de revisión en el blog de Elijah (newren's).
Opinión personal: creo que los números de revisión están sobrevalorados (al menos para el desarrollo distribuido y / o el historial no lineal / ramificado). Primero, para un sistema de control de versiones distribuido tienen que ser locales para el repositorio, o requieren tratar algún repositorio de manera especial como una autoridad central de numeración. En segundo lugar, los proyectos más grandes, con un historial más largo, pueden tener varias revisiones en el rango de 5 dígitos, por lo que ofrecen una ligera ventaja sobre los identificadores de revisión acortados a 6-7 caracteres, e implican un pedido estricto, mientras que las revisiones son solo parcialmente ordenadas (quiero decir aquí que las revisiones n y n + 1 no necesitan ser padre e hijo).
Rangos de revisión
En Git, los rangos de revisión son topológicos . La A..B
sintaxis comúnmente vista , que para el historial lineal significa un rango de revisión que comienza en A (pero excluye A) y termina en B (es decir, el rango está abierto desde abajo ), es una forma abreviada ("azúcar sintáctico") para ^A B
, que para los comandos de recorrido de historia significa todo commits accesibles desde B, excluyendo aquellos accesibles desde A. Esto significa que el comportamiento del A..B
rango es completamente predecible (y bastante útil) incluso si A no es ancestro de B: A..B
significa entonces el rango de revisiones del ancestro común de A y B (fusionar base ) a la revisión B.
En Mercurial, los rangos de revisión se basan en el rango de números de revisión . El rango se especifica utilizando la A:B
sintaxis y, al contrario que Git, el rango actúa como un intervalo cerrado . También el rango B: A es el rango A: B en orden inverso, que no es el caso en Git (pero vea la nota a continuación sobre la A...B
sintaxis). Pero tal simplicidad tiene un precio: el rango de revisión A: B solo tiene sentido si A es antepasado de B o viceversa, es decir, con historia lineal; de lo contrario (supongo que) el rango es impredecible, y el resultado es local al repositorio (porque los números de revisión son locales al repositorio).
Esto se soluciona con Mercurial 1.6, que tiene un nuevo rango de revisión topológica , donde 'A..B' (o 'A :: B') se entiende como el conjunto de conjuntos de cambios que son descendientes de X y ancestros de Y. Esto es , Supongo, equivalente a '--ancestry-path A..B' en Git.
Git también tiene notación A...B
para diferencia simétrica de revisiones; significa A B --not $(git merge-base A B)
, lo que significa que todas las confirmaciones accesibles desde A o B, pero excluyendo todas las confirmaciones alcanzables desde ambos (alcanzables desde ancestros comunes).
Renombra
Mercurial utiliza el seguimiento de cambio de nombre para tratar los cambios de nombre de los archivos. Esto significa que la información sobre el hecho de que se cambió el nombre de un archivo se guarda en el momento de la confirmación; en Mercurial, esta información se guarda en la forma "diff mejorada" en los metadatos del registro de archivos (registro de archivos). La consecuencia de esto es que debe usar hg rename
/ hg mv
... o debe recordar ejecutar hg addremove
para hacer una detección de cambio de nombre basada en similitudes.
Git es único entre los sistemas de control de versiones, ya que utiliza la detección de cambio de nombre para tratar los cambios de nombre de archivo. Esto significa que el hecho de que se cambió el nombre del archivo se detecta en el momento en que se necesita: cuando se realiza una fusión o cuando se muestra una diferencia (si se solicita / configura). Esto tiene la ventaja de que el algoritmo de detección de cambio de nombre se puede mejorar y no se congela en el momento de la confirmación.
Tanto Git como Mercurial requieren el uso de la --follow
opción para seguir los cambios de nombre al mostrar el historial de un solo archivo. Ambos pueden seguir los cambios de nombre cuando se muestra el historial en línea de un archivo en git blame
/ hg annotate
.
En Git, el git blame
comando puede seguir el movimiento del código, también mover (o copiar) el código de un archivo a otro, incluso si el movimiento del código no forma parte del cambio de nombre del archivo. Hasta donde yo sé, esta característica es exclusiva de Git (en el momento de la redacción, octubre de 2009).
Protocolos de red
Tanto Mercurial como Git tienen soporte para buscar y empujar a repositorios en el mismo sistema de archivos, donde la URL del repositorio es solo una ruta del sistema de archivos al repositorio. Ambos también tienen soporte para recuperar archivos de paquete .
Soporte Mercurial para buscar y empujar a través de SSH y protocolos HTTP. Para SSH, se necesita una cuenta de shell accesible en la máquina de destino y una copia de hg instalada / disponible. Para el acceso HTTP hg-serve
se requiere la ejecución del script Mercurial CGI, y Mercurial debe instalarse en la máquina del servidor.
Git admite dos tipos de protocolos utilizados para acceder al repositorio remoto:
- Los protocolos "inteligentes" , que incluyen el acceso a través de SSH y a través del protocolo personalizado git: // (by
git-daemon
), requieren tener instalado git en el servidor. El intercambio en esos protocolos consiste en que el cliente y el servidor negocien sobre qué objetos tienen en común y luego generen y envíen un paquete. Modern Git incluye soporte para el protocolo HTTP "inteligente".
- Los protocolos "tontos" , que incluyen HTTP y FTP (solo para buscar) y HTTPS (para enviar a través de WebDAV), no requieren que git esté instalado en el servidor, pero sí requieren que el repositorio contenga información adicional generada por
git update-server-info
(generalmente se ejecuta desde un enlace ) El intercambio consiste en que el cliente recorre la cadena de confirmación y descarga objetos sueltos y archivos de paquete según sea necesario. La desventaja es que se descarga más de lo estrictamente requerido (por ejemplo, en el caso de una esquina cuando solo hay un solo paquete, se descargará completo incluso cuando se obtienen solo unas pocas revisiones), y que puede requerir muchas conexiones para finalizar.
Ampliación: capacidad de escritura frente a extensiones (complementos)
Mercurial se implementa en Python , con un código central escrito en C para el rendimiento. Proporciona API para escribir extensiones (complementos) como una forma de agregar funciones adicionales. Parte de la funcionalidad, como "sucursales de marcadores" o revisiones de firma, se proporciona en extensiones distribuidas con Mercurial y requiere activarla.
Git se implementa en C , Perl y scripts de shell . Git proporciona muchos comandos de bajo nivel ( plomería ) adecuados para usar en scripts. La forma habitual de introducir una nueva característica es escribirla como Perl o script de shell, y cuando la interfaz de usuario se estabilice, vuelva a escribirla en C para obtener rendimiento, portabilidad y, en el caso de script de shell, evitar los casos de esquina (este procedimiento se llama builtinificación ).
Git se basa y se basa en formatos [repositorios] y protocolos [de red]. En lugar de enlaces de lenguaje, hay reimplementaciones (parciales o completas) de Git en otros idiomas (algunos de ellos son parcialmente reimplementaciones y parcialmente envolturas alrededor de comandos git): JGit (Java, usado por EGit, Eclipse Git Plugin), Grit (Ruby) , Dulwich (Python), git # (C #).
TL; DR