Git y Mercurial-Comparar y Contrastar


Desde hace un tiempo uso subversion para mis proyectos personales.

Cada vez escucho más cosas geniales sobre Git y Mercurial, y DVCS en general.

Me gustaría darle un giro a todo el asunto DVCS, pero no estoy muy familiarizado con ninguna de las dos opciones.

¿Cuáles son algunas de las diferencias entre Mercurial y Git?

Tenga en cuenta que estoy no tratando de averiguar cuál es "mejor" o incluso con cuál debería comenzar. Estoy buscando la llave. áreas donde son similares y donde son diferentes, porque me interesa saber cómo difieren en términos de implementación y filosofía.

Author: Jon Seigel, 2009-10-21

11 answers

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 por la documentación y algunos por la discusión en el canal IRC # revctrl en FreeNode.

Gracias a todas las personas en el canal de IRC #mercurial que proporcionaron ayuda sobre Mercurial para este writeup



Resumen

Aquí sería bueno tener alguna sintaxis para la tabla, algo como en PHPMarkdown / MultiMarkdown / Maruku extensión de Markdown

  • Estructura del repositorio: Mercurial no permite fusiones octopus (con más de dos padres), ni etiquetar objetos no confirmados.
  • Etiquetas: Mercurial usa un archivo versionado .hgtags con reglas especiales para etiquetas por repositorio, y también tiene soporte para etiquetas locales en .hg/localtags; en Git las etiquetas son refs que residen en refs/tags/ espacio de nombres, y por defecto son auto-seguidas al empujando explícitamente.
  • Ramas:En Mercurial basic el flujo de trabajo se basa en cabezas anónimas; Git utiliza ramas con nombre ligero, y tiene un tipo especial de ramas ( ramas de seguimiento remoto) que siguen ramas en el repositorio remoto.
  • Nombres y rangos de revisión: Mercurial proporciona números de revisión , local al repositorio, y basa las revisiones relativas (contando desde tip, es decir, la rama actual) y los rangos de revisión en esto numeración local; Git proporciona una forma de referirse a la revisión relativa a la tip de rama, y los rangos de revisión son topológicos (basados en el gráfico de revisiones)
  • Mercurial usa rename tracking , mientras que Git usa rename detection para tratar los renombres de archivos
  • Red: Mercurial soporta protocolos SSH y HTTP "smart", y protocolo HTTP estático; Git moderno soporta protocolos SSH, HTTP y GIT "smart", y protocolo HTTP(S) "dumb". Ambos tienen soporte para paquetes de archivos para el transporte fuera de línea.
  • Mercurial utiliza extensiones (plugins) y API establecida; Git tiene scriptability y formatos establecidos.

Hay algunas cosas que difieren Mercurial de Git, pero hay otras cosas que las hacen similares. Ambos proyectos toman ideas prestadas el uno del otro. Por ejemplo, el comando hg bisect en Mercurial (anteriormente extensión bisect) se inspiró en el comando git bisect en Git, mientras que idea de git bundle fue inspirado por hg bundle.

Estructura del repositorio, almacenando revisiones

En Git hay cuatro tipos de objetos en su base de datos de objetos: blob objetos que contienen el contenido de un archivo, jerárquico árbol objetos que almacenan la estructura de directorios, incluyendo nombres de archivo y partes relevantes de los permisos de archivo (permiso ejecutable para archivos, siendo un enlace simbólico), commit objeto que contiene información de autoría, puntero repositorio en la revisión representado por un commit (a través de un objeto árbol del directorio superior del proyecto) y referencias a cero o más commits padre, y tag objetos que hacen referencia a otros objetos y pueden ser firmados usando PGP / GPG.

Git utiliza dos formas de almacenar objetos: el formato loose , donde cada objeto se almacena en un archivo separado (esos archivos se escriben una vez y nunca se modifican), y el formato packed donde muchos objetos se almacenan en fila india. La atomicidad de las operaciones es proporcionada por el hecho de que la referencia a un nuevo objeto se escribe (atómicamente, usando create + rename trick) después de escribir un objeto.

Los repositorios Git requieren mantenimiento periódico usando git gc (para reducir el espacio en disco y mejorar el rendimiento), aunque hoy en día Git lo hace automáticamente. (Este método proporciona una mejor compresión de los repositorios.)

Mercurial (hasta donde yo lo entiendo) almacena el historial de un archivo en un filelog (junto, creo, con metadatos adicionales como el seguimiento de cambio de nombre, y algo de información auxiliar); utiliza una estructura plana llamada manifest para almacenar la estructura de directorios, y una estructura llamada changelog que almacena información sobre conjuntos de cambios (revisiones), incluido el mensaje de confirmación y cero, uno o dos padres.

Mercurial utiliza diario de transacciones para proporcionar atomicidad de las operaciones, y se basa en truncando archivos para limpiar después de operación interrumpida. Los Revlogs son solo anexos.

Mirando la estructura del repositorio en Git versus en Mercurial, se puede ver que Git es más como una base de datos de objetos (o un sistema de archivos con dirección de contenido), y Mercurial más como una base de datos relacional de campo fijo tradicional.

