Hace un tiempo que uso Subversion para mis proyectos personales.
Cada vez escucho más cosas buenas sobre Git y Mercurial, y DVCS en general.
Me gustaría darle un giro a todo el DVCS, pero no estoy muy familiarizado con ninguna de las opciones.
¿Cuáles son algunas de las diferencias entre Mercurial y Git?
Nota: Estoy no tratar de averiguar cuál es el "mejor" o incluso cuál debo empezar. Principalmente busco áreas clave donde sean similares y donde sean diferentes, porque me interesa saber cómo difieren en términos de implementación y filosofía.
Respuestas:
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
.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 elrefs/tags/
espacio de nombres y, de forma predeterminada, se siguen automáticamente al buscar y requieren un empuje explícito.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 elgit bisect
comando en Git, mientras que la idea degit bundle
se inspiró enhg 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 elrefs/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 elrefs/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
otags
, 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 usarhg 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 elrefs/heads/
espacio de nombres), y las almacena enrefs/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 ):
^
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'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 ):
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 delA..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 laA...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; significaA 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 ejecutarhg 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 engit 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:
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".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
fuente
Creo que puedes tener una idea de en qué se parecen o difieren esos sistemas al ver 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.
Yo uso Mercurial. Por lo que yo entiendo Git, una cosa importante que Git es diferente es que rastrea el contenido de los archivos en lugar de los archivos en sí. Linus dice que si mueve una función de un archivo a otro, Git le contará el historial de esa única función a través del movimiento.
También dicen que git es más lento que HTTP pero tiene su propio protocolo de red y servidor.
Git funciona mejor como un cliente grueso SVN que Mercurial. Puede tirar y empujar contra un servidor SVN. Esta funcionalidad aún está en desarrollo en Mercurial
Tanto Mercurial como Git tienen soluciones de alojamiento web muy buenas 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 admitir ( http://code.google.com/p/support/wiki/DVCSAnalysis ). Tiene mucha buena información.
fuente
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. Quizás lo encuentres interesante: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/
fuente
Yo uso ambos con bastante regularidad. La principal diferencia funcional está en la forma en que Git y Mercurial se ramifican dentro de los repositorios. Con Mercurial, los nombres de las ramas se clonan y se extraen junto con sus conjuntos de cambios. Cuando agrega cambios a una nueva rama en Mercurial y lo transfiere a otro repositorio, el nombre de la rama se transfiere al mismo tiempo. Por lo tanto, los nombres de las sucursales son más o menos globales en Mercurial, y debe usar la extensión Bookmark para tener nombres ligeros solo locales (si lo desea; Mercurial, de forma predeterminada, utiliza líneas de código ligeras anónimas, que en su terminología son llamado "cabezas"). En Git, los nombres de las sucursales y su asignación inyectiva a las sucursales remotas se almacenan localmente y debe administrarlos explícitamente, lo que significa saber cómo hacerlo.
Como otros notarán aquí, hay muchísimas diferencias menores. Lo que pasa con las ramas es el gran diferenciador.
fuente
Eche un vistazo a Git vs. Mercurial: Por favor, relájese en la publicación de blog de Patrick Thomson, donde escribe:
Git es MacGyver , Mercurial es James Bond
Tenga en cuenta que esta publicación de blog es del 7 de agosto de 2008, y tanto SCM mejoró mucho desde entonces.
fuente
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 llevar todas estas utilidades e intérpretes al sistema que no las contiene (por ejemplo, Windows).
Ambos soportes funcionan con SVN, aunque el soporte de AFAIK svn está roto para git en Windows (puede ser que solo tenga mala suerte / cojo, quién sabe). También hay extensiones que permiten interoperar entre git y Mercurial.
Mercurial tiene una buena integración de Visual Studio . La última vez que lo comprobé, el complemento para Git funcionaba pero era extremadamente lento.
Los conjuntos de comandos básicos son muy similares (init, clone, add, status, commit, push, pull, etc.). Entonces, el flujo de trabajo básico será el mismo. Además, hay un 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 locamente poderosas, como
git bisect
.fuente
Si necesita un buen soporte de Windows, puede preferir Mercurial. TortoiseHg (complemento del explorador de Windows) se las arregla para ofrecer una interfaz gráfica fácil de usar a una herramienta bastante compleja. Como se indica aquí, también tendrá un complemento de Visual Studio . Sin embargo, la última vez que lo intenté, la interfaz SVN no funcionó tan bien en Windows.
Si no te importa la interfaz de línea de comandos, recomendaría Git. No por razones técnicas, sino por razones estratégicas. La tasa de adopción de git es mucho mayor. Solo vea cuántos proyectos famosos 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 el alojamiento Mercurial.
fuente
Después de leer todo eso, Mercurial es más fácil (lo que todavía creo que es, después de que toda la comunidad de Internet es de la opinión), cuando comencé a trabajar con Git y Mercurial sentí que Git es relativamente más fácil de adaptar (comencé con Mercurial con TortoiseHg) cuando se trabaja desde la línea de comandos, principalmente porque los comandos git fueron nombrados apropiadamente de acuerdo a mí y son menos numerosos. Mercurial tiene diferentes nombres para cada comando que realiza un trabajo distinto, mientras que los comandos Git pueden ser multipropósito según la situación (por ejemplo,
checkout
) Si bien Git era más difícil en aquel entonces, ahora la diferencia es apenas sustancial. YMMV .. Con un buen cliente GUI como TortoiseHg, es cierto que fue mucho más fácil trabajar con Mercurial y no tuve que recordar los comandos ligeramente confusos. No voy a entrar en detalles sobre cómo variaba cada comando para la misma acción, pero aquí hay dos listas completas: 1 del sitio de Mercurial y la segunda de wikivs .Git guarda un registro de cada versión de archivos comprometidos internamente, 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 la historia en comparación con Hg, pero de nuevo es una función de odiar o amar. Me gusta Hg para el primero y Git para el segundo.
Lo que extraño en Hg es la función de submódulo de Git. Hg tiene subrepos pero eso no es exactamente el submódulo Git.
El ecosistema alrededor de los dos también puede influir en la elección de uno: Git tiene que 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.
fuente
Echa un vistazo a la publicación de Scott Chacon desde 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 debería ser. En mi opinión, el modelo git es mucho más fácil de entender (las etiquetas contienen confirmaciones (y los punteros a cero o más confirmaciones principales) contienen árboles contienen blobs y otros árboles ... hecho).
No es solo mi experiencia que git no es más confuso que mercurial. Recomiendo nuevamente leer esta publicación de blog de Scott Chacon sobre el tema.
fuente
.hgtags
cuando has revisado la revisión 1.0. Sin embargo, no necesita mirar dentro.hgtags
y encontrará quehg tags
todavía enumera todas las etiquetas. Además, este comportamiento es una consecuencia simple del almacenamiento de etiquetas en un archivo controlado por versión; nuevamente, el modelo es fácil de entender y muy predecible .Utilicé Git durante poco más de un año en mi trabajo actual, y antes de eso, utilicé 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 de mentalidad de los sistemas de control de versiones tradicionales, pero en realidad funcionan mucho mejor de muchas maneras una vez que uno los comprende. Por esta razón, considero que Git y Mercurial son muy superiores 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 simple de aprender. Llegué al punto en que rara vez tuve que referirme a la documentación o notas después de unas semanas de usar Mercurial; Todavía tengo que consultar 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. Raramente tiene que bifurcarse manualmente en Mercurial; Mercurial creará una sucursal anónima automáticamente para usted si lo necesita. La nomenclatura mercurial es más intuitiva; no tiene que preocuparse por la diferencia entre "buscar" y "extraer" como lo hace con Git. Mercurial es un poco menos buggy. Hay problemas de mayúsculas y minúsculas en los nombres de archivos que solían causar problemas al impulsar 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 lo revisé. Puede 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 errónea en mi experiencia, el cambio de nombre no se puede rastrear en absoluto.
Sin embargo, la otra razón de la complicación adicional de Git es que se necesita mucho para admitir funciones 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 prácticamente imposibles en Mercurial. Rebasar ramas es una de estas cosas: puede mover su rama de modo que su base, en lugar de ser el estado del tronco cuando se ramificó, sea el estado del tronco ahora; esto simplifica enormemente el historial de versiones cuando hay muchas personas trabajando en la misma base de código, ya que cada uno de los empujes al tronco puede aparecer de forma secuencial, en lugar de entrelazarse. Del mismo modo, es mucho más fácil contraer varias confirmaciones en su rama en una sola confirmación,
En última instancia, creo que la elección entre Mercurial y Git debería depender de qué tan grandes sean sus proyectos de control de versiones, medidos en términos de la cantidad de personas que trabajan en ellos simultáneamente. Si tiene 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 sucursales más potentes de Git lo harán mucho mejor para su proyecto. Por otro lado, si su equipo está desarrollando un sistema distribuido heterogéneo, 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 avance más suavemente con menos gestión del repositorio de gastos generales.
En pocas palabras: si tiene un gran equipo desarrollando una sola aplicación enorme, use Git; Si sus aplicaciones individuales son pequeñas, y cualquier escala proviene del número en lugar del tamaño de dichas aplicaciones, use Mercurial.
fuente
Una diferencia totalmente ajena a los DVCS mismos:
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 favorecer a Mercurial sobre Git. Posiblemente hay dos razones para eso: una es que varios proyectos Java muy grandes están alojados en Mercurial, incluido el JDK mismo. Otra es que la estructura y la documentación limpia de Mercurial atrae a las personas que vienen del campamento de Java, mientras que esas personas encuentran que el comando wrt inconsistente de Git nombra y carece de documentación. No digo que eso sea realmente cierto, digo que las personas se han acostumbrado a algo de su hábitat habitual y luego tienden a elegir DVCS de eso.
Los desarrolladores de Python favorecen casi exclusivamente a Mercurial, supongo. En realidad, no hay una razón racional para eso aparte del hecho de que Mercurial se basa en Python. (También uso Mercurial y realmente no entiendo por qué la gente hace tanto escándalo por el lenguaje de implementación del DVCS. No entiendo una palabra de Python y si no fuera por el hecho de que aparece en alguna parte que se basa en Python, entonces no lo habría sabido).
No creo que pueda decir que un DVCS se adapta mejor a un idioma que otro, por lo que no debe elegir entre eso. Pero, en realidad, las personas eligen (en parte) según el DVCS al que están más expuestos como parte de su comunidad.
(no, no tengo estadísticas de uso para respaldar mis afirmaciones anteriores ... todo se basa en mi propia subjetividad)
fuente