Si los entiendo correctamente (y estoy lejos de ser un experto en cada uno), fundamentalmente cada uno tiene una filosofía diferente. La primera vez que usé mercurial fue durante 9 meses. Ahora he usado git para 6.
hg es un software de control de versiones. Su objetivo principal es rastrear las versiones de una pieza de software.
git es un sistema de archivos basado en el tiempo. Su objetivo es agregar otra dimensión a un sistema de archivos. La mayoría tiene archivos y carpetas, git agrega tiempo. El hecho de que funcione increíblemente como VCS es un subproducto de su diseño.
En hg, hay una historia de todo el proyecto que siempre intenta mantener. Por defecto, creo que hg quiere todos los cambios en todos los objetos por parte de todos los usuarios al empujar y tirar.
En git solo hay un grupo de objetos y estos archivos de seguimiento (ramas / cabezas) que determinan qué conjunto de esos objetos representan el árbol de archivos en un estado particular. Cuando empuja o tira, git solo envía los objetos necesarios para las ramas particulares que empuja o tira, que es un pequeño subconjunto de todos los objetos.
En lo que respecta a git, no hay un "1 proyecto". Podrías tener 50 proyectos en el mismo repositorio y a git no le importaría. Cada uno podría gestionarse por separado en el mismo repositorio y vivir bien.
El concepto de sucursales de Hg es ramificaciones del proyecto principal o ramificaciones de sucursales, etc. Git no tiene ese concepto. Una rama en git es solo un estado del árbol, todo es una rama en git. Qué rama es oficial, actual o más reciente no tiene significado en git.
No sé si eso tenía sentido. Si pudiera dibujar imágenes, hg podría verse así donde cada commit es uno
o---o---o
/
o---o---o---o---o---o---o---o
\ /
o---o---o
Un árbol con una sola raíz y ramas saliendo de él. Si bien git puede hacer eso y, a menudo, las personas lo usan de esa manera, eso no se aplica. Una imagen de git, si existe, podría verse fácilmente así
o---o---o---o---o
o---o---o---o
\
o---o
o---o---o---o
De hecho, de alguna manera ni siquiera tiene sentido mostrar ramas en git.
Una cosa que es muy confusa para la discusión, git y mercurial tienen algo llamado "rama" pero no son remotamente las mismas cosas. Se produce una rama en mercurial cuando hay conflictos entre diferentes repositorios. Una rama en git es aparentemente similar a un clon en hg. Pero un clon, aunque podría dar un comportamiento similar, definitivamente no es lo mismo. Considéreme probar estos en git vs hg usando el repositorio de cromo que es bastante grande.
$ time git checkout -b some-new-branch
Switched to new branch 'some-new-branch'
real 0m1.759s
user 0m1.596s
sys 0m0.144s
Y ahora en hg usando clon
$ time hg clone project/ some-clone/
updating to branch default
29387 files updated, 0 files merged, 0 files removed, 0 files unresolved.
real 0m58.196s
user 0m19.901s
sys 0m8.957
Ambas son carreras calientes. Es decir, los ejecuté dos veces y esta es la segunda carrera. hg clone es lo mismo que git-new-workdir. Ambos crean un directorio de trabajo completamente nuevo casi como si hubieras escritocp -r project project-clone
. Eso no es lo mismo que hacer una nueva rama en git. Es mucho más pesado. Si hay un verdadero equivalente de la ramificación de git en hg, no sé qué es.
Entiendo que, en algún nivel, hg y git podrían hacer cosas similares. Si es así, todavía hay una gran diferencia en el flujo de trabajo al que lo llevan. En git, el flujo de trabajo típico es crear una rama para cada característica.
git checkout master
git checkout -b add-2nd-joypad-support
git checkout master
git checkout -b fix-game-save-bug
git checkout master
git checkout -b add-a-star-support
Eso acaba de crear 3 ramas, cada una basada en una rama llamada master. (Estoy seguro de que hay alguna forma en git para hacer esas 1 línea cada una en lugar de 2)
Ahora para trabajar en uno solo hago
git checkout fix-game-save-bug
y empezar a trabajar Cometer cosas, etc. Cambiar entre ramas incluso en un proyecto tan grande como el cromo es casi instantáneo. En realidad no sé cómo hacer eso en hg. No es parte de ningún tutorial que haya leído.
Otra gran diferencia. El escenario de Git.
Git tiene esta idea de un escenario. Puedes pensarlo como una carpeta oculta. Cuando se compromete, solo se compromete lo que está en el escenario, no los cambios en su árbol de trabajo. Eso puede sonar extraño. Si desea confirmar todos los cambios en su árbol de trabajo, haría lo git commit -a
que agrega todos los archivos modificados a la etapa y luego los confirma.
¿Cuál es el punto del escenario entonces? Puedes separar fácilmente tus commits. Imagina que editaste joypad.cpp y gamesave.cpp y quieres comprometerlos por separado
git add joypad.cpp // copies to stage
git commit -m "added 2nd joypad support"
git add gamesave.cpp // copies to stage
git commit -m "fixed game save bug"
Git incluso tiene comandos para decidir qué líneas particulares en el mismo archivo que desea copiar en el escenario para que también pueda dividir esas confirmaciones por separado. ¿Por qué querrías hacer eso? Porque como confirmaciones separadas, otros pueden obtener solo las que desean o, si hubo un problema, pueden revertir solo la confirmación que tuvo el problema.