Skip to content

Latest commit

 

History

History
398 lines (333 loc) · 15.1 KB

File metadata and controls

398 lines (333 loc) · 15.1 KB

Git y Mercurial

El universo DVCS es más grande que el de Git. De hecho, hay muchos otros sistemas en este espacio, cada uno con su propio ángulo sobre cómo hacer el control de versión distribuida correctamente. Aparte de Git, el más popular es Mercurial, y los dos son muy similares en muchos aspectos.

La buena noticia, si prefiere el comportamiento del cliente de Git pero está trabajando con un proyecto cuyo código fuente está controlado con Mercurial, es que hay una manera de usar Git como cliente para un repositorio alojado en Mercurial. Dado que la forma en que Git habla con los repositorios del servidor es a través de controles remotos, no debería sorprendernos que este puente se implemente como un ayudante remoto. El nombre del proyecto es 'git-remote-hg', y se puede encontrar en https://github.com/felipec/git-remote-hg.

git-remote-hg

Primero, necesita instalar git-remote-hg. Esto básicamente implica dejar caer su archivo en algún lugar de su camino, así:

$ curl -o ~/bin/git-remote-hg \
  https://raw.githubusercontent.com/felipec/git-remote-hg/master/git-remote-hg
$ chmod +x ~/bin/git-remote-hg
  1. asumiendo que ~ / bin está en su` $ PATH`. Git-remote-hg tiene otra dependencia: la biblioteca mercurial para Python. Si tiene instalado Python, es tan sencillo como:

$ pip install mercurial