Diferencias:
En Git los objetos tree forman una estructura jerárquica ; en Mercurial manifest el archivo es plano . En Git blobobject store una versiónde un contenido de un archivo; en Mercurial filelogalmacena toda la historia de un solo archivo (si no tenemos en cuenta aquí cualquier 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 historia de un solo archivo). Este problema podría no ser importante para el usuario final.

Debido a la estructura de registro fijo de Mercurial changelog, las confirmaciones en Mercurial solo pueden tener hasta dos padres; las confirmaciones en Git pueden tener más de dos padres (lo que se conoce como "octopus merge"). Si bien puedes (en teoría) reemplazar la fusión de octopus por una serie de fusiones de dos padres, esto podría causar complicaciones al convertir entre Mercurial y Git repositorio.

Por lo que sé, Mercurial no tiene el equivalente de etiquetas anotadas (objetos de etiquetas) de Git. Un caso especial de etiquetas anotadas son etiquetas firmadas (con firma PGP / GPG); equivalente en Mercurial se puede hacer usando GpgExtension , cuya extensión se distribuye junto con Mercurial. No puedes etiquetar objetos no confirmados en Mercurial como puedes 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 usar para verificar las etiquetas firmadas).

Referencias: ramas y etiquetas

En Git las referencias (ramas, ramas de seguimiento remoto y etiquetas) residen fuera de DAG de commits (como deberían). Las referencias en refs/heads/ namespace ( local branches) apuntan a commits, y son usualmente actualizadas por "git commit"; apuntan a la punta (head) de la rama, por eso dicho nombre. Referencias en refs/remotes/<remotename>/ espacio de nombres (ramas de seguimiento remoto) punto para confirmar, siga las ramas en el repositorio remoto <remotename>, y se actualizan con "git fetch" o equivalente. Las referencias en refs/tags/ espacio de nombres ( etiquetas) apuntan generalmente a commits (etiquetas ligeras) u objetos de etiqueta (etiquetas anotadas y firmadas), y no están destinadas a cambiar.

Tags

En Mercurial puede dar un nombre persistente a la revisión usando tag; las etiquetas se almacenan de manera similar a los patrones ignorados. Esto significa que las etiquetas visibles globalmente se almacenan en archivo .hgtags 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 para actualizar dicho archivo (por ejemplo, lee la revisión más reciente del archivo, que no está actualmente descargada); segundo, tiene que confirmar los cambios en este archivo para tener una nueva etiqueta visible para otros usuarios / otros repositorios (por lo que yo entiendo).

Mercurial también soporta etiquetas locales , almacenadas en hg/localtags, que no son visibles para otros (y por supuesto no son transferibles)

En Git las etiquetas son referencias fijas (constantes) con nombre a otros objetos (generalmente objetos de etiqueta, que a su vez apuntan a confirmaciones) almacenados en el espacio de nombres refs/tags/. De forma predeterminada, cuando se obtiene o empuja un conjunto de revisiones, git automáticamente obtiene o empuja etiquetas que apuntan a revisiones que se obtienen o empujan. Sin embargo, puede controlar hasta cierto punto qué etiquetas se obtienen o empujar.

Git trata las etiquetas ligeras (que apuntan directamente a las confirmaciones) y las etiquetas anotadas (que apuntan a objetos de etiqueta, que contienen mensajes de etiqueta que opcionalmente incluyen firma PGP, que a su vez apuntan a la confirmación) de manera ligeramente diferente, por ejemplo, por defecto considera solo las etiquetas anotadas cuando describe confirmaciones usando "git describe".

Git no tiene un equivalente estricto de las etiquetas locales en Mercurial. Sin embargo, las mejores prácticas de git recomiendan configurar desnudo público separado repositorio, en el que envías los cambios listos, y desde el que otros clonan y obtienen. Esto significa que las etiquetas (y ramas) que no envías, son privadas en tu repositorio. Por otro lado, también puede usar espacios de nombres que no sean heads, remotes o tags, por ejemplo local-tags para las etiquetas locales.

Opinión personal: En mi opinión, las etiquetas deben residir fuera del gráfico de revisiones, ya que son externas a él (son punteros en el gráfico de revisiones). Las etiquetas deben ser no versionada, pero transferible. La elección de Mercurial de usar un mecanismo similar al de ignorar archivos, significa que tiene que tratar .hgtags especialmente (el archivo en el árbol es transferible, pero ordinario es versionado), o tener etiquetas que son solo locales (.hg/localtags no es versionado, pero intransferible).

Ramas

En Git local branch (branch tip, o branch head) es una referencia con nombre a un commit, donde uno puede hacer crecer nuevos commits. Rama también puede significar línea de desarrollo activa, es decir, todas las confirmaciones alcanzables desde branch tip. Las ramas locales residen en el espacio de nombres refs/heads/, por lo que, por ejemplo, el nombre completo de la rama 'master' es 'refs/heads/master'.

La rama actual en Git (es decir, la rama eliminada, y la rama a la que irá la nueva confirmación) es la rama a la que hace referencia el HEAD ref. 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 detached HEAD ("git branch" muestra que estás en '(no branch)').

