remote - ¿Cómo sincronizo dos repositorios remotos de Git?
git remote add (5)
Tengo dos URL de repositorio, y quiero sincronizarlas para que ambas contengan lo mismo. En Mercurial, lo que estoy tratando de hacer sería:
hg pull {repo1}
hg pull {repo2}
hg push -f {repo1}
hg push -f {repo2}
Esto dará como resultado dos cabezas en ambos repos (sé que no es común tener dos cabezas, pero estoy haciendo esto para la sincronización) y no debe ser interactivo. Las cabezas se fusionarán manualmente desde una de las reposiciones y luego la sincronización se ejecuta de nuevo).
Me gustaría hacer lo mismo en Git. Por ejemplo, sin la interacción del usuario, obtenga todos los cambios en ambos repos, con múltiples sucursales / jefes / lo que se fusionará más adelante. Estoy tratando de hacer esto utilizando las URL en los comandos, en lugar de agregar controles remotos (?), Ya que podría haber varios repositorios involucrados, y tener alias para ellos solo hará que mi script sea más complicado.
Actualmente estoy clonando el repositorio usando git clone --bar {repo1}
sin embargo estoy luchando para "actualizarlo". He intentado get fetch {repo1}
pero eso no parece reducir mis cambios; git log
aún no muestra el conjunto de cambios que se ha agregado en repo1.
También intenté usar --mirror
en mi push
y clone
, pero eso parecía a los cambios remotos del repo2 que no existían localmente, mientras que necesito mantener los cambios de ambos repos: /
¿Cuál es la mejor manera de hacer esto?
Edit: para dejar un poco más claro lo que estoy tratando de hacer ...
Tengo dos repositorios (por ejemplo, BitBucket y GitHub) y quiero que la gente pueda empujar a cualquiera de ellos (en última instancia, uno será Git, uno será Mercurial, pero supongamos que ambos son Git por ahora para simplificar las cosas). Necesito poder ejecutar un script que "sincronice" los dos repositorios de manera que ambos contengan ambos conjuntos de cambios, y es posible que deba fusionarse manualmente más adelante.
Eventualmente, esto significa que puedo interactuar con uno de los repositorios (por ejemplo, el de Mercurial), y mi script periódicamente incluirá los cambios de Git en los que puedo fusionar, y luego serán rechazados.
En Mercurial esto es trivial ! Simplemente jalo de ambos repos y presiono con la -f/--force
para permitir empujar múltiples cabezas. Entonces cualquiera puede clonar uno de los repositorios, fusionar las cabezas y empujar hacia atrás. Quiero saber cómo hacer lo más parecido en Git. Debe ser 100% no interactivo, y debe mantener ambos repositorios en un estado en el que el proceso pueda repetirse infinitamente (eso significa que no se debe volver a escribir el historial / cambiar los conjuntos de cambios, etc.).
Aquí hay una solución probada para el problema: http://www.tikalk.com/devops/sync-remote-repositories/
Los comandos a ejecutar:
#!/bin/bash
# REPO_NAME=<repo>.git
# ORIGIN_URL=git@<host>:<project>/$REPO_NAME
# REPO1_URL=git@<host>:<project>/$REPO_NAME
rm -rf $REPO_NAME
git clone --bare $ORIGIN_URL
cd $REPO_NAME
git remote add --mirror=fetch repo1 $REPO1_URL
git fetch origin --tags ; git fetch repo1 --tags
git push origin --all ; git push origin --tags
git push repo1 --all ; git push repo1 --tags
Es posible que no haya visto que la recuperación funcionó cuando usó git clone --mirror --bare
, porque de manera predeterminada git no enumera sus sucursales remotas. Puedes git branch -a
con git branch -a
.
No tengo la sintaxis bien desarrollada para los controles remotos sin nombre, pero podría agregar controles remotos automáticamente según algún esquema de la url ... en cualquier caso, probablemente funcionará mejor si elige un nombre único y consistente para cada uno Repo, para que puedas saber que cambios vinieron de donde
Sin embargo, podrías intentar algo como esto:
git clone --bare --mirror --origin thing1 {repo1} repo.git
cd repo.git
git fetch thing2 --mirror
git push thing1 --mirror
git push thing2 --mirror
Una vez hecho esto, thing1 tendría todas las sucursales de thing2 disponibles para fusionarse en cualquier momento, como sucursales remotas. Puedes listar las ramas remotas con git branch -a
.
En github o bitbucket, no podrá ver estas sucursales remotas a través de las interfaces web, sin embargo, puede verlas si clona con --mirror, por lo que existen.
Las ramas de Git no tienen "cabezas" en el sentido mercurial. Solo hay una cosa llamada HEAD
, y es efectivamente un enlace simbólico a la confirmación que actualmente ha verificado. En el caso de repositorios alojados como GitHub, no se ha confirmado ningún compromiso, solo existe el historial del repositorio. (Llamado un repo "desnudo".)
La razón de esta diferencia es que los nombres de las sucursales de Git son completamente arbitrarios; no tienen que coincidir entre las copias de un repositorio, y puedes crearlas y destruirlas a tu antojo. [1] Las ramas de Git son como nombres de variables de Python, que se pueden barajar y pegar en cualquier valor que desees; Las ramas mercuriales son como las variables C, que se refieren a ubicaciones fijas de memoria preasignadas que luego llena con datos.
Entonces, cuando atraes a Mercurial, tienes dos historias para la misma rama, porque el nombre de la rama es una cosa significativa y fija en ambos repositorios. La hoja de cada historia es una "cabeza", y normalmente las fusionarías para crear una sola cabeza.
Pero en Git, recuperar una rama remota no afecta en realidad a tu rama. Si obtiene la rama master
desde el origin
, solo ingresa a una rama llamada origin/master
. [2] git pull origin master
es solo azúcar delgada en dos pasos: busca la rama remota en origin/master
, y luego combina esa otra rama en su rama actual. Pero no tienen que tener el mismo nombre; Su rama podría llamarse development
o trunk
o cualquier otra cosa. Puede tirar o fusionar cualquier otra rama en ella, y puede empujarla a cualquier otra rama. Git no le importa.
Lo que me lleva de nuevo a su problema: no puede enviar una "segunda" rama a un repositorio de Git remoto, porque el concepto no existe. Podría empujar a las sucursales con nombres destrozados ( bitbucket_master
?), Pero hasta donde sé, no puede actualizar remotos de un control remoto de forma remota.
Sin embargo, no creo que su plan tenga mucho sentido, ya que con las ramas no fusionadas expuestas a ambos repositorios, tendría que fusionarlas o fusionar una y luego reflejarla sobre la otra. .. en cuyo caso dejó el segundo repositorio en un estado inútil sin ninguna razón.
¿Hay alguna razón por la que no puedas hacer esto?
Elija un repositorio para que sea canónico: asumo BitBucket. Clonalo Se convierte en
origin
.Agregue el otro repositorio como un remoto llamado, por ejemplo,
github
.Haga que un script simple
github
periódicamente ambos controles remotos e intente fusionar las ramas degithub
en las ramas deorigin
. Si la combinación falla, aborta y te envía un correo electrónico o lo que sea. Si la combinación es trivial, presione el resultado en ambos controles remotos.
Por supuesto, si solo hace todo su trabajo en las ramas de características, todo esto se convierte en un problema mucho menor. :)
[1] Se pone aún mejor: puedes unir ramas de diferentes repositorios que no tienen ninguna historia en común. He hecho esto para consolidar proyectos que se iniciaron por separado; Usaron diferentes estructuras de directorio, por lo que funciona bien. GitHub utiliza un truco similar para su función de Páginas: el historial de sus Páginas se almacena en una rama llamada gh-pages
que vive en el mismo repositorio pero no tiene absolutamente ninguna historia en común con el resto de su proyecto.
[2] Esta es una mentira blanca. La rama todavía se llama master
, pero pertenece al origin
remoto llamado origin
, y la barra es sintaxis para referirse a ella. La distinción puede ser importante porque Git no tiene reparos en las barras diagonales en los nombres de las sucursales, por lo que podría tener una sucursal local llamada origin/master
, y eso ocultaría la rama remota.
Para algo similar, uso este simple código activado por el webhook en ambos repositorios para sincronizar GitLab y la rama principal de Bitbucket:
git pull origin master
git pull gitlab master
git push origin master
git push gitlab master
Probablemente no es lo que necesita en cuestión, pero podría ser útil para alguien que necesite sincronizar solo una rama.
Prueba git reset --hard HEAD
después de git fetch
. Sin embargo, no estoy seguro de entender exactamente cuál es tu objetivo. Deberá ingresar en los directorios de repositorio separados antes de ejecutar los comandos fetch, reset y push.