(Si no tiene instalado Python, visite https://www.python.org/ y consígalo primero.)

Lo último que necesitará es el cliente Mercurial. Vaya a https://www.mercurial-scm.org/ e instálelo si aún no lo ha hecho.

Ahora está listo para el rock. Todo lo que necesita es un repositorio Mercurial al que pueda presionar. Afortunadamente, todos los repositorios de Mercurial pueden actuar de esta manera, así que sólo usaremos el repositorio de "hola mundo" que todos usan para aprender Mercurial:

$ hg clone http://selenic.com/repo/hello /tmp/hello
Empezando

Ahora que tenemos un repositorio ``server-side'' adecuado, podemos pasar por un flujo de trabajo típico. Como verá, estos dos sistemas son lo suficientemente similares como para que no haya mucha fricción.

Como siempre con Git, primero clonamos:

$ git clone hg::/tmp/hello /tmp/hello-git
$ cd /tmp/hello-git
$ git log --oneline --graph --decorate
* ac7955c (HEAD, origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master, master) Create a makefile
* 65bb417 Create a standard "hello, world" program

Notará que el uso de un repositorio de Mercurial utiliza el comando git clone estándar. Esto se debe a que git-remote-hg está funcionando a un nivel bastante bajo, utilizando un mecanismo similar a como se implementa el protocolo HTTP / S de Git (auxiliares remotos). Dado que Git y Mercurial están diseñados para que cada cliente tenga una copia completa del historial del repositorio, este comando hace un clon completo, incluyendo todo el historial del proyecto, y lo hace con bastante rapidez.

El comando de registro muestra dos confirmaciones, la última de las cuales es señalada por un montón de refs. Resulta que algunos de estos no están realmente allí. Echemos un vistazo a lo que realmente está en el directorio .git:

$ tree .git/refs
.git/refs
├── heads
│   └── master
├── hg
│   └── origin
│       ├── bookmarks
│       │   └── master
│       └── branches
│           └── default
├── notes
│   └── hg
├── remotes
│   └── origin
│       └── HEAD
└── tags

9 directories, 5 files

'Git-remote-hg' está tratando de hacer las cosas más idiomáticamente 'Git-esque', pero bajo el capó es la gestión de la cartografía conceptual entre dos sistemas ligeramente diferentes. El directorio refs/hg es donde se almacenan las referencias remotas reales. Por ejemplo, el refs/hg/origen/branches/default es un archivo 'ref' de Git que contiene el SHA-1 que comienza con `ac7955c'', que es el 'commit' que señala `master. Así que el directorio refs/hg es como un`refs/remotes/origen' falso, pero tiene la distinción añadida entre marcadores y ramas.

El archivo notes/hg es el punto de partida de cómo 'git-remote-hg' asigna los hashes de 'commit' de Git a los identificadores de cambios de Mercurial. Vamos a explorar un poco:

$ cat notes/hg
d4c10386...

$ git cat-file -p d4c10386...
tree 1781c96...
author remote-hg <> 1408066400 -0800
committer remote-hg <> 1408066400 -0800

Notes for master

$ git ls-tree 1781c96...
100644 blob ac9117f...	65bb417...
100644 blob 485e178...	ac7955c...

$ git cat-file -p ac9117f
0a04b987be5ae354b710cefeba0e2d9de7ad41a9

Así que refs/notes/hg apunta a un árbol, que en la base de datos de objetos Git es una lista de otros objetos con nombres. Git ls-tree genera el modo, el tipo, el hash de objeto y el nombre de archivo de elementos dentro de un árbol. Una vez que excavamos hacia abajo a uno de los elementos del árbol, encontramos que en su interior hay un blob llamado ac9117f'' (el hash SHA-1 del 'commit' apuntado por master), con contenidos 0a04b98''. Que es el identificador del conjunto de cambios Mercurial en la punta de la rama default).

La buena noticia es, que en general, no tenemos que preocuparnos por todo esto. El flujo de trabajo típico no será muy diferente de trabajar con un control remoto de Git.

Hay una cosa más a la que debemos atender antes de continuar: 'ignore'. Mercurial y Git usan un mecanismo muy similar para esto, pero es probable que no quiera realmente comprometer un archivo .gitignore en un repositorio de Mercurial. Afortunadamente, Git tiene una forma de ignorar los archivos que son locales a un repositorio en disco, y el formato Mercurial es compatible con Git, por lo que sólo tiene que copiarlo:

$ cp .hgignore .git/info/exclude

El archivo .git / info / exclude 'actúa como un .gitignore`, pero no está incluido en 'commits'.

Flujo de Trabajo

Supongamos que hemos hecho algunos trabajos e hicimos algunos 'commit' en la rama master y estamos listos para enviarlo al repositorio remoto. A continuación, le mostramos nuestro repositorio:

$ git log --oneline --graph --decorate
* ba04a2a (HEAD, master) Update makefile
* d25d16f Goodbye
* ac7955c (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Create a makefile
* 65bb417 Create a standard "hello, world" program

Nuestra rama master está a dos compromisos por delante de origin/master, pero estos dos 'commits' sólo existen en nuestra máquina local. Veamos si alguien más ha estado haciendo un trabajo importante al mismo tiempo:

$ git fetch
From hg::/tmp/hello
   ac7955c..df85e87  master     -> origin/master
   ac7955c..df85e87  branches/default -> origin/branches/default
$ git log --oneline --graph --decorate --all
* 7b07969 (refs/notes/hg) Notes for default
* d4c1038 Notes for master
* df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation
| * ba04a2a (HEAD, master) Update makefile
| * d25d16f Goodbye
|/
* ac7955c Create a makefile
* 65bb417 Create a standard "hello, world" program

Puesto que utilizamos el indicador --all, vemos las `notes refs'' que son utilizadas internamente por 'git-remote-hg', pero podemos ignorarlas. El resto es lo que esperábamos; `origin / master ha avanzado por una comisión, y nuestra historia ha divergido ahora. A diferencia de los otros sistemas con los que trabajamos en este capítulo, Mercurial es capaz de manejar fusiones, por lo que no vamos a hacer nada extravagante.

$ git merge origin/master
Auto-merging hello.c
Merge made by the 'recursive' strategy.
 hello.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git log --oneline --graph --decorate
*   0c64627 (HEAD, master) Merge remote-tracking branch 'origin/master'
|\
| * df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation
* | ba04a2a Update makefile
* | d25d16f Goodbye
|/
* ac7955c Create a makefile
* 65bb417 Create a standard "hello, world" program

Perfecto. Hacemos las pruebas y todo pasa, así que estamos listos para compartir nuestro trabajo con el resto del equipo:

$ git push
To hg::/tmp/hello
   df85e87..0c64627  master -> master

¡Eso es! Si echa un vistazo al repositorio de Mercurial, verá que esto hizo lo que esperábamos:

$ hg log -G --style compact
o    5[tip]:4,2   dc8fa4f932b8   2014-08-14 19:33 -0700   ben
|\     Merge remote-tracking branch 'origin/master'
| |
| o  4   64f27bcefc35   2014-08-14 19:27 -0700   ben
| |    Update makefile
| |
| o  3:1   4256fc29598f   2014-08-14 19:27 -0700   ben
| |    Goodbye
| |
@ |  2   7db0b4848b3c   2014-08-14 19:30 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

El conjunto de cambios numerado 2 fue hecho por Mercurial, y los conjuntos de cambios numerados 3 y 4 fueron hechos por 'git-remote-hg', al empujar los 'commit' hechos con Git.

Branches(Ramas) y Bookmarks(Marcadores)

Git tiene sólo un tipo de rama: una referencia que se mueve cuando se hacen los compromisos. En Mercurial, este tipo de referencia se llama marcador, y se comporta de la misma manera que una rama de Git.

El concepto de Mercurial de una "rama" es más pesado. La rama en la que se realiza un conjunto de cambios se registra con el conjunto de cambios, lo que significa que siempre estará en el historial del repositorio. He aquí un ejemplo de un 'commit' que se hizo en la rama develop:

$ hg log -l 1
changeset:   6:8f65e5e02793
branch:      develop
tag:         tip
user:        Ben Straub <[email protected]>
date:        Thu Aug 14 20:06:38 2014 -0700
summary:     More documentation

Observe la línea que comienza con ``branch''. Git no puede realmente replicar esto (y no necesita, ambos tipos de rama puede representarse como una referencia Git), pero 'git-remote-hg' necesita entender la diferencia, porque Mercurial se preocupa.

Crear marcadores de Mercurial es tan fácil como crear ramas de Git. En el lado Git:

$ git checkout -b featureA
Switched to a new branch 'featureA'
$ git push origin featureA
To hg::/tmp/hello
 * [new branch]      featureA -> featureA

Eso es todo al respecto. En el lado mercurial, se ve así:

$ hg bookmarks
   featureA                  5:bd5ac26f11f9
$ hg log --style compact -G
@  6[tip]   8f65e5e02793   2014-08-14 20:06 -0700   ben
|    More documentation
|
o    5[featureA]:4,2   bd5ac26f11f9   2014-08-14 20:02 -0700   ben
|\     Merge remote-tracking branch 'origin/master'
| |
| o  4   0434aaa6b91f   2014-08-14 20:01 -0700   ben
| |    update makefile
| |
| o  3:1   318914536c86   2014-08-14 20:00 -0700   ben
| |    goodbye
| |
o |  2   f098c7f45c4f   2014-08-14 20:01 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

Tenga en cuenta la nueva etiqueta [featureA] en la revisión 5. Éstos actúan exactamente como las ramas de Git en el lado de Git, con una excepción: usted no puede suprimir un marcador del lado de Git (ésta es una limitación de ayudantes remotos).

Puede trabajar con una rama `heavyweight'' de Mercurial si: introduce ramas en los espacios para `branches así:

$ git checkout -b branches/permanent
Switched to a new branch 'branches/permanent'
$ vi Makefile
$ git commit -am 'A permanent change'
$ git push origin branches/permanent
To hg::/tmp/hello
 * [new branch]      branches/permanent -> branches/permanent

Esto es lo que aparece en el lado de Mercurial:

$ hg branches
permanent                      7:a4529d07aad4
develop                        6:8f65e5e02793
default                        5:bd5ac26f11f9 (inactive)
$ hg log -G
o  changeset:   7:a4529d07aad4
|  branch:      permanent
|  tag:         tip
|  parent:      5:bd5ac26f11f9
|  user:        Ben Straub <[email protected]>
|  date:        Thu Aug 14 20:21:09 2014 -0700
|  summary:     A permanent change
|
| @  changeset:   6:8f65e5e02793
|/   branch:      develop
|    user:        Ben Straub <[email protected]>
|    date:        Thu Aug 14 20:06:38 2014 -0700
|    summary:     More documentation
|
o    changeset:   5:bd5ac26f11f9
|\   bookmark:    featureA
| |  parent:      4:0434aaa6b91f
| |  parent:      2:f098c7f45c4f
| |  user:        Ben Straub <[email protected]>
| |  date:        Thu Aug 14 20:02:21 2014 -0700
| |  summary:     Merge remote-tracking branch 'origin/master'
[...]

El nombre de la rama ``permanent'' se registró en el conjunto de cambios marcados con 7.

Desde el lado de Git, el trabajo con cualquiera de estos estilos de rama es el mismo: sólo checkout'', commit'', fetch'', merge'', pull'' y push'' como lo haría normalmente. Una cosa que usted debe saber es que Mercurial no apoya la historia de la reescritura, agregando solamente a ella. Esto es lo que nuestro repositorio de Mercurial parece después de un rebase interactivo'' y un force-push'':

$ hg log --style compact -G
o  10[tip]   99611176cbc9   2014-08-14 20:21 -0700   ben
|    A permanent change
|
o  9   f23e12f939c3   2014-08-14 20:01 -0700   ben
|    Add some documentation
|
o  8:1   c16971d33922   2014-08-14 20:00 -0700   ben
|    goodbye
|
| o  7:5   a4529d07aad4   2014-08-14 20:21 -0700   ben
| |    A permanent change
| |
| | @  6   8f65e5e02793   2014-08-14 20:06 -0700   ben
| |/     More documentation
| |
| o    5[featureA]:4,2   bd5ac26f11f9   2014-08-14 20:02 -0700   ben
| |\     Merge remote-tracking branch 'origin/master'
| | |
| | o  4   0434aaa6b91f   2014-08-14 20:01 -0700   ben
| | |    update makefile
| | |
+---o  3:1   318914536c86   2014-08-14 20:00 -0700   ben
| |      goodbye
| |
| o  2   f098c7f45c4f   2014-08-14 20:01 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

CHangesets 8, 9 y 10 han sido creados y pertenecen a la rama permanent, pero los viejos ``changesets'' siguen ahí. Esto puede ser muy confuso para sus compañeros de equipo que están usando Mercurial, así que trate de evitarlo.

Resumen de Mercurial

Git y Mercurial son bastante similares, por lo que trabajar a través de la frontera es bastante indoloro. Si evita cambiar el historial que ha dejado su máquina (como se recomienda generalmente), puede que ni siquiera sepa que el otro extremo es Mercurial.