En Mercurial hay ramas anónimas (cabezas de rama), y uno puede usar marcadores (a través de extensión de marcadores). Tales 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 archivo .hg/bookmarks a un repositorio remoto. También puede usar hg id -r <bookmark> <url> para obtener el id de revisión de una punta actual de un marcador.

Desde 1.6 los marcadores pueden ser empujados/tirados. La página BookmarksExtension tiene una sección sobre Trabajando con Repositorios Remotos. Hay una diferencia en que en Mercurial los nombres de los marcadores son globales , mientras que la definición de 'remoto' en Git describe también la asignación de nombres de ramas desde los nombres en el repositorio remoto hasta los nombres de ramas locales de seguimiento remoto; por ejemplo refs/heads/*:refs/remotes/origin/* la asignación significa que uno puede encontrar el estado de la rama' maestra' ('refs / heads / master') en el repositorio remoto en la rama de seguimiento remoto' origin/master '('refs/remotes/origin/master').

Mercurial también ha llamado ramas nombradas, donde el nombre de la rama es incrustado en una confirmación (en un conjunto de cambios). Dicho nombre es global (transferido en fetch). Esos nombres de rama se registran permanentemente como parte de los metadatos del conjunto de cambios\u2019s. Con modern Mercurial puede cerrar "named branch" y detener la grabación del nombre de la rama. En este las puntas del mecanismo de las ramas se calculan sobre la marcha.

Las "ramas con nombre" de Mercurial deberían, en mi opinión, llamarse etiquetas de confirmación en cambio, porque es lo que son. Hay situaciones donde" named branch " puede tener múltiples tips (múltiples commits sin hijos), y también puede consistir en varias partes disjuntos de graph of revisions.

No hay un equivalente de esas "ramas embebidas" mercuriales en Git; además, la filosofía de Git es que mientras uno puede decir que la rama incluye algún commit, no significa que un commit pertenezca a alguna rama.

Tenga en cuenta que la documentación de Mercurial todavía propone usar 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 quieres empujar una sola rama ( una sola cabeza ), tienes que especifique la revisión de tip de la rama que desea enviar. Puede especificar la tip de 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 nombre de rama incrustada (rama con nombre).

Por lo que yo entiendo, si envías un rango de revisiones que contienen commits marcados como pertenecientes a alguna "rama con nombre" en lenguaje Mercurial, tendrás esta "rama con nombre" en el repositorio al que envías. Esto significa que los nombres de dichas ramas incrustadas ("ramas nombradas") son globales (con respecto a clones de un repositorio / proyecto dado).

Por defecto (sujeto a la variable de configuración push.default) "git push" o "git push remote>" Git empujaría ramas coincidentes, es decir, solo aquellas ramas locales que tienen su equivalente ya presente en el repositorio remoto en el que envías. Puede usar la opción --all para git-push ("git push all all") para empujar todas las ramas , usted puede usar " git push remoto> branch>" to push a given single branch, and you can use "git push remote> HEAD" to push current branch.

Todo lo anterior asume que Git no está configurado qué ramas enviar a través de variables de configuración remote.<remotename>.push.

Ramas en la búsqueda

Nota: aquí uso la terminología de Git donde "fetch" significa descargar cambios desde un repositorio remoto sin integrar esos cambios con el trabajo local. Esto es lo que hace "git fetch" y "hg pull".

Si lo entiendo correctamente, por defecto Mercurial obtiene todas las cabezas desde el 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 usando 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 lo hace que te transfieran. Todas las revisiones de" ramas con nombre " que obtienes pertenecen a ser transferidas. "hg pull" almacena las puntas de las ramas que obtuvo como cabezas anónimas sin nombre.

En Git de forma predeterminada (para el control remoto' origin 'creado por " git clone", y para los controles remotos creados mediante "git remote add") "git fetch" (o " git fetch <remote>") obtiene todas las ramas del repositorio remoto (desde el espacio de nombres refs/heads/), y las almacena en el espacio de nombres refs/remotes/. Esto significa, por ejemplo, que la rama llamada ' master '(nombre completo: 'refs / heads / master') en' origin ' remoto se almacenaría (guardaría) como 'origin/master' rama de seguimiento remoto (nombre completo: 'refs/remotes/origin/master').

Puedes obtener una sola rama en Git usando git fetch <remote> <branch> - Git almacenaría la(s) rama (s) solicitada (s) en FETCH_HEAD, que es algo similar a las cabezas Mercuriales sin nombre.

Estos son solo ejemplos de casos predeterminados de potente refspec Sintaxis de Git: con refspecs puede especificar y / o configurar cuál ramas uno quiere buscar, y dónde almacenarlos. Por ejemplo, el caso predeterminado "fetch all branches" está representado por '+refs/heads/*:refs/remotes/origin/*' comodín refspec, y "fetch single branch" es la abreviatura de 'refs/heads/:'. Las refspecs se utilizan para asignar nombres de ramas (refs) en el repositorio remoto a nombres de refs locales. Pero no necesitas saber (mucho) sobre refspecs para poder trabajar eficazmente con Git (gracias principalmente a " git remote" comando).

Opinión personal: Personalmente creo que las "ramas con nombre" (con nombres de rama incrustados en metadatos de conjuntos de cambios) en Mercurial son un diseño erróneo con su espacio de nombres global, especialmente para un sistema de control de versiones distribuido. Por ejemplo, tomemos el caso donde tanto Alice como Bob tienen "named branch" llamado 'for-joe' en sus repositorios, ramas que no tienen nada en común. En el repositorio de Joe, sin embargo, esas dos ramas serían maltratadas como una sola rama. Así que de alguna manera ha llegado a la convención de protección contra los choques de nombre de rama. Esto no es un 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'. Véase también Separar el nombre de la rama de la identidad de la rama problema planteado en Mercurial wiki.

Las "ramas de marcadores" de Mercurial carecen actualmente de distribución en el núcleo mecanismo.

Diferencias:
Esta área es una de las principales diferencias entre Mercurial y Git, como james woodyatt y Steve Losh dijeron en sus respuestas. Mercurial, por defecto, utiliza líneas de código ligeras anónimas, que en su terminología se llaman "cabezas". Git utiliza ramas con nombre ligero, con asignación inyectiva para asignar nombres de ramas en el repositorio remoto a nombres de ramas de seguimiento remoto. Git te" fuerza " a nombrar ramas (bueno, con la excepción de una sola rama sin nombre, la situación se llama CABEZA separada), pero creo que esto funciona mejor con flujos de trabajo con ramas pesadas, como el flujo de trabajo de ramas temáticas, lo que significa múltiples ramas en el paradigma de repositorio único.

Revisiones de nombres

En Git hay muchas formas de nombrar revisiones (descritas por ejemplo en git rev-parse manpage):

  • El nombre completo del objeto SHA1 (cadena hexadecimal de 40 bytes), o una subcadena de tales que es única dentro del repositorio
  • Un nombre de referencia simbólico, por ejemplo, 'master' (refiriéndose a la rama 'master'), o 'v1.5.0' (refiriéndose a la etiqueta), o 'origin/next' (refiriéndose a la rama de seguimiento remoto)
  • Un sufijo ^ al parámetro revision significa el primer padre de un objeto commit, ^n significa el n-ésimo padre de un commit de fusión. Un sufijo ~n para el parámetro revision significa el n-ésimo antepasado de un commit en línea directa del primer padre. Esos sufijos se pueden combinar, para formar el especificador de revisión siguiendo la ruta de un referencia simbólica, por ejemplo, 'pu~3^2~3'
  • Salida de "git describe", es decir, una etiqueta más cercana, opcionalmente seguida de un guion y un número de confirmaciones, seguido de un guion, 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 a á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 hg página de manual):

  • Un entero simple se trata como un número de revisión. Hay que recordar que los números de revisión son locales al repositorio dado; en otro repositorio pueden ser diferentes.
  • Los enteros negativos se tratan como desplazamientos secuenciales de la punta, con -1 denotando la punta, -2 denotando el revisión antes de la punta, y así sucesivamente. También son locales al 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 nombrada" (etiqueta de confirmación; la revisión dada por "rama nombrada" es tip (confirmación sin hijos) de todas las confirmaciones con la etiqueta número de revisión más grande si hay más de un consejo de este tipo)
  • El nombre reservado "tip" es una etiqueta especial que siempre identifica la revisión más reciente.
  • El nombre reservado "null" indica la revisión null.
  • El nombre reservado "."indica el padre del directorio de trabajo.

Diferencias
Como puedes ver comparando las listas anteriores, Mercurial ofrece números de revisión, locales al repositorio, mientras que Git no. ofrece compensaciones relativas solo desde 'tip' (rama actual), que son locales al repositorio (al menos sin ParentrevspecExtension), mientras que Git permite especificar cualquier confirmación posterior de cualquier tip.

La revisión más reciente se llama HEAD en Git, y "tip" en Mercurial; no hay ninguna revisión nula en Git. Tanto Mercurial como Git pueden tener muchos root (pueden tener más de una confirmación sin padres; esto suele ser el resultado de la unión de proyectos anteriormente separados).

Véase también: Muchos tipos diferentes de especificadores de revisión artículo en el Blog de Elías (newren).

Opinión personal: Creo que los números de revisión están sobrevalorados (al menos para el desarrollo distribuido y/o la historia no lineal / ramificada). En primer lugar, para un sistema de control de versiones distribuido tienen que ser locales al repositorio, o requieren tratar a algún repositorio de una manera especial como una autoridad central de numeración. Segundo, proyectos más grandes, con un historial más largo, puede tener un número de revisiones en un rango de 5 dígitos, por lo que solo ofrecen una ligera ventaja sobre los identificadores de revisión acortados a 6-7 caracteres, e implican un orden estricto mientras que las revisiones solo están ordenadas parcialmente (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. Sintaxis A..B comúnmente vista, que para la historia lineal significa rango de revisión que comienza en un (pero excluyendo A), y terminando en B (i. e. range is open from below), es una abreviatura ("azúcar sintáctico") para ^A B, que para la historia los comandos que atraviesan significan todas las confirmaciones alcanzables desde B, excluyendo aquellas alcanzables desde A. Esto significa que el comportamiento de A..B range es completamente predecible (y bastante útil) incluso si A no es antepasado de B: A..B significa entonces rango de revisiones del ancestro común de A y B (merge base) a la revisión B.

En los rangos de revisión mercurial son basado en el intervalo de números de revisión. Range se especifica usando la sintaxis A:B, y contrariamente a Git range 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 siguiente nota sobre la sintaxis A...B). Pero tal simplicidad viene con un precio: rango de revisión A: B tiene sentido solo 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 a 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 ' ances ancestry-path A..B ' in Git.

Git también tiene notación A...B para la diferencia simétrica de revisiones; significa A B --not $(git merge-base A B), que significa todas las confirmaciones accesibles desde A o B, pero excluyendo todas las confirmaciones alcanzables desde ambas (alcanzables desde ancestros comunes).

Cambia el nombre

Mercurial utiliza rename tracking para tratar el cambio de nombre de archivos. Esto significa que la información sobre el hecho de que un archivo fue renombrado se guarda en el momento de la confirmación; en Mercurial esta información se guarda en el formulario "enhanced diff" en filelog (file revlog) metadatos. La consecuencia de esto es que usted tiene que utilizar hg rename / hg mv... o tienes que recordar ejecute hg addremove para realizar la detección de cambio de nombre basada en similitud.

Git es único entre los sistemas de control de versiones en el sentido de que utiliza rename detection para tratar el cambio de nombre de archivos. Esto significa que el hecho de que el archivo fue renombrado se detecta en el momento en que se necesita: cuando se hace 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 usar --follow opción para seguir los cambios de nombre cuando se muestra el historial de un solo archivo. Ambos pueden seguir los renombres cuando se muestra el historial de líneas de un archivo en git blame / hg annotate.

En Git el comando git blame es capaz de seguir el movimiento del código, también moviendo (o copiando) código de un archivo a otro, incluso si el movimiento del código no es parte de wholesome file rename. Por lo que sé, esta característica es única para Git (en el momento de escribir esto, octubre de 2009).

Red protocolos

Tanto Mercurial como Git tienen soporte para obtener y enviar 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 obtener desde archivos bundle.

Mercurial soporta la búsqueda y el envío a través de protocolos SSH y HTTP. Para SSH se necesita una cuenta shell accesible en la máquina de destino y una copia de hg instalada / disponible. Para el acceso HTTP el hg-serve o Mercurial Se requiere la ejecución del script CGI y Mercurial debe instalarse en el equipo servidor.

Git soporta dos tipos de protocolos utilizados para acceder al repositorio remoto:

  • Los protocolos"inteligentes" , que incluyen acceso a través de SSH y a través del protocolo personalizado git:// (por git-daemon), requieren tener git instalado en el servidor. El intercambio en esos protocolos consiste en la negociación de cliente y servidor sobre qué objetos tienen en común, y luego generar y enviar un archivo de paquete. Git moderno incluye soporte para protocolo HTTP "inteligente".
  • Los protocolos" tontos " , que incluyen HTTP y FTP (solo para obtener), 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 gancho). El intercambio consiste en que el cliente recorre la cadena de confirmación y descarga objetos sueltos y archivos de paquetes según sea necesario. La desventaja es que se descarga más que estrictamente necesario (por ejemplo, en el caso de esquina cuando hay un solo packfile sería descargado todo, incluso al obtener sólo un par de revisiones), y que puede requerir muchas conexiones para terminar.

Extensión: scriptability vs extensiones (plugins)

Mercurial está implementado en Python, con algún código de núcleo escrito en C para el rendimiento. Proporciona API para escribir extensiones (plugins) como una forma de agregar características adicionales. Algunos de funcionalidad, como "ramas de marcadores" o revisiones de firma, se proporciona en extensiones distribuidas con Mercurial y requiere activarlo.

Git está implementado en C, Perl and shell scripts. Git proporciona muchos comandos de bajo nivel ( plumbing) adecuados para usar en scripts. La forma habitual de introducir nuevas características es escribirlo como Perl o shell script, y cuando la interfaz de usuario se estabiliza reescribirlo en C para el rendimiento, portabilidad, y en el caso de shell script evitando casos de esquina (este procedimiento se llama builtinification).

Git se basa y está construido alrededor de formatos [repositorios] y protocolos [red]. En lugar de los enlaces de idioma hay (parcial o completa) reimplementaciones de Git en otros idiomas (algunos de ellos son reimplementaciones parciales y envoltorios parcialmente alrededor de los comandos de git): JGit (Java, utilizado por EGit, Eclipse Git Plugin), Grit (Ruby), Dulwich (Python), git# (C#).


TL; DR{[63]]}

 443
Author: Jakub Narębski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-22 09:31:22

Creo que se puede tener una idea de lo que esos sistemas son similares o diferentes en whatching esos dos videos:

Linus Torvalds en Git ( http://www.youtube.com/watch?v=4XpnKHJAok8 )
Bryan O'Sullivan en Mercurial ( http://www.youtube.com/watch?v=JExtkqzEoHY )

Ambos son muy similares en diseño pero muy diferentes en implementaciones.

Uso Mercurial. Por lo que entiendo Git, una cosa importante git es diferente es que rastrea contenido de los archivos en lugar de los propios archivos. Linus dice que si mueves una función de un archivo a otro, Git te dirá el historial de esa sola función a través del movimiento.

También dicen que git es más lento sobre HTTP pero tiene su propio protocolo de red y servidor.

Git funciona mejor como cliente SVN thick que Mercurial. Puede tirar y empujar contra un servidor SVN. Esta funcionalidad todavía está en desarrollo en Mercurial

Tanto Mercurial como Git tienen muy buenas soluciones de alojamiento web disponibles (BitBucket y GitHub), pero Google Code solo admite Mercurial. Por cierto, tienen una comparación muy detallada de Mercurial y Git que hicieron para decidir cuál apoyar ( http://code.google.com/p/support/wiki/DVCSAnalysis ). Tiene mucha información buena.

 56
Author: artemb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-22 23:46:35

Escribí una entrada de blog sobre los modelos de ramificación de Mercurial hace un tiempo, e incluí comparaciones con el modelo de ramificación de git. Tal vez lo encuentres interesante: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial /

 29
Author: Steve Losh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 13:27:12

Uso ambos con bastante regularidad. La principal diferencia funcional está en la forma en que Git y Mercurial nombran las ramas dentro de los repositorios. Con Mercurial, los nombres de las ramas son clonados y arrastrados junto con sus conjuntos de cambios. Cuando agrega cambios a una nueva rama en Mercurial y los envía a otro repositorio, el nombre de la rama se envía al mismo tiempo. Por lo tanto, los nombres de las ramas son más o menos globales en Mercurial, y debe usar la extensión Bookmark para tener nombres ligeros solo locales (si los desea; Mercurial, por defecto, utiliza líneas de código ligeras anónimas, que en su terminología se llaman "cabezas"). En Git, los nombres de rama y su asignación inyectiva a ramas remotas se almacenan localmente y debe administrarlas explícitamente, lo que significa saber cómo hacerlo. Esto es más o menos donde Git obtiene su reputación de ser más difícil de aprender y usar que Mercurial.

Como otros notarán aquí, hay muchas y muchas diferencias menores. La cosa con las ramas es la gran diferenciador.

 25
Author: james woodyatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 05:26:52

Echa un vistazo a Git vs. Mercurial: Please Relax entrada de blog de Patrick Thomson, donde escribe:
Git es MacGyver, Mercurial es James Bond

Tenga en cuenta que esta entrada del blog es del 7 de agosto de 2008, y ambos SCM mejoraron mucho desde entonces.

 18
Author: Jakub Narębski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-22 23:27:40

Mercurial está casi completamente escrito en python. El núcleo de Git está escrito en C (y debería ser más rápido que el de Mercurial) y las herramientas escritas en sh, perl, tcl y utiliza utilidades GNU estándar. Por lo tanto, necesita traer todos estos utils e intérpretes con él al sistema que no los contiene (por ejemplo, Windows).

Ambos soportes funcionan con SVN, aunque el soporte de svn de AFAIK está roto para git en Windows (puede ser que solo sea desafortunado/lame, quién sabe). También hay extensiones que permiten interoperar entre git y Mercurial.

Mercurial tiene una buena integración Visual Studio. La última vez que lo comprobé, plugin para Git estaba funcionando, pero extremadamente lento.

Los conjuntos de comandos básicos son muy similares(init, clone, add, status, commit, push, pull, etc.). Por lo tanto, el flujo de trabajo básico será el mismo. Además, hay cliente similar a TortoiseSVN para ambos.

Las extensiones para Mercurial se pueden escribir en python (¡no es de extrañar!) y para git se pueden escribir en cualquier forma ejecutable (binario ejecutable, script de shell, etc.). Algunas extensiones son muy potentes, como git bisect.

 11
Author: elder_george,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 05:13:33

Si necesita un buen soporte para Windows, es posible que prefiera Mercurial. TortoiseHg (plugin de explorador de Windows) logra ofrecer una interfaz gráfica simple de usar a una herramienta bastante compleja. Como estado aquí, también tendrá un Visual Studio plugin . Sin embargo, la última vez que lo intenté, la interfaz SVN no funcionaba tan bien en Windows.

Si no te importa la interfaz de línea de comandos, recomendaría Git. No por razones técnicas, sino estratégicas. La tasa de adopción de git es mucho mayor. Basta con ver cuántos famosos proyectos de código abierto están cambiando de cvs / svn a Mercurial y cuántos están cambiando a Git. Vea cuántos proveedores de alojamiento de código/proyecto puede encontrar con soporte git en comparación con Mercurial hosting.

 11
Author: Eric Darchis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 23:50:00

Después de leer por todas partes que Mercurial es más fácil (que todavía creo que es, después de toda la comunidad de Internet es de la opinión), cuando empecé a trabajar con Git y Mercurial sentí Git es relativamente más simple para mí para adaptarse (empecé con Mercurial con TortoiseHg) cuando se trabaja desde la línea de comandos, principalmente porque los comandos de git fueron nombrados apropiadamente de acuerdo a mí y son menos en número. Mercurial tiene nombres diferentes para cada comando que hace una job, mientras que los comandos Git pueden ser multipropósito según la situación (por ejemplo, checkout). Mientras que Git era más difícil en ese entonces, ahora la diferencia es apenas sustancial. YMMV.. Con un buen cliente GUI como TortoiseHg, es cierto que era mucho más fácil trabajar con Mercurial y no tuve que recordar los comandos ligeramente confusos. No voy a entrar en detalles de cómo cada comando para la misma acción varió, pero aquí hay dos listas completas: 1 del propio sitio de Mercurial y 2nd de wikivs.

╔═════════════════════════════╦════════════════════════════════════════════════════════════════════════════════════════════════╗
║           Git               ║                Mercurial                                                                       ║
╠═════════════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════╣
║ git pull                    ║ hg pull -u                                                                                     ║
║ git fetch                   ║ hg pull                                                                                        ║
║ git reset --hard            ║ hg up -C                                                                                       ║
║ git revert <commit>         ║ hg backout <cset>                                                                              ║
║ git add <new_file>          ║ hg add <new_file> (Only equivalent when <new_file> is not tracked.)                            ║
║ git add <file>              ║ Not necessary in Mercurial.                                                                    ║
║ git add -i                  ║ hg record                                                                                      ║
║ git commit -a               ║ hg commit                                                                                      ║
║ git commit --amend          ║ hg commit --amend                                                                              ║
║ git blame                   ║ hg blame or hg annotate                                                                        ║
║ git blame -C                ║ (closest equivalent): hg grep --all                                                            ║
║ git bisect                  ║ hg bisect                                                                                      ║
║ git rebase --interactive    ║ hg histedit <base cset> (Requires the HisteditExtension.)                                      ║
║ git stash                   ║ hg shelve (Requires the ShelveExtension or the AtticExtension.)                                ║
║ git merge                   ║ hg merge                                                                                       ║
║ git cherry-pick <commit>    ║ hg graft <cset>                                                                                ║
║ git rebase <upstream>       ║ hg rebase -d <cset> (Requires the RebaseExtension.)                                            ║
║ git format-patch <commits>  ║ hg email -r <csets> (Requires the PatchbombExtension.)                                         ║
║   and git send-mail         ║                                                                                                ║
║ git am <mbox>               ║ hg mimport -m <mbox> (Requires the MboxExtension and the MqExtension. Imports patches to mq.)  ║
║ git checkout HEAD           ║ hg update                                                                                      ║
║ git log -n                  ║ hg log --limit n                                                                               ║
║ git push                    ║ hg push                                                                                        ║
╚═════════════════════════════╩════════════════════════════════════════════════════════════════════════════════════════════════╝

Git guarda internamente un registro de cada versión de los archivos confirmados, mientras que Hg guarda solo los conjuntos de cambios que pueden tener una huella más pequeña. Git hace que sea más fácil cambiar el historial en comparación con Hg, pero de nuevo es una función de odio o amor. Me gusta Hg para el primero y Git para el segundo.

Lo que echo de menos en Hg es la función de submódulo de Git. Hg tiene subrepos pero eso no es exactamente Git submodule.

El ecosistema alrededor de los dos también puede influir en la elección de uno: Git tiene para ser más popular (pero eso es trivial), Git tiene GitHub mientras que Mercurial tiene BitBucket, Mercurial tiene TortoiseHg para el cual no he visto un equivalente tan bueno para Git.

Cada uno tiene sus ventajas y desventajas, con cualquiera de ellos no vas a perder.

 11
Author: nawfal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-22 09:32:12

Echa un vistazo a El post de Scott Chacon de hace un tiempo.

Creo que git tiene la reputación de ser "más complicado", aunque en mi experiencia no es más complicado de lo que debe ser. IMO, el modelo git es way más fácil de entender (las etiquetas contienen commits (y los punteros a cero o más commits primarios) contienen árboles contienen blobs y otros árboles... hacer).

No es solo mi experiencia que git no es más confuso que mercurial. Lo recomendaría de nuevo leyendo este post de Scott Chacon sobre el asunto.

 8
Author: Dustin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-03 17:02:09

He usado Git durante un poco más de un año en mi trabajo actual, y antes de eso, usé Mercurial durante un poco más de un año en mi trabajo anterior. Voy a proporcionar una evaluación desde la perspectiva de un usuario.

Primero, ambos son sistemas de control de versiones distribuidos. Los sistemas de control de versiones distribuidos requieren un cambio en la mentalidad de los sistemas de control de versiones tradicionales, pero en realidad funcionan mucho mejor en muchos aspectos una vez que uno los entiende. Por esta razón, considero tanto Git como Mercurial muy superior a Subversion, Perforce, etc. La diferencia entre los sistemas de control de versiones distribuidos y los sistemas de control de versiones tradicionales es mucho mayor que la diferencia entre Git y Mercurial.

Sin embargo, también hay diferencias significativas entre Git y Mercurial que hacen que cada uno se adapte mejor a su propio subconjunto de casos de uso.

Mercurial es más fácil de aprender. Llegué al punto en el que rara vez tuve que hacer referencia a la documentación o notas después de unas semanas de usando Mercurial; todavía tengo que hacer referencia a mis notas regularmente con Git, incluso después de usarlo durante un año. Git es considerablemente más complicado.

Esto se debe en parte a que Mercurial es simplemente más limpio. Rara vez tiene que ramificar manualmente en Mercurial; Mercurial creará una rama anónima automáticamente para usted si y cuando lo necesite. La nomenclatura Mercurial es más intuitiva; no tienes que preocuparte por la diferencia entre "fetch" y "pull" como lo haces con Git. Mercurial es un un poco menos buggy. Hay problemas de sensibilidad de mayúsculas y minúsculas en los nombres de archivo que solían causar problemas al enviar proyectos a través de plataformas con Git y Mercurial; esto se solucionó en Mercurial hace algún tiempo, mientras que no se habían solucionado en Git la última vez que revisé. Puedes decirle a Mercurial sobre el cambio de nombre de los archivos; con Git, si no detecta el cambio de nombre automáticamente, una propuesta muy acertada o errada en mi experiencia, el cambio de nombre no se puede rastrear en absoluto.

La otra razón para el adicional de Git complicación, sin embargo, es que gran parte de ella es necesaria para soportar características y potencia adicionales. Sí, es más complicado manejar la ramificación en Git , pero por otro lado, una vez que tienes las ramas, no es demasiado difícil hacer cosas con esas ramas que son virtualmente imposibles en Mercurial. Rebasar ramas es una de estas cosas: puedes mover tu rama para que su base, en lugar de ser el estado del tronco cuando ramificaste, sea el estado del tronco ahora; esto en gran medida simplifica el historial de versiones cuando hay muchas personas trabajando en la misma base de código, ya que cada uno de los push to trunk puede aparecer secuencial, en lugar de entrelazado. Del mismo modo, es mucho más fácil colapsar varias confirmaciones en su rama en una sola confirmación, lo que puede ayudar a mantener limpio el historial de control de versiones: idealmente, todo el trabajo en una característica puede aparecer como una sola confirmación en el tronco, reemplazando todas las confirmaciones menores y subramas que el desarrollador puede haber hecho mientras se desarrolla la característica.

En última instancia, creo que la elección entre Mercurial y Git debe depender de cuán grandes sean sus proyectos de control de versiones, medidos en términos del número de personas que trabajan en ellos simultáneamente. Si tienes un grupo de una docena o más trabajando en una sola aplicación web monolítica, por ejemplo, las herramientas de administración de ramas más potentes de Git lo harán mucho mejor para tu proyecto. Por otro lado, si tu equipo está desarrollando una sistema distribuido, con solo uno o dos desarrolladores trabajando en cualquier componente al mismo tiempo, el uso de un repositorio Mercurial para cada uno de los proyectos de componentes permitirá que el desarrollo proceda de manera más fluida con menos sobrecarga de administración de repositorios.

En pocas palabras: si tienes un gran equipo desarrollando una sola aplicación enorme, usa Git; si tus aplicaciones individuales son pequeñas, con cualquier escala que provenga del número en lugar del tamaño de dichas aplicaciones, usa Mercurial.

 5
Author: Warren Dew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-11 05:01:32

Una diferencia totalmente no relacionada con los propios DVCSs:

Git parece ser muy popular entre los desarrolladores de C. Git es el repositorio de facto para el Kernel de Linux y esta puede ser la razón por la que es tan popular entre los desarrolladores de C. Esto es especialmente cierto para aquellos que tienen el lujo de trabajar solo en el mundo Linux / Unix.

Los desarrolladores de Java parecen preferir Mercurial a Git. Posiblemente hay dos razones para ello: Una es que una serie de proyectos Java muy grandes son alojado en Mercurial, incluyendo el propio JDK. Otra es que la estructura y la documentación limpia de Mercurial apela a las personas que vienen del campamento de Java, mientras que estas personas encuentran que Git es inconsistente en el nombramiento de comandos wrt y carece de documentación. No estoy diciendo que eso sea cierto, estoy diciendo que la gente se ha acostumbrado a algo de su hábitat habitual y luego tienden a elegir DVCS de eso.

Los desarrolladores de Python prefieren casi exclusivamente Mercurial, supongo. Hay en realidad no hay razón racional para eso, aparte del hecho de que Mercurial se basa en Python. (Yo uso Mercurial también y realmente no entiendo por qué la gente hace un alboroto sobre el lenguaje de implementación de los DVCS. No entiendo una palabra de Python y si no fuera por el hecho de que está en alguna parte que se basa en Python, entonces no lo habría sabido).

No creo que se pueda decir que un DVCS se ajuste mejor a un idioma que otro, por lo que no debería elegir entre eso. Pero en realidad las personas eligen (en parte) en función de a qué DVC están más expuestas como parte de su comunidad.

(no, no tengo estadísticas de uso para respaldar mis afirmaciones anteriores .. todo se basa en mi propia subjetividad)

 4
Author: peterh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-28 11:21